diff --git a/.changeset/production-hardening.md b/.changeset/production-hardening.md deleted file mode 100644 index 197fa1f..0000000 --- a/.changeset/production-hardening.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@guidekit/core": patch -"@guidekit/react": patch -"@guidekit/server": patch ---- - -Production hardening: stable pipeline telemetry export and DevTools Telemetry tab; LLM/voice proxy permission and origin checks with request validation; example app Redis session-store path and operational docs (rate limits, failure modes, observability). diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 6efc30d..e9309da 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -37,6 +37,7 @@ jobs: - name: Run live E2E suite env: LIVE_LLM: '1' + SKIP_LIVE_VOICE: '1' GUIDEKIT_SECRET: guidekit-example-e2e-secret-32-chars LLM_API_KEY: ${{ secrets.LLM_API_KEY }} SKIP_NPM_DRY_RUN: '1' diff --git a/.size-limit.json b/.size-limit.json index 7f35214..52539ab 100644 --- a/.size-limit.json +++ b/.size-limit.json @@ -2,7 +2,7 @@ { "name": "@guidekit/core (ESM)", "path": "packages/core/dist/index.js", - "limit": "85 KB", + "limit": "92 KB", "gzip": true }, { diff --git a/AGENTS.md b/AGENTS.md index 2fce5c9..7de4c3c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -77,27 +77,27 @@ e2e/ └── env.ts # .env.local + LIVE_LLM detection ``` -Voice E2E always mocks the browser Web Speech API — no Deepgram/ElevenLabs in Playwright. +Voice E2E: contract tier mocks Web Speech in Playwright; live tier uses real Web Speech via Chromium fake-audio-capture (no Deepgram/ElevenLabs). ### E2E coverage matrix (user-facing flows) | Flow | Contract | Live | |------|:--------:|:----:| -| Widget UI / a11y | yes | — | +| Widget UI / a11y | yes | yes | | Proxy health / token / LLM | yes | yes | | Text chat + streaming | mocked | yes | | Multi-turn memory | — | yes | | Agent tools (scroll, highlight, navigate, tour, clickElement) | yes | yes | | Platform Mode (RAG, plugin, cognitive page) | yes | yes | | Session recovery 401 | yes | yes | -| Voice (Web Speech mock → LLM) | yes | yes | -| Custom actions / form / readPage / dismiss | yes | partial | +| Voice (Web Speech → LLM) | mocked STT | real STT | +| Custom actions / form / readPage / dismiss | yes | yes | | STT/TTS proxy key minting | yes | — | -| Hallucination guard bus event | yes | — | -| Vanilla IIFE widget | yes | — | -| Headless custom UI | yes | — | +| Hallucination guard bus event | yes | yes | +| Vanilla IIFE widget | yes | yes | +| Headless custom UI | yes | yes | -Commands: `pnpm test:e2e:contract` (CI), `pnpm test:e2e:live` (local), `pnpm test:e2e:live:full` (publish gate). +Commands: `pnpm test:e2e:contract` (CI), `pnpm test:e2e:live` (local), `pnpm test:e2e:live:full` (publish gate). Set `SKIP_LIVE_VOICE=1` to skip the headed real-Web-Speech live voice spec when STT is unavailable. Before release, run `pnpm check:release` (runs live suite twice for the flake budget). Publish workflow uploads Playwright artifacts on failure. diff --git a/SECURITY.md b/SECURITY.md index 644ffcb..4ab13e8 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,7 +4,9 @@ | Version | Supported | | ------- | --------- | -| 0.1.x | Yes | +| 1.x | Yes | +| 0.3.x | Security fixes only | +| 0.1.x | No | ## Reporting a Vulnerability diff --git a/apps/docs/app/docs/getting-started/page.mdx b/apps/docs/app/docs/getting-started/page.mdx index c3f3bc8..e47ea60 100644 --- a/apps/docs/app/docs/getting-started/page.mdx +++ b/apps/docs/app/docs/getting-started/page.mdx @@ -167,6 +167,64 @@ For quick prototyping without server routes, pass API keys directly: | Create React App | Full | | Non-React (vanilla JS) | Via `@guidekit/vanilla` | +## SPA navigation (Next.js App Router) + +GuideKit detects URL changes via the Navigation API, `popstate`, and polling. For client-side route changes that bypass full page loads, pass your App Router instance so `navigate()` and post-nav rescans stay reliable: + +```tsx +'use client'; + +import { useRouter } from 'next/navigation'; +import { GuideKitProvider } from '@guidekit/react'; + +export function Providers({ children }: { children: React.ReactNode }) { + const router = useRouter(); + + return ( + router.push(href) } }} + > + {children} + + ); +} +``` + +On each route change, GuideKit clears **PageMemory**, rescans the DOM, and emits `dom:route-change` plus `context:memory-cleared`. + +For **in-page DOM swaps** (tabs, modals, virtual lists) without a URL change, call `core.rescanPage()` after updating the UI so the assistant sees fresh sections: + +```tsx +'use client'; + +import { useEffect, useState } from 'react'; +import { useGuideKitCore } from '@guidekit/react'; + +export function TabPanel({ activeTab }: { activeTab: string }) { + const core = useGuideKitCore(); + + useEffect(() => { + if (core?.isReady) core.rescanPage(); + }, [activeTab, core]); + + return
{/* tab content */}
; +} +``` + +## Universal site checklist + +1. Proxy mode: `tokenEndpoint` + `/api/guidekit/llm` (never ship LLM keys to the browser) +2. Optional `contentMap` for product facts the DOM cannot infer +3. Optional `data-guidekit-target` on critical CTAs (improves accuracy, not required) +4. `clickableSelectors.allow/deny` for production click boundaries +5. Redis session store for multi-instance deployments +6. `hallucinationGuard={true}` + `intelligence={true}` for Platform Mode on public sites + +See the example app routes `/plain`, `/spa-rescan`, and `/iframe-test` for unannotated page demos used in contract E2E. + ## Next Steps - [Provider Setup](/docs/provider) — Configuration options in depth diff --git a/apps/docs/app/docs/observability/page.mdx b/apps/docs/app/docs/observability/page.mdx index ad94c82..571ea20 100644 --- a/apps/docs/app/docs/observability/page.mdx +++ b/apps/docs/app/docs/observability/page.mdx @@ -56,6 +56,27 @@ GuideKit guarantees these attribute keys when applicable: Additional attributes may be added over time, but existing keys are stable. +## Reliability scorecard (Universal Assistant targets) + +Track these signals in contract and live E2E suites when rolling out to production: + +| Metric | Contract target | Live target | +|--------|-----------------|-------------| +| Claim grounding (hallucination guard clean) | ≥ 90% | ≥ 85% | +| Highlight accuracy on plain pages | ≥ 85% | ≥ 85% | +| Tool success (`highlight`, `scroll`, `readPageContent`) | ≥ 95% | ≥ 90% | +| Prompt tokens per turn (after PageMemory) | −40% vs full prompt | −40% | + +**Bus events for context and grounding:** + +- `context:memory-rebuild` — PageMemory rebuilt after route or hash change +- `context:delta` — incremental TurnDelta sent on subsequent turns +- `element:resolve` — semantic ref resolved to selector (`confidence`, `reason`) +- `action:confirmation-required` — dangerous click blocked pending user confirmation +- `validation:corrected` — high-severity hallucination issues appended to response + +Use DevTools **Events** or `window.__guidekitTest` in the example app to capture these during E2E debugging. + ## Debugging workflow 1. Reproduce the slow or failed message in dev with `options={{ debug: true }}`. diff --git a/apps/example-nextjs/CHANGELOG.md b/apps/example-nextjs/CHANGELOG.md index d81cc8d..e24d919 100644 --- a/apps/example-nextjs/CHANGELOG.md +++ b/apps/example-nextjs/CHANGELOG.md @@ -4,6 +4,18 @@ ### Patch Changes +- Updated dependencies [e504e76] + - @guidekit/core@1.1.0 + - @guidekit/react@1.2.0 + - @guidekit/server@1.0.2 + - @guidekit/intelligence@2.0.0 + - @guidekit/knowledge@2.0.0 + - @guidekit/plugins@2.0.0 + +## 0.0.4 + +### Patch Changes + - Updated dependencies [2b44662] - @guidekit/core@1.0.0 - @guidekit/react@1.0.0 diff --git a/apps/example-nextjs/app/(main)/iframe-test/page.tsx b/apps/example-nextjs/app/(main)/iframe-test/page.tsx new file mode 100644 index 0000000..edc03cb --- /dev/null +++ b/apps/example-nextjs/app/(main)/iframe-test/page.tsx @@ -0,0 +1,27 @@ +export default function IframeTestPage() { + return ( +
+

Iframe Grounding Demo

+

Same-origin iframe content is readable; cross-origin iframes are listed as limitations.

+ +
+

Same-origin embed

+