network-ai 5.13.4 → 5.15.0

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 (73) hide show
  1. package/INTEGRATION_GUIDE.md +6 -3
  2. package/QUICKSTART.md +9 -4
  3. package/README.md +72 -15
  4. package/SKILL.md +1 -1
  5. package/bin/cli.ts +73 -0
  6. package/bin/mcp-server.ts +24 -1
  7. package/dist/adapters/claude-agent-sdk-adapter.d.ts +100 -0
  8. package/dist/adapters/claude-agent-sdk-adapter.d.ts.map +1 -0
  9. package/dist/adapters/claude-agent-sdk-adapter.js +204 -0
  10. package/dist/adapters/claude-agent-sdk-adapter.js.map +1 -0
  11. package/dist/adapters/gemini-adapter.d.ts +124 -0
  12. package/dist/adapters/gemini-adapter.d.ts.map +1 -0
  13. package/dist/adapters/gemini-adapter.js +239 -0
  14. package/dist/adapters/gemini-adapter.js.map +1 -0
  15. package/dist/adapters/index.d.ts +6 -0
  16. package/dist/adapters/index.d.ts.map +1 -1
  17. package/dist/adapters/index.js +10 -1
  18. package/dist/adapters/index.js.map +1 -1
  19. package/dist/adapters/openai-responses-adapter.d.ts +119 -0
  20. package/dist/adapters/openai-responses-adapter.d.ts.map +1 -0
  21. package/dist/adapters/openai-responses-adapter.js +235 -0
  22. package/dist/adapters/openai-responses-adapter.js.map +1 -0
  23. package/dist/bin/cli.js +72 -0
  24. package/dist/bin/cli.js.map +1 -1
  25. package/dist/bin/mcp-server.js +22 -1
  26. package/dist/bin/mcp-server.js.map +1 -1
  27. package/dist/esm/adapters/claude-agent-sdk-adapter.js +204 -0
  28. package/dist/esm/adapters/claude-agent-sdk-adapter.js.map +1 -0
  29. package/dist/esm/adapters/gemini-adapter.js +239 -0
  30. package/dist/esm/adapters/gemini-adapter.js.map +1 -0
  31. package/dist/esm/adapters/index.js +10 -1
  32. package/dist/esm/adapters/index.js.map +1 -1
  33. package/dist/esm/adapters/openai-responses-adapter.js +235 -0
  34. package/dist/esm/adapters/openai-responses-adapter.js.map +1 -0
  35. package/dist/esm/index.js +20 -5
  36. package/dist/esm/index.js.map +1 -1
  37. package/dist/esm/lib/a2a-server.js +293 -0
  38. package/dist/esm/lib/a2a-server.js.map +1 -0
  39. package/dist/esm/lib/claude-hooks.js +307 -0
  40. package/dist/esm/lib/claude-hooks.js.map +1 -0
  41. package/dist/esm/lib/context-composer.js +332 -0
  42. package/dist/esm/lib/context-composer.js.map +1 -0
  43. package/dist/esm/lib/mcp-elicitation.js +198 -0
  44. package/dist/esm/lib/mcp-elicitation.js.map +1 -0
  45. package/dist/esm/lib/mcp-tools-context.js +266 -0
  46. package/dist/esm/lib/mcp-tools-context.js.map +1 -0
  47. package/dist/index.d.ts +10 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +20 -5
  50. package/dist/index.js.map +1 -1
  51. package/dist/lib/a2a-server.d.ts +120 -0
  52. package/dist/lib/a2a-server.d.ts.map +1 -0
  53. package/dist/lib/a2a-server.js +293 -0
  54. package/dist/lib/a2a-server.js.map +1 -0
  55. package/dist/lib/claude-hooks.d.ts +150 -0
  56. package/dist/lib/claude-hooks.d.ts.map +1 -0
  57. package/dist/lib/claude-hooks.js +307 -0
  58. package/dist/lib/claude-hooks.js.map +1 -0
  59. package/dist/lib/context-composer.d.ts +187 -0
  60. package/dist/lib/context-composer.d.ts.map +1 -0
  61. package/dist/lib/context-composer.js +332 -0
  62. package/dist/lib/context-composer.js.map +1 -0
  63. package/dist/lib/mcp-elicitation.d.ts +116 -0
  64. package/dist/lib/mcp-elicitation.d.ts.map +1 -0
  65. package/dist/lib/mcp-elicitation.js +198 -0
  66. package/dist/lib/mcp-elicitation.js.map +1 -0
  67. package/dist/lib/mcp-tools-context.d.ts +77 -0
  68. package/dist/lib/mcp-tools-context.d.ts.map +1 -0
  69. package/dist/lib/mcp-tools-context.js +266 -0
  70. package/dist/lib/mcp-tools-context.js.map +1 -0
  71. package/package.json +2 -2
  72. package/scripts/clawhub-publish.js +14 -1
  73. package/socket.json +1 -1
@@ -64,7 +64,7 @@ Answers drive `AuthGuardian` configuration and audit log retention policy.
64
64
 
65
65
  ## 2. Framework Mapping
66
66
 
67
- Network-AI ships 29 adapters. Map your existing agents to the right one:
67
+ Network-AI ships 32 adapters. Map your existing agents to the right one:
68
68
 
69
69
  | Your Stack | Network-AI Adapter | Notes |
70
70
  |-----------|-------------------|-------|
@@ -89,6 +89,9 @@ Network-AI ships 29 adapters. Map your existing agents to the right one:
89
89
  | GitHub Copilot | `CopilotAdapter` | Code generate/review/explain/fix/test/refactor/chat |
90
90
  | Anthropic Computer Use | `AnthropicComputerUseAdapter` | Screenshot/click/type/scroll browser automation |
91
91
  | Google Vertex AI / Gemini | `VertexAIAdapter` | Function calling, multi-modal (text+image) |
