@nekzus/liop 1.2.0-alpha.9 → 1.3.0-alpha.1

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 (53) hide show
  1. package/README.md +59 -47
  2. package/dist/bin/agent.js +222 -51
  3. package/dist/bridge/index.js +7 -6
  4. package/dist/bridge/stream.js +23 -15
  5. package/dist/client/index.js +53 -42
  6. package/dist/crypto/logic-image-id.d.ts +3 -0
  7. package/dist/crypto/logic-image-id.js +27 -0
  8. package/dist/crypto/verifier.d.ts +1 -1
  9. package/dist/crypto/verifier.js +9 -20
  10. package/dist/economy/estimator.d.ts +53 -0
  11. package/dist/economy/estimator.js +69 -0
  12. package/dist/economy/index.d.ts +5 -0
  13. package/dist/economy/index.js +3 -0
  14. package/dist/economy/otel.d.ts +38 -0
  15. package/dist/economy/otel.js +100 -0
  16. package/dist/economy/telemetry.d.ts +77 -0
  17. package/dist/economy/telemetry.js +224 -0
  18. package/dist/errors.d.ts +14 -0
  19. package/dist/errors.js +19 -0
  20. package/dist/gateway/hybrid.d.ts +3 -1
  21. package/dist/gateway/hybrid.js +38 -13
  22. package/dist/gateway/router.d.ts +25 -9
  23. package/dist/gateway/router.js +484 -133
  24. package/dist/index.d.ts +3 -0
  25. package/dist/index.js +3 -0
  26. package/dist/mesh/node.d.ts +16 -0
  27. package/dist/mesh/node.js +394 -113
  28. package/dist/prompts/adapters.d.ts +16 -0
  29. package/dist/prompts/adapters.js +55 -0
  30. package/dist/rpc/proto.js +2 -1
  31. package/dist/rpc/server.d.ts +1 -1
  32. package/dist/rpc/server.js +4 -3
  33. package/dist/rpc/tls.js +3 -2
  34. package/dist/sandbox/guardian.js +27 -4
  35. package/dist/sandbox/wasi.d.ts +1 -1
  36. package/dist/sandbox/wasi.js +44 -3
  37. package/dist/security/guardian.js +3 -2
  38. package/dist/security/zk.d.ts +3 -4
  39. package/dist/security/zk.js +33 -10
  40. package/dist/server/index.d.ts +53 -4
  41. package/dist/server/index.js +362 -49
  42. package/dist/server/pii.d.ts +12 -0
  43. package/dist/server/pii.js +90 -0
  44. package/dist/types.d.ts +16 -0
  45. package/dist/utils/logger.d.ts +21 -0
  46. package/dist/utils/logger.js +70 -0
  47. package/dist/utils/mcpCompact.d.ts +11 -0
  48. package/dist/utils/mcpCompact.js +29 -0
  49. package/dist/workers/logic-execution.d.ts +1 -1
  50. package/dist/workers/logic-execution.js +42 -22
  51. package/dist/workers/zk-verifier.d.ts +2 -0
  52. package/dist/workers/zk-verifier.js +52 -34
  53. package/package.json +16 -4
package/README.md CHANGED
@@ -4,19 +4,19 @@
4
4
  <img alt="Logic-Injection-on-Origin Protocol Logo" src="https://res.cloudinary.com/dsvsl0b0b/image/upload/v1774702621/Neural-Mesh-Protocol/hoanw0m6tybpz5fbl12n.svg?v=20260328" width="700">
5
5
  </picture>
6
6
 
7
- <h1>Logic-Injection-on-Origin Protocol (LIOP) — TypeScript SDK</h1>
7
+ <h1>Logic-Injection-on-Origin Protocol (LIOP) — TypeScript SDK</h1>
8
8
  <p align="center">
9
- <a href="https://github.com/Nekzus/Neural-Mesh-Protocol/actions/workflows/ci.yml"><img src="https://github.com/Nekzus/Neural-Mesh-Protocol/actions/workflows/ci.yml/badge.svg?event=push" alt="Github Workflow"></a>
9
+ <a href="https://github.com/Nekzus/LIOP/actions/workflows/ci.yml"><img src="https://github.com/Nekzus/LIOP/actions/workflows/ci.yml/badge.svg?event=push" alt="Github Workflow"></a>
10
10
  <a href="https://www.npmjs.com/package/@nekzus/liop"><img src="https://img.shields.io/npm/v/@nekzus/liop.svg" alt="npm version"></a>
11
11
  <a href="https://www.npmjs.com/package/@nekzus/liop"><img src="https://img.shields.io/npm/dm/@nekzus/liop.svg" alt="npm-month"></a>
12
12
  <a href="https://www.npmjs.com/package/@nekzus/liop"><img src="https://img.shields.io/npm/dt/@nekzus/liop.svg?style=flat" alt="npm-total"></a>
13
- <a href="https://github.com/Nekzus/Neural-Mesh-Protocol/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Nekzus/LIOP.svg" alt="License"></a>
14
- <a href="https://liop.mintlify.app/"><img src="https://img.shields.io/badge/docs-mintlify-0D9373?style=flat" alt="Docs"></a>
13
+ <a href="https://github.com/Nekzus/LIOP/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Nekzus/LIOP.svg" alt="License"></a>
14
+ <a href="https://nekzus-32.mintlify.app/"><img src="https://img.shields.io/badge/docs-mintlify-0D9373?style=flat" alt="Docs"></a>
15
15
  <a href="https://deepwiki.com/Nekzus/LIOP"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
