network-ai 3.1.0 → 3.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  **The plug-and-play AI agent orchestrator for TypeScript/Node.js -- connect 12 agent frameworks with zero glue code**
4
4
 
5
- [![Release](https://img.shields.io/badge/release-v3.1.0-blue.svg)](https://github.com/jovanSAPFIONEER/Network-AI/releases)
5
+ [![Release](https://img.shields.io/badge/release-v3.1.2-blue.svg)](https://github.com/jovanSAPFIONEER/Network-AI/releases)
6
+ [![ClawHub](https://img.shields.io/badge/ClawHub-network--ai-orange.svg)](https://clawhub.ai/skills/network-ai)
6
7
  [![Node.js](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg)](https://nodejs.org)
7
8
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-3178C6.svg)](https://typescriptlang.org)
8
9
  [![Python](https://img.shields.io/badge/python-3.9+-green.svg)](https://python.org)
@@ -122,6 +123,7 @@ Network-AI wraps your agent swarm with **file-system mutexes**, **atomic commits
122
123
  ### Security Module (Defense-in-Depth)
123
124
  - **HMAC-Signed Tokens** -- Cryptographic token generation with expiration
124
125
  - **Input Sanitization** -- XSS, injection, path traversal, and prototype pollution prevention
126
+ - **Blackboard Path Safety** -- Change ID sanitization prevents directory traversal in atomic commits
125
127
  - **Rate Limiting** -- Per-agent request throttling with lockout on failed auth
126
128
  - **AES-256-GCM Encryption** -- Encrypt sensitive blackboard entries at rest
127
129
  - **Privilege Escalation Prevention** -- Trust-ceiling enforcement
@@ -229,10 +231,10 @@ Copy this skill into your OpenClaw workspace:
229
231
  cp -r Network-AI ~/.openclaw/workspace/skills/swarm-orchestrator
230
232
  ```
231
233
 
232
- Or install via ClawHub (when available):
234
+ Or install via ClawHub:
233
235
 
234
236
  ```bash
235
- openclaw skills install swarm-orchestrator
237
+ clawhub install network-ai
236
238
  ```
237
239
 
238
240
  ## Usage
@@ -618,6 +620,6 @@ If you're using LangGraph, Dify, Flowise, PraisonAI, AutoGen/AG2, CrewAI, or any
618
620
  <details>
619
621
  <summary>Keywords (for search)</summary>
620
622
 
621
- ai-agents, agentic-ai, multi-agent, multi-agent-systems, multi-agent-system, agent-framework, ai-agent-framework, agentic-framework, agentic-workflow, llm, llm-agents, llm-agent, large-language-models, generative-ai, genai, orchestration, ai-orchestration, swarm, swarm-intelligence, autonomous-agents, agents, ai, typescript, nodejs, mcp, model-context-protocol, a2a, agent-to-agent, function-calling, tool-integration, context-engineering, rag, ai-safety, multi-agents-collaboration, multi-agents, aiagents, aiagentframework, plug-and-play, adapter-registry, blackboard-pattern, agent-coordination, agent-handoffs, token-permissions, budget-tracking, cost-awareness, atomic-commits, hallucination-detection, content-quality-gate, OpenClaw, Clawdbot, Moltbot, Clawdbot Swarm, Moltbot Security, Moltbot multi-agent, OpenClaw skills, AgentSkills, LangChain adapter, LangGraph, AutoGen adapter, AG2, CrewAI adapter, MCP adapter, LlamaIndex adapter, Semantic Kernel adapter, OpenAI Assistants adapter, Haystack adapter, DSPy adapter, Agno adapter, Phidata adapter, Dify, Flowise, PraisonAI, custom-adapter, AES-256 encryption, HMAC tokens, rate limiting, input sanitization, privilege escalation prevention, agentic-rag, deep-research, workflow-orchestration, ai-assistant, ai-tools, developer-tools, open-source
623
+ ai-agents, agentic-ai, multi-agent, multi-agent-systems, multi-agent-system, agent-framework, ai-agent-framework, agentic-framework, agentic-workflow, llm, llm-agents, llm-agent, large-language-models, generative-ai, genai, orchestration, ai-orchestration, swarm, swarm-intelligence, autonomous-agents, agents, ai, typescript, nodejs, mcp, model-context-protocol, a2a, agent-to-agent, function-calling, tool-integration, context-engineering, rag, ai-safety, multi-agents-collaboration, multi-agents, aiagents, aiagentframework, plug-and-play, adapter-registry, blackboard-pattern, agent-coordination, agent-handoffs, token-permissions, budget-tracking, cost-awareness, atomic-commits, hallucination-detection, content-quality-gate, OpenClaw, Clawdbot, Moltbot, Clawdbot Swarm, Moltbot Security, Moltbot multi-agent, OpenClaw skills, AgentSkills, LangChain adapter, LangGraph, AutoGen adapter, AG2, CrewAI adapter, MCP adapter, LlamaIndex adapter, Semantic Kernel adapter, OpenAI Assistants adapter, Haystack adapter, DSPy adapter, Agno adapter, Phidata adapter, Dify, Flowise, PraisonAI, custom-adapter, AES-256 encryption, HMAC tokens, rate limiting, input sanitization, privilege escalation prevention, ClawHub, clawhub, agentic-rag, deep-research, workflow-orchestration, ai-assistant, ai-tools, developer-tools, open-source
622
624
 
623
625
  </details>
package/SKILL.md CHANGED
@@ -1,7 +1,13 @@
1
1
  ---
2
- name: swarm-orchestrator
3
- description: Multi-agent swarm orchestration for complex workflows. Use when coordinating multiple agents, delegating tasks between sessions, managing shared state via blackboard, or enforcing permission walls for DATABASE/PAYMENTS/EMAIL access. Triggers on: agent coordination, task delegation, parallel execution, permission requests, blackboard state management.
4
- metadata: { "openclaw": { "emoji": "🐝", "homepage": "https://github.com/jovanSAPFIONEER/Network-AI" } }
2
+ name: Network-AI
3
+ description: Multi-agent swarm orchestration for complex workflows. Coordinates multiple agents, decomposes tasks, manages shared state via a local blackboard file, and enforces permission walls before sensitive operations. All execution is local and sandboxed.
4
+ metadata:
5
+ openclaw:
6
+ emoji: "\U0001F41D"
7
+ homepage: https://github.com/jovanSAPFIONEER/Network-AI
8
+ requires:
9
+ bins:
10
+ - python3
5
11
  ---
6
12
 
7
13
  # Swarm Orchestrator Skill
@@ -363,11 +369,12 @@ Sequential processing - output of one feeds into next.
363
369
 
364
370
  ## Security Considerations
365
371
 
366
- 1. **Never bypass the permission wall** for DATABASE/PAYMENTS APIs
372
+ 1. **Never bypass the permission wall** for gated resources
367
373
  2. **Always include justification** explaining the business need
368
374
  3. **Use minimal scope** - request only what you need
369
375
  4. **Check token expiry** - tokens are valid for 5 minutes
370
- 5. **Audit trail** - all permission requests are logged
376
+ 5. **Validate tokens** - use `python {baseDir}/scripts/validate_token.py TOKEN` to verify grant tokens before use
377
+ 6. **Audit trail** - all permission requests are logged
371
378
 
372
379
  ## 📝 Audit Trail Requirements (MANDATORY)
373
380
 
@@ -439,6 +446,9 @@ with open(audit_file, "a") as f:
439
446
  Expired permission tokens are automatically tracked. Run periodic cleanup:
440
447
 
441
448
  ```bash
449
+ # Validate a grant token
450
+ python {baseDir}/scripts/validate_token.py grant_a1b2c3d4e5f6
451
+
442
452
  # List expired tokens (without removing)
443
453
  python {baseDir}/scripts/revoke_token.py --list-expired
444
454
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "network-ai",
3
- "version": "3.1.0",
3
+ "version": "3.1.3",
4
4
  "description": "AI agent orchestration framework for TypeScript/Node.js - plug-and-play multi-agent coordination with 12 frameworks (LangChain, AutoGen, CrewAI, OpenAI Assistants, LlamaIndex, Semantic Kernel, Haystack, DSPy, Agno, MCP, OpenClaw). Built-in security, swarm intelligence, and agentic workflow patterns.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -307,7 +307,38 @@ Last Updated: {datetime.now(timezone.utc).isoformat()}
307
307
  # ========================================================================
308
308
  # ATOMIC COMMIT WORKFLOW: propose → validate → commit
309
309
  # ========================================================================
310
-
310
+
311
+ @staticmethod
312
+ def _sanitize_change_id(change_id: str) -> str:
313
+ """
314
+ Sanitize change_id to prevent path traversal attacks.
315
+ Only allows alphanumeric characters, hyphens, underscores, and dots.
316
+ Rejects any path separators or parent directory references.
317
+ """
318
+ if not change_id or not isinstance(change_id, str):
319
+ raise ValueError("change_id must be a non-empty string")
320
+ # Strip whitespace
321
+ sanitized = change_id.strip()
322
+ # Reject path separators and parent directory traversal
323
+ if any(c in sanitized for c in ('/', '\\', '..')):
324
+ raise ValueError(
325
+ f"Invalid change_id '{change_id}': must not contain path separators or '..'"
326
+ )
327
+ # Only allow safe characters: alphanumeric, hyphen, underscore, dot
328
+ if not re.match(r'^[a-zA-Z0-9_\-\.]+$', sanitized):
329
+ raise ValueError(
330
+ f"Invalid change_id '{change_id}': only alphanumeric, hyphen, underscore, and dot allowed"
331
+ )
332
+ return sanitized
333
+
334
+ def _safe_pending_path(self, change_id: str, suffix: str = ".pending.json") -> Path:
335
+ """Build a pending-file path and verify it stays inside pending_dir."""
336
+ safe_id = self._sanitize_change_id(change_id)
337
+ target = (self.pending_dir / f"{safe_id}{suffix}").resolve()
338
+ if not str(target).startswith(str(self.pending_dir.resolve())):
339
+ raise ValueError(f"Path traversal blocked for change_id '{change_id}'")
340
+ return target
341
+
311
342
  def propose_change(self, change_id: str, key: str, value: Any,
312
343
  source_agent: str = "unknown", ttl: Optional[int] = None,
313
344
  operation: str = "write") -> dict[str, Any]:
@@ -317,7 +348,7 @@ Last Updated: {datetime.now(timezone.utc).isoformat()}
317
348
  The change is written to a .pending file and must be validated
318
349
  and committed by the orchestrator before it takes effect.
319
350
  """
320
- pending_file = self.pending_dir / f"{change_id}.pending.json"
351
+ pending_file = self._safe_pending_path(change_id)
321
352
 
322
353
  # Check for duplicate change_id
323
354
  if pending_file.exists():
@@ -365,7 +396,7 @@ Last Updated: {datetime.now(timezone.utc).isoformat()}
365
396
  - No conflicting changes to the same key
366
397
  - Base hash matches (data hasn't changed since proposal)
367
398
  """
368
- pending_file = self.pending_dir / f"{change_id}.pending.json"
399
+ pending_file = self._safe_pending_path(change_id)
369
400
 
370
401
  if not pending_file.exists():
371
402
  return {
@@ -439,7 +470,7 @@ Last Updated: {datetime.now(timezone.utc).isoformat()}
439
470
  """
440
471
  Apply a validated change atomically (Step 3 of atomic commit).
441
472
  """
442
- pending_file = self.pending_dir / f"{change_id}.pending.json"
473
+ pending_file = self._safe_pending_path(change_id)
443
474
 
444
475
  if not pending_file.exists():
445
476
  return {
@@ -479,9 +510,10 @@ Last Updated: {datetime.now(timezone.utc).isoformat()}
479
510
  change_set["status"] = "committed"
480
511
  change_set["committed_at"] = datetime.now(timezone.utc).isoformat()
481
512
 
513
+ safe_id = self._sanitize_change_id(change_id)
482
514
  archive_dir = self.pending_dir / "archive"
483
515
  archive_dir.mkdir(exist_ok=True)
484
- archive_file = archive_dir / f"{change_id}.committed.json"
516
+ archive_file = archive_dir / f"{safe_id}.committed.json"
485
517
  archive_file.write_text(json.dumps(change_set, indent=2))
486
518
 
487
519
  # Remove pending file
@@ -497,7 +529,7 @@ Last Updated: {datetime.now(timezone.utc).isoformat()}
497
529
 
498
530
  def abort_change(self, change_id: str) -> dict[str, Any]:
499
531
  """Abort a pending change without applying it."""
500
- pending_file = self.pending_dir / f"{change_id}.pending.json"
532
+ pending_file = self._safe_pending_path(change_id)
501
533
 
502
534
  if not pending_file.exists():
503
535
  return {
@@ -510,9 +542,10 @@ Last Updated: {datetime.now(timezone.utc).isoformat()}
510
542
  change_set["aborted_at"] = datetime.now(timezone.utc).isoformat()
511
543
 
512
544
  # Archive the aborted change
545
+ safe_id = self._sanitize_change_id(change_id)
513
546
  archive_dir = self.pending_dir / "archive"
514
547
  archive_dir.mkdir(exist_ok=True)
515
- archive_file = archive_dir / f"{change_id}.aborted.json"
548
+ archive_file = archive_dir / f"{safe_id}.aborted.json"
516
549
  archive_file.write_text(json.dumps(change_set, indent=2))
517
550
 
518
551
  pending_file.unlink()