92
+ | Google Gemini (Developer API) | `GeminiAdapter` | Gemini 2.5 models, system instructions, thinking budgets (BYOC or `GEMINI_API_KEY`) |
93
+ | OpenAI Responses API | `OpenAIResponsesAdapter` | Assistants successor — reasoning effort, instructions (BYOC or `OPENAI_API_KEY`) |
94
+ | Claude Agent SDK | `ClaudeAgentSDKAdapter` | Full agentic loops (tools, file edits) as swarm agents (BYOC `query`) |
92
95
  | Pydantic AI | `PydanticAIAdapter` | Structured output with validation, deps injection |
93
96
  | Browser automation | `BrowserAgentAdapter` | Playwright/Puppeteer/CDP browser control |
94
97
  | NousResearch Hermes / OpenAI-compatible | `HermesAdapter` | Ollama, Together AI, Fireworks, llama.cpp |
@@ -496,7 +499,7 @@ Run these before declaring the integration production-ready:
496
499
  - [ ] `npx ts-node test-phase4.ts` — 147 behavioral tests pass
497
500
  - [ ] `npx ts-node test-qa.ts` — 67 QA orchestrator tests pass
498
501
  - [ ] `npx ts-node test-phase7.ts` — 94 Phase 7 tests pass (hooks, flow control, composer, semantic search)
499
- - [ ] `npm run test:all` — all 3,388 tests pass across 38 suites
502
+ - [ ] `npm run test:all` — all 3,603 tests pass across 40 suites
500
503
  - [ ] `npm run demo -- --08` runs to completion in < 10 seconds
501
504
 
502
505
  ### Race Condition Safety
@@ -554,7 +557,7 @@ Run these before declaring the integration production-ready:
554
557
  |----------|---------------|
555
558
  | [QUICKSTART.md](QUICKSTART.md) | Get running in 5 minutes |
556
559
  | [QUICKSTART.md § CLI](QUICKSTART.md) | CLI reference — bb, auth, budget, audit commands |
557
- | [references/adapter-system.md](references/adapter-system.md) | All 29 adapters with code examples |
560
+ | [references/adapter-system.md](references/adapter-system.md) | All 32 adapters with code examples |
558
561
  | [references/trust-levels.md](references/trust-levels.md) | Trust scoring formula and agent roles |
559
562
  | [references/auth-guardian.md](references/auth-guardian.md) | Permission system, justification scoring, token lifecycle |
560
563
  | [references/blackboard-schema.md](references/blackboard-schema.md) | Blackboard key conventions and namespacing |
package/QUICKSTART.md CHANGED
@@ -18,7 +18,7 @@ npm install
18
18
  npx ts-node setup.ts --check
19
19
  ```
20
20
 
21
- **Zero external AI dependencies.** All 29 adapters are self-contained — add framework SDKs only when you need them.
21
+ **Zero external AI dependencies.** All 32 adapters are self-contained — add framework SDKs only when you need them.
22
22
 
23
23
  ---
24
24
 
@@ -49,6 +49,9 @@ npx ts-node setup.ts --check
49
49
  | `anthropic-computer-use` | Anthropic Computer Use | `@anthropic-ai/sdk` | Screenshot/click/type/scroll automation |
50
50
  | `openai-agents` | OpenAI Agents SDK | `openai` | Tool use, handoffs, guardrails |
51
51
  | `vertex-ai` | Vertex AI / Gemini | `@google-cloud/vertexai` | Function calling, multi-modal |
52
+ | `gemini` | Gemini Developer API | none | Google AI Studio models, thinking budgets |
53
+ | `openai-responses` | OpenAI Responses API | none | GPT-5.x / o-series via `/v1/responses` (Assistants successor) |
54
+ | `claude-agent-sdk` | Claude Agent SDK | `@anthropic-ai/claude-agent-sdk` | Full agentic loops as swarm agents |
52
55
  | `pydantic-ai` | Pydantic AI | none | Structured output with validation |
53
56
  | `browser-agent` | Browser Automation | none | Playwright/Puppeteer/CDP browser control |
54
57
  | `hermes` | NousResearch Hermes / OpenAI-compatible | none | Ollama, Together AI, Fireworks, llama.cpp |
@@ -255,7 +258,7 @@ export class MyFrameworkAdapter extends BaseAdapter {
255
258
  ```bash
256
259
  npx ts-node test-standalone.ts # 88 core tests
257
260
  npx ts-node test-security.ts # 34 security tests
258
- npx ts-node test-adapters.ts # 218 adapter tests (all 29 frameworks)
261
+ npx ts-node test-adapters.ts # 271 adapter tests (all 32 frameworks)
259
262
  npx ts-node test-cli.ts # 65 CLI tests
260
263
  npx ts-node test-qa.ts # 67 QA orchestrator tests
261
264
  ```
@@ -266,7 +269,7 @@ npx ts-node test-qa.ts # 67 QA orchestrator tests
266
269
 
267
270
  ```bash
268
271
  npx ts-node setup.ts --check # Verify installation
269
- npx ts-node setup.ts --list # List all 29 adapters
272
+ npx ts-node setup.ts --list # List adapter quick-start snippets
270
273
  npx ts-node setup.ts --example # Generate example.ts