16
16
  <a href="https://paypal.me/maseortega"><img src="https://img.shields.io/badge/donate-paypal-blue.svg?style=flat-square" alt="Donate"></a>
17
17
  </p>
18
18
 
19
- <p><strong>The official TypeScript SDK for the Logic-Injection-on-Origin Protocol.</strong></p>
19
+ <p><strong>The official TypeScript SDK for the Logic-Injection-on-Origin Protocol.</strong></p>
20
20
  <p>Deploy Logic-on-Origin with WebAssembly sandboxing, gRPC-speed execution, and full MCP backward compatibility.</p>
21
21
  </div>
22
22
 
@@ -30,18 +30,19 @@ This fundamentally solves the data privacy, bandwidth, and latency challenges of
30
30
 
31
31
  ### Key Capabilities
32
32
 
33
- | Feature | Description |
34
- |:--|:--|
35
- | **Logic-Injection-on-Origin** | LLMs send code, not queries. Data never leaves the origin server. |
36
- | **MCP Drop-in Replacement** | `LiopServer` mirrors the Anthropic MCP `Server` API — tools, resources, and prompts with `Zod` schemas. |
37
- | **Guardian AST** | Zero-time heuristic inspection blocks sandbox escapes (`require`, `fs`, `eval`, `fetch`, prototype pollution). |
38
- | **WASI Sandbox** | JavaScript payloads execute inside V8 isolates with CPU fuel limits and no access to Node.js globals. |
39
- | **PII Shield** | Multi-layer egress filter with NIST/OWASP patterns (Email, Credit Card with Luhn, IP, Phone) and configurable forbidden keys. |
40
- | **ZK-Receipts** | Cryptographic proof (SHA-256 + SHA-512 seal) that the returned result was computed honestly from the injected logic. |
41
- | **Worker Pool** | Heavy computation (crypto, sandboxing) dispatched to OS threads via `piscina`, unblocking the V8 event loop. |
42
- | **MCP Bridge** | `LiopMcpBridge` adapts any `LiopServer` to the JSON-RPC 2.0 / stdio protocol used by Claude Desktop, Cursor, etc. |
43
- | **Post-Quantum Ready** | ML-KEM-768 (Kyber) handshake + AES-256-GCM symmetric encryption for transport-layer security. |
44
- | **P2P Mesh** | Kademlia DHT discovery via `libp2p` with TCP + WebSocket + Yamux multiplexing and Noise encryption. |
33
+ | Feature | Description |
34
+ | :---------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------- |
35
+ | **Logic-Injection-on-Origin** | LLMs send code, not queries. Data never leaves the origin server. |
36
+ | **MCP Drop-in Replacement** | `LiopServer` mirrors the Anthropic MCP `Server` API — tools, resources, and prompts with `Zod` schemas. |
37
+ | **Guardian AST** | Zero-time heuristic inspection blocks sandbox escapes (`require`, `fs`, `eval`, `fetch`, prototype pollution). |
38
+ | **WASI Sandbox** | JavaScript payloads execute inside V8 isolates with CPU fuel limits and no access to Node.js globals. |
39
+ | **PII Shield** | Multi-layer egress filter with Regional Presets (Email, Credit Card with Luhn, IP, Phone, SSN, IBAN Mod-97, Passport MRZ) and custom keys. |
40
+ | **ZK-Receipts** | Cryptographic proof (SHA-256 ImageID + HMAC-SHA256 seal) that the returned result was computed honestly from the injected logic. |
41
+ | **Worker Pool** | Heavy computation (crypto, sandboxing) dispatched to OS threads via `piscina`, unblocking the V8 event loop. |
42
+ | **Cross-AI Adapters** | Zero-Shot system prompts automatically adapt instructions for Claude (XML-heavy) vs OpenAI/Gemini (JSON-schema). |
43
+ | **MCP Bridge** | `LiopMcpBridge` adapts any `LiopServer` to the JSON-RPC 2.0 / stdio protocol used by Claude Desktop, Cursor, etc. |
44
+ | **Post-Quantum Ready** | ML-KEM-768 (Kyber) handshake + AES-256-GCM symmetric encryption for transport-layer security. |
45
+ | **P2P Mesh** | Kademlia DHT discovery via `libp2p` with TCP + WebSocket + Yamux multiplexing and Noise encryption. |
45
46
 
46
47
  ---
47
48
 
@@ -90,6 +91,7 @@ To use the Neural Mesh inside Claude Desktop, update your `claude_desktop_config
90
91
  ### Persistence & Identity
91
92
 
92
93
  The agent automatically manages your P2P identity:
94
+
93
95
  - **Identity Path**: `~/.liop/identity.json`. This file contains your unique PeerID. Keep it safe if you want to maintain a consistent identity in the mesh.
94
96
  - **Bootstrap Nodes**: By default, the agent connects to the **LIOP Alpha Nexus**. You can provide custom bootstrap addresses as CLI arguments:
95
97
  ```bash
