{"_id":"@astermind/evo-virtual-assistant-client","_rev":"5-65c7cec21384349c933d76b4cb514331","name":"@astermind/evo-virtual-assistant-client","dist-tags":{"latest":"2.6.4"},"versions":{"2.3.23":{"name":"@astermind/evo-virtual-assistant-client","version":"2.3.23","keywords":["virtual-assistant","rag","ai","offline","offline-first","agentic","astermind","cybernetic","indexeddb","cache","streaming","sse","dom-automation","intent-classification","client-sdk"],"author":{"name":"AsterMind Team"},"license":"MIT","_id":"@astermind/evo-virtual-assistant-client@2.3.23","maintainers":[{"name":"spockinnator","email":"tim@astermind.ai"},{"name":"clockworksyler","email":"clockworksyler@gmail.com"}],"homepage":"https://astermind.ai","dist":{"shasum":"3bbd9a5c4eac906b541075a46ebf979fe95b48fd","tarball":"https://registry.npmjs.org/@astermind/evo-virtual-assistant-client/-/evo-virtual-assistant-client-2.3.23.tgz","fileCount":81,"integrity":"sha512-ByRWsvXpsB0gKuFuym5QnblCJuk29+dkurHt+cUQwAaA9DOocdJlkGwRjKjnvSu9X3A5Bnu8whuI93u5578PPg==","signatures":[{"sig":"MEUCICeUVzwEx3cx4fX30UsfsLalQeD/xSD9zNgFQYAsukZ0AiEA9Y5qqZAvWndwpxuSQKFMQ3dgqjl6kuMujvvSUspqrYo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":6458681},"main":"dist/evo-virtual-assistant-client.umd.js","type":"module","types":"dist/index.d.ts","module":"dist/evo-virtual-assistant-client.esm.js","engines":{"node":">=16.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/evo-virtual-assistant-client.esm.js","require":"./dist/evo-virtual-assistant-client.umd.js"},"./full":{"types":"./dist/full.d.ts","import":"./dist/evo-virtual-assistant-client-full.esm.js","require":"./dist/evo-virtual-assistant-client-full.umd.js"}},"gitHead":"64567624e1feb05ca9cee7876a4c0c49da234b2c","scripts":{"dev":"rollup -c -w","lint":"eslint src/","test":"vitest run","audit":"npm audit","build":"rollup -c","prebuild":"node scripts/bump-version.js","typecheck":"tsc --noEmit","prerelease":"npm run build:clean && npm run typecheck && npm run test && npm run audit","test:watch":"vitest","build:clean":"rm -rf dist && npm run build","test:coverage":"vitest --coverage","version:major":"node scripts/bump-version.js major","version:minor":"node scripts/bump-version.js minor","version:patch":"node scripts/bump-version.js patch","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"spockinnator","email":"tim@astermind.ai"},"_npmVersion":"10.8.2","description":"Offline-capable AI virtual assistant client with local RAG fallback and agentic capabilities for AsterMind","directories":{},"sideEffects":false,"_nodeVersion":"20.19.0","dependencies":{"idb":"^7.1.1","@astermind/astermind-community":"^3.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^27.4.0","tslib":"^2.8.1","rollup":"^4.0.0","vitest":"^4.0.17","typescript":"^5.0.0","@types/node":"^20.0.0","@types/react":"^18.0.0","@rollup/plugin-terser":"^0.4.0","@rollup/plugin-commonjs":"^25.0.0","@rollup/plugin-typescript":"^11.0.0","@rollup/plugin-node-resolve":"^15.0.0"},"peerDependencies":{"react":">=16.8.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/evo-virtual-assistant-client_2.3.23_1775231865728_0.889564419095185","host":"s3://npm-registry-packages-npm-production"}},"2.3.25":{"name":"@astermind/evo-virtual-assistant-client","version":"2.3.25","keywords":["virtual-assistant","rag","ai","offline","offline-first","agentic","astermind","cybernetic","indexeddb","cache","streaming","sse","dom-automation","intent-classification","client-sdk"],"author":{"name":"AsterMind Team"},"license":"MIT","_id":"@astermind/evo-virtual-assistant-client@2.3.25","maintainers":[{"name":"spockinnator","email":"tim@astermind.ai"},{"name":"clockworksyler","email":"clockworksyler@gmail.com"}],"homepage":"https://astermind.ai","dist":{"shasum":"7ed6dbb0306de04dedb817fb42888b9799c8e778","tarball":"https://registry.npmjs.org/@astermind/evo-virtual-assistant-client/-/evo-virtual-assistant-client-2.3.25.tgz","fileCount":81,"integrity":"sha512-+vR5vGl/noaAwnBeIsJIduP5sSLfHZQcykZkrvy2CXcFA4hxYX4lTKK0nzgs2XIkwo3izRNpNTyWtSyZWMh1yA==","signatures":[{"sig":"MEUCIH6qtWJKQCoIBuPK1cjsuIhTgI7LjXCmthljEpzkyP7CAiEAzCkgxvshz/kN5OLUJEqUIlrqFcR1U7SObYq5d1dTc/k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":6458681},"main":"dist/evo-virtual-assistant-client.umd.js","type":"module","types":"dist/index.d.ts","module":"dist/evo-virtual-assistant-client.esm.js","engines":{"node":">=16.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/evo-virtual-assistant-client.esm.js","require":"./dist/evo-virtual-assistant-client.umd.js"},"./full":{"types":"./dist/full.d.ts","import":"./dist/evo-virtual-assistant-client-full.esm.js","require":"./dist/evo-virtual-assistant-client-full.umd.js"}},"gitHead":"fd8f64d26d664bb4f3651e0e27ba555707563bbe","scripts":{"dev":"rollup -c -w","lint":"eslint src/","test":"vitest run","audit":"npm audit","build":"rollup -c","prebuild":"node scripts/bump-version.js","typecheck":"tsc --noEmit","prerelease":"npm run build:clean && npm run typecheck && npm run test && npm run audit","test:watch":"vitest","build:clean":"rm -rf dist && npm run build","test:coverage":"vitest --coverage","version:major":"node scripts/bump-version.js major","version:minor":"node scripts/bump-version.js minor","version:patch":"node scripts/bump-version.js patch","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"spockinnator","email":"tim@astermind.ai"},"_npmVersion":"10.8.2","description":"Offline-capable AI virtual assistant client with local RAG fallback and agentic capabilities for AsterMind","directories":{},"sideEffects":false,"_nodeVersion":"20.19.0","dependencies":{"idb":"^7.1.1","@astermind/astermind-community":"^3.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^27.4.0","tslib":"^2.8.1","rollup":"^4.0.0","vitest":"^4.0.17","typescript":"^5.0.0","@types/node":"^20.0.0","@types/react":"^18.0.0","@rollup/plugin-terser":"^0.4.0","@rollup/plugin-commonjs":"^25.0.0","@rollup/plugin-typescript":"^11.0.0","@rollup/plugin-node-resolve":"^15.0.0"},"peerDependencies":{"react":">=16.8.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/evo-virtual-assistant-client_2.3.25_1775236328954_0.7786217419756676","host":"s3://npm-registry-packages-npm-production"}},"2.3.28":{"name":"@astermind/evo-virtual-assistant-client","version":"2.3.28","keywords":["virtual-assistant","rag","ai","offline","offline-first","agentic","astermind","cybernetic","indexeddb","cache","streaming","sse","dom-automation","intent-classification","client-sdk"],"author":{"name":"AsterMind Team"},"license":"MIT","_id":"@astermind/evo-virtual-assistant-client@2.3.28","maintainers":[{"name":"spockinnator","email":"tim@astermind.ai"},{"name":"clockworksyler","email":"clockworksyler@gmail.com"}],"homepage":"https://astermind.ai","dist":{"shasum":"32b4917af3edf1b4cb6aa785451277a8ab7e1d4c","tarball":"https://registry.npmjs.org/@astermind/evo-virtual-assistant-client/-/evo-virtual-assistant-client-2.3.28.tgz","fileCount":81,"integrity":"sha512-UJUXG1zTXenK61H0+dQkI0lo+et0kMLD/moKqwPM77+hjvfywMtVGEVLOmkX3IMzQcT2cYqSUzJE7QioY0LkAw==","signatures":[{"sig":"MEUCIGTzVE2djMJ5Tr6BdL3qgeQsmfzK9oevAa27IGBYCS8UAiEArHM6w207//y4Yvef/814ohP3w5dO2w7sMAR13C7xKAk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":6458998},"main":"dist/evo-virtual-assistant-client.umd.js","type":"module","types":"dist/index.d.ts","module":"dist/evo-virtual-assistant-client.esm.js","engines":{"node":">=16.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/evo-virtual-assistant-client.esm.js","require":"./dist/evo-virtual-assistant-client.umd.js"},"./full":{"types":"./dist/full.d.ts","import":"./dist/evo-virtual-assistant-client-full.esm.js","require":"./dist/evo-virtual-assistant-client-full.umd.js"}},"gitHead":"b20c1c7371b1910fab85b8d060da13fee074af9f","scripts":{"dev":"rollup -c -w","lint":"eslint src/","test":"vitest run","audit":"npm audit","build":"rollup -c","prebuild":"node scripts/bump-version.js","typecheck":"tsc --noEmit","prerelease":"npm run build:clean && npm run typecheck && npm run test && npm run audit","test:watch":"vitest","build:clean":"rm -rf dist && npm run build","test:coverage":"vitest --coverage","version:major":"node scripts/bump-version.js major","version:minor":"node scripts/bump-version.js minor","version:patch":"node scripts/bump-version.js patch","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"spockinnator","email":"tim@astermind.ai"},"_npmVersion":"10.8.2","description":"Offline-capable AI virtual assistant client with local RAG fallback and agentic capabilities for AsterMind","directories":{},"sideEffects":false,"_nodeVersion":"20.19.0","dependencies":{"idb":"^7.1.1","@astermind/astermind-community":"^3.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^27.4.0","tslib":"^2.8.1","rollup":"^4.0.0","vitest":"^4.0.17","typescript":"^5.0.0","@types/node":"^20.0.0","@types/react":"^18.0.0","@rollup/plugin-terser":"^0.4.0","@rollup/plugin-commonjs":"^25.0.0","@rollup/plugin-typescript":"^11.0.0","@rollup/plugin-node-resolve":"^15.0.0"},"peerDependencies":{"react":">=16.8.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/evo-virtual-assistant-client_2.3.28_1777465123715_0.8606103847926259","host":"s3://npm-registry-packages-npm-production"}},"2.5.3":{"name":"@astermind/evo-virtual-assistant-client","version":"2.5.3","keywords":["virtual-assistant","rag","ai","offline","offline-first","agentic","astermind","cybernetic","indexeddb","cache","streaming","sse","dom-automation","intent-classification","client-sdk"],"author":{"name":"AsterMind Team"},"license":"MIT","_id":"@astermind/evo-virtual-assistant-client@2.5.3","maintainers":[{"name":"spockinnator","email":"tim@astermind.ai"},{"name":"clockworksyler","email":"clockworksyler@gmail.com"}],"homepage":"https://astermind.ai","dist":{"shasum":"e8895381433d189d030919bc3477fb476ae3c42e","tarball":"https://registry.npmjs.org/@astermind/evo-virtual-assistant-client/-/evo-virtual-assistant-client-2.5.3.tgz","fileCount":85,"integrity":"sha512-UGF9d8BSDGCoWSloOMoLzxNuNwa+1I+uzsuo6VOD6IYbRJTG8eBGHEt0h8xj3/Q52aoVCgzrXmnxMNNIl97VHQ==","signatures":[{"sig":"MEUCIQDe6cIpNH4KjSqD4bIN5GDU+GlKkpRTpvAmJmsGIFsQNwIgcOfjW/nj/83v4Ell7ZDydwlS0QD3Q57nFMHDXpwf0QA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":6509093},"main":"dist/evo-virtual-assistant-client.umd.js","type":"module","types":"dist/index.d.ts","module":"dist/evo-virtual-assistant-client.esm.js","engines":{"node":">=16.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/evo-virtual-assistant-client.esm.js","require":"./dist/evo-virtual-assistant-client.umd.js"},"./full":{"types":"./dist/full.d.ts","import":"./dist/evo-virtual-assistant-client-full.esm.js","require":"./dist/evo-virtual-assistant-client-full.umd.js"}},"gitHead":"b20c1c7371b1910fab85b8d060da13fee074af9f","scripts":{"dev":"rollup -c -w","lint":"eslint src/","test":"vitest run","audit":"npm audit","build":"rollup -c","prebuild":"node scripts/bump-version.js","typecheck":"tsc --noEmit","prerelease":"npm run build:clean && npm run typecheck && npm run test && npm run audit","test:watch":"vitest","build:clean":"rm -rf dist && npm run build","test:coverage":"vitest --coverage","version:major":"node scripts/bump-version.js major","version:minor":"node scripts/bump-version.js minor","version:patch":"node scripts/bump-version.js patch","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"_npmUser":{"name":"spockinnator","email":"tim@astermind.ai"},"_npmVersion":"10.8.2","description":"Offline-capable AI virtual assistant client with local RAG fallback and agentic capabilities for AsterMind","directories":{},"sideEffects":false,"_nodeVersion":"20.19.0","dependencies":{"idb":"^7.1.1","@astermind/astermind-community":"^3.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^27.4.0","tslib":"^2.8.1","rollup":"^4.0.0","vitest":"^4.0.17","typescript":"^5.0.0","@types/node":"^20.0.0","@types/react":"^18.0.0","@rollup/plugin-terser":"^0.4.0","@rollup/plugin-commonjs":"^25.0.0","@rollup/plugin-typescript":"^11.0.0","@rollup/plugin-node-resolve":"^15.0.0"},"peerDependencies":{"react":">=16.8.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/evo-virtual-assistant-client_2.5.3_1777596072966_0.867809555221196","host":"s3://npm-registry-packages-npm-production"}},"2.6.4":{"name":"@astermind/evo-virtual-assistant-client","version":"2.6.4","type":"module","description":"Offline-capable AI virtual assistant client with local RAG fallback and agentic capabilities for AsterMind","main":"dist/evo-virtual-assistant-client.umd.js","module":"dist/evo-virtual-assistant-client.esm.js","types":"dist/index.d.ts","sideEffects":false,"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/evo-virtual-assistant-client.esm.js","require":"./dist/evo-virtual-assistant-client.umd.js"},"./full":{"types":"./dist/full.d.ts","import":"./dist/evo-virtual-assistant-client-full.esm.js","require":"./dist/evo-virtual-assistant-client-full.umd.js"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/evo-virtual-assistant-client-react.esm.js","require":"./dist/evo-virtual-assistant-client-react.umd.js"}},"scripts":{"prebuild":"node scripts/bump-version.js","build":"rollup -c","build:clean":"rm -rf dist && npm run build","dev":"rollup -c -w","test":"vitest run","test:watch":"vitest","test:coverage":"vitest --coverage","lint":"eslint src/","typecheck":"tsc --noEmit","audit":"npm audit","audit:bundle":"node scripts/audit-bundle.js","prerelease":"npm ci && npm run build:clean && npm run typecheck && npm run test && npm run audit && npm run audit:bundle","version:patch":"node scripts/bump-version.js patch","version:minor":"node scripts/bump-version.js minor","version:major":"node scripts/bump-version.js major","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"dependencies":{},"peerDependencies":{},"devDependencies":{"@astermind/astermind-community":"^3.0.0","@rollup/plugin-commonjs":"^25.0.0","@rollup/plugin-node-resolve":"^15.0.0","@rollup/plugin-terser":"^0.4.0","@rollup/plugin-typescript":"^11.0.0","@types/node":"^20.0.0","@types/react":"^18.0.0","fake-indexeddb":"^6.2.5","jsdom":"^27.4.0","react":"^18.3.1","react-dom":"^18.3.1","rollup":"^4.0.0","typescript":"^5.0.0","vitest":"^4.0.17"},"engines":{"node":">=16.0.0"},"keywords":["virtual-assistant","rag","ai","offline","offline-first","agentic","astermind","cybernetic","indexeddb","cache","streaming","sse","dom-automation","intent-classification","client-sdk"],"author":{"name":"AsterMind Team"},"license":"MIT","publishConfig":{"access":"public"},"homepage":"https://astermind.ai","_id":"@astermind/evo-virtual-assistant-client@2.6.4","gitHead":"09fcbef3c3f5a636b56ec9ba1339c0a96cbc17a5","_nodeVersion":"20.19.0","_npmVersion":"10.8.2","dist":{"integrity":"sha512-vtpNoa8PnxctNlcvAMEtt6U2Ix861HgofpWzpkjriXrhyLd+bcysHJuinrpYxUbV8bqYJbzepbS6JRUZNsO+WA==","shasum":"47444cc162b51886e5357445b7261258dae5feeb","tarball":"https://registry.npmjs.org/@astermind/evo-virtual-assistant-client/-/evo-virtual-assistant-client-2.6.4.tgz","fileCount":181,"unpackedSize":3080106,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBNNFyo24KCDwJsAOLxkw/vsQdqurKEpJL01X2HsvYe/AiEA5pLqo19gvtPJ2MGMAYjjhDKkmhrcDAVsKWFosozGT5I="}]},"_npmUser":{"name":"spockinnator","email":"tim@astermind.ai"},"directories":{},"maintainers":[{"name":"spockinnator","email":"tim@astermind.ai"},{"name":"clockworksyler","email":"clockworksyler@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/evo-virtual-assistant-client_2.6.4_1778616529255_0.13605301192695496"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-03T15:57:44.612Z","modified":"2026-05-12T20:08:49.657Z","2.3.23":"2026-04-03T15:57:45.986Z","2.3.25":"2026-04-03T17:12:09.212Z","2.3.28":"2026-04-29T12:18:43.922Z","2.5.3":"2026-05-01T00:41:13.226Z","2.6.4":"2026-05-12T20:08:49.521Z"},"author":{"name":"AsterMind Team"},"license":"MIT","homepage":"https://astermind.ai","keywords":["virtual-assistant","rag","ai","offline","offline-first","agentic","astermind","cybernetic","indexeddb","cache","streaming","sse","dom-automation","intent-classification","client-sdk"],"description":"Offline-capable AI virtual assistant client with local RAG fallback and agentic capabilities for AsterMind","maintainers":[{"name":"spockinnator","email":"tim@astermind.ai"},{"name":"clockworksyler","email":"clockworksyler@gmail.com"}],"readme":"# @astermind/evo-virtual-assistant-client\n\nOffline-capable AI virtual assistant client with local RAG fallback and agentic capabilities for [AsterMind](https://astermind.ai).\n\n[![npm version](https://img.shields.io/npm/v/@astermind/evo-virtual-assistant-client.svg)](https://www.npmjs.com/package/@astermind/evo-virtual-assistant-client)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.0-blue.svg)](https://www.typescriptlang.org/)\n\n## What is EVO Virtual Assistant Client?\n\nEVO Virtual Assistant Client is the official JavaScript SDK for integrating [AsterMind](https://astermind.ai) AI virtual assistant capabilities into your web applications. It provides a robust, offline-first architecture that ensures your users always get answers, even when disconnected from the server.\n\n## Key Features\n\n- **Dual Transport** - WebSocket streaming for SaaS, REST+SSE for on-prem (auto-detected)\n- **Offline-First Architecture** - IndexedDB caching with TF-IDF local search\n- **SSE Streaming** - Real-time token-by-token responses (REST fallback)\n- **WebSocket Streaming** - Low-latency streaming via persistent connection (SaaS)\n- **Session Management** - Multi-turn conversation continuity\n- **Configurable Retry Logic** - Exponential backoff with customizable settings\n- **Connection Status Monitoring** - Real-time online/offline detection\n- **Maintenance Mode Support** - Graceful degradation per ADR-200\n- **Agentic Capabilities** - Intent classification and DOM automation (full bundle)\n- **Tree-Shakeable** - Import only what you need (core / full / React sub-exports)\n- **Zero Runtime Dependencies** - No third-party npm packages reach the consumer browser\n- **Optional React Adapter** - `useSiteMapDiscovery` lives at `/react`; main package never imports `react`\n\n## Zero-Trust Posture\n\nThis package ships **zero third-party runtime dependencies** and **zero peer\ndependencies**. Every line of JavaScript inside the published bundle is\nauthored or vendored under the AsterMind team's signature. Installing this\nclient adds no transitive `node_modules` to your project beyond the package\nitself.\n\n| Aspect | Posture |\n|---|---|\n| `dependencies` in `package.json` | empty (`{}`) |\n| `peerDependencies` in `package.json` | empty (none) |\n| Third-party code in published `dist/` | none |\n| `npm audit` surface for consumers | only this package |\n| Build tooling (rollup, typescript, vitest) | dev-only; never reaches the consumer; pinned and audited every release |\n\nFor the rationale, threat model, and per-dependency removal plan, see\nADR-002 (`claude-markdown-documents/ADRs/ADR-002-...`) and DOC-002 in this\nrepository. The Omega offline RAG implementation is vendored from the\nsibling `@astermind/astermind-community` package and re-vendored via\n`scripts/update-vendored-community.js`; the change history lives in\n`claude-markdown-documents/VENDORED-COMMUNITY-LOG.md`.\n\n### React (optional sub-export)\n\nThe previous React `useSiteMapDiscovery` hook moved out of the main bundle.\nNon-React consumers can use the new framework-agnostic class directly:\n\n```ts\nimport { SiteMapDiscoveryRunner } from '@astermind/evo-virtual-assistant-client';\n\nconst runner = new SiteMapDiscoveryRunner({ enabled: true });\nrunner.subscribe((state) => render(state.entries));\nrunner.start();\n```\n\nReact consumers should import the hook from the dedicated sub-export, which\nis the only place in this package that touches React:\n\n```ts\nimport { useSiteMapDiscovery } from '@astermind/evo-virtual-assistant-client/react';\n```\n\nImporting from `/react` requires React >= 16.8 to be installed in your\nproject. The requirement is documented here rather than enforced via an\nnpm `peerDependency` on the main package.\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Licensing](#licensing)\n- [Configuration](#configuration)\n- [Features](#features)\n  - [WebSocket Transport (SaaS)](#websocket-transport-saas)\n  - [Offline-First Architecture](#offline-first-architecture)\n  - [Pre-computed Vector Export (Advanced)](#pre-computed-vector-export-advanced)\n  - [Streaming Responses](#streaming-responses)\n  - [Session Management](#session-management)\n  - [Agentic Capabilities](#agentic-capabilities)\n  - [Sitemap Configuration](#sitemap-configuration)\n  - [Maintenance Mode Support](#maintenance-mode-support)\n- [Bundle Options](#bundle-options)\n- [API Reference](#api-reference)\n- [Browser Support](#browser-support)\n- [Integration with EVO Virtual Assistant Backend](#integration-with-evo-virtual-assistant-backend)\n- [License](#license)\n\n## Installation\n\n### npm / yarn / pnpm\n\n```bash\nnpm install @astermind/evo-virtual-assistant-client\n```\n\n```bash\nyarn add @astermind/evo-virtual-assistant-client\n```\n\n```bash\npnpm add @astermind/evo-virtual-assistant-client\n```\n\n**Required import** — add to your JavaScript/TypeScript file:\n\n```typescript\nimport { CyberneticClient } from '@astermind/evo-virtual-assistant-client';\n```\n\n> **Note:** Most users should install `@astermind/evo-virtual-assistant-template` instead, which includes this package as a dependency along with pre-built UI components. Use this package directly only if you're building a custom chat UI.\n\n### CDN (Script Tag)\n\nInclude **one** of the following script tags in your HTML:\n\n```html\n<!-- Core bundle (API client, caching, offline fallback) -->\n<script src=\"https://unpkg.com/@astermind/evo-virtual-assistant-client/dist/evo-virtual-assistant-client.umd.js\"></script>\n\n<!-- Or full bundle (core + agentic capabilities) -->\n<script src=\"https://unpkg.com/@astermind/evo-virtual-assistant-client/dist/evo-virtual-assistant-client-full.umd.js\"></script>\n```\n\nThe client is available as `window.AsterMindCybernetic` (core) or `window.AsterMindCyberneticFull` (full bundle).\n\n## Quick Start\n\n> **Note:** No license key is required for development. See [Licensing](#licensing) for production requirements.\n\n### Basic Usage\n\n```typescript\nimport { CyberneticClient } from '@astermind/evo-virtual-assistant-client';\n\nconst client = new CyberneticClient({\n  apiUrl: 'https://api.astermind.ai',\n  apiKey: 'am_your_api_key',\n  // licenseKey: 'your-license-key',  // Optional in development, required in production\n  fallback: {\n    enabled: true,\n    cacheOnConnect: true\n  },\n  onStatusChange: (status) => {\n    console.log('Connection status:', status);\n  }\n});\n\n// Simple question\nconst response = await client.ask('What is AsterMind?');\nconsole.log(response.reply);\n\n// With streaming\nawait client.askStream('Tell me about RAG', {\n  onToken: (token) => process.stdout.write(token),\n  onSources: (sources) => console.log('Sources:', sources),\n  onComplete: (response) => console.log('\\nDone:', response.sessionId)\n});\n```\n\n### Script Tag Integration\n\n```html\n<script\n  src=\"https://unpkg.com/@astermind/evo-virtual-assistant-client/dist/evo-virtual-assistant-client.umd.js\"\n  data-astermind-key=\"am_your_api_key\"\n  data-astermind-url=\"https://api.astermind.ai\"\n></script>\n```\n\n### Global Config Object\n\n```html\n<script>\n  window.astermindConfig = {\n    apiUrl: 'https://api.astermind.ai',\n    apiKey: 'am_your_api_key',\n    fallback: { enabled: true }\n  };\n</script>\n<script src=\"https://unpkg.com/@astermind/evo-virtual-assistant-client/dist/evo-virtual-assistant-client.umd.js\"></script>\n```\n\n## Licensing\n\n**Free for Development** — This package is free to use during development and testing. No license key is required for local development environments.\n\n**License Required for Production** — A valid license key is required for production deployments. Without a license, virtual assistant responses in production will include a visible license notice. Licenses are available at [https://astermind.ai](https://astermind.ai).\n\n### License Products\n\n| Product | Feature Flag | Included With |\n|---------|--------------|---------------|\n| **EVO Virtual Assistant Client** | `evo-virtual-assistant-client` | EVO Virtual Assistant purchase |\n| **Agentic Add-On** | `agentic` | Separate Agentic Add-On purchase |\n\n- **EVO Virtual Assistant**: Includes the `evo-virtual-assistant-client` feature, enabling all core client functionality (API communication, offline caching, streaming, session management).\n- **Agentic Add-On**: Requires a separate purchase. Enables the `agentic` feature for intent classification and DOM automation capabilities.\n\n### Applying Your License Key\n\nAdd your license key to the client configuration:\n\n```typescript\nimport { CyberneticClient } from '@astermind/evo-virtual-assistant-client';\n\nconst client = new CyberneticClient({\n  apiUrl: 'https://api.astermind.ai',\n  apiKey: 'am_your_api_key',\n  licenseKey: 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9...'  // Your license key (JWT)\n});\n```\n\nFor script tag integration:\n\n```html\n<script>\n  window.astermindConfig = {\n    apiUrl: 'https://api.astermind.ai',\n    apiKey: 'am_your_api_key',\n    licenseKey: 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9...'\n  };\n</script>\n<script src=\"https://unpkg.com/@astermind/evo-virtual-assistant-client/dist/evo-virtual-assistant-client.umd.js\"></script>\n```\n\n### Enforcement Behavior\n\nThe license system uses environment-aware enforcement:\n\n| Environment | Detection | License Required? | Behavior |\n|-------------|-----------|-------------------|----------|\n| **Development** | `localhost`, `127.0.0.1`, `.local`, `.dev`, dev ports (3000, 5173, 8080, etc.) | **No** | Free to use. Console warnings only. |\n| **Production** | All other URLs | **Yes** | License warning appended to responses if missing/invalid. |\n\n**Development Mode** (free, soft enforcement):\n- **No license key required** — develop and test without any restrictions\n- Console warnings are logged when license is missing, expired, or invalid (for awareness)\n- Console warnings when using features not included in your license\n- All functionality works normally — responses are returned unchanged\n\n**Production Mode** (license required, hard enforcement):\n- A valid license key is required for production use\n- Without a valid license, virtual assistant responses include a visible notice:\n\n  *\"⚠️ License Notice: Your AsterMind license key needs to be updated. Please contact support@astermind.ai or visit https://astermind.ai/license to renew your license.\"*\n\n- With a valid license, responses are returned normally without any modifications\n\n### Checking License Status\n\n```typescript\n// Get current status including license state\nconst status = client.getStatus();\nconsole.log(status.license);\n// {\n//   status: 'valid' | 'invalid' | 'expired' | 'missing' | 'eval',\n//   payload: { plan, features, exp, ... },\n//   daysRemaining: 30,\n//   inGracePeriod: false\n// }\n\n// Get license manager for advanced operations\nconst license = client.getLicenseManager();\n\n// Check if license is valid\nlicense.isValid();\n\n// Check specific features\nlicense.hasFeature('evo-virtual-assistant-client');\nlicense.hasFeature('agentic');\n\n// Get human-readable status\nlicense.getStatusMessage();\n// \"License valid (30 days remaining)\"\n```\n\n### Feature Validation\n\nThe client automatically validates features:\n\n- **Client feature** (`evo-virtual-assistant-client`): Checked on client initialization\n- **Agentic feature** (`agentic`): Checked only when agentic capabilities are used\n\nIf a required feature is missing, the console displays:\n- Current license plan\n- Available features in your license\n- The missing feature name\n- Link to upgrade at https://astermind.ai/license\n\n### Obtaining a License\n\n1. Visit [https://astermind.ai](https://astermind.ai)\n2. Purchase **EVO Virtual Assistant** for core client functionality\n3. Optionally purchase the **Agentic Add-On** for DOM automation features\n4. Your license key (JWT token) will be provided in your account dashboard\n5. Add the license key to your client configuration\n\nFor licensing questions, contact support@astermind.ai.\n\n## Configuration\n\nAll configuration is done in **your own project**—you never need to modify `node_modules` or the package source code.\n\n### Multi-Method Configuration\n\nThe client supports multiple configuration methods with a priority-based fallback chain. This allows you to use the most appropriate method for your hosting environment.\n\n**Priority Order (highest to lowest):**\n\n1. **Constructor config** - Direct configuration passed to `CyberneticClient` or `createClient()`\n2. **Environment variables** - `VITE_ASTERMIND_RAG_API_KEY`, `REACT_APP_ASTERMIND_RAG_API_KEY`, etc.\n3. **SSR-injected config** - `window.__ASTERMIND_CONFIG__` (for server-side rendering)\n4. **Global object** - `window.astermindConfig`\n5. **Script data attributes** - `data-astermind-key`, `data-astermind-url`\n\n#### Environment Variables\n\nFor bundled applications (Vite, Create React App, etc.), you can configure the client using environment variables:\n\n**Vite:**\n```env\nVITE_ASTERMIND_RAG_API_KEY=am_your_api_key\nVITE_ASTERMIND_RAG_API_SERVER_URL=https://api.astermind.ai\n```\n\n**Create React App:**\n```env\nREACT_APP_ASTERMIND_RAG_API_KEY=am_your_api_key\nREACT_APP_ASTERMIND_RAG_API_SERVER_URL=https://api.astermind.ai\n```\n\n**Node.js / Server:**\n```env\nASTERMIND_RAG_API_KEY=am_your_api_key\nASTERMIND_RAG_API_SERVER_URL=https://api.astermind.ai\n```\n\n#### Auto-Loading Configuration\n\nUse `loadConfig()` to automatically detect configuration from available sources:\n\n```typescript\nimport { loadConfig, createClient } from '@astermind/evo-virtual-assistant-client';\n\n// Auto-detect configuration (throws if no API key found)\nconst config = loadConfig();\nconst client = createClient(config);\n\n// Or suppress errors and handle missing config gracefully\nconst config = loadConfig({ throwOnMissingKey: false });\nif (config) {\n  const client = createClient(config);\n} else {\n  console.log('Virtual assistant not configured');\n}\n```\n\n#### SSR / Runtime Injection\n\nFor server-side rendered applications, inject configuration at runtime:\n\n```html\n<!-- In your SSR template -->\n<script>\n  window.__ASTERMIND_CONFIG__ = {\n    apiKey: '<%= process.env.ASTERMIND_RAG_API_KEY %>',\n    apiUrl: '<%= process.env.ASTERMIND_RAG_API_SERVER_URL %>'\n  };\n</script>\n```\n\n#### Configuration Source Debugging\n\nThe loaded configuration includes a `_source` field for debugging:\n\n```typescript\nconst config = loadConfig();\nconsole.log(config._source);\n// 'env' | 'vite' | 'window' | 'data-attr' | 'props'\n```\n\n### Full Configuration Interface\n\n```typescript\ninterface CyberneticConfig {\n  /** Backend API URL (required) */\n  apiUrl: string;\n\n  /** API key for authentication - must start with 'am_' (required) */\n  apiKey: string;\n\n  /** WebSocket URL for SaaS streaming (auto-derived from apiUrl for known SaaS domains) */\n  wsUrl?: string;\n\n  /** Transport mode: 'auto' (default) tries WebSocket then REST, 'websocket' forces WS, 'rest' forces REST+SSE */\n  transport?: 'auto' | 'websocket' | 'rest';\n\n  /** WebSocket transport options */\n  websocket?: {\n    maxReconnectAttempts?: number;  // Default: 3\n    reconnectDelay?: number;       // Default: 1000ms (exponential backoff)\n    connectionTimeout?: number;    // Default: 10000ms\n  };\n\n  /** License key (JWT token) from https://astermind.ai */\n  licenseKey?: string;\n\n  /** Fallback/offline configuration */\n  fallback?: {\n    /** Enable offline fallback (default: true) */\n    enabled?: boolean;\n\n    /** Cache max age in milliseconds (default: 86400000 = 24 hours) */\n    cacheMaxAge?: number;\n\n    /** Sync documents on connect (default: true) */\n    cacheOnConnect?: boolean;\n\n    /** Storage type (default: 'indexeddb') */\n    cacheStorage?: 'indexeddb' | 'localstorage';\n  };\n\n  /** Retry configuration */\n  retry?: {\n    /** Max retries before fallback (default: 2) */\n    maxRetries?: number;\n\n    /** Initial delay in ms (default: 1000) */\n    initialDelay?: number;\n\n    /** Use exponential backoff (default: true) */\n    exponentialBackoff?: boolean;\n  };\n\n  /** Event callbacks */\n  onStatusChange?: (status: ConnectionStatus) => void;\n  onError?: (error: CyberneticError) => void;\n\n  /** Agentic capabilities configuration (requires full bundle) */\n  agentic?: AgenticConfig;\n\n  /** Offline vector export configuration (see Pre-computed Vector Export section) */\n  offline?: OfflineConfig;\n\n  /** Sitemap configuration for agentic navigation (see Sitemap Configuration section) */\n  sitemap?: SiteMapConfig;\n\n  /** Source display and cap configuration (see Sources Configuration section) */\n  sources?: SourcesConfig;\n\n  /** Reply post-processing (see Response Normalization section) */\n  responseNormalization?: ResponseNormalizationConfig;\n}\n\ntype ConnectionStatus = 'online' | 'offline' | 'connecting' | 'error';\n```\n\n### Sources Configuration\n\nControls how source documents are surfaced to consumers. The cap is enforced at every emission site (REST, WebSocket, and offline fallback paths), so the configured maximum is the actual maximum a consumer ever sees.\n\n```typescript\ninterface SourcesConfig {\n  /** Include sources in responses (default: true) */\n  enabled?: boolean;\n\n  /** Show summary/eye icon in UI (default: true) */\n  showSummary?: boolean;\n\n  /** Show download button in UI - only works online (default: true) */\n  showDownload?: boolean;\n\n  /** Include fullContent for offline summary capability (default: false) */\n  includeFullContent?: boolean;\n\n  /**\n   * Max sources to return (default: 7).\n   *\n   * Raised from 5 to 7 in v2.5.x to match the AsterMind backend's own cap.\n   * The client slices any larger result set to this size before invoking\n   * `onSources` and before building the `sources` array on the final\n   * response — so `onSources` and `onComplete` always agree.\n   */\n  maxSources?: number;\n}\n```\n\n### Response Normalization\n\nOpt-in defensive post-processing of the assembled reply text. Off by default — enable only if your renderer does **not** already handle malformed code fences. The official `@astermind/evo-virtual-assistant-template` package handles this at render time and does not need this enabled.\n\n```typescript\ninterface ResponseNormalizationConfig {\n  /** Enable normalization passes on the assembled reply (default: false) */\n  enabled?: boolean;\n\n  /**\n   * Promote single-backtick runs that contain a newline (a malformed\n   * \"code block\" some older backend Lambdas emit) to triple-backtick\n   * fenced blocks. Default: true when `enabled` is true.\n   *\n   * Applied at WebSocket `done` / REST stream completion only — never per\n   * chunk, since a chunk boundary may split a fence and corrupt it.\n   */\n  normalizeFencedBlocks?: boolean;\n}\n```\n\nExample:\n\n```typescript\nconst client = new CyberneticClient({\n  apiUrl: 'https://chatapi.astermind.ai',\n  apiKey: 'am_your_api_key',\n  sources: {\n    maxSources: 5,         // Override the default cap of 7\n  },\n  responseNormalization: {\n    enabled: true,         // For non-template consumers building custom UIs\n  },\n});\n```\n\n### Agentic Configuration\n\n```typescript\ninterface AgenticConfig {\n  /** Enable agentic DOM interactions (default: false) */\n  enabled: boolean;\n\n  /** Confidence threshold for action execution (default: 0.8) */\n  confidenceThreshold?: number;\n\n  /** Allowed DOM actions */\n  allowedActions?: ('click' | 'fill' | 'scroll' | 'navigate' | 'select')[];\n\n  /** Require user confirmation before actions (default: true) */\n  requireConfirmation?: boolean;\n\n  /** Maximum actions per conversation turn (default: 5) */\n  maxActionsPerTurn?: number;\n\n  /** CSS selectors to never interact with */\n  blockedSelectors?: string[];\n\n  /** Only allow actions within these selectors */\n  allowedSelectors?: string[];\n}\n```\n\n## Features\n\n### WebSocket Transport (SaaS)\n\nWhen connecting to AsterMind's SaaS infrastructure, the client automatically uses WebSocket transport for streaming chat. This provides lower latency and access to the full RAG pipeline (RSF temporal scoring, hybrid reranking, Omega embeddings, BYOLLM).\n\n**Auto-detection (zero config for SaaS users):**\n\n```typescript\nconst client = new CyberneticClient({\n  apiUrl: 'https://chatapi.astermind.ai',\n  apiKey: 'am_your_api_key',\n  // wsUrl auto-derived → wss://chatws.astermind.ai\n});\n```\n\nThe client auto-derives WebSocket URLs for known SaaS domains:\n- `chatapi.astermind.ai` → `wss://chatws.astermind.ai`\n- `chatapi-dev.astermind.ai` → `wss://chatws-dev.astermind.ai`\n- `api.astermind.ai` → `wss://chatws.astermind.ai`\n\n**Explicit configuration:**\n\n```typescript\nconst client = new CyberneticClient({\n  apiUrl: 'https://chatapi.astermind.ai',\n  apiKey: 'am_your_api_key',\n  wsUrl: 'wss://chatws.astermind.ai',\n  transport: 'websocket',  // Force WebSocket only (no REST fallback)\n});\n```\n\n**On-prem (unchanged, REST+SSE):**\n\n```typescript\nconst client = new CyberneticClient({\n  apiUrl: 'http://localhost:3000',\n  apiKey: 'am_your_api_key',\n  // No wsUrl → uses REST+SSE as before\n});\n```\n\n**Transport modes:**\n- `'auto'` (default) — Uses WebSocket when available, falls back to REST+SSE on failure\n- `'websocket'` — Forces WebSocket only, no REST fallback\n- `'rest'` — Forces REST+SSE only, ignores WebSocket\n\n**Environment variable support:**\n\n```env\n# Vite\nVITE_ASTERMIND_RAG_WS_URL=wss://chatws.astermind.ai\n\n# Node.js / CRA\nASTERMIND_RAG_WS_URL=wss://chatws.astermind.ai\nREACT_APP_ASTERMIND_RAG_WS_URL=wss://chatws.astermind.ai\n```\n\n**Cleanup:**\n\nCall `destroy()` when disposing the client to close the WebSocket connection:\n\n```typescript\nclient.destroy();\n```\n\n### Offline-First Architecture\n\nThe client includes **built-in offline fallback** with IndexedDB caching and TF-IDF local search—no additional setup required. When the server is unreachable, the client automatically serves cached responses:\n\n```typescript\nconst client = new CyberneticClient({\n  apiUrl: 'https://api.astermind.ai',\n  apiKey: 'am_your_api_key',\n  fallback: {\n    enabled: true,\n    cacheOnConnect: true,    // Cache responses for offline use\n    cacheMaxAge: 86400000,   // 24 hours\n    cacheStorage: 'indexeddb'\n  }\n});\n\n// Check connection status\nconst status = client.getStatus();\nconsole.log(status.connection); // 'online' | 'offline' | 'connecting'\nconsole.log(status.cache);      // { documentCount, lastSyncAt, cacheSize, isStale }\n\n// Response includes offline indicator\nconst response = await client.ask('cached question');\nif (response.offline) {\n  console.log('Response from local cache');\n  console.log('Confidence:', response.confidence); // 'medium' or 'low' when offline\n}\n\n// Manually sync cache\nawait client.syncCache();\n\n// Clear cache\nawait client.clearCache();\n```\n\n**Cache Validation**: The server controls cache retention via `cacheRetentionHours` (default: 168 hours / 7 days). The client respects this setting and marks responses as stale when appropriate.\n\n### Pre-computed Vector Export (Advanced)\n\nFor enhanced offline performance, the client supports loading pre-computed TF-IDF vectors exported from the AsterMind admin panel. This eliminates client-side vector computation and provides faster, more consistent offline search results.\n\n#### Exporting Vectors from Admin\n\n1. Navigate to your AsterMind admin panel\n2. Go to **Settings > Vector Export** (or **Documents > Export**)\n3. Click **Export Vectors for Offline Use**\n4. Download the JSON export file or note the export URL\n\nThe export file contains pre-computed TF-IDF vectors, document metadata, and optionally sitemap and category information for agentic navigation.\n\n#### Configuring Offline Vectors\n\n```typescript\nimport { CyberneticClient } from '@astermind/evo-virtual-assistant-client';\n\nconst client = new CyberneticClient({\n  apiUrl: 'https://api.astermind.ai',\n  apiKey: 'am_your_api_key',\n\n  // Offline vector configuration\n  offline: {\n    enabled: true,\n    vectorFileUrl: 'https://your-cdn.com/vectors/export.json',  // URL to exported vectors\n    storageMode: 'indexeddb',  // 'memory' | 'indexeddb' | 'hybrid'\n    maxCacheAge: 604800000,    // 7 days in milliseconds\n    autoRefresh: true,         // Auto-refresh when new export available\n\n    // Optional: Omega advanced RAG (vendored into the package — no extra install required)\n    omega: {\n      enabled: true,\n      modelUrl: 'https://your-cdn.com/models/omega-model.json'\n    }\n  }\n});\n```\n\n#### Inline Vector Data\n\nYou can also provide vector data directly in the configuration:\n\n```typescript\nconst client = new CyberneticClient({\n  apiUrl: 'https://api.astermind.ai',\n  apiKey: 'am_your_api_key',\n  offline: {\n    enabled: true,\n    vectorData: exportedVectorObject,  // Loaded from file or bundled\n    storageMode: 'memory'\n  }\n});\n```\n\n#### Offline Configuration Options\n\n```typescript\ninterface OfflineConfig {\n  /** Enable offline vector support */\n  enabled: boolean;\n\n  /** URL to fetch vector export JSON */\n  vectorFileUrl?: string;\n\n  /** Inline vector data (alternative to URL) */\n  vectorData?: OfflineVectorExport;\n\n  /** Storage mode for cached vectors */\n  storageMode?: 'memory' | 'indexeddb' | 'hybrid';\n\n  /** Maximum cache age in milliseconds (default: 7 days) */\n  maxCacheAge?: number;\n\n  /** Auto-refresh vectors when new export available */\n  autoRefresh?: boolean;\n\n  /** Omega advanced RAG configuration */\n  omega?: {\n    enabled: boolean;\n    modelUrl?: string;\n    modelData?: SerializedModel;\n    config?: {\n      topK?: number;\n      rerankerTopK?: number;\n      minScore?: number;\n    };\n  };\n}\n```\n\n#### Checking Offline Status\n\n```typescript\n// Get local RAG status\nconst ragStatus = client.getLocalRAGStatus();\nconsole.log(ragStatus);\n// {\n//   loaded: true,\n//   loadedFromExport: true,\n//   documentCount: 150,\n//   chunkCount: 1200,\n//   exportVersion: '1.0.0',\n//   exportedAt: '2024-01-15T10:30:00Z'\n// }\n\n// Check if Omega is enabled and ready\nif (client.isOmegaOfflineEnabled()) {\n  const modelInfo = client.getOfflineModelInfo();\n  console.log('Omega model:', modelInfo);\n}\n\n// Force reload vectors\nawait client.reloadOfflineVectors();\n```\n\n#### Console Warning\n\nWhen `offline.enabled` is `true` but no vectors are loaded (missing URL, network error, or invalid data), the client logs a one-time console warning:\n\n```\n[CyberneticClient] Warning: Offline mode enabled but no vectors loaded.\nConfigure 'offline.vectorFileUrl' or provide 'offline.vectorData' for offline support.\nFalling back to standard caching mode.\n```\n\nThis helps identify configuration issues without disrupting functionality.\n\n### Streaming Responses\n\nReal-time token streaming via WebSocket (SaaS) or Server-Sent Events (on-prem):\n\n```typescript\nawait client.askStream('Explain quantum computing', {\n  onToken: (token) => {\n    // Called for each token as it arrives\n    document.getElementById('output').textContent += token;\n  },\n  onSources: (sources) => {\n    // Called when sources are available\n    console.log('Sources:', sources);\n  },\n  onComplete: (response) => {\n    // Called when streaming is complete\n    console.log('Session ID:', response.sessionId);\n  },\n  onError: (error) => {\n    // Called on error\n    console.error('Error:', error.message);\n  }\n});\n```\n\n### Session Management\n\nMaintain conversation context across multiple turns:\n\n```typescript\n// First message establishes session\nconst response1 = await client.ask('Hello!');\nconst sessionId = response1.sessionId;\n\n// Continue conversation with session ID\nconst response2 = await client.ask('Tell me more', { sessionId });\nconst response3 = await client.ask('Can you clarify?', { sessionId });\n\n// Optionally pass page context\nconst response = await client.ask('Help me with this page', {\n  sessionId,\n  context: {\n    currentPage: '/products/widget',\n    pageTitle: 'Widget Product Page'\n  }\n});\n```\n\n### Agentic Capabilities\n\nThe full bundle includes intent classification and DOM automation:\n\n```typescript\nimport {\n  CyberneticClient,\n  CyberneticAgent,\n  CyberneticIntentClassifier\n} from '@astermind/evo-virtual-assistant-client/full';\n\nconst client = new CyberneticClient({\n  apiUrl: 'https://api.astermind.ai',\n  apiKey: 'am_your_api_key',\n  agentic: {\n    enabled: true,\n    confidenceThreshold: 0.8,\n    requireConfirmation: true,\n    allowedActions: ['click', 'fill', 'navigate', 'scroll'],\n    blockedSelectors: ['.admin-panel', '#dangerous-button'],\n    maxActionsPerTurn: 5\n  }\n});\n\n// Smart ask - checks for action intent first, then falls back to RAG\nconst result = await client.smartAsk('Take me to the settings page');\n\nif (result.action) {\n  // Action detected\n  console.log('Action:', result.action.type, result.action.target);\n  console.log('Confidence:', result.action.confidence);\n\n  // If requireConfirmation is true, action is returned but not executed\n  // Your UI can show a confirmation dialog, then execute:\n  if (userConfirmed) {\n    const actionResult = await client.executeAction(result.action);\n    console.log('Result:', actionResult.message);\n  }\n} else if (result.response) {\n  // Standard RAG response\n  console.log('Reply:', result.response.reply);\n}\n```\n\n#### Supported Action Types\n\n| Action | Description | Example Phrases |\n|--------|-------------|-----------------|\n| `navigate` | Navigate to URL/route | \"go to settings\", \"take me to dashboard\" |\n| `fillForm` | Fill form input fields | \"search for products\", \"enter my email\" |\n| `clickElement` | Click buttons/links | \"click submit\", \"press the save button\" |\n| `scroll` | Scroll to element/position | \"scroll to top\", \"jump to pricing section\" |\n| `highlight` | Highlight elements | \"show me the login button\" |\n| `triggerModal` | Open modal dialogs | \"open help modal\", \"show settings dialog\" |\n| `custom` | Custom action handlers | \"export data\", \"refresh dashboard\" |\n\n#### Intent Classification\n\nThe classifier uses a hybrid approach with regex patterns and Jaccard similarity for fuzzy matching:\n\n```typescript\nimport { CyberneticIntentClassifier } from '@astermind/evo-virtual-assistant-client/full';\n\nconst classifier = new CyberneticIntentClassifier({\n  enabled: true,\n  confidenceThreshold: 0.8,\n  siteMap: [\n    { path: '/settings', name: 'Settings', aliases: ['preferences', 'config'] },\n    { path: '/dashboard', name: 'Dashboard', aliases: ['home', 'main'] }\n  ]\n});\n\nconst intent = classifier.classify('take me to the settings page');\n// { action: { type: 'navigate', target: '/settings', confidence: 0.92 }, ... }\n```\n\n#### Security Features\n\n- **Selector Sanitization**: Removes potentially dangerous characters from CSS selectors\n- **URL Validation**: Blocks `javascript:` and `data:` URLs\n- **Blocked Selectors**: Configure selectors that should never be interacted with\n- **Allowed Selectors**: Optionally whitelist specific selectors\n- **Rate Limiting**: Maximum actions per minute (default: 5)\n- **Confirmation Flow**: Optional user approval before action execution\n\n### Sitemap Configuration\n\nThe sitemap enables intelligent navigation by mapping user intent to application routes. You can configure it statically or load it from the vector export:\n\n#### Static Sitemap Configuration\n\n```typescript\nconst client = new CyberneticClient({\n  apiUrl: 'https://api.astermind.ai',\n  apiKey: 'am_your_api_key',\n\n  // Static sitemap configuration\n  sitemap: {\n    enabled: true,\n    entries: [\n      {\n        path: '/dashboard',\n        name: 'Dashboard',\n        description: 'Main dashboard with analytics',\n        aliases: ['home', 'main', 'overview'],\n        keywords: ['stats', 'metrics', 'analytics']\n      },\n      {\n        path: '/settings',\n        name: 'Settings',\n        description: 'User and application settings',\n        aliases: ['preferences', 'config', 'options'],\n        keywords: ['account', 'profile', 'configuration']\n      },\n      {\n        path: '/products',\n        name: 'Products',\n        description: 'Product catalog and management',\n        aliases: ['catalog', 'inventory'],\n        keywords: ['items', 'shop', 'store']\n      }\n    ]\n  }\n});\n```\n\n#### Loading Sitemap from Vector Export\n\nWhen using pre-computed vectors, the sitemap can be included in the export and loaded automatically:\n\n```typescript\nconst client = new CyberneticClient({\n  apiUrl: 'https://api.astermind.ai',\n  apiKey: 'am_your_api_key',\n  offline: {\n    enabled: true,\n    vectorFileUrl: 'https://your-cdn.com/vectors/export.json'\n  },\n  sitemap: {\n    enabled: true,\n    loadFromExport: true  // Load sitemap from vector export\n  }\n});\n```\n\n#### Sitemap Configuration Options\n\n```typescript\ninterface SiteMapConfig {\n  /** Enable sitemap-based navigation */\n  enabled: boolean;\n\n  /** Static sitemap entries */\n  entries?: SiteMapEntry[];\n\n  /** Load sitemap from vector export (requires offline.enabled) */\n  loadFromExport?: boolean;\n\n  /** URL to fetch sitemap JSON separately */\n  sitemapUrl?: string;\n}\n\ninterface SiteMapEntry {\n  /** Route path (e.g., '/dashboard') */\n  path: string;\n\n  /** Display name */\n  name: string;\n\n  /** Description for context matching */\n  description?: string;\n\n  /** Alternative names/phrases */\n  aliases?: string[];\n\n  /** Related keywords for matching */\n  keywords?: string[];\n\n  /** Authentication required */\n  requiresAuth?: boolean;\n\n  /** Required user roles */\n  roles?: string[];\n\n  /** Child routes */\n  children?: SiteMapEntry[];\n}\n```\n\n### Maintenance Mode Support\n\nThe client handles backend maintenance mode gracefully (per ADR-200):\n\n```typescript\n// Check if maintenance mode is active\nif (client.isMaintenanceMode()) {\n  const message = client.getMaintenanceMessage();\n  console.log('Maintenance:', message);\n}\n\n// Get full system status\nconst status = client.getStatus();\nconsole.log(status.systemSettings);\n// {\n//   maintenanceMode: boolean,\n//   maintenanceMessage?: string,\n//   cacheRetentionHours: number,\n//   forceOfflineClients: boolean\n// }\n```\n\nWhen maintenance mode is active:\n- The client automatically uses cached data\n- New requests are served from local RAG\n- `response.offline` will be `true`\n- `response.degradedReason` will indicate maintenance mode\n\n## Bundle Options\n\n| Entry Point | Import Path | Description | Size (minified) |\n|-------------|-------------|-------------|-----------------|\n| Core | `@astermind/evo-virtual-assistant-client` | Client, caching, local RAG, vendored Omega offline RAG | ~105 KB |\n| Full | `@astermind/evo-virtual-assistant-client/full` | Core + agentic capabilities (intent classifier, DOM agent) | ~100 KB |\n| React | `@astermind/evo-virtual-assistant-client/react` | `useSiteMapDiscovery` hook adapter (ESM only) | ~11 KB |\n\nThe core bundle is slightly larger than the full bundle in the current\nrelease because the vendored Omega RAG implementation ships with core; the\nfull entry adds the agentic surface but does not duplicate Omega.\n\nThe `/react` sub-export is the only place in the package that imports\n`react`. It is published as ESM only — consumers that need a UMD build\nshould compose the framework-agnostic `SiteMapDiscoveryRunner` instead.\n\n### Tree-Shakeable Imports\n\n```typescript\n// Import only core client\nimport { CyberneticClient } from '@astermind/evo-virtual-assistant-client';\n\n// Import agentic features when needed\nimport {\n  CyberneticClient,\n  CyberneticAgent,\n  CyberneticIntentClassifier\n} from '@astermind/evo-virtual-assistant-client/full';\n\n// React adapter (sub-export — requires React >= 16.8 in your project)\nimport { useSiteMapDiscovery } from '@astermind/evo-virtual-assistant-client/react';\n```\n\n## API Reference\n\n### CyberneticClient\n\n```typescript\nclass CyberneticClient {\n  constructor(config: CyberneticConfig);\n\n  // Core methods\n  ask(message: string, options?: AskOptions): Promise<CyberneticResponse>;\n  askStream(message: string, callbacks: StreamCallbacks, options?: AskOptions): Promise<void>;\n\n  // Agentic methods (requires agentic config and license)\n  smartAsk(message: string, options?: AskOptions): Promise<SmartAskResult>;\n  classifyIntent(message: string): IntentClassification | null;\n  executeAction(action: AgentAction): Promise<ActionResult>;\n  isAgenticEnabled(): boolean;\n\n  // Status methods (includes license state)\n  getStatus(): { connection: ConnectionStatus; cache: CacheStatus; lastError: CyberneticError | null; systemSettings: SystemSettings | null; license: LicenseState | null };\n  checkConnection(): Promise<boolean>;\n  checkSystemStatus(): Promise<SystemSettings>;\n  isMaintenanceMode(): boolean;\n  getMaintenanceMessage(): string | undefined;\n  isCacheValid(): boolean;\n\n  // License methods\n  getLicenseManager(): LicenseManager;\n\n  // Cache methods\n  syncCache(): Promise<void>;\n  clearCache(): Promise<void>;\n\n  // Cleanup\n  destroy(): void;  // Close WebSocket connection and clean up resources\n}\n```\n\n### Response Types\n\n```typescript\ninterface CyberneticResponse {\n  reply: string;\n  confidence: 'high' | 'medium' | 'low' | 'none';\n  sources: Source[];\n  offline: boolean;\n  sessionId?: string;\n  retryAfter?: number;\n  degradedReason?: string;\n}\n\ninterface Source {\n  title: string;\n  snippet: string;\n  relevance: number;\n  documentId?: string;\n}\n\ninterface StreamCallbacks {\n  onToken?: (token: string) => void;\n  onSources?: (sources: Source[]) => void;\n  onComplete?: (response: CyberneticResponse) => void;\n  onError?: (error: CyberneticError) => void;\n}\n\ninterface CyberneticError {\n  code: 'NETWORK_ERROR' | 'AUTH_ERROR' | 'RATE_LIMIT' | 'SERVER_ERROR' | 'CACHE_ERROR' | 'LOCAL_RAG_ERROR' | 'WS_ERROR';\n  message: string;\n  retryAfter?: number;\n}\n\ninterface LicenseState {\n  status: 'valid' | 'invalid' | 'expired' | 'missing' | 'eval';\n  payload: LicensePayload | null;\n  error?: string;\n  inGracePeriod: boolean;\n  daysRemaining: number | null;\n}\n\ninterface LicensePayload {\n  iss: string;          // Issuer\n  sub: string;          // Subject (license ID)\n  aud: string;          // Audience (product)\n  iat: number;          // Issued at\n  exp: number;          // Expiration\n  plan: 'free' | 'pro' | 'business' | 'enterprise' | 'eval';\n  org?: string;         // Organization\n  seats: number;        // Number of seats\n  features: string[];   // Enabled features\n  graceUntil?: number;  // Grace period end\n  licenseVersion: number;\n}\n```\n\n## Browser Support\n\n| Browser | Version | Notes |\n|---------|---------|-------|\n| Chrome | 80+ | Full support |\n| Firefox | 75+ | Full support |\n| Safari | 13.1+ | Full support |\n| Edge | 80+ | Full support |\n\nRequires IndexedDB support for offline caching.\n\n## Integration with EVO Virtual Assistant Backend\n\nThis client is designed to work with the AsterMind EVO Virtual Assistant backend. The client supports two transport modes:\n\n**REST API Endpoints** (on-prem and supplementary):\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/api/external/chat` | POST | Send message, get complete response |\n| `/api/external/chat/stream` | POST | Send message, get SSE streaming response |\n| `/api/external/docs` | GET | Fetch documents for offline caching |\n| `/api/external/status` | GET | Check API status, quota, and system settings |\n| `/api/external/health` | GET | Health check (no auth required) |\n| `/api/external/search` | GET | Search documents |\n| `/api/external/sitemap` | GET | Get document sitemap for navigation |\n| `/api/external/config` | GET | Get virtual assistant configuration |\n\n**WebSocket Endpoint** (SaaS streaming):\n\n| Endpoint | Description |\n|----------|-------------|\n| `wss://chatws.astermind.ai` | Production WebSocket streaming |\n| `wss://chatws-dev.astermind.ai` | Development WebSocket streaming |\n\nWebSocket authentication uses an API key query parameter: `?apiKey=am_xxx`\n\n**Authentication**: REST endpoints require an `X-API-Key` header with a valid API key (prefixed with `am_`). WebSocket endpoints use a `?apiKey=am_xxx` query parameter.\n\n**Rate Limiting**: The backend enforces rate limits. The client handles 429 responses gracefully and includes `retryAfter` in responses when applicable.\n\n## Links\n\n- [AsterMind Website](https://astermind.ai)\n\n## License\n\nMIT License - see [LICENSE](LICENSE) for details.\n","readmeFilename":"README.md"}