271
274
  ```
272
275
 
@@ -495,11 +498,13 @@ Your App
495
498
  ├── HaystackAdapter ─── Haystack pipelines
496
499
  ├── DSPyAdapter ─── DSPy modules
497
500
  ├── AgnoAdapter ─── Agno agents/teams
498
- ├── AgnoAdapter ─── Agno agents/teams
499
501
  ├── APSAdapter ─── APS delegation-chain trust
500
502
  ├── CopilotAdapter ─── GitHub Copilot
501
503
  ├── LangGraphAdapter ─── LangGraph state graphs
502
504
  ├── VertexAIAdapter ─── Vertex AI / Gemini
505
+ ├── GeminiAdapter ─── Gemini Developer API
506
+ ├── OpenAIResponsesAdapter ── OpenAI Responses API
507
+ ├── ClaudeAgentSDKAdapter ─── Claude Agent SDK loops
503
508
  ├── PydanticAIAdapter ─── Pydantic AI structured output
504
509
  ├── OpenAIAgentsAdapter ─── OpenAI Agents SDK
505
510
  ├── AnthropicComputerUseAdapter ─── Computer Use
package/README.md CHANGED
@@ -5,10 +5,10 @@
5
5
  [![Website](https://img.shields.io/badge/website-network--ai.org-4b9df2?style=flat&logo=web&logoColor=white)](https://network-ai.org/)
6
6
  [![CI](https://github.com/Jovancoding/Network-AI/actions/workflows/ci.yml/badge.svg)](https://github.com/Jovancoding/Network-AI/actions/workflows/ci.yml)
7
7
  [![CodeQL](https://github.com/Jovancoding/Network-AI/actions/workflows/codeql.yml/badge.svg)](https://github.com/Jovancoding/Network-AI/actions/workflows/codeql.yml)
8
- [![Release](https://img.shields.io/badge/release-v5.13.4-blue.svg)](https://github.com/Jovancoding/Network-AI/releases)
8
+ [![Release](https://img.shields.io/badge/release-v5.15.0-blue.svg)](https://github.com/Jovancoding/Network-AI/releases)
9
9
  [![npm](https://img.shields.io/npm/dw/network-ai.svg?label=npm%20downloads)](https://www.npmjs.com/package/network-ai)
10
- [![Tests](https://img.shields.io/badge/tests-3388%20passing-brightgreen.svg)](#testing)
11
- [![Adapters](https://img.shields.io/badge/frameworks-29%20supported-blueviolet.svg)](#adapter-system)
10
+ [![Tests](https://img.shields.io/badge/tests-3603%20passing-brightgreen.svg)](#testing)
11
+ [![Adapters](https://img.shields.io/badge/frameworks-32%20supported-blueviolet.svg)](#adapter-system)
12
12
  [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE)
13
13
  [![Socket](https://socket.dev/api/badge/npm/package/network-ai)](https://socket.dev/npm/package/network-ai/overview)
14
14
  [![Node.js](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg)](https://nodejs.org)
@@ -31,7 +31,8 @@ Network-AI is a TypeScript/Node.js multi-agent orchestrator that adds coordinati
31
31
 
32
32
  - **Shared blackboard with locking** — atomic `propose → validate → commit` prevents race conditions and split-brain failures across parallel agents
33
33
  - **Guardrails and budgets** — FSM governance, per-agent token ceilings, HMAC / Ed25519 audit trails, and permission gating
34
- - **29 adapters** — LangChain (+ streaming), AutoGen, CrewAI, OpenAI Assistants, LlamaIndex, Semantic Kernel, Haystack, DSPy, Agno, MCP, Custom (+ streaming), OpenClaw, A2A, Codex, MiniMax, NemoClaw, APS, Copilot, LangGraph, Anthropic Computer Use, OpenAI Agents SDK, Vertex AI, Pydantic AI, Browser Agent, Hermes (NousResearch Hermes / any OpenAI-compatible endpoint), Orchestrator (hierarchical multi-orchestrator), and RLM (Recursive Language Model / any RLM-compatible HTTP endpoint) no glue code, no lock-in
34
+ - **Context signal-over-noise (v5.15)** `ContextComposer` assembles token-budgeted, relevance-ranked context packs (semantic/lexical × recency decay × scope affinity, position-aware layout); `context_pack` + `blackboard_search` MCP tools let agents pull curated state instead of dumping the whole board into their window
35
+ - **32 adapters** — LangChain (+ streaming), AutoGen, CrewAI, OpenAI Assistants, OpenAI Responses (Assistants successor), LlamaIndex, Semantic Kernel, Haystack, DSPy, Agno, MCP, Custom (+ streaming), OpenClaw, A2A, Codex, MiniMax, NemoClaw, APS, Copilot, LangGraph, Anthropic Computer Use, Claude Agent SDK (agentic loops), OpenAI Agents SDK, Vertex AI, Gemini (Developer API), Pydantic AI, Browser Agent, Hermes (NousResearch Hermes / any OpenAI-compatible endpoint), Orchestrator (hierarchical multi-orchestrator), and RLM (Recursive Language Model / any RLM-compatible HTTP endpoint) — no glue code, no lock-in
35
36
  - **Persistent project memory (Layer 3)** — `context_manager.py` injects decisions, goals, stack, milestones, and banned patterns into every system prompt so agents always have full project context
36
37
  - **v5.0 modules** — Agent VCR (record/replay), comparison runner, coverage reporter, goal DSL, approval inbox, job queue, gRPC/HTTP transport, playground REPL, adapter test harness, and more
37
38
  - **Model-interaction lifecycle governance (v5.13)** — `GovernedModelGateway` absorbs the model refusal → fallback → billing chain (cross-model fallback, fallback-credit repricing, effort governance, thinking-block handoff) behind one governed, budgeted, audited call
@@ -46,6 +47,8 @@ Network-AI is a TypeScript/Node.js multi-agent orchestrator that adds coordinati
46
47
  - A **TypeScript/Node.js library** — `import { createSwarmOrchestrator } from 'network-ai'`
47
48
  - An **MCP server** — `npx network-ai-server --port 3001`
48
49
  - A **CLI** — `network-ai bb get status` / `network-ai audit tail`
50
+ - A **Claude Code plugin** — `/plugin install network-ai@network-ai`
51
+ - A **Gemini CLI extension** — `gemini extensions install https://github.com/Jovancoding/Network-AI`
49
52
  - An **OpenClaw skill** — `clawhub install network-ai`
50
53
 