@@ -196,24 +198,24 @@ new LiopServer(
196
198
 
197
199
  #### Methods
198
200
 
199
- | Method | Signature | Description |
200
- |:--|:--|:--|
201
- | `tool()` | `(name, description, zodSchema, handler)` | Registers a callable tool with Zod input validation. |
202
- | `prompt()` | `(name, description, args, handler)` | Registers a dynamic prompt template. |
203
- | `resource()` | `(name, uri, description?, mimeType?, content?)` | Registers a readable resource. |
204
- | `dataDictionary()` | `(schema, name?, uri?, description?)` | Broadcasts a data schema so LLMs can write accurate Logic-Injection-on-Origin code. |
205
- | `setSandboxData()` | `(records: Record[])` | Injects data into the sandbox as `env.records` for Logic-on-Origin tools. |
206
- | `enableZeroShotAutonomy()` | `()` | Registers the "Blind Analyst" prompt for autonomous code generation. |
207
- | `callTool()` | `(request: CallToolRequest)` | Invokes a registered tool (used locally or via MCP Bridge). |
208
- | `listTools()` | `()` | Returns all registered tools. |
209
- | `listPrompts()` | `()` | Returns all registered prompts. |
210
- | `getPrompt()` | `(request: GetPromptRequest)` | Returns a specific prompt by name. |
211
- | `listResources()` | `()` | Returns all registered resources. |
212
- | `readResource()` | `(uri: string)` | Reads a resource by URI. |
213
- | `getServerInfo()` | `()` | Returns the server's name and version. |
214
- | `connectToMesh()` | `()` | Connects to the libp2p Kademlia DHT. |
215
- | `clearAstCache()` | `()` | Invalidates the Guardian AST logic cache. |
216
- | `close()` | `()` | Destroys the worker pool and releases threads. |
201
+ | Method | Signature | Description |
202
+ | :--------------------------- | :------------------------------------------------- | :---------------------------------------------------------------------------------- |
203
+ | `tool()` | `(name, description, zodSchema, handler)` | Registers a callable tool with Zod input validation. |
204
+ | `prompt()` | `(name, description, args, handler)` | Registers a dynamic prompt template. |
205
+ | `resource()` | `(name, uri, description?, mimeType?, content?)` | Registers a readable resource. |
206
+ | `dataDictionary()` | `(schema, name?, uri?, description?)` | Broadcasts a data schema so LLMs can write accurate Logic-Injection-on-Origin code. |
207
+ | `setSandboxData()` | `(records: Record[])` | Injects data into the sandbox as `env.records` for Logic-on-Origin tools. |
208
+ | `enableZeroShotAutonomy()` | `()` | Registers the "Blind Analyst" prompt for autonomous code generation. |
209
+ | `callTool()` | `(request: CallToolRequest)` | Invokes a registered tool (used locally or via MCP Bridge). |
210
+ | `listTools()` | `()` | Returns all registered tools. |
211
+ | `listPrompts()` | `()` | Returns all registered prompts. |
212
+ | `getPrompt()` | `(request: GetPromptRequest)` | Returns a specific prompt by name. |
213
+ | `listResources()` | `()` | Returns all registered resources. |
214
+ | `readResource()` | `(uri: string)` | Reads a resource by URI. |
215
+ | `getServerInfo()` | `()` | Returns the server's name and version. |
216
+ | `connectToMesh()` | `()` | Connects to the libp2p Kademlia DHT. |
217
+ | `clearAstCache()` | `()` | Invalidates the Guardian AST logic cache. |
218
+ | `close()` | `()` | Destroys the worker pool and releases threads. |
217
219
 
218
220
  ### `LiopMcpBridge`
219
221
 
@@ -225,6 +227,7 @@ await bridge.connect();
225
227
  ```
226
228
 
227
229
  **Supported JSON-RPC methods:**
230
+
228
231
  - `initialize` — Returns server capabilities and info
229
232
  - `tools/list` — Lists available tools
230
233
  - `tools/call` — Calls a tool (with ZK-Receipt verification)
@@ -254,7 +257,7 @@ await bridge.connect();
254
257
  ├─────────────────────────────────────────────────────┤
255
258
  │ Layer 4: ZK-Receipt (Integrity Verification) │
256
259
  │ SHA-256 ImageID + SHA-512 RISC0-style Seal │
257
- │ LiopMcpBridge verifies before forwarding to LLM
260
+ │ LiopMcpBridge verifies before forwarding to LLM
258
261
  └─────────────────────────────────────────────────────┘
259
262
  ```
260
263
 
@@ -263,13 +266,21 @@ await bridge.connect();
263
266
  Built-in patterns with multi-layer verification:
264
267
 
265
268
  ```typescript
266
- import { PII_PATTERNS } from "@nekzus/liop/server";
269
+ import { PII_PATTERNS, PII_PRESETS } from "@nekzus/liop/server";
267
270
 
268
271
  // Available patterns:
269
272
  PII_PATTERNS.EMAIL // RFC 5322 compliant, excludes @example.com/@test.com
270
273
  PII_PATTERNS.CREDIT_CARD // Visa/MC/Amex + Luhn algorithm validation
271
274
  PII_PATTERNS.IP_ADDRESS // IPv4 with octet range validation (excludes localhost)
272
275
  PII_PATTERNS.PHONE // International phone formats with digit-length validation
276
+ PII_PATTERNS.SSN // USA Social Security Number rules (blocks 000 segments)
277
+ PII_PATTERNS.IBAN // ISO 7064 Modulo 97-10 algorithm precision via BigInt
278
+ PII_PATTERNS.PASSPORT_MRZ // Strict 44-character TD3 international passport MRZ string
279
+
280
+ // Pre-built Regional Presets ready to drop-in via LiopServer(options):
281
+ PII_PRESETS.GLOBAL_STRICT
282
+ PII_PRESETS.US_COMPLIANT
283
+ PII_PRESETS.EU_GDPR
273
284
  ```
274
285
 
275
286
  ### Forbidden Keys
@@ -292,7 +303,7 @@ const server = new LiopServer(info, {
292
303
  The following shows a complete Logic-Injection-on-Origin execution cycle (handled internally by the SDK):
293
304
 
294
305
  ```
295
- 1. LLM generates JavaScript analysis code wrapped in ---BEGIN_LOGIC--- / ---END_LOGIC--- boundaries
306
+ 1. LLM generates JavaScript analysis code wrapped in @LIOP / @END boundaries
296
307
  2. LiopServer receives the payload via tools/call (JSON-RPC or direct)
297
308
  3. Guardian AST inspects for sandbox escapes (zero-time heuristic analysis)
298
309
  4. Code executes inside a V8 isolate with CPU fuel limits (no Node.js globals)
@@ -379,26 +390,27 @@ await server.connectToMesh();
379
390
 
380
391
  This package is continuously tested across multiple platforms and Node.js versions via CI/CD:
381
392
 
382
- - **51+ tests** spanning unit, integration, and conformance suites
393
+ - **209+ tests** spanning unit, integration, conformance, and crossnet suites
383
394
  - **Multi-OS matrix:** Ubuntu, Windows, macOS
384
395
  - **Node.js versions:** 22.x, 24.x
385
396
  - **Code quality:** Enforced by [Biome.js](https://biomejs.dev/) (linting + formatting)
397
+ - **Security:** Verified defense-in-depth architecture — see [Security Architecture](https://nekzus-32.mintlify.app/typescript-sdk/security)
386
398
 
387
- > To run tests locally or contribute, clone the [repository](https://github.com/Nekzus/Neural-Mesh-Protocol) and follow the [Contributing Guide](https://github.com/Nekzus/Neural-Mesh-Protocol/blob/main/CONTRIBUTING.md).
399
+ > To run tests locally or contribute, clone the [repository](https://github.com/Nekzus/LIOP) and follow the [Contributing Guide](https://github.com/Nekzus/LIOP/blob/main/CONTRIBUTING.md).
388
400
 
389
401
  ---
390
402
 
391
403
  ## Related
392
404
 
393
- - [LIOP Documentation](https://liop.mintlify.app/) — Full conceptual and API documentation
394
- - [LIOP Specification](https://github.com/Nekzus/Neural-Mesh-Protocol/blob/main/protocol/SPECIFICATION.md) — Technical specification
395
- - [LIOP Manifesto](https://github.com/Nekzus/Neural-Mesh-Protocol/blob/main/MANIFESTO.md) — Project philosophy
396
- - [Contributing Guide](https://github.com/Nekzus/Neural-Mesh-Protocol/blob/main/CONTRIBUTING.md) — How to contribute
397
- - [Rust Mesh Node](https://github.com/Nekzus/Neural-Mesh-Protocol/tree/main/servers/liop-node) — Native high-performance backend
398
- - [LIOP CLI](https://github.com/Nekzus/Neural-Mesh-Protocol/tree/main/tools/liop-cli) — Developer diagnostics
405
+ - [LIOP Documentation](https://nekzus-32.mintlify.app/) — Full conceptual and API documentation
406
+ - [LIOP Specification](https://github.com/Nekzus/LIOP/blob/main/protocol/SPECIFICATION.md) — Technical specification
407
+ - [LIOP Manifesto](https://github.com/Nekzus/LIOP/blob/main/MANIFESTO.md) — Project philosophy
408
+ - [Contributing Guide](https://github.com/Nekzus/LIOP/blob/main/CONTRIBUTING.md) — How to contribute
409
+ - [Rust Mesh Node](https://github.com/Nekzus/LIOP/tree/main/servers/liop-node) — Native high-performance backend
410
+ - [LIOP CLI](https://github.com/Nekzus/LIOP/tree/main/tools/liop-cli) — Developer diagnostics
399
411
 
400
412
  ---
401
413
 
402
414
  ## License
403
415
 
404
- [MIT](https://github.com/Nekzus/Neural-Mesh-Protocol/blob/main/LICENSE) © [Nekzus](https://github.com/Nekzus)
416
+ [MIT](https://github.com/Nekzus/LIOP/blob/main/LICENSE) © [Nekzus](https://github.com/Nekzus)
package/dist/bin/agent.js CHANGED
@@ -2,9 +2,105 @@
2
2
  import * as fs from "node:fs";
3
3
  import * as os from "node:os";
4
4
  import * as path from "node:path";
5
+ import { multiaddr } from "@multiformats/multiaddr";
5
6
  import { LiopMcpRouter } from "../gateway/router.js";
6
7
  import { MeshNode } from "../mesh/index.js";
7
8
  import { LiopServer } from "../server/index.js";
9
+ import { log } from "../utils/logger.js";
10
+ /**
11
+ * Resolves a full libp2p multiaddr (with PeerID) from a LIOP node's
12
+ * HTTP health endpoint. This enables zero-config bootstrap — users
13
+ * only need to provide a URL, not a cryptographic PeerID.
14
+ *
15
+ * @param url - HTTP URL of a LIOP node's health endpoint (e.g. "http://host:3000")
16
+ * @returns Full multiaddr string with PeerID, or null if resolution fails
17
+ */
18
+ async function resolveBootstrapFromUrl(url) {
19
+ try {
20
+ const healthUrl = url.endsWith("/health") ? url : `${url}/health`;
21
+ const response = await fetch(healthUrl, {
22
+ headers: { Accept: "application/json" },
23
+ signal: AbortSignal.timeout(10000), // Increased to 10s
24
+ });
25
+ if (!response.ok)
26
+ return null;
27
+ const data = await response.json();
28
+ if (!data.mesh?.multiaddrs?.length || !data.mesh?.peerId)
29
+ return null;
30
+ // Find TCP multiaddr (prefer non-websocket for stability)
31
+ const tcpAddr = data.mesh.multiaddrs.find((a) => a.includes("/tcp/") &&
32
+ !a.includes("/ws") &&
33
+ !a.includes("/ip4/127.0.0.1/"));
34
+ if (!tcpAddr)
35
+ return null;
36
+ // Rewrite internal Docker IP using industrial mapper if available
37
+ let resolved = industrialAddressMapper(tcpAddr);
38
+ if (!resolved || resolved === tcpAddr) {
39
+ const urlHost = new URL(url).hostname;
40
+ resolved = tcpAddr.replace(/\/ip4\/[^/]+/, `/ip4/${urlHost}`);
41
+ }
42
+ if (!resolved)
43
+ return null;
44
+ resolved += resolved.includes("/p2p/") ? "" : `/p2p/${data.mesh.peerId}`;
45
+ return resolved;
46
+ }
47
+ catch {
48
+ return null;
49
+ }
50
+ }
51
+ /**
52
+ * Normalizes a bootstrap multiaddr string.
53
+ * If the address contains a Docker bridge IP (172.16-31.x.x) or Loopback (127.0.0.1),
54
+ * rewrites it to the host accessible via LIOP_NEXUS_URL (e.g. WSL2 IP).
55
+ * This is critical when WSL2 mirror-mode networking is broken.
56
+ */
57
+ function normalizeBootstrap(addr) {
58
+ const trimmed = addr.trim();
59
+ // Remap Docker bridge IPs and ANY external physical IPs to 127.0.0.1
60
+ // because Test-NetConnection confirmed 127.0.0.1 is the only reliable path to Docker ports.
61
+ const dockerIpRegex = /\/ip4\/172\.(1[6-9]|2[0-9]|3[0-1])\.[0-9]{1,3}\.[0-9]{1,3}/;
62
+ const loopbackRegex = /\/ip4\/127\.0\.0\.1/;
63
+ const physicalIpRegex = /\/ip4\/192\.168\.[0-9]{1,3}\.[0-9]{1,3}/;
64
+ if (dockerIpRegex.test(trimmed) ||
65
+ loopbackRegex.test(trimmed) ||
66
+ physicalIpRegex.test(trimmed)) {
67
+ const targetIp = "127.0.0.1";
68
+ const normalized = trimmed
69
+ .replace(dockerIpRegex, `/ip4/${targetIp}`)
70
+ .replace(loopbackRegex, `/ip4/${targetIp}`)
71
+ .replace(physicalIpRegex, `/ip4/${targetIp}`);
72
+ if (normalized !== trimmed) {
73
+ log.info(`[LIOP-Agent] 🔄 Local Routing Hack → Forced 127.0.0.1: ${normalized}`);
74
+ }
75
+ return normalized;
76
+ }
77
+ return trimmed;
78
+ }
79
+ /**
80
+ * industrialAddressMapper
81
+ *
82
+ * Mapea IPs internas de Docker a puertos industriales mapeados en el Host.
83
+ * Nexus (172.20.0.10) -> 13001
84
+ * Vault (172.20.0.11) -> 13003
85
+ * Bank (172.20.0.12) -> 13004
86
+ * Oracle(172.20.0.13) -> 13005
87
+ */
88
+ function industrialAddressMapper(addr) {
89
+ if (addr.includes("/ip4/172.20.0.10"))
90
+ return addr.replace(/\/ip4\/172\.20\.0\.10\/tcp\/[0-9]+/, "/ip4/127.0.0.1/tcp/13001");
91
+ if (addr.includes("/ip4/172.20.0.11"))
92
+ return addr.replace(/\/ip4\/172\.20\.0\.11\/tcp\/[0-9]+/, "/ip4/127.0.0.1/tcp/13003");
93
+ if (addr.includes("/ip4/172.20.0.12"))
94
+ return addr.replace(/\/ip4\/172\.20\.0\.12\/tcp\/[0-9]+/, "/ip4/127.0.0.1/tcp/13004");
95
+ if (addr.includes("/ip4/172.20.0.13"))
96
+ return addr.replace(/\/ip4\/172\.20\.0\.13\/tcp\/[0-9]+/, "/ip4/127.0.0.1/tcp/13005");
97
+ // Drop container-internal loopbacks to prevent the Host Agent from dialing itself or conflicting ports
98
+ if (addr.includes("/ip4/127.0.0.1/tcp/4000") ||
99
+ addr.includes("/ip4/127.0.0.1/tcp/3000")) {
100
+ return null;
101
+ }
102
+ return addr;
103
+ }
8
104
  /**
9
105
  * LIOP Agent (Zero-Config CLI)
10
106
  *
@@ -15,6 +111,8 @@ import { LiopServer } from "../server/index.js";
15
111
  * No hardcoded tools, PeerIDs, or port mappings.
16
112
  */
17
113
  async function main() {
114
+ const buildTime = new Date().toISOString();
115
+ log.info(`[LIOP-Agent] 🚀 Version 1.2.0-alpha.9 | Build: ${buildTime}`);
18
116
  const liopDir = path.join(os.homedir(), ".liop");
19
117
  const identityPath = path.join(liopDir, "identity.json");
20
118
  if (!fs.existsSync(liopDir)) {
@@ -27,31 +125,41 @@ async function main() {
27
125
  if (args.length > 0) {
28
126
  bootstrapNodes = args.filter((a) => a.startsWith("/"));
29
127
  }
30
- // Environment variable
31
- if (bootstrapNodes.length === 0 && process.env.LIOP_BOOTSTRAP) {
32
- bootstrapNodes.push(process.env.LIOP_BOOTSTRAP.trim());
33
- }
34
- // Convenience: Try to read nexus.multiaddr from multiple locations
128
+ // Priority 1: Physical Beacons (Industrial Pattern) - DETERMINISTIC & INSTANT
35
129
  if (bootstrapNodes.length === 0) {
36
- const searchPaths = [
37
- path.join(process.cwd(), "nexus.multiaddr"),
38
- path.join(liopDir, "nexus.multiaddr"),
39
- // Try relative to the agent binary (dist/bin/agent.js -> root/nexus.multiaddr)
40
- path.join(path.dirname(new URL(import.meta.url).pathname), "../../nexus.multiaddr"),
41
- // Windows path fix (remove leading slash if present)
42
- path.join(path
43
- .dirname(new URL(import.meta.url).pathname)
44
- .replace(/^\/([A-Z]:)/, "$1"), "../../nexus.multiaddr"),
45
- ];
46
- for (const nexusPath of searchPaths) {
130
+ const searchDirs = [];
131
+ // Priority 1.1: Explicit file from environment variable
132
+ if (process.env.LIOP_BOOTSTRAP_FILE) {
133
+ const filePath = path.resolve(process.env.LIOP_BOOTSTRAP_FILE);
134
+ if (fs.existsSync(filePath)) {
135
+ const addr = fs.readFileSync(filePath, "utf8").trim();
136
+ if (addr)
137
+ bootstrapNodes.push(normalizeBootstrap(addr));
138
+ }
139
+ }
140
+ // Priority 1.2: Traditional locations (Scan for all *.multiaddr)
141
+ searchDirs.push(process.cwd(), path.join(process.cwd(), "tests/infra/nexus-data"), liopDir, path.join(path
142
+ .dirname(new URL(import.meta.url).pathname)
143
+ .replace(/^\/([A-Z]:)/, "$1"), "../../tests/infra/nexus-data"));
144
+ for (const dir of searchDirs) {
47
145
  try {
48
- if (fs.existsSync(nexusPath)) {
49
- const addr = fs.readFileSync(nexusPath, "utf8").trim();
50
- if (addr && !bootstrapNodes.includes(addr)) {
51
- bootstrapNodes.push(addr);
52
- console.error(`[LIOP-Agent] Found bootstrap at: ${nexusPath}`);
53
- break;
146
+ if (fs.existsSync(dir)) {
147
+ const files = fs.readdirSync(dir);
148
+ const multiaddrFiles = files.filter((f) => f.endsWith(".multiaddr"));
149
+ for (const file of multiaddrFiles) {
150
+ const filePath = path.join(dir, file);
151
+ const addr = fs.readFileSync(filePath, "utf8").trim();
152
+ if (addr) {
153
+ const normalized = normalizeBootstrap(addr);
154
+ if (!bootstrapNodes.includes(normalized)) {
155
+ bootstrapNodes.push(normalized);
156
+ log.info(`[LIOP-Agent] ✅ Loaded beacon: ${file} from ${dir}`);
157
+ }
158
+ }
54
159
  }
160
+ // If we found any beacons in this directory, we consider discovery successful for this layer
161
+ if (bootstrapNodes.length > 0)
162
+ break;
55
163
  }
56
164
  }
57
165
  catch (_e) {
@@ -59,78 +167,141 @@ async function main() {
59
167
  }
60
168
  }
61
169
  }
170
+ // Priority 2: Auto-Discovery via NEXUS URL (Aggressive Parallel Discovery)
171
+ if (process.env.LIOP_NEXUS_URL) {
172
+ const nexusUrl = process.env.LIOP_NEXUS_URL;
173
+ log.info(`[LIOP-Agent] 🌐 Running parallel discovery from: ${nexusUrl} (Sources Found: ${bootstrapNodes.length})`);
174
+ const resolved = await resolveBootstrapFromUrl(nexusUrl);
175
+ if (resolved) {
176
+ const normalized = normalizeBootstrap(resolved);
177
+ if (!bootstrapNodes.includes(normalized)) {
178
+ bootstrapNodes.push(normalized);
179
+ log.info(`[LIOP-Agent] ✅ Added bootstrap from URL discovery: ${normalized}`);
180
+ }
181
+ }
182
+ }
183
+ // Priority 3: Environment variable (direct multiaddr)
184
+ if (bootstrapNodes.length === 0 && process.env.LIOP_BOOTSTRAP) {
185
+ bootstrapNodes.push(process.env.LIOP_BOOTSTRAP.trim());
186
+ }
187
+ // Final fallback: local Nexus bootstrap for demo environments.
188
+ // Avoid injecting stale static peer IDs when discovery already found valid peers.
189
+ if (bootstrapNodes.length === 0) {
190
+ bootstrapNodes.push("/ip4/127.0.0.1/tcp/13001/p2p/12D3KooWD8FUFdnLQzzLFNdicsaTknM5cpD7os9sK9NWVSVABJMD");
191
+ }
192
+ // Sanitize/validate all candidate multiaddrs so malformed PeerIDs don't crash startup.
193
+ bootstrapNodes = bootstrapNodes.filter((addr) => {
194
+ try {
195
+ multiaddr(addr);
196
+ return true;
197
+ }
198
+ catch {
199
+ log.warn(`[LIOP-Agent] Ignoring invalid bootstrap multiaddr: ${addr}`);
200
+ return false;
201
+ }
202
+ });
62
203
  // If no bootstrap nodes found, the agent operates in standalone mode.
63
204
  // It will only serve local tools until peers are discovered.
64
205
  if (bootstrapNodes.length === 0) {
65
- console.error("[LIOP-Agent] No bootstrap nodes configured. Operating in standalone mode.");
66
- console.error("[LIOP-Agent] Pass a multiaddr as argument or create 'nexus.multiaddr' file.");
206
+ log.info("[LIOP-Agent] No bootstrap nodes configured. Operating in standalone mode.");
207
+ log.info("[LIOP-Agent] Pass a multiaddr as argument or create 'nexus.multiaddr' file.");
67
208
  }
68
209
  // Initialize local server node (lightweight, no tools registered locally)
69
210
  const liopServer = new LiopServer({
70
211
  name: "@nekzus/liop-agent",
71
212
  version: "1.0.0",
72
213
  });
214
+ // Enable Zero-Shot Autonomy (Industrial Prompt Injection)
215
+ liopServer.enableZeroShotAutonomy();
73
216
  // 2. Mesh Node Configuration
74
217
  const meshNode = new MeshNode({
75
218
  identityPath: identityPath,
76
219
  bootstrapNodes: bootstrapNodes,
220
+ addressMapper: industrialAddressMapper,
77
221
  });
78
222
  // Start P2P Mesh
79
223
  await meshNode.start();
80
224
  // 3. Initialize the Dynamic Router
81
225
  // No hardcoded tools — all discovery happens via liop:manifest protocol
82
226
  const router = new LiopMcpRouter(liopServer, meshNode);
83
- // Proactive Notification to Claude Desktop when tools are discovered dynamically
227
+ // Proactive Notification to Claude Desktop when tools/resources are discovered dynamically
84
228
  router.onToolsChanged = () => {
85
229
  process.stdout.write(`{"jsonrpc":"2.0","method":"notifications/tools/list_changed"}\n`);
230
+ process.stdout.write(`{"jsonrpc":"2.0","method":"notifications/resources/list_changed"}\n`);
86
231
  };
87
- // Initial warming period (2s) then Periodic Discovery Worker (every 10 seconds)
88
- // This silently polls the DHT for new nodes and triggers onToolsChanged if the topology shifts.
232
+ // Initial warming period (2s) then Adaptive Background Discovery
233
+ // Polls DHT for new nodes and triggers onToolsChanged when topology shifts.
234
+ // Uses exponential backoff to reduce polling load on stable meshes.
89
235
  setTimeout(() => {
90
236
  // biome-ignore lint/suspicious/noExplicitAny: access internal for telemetry
91
237
  const rtSize = meshNode.getRoutingTableSize?.() || 0;
92
- console.error(`[LIOP-Agent] Warm-up complete. Routing Table size: ${rtSize}`);
238
+ log.info(`[LIOP-Agent] Warm-up complete. Routing Table size: ${rtSize}`);
93
239
  router.refreshManifestCache(true).catch(() => { });
94
240
  }, 2000);
95
- setInterval(() => {
96
- router.refreshManifestCache(true).catch(() => { });
97
- }, 15000);
98
- // 4. STDIO Transport implementation
241
+ const POLL_BASE_MS = 10_000;
242
+ const POLL_MAX_MS = 120_000;
243
+ let pollIntervalMs = POLL_BASE_MS;
244
+ const scheduleAdaptivePoll = () => {
245
+ setTimeout(async () => {
246
+ const prevSize = router.getCacheSize();
247
+ await router.refreshManifestCache(true).catch(() => { });
248
+ const newSize = router.getCacheSize();
249
+ if (newSize !== prevSize) {
250
+ // Topology changed — reset to aggressive polling
251
+ pollIntervalMs = POLL_BASE_MS;
252
+ log.info(`[LIOP-Agent] Topology change detected (${prevSize} → ${newSize}). Resetting poll to ${POLL_BASE_MS / 1000}s.`);
253
+ }
254
+ else {
255
+ // Stable — relax polling interval (factor 1.5)
256
+ pollIntervalMs = Math.min(Math.round(pollIntervalMs * 1.5), POLL_MAX_MS);
257
+ }
258
+ scheduleAdaptivePoll();
259
+ }, pollIntervalMs);
260
+ };
261
+ scheduleAdaptivePoll();
262
+ // 4. STDIO Transport — Buffered Line Reader
263
+ // Uses readline to guarantee complete JSON-RPC messages before parsing.
264
+ // Raw stdin.on("data") can fragment large payloads across multiple chunks.
265
+ const readline = await import("node:readline");
266
+ const rl = readline.createInterface({
267
+ input: process.stdin,
268
+ terminal: false,
269
+ });
99
270
  process.stdout.on("error", (err) => {
100
271
  if (err.code === "EPIPE") {
101
272
  process.exit(0); // Graceful exit when Claude Desktop disconnects
102
273
  }
103
274
  });
104
- process.stdin.on("data", async (data) => {
105
- const payload = data.toString().trim();
106
- if (!payload)
275
+ rl.on("line", async (line) => {
276
+ const trimmed = line.trim();
277
+ if (!trimmed)
107
278
  return;
108
- const messages = payload.split("\n");
109
- for (const msg of messages) {
110
- try {
111
- const request = JSON.parse(msg);
112
- if (request.method) {
113
- const response = await router.dispatch(request);
114
- if (response) {
115
- process.stdout.write(`${JSON.stringify(response)}\n`);
116
- }
279
+ try {
280
+ const request = JSON.parse(trimmed);
281
+ if (request.method) {
282
+ const response = await router.dispatch(request);
283
+ if (response) {
284
+ process.stdout.write(`${JSON.stringify(response)}\n`);
117
285
  }
118
286
  }
119
- catch (_err) {
120
- // Silent catch for binary noise
121
- }
122
287
  }
288
+ catch (_err) {
289
+ // Silent catch for binary noise or malformed lines
290
+ }
291
+ });
292
+ rl.on("close", () => {
293
+ process.exit(0);
123
294
  });
124
295
  // Status directed only to stderr
125
- console.error(`[LIOP-Agent] Guarding Claude Desktop via STDIO.`);
126
- console.error(`[LIOP-Agent] P2P Mesh: Joined (${bootstrapNodes.length} bootstraps)`);
127
- console.error("[LIOP-Agent] Tool discovery: Dynamic via /liop/manifest/1.0.0");
296
+ log.info(`[LIOP-Agent] Guarding Claude Desktop via STDIO.`);
297
+ log.info(`[LIOP-Agent] P2P Mesh: Joined (${bootstrapNodes.length} bootstraps)`);
298
+ log.info("[LIOP-Agent] Tool discovery: Dynamic via /liop/manifest/1.0.0");
128
299
  process.on("SIGINT", async () => {
129
300
  await meshNode.stop();
130
301
  process.exit(0);
131
302
  });
132
303
  }
133
304
  main().catch((err) => {
134
- console.error(`[LIOP-Agent] Fatal Error: ${err.message}`);
305
+ log.error(`[LIOP-Agent] Fatal Error: ${err.message}`);
135
306
  process.exit(1);
136
307
  });
@@ -1,5 +1,6 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { LiopServer } from "../server/index.js";
3
+ import { log } from "../utils/logger.js";
3
4
  /**
4
5
  * LIOP MCP Bridge
5
6
  * A bi-directional bridge that allows legacy MCP servers to join the LIOP mesh,
@@ -14,11 +15,11 @@ export class LiopMcpBridge {
14
15
  // Determine mode: Exposing LIOP to MCP (Claude) or Wrapping MCP to LIOP (Mesh)
15
16
  if (source instanceof LiopServer) {
16
17
  this.liopServer = source;
17
- console.error("[LIOP-Bridge] Mode: EXPOSE (LIOP -> MCP Stdio)");
18
+ log.info("[LIOP-Bridge] Mode: EXPOSE (LIOP -> MCP Stdio)");
18
19
  }
19
20
  else if (source instanceof McpServer) {
20
21
  this.legacyMcpServer = source;
21
- console.error("[LIOP-Bridge] Mode: WRAP (Legacy MCP -> LIOP Mesh)");
22
+ log.info("[LIOP-Bridge] Mode: WRAP (Legacy MCP -> LIOP Mesh)");
22
23
  }
23
24
  }
24
25
  /**
@@ -47,7 +48,7 @@ export class LiopMcpBridge {
47
48
  return null;
48
49
  if (method === "initialize") {
49
50
  return this.successResponse(id, {
50
- protocolVersion: "2025-03-26",
51
+ protocolVersion: "2025-11-25",
51
52
  capabilities: {
52
53
  prompts: {},
53
54
  resources: {},
@@ -167,7 +168,7 @@ export class LiopMcpBridge {
167
168
  return true;
168
169
  }
169
170
  catch (e) {
170
- console.error("[LIOP-Bridge] ZK-Verifier Failure:", e);
171
+ log.info("[LIOP-Bridge] ZK-Verifier Failure:", e);
171
172
  return false;
172
173
  }
173
174
  }
@@ -221,7 +222,7 @@ export class LiopMcpBridge {
221
222
  terminal: false,
222
223
  });
223
224
  const shutdown = async () => {
224
- console.error("[LIOP-Bridge] Disconnecting session...");
225
+ log.info("[LIOP-Bridge] Disconnecting session...");
225
226
  if (this.liopServer)
226
227
  await this.liopServer.close();
227
228
  process.exit(0);
@@ -240,7 +241,7 @@ export class LiopMcpBridge {
240
241
  }
241
242
  }
242
243
  catch (e) {
243
- console.error(`[LIOP-Bridge] Error: ${e.message}`);
244
+ log.error(`[LIOP-Bridge] Error: ${e.message}`);
244
245
  }
245
246
  });
246
247
  }