51
54
  [**5-minute quickstart →**](QUICKSTART.md) &nbsp;|&nbsp; [**Architecture →**](ARCHITECTURE.md) &nbsp;|&nbsp; [**All adapters →**](#adapter-system) &nbsp;|&nbsp; [**Benchmarks →**](BENCHMARKS.md)
@@ -143,7 +146,7 @@ Runs priority preemption, AuthGuardian permission gating, FSM governance, and co
143
146
  | ✅ Token budgets | Hard per-agent ceilings with live spend tracking |
144
147
  | ✅ Permission gating | HMAC / Ed25519-signed tokens, scoped per agent and resource |
145
148
  | ✅ Append-only audit log | Every write, grant, and transition signed and logged |
146
- | ✅ 29 framework adapters | LangChain, CrewAI, AutoGen, MCP, Codex, APS, RLM, and 22 more — zero lock-in |
149
+ | ✅ 32 framework adapters | LangChain, CrewAI, AutoGen, MCP, Codex, Gemini, APS, RLM, and 24 more — zero lock-in |
147
150
  | ✅ FSM governance | Hard-stop agents at state boundaries, timeout enforcement |
148
151
  | ✅ Compliance monitoring | Real-time violation detection (tool abuse, turn-taking, timeouts) |
149
152
  | ✅ Claim verification | Tier 1 agent honesty — outcome-bound signed receipts, manifest reconciliation, trust decay for liars |
@@ -193,7 +196,7 @@ Runs priority preemption, AuthGuardian permission gating, FSM governance, and co
193
196
  | Race conditions in parallel agents | Atomic blackboard: `propose → validate → commit` with file-system mutex |
194
197
  | Agent overspend / runaway costs | `FederatedBudget` — hard per-agent token ceilings with live spend tracking |
195
198
  | No visibility into what agents did | HMAC / Ed25519-signed audit log on every write, permission grant, and FSM transition |
196
- | Locked into one AI framework | 29 adapters — mix LangChain + AutoGen + CrewAI + Codex + MiniMax + NemoClaw + APS + LangGraph + Vertex AI + Hermes + RLM + custom in one swarm |
199
+ | Locked into one AI framework | 32 adapters — mix LangChain + AutoGen + CrewAI + Codex + Gemini + MiniMax + NemoClaw + APS + LangGraph + Vertex AI + Hermes + RLM + custom in one swarm |
197
200
  | Agents escalating beyond their scope | `AuthGuardian` — scoped permission tokens required before sensitive operations |
198
201
  | Agents lack project context between runs | `ProjectContextManager` (Layer 3) — inject decisions, goals, stack, and milestones into every system prompt |
199
202
  | No regression tracking on agent output quality | `QAOrchestratorAgent` — scenario replay, feedback loops, cross-agent contradiction detection, historical trend tracking |
@@ -297,6 +300,8 @@ curl http://localhost:3001/tools # full tool list
297
300
 
298
301
  **Tools exposed over MCP:**
299
302
  - `blackboard_read` / `blackboard_write` / `blackboard_list` / `blackboard_delete` / `blackboard_exists`
303
+ - `context_pack` — token-budgeted, relevance-ranked context brief for a task (use instead of dumping the whole board into your window)
304
+ - `blackboard_search` — ranked top-K search over blackboard entries (semantic when an embedder is wired, lexical otherwise)
300
305
  - `budget_status` / `budget_spend` / `budget_reset` — federated token tracking
301
306
  - `token_create` / `token_validate` / `token_revoke` — HMAC / Ed25519-signed permission tokens
302
307
  - `audit_query` — query the append-only audit log
@@ -330,9 +335,27 @@ The repo root carries the standard plugin layout:
330
335
  | [`.claude-plugin/plugin.json`](.claude-plugin/plugin.json) | Plugin manifest |
331
336
  | [`.mcp.json`](.mcp.json) | Registers the Network-AI MCP server (stdio) |
332
337
  | [`.claude-plugin/marketplace.json`](.claude-plugin/marketplace.json) | Self-hosted marketplace catalog |
338
+ | [`commands/`](commands/status.md) | Slash commands — `/network-ai:status`, `/network-ai:budget`, `/network-ai:audit`, `/network-ai:blackboard` |
333
339
 
334
340
  Validate the manifests locally with `claude plugin validate .`.
335
341
 
342
+ **Gate Claude Code itself with AuthGuardian (hooks).** Every tool call Claude Code makes — shell commands, file edits, web fetches — can be audited and permission-gated through the same weighted scoring (justification 40%, trust 30%, risk 30%) Network-AI applies to swarm agents:
343
+
344
+ ```jsonc
345
+ // .claude/settings.json — see examples/claude-code-hooks.json for the full config
346
+ {
347
+ "hooks": {
348
+ "PreToolUse": [{
349
+ "matcher": "Bash|Write|Edit|WebFetch",
350
+ "hooks": [{ "type": "command",
351
+ "command": "npx -y -p network-ai network-ai hook pre-tool-use --mode enforce" }]
352
+ }]
353
+ }
354
+ }
355
+ ```
356
+
357
+ `--mode observe` (default) audits every call to `data/hooks_audit.jsonl` without blocking; `--mode enforce` maps tools to resource types (Bash → `SHELL_EXEC`, Write/Edit → `FILE_SYSTEM`, WebFetch → `EXTERNAL_SERVICE`) and requires an AuthGuardian grant — denied calls escalate to you as an interactive prompt. `--deny "rm -rf"` patterns hard-block regardless of mode.
358
+
336
359
  ---
337
360
 
338
361
  ## Use with OpenAI Codex
@@ -359,6 +382,35 @@ Either route exposes the full tool set (`blackboard_read`, `budget_status`, `aud
359
382
 
360
383
  ---
361
384
 
385
+ ## Use with Gemini CLI
386
+
387
+ Network-AI ships as a [Gemini CLI](https://github.com/google-gemini/gemini-cli) extension — the repo root carries [`gemini-extension.json`](gemini-extension.json), which wires in the stdio MCP server and a [`GEMINI.md`](GEMINI.md) context file automatically:
388
+
389
+ ```bash
390
+ gemini extensions install https://github.com/Jovancoding/Network-AI
391
+ ```
392
+
393
+ Or register just the MCP server directly:
394
+
395
+ ```bash
396
+ gemini mcp add network-ai npx -- -y -p network-ai network-ai-server --stdio
397
+ ```
398
+
399
+ Run `/mcp` inside Gemini CLI to confirm the `network-ai` tools are loaded. For building Gemini-powered swarm agents, use the `GeminiAdapter` (Gemini Developer API / AI Studio) or `VertexAIAdapter` (Vertex AI on GCP) — and for Google's Agent2Agent ecosystem, `A2AServer` exposes this orchestrator as a discoverable A2A agent:
400
+
401
+ ```typescript
402
+ import { A2AServer } from 'network-ai';
403
+
404
+ const a2a = new A2AServer({
405
+ name: 'Network-AI Orchestrator',
406
+ secret: process.env.A2A_SECRET,
407
+ executor: async (text) => ({ text: await runSwarmTask(text) }),
408
+ });
409
+ a2a.startServer(4310); // serves /.well-known/agent.json + tasks/send
410
+ ```
411
+
412
+ ---
413
+
362
414
  ## CLI
363
415
 
364
416
  Control Network-AI directly from the terminal — no server required. The CLI imports the same core engine used by the MCP server.
@@ -467,7 +519,7 @@ npx ts-node examples/10-nemoclaw-sandbox-swarm.ts
467
519
 
468
520
  ## Adapter System
469
521
 
470
- 29 adapters, zero adapter dependencies. You bring your own SDK objects.
522
+ 32 adapters, zero adapter dependencies. You bring your own SDK objects.
471
523
 
472
524
  | Adapter | Framework / Protocol | Register method |
473
525
  |---|---|---|
@@ -532,7 +584,7 @@ Extend `BaseAdapter` (or `StreamingBaseAdapter` for streaming) to add your own i
532
584
  npm run test:all # All suites in sequence
533
585
  npm test # Core orchestrator
534
586
  npm run test:security # Security module
535
- npm run test:adapters # All 29 adapters
587
+ npm run test:adapters # All 32 adapters
536
588
  npm run test:streaming # Streaming adapters
537
589
  npm run test:a2a # A2A protocol adapter
538
590
  npm run test:codex # Codex adapter
@@ -542,15 +594,15 @@ npm run test:phase9 # Agent runtime, console, strategy agent
542
594
  npm run test:phase12 # Context Throttler, Partition Planner, Coverage Gate, Route Classifier
543
595
  ```
544
596
 
545
- **3,388 passing assertions across 38 test suites** (`npm run test:all`):
597
+ **3,603 passing assertions across 40 test suites** (`npm run test:all`):
546
598
 
547
599
  | Suite | Assertions | Covers |
548
600
  |---|---|---|
549
601
  | `test-phase4.ts` | 147 | FSM governance, compliance monitor, adapter integration |
550
602
  | `test-phase5f.ts` | 127 | SSE transport, `McpCombinedBridge`, extended MCP tools |
551
603
  | `test-phase5g.ts` | 121 | CRDT backend, vector clocks, bidirectional sync |
552
- | `test-phase6.ts` | 121 | MCP server, control-plane tools, audit tools |
553
- | `test-adapters.ts` | 218 | All 29 adapters, registry routing, integration, edge cases |
604
+ | `test-phase6.ts` | 129 | MCP server, control-plane tools, audit tools |
605
+ | `test-adapters.ts` | 271 | All 32 adapters, registry routing, integration, edge cases |
554
606
  | `test-phase5d.ts` | 117 | Pluggable backend (Redis, CRDT, Memory) |
555
607
  | `test-standalone.ts` | 88 | Blackboard, auth, integration, persistence, parallelisation, quality gate |
556
608
  | `test-phase5e.ts` | 87 | Federated budget tracking |
@@ -568,9 +620,9 @@ npm run test:phase12 # Context Throttler, Partition Planner, Coverage Gate,
568
620
  | `test-qa.ts` | 67 | QA orchestrator: scenarios, feedback loop, regression, contradictions |
569
621
  | `test-phase7.ts` | 94 | Deferred init, hook middleware, flow control, skill composer, semantic search |
570
622
  | `test-phase8.ts` | 146 | Phase pipeline, confidence filter, matcher-based hooks, fan-out/fan-in |
571
- | `test-phase9.ts` | 280 | Agent runtime, sandbox policy, shell executor, file accessor, approval gate, console UI, orchestrator wiring, pipe mode, strategy agent |
623
+ | `test-phase9.ts` | 293 | Agent runtime, sandbox policy, shell executor, file accessor, approval gate, console UI, orchestrator wiring, pipe mode, strategy agent |
572
624
  | `test-phase10.ts` | 153 | Goal decomposer, task DAG validation, topological layers, JSON parsing, team runner, concurrency, timeouts, events, runTeam one-liner, dependency injection, LLM planner |
573
- | `test-phase11.ts` | 43 | TTL background sweep, WAL crash recovery, CircuitBreaker, `ITelemetryProvider` / OTel hooks |
625
+ | `test-phase11.ts` | 55 | TTL background sweep, WAL crash recovery, CircuitBreaker, `ITelemetryProvider` / OTel hooks |
574
626
  | `test-topology.ts` | 304 | WorkTree, ControlPlane, dashboard server, topology visualization, WebSocket protocol |
575
627
  | `test-rlm-phases.ts` | 123 | FederatedBudget child spending, blackboard metadata API, best-partial result, HookContext depth, sub-goal recursion, semaphore fan-out, PhasePipeline compaction, RLMAdapter end-to-end |
576
628
  | `test-phase12.ts` | 65 | Context Throttler, Partition Planner, Coverage Gate, Route Classifier, EVALUATING FSM state, runTeam integration |
@@ -582,6 +634,8 @@ npm run test:phase12 # Context Throttler, Partition Planner, Coverage Gate,
582
634
  | `test-phase15.ts` | 32 | Orchestration resilience: `RetryBudget`, per-sub-agent fallback in `FanOutFanIn` + `TeamRunner`, `EffortPolicy` |
583
635
  | `test-phase16.ts` | 21 | `ThinkingBlockManager` lifecycle + reasoning-extraction guard, OWASP Agentic Top 10 coverage matrix |
584
636
  | `test-phase17.ts` | 13 | `ApprovalInbox` GHSA-m4jg-6w3q-gm86 fix: read-route auth gating, token validation, backward compatibility, CORS allowlist |
637
+ | `test-phase18.ts` | 85 | `ClaudeHookBridge` observe/enforce gating, MCP elicitation channel + fail-closed approval callback, `A2AServer` agent card / tasks / auth / eviction |
638
+ | `test-phase19.ts` | 78 | `ContextComposer` ranking/budget/pinning/staleness/layout, `estimateTokens`, `context_pack` + `blackboard_search` MCP tools (lexical + semantic modes) |
585
639
  | `test.ts` | 39 | Core orchestrator smoke tests |
586
640
 
587
641
  ---
@@ -600,9 +654,10 @@ npm run test:phase12 # Context Throttler, Partition Planner, Coverage Gate,
600
654
  | [ENTERPRISE.md](ENTERPRISE.md) | Evaluation checklist, stability policy, security summary, integration entry points |
601
655
  | [AUDIT_LOG_SCHEMA.md](AUDIT_LOG_SCHEMA.md) | Audit log field reference, all event types (including `model.refusal` / `model.attempt`), scoring formula |
602
656
  | [ADOPTERS.md](ADOPTERS.md) | Known adopters — open a PR to add yourself |
603
- | [INTEGRATION_GUIDE.md](INTEGRATION_GUIDE.md) | End-to-end integration walkthrough with v5.13 modules |
657
+ | [INTEGRATION_GUIDE.md](INTEGRATION_GUIDE.md) | End-to-end integration walkthrough with v5.15 modules |
604
658
  | [SKILL.md](SKILL.md) | OpenClaw/ClawHub Python skill — setup, orchestrator protocol, OWASP engine coverage, security scan findings |
605
- | [references/adapter-system.md](references/adapter-system.md) | Adapter architecture, all 29 adapters (incl. `AnthropicMessagesAdapter`), writing custom adapters |
659
+ | [AGENTS.md](AGENTS.md) | Cross-vendor agent instructions (Codex, Gemini CLI, Cursor, Factory) — build commands, conventions, architecture patterns |
660
+ | [references/adapter-system.md](references/adapter-system.md) | Adapter architecture, all 32 adapters (incl. `AnthropicMessagesAdapter`), writing custom adapters |
606
661
  | [references/auth-guardian.md](references/auth-guardian.md) | Permission scoring, resource types, `scoreRequest()`, IAuthValidator interface |
607
662
  | [references/trust-levels.md](references/trust-levels.md) | Trust level configuration, APS delegation-chain mapping |
608
663
 
@@ -613,6 +668,8 @@ npm run test:phase12 # Context Throttler, Partition Planner, Coverage Gate,
613
668
  > Using **Claude Code** (the CLI)? See [Use as a Claude Code Plugin](#use-as-a-claude-code-plugin) — one command installs every tool.
614
669
  >
615
670
  > Using **OpenAI Codex** (CLI or IDE)? See [Use with OpenAI Codex](#use-with-openai-codex) — add the MCP server with a single `codex mcp add`.
671
+ >
672
+ > Using **Gemini CLI**? See [Use with Gemini CLI](#use-with-gemini-cli) — install the extension with a single `gemini extensions install`.
616
673
 
617
674
  Three integration files are included in the repo root:
618
675
 
package/SKILL.md CHANGED
@@ -767,7 +767,7 @@ The following findings are drawn from the **MAESTRO Agent Security Threat** fram
767
767
 
768
768
  | Control | How Network-AI addresses it |
769
769
  |---|---|
770
- | **Exact version pinning** | npm `package.json` uses exact `"version": "5.13.4"` — no semver range specifiers; `clawhub install network-ai` pins to a specific published version |
770
+ | **Exact version pinning** | npm `package.json` uses exact `"version": "5.15.0"` — no semver range specifiers; `clawhub install network-ai` pins to a specific published version |
771
771
  | **Zero transitive dependency drift** | All bundled Python scripts use Python stdlib only — `pip install` is never required; there are no third-party packages to drift, be compromised upstream, or introduce CVEs |
772
772
  | **Signed, tagged releases** | Every release is committed with a signed Git tag (`v5.7.x`); commit hash is verifiable against CHANGELOG.md; GitHub releases link tag → diff → changelog entry |
773
773
  | **Supply chain monitoring** | npm package continuously scored by Socket.dev (score A); any new dependency or permission change triggers an alert |
package/bin/cli.ts CHANGED
@@ -17,6 +17,7 @@ import { LockedBlackboard } from '../lib/locked-blackboard';
17
17
  import { AuthGuardian } from '../index';
18
18
  import { FederatedBudget } from '../lib/federated-budget';
19
19
  import { EnvironmentManager } from '../lib/env-manager';
20
+ import { ClaudeHookBridge } from '../lib/claude-hooks';
20
21
 
21
22
  // eslint-disable-next-line @typescript-eslint/no-var-requires
22
23
  const pkg = (() => {
@@ -695,6 +696,78 @@ program.command('inspect <key>')
695
696
  }
696
697
  });
697
698
 
699
+ // ── hook (coding-agent hooks bridge) ──────────────────────────────────────────
700
+
701
+ function readStdinFully(): Promise<string> {
702
+ return new Promise((resolvePromise, rejectPromise) => {
703
+ let data = '';
704
+ process.stdin.setEncoding('utf8');
705
+ process.stdin.on('data', (chunk: string) => { data += chunk; });
706
+ process.stdin.on('end', () => resolvePromise(data));
707
+ process.stdin.on('error', rejectPromise);
708
+ });
709
+ }
710
+
711
+ const hookCmd = program.command('hook')
712
+ .description('Coding-agent hook bridge — audit/gate tool calls through AuthGuardian (Claude Code PreToolUse/PostToolUse)');
713
+
714
+ hookCmd.command('pre-tool-use')
715
+ .description('Handle a PreToolUse hook event: reads hook JSON from stdin, writes a permission decision to stdout')
716
+ .option('--mode <mode>', "'observe' (audit only) or 'enforce' (AuthGuardian-gated)", process.env['NETWORK_AI_HOOKS_MODE'] ?? 'observe')
717
+ .option('--agent <id>', 'agent identity for permission requests', 'claude-code')
718
+ .option('--trust <level>', 'trust level for the agent identity (0-1)', (v: string) => parseFloat(v), 0.7)
719
+ .option('--deny <pattern...>', 'regex pattern(s) — matching tool calls are denied outright')
720
+ .option('--allow <pattern...>', 'regex pattern(s) — matching tool calls are allowed without gating')
721
+ .option('--blocked-decision <decision>', "decision when the guardian denies: 'ask' (escalate to human) or 'deny'", 'ask')
722
+ .action(async (opts: { mode: string; agent: string; trust: number; deny?: string[]; allow?: string[]; blockedDecision: string }, cmd: Command) => {
723
+ const g = cmd.optsWithGlobals<{ data: string; json: boolean }>();
724
+ if (opts.mode !== 'observe' && opts.mode !== 'enforce') die(`invalid --mode: ${opts.mode} (use observe|enforce)`);
725
+ if (opts.blockedDecision !== 'ask' && opts.blockedDecision !== 'deny') die(`invalid --blocked-decision: ${opts.blockedDecision} (use ask|deny)`);
726
+ const dataDir = resolveData(g);
727
+ const bridge = new ClaudeHookBridge({
728
+ mode: opts.mode,
729
+ agentId: opts.agent,
730
+ trustLevel: opts.trust,
731
+ denyPatterns: opts.deny,
732
+ allowPatterns: opts.allow,
733
+ blockedDecision: opts.blockedDecision,
734
+ auditLogPath: path.join(dataDir, 'hooks_audit.jsonl'),
735
+ guardianAuditLogPath: path.join(dataDir, 'audit_log.jsonl'),
736
+ trustConfigPath: path.join(dataDir, 'trust_levels.json'),
737
+ });
738
+ try {
739
+ const raw = await readStdinFully();
740
+ const input = ClaudeHookBridge.parseInput(raw);
741
+ const out = await bridge.handlePreToolUse(input);
742
+ process.stdout.write(JSON.stringify(out) + '\n');
743
+ } catch (err) {
744
+ process.stderr.write(`network-ai hook: ${err instanceof Error ? err.message : String(err)}\n`);
745
+ process.exit(1);
746
+ }
747
+ });
748
+
749
+ hookCmd.command('post-tool-use')
750
+ .description('Handle a PostToolUse hook event: reads hook JSON from stdin, appends an audit entry')
751
+ .option('--agent <id>', 'agent identity recorded in the audit trail', 'claude-code')
752
+ .action(async (opts: { agent: string }, cmd: Command) => {
753
+ const g = cmd.optsWithGlobals<{ data: string; json: boolean }>();
754
+ const dataDir = resolveData(g);
755
+ const bridge = new ClaudeHookBridge({
756
+ mode: 'observe',
757
+ agentId: opts.agent,
758
+ auditLogPath: path.join(dataDir, 'hooks_audit.jsonl'),
759
+ });
760
+ try {
761
+ const raw = await readStdinFully();
762
+ const input = ClaudeHookBridge.parseInput(raw);
763
+ const out = await bridge.handlePostToolUse(input);
764
+ process.stdout.write(JSON.stringify(out) + '\n');
765
+ } catch (err) {
766
+ process.stderr.write(`network-ai hook: ${err instanceof Error ? err.message : String(err)}\n`);
767
+ process.exit(1);
768
+ }
769
+ });
770
+
698
771
  // ── pause / resume (kill switch) ──────────────────────────────────────────────
699
772
 
700
773
  program.command('pause')
package/bin/mcp-server.ts CHANGED
@@ -48,6 +48,7 @@ import {
48
48
  import type { McpJsonRpcRequest } from '../lib/mcp-bridge';
49
49
  import { ExtendedMcpTools } from '../lib/mcp-tools-extended';
50
50
  import { ControlMcpTools } from '../lib/mcp-tools-control';
51
+ import { ContextMcpTools } from '../lib/mcp-tools-context';
51
52
 
52
53
  // ============================================================================
53
54
  // ARGUMENT PARSING
@@ -157,6 +158,14 @@ SSE/HTTP mode (for network clients):
157
158
  */
158
159
  async function runStdio(combined: McpCombinedBridge): Promise<void> {
159
160
  const { createInterface } = await import('readline');
161
+ const { StdioElicitationChannel } = await import('../lib/mcp-elicitation');
162
+
163
+ // Server→client request channel (MCP elicitation). Client responses to
164
+ // server-initiated requests are routed here instead of being dispatched
165
+ // (incorrectly) as client requests.
166
+ const elicitation = new StdioElicitationChannel((line: string) => {
167
+ process.stdout.write(line + '\n');
168
+ });
160
169
 
161
170
  const rl = createInterface({ input: process.stdin, terminal: false });
162
171
 
@@ -178,11 +187,17 @@ async function runStdio(combined: McpCombinedBridge): Promise<void> {
178
187
  return;
179
188
  }
180
189
 
190
+ // Response to a server-initiated request (elicitation)? Consume it.
191
+ if (elicitation.handleMessage(request)) return;
192
+
181
193
  const response = await combined.handleRPC(request);
182
194
  process.stdout.write(JSON.stringify(response) + '\n');
183
195
  });
184
196
 
185
- rl.on('close', () => process.exit(0));
197
+ rl.on('close', () => {
198
+ elicitation.rejectAll('stdin closed');
199
+ process.exit(0);
200
+ });
186
201
  }
187
202
 
188
203
  // ============================================================================
@@ -286,6 +301,14 @@ async function main(): Promise<void> {
286
301
  if (extendedTools) combined.register(extendedTools);
287
302
  if (controlTools) combined.register(controlTools);
288
303
 
304
+ // Context tools: token-budgeted context packs + ranked blackboard search
305
+ // (lexical ranking out of the box; embed a SemanticMemory for semantic mode)
306
+ const contextTools = new ContextMcpTools({
307
+ blackboard: blackboard as unknown as import('../lib/mcp-blackboard-tools').IBlackboard,
308
+ });
309
+ combined.register(contextTools);
310
+ console.log(`[network-ai-server] Context tools: context_pack, blackboard_search (lexical mode)`);
311
+
289
312
  const totalTools = combined.allDefinitions().length;
290
313
  console.log(`[network-ai-server] Total tools exposed: ${totalTools}`);
291
314
 
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Claude Agent SDK Adapter
3
+ *
4
+ * Integrates agents built with Anthropic's Claude Agent SDK
5
+ * (`@anthropic-ai/claude-agent-sdk`) with the SwarmOrchestrator. The SDK's
6
+ * `query()` function runs a full agentic loop (tool use, file edits, shell)
7
+ * and streams SDK messages; this adapter drives that loop and returns the
8
+ * final result to the swarm.
9
+ *
10
+ * Strictly BYOC: the SDK is never imported here. Callers pass the SDK's
11
+ * `query` function (or any compatible implementation) at registration time.
12
+ *
13
+ * Usage:
14
+ * import { query } from '@anthropic-ai/claude-agent-sdk';
15
+ *
16
+ * const adapter = new ClaudeAgentSDKAdapter();
17
+ * await adapter.initialize({});
18
+ * adapter.registerAgent('coder', {
19
+ * query, // the SDK's query function
20
+ * options: { maxTurns: 10, allowedTools: ['Read', 'Grep'] },
21
+ * systemPrompt: 'You are a careful refactoring agent.',
22
+ * });
23
+ *
24
+ * await registry.addAdapter(adapter);
25
+ * // orchestrator: delegateTask({ targetAgent: 'claude-agent-sdk:coder', ... })
26
+ *
27
+ * @module ClaudeAgentSDKAdapter
28
+ * @version 1.0.0
29
+ */
30
+ import { BaseAdapter } from './base-adapter';
31
+ import type { AdapterCapabilities, AgentPayload, AgentContext, AgentResult } from '../types/agent-adapter';
32
+ /**
33
+ * A message yielded by the Claude Agent SDK's query loop. Only the fields
34
+ * this adapter consumes are modeled; extra fields pass through untouched.
35
+ */
36
+ export interface ClaudeSDKMessage {
37
+ /** Message kind — 'assistant', 'user', 'system', 'result', ... */
38
+ type: string;
39
+ /** For result messages: 'success' or an error subtype */
40
+ subtype?: string;
41
+ /** For result messages: the final result text */
42
+ result?: string;
43
+ /** Total cost in USD, when reported */
44
+ total_cost_usd?: number;
45
+ /** Number of agentic turns taken */
46
+ num_turns?: number;
47
+ /** Session identifier assigned by the SDK */
48
+ session_id?: string;
49
+ /** Token usage, when reported */
50
+ usage?: Record<string, unknown>;
51
+ /** Whether the run ended in an error */
52
+ is_error?: boolean;
53
+ }
54
+ /**
55
+ * The Claude Agent SDK `query` function shape. Matches
56
+ * `@anthropic-ai/claude-agent-sdk`'s `query({ prompt, options })`, which
57
+ * returns an async iterable of SDK messages.
58
+ */
59
+ export type ClaudeAgentQueryFn = (params: {
60
+ prompt: string;
61
+ options?: Record<string, unknown>;
62
+ }) => AsyncIterable<ClaudeSDKMessage>;
63
+ /** Configuration for a registered Claude Agent SDK agent */
64
+ export interface ClaudeAgentSDKConfig {
65
+ /** The SDK's query function (BYOC — required) */
66
+ query: ClaudeAgentQueryFn;
67
+ /**
68
+ * Options forwarded to the SDK on every run — e.g. `maxTurns`,
69
+ * `allowedTools`, `permissionMode`, `cwd`, `model`.
70
+ */
71
+ options?: Record<string, unknown>;
72
+ /** System prompt override — forwarded as `options.systemPrompt` */
73
+ systemPrompt?: string;
74
+ /**
75
+ * Called for every intermediate SDK message (assistant turns, tool use)
76
+ * before the final result — useful for progress reporting.
77
+ */
78
+ onMessage?: (message: ClaudeSDKMessage) => void;
79
+ }
80
+ /**
81
+ * Adapter that runs Claude Agent SDK agentic loops as swarm agents.
82
+ * The final `result` message becomes the AgentResult; intermediate messages
83
+ * are surfaced through the per-agent `onMessage` callback.
84
+ */
85
+ export declare class ClaudeAgentSDKAdapter extends BaseAdapter {
86
+ readonly name = "claude-agent-sdk";
87
+ readonly version = "1.0.0";
88
+ private agents;
89
+ get capabilities(): AdapterCapabilities;
90
+ /**
91
+ * Register a Claude Agent SDK-powered agent.
92
+ *
93
+ * @param agentId Unique identifier used in `delegateTask` calls.
94
+ * @param config Agent configuration — `query` is required.
95
+ */
96
+ registerAgent(agentId: string, config: ClaudeAgentSDKConfig): void;
97
+ executeAgent(agentId: string, payload: AgentPayload, context: AgentContext): Promise<AgentResult>;
98
+ shutdown(): Promise<void>;
99
+ }
100
+ //# sourceMappingURL=claude-agent-sdk-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-agent-sdk-adapter.d.ts","sourceRoot":"","sources":["../../adapters/claude-agent-sdk-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EACV,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,WAAW,EACZ,MAAM,wBAAwB,CAAC;AAMhC;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC,KAAK,aAAa,CAAC,gBAAgB,CAAC,CAAC;AAEtC,4DAA4D;AAC5D,MAAM,WAAW,oBAAoB;IACnC,iDAAiD;IACjD,KAAK,EAAE,kBAAkB,CAAC;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAC;CACjD;AAuCD;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,WAAW;IACpD,QAAQ,CAAC,IAAI,sBAAsB;IACnC,QAAQ,CAAC,OAAO,WAAW;IAE3B,OAAO,CAAC,MAAM,CAA4C;IAE1D,IAAI,YAAY,IAAI,mBAAmB,CAStC;IAMD;;;;;OAKG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,IAAI;IA6B5D,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,WAAW,CAAC;IA8FjB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAIhC"}