@sentientui/react 0.12.1 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,33 +1,34 @@
1
1
  # @sentientui/react
2
2
 
3
- React SDK for [SentientUI](https://sentient-ui.com) — drop-in components and hooks that let a Thompson Sampling bandit, persona clusters, and visitor portraits automatically serve the best-performing UI variant (and section order) for each visitor.
4
-
5
- Learning, assignment, portraits, clustering, and graph storage all run on the SentientUI hosted API. You only install the SDK and add API keys from the dashboard.
3
+ React SDK for [SentientUI](https://sentient-ui.com) — the adaptive ladder. Declare bounded
4
+ variations (styles, content, arrangement order); a persona-keyed optimizer on the hosted API
5
+ learns which one converts best for each visitor type. Visit 1 learns; Visit 2 converts.
6
6
 
7
7
  ## Installation
8
8
 
9
9
  ```bash
10
- npm install @sentientui/react
11
- # or
12
- pnpm add @sentientui/react
10
+ npm install @sentientui/react # or: npx sentientui init (scaffolds everything)
13
11
  ```
14
12
 
15
- `@sentientui/core` is a transitive dependency — you do not need to install it directly. Only import from `@sentientui/react`.
13
+ ## 60-second start (no account)
16
14
 
17
- ## API key
15
+ ```bash
16
+ npx sentientui init && npm run dev
17
+ # open http://localhost:3000?sentient_persona=buyer — watch the page adapt
18
+ ```
18
19
 
19
- Create a project at [sentient-ui.com](https://sentient-ui.com) and copy the API key shown once at project creation. It looks like `pk_xxxxxxxx…`. The key is safe to ship in browser bundles the API enforces an allowed-origins allowlist on every request. Add your production domain in Project → Settings → Allowed origins.
20
+ With no API key the SDK runs in keyless **local mode**: deterministic simulated decisions, zero
21
+ network. Add a `pk_…` key from [sentient-ui.com](https://sentient-ui.com) to learn from real
22
+ traffic:
20
23
 
21
24
  ```bash
22
25
  # .env.local
23
26
  NEXT_PUBLIC_SENTIENT_API_KEY=pk_your_key
24
27
  ```
25
28
 
26
- One env var is all you need. The SDK points at `https://api.sentient-ui.com` automatically — no ingest URL required.
27
-
28
- ## Quick start — Next.js App Router (recommended)
29
+ ## Setup
29
30
 
30
- Wrap your root layout with `<AdaptiveRoot>`. It is a Server Component: variant assignments and persona-specific layout order are resolved server-side before HTML is sent, so the first paint has the right content with no layout shift.
31
+ Wrap your root layout (Next App Router server component):
31
32
 
32
33
  ```tsx
33
34
  // app/layout.tsx
@@ -35,14 +36,9 @@ import { AdaptiveRoot } from '@sentientui/react/next';
35
36
 
36
37
  export default function RootLayout({ children }: { children: React.ReactNode }) {
37
38
  return (
38
- <html lang="en">
39
+ <html lang="en" suppressHydrationWarning>
39
40
  <body>
40
41
  <AdaptiveRoot
41
- components={[
42
- { id: 'hero_cta', variantIds: ['control', 'variant_a'] },
43
- { id: 'pricing', variantIds: ['monthly', 'annual_first'] },
44
- ]}
45
- sections={['hero', 'pricing', 'features', 'social_proof']}
46
42
  apiKey={process.env.NEXT_PUBLIC_SENTIENT_API_KEY!}
47
43
  appOrigin={process.env.NEXT_PUBLIC_APP_URL!}
48
44
  context="saas"
@@ -55,44 +51,116 @@ export default function RootLayout({ children }: { children: React.ReactNode })
55
51
  }
56
52
  ```
57
53
 
58
- Then drop `<Adaptive>` anywhere you want a tested component:
54
+ `suppressHydrationWarning` on `<html>` is required: an inline script (rendered by
55
+ `AdaptiveRoot` as its first child) sets the persona attributes before first paint, exactly like
56
+ the `next-themes` pattern. Other React apps (Vite, CRA, Remix, Pages Router) use
57
+ `<AdaptiveProvider>` from `@sentientui/react` with the same props.
58
+
59
+ ## The adaptive ladder
60
+
61
+ ### Rung 0 — Observe
62
+
63
+ Install is the integration. The dashboard immediately shows who is arriving: persona mix, device
64
+ and traffic-source segments, engagement signals. The "Suggested next step" card tells you which
65
+ rung to climb next, with a copy-pasteable snippet.
66
+
67
+ ### Rung 1 — Style (CSS only)
68
+
69
+ **1a. Persona attributes — zero declaration.** The SDK sets on `<html>`:
70
+
71
+ ```
72
+ data-sentient-persona = buyer | researcher | deal_seeker | browser | unknown
73
+ data-sentient-confidence = low | medium | high
74
+ ```
75
+
76
+ Write plain CSS against them (the canonical block — safe defaults for every persona):
77
+
78
+ ```css
79
+ /* Show each visitor type what it cares about. Confidence-gate bold treatments. */
80
+ html[data-sentient-persona='buyer'] .cta-primary { font-weight: 700; }
81
+ html[data-sentient-persona='researcher'] .spec-details { display: block; }
82
+ html[data-sentient-persona='deal_seeker'] .discount-banner { display: block; }
83
+ html[data-sentient-persona='browser'] .newsletter-nudge { display: block; }
84
+ html[data-sentient-confidence='low'] .discount-banner,
85
+ html[data-sentient-confidence='low'] .newsletter-nudge { display: none; }
86
+ ```
87
+
88
+ Force any persona in dev: `?sentient_persona=deal_seeker`.
89
+
90
+ **1b. Adaptive tokens — learned.** Declare a bounded design space; the optimizer picks per
91
+ visitor type; values arrive as element-scoped `data-*` props (SSR-serialized — zero flicker):
59
92
 
60
93
  ```tsx
61
- import { Adaptive } from '@sentientui/react';
94
+ import { useAdaptiveTokens } from '@sentientui/react';
62
95
 
63
- export default function Hero() {
64
- return (
65
- <Adaptive
66
- id="hero_cta"
67
- goal="signup_click"
68
- variants={{
69
- control: <button className="btn-dark">Start free trial</button>,
70
- variant_a: <button className="btn-blue">Get instant access →</button>,
71
- }}
72
- />
73
- );
96
+ function Hero() {
97
+ const t = useAdaptiveTokens('hero', {
98
+ tone: ['calm', 'urgent'], // first value = baseline (what you show today)
99
+ motion: ['none', 'pulse'],
100
+ });
101
+ return <section {...t.props} className="hero">…</section>;
102
+ // t.props → { 'data-tone': 'urgent', 'data-motion': 'pulse' }
103
+ // t.tokens → { tone: 'urgent', motion: 'pulse' }
104
+ }
105
+ ```
106
+
107
+ ```css
108
+ .hero[data-tone='urgent'] .cta { font-weight: 700; }
109
+
110
+ /* Animation values are enum values whose CSS you own — always respect reduced motion: */
111
+ .hero[data-motion='pulse'] .cta { animation: pulse 2s infinite; }
112
+ @media (prefers-reduced-motion: reduce) {
113
+ .hero[data-motion='pulse'] .cta { animation: none; }
74
114
  }
75
115
  ```
76
116
 
77
- ## Quick start other React apps (Vite, CRA, Remix, Pages Router)
117
+ Constraints: 1–4 dims, 2–6 values each, combinations 64. Enum values only — no arbitrary CSS.
118
+ Optional `{ goal: 'buy_click' }` third argument credits conversions to this element directly.
78
119
 
79
- Use `<AdaptiveProvider>` directly. Assignments are made on the client after mount no SSR preloading, but the bandit still learns normally.
120
+ ### Rung 2Swap (alternate content)
80
121
 
81
122
  ```tsx
82
- import { AdaptiveProvider } from '@sentientui/react';
83
-
84
- export default function App({ children }: { children: React.ReactNode }) {
85
- return (
86
- <AdaptiveProvider
87
- apiKey={import.meta.env.VITE_SENTIENT_API_KEY}
88
- context="saas"
89
- >
90
- {children}
91
- </AdaptiveProvider>
92
- );
123
+ import { useAdaptive } from '@sentientui/react';
124
+
125
+ function BuyBox() {
126
+ const { variant, value, bind, fireGoal } = useAdaptive('buy-box', {
127
+ variants: { calm: <CalmBuyBox />, urgent: <UrgentBuyBox /> }, // first key = baseline
128
+ goal: 'buy_click', // required
129
+ });
130
+ return <div {...bind}>{value}</div>;
93
131
  }
94
132
  ```
95
133
 
134
+ `bind` (ref + data attributes) wires exposure tracking, goal listeners, and engagement signals —
135
+ attach it or the slot cannot learn (dev mode warns loudly if you don't). `<Adaptive>` is the
136
+ wrapper form of the same rung; `<AdaptiveText>` swaps dashboard-managed text.
137
+
138
+ ### Rung 3 — Reorder (structure)
139
+
140
+ Region-scope — declared arrangements of keyed children only, never free permutation:
141
+
142
+ ```tsx
143
+ import { AdaptiveGroup } from '@sentientui/react';
144
+
145
+ <AdaptiveGroup
146
+ id="pricing-area"
147
+ arrangements={{
148
+ standard: ['plans', 'faq', 'social'], // first key = baseline
149
+ social_first: ['social', 'plans', 'faq'],
150
+ }}
151
+ goal="plan_selected"
152
+ >
153
+ <PlanGrid key="plans" />
154
+ <Faq key="faq" />
155
+ <Testimonials key="social" />
156
+ </AdaptiveGroup>
157
+ ```
158
+
159
+ Page-scope — declare `sections` on `AdaptiveRoot` and read the order with `useLayoutOrder()`
160
+ (see the API reference below). Use `AdaptiveGroup` for a region, `sections` for the page.
161
+
162
+ Every decision is locked for the session — visitors never see the page reshuffle under them.
163
+
96
164
  ## API
97
165
 
98
166
  ### `<AdaptiveRoot>` (Next.js App Router — server component)
@@ -184,8 +252,59 @@ import { AdaptiveText } from '@sentientui/react';
184
252
  </h1>
185
253
  ```
186
254
 
255
+ ### `useAdaptiveTokens(id, dims, opts?)`
256
+
257
+ ```ts
258
+ function useAdaptiveTokens(
259
+ id: string,
260
+ dims: Record<string, readonly string[]>, // 1–4 dims × 2–6 values; first value = baseline
261
+ opts?: { goal?: string | GoalConfig },
262
+ ): { tokens: Record<string, string>; props: Record<string, string> }; // props keys: `data-${dim}`
263
+ ```
264
+
265
+ Spread `props` onto the element you style. Values serialize through SSR markup — no flicker, no
266
+ hydration mismatch. Renaming a value is a cold start for that value's learning.
267
+
268
+ ### `useAdaptive(id, config)`
269
+
270
+ ```ts
271
+ function useAdaptive<T>(
272
+ id: string,
273
+ config: { variants: Record<string, T>; goal: string | GoalConfig }, // first key = baseline
274
+ ): {
275
+ variant: string;
276
+ value: T;
277
+ bind: { ref: (el: HTMLElement | null) => void; 'data-sentient-id': string; 'data-sentient-variant': string };
278
+ fireGoal: (goalType?: string, opts?: ComponentGoalOptions) => void;
279
+ };
280
+ ```
281
+
282
+ Headless Swap-rung hook. `goal` is required and `bind` must be attached to a rendered element —
283
+ learning needs both. Supersedes `useAssignment`.
284
+
285
+ ### `<AdaptiveGroup>`
286
+
287
+ | Prop | Type | Description |
288
+ |------|------|-------------|
289
+ | `id` | `string` | Unique group identifier. |
290
+ | `arrangements` | `Record<string, string[]>` | Arrangement id → ordered child keys. First entry = baseline. |
291
+ | `baseline` | `string` *(optional)* | Explicit baseline arrangement id (defaults to the first key). |
292
+ | `goal` | `string \| GoalConfig` *(optional)* | Conversion goal credited to this group. |
293
+ | `children` | keyed `ReactNode`s | Every key referenced by an arrangement must exist. |
294
+
295
+ Reorders via React keys (DOM moves, state preserved). Declared orders only.
296
+
297
+ ### Persona attributes (Rung 1a)
298
+
299
+ `AdaptiveRoot` renders an inline script (its first child) that sets `data-sentient-persona` and
300
+ `data-sentient-confidence` on `<html>` before first paint; the client SDK adopts those values
301
+ and never rewrites them mid-session. Requirements: `suppressHydrationWarning` on `<html>`,
302
+ `AdaptiveRoot` at the top of the tree. Override in dev with `?sentient_persona=<persona>`.
303
+
187
304
  ### `useAssignment(componentId, variantIds?)`
188
305
 
306
+ > **Deprecated** — use [`useAdaptive`](#useadaptiveid-config) instead; it carries the goal and exposure wiring `useAssignment` leaves to you. Kept for backward compatibility.
307
+
189
308
  Lower-level hook when you need the variant ID inside your own render logic (e.g. full-page layout tests where `<Adaptive>`'s wrapper `<div>` would break a flex/grid layout).
190
309
 
191
310
  ```tsx
@@ -1,5 +1,6 @@
1
+ declare const LOCAL_MODE_DEVTOOLS_BANNER = "Local mode \u2014 decisions are simulated; add a key to learn from real traffic";
1
2
  declare function AdaptiveDevtools({ apiKey }?: {
2
3
  apiKey?: string;
3
4
  }): JSX.Element | null;
4
5
 
5
- export { AdaptiveDevtools };
6
+ export { AdaptiveDevtools, LOCAL_MODE_DEVTOOLS_BANNER };
@@ -1,5 +1,6 @@
1
+ declare const LOCAL_MODE_DEVTOOLS_BANNER = "Local mode \u2014 decisions are simulated; add a key to learn from real traffic";
1
2
  declare function AdaptiveDevtools({ apiKey }?: {
2
3
  apiKey?: string;
3
4
  }): JSX.Element | null;
4
5
 
5
- export { AdaptiveDevtools };
6
+ export { AdaptiveDevtools, LOCAL_MODE_DEVTOOLS_BANNER };
package/dist/devtools.js CHANGED
@@ -1,3 +1,3 @@
1
1
  'use client';
2
- "use strict";"use client";var l=Object.defineProperty;var P=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames,x=Object.getOwnPropertySymbols;var h=Object.prototype.hasOwnProperty,B=Object.prototype.propertyIsEnumerable;var w=(e,t,i)=>t in e?l(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i,R=(e,t)=>{for(var i in t||(t={}))h.call(t,i)&&w(e,i,t[i]);if(x)for(var i of x(t))B.call(t,i)&&w(e,i,t[i]);return e};var I=(e,t)=>{for(var i in t)l(e,i,{get:t[i],enumerable:!0})},N=(e,t,i,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of E(t))!h.call(e,r)&&r!==i&&l(e,r,{get:()=>t[r],enumerable:!(s=P(t,r))||s.enumerable});return e};var D=e=>N(l({},"__esModule",{value:!0}),e);var z={};I(z,{AdaptiveDevtools:()=>j});module.exports=D(z);var p=require("react");var V=new Map,k=new Set;function c(){return[...V.values()]}function S(e){return k.add(e),()=>{k.delete(e)}}function f(){let e=window;return e.__sentient_overrides||(e.__sentient_overrides={}),e.__sentient_overrides}function m(e,t){f()[e]=t}function O(e){delete f()[e]}function b(){return R({},f())}var y=!1,M=new Set;function u(e){if(y!==e){y=e;for(let t of M)t()}}function _(){return y}var n=require("react/jsx-runtime"),C,A=typeof process!="undefined"&&((C=process.env)==null?void 0:C.NODE_ENV)==="production",T=["browsers","buyers","researchers","deal-seekers"];async function W(e,t){let i=c().map(d=>({id:d.id})),s=c().map(d=>({id:d.id,variantIds:d.variantIds})),r=await fetch("/v1/explain",{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e}`},body:JSON.stringify({persona:t,sections:i,components:s})});if(!r.ok)return;let g=await r.json();for(let[d,v]of Object.entries(g.assignments))m(d,v);u(!0)}function j({apiKey:e}={}){let[t,i]=(0,p.useState)(!1),[,s]=(0,p.useReducer)(o=>o+1,0);if((0,p.useEffect)(()=>S(s),[]),A)return null;let r=c(),g=b();function d(o,a){m(o,a),u(!0),s()}function v(o){O(o),Object.keys(b()).length===0&&u(!1),s()}return(0,n.jsxs)("div",{style:{position:"fixed",bottom:16,right:16,zIndex:2147483647,fontFamily:"system-ui"},children:[t&&(0,n.jsxs)("div",{style:{width:300,maxHeight:420,overflowY:"auto",background:"#111",color:"#eee",borderRadius:8,padding:12,marginBottom:8,boxShadow:"0 8px 30px rgba(0,0,0,.4)",fontSize:12},children:[(0,n.jsxs)("div",{style:{opacity:.7,marginBottom:8},children:[r.length," component",r.length===1?"":"s"," \xB7 ",_()?"preview \u2014 writing nothing":"live"]}),e&&(0,n.jsxs)("div",{style:{borderBottom:"1px solid #333",paddingBottom:8,marginBottom:8},children:[(0,n.jsx)("div",{style:{opacity:.7,marginBottom:4},children:"Preview persona"}),(0,n.jsx)("div",{style:{display:"flex",flexWrap:"wrap",gap:4},children:T.map(o=>(0,n.jsx)("button",{onClick:()=>{W(e,o).then(s)},style:{padding:"2px 8px",borderRadius:4,border:"1px solid #444",background:"#222",color:"#eee",cursor:"pointer"},children:o},o))})]}),r.length===0&&(0,n.jsx)("div",{style:{opacity:.6},children:"No components on this page yet."}),r.map(o=>(0,n.jsxs)("div",{style:{borderTop:"1px solid #333",padding:"8px 0"},children:[(0,n.jsxs)("div",{style:{fontWeight:600},children:[o.id,o.goal?` \xB7 goal: ${o.goal}`:""]}),(0,n.jsxs)("div",{style:{display:"flex",flexWrap:"wrap",gap:4,marginTop:4},children:[o.variantIds.map(a=>(0,n.jsx)("button",{onClick:()=>d(o.id,a),style:{padding:"2px 8px",borderRadius:4,border:"1px solid #444",background:g[o.id]===a?"#3b82f6":"#222",color:"#eee",cursor:"pointer"},children:a},a)),g[o.id]&&(0,n.jsx)("button",{onClick:()=>v(o.id),style:{padding:"2px 8px",borderRadius:4,border:"1px solid #444",background:"#222",color:"#aaa",cursor:"pointer"},children:"reset"})]})]},o.id))]}),(0,n.jsx)("button",{"aria-label":"Sentient DevTools",onClick:()=>i(o=>!o),style:{width:40,height:40,borderRadius:20,border:"none",background:"#3b82f6",color:"#fff",cursor:"pointer",boxShadow:"0 4px 14px rgba(0,0,0,.3)"},children:"\u25E7"})]})}0&&(module.exports={AdaptiveDevtools});
2
+ "use strict";"use client";var ce=Object.create;var S=Object.defineProperty,pe=Object.defineProperties,ge=Object.getOwnPropertyDescriptor,ue=Object.getOwnPropertyDescriptors,fe=Object.getOwnPropertyNames,U=Object.getOwnPropertySymbols,ve=Object.getPrototypeOf,F=Object.prototype.hasOwnProperty,me=Object.prototype.propertyIsEnumerable;var z=(e,t,o)=>t in e?S(e,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[t]=o,d=(e,t)=>{for(var o in t||(t={}))F.call(t,o)&&z(e,o,t[o]);if(U)for(var o of U(t))me.call(t,o)&&z(e,o,t[o]);return e},h=(e,t)=>pe(e,ue(t));var ye=(e,t)=>{for(var o in t)S(e,o,{get:t[o],enumerable:!0})},G=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of fe(t))!F.call(e,a)&&a!==o&&S(e,a,{get:()=>t[a],enumerable:!(r=ge(t,a))||r.enumerable});return e};var _e=(e,t,o)=>(o=e!=null?ce(ve(e)):{},G(t||!e||!e.__esModule?S(o,"default",{value:e,enumerable:!0}):o,e)),we=e=>G(S({},"__esModule",{value:!0}),e);var Le={};ye(Le,{AdaptiveDevtools:()=>Ae,LOCAL_MODE_DEVTOOLS_BANNER:()=>Q});module.exports=we(Le);var c=require("react"),_=require("@sentientui/policy"),q=require("@sentientui/core");var be={components:new Map,slots:new Map,sections:[],listeners:new Set};function R(){if(typeof window=="undefined")return be;let e=window;return e.__sentient_registry||(e.__sentient_registry={components:new Map,slots:new Map,sections:[],listeners:new Set}),e.__sentient_registry}function O(){return[...R().components.values()]}function A(){return[...R().slots.values()]}function L(){return[...R().sections]}function H(e){let t=R().listeners;return t.add(e),()=>{t.delete(e)}}function W(){let e=window;return e.__sentient_overrides||(e.__sentient_overrides={}),e.__sentient_overrides}function D(e,t){W()[e]=t}function I(e){delete W()[e]}function k(){return d({},W())}function T(){let e=window;return e.__sentient_slot_overrides||(e.__sentient_slot_overrides={}),e.__sentient_slot_overrides}function B(e,t){T()[e]=t}function Y(e){delete T()[e]}function C(){return d({},T())}var Se={on:!1,listeners:new Set};function J(){if(typeof window=="undefined")return Se;let e=window;return e.__sentient_preview||(e.__sentient_preview={on:!1,listeners:new Set}),e.__sentient_preview}function f(e){let t=J();if(t.on!==e){t.on=e;for(let o of t.listeners)o()}}function K(){return J().on}var he="sentient:overrides-changed";function g(){var t;if(typeof window=="undefined")return;let e=window;e.__sentient_overrides_version=((t=e.__sentient_overrides_version)!=null?t:0)+1,window.dispatchEvent(new Event(he))}function X(){var e;return typeof window=="undefined"?null:(e=window.__sentient_devtools_config)!=null?e:null}var i=require("react/jsx-runtime"),$,xe=typeof process!="undefined"&&(($=process.env)==null?void 0:$.NODE_ENV)==="production",Re="https://api.sentient-ui.com/v1",Q="Local mode \u2014 decisions are simulated; add a key to learn from real traffic";function Z(e){var o,r;for(let[a,m]of Object.entries((o=e.assignments)!=null?o:{}))D(a,m);let t=window;e.layoutOrder&&e.layoutOrder.length>0&&(t.__sentient_layout_override=e.layoutOrder),e.slots&&(t.__sentient_slot_overrides=d(d({},(r=t.__sentient_slot_overrides)!=null?r:{}),e.slots)),e.personaAttributes&&(document.documentElement.dataset.sentientPersona=e.personaAttributes.persona,document.documentElement.dataset.sentientConfidence=e.personaAttributes.confidence),f(!0),g()}function Oe(){try{let e=document.cookie.match(/(?:^|; )_snt_uid=([^;]*)/);if(e)return decodeURIComponent(e[1])}catch(e){}return"devtools-preview"}function ee(){return A().map(e=>d(d({id:e.id},e.arms?{arms:e.arms}:{}),e.dims?{dims:e.dims}:{}))}async function ke(e,t,o){var m;let r=await fetch(`${t}/explain`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e}`},body:JSON.stringify({persona:o,sections:L().map(y=>({id:y})),components:O().map(y=>({id:y.id,variantIds:y.variantIds})),slots:ee()})});if(!r.ok)return;let a=await r.json();Z(h(d({},a),{personaAttributes:(m=a.personaAttributes)!=null?m:{persona:o,confidence:"high"}}))}async function Ce(e){let t=await import("@sentientui/core/local");if(!t.LOCAL_ENGINE_AVAILABLE)return;let o=t.createLocalEngine({sessionId:Oe(),forcedPersona:e}).decide({sections:L(),components:O().map(r=>({id:r.id,variantIds:r.variantIds})),slots:ee()});Z({assignments:o.assignments,layoutOrder:o.layoutOrder,slots:o.slots,personaAttributes:{persona:o.persona,confidence:(0,_.confidenceBand)(o.confidence)}})}function Pe(){for(let t of Object.keys(k()))I(t);let e=window;delete e.__sentient_layout_override,delete e.__sentient_slot_overrides,delete document.documentElement.dataset.sentientPersona,delete document.documentElement.dataset.sentientConfidence;try{let t=[];for(let o=0;o<localStorage.length;o++){let r=localStorage.key(o);r&&r.startsWith(q.SNAPSHOT_STORAGE_KEY_PREFIX)&&t.push(r)}for(let o of t)localStorage.removeItem(o)}catch(t){}f(!1),g();try{window.location.reload()}catch(t){}}var v=e=>({padding:"2px 8px",borderRadius:4,border:"1px solid #444",background:e?"#3b82f6":"#222",color:"#eee",cursor:"pointer"});function Ee({size:e=26}={}){return(0,i.jsxs)("svg",{width:e,height:e,viewBox:"0 0 32 32",fill:"none","aria-hidden":"true",children:[(0,i.jsx)("path",{d:"M21 9H14C11.2 9 9.8 10.8 9.8 13C9.8 15.4 11.6 16.6 14.5 16.6H18.5C20.5 16.6 20.7 18.2 20.4 19.6",stroke:"#fff",strokeWidth:"2.2",strokeLinecap:"round",strokeLinejoin:"round"}),(0,i.jsx)("path",{d:"M10 22H17",stroke:"#fff",strokeWidth:"2.2",strokeLinecap:"round"}),(0,i.jsx)("circle",{cx:"20.6",cy:"22",r:"2.1",fill:"#fff"})]})}function Ae({apiKey:e}={}){var N;let[t,o]=(0,c.useState)(!1),[r,a]=(0,c.useState)(null),[m,y]=(0,c.useState)(!1),[,u]=(0,c.useReducer)(n=>n+1,0);if((0,c.useEffect)(()=>H(u),[]),(0,c.useEffect)(()=>y(!0),[]),xe||!m)return null;let w=(N=X())!=null?N:{apiKey:e!=null?e:"",apiBaseUrl:Re,isLocal:!1},te=w.isLocal||!w.apiKey,x=O(),P=A(),E=k(),M=C();function j(){Object.keys(k()).length===0&&Object.keys(C()).length===0&&f(!1)}function ne(n,s){D(n,s),f(!0),g(),u()}function oe(n){I(n),j(),g(),u()}function ie(n,s){B(n,s),f(!0),g(),u()}function re(n,s,l,b){let p=C()[n],V=p&&typeof p=="object"?d({},p):Object.fromEntries(Object.entries(b!=null?b:{}).map(([ae,le])=>[ae,le[0]]));V[s]=l,B(n,V),f(!0),g(),u()}function se(n){Y(n),j(),g(),u()}function de(n){a(n),(te?Ce(n):ke(w.apiKey,w.apiBaseUrl,n)).then(u)}return(0,i.jsxs)("div",{style:{position:"fixed",bottom:16,right:16,zIndex:2147483647,fontFamily:"system-ui"},children:[(0,i.jsx)("div",{"aria-hidden":!t,style:{position:"absolute",bottom:52,right:0,transformOrigin:"bottom right",transition:"opacity .18s ease, transform .2s cubic-bezier(.16,1,.3,1)",opacity:t?1:0,transform:t?"translateY(0) scale(1)":"translateY(6px) scale(.96)",pointerEvents:t?"auto":"none"},children:(0,i.jsxs)("div",{style:{width:300,maxHeight:460,overflowY:"auto",background:"#111",color:"#eee",borderRadius:8,padding:12,boxShadow:"0 8px 30px rgba(0,0,0,.4)",fontSize:12},children:[w.isLocal&&(0,i.jsx)("div",{style:{background:"#1e293b",border:"1px solid #334155",borderRadius:4,padding:"6px 8px",marginBottom:8},children:Q}),(0,i.jsxs)("div",{style:{opacity:.7,marginBottom:8},children:[x.length," component",x.length===1?"":"s"," \xB7 ",K()?"preview \u2014 writing nothing":"live"]}),(0,i.jsxs)("div",{style:{borderBottom:"1px solid #333",paddingBottom:8,marginBottom:8},children:[(0,i.jsx)("div",{style:{opacity:.7,marginBottom:4},children:"Preview persona"}),(0,i.jsxs)("div",{style:{display:"flex",flexWrap:"wrap",gap:4},children:[_.PERSONAS.map(n=>(0,i.jsx)("button",{onClick:()=>de(n),style:v(r===n),children:_.PERSONA_DISPLAY[n]},n)),(r!==null||Object.keys(E).length>0||Object.keys(M).length>0)&&(0,i.jsx)("button",{onClick:Pe,style:h(d({},v(!1)),{color:"#aaa"}),children:"Reset"})]})]}),x.length===0&&P.length===0&&(0,i.jsx)("div",{style:{opacity:.6},children:"No components or slots on this page yet."}),x.map(n=>(0,i.jsxs)("div",{style:{borderTop:"1px solid #333",padding:"8px 0"},children:[(0,i.jsxs)("div",{style:{fontWeight:600},children:[n.id,n.goal?` \xB7 goal: ${n.goal}`:""]}),(0,i.jsxs)("div",{style:{display:"flex",flexWrap:"wrap",gap:4,marginTop:4},children:[n.variantIds.map(s=>(0,i.jsx)("button",{onClick:()=>ne(n.id,s),style:v(E[n.id]===s),children:s},s)),E[n.id]&&(0,i.jsx)("button",{onClick:()=>oe(n.id),style:h(d({},v(!1)),{color:"#aaa"}),children:"reset"})]})]},n.id)),P.length>0&&(0,i.jsxs)("div",{style:{borderTop:"1px solid #333",paddingTop:8,marginTop:4},children:[(0,i.jsx)("div",{style:{opacity:.7,marginBottom:4},children:"Slots"}),P.map(n=>{let s=M[n.id];return(0,i.jsxs)("div",{style:{padding:"6px 0"},children:[(0,i.jsx)("div",{style:{fontWeight:600},children:n.id}),n.arms&&(0,i.jsx)("div",{style:{display:"flex",flexWrap:"wrap",gap:4,marginTop:4},children:n.arms.map(l=>(0,i.jsx)("button",{onClick:()=>ie(n.id,l),style:v(s===l),children:l},l))}),n.dims&&Object.entries(n.dims).map(([l,b])=>(0,i.jsxs)("div",{style:{marginTop:4},children:[(0,i.jsx)("div",{style:{opacity:.6,fontSize:11},children:l}),(0,i.jsx)("div",{style:{display:"flex",flexWrap:"wrap",gap:4},children:b.map(p=>(0,i.jsx)("button",{onClick:()=>re(n.id,l,p,n.dims),style:v(!!s&&typeof s=="object"&&s[l]===p),children:p},p))})]},l)),s!==void 0&&(0,i.jsx)("button",{onClick:()=>se(n.id),style:h(d({},v(!1)),{color:"#aaa",marginTop:4}),children:"reset"})]},n.id)})]})]})}),(0,i.jsx)("button",{"aria-label":"Sentient DevTools","aria-expanded":t,onClick:()=>o(n=>!n),style:{width:44,height:44,borderRadius:12,border:"1px solid #2a2a2a",background:"#000",display:"flex",alignItems:"center",justifyContent:"center",padding:0,cursor:"pointer",boxShadow:"0 6px 18px rgba(0,0,0,.4)"},children:(0,i.jsx)(Ee,{})})]})}0&&(module.exports={AdaptiveDevtools,LOCAL_MODE_DEVTOOLS_BANNER});
3
3
  //# sourceMappingURL=devtools.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/devtools/index.tsx","../src/devtools-registry.ts","../src/devtools-overrides.ts","../src/preview-mode.ts"],"sourcesContent":["'use client';\nimport { useEffect, useReducer, useState } from 'react';\nimport { getRegistered, subscribeRegistry } from '../devtools-registry.js';\nimport { setVariantOverride, clearVariantOverride, getOverrides } from '../devtools-overrides.js';\nimport { setPreviewMode, getPreviewMode } from '../preview-mode.js';\n\ndeclare const process: { env?: { NODE_ENV?: string } } | undefined;\nconst IS_PROD = typeof process !== 'undefined' && process.env?.NODE_ENV === 'production';\n\nconst SEED_PERSONAS = ['browsers', 'buyers', 'researchers', 'deal-seekers'];\n\n/** Simulate a persona via /v1/explain (read-only) and apply the result as overrides. */\nasync function forcePersona(apiKey: string, persona: string): Promise<void> {\n const sections = getRegistered().map((c) => ({ id: c.id }));\n const components = getRegistered().map((c) => ({ id: c.id, variantIds: c.variantIds }));\n const res = await fetch('/v1/explain', {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${apiKey}` },\n body: JSON.stringify({ persona, sections, components }),\n });\n if (!res.ok) return;\n const data = (await res.json()) as { assignments: Record<string, string> };\n for (const [id, variantId] of Object.entries(data.assignments)) setVariantOverride(id, variantId);\n setPreviewMode(true);\n}\n\nexport function AdaptiveDevtools({ apiKey }: { apiKey?: string } = {}): JSX.Element | null {\n const [open, setOpen] = useState(false);\n const [, force] = useReducer((n: number) => n + 1, 0);\n useEffect(() => subscribeRegistry(force), []);\n\n // Never render in production, even if imported by mistake. (Hooks run first\n // so the rules of hooks hold regardless of this compile-time constant.)\n if (IS_PROD) return null;\n\n const components = getRegistered();\n const overrides = getOverrides();\n\n function choose(id: string, variantId: string): void {\n setVariantOverride(id, variantId);\n setPreviewMode(true); // suppress events while previewing\n force();\n }\n function reset(id: string): void {\n clearVariantOverride(id);\n if (Object.keys(getOverrides()).length === 0) setPreviewMode(false);\n force();\n }\n\n return (\n <div style={{ position: 'fixed', bottom: 16, right: 16, zIndex: 2147483647, fontFamily: 'system-ui' }}>\n {open && (\n <div style={{ width: 300, maxHeight: 420, overflowY: 'auto', background: '#111', color: '#eee',\n borderRadius: 8, padding: 12, marginBottom: 8, boxShadow: '0 8px 30px rgba(0,0,0,.4)', fontSize: 12 }}>\n <div style={{ opacity: .7, marginBottom: 8 }}>\n {components.length} component{components.length === 1 ? '' : 's'} · {getPreviewMode() ? 'preview — writing nothing' : 'live'}\n </div>\n {apiKey && (\n <div style={{ borderBottom: '1px solid #333', paddingBottom: 8, marginBottom: 8 }}>\n <div style={{ opacity: .7, marginBottom: 4 }}>Preview persona</div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>\n {SEED_PERSONAS.map((p) => (\n <button key={p} onClick={() => void forcePersona(apiKey, p).then(force)}\n style={{ padding: '2px 8px', borderRadius: 4, border: '1px solid #444', background: '#222', color: '#eee', cursor: 'pointer' }}>\n {p}\n </button>\n ))}\n </div>\n </div>\n )}\n {components.length === 0 && <div style={{ opacity: .6 }}>No components on this page yet.</div>}\n {components.map((c) => (\n <div key={c.id} style={{ borderTop: '1px solid #333', padding: '8px 0' }}>\n <div style={{ fontWeight: 600 }}>{c.id}{c.goal ? ` · goal: ${c.goal}` : ''}</div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4, marginTop: 4 }}>\n {c.variantIds.map((v) => (\n <button key={v} onClick={() => choose(c.id, v)}\n style={{ padding: '2px 8px', borderRadius: 4, border: '1px solid #444',\n background: overrides[c.id] === v ? '#3b82f6' : '#222', color: '#eee', cursor: 'pointer' }}>\n {v}\n </button>\n ))}\n {overrides[c.id] && (\n <button onClick={() => reset(c.id)}\n style={{ padding: '2px 8px', borderRadius: 4, border: '1px solid #444', background: '#222', color: '#aaa', cursor: 'pointer' }}>\n reset\n </button>\n )}\n </div>\n </div>\n ))}\n </div>\n )}\n <button aria-label=\"Sentient DevTools\" onClick={() => setOpen((o) => !o)}\n style={{ width: 40, height: 40, borderRadius: 20, border: 'none', background: '#3b82f6', color: '#fff',\n cursor: 'pointer', boxShadow: '0 4px 14px rgba(0,0,0,.3)' }}>◧</button>\n </div>\n );\n}\n","export type RegisteredComponent = { id: string; variantIds: string[]; goal?: string };\n\nconst registry = new Map<string, RegisteredComponent>();\nconst listeners = new Set<() => void>();\n\nfunction emit(): void {\n for (const fn of listeners) fn();\n}\n\n/** Register (or re-register) a component. Returns an unregister function. */\nexport function registerComponent(c: RegisteredComponent): () => void {\n registry.set(c.id, c);\n emit();\n return () => {\n registry.delete(c.id);\n emit();\n };\n}\n\nexport function getRegistered(): RegisteredComponent[] {\n return [...registry.values()];\n}\n\nexport function subscribeRegistry(fn: () => void): () => void {\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n}\n","function store(): Record<string, string> {\n const w = window as unknown as { __sentient_overrides?: Record<string, string> };\n if (!w.__sentient_overrides) w.__sentient_overrides = {};\n return w.__sentient_overrides;\n}\n\n/** Force `componentId` to render `variantId` — read by `useAssignment`. */\nexport function setVariantOverride(componentId: string, variantId: string): void {\n store()[componentId] = variantId;\n}\n\nexport function clearVariantOverride(componentId: string): void {\n delete store()[componentId];\n}\n\nexport function getOverrides(): Record<string, string> {\n return { ...store() };\n}\n","import type { SentientClient } from '@sentientui/core';\n\nlet previewOn = false;\nconst listeners = new Set<() => void>();\n\nexport function setPreviewMode(on: boolean): void {\n if (previewOn === on) return;\n previewOn = on;\n for (const fn of listeners) fn();\n}\n\nexport function getPreviewMode(): boolean {\n return previewOn;\n}\n\nexport function subscribePreview(fn: () => void): () => void {\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n}\n\n/**\n * Wraps a client so it writes nothing: reads pass through, all emitters no-op.\n * Used while previewing variants/personas so no `variant_assigned`, goal, or\n * session events are sent.\n */\nexport function createPreviewClient(inner: SentientClient): SentientClient {\n return {\n track: () => undefined,\n goal: () => undefined,\n componentGoal: () => undefined,\n identify: () => undefined,\n fetchWeights: () => Promise.resolve([]),\n getAssignment: (componentId, segment) => inner.getAssignment(componentId, segment),\n assign: (componentId, variantIds, agentData, agentDataByVariant) =>\n inner.assign(componentId, variantIds, agentData, agentDataByVariant),\n getGraph: () => inner.getGraph(),\n destroy: () => inner.destroy(),\n };\n}\n"],"mappings":"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","names":["devtools_exports","__export","AdaptiveDevtools","__toCommonJS","import_react","registry","listeners","getRegistered","registry","subscribeRegistry","fn","listeners","store","w","setVariantOverride","componentId","variantId","clearVariantOverride","getOverrides","__spreadValues","previewOn","listeners","setPreviewMode","on","fn","getPreviewMode","import_jsx_runtime","_a","IS_PROD","SEED_PERSONAS","forcePersona","apiKey","persona","sections","getRegistered","c","components","res","data","id","variantId","setVariantOverride","setPreviewMode","AdaptiveDevtools","open","setOpen","force","n","subscribeRegistry","overrides","getOverrides","choose","reset","clearVariantOverride","getPreviewMode","p","v"]}
1
+ {"version":3,"sources":["../src/devtools/index.tsx","../src/devtools-registry.ts","../src/devtools-overrides.ts","../src/devtools-slot-overrides.ts","../src/preview-mode.ts","../src/override-events.ts","../src/devtools-config.ts"],"sourcesContent":["'use client';\nimport { useEffect, useReducer, useState, type CSSProperties } from 'react';\nimport { PERSONAS, PERSONA_DISPLAY, confidenceBand } from '@sentientui/policy';\nimport { SNAPSHOT_STORAGE_KEY_PREFIX } from '@sentientui/core';\nimport {\n getRegistered,\n getRegisteredSlots,\n getRegisteredSections,\n subscribeRegistry,\n type RegisteredSlot,\n} from '../devtools-registry.js';\nimport { setVariantOverride, clearVariantOverride, getOverrides } from '../devtools-overrides.js';\nimport { setSlotOverride, clearSlotOverride, getSlotOverrides } from '../devtools-slot-overrides.js';\nimport { setPreviewMode, getPreviewMode } from '../preview-mode.js';\nimport { notifyOverridesChanged } from '../override-events.js';\nimport { readDevtoolsConfig, type DevtoolsConfig } from '../devtools-config.js';\n\ndeclare const process: { env?: { NODE_ENV?: string } } | undefined;\nconst IS_PROD = typeof process !== 'undefined' && process.env?.NODE_ENV === 'production';\nconst DEFAULT_API_BASE_URL = 'https://api.sentient-ui.com/v1';\n\nexport const LOCAL_MODE_DEVTOOLS_BANNER =\n 'Local mode — decisions are simulated; add a key to learn from real traffic';\n\ntype OutcomeToApply = {\n assignments?: Record<string, string>;\n layoutOrder?: string[] | null;\n slots?: Record<string, string | Record<string, string>>;\n personaAttributes?: { persona: string; confidence: 'low' | 'medium' | 'high' };\n};\n\ntype OverrideWindow = Window & {\n __sentient_layout_override?: string[];\n __sentient_slot_overrides?: Record<string, string | Record<string, string>>;\n};\n\n/** Apply a simulated outcome across every surface: variants, layout, slots/tokens, persona attrs. */\nfunction applyOutcome(result: OutcomeToApply): void {\n for (const [id, variantId] of Object.entries(result.assignments ?? {})) {\n setVariantOverride(id, variantId);\n }\n const w = window as unknown as OverrideWindow;\n if (result.layoutOrder && result.layoutOrder.length > 0) {\n w.__sentient_layout_override = result.layoutOrder;\n }\n if (result.slots) {\n w.__sentient_slot_overrides = { ...(w.__sentient_slot_overrides ?? {}), ...result.slots };\n }\n if (result.personaAttributes) {\n document.documentElement.dataset.sentientPersona = result.personaAttributes.persona;\n document.documentElement.dataset.sentientConfidence = result.personaAttributes.confidence;\n }\n setPreviewMode(true); // suppress events while previewing\n notifyOverridesChanged(); // re-render layout/slot consumers\n}\n\nfunction readSessionId(): string {\n try {\n const match = document.cookie.match(/(?:^|; )_snt_uid=([^;]*)/);\n if (match) return decodeURIComponent(match[1]);\n } catch {\n /* ignore */\n }\n return 'devtools-preview';\n}\n\nfunction slotDecls(): Array<{ id: string; arms?: string[]; dims?: RegisteredSlot['dims'] }> {\n return getRegisteredSlots().map((s) => ({\n id: s.id,\n ...(s.arms ? { arms: s.arms } : {}),\n ...(s.dims ? { dims: s.dims } : {}),\n }));\n}\n\n/** Keyed mode: simulate via /v1/explain (read-only, event-free). */\nasync function forcePersonaKeyed(apiKey: string, apiBaseUrl: string, persona: string): Promise<void> {\n const res = await fetch(`${apiBaseUrl}/explain`, {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${apiKey}` },\n body: JSON.stringify({\n persona,\n sections: getRegisteredSections().map((id) => ({ id })),\n components: getRegistered().map((c) => ({ id: c.id, variantIds: c.variantIds })),\n slots: slotDecls(),\n }),\n });\n if (!res.ok) return;\n const data = (await res.json()) as OutcomeToApply;\n applyOutcome({\n ...data,\n personaAttributes: data.personaAttributes ?? { persona, confidence: 'high' },\n });\n}\n\n/** Local mode: simulate via the deterministic local engine — zero network. */\nasync function forcePersonaLocal(persona: string): Promise<void> {\n const mod = await import('@sentientui/core/local');\n if (!mod.LOCAL_ENGINE_AVAILABLE) return;\n const outcome = mod\n .createLocalEngine({ sessionId: readSessionId(), forcedPersona: persona })\n .decide({\n sections: getRegisteredSections(),\n components: getRegistered().map((c) => ({ id: c.id, variantIds: c.variantIds })),\n slots: slotDecls(),\n });\n applyOutcome({\n assignments: outcome.assignments,\n layoutOrder: outcome.layoutOrder,\n slots: outcome.slots,\n personaAttributes: {\n persona: outcome.persona,\n confidence: confidenceBand(outcome.confidence),\n },\n });\n}\n\n/** Reset: clear the decision snapshot + every override, then reload to re-decide. */\nfunction resetAll(): void {\n for (const id of Object.keys(getOverrides())) clearVariantOverride(id);\n const w = window as unknown as OverrideWindow;\n delete w.__sentient_layout_override;\n delete w.__sentient_slot_overrides;\n delete document.documentElement.dataset.sentientPersona;\n delete document.documentElement.dataset.sentientConfidence;\n try {\n const stale: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key && key.startsWith(SNAPSHOT_STORAGE_KEY_PREFIX)) stale.push(key);\n }\n for (const key of stale) localStorage.removeItem(key);\n } catch {\n /* ignore */\n }\n setPreviewMode(false);\n notifyOverridesChanged();\n try {\n window.location.reload();\n } catch {\n /* jsdom */\n }\n}\n\nconst btn = (active: boolean): CSSProperties => ({\n padding: '2px 8px',\n borderRadius: 4,\n border: '1px solid #444',\n background: active ? '#3b82f6' : '#222',\n color: '#eee',\n cursor: 'pointer',\n});\n\n/** Sentient \"S.\" wordmark, monoline — white strokes for the black launcher button. */\nfunction SentientMark({ size = 26 }: { size?: number } = {}): JSX.Element {\n return (\n <svg width={size} height={size} viewBox=\"0 0 32 32\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M21 9H14C11.2 9 9.8 10.8 9.8 13C9.8 15.4 11.6 16.6 14.5 16.6H18.5C20.5 16.6 20.7 18.2 20.4 19.6\"\n stroke=\"#fff\"\n strokeWidth=\"2.2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path d=\"M10 22H17\" stroke=\"#fff\" strokeWidth=\"2.2\" strokeLinecap=\"round\" />\n <circle cx=\"20.6\" cy=\"22\" r=\"2.1\" fill=\"#fff\" />\n </svg>\n );\n}\n\nexport function AdaptiveDevtools({ apiKey }: { apiKey?: string } = {}): JSX.Element | null {\n const [open, setOpen] = useState(false);\n const [activePersona, setActivePersona] = useState<string | null>(null);\n const [mounted, setMounted] = useState(false);\n const [, force] = useReducer((n: number) => n + 1, 0);\n useEffect(() => subscribeRegistry(force), []);\n // Client-mount gate: render nothing during SSR / the first paint so the widget\n // never reads `window` on the server. Lets consumers drop `<AdaptiveDevtools/>`\n // straight into a tree without a `dynamic(..., { ssr: false })` wrapper.\n useEffect(() => setMounted(true), []);\n\n // Never render in production, even if imported by mistake. (Hooks run first\n // so the rules of hooks hold regardless of these early returns.)\n if (IS_PROD) return null;\n if (!mounted) return null;\n\n const config: DevtoolsConfig = readDevtoolsConfig() ?? {\n apiKey: apiKey ?? '',\n apiBaseUrl: DEFAULT_API_BASE_URL,\n isLocal: false,\n };\n const useLocalEngine = config.isLocal || !config.apiKey;\n const components = getRegistered();\n const slots = getRegisteredSlots();\n const overrides = getOverrides();\n const slotOverrides = getSlotOverrides();\n\n // Preview mode stays on while ANY override (variant or slot) is active.\n function maybeExitPreview(): void {\n if (Object.keys(getOverrides()).length === 0 && Object.keys(getSlotOverrides()).length === 0) {\n setPreviewMode(false);\n }\n }\n\n function choose(id: string, variantId: string): void {\n setVariantOverride(id, variantId);\n setPreviewMode(true);\n notifyOverridesChanged();\n force();\n }\n function resetVariant(id: string): void {\n clearVariantOverride(id);\n maybeExitPreview();\n notifyOverridesChanged();\n force();\n }\n function chooseSlotArm(id: string, arm: string): void {\n setSlotOverride(id, arm);\n setPreviewMode(true);\n notifyOverridesChanged();\n force();\n }\n function chooseSlotDim(id: string, dim: string, value: string, dims: RegisteredSlot['dims']): void {\n const current = getSlotOverrides()[id];\n // Merge onto the existing forced object, or seed from each dim's baseline\n // (first value) so unset dims stay at baseline instead of vanishing.\n const next: Record<string, string> =\n current && typeof current === 'object'\n ? { ...current }\n : Object.fromEntries(Object.entries(dims ?? {}).map(([d, values]) => [d, values[0]!]));\n next[dim] = value;\n setSlotOverride(id, next);\n setPreviewMode(true);\n notifyOverridesChanged();\n force();\n }\n function resetSlot(id: string): void {\n clearSlotOverride(id);\n maybeExitPreview();\n notifyOverridesChanged();\n force();\n }\n function choosePersona(persona: string): void {\n setActivePersona(persona);\n const apply = useLocalEngine\n ? forcePersonaLocal(persona)\n : forcePersonaKeyed(config.apiKey, config.apiBaseUrl, persona);\n void apply.then(force);\n }\n\n return (\n <div style={{ position: 'fixed', bottom: 16, right: 16, zIndex: 2147483647, fontFamily: 'system-ui' }}>\n {/* Panel stays mounted and animates in/out from the button's corner, so the\n launcher below never shifts. transform-origin is the button (bottom-right). */}\n <div\n aria-hidden={!open}\n style={{\n position: 'absolute',\n bottom: 52,\n right: 0,\n transformOrigin: 'bottom right',\n transition: 'opacity .18s ease, transform .2s cubic-bezier(.16,1,.3,1)',\n opacity: open ? 1 : 0,\n transform: open ? 'translateY(0) scale(1)' : 'translateY(6px) scale(.96)',\n pointerEvents: open ? 'auto' : 'none',\n }}\n >\n <div style={{ width: 300, maxHeight: 460, overflowY: 'auto', background: '#111', color: '#eee',\n borderRadius: 8, padding: 12, boxShadow: '0 8px 30px rgba(0,0,0,.4)', fontSize: 12 }}>\n {config.isLocal && (\n <div style={{ background: '#1e293b', border: '1px solid #334155', borderRadius: 4,\n padding: '6px 8px', marginBottom: 8 }}>\n {LOCAL_MODE_DEVTOOLS_BANNER}\n </div>\n )}\n <div style={{ opacity: .7, marginBottom: 8 }}>\n {components.length} component{components.length === 1 ? '' : 's'} · {getPreviewMode() ? 'preview — writing nothing' : 'live'}\n </div>\n <div style={{ borderBottom: '1px solid #333', paddingBottom: 8, marginBottom: 8 }}>\n <div style={{ opacity: .7, marginBottom: 4 }}>Preview persona</div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>\n {PERSONAS.map((p) => (\n <button key={p} onClick={() => choosePersona(p)} style={btn(activePersona === p)}>\n {PERSONA_DISPLAY[p]}\n </button>\n ))}\n {(activePersona !== null || Object.keys(overrides).length > 0 || Object.keys(slotOverrides).length > 0) && (\n <button onClick={resetAll} style={{ ...btn(false), color: '#aaa' }}>\n Reset\n </button>\n )}\n </div>\n </div>\n {components.length === 0 && slots.length === 0 && (\n <div style={{ opacity: .6 }}>No components or slots on this page yet.</div>\n )}\n {components.map((c) => (\n <div key={c.id} style={{ borderTop: '1px solid #333', padding: '8px 0' }}>\n <div style={{ fontWeight: 600 }}>{c.id}{c.goal ? ` · goal: ${c.goal}` : ''}</div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4, marginTop: 4 }}>\n {c.variantIds.map((v) => (\n <button key={v} onClick={() => choose(c.id, v)} style={btn(overrides[c.id] === v)}>\n {v}\n </button>\n ))}\n {overrides[c.id] && (\n <button onClick={() => resetVariant(c.id)} style={{ ...btn(false), color: '#aaa' }}>\n reset\n </button>\n )}\n </div>\n </div>\n ))}\n {slots.length > 0 && (\n <div style={{ borderTop: '1px solid #333', paddingTop: 8, marginTop: 4 }}>\n <div style={{ opacity: .7, marginBottom: 4 }}>Slots</div>\n {slots.map((s) => {\n const ov = slotOverrides[s.id];\n return (\n <div key={s.id} style={{ padding: '6px 0' }}>\n <div style={{ fontWeight: 600 }}>{s.id}</div>\n {s.arms && (\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4, marginTop: 4 }}>\n {s.arms.map((arm) => (\n <button key={arm} onClick={() => chooseSlotArm(s.id, arm)} style={btn(ov === arm)}>\n {arm}\n </button>\n ))}\n </div>\n )}\n {s.dims && Object.entries(s.dims).map(([dim, values]) => (\n <div key={dim} style={{ marginTop: 4 }}>\n <div style={{ opacity: .6, fontSize: 11 }}>{dim}</div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>\n {values.map((v) => (\n <button\n key={v}\n onClick={() => chooseSlotDim(s.id, dim, v, s.dims)}\n style={btn(!!ov && typeof ov === 'object' && ov[dim] === v)}\n >\n {v}\n </button>\n ))}\n </div>\n </div>\n ))}\n {ov !== undefined && (\n <button onClick={() => resetSlot(s.id)} style={{ ...btn(false), color: '#aaa', marginTop: 4 }}>\n reset\n </button>\n )}\n </div>\n );\n })}\n </div>\n )}\n </div>\n </div>\n <button\n aria-label=\"Sentient DevTools\"\n aria-expanded={open}\n onClick={() => setOpen((o) => !o)}\n style={{ width: 44, height: 44, borderRadius: 12, border: '1px solid #2a2a2a', background: '#000',\n display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 0,\n cursor: 'pointer', boxShadow: '0 6px 18px rgba(0,0,0,.4)' }}\n >\n <SentientMark />\n </button>\n </div>\n );\n}\n","export type RegisteredComponent = { id: string; variantIds: string[]; goal?: string };\nexport type RegisteredSlot = {\n id: string;\n arms?: string[];\n dims?: Record<string, readonly string[]>;\n};\n\ntype RegistryState = {\n components: Map<string, RegisteredComponent>;\n slots: Map<string, RegisteredSlot>;\n sections: string[];\n listeners: Set<() => void>;\n};\n\n// Shared through a window global: the main entry and the /devtools entry are\n// separate bundles, each with its own copy of this module — module-local\n// state would give the devtools an always-empty registry in published apps.\nconst ssrFallback: RegistryState = {\n components: new Map(),\n slots: new Map(),\n sections: [],\n listeners: new Set(),\n};\n\nfunction state(): RegistryState {\n if (typeof window === 'undefined') return ssrFallback;\n const w = window as unknown as { __sentient_registry?: RegistryState };\n if (!w.__sentient_registry) {\n w.__sentient_registry = {\n components: new Map(),\n slots: new Map(),\n sections: [],\n listeners: new Set(),\n };\n }\n return w.__sentient_registry;\n}\n\nfunction emit(): void {\n for (const fn of state().listeners) fn();\n}\n\n/** Register (or re-register) a component. Returns an unregister function. */\nexport function registerComponent(c: RegisteredComponent): () => void {\n state().components.set(c.id, c);\n emit();\n return () => {\n state().components.delete(c.id);\n emit();\n };\n}\n\n/** Register (or re-register) a slot declaration. Returns an unregister function. */\nexport function registerSlot(s: RegisteredSlot): () => void {\n state().slots.set(s.id, s);\n emit();\n return () => {\n state().slots.delete(s.id);\n emit();\n };\n}\n\n/** Register the page's declared section ids (from AdaptiveRoot/provider). */\nexport function registerSections(sections: string[]): void {\n state().sections = [...sections];\n emit();\n}\n\nexport function getRegistered(): RegisteredComponent[] {\n return [...state().components.values()];\n}\n\nexport function getRegisteredSlots(): RegisteredSlot[] {\n return [...state().slots.values()];\n}\n\nexport function getRegisteredSections(): string[] {\n return [...state().sections];\n}\n\nexport function subscribeRegistry(fn: () => void): () => void {\n const listeners = state().listeners;\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n}\n","function store(): Record<string, string> {\n const w = window as unknown as { __sentient_overrides?: Record<string, string> };\n if (!w.__sentient_overrides) w.__sentient_overrides = {};\n return w.__sentient_overrides;\n}\n\n/** Force `componentId` to render `variantId` — read by `useAssignment`. */\nexport function setVariantOverride(componentId: string, variantId: string): void {\n store()[componentId] = variantId;\n}\n\nexport function clearVariantOverride(componentId: string): void {\n delete store()[componentId];\n}\n\nexport function getOverrides(): Record<string, string> {\n return { ...store() };\n}\n","import type { SlotResult } from '@sentientui/core';\n\n/**\n * Slot-override store — the channel `useSlotResult` reads (`useAdaptiveTokens` /\n * `AdaptiveGroup`). Separate from `__sentient_overrides` (variant components):\n * a slot result is a token object (`{ tone: 'urgent' }`) or an arm string\n * (`'social_first'`), never a bare variant id. Window-backed so the /devtools\n * bundle and the main bundle share one store.\n */\nfunction store(): Record<string, SlotResult> {\n const w = window as unknown as { __sentient_slot_overrides?: Record<string, SlotResult> };\n if (!w.__sentient_slot_overrides) w.__sentient_slot_overrides = {};\n return w.__sentient_slot_overrides;\n}\n\n/** Force `slotId` to resolve to `result` — read by `useSlotResult`. */\nexport function setSlotOverride(slotId: string, result: SlotResult): void {\n store()[slotId] = result;\n}\n\nexport function clearSlotOverride(slotId: string): void {\n delete store()[slotId];\n}\n\nexport function getSlotOverrides(): Record<string, SlotResult> {\n return { ...store() };\n}\n","import type { SentientClient } from '@sentientui/core';\n\ntype PreviewState = { on: boolean; listeners: Set<() => void> };\nconst ssrFallback: PreviewState = { on: false, listeners: new Set() };\n\n// Window-backed: the /devtools entry (a separate bundle) toggles preview mode\n// and the provider (main bundle) must observe it.\nfunction state(): PreviewState {\n if (typeof window === 'undefined') return ssrFallback;\n const w = window as unknown as { __sentient_preview?: PreviewState };\n if (!w.__sentient_preview) w.__sentient_preview = { on: false, listeners: new Set() };\n return w.__sentient_preview;\n}\n\nexport function setPreviewMode(on: boolean): void {\n const s = state();\n if (s.on === on) return;\n s.on = on;\n for (const fn of s.listeners) fn();\n}\n\nexport function getPreviewMode(): boolean {\n return state().on;\n}\n\nexport function subscribePreview(fn: () => void): () => void {\n const listeners = state().listeners;\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n}\n\n/**\n * Wraps a client so it writes nothing: reads pass through, all emitters no-op.\n * Used while previewing variants/personas so no `variant_assigned`, goal, or\n * session events are sent.\n */\nexport function createPreviewClient(inner: SentientClient): SentientClient {\n return {\n isLocal: inner.isLocal,\n track: () => undefined,\n goal: () => undefined,\n componentGoal: () => undefined,\n identify: () => undefined,\n fetchWeights: () => Promise.resolve([]),\n getAssignment: (componentId, segment) => inner.getAssignment(componentId, segment),\n assign: (componentId, variantIds, agentData, agentDataByVariant) =>\n inner.assign(componentId, variantIds, agentData, agentDataByVariant),\n // Reads pass through; decide is a write (slot decisions persist server-side)\n // so preview mode never issues it.\n decide: () => Promise.resolve(null),\n getSlotResult: (slotId) => inner.getSlotResult(slotId),\n getPersona: () => inner.getPersona(),\n getGraph: () => inner.getGraph(),\n destroy: () => inner.destroy(),\n };\n}\n","/**\n * Cross-bundle re-render bus for devtools overrides. The main entry and the\n * /devtools entry are separate bundles, so state and notifications go through\n * window (a version counter + a DOM event) — never module-local state.\n */\nconst EVENT = 'sentient:overrides-changed';\n\ntype VersionWindow = Window & { __sentient_overrides_version?: number };\n\nexport function getOverridesVersion(): number {\n if (typeof window === 'undefined') return 0;\n return (window as VersionWindow).__sentient_overrides_version ?? 0;\n}\n\nexport function notifyOverridesChanged(): void {\n if (typeof window === 'undefined') return;\n const w = window as VersionWindow;\n w.__sentient_overrides_version = (w.__sentient_overrides_version ?? 0) + 1;\n window.dispatchEvent(new Event(EVENT));\n}\n\nexport function subscribeOverridesChanged(fn: () => void): () => void {\n if (typeof window === 'undefined') return () => undefined;\n window.addEventListener(EVENT, fn);\n return () => window.removeEventListener(EVENT, fn);\n}\n","/** Provider → devtools config handoff. Window-backed: the /devtools entry is a\n * separate bundle and cannot share the provider's React context instance. */\nexport type DevtoolsConfig = {\n apiKey: string;\n apiBaseUrl: string;\n isLocal: boolean;\n};\n\ntype ConfigWindow = Window & { __sentient_devtools_config?: DevtoolsConfig };\n\nexport function publishDevtoolsConfig(config: DevtoolsConfig): void {\n if (typeof window === 'undefined') return;\n (window as ConfigWindow).__sentient_devtools_config = config;\n}\n\nexport function readDevtoolsConfig(): DevtoolsConfig | null {\n if (typeof window === 'undefined') return null;\n return (window as ConfigWindow).__sentient_devtools_config ?? null;\n}\n"],"mappings":"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","names":["devtools_exports","__export","AdaptiveDevtools","LOCAL_MODE_DEVTOOLS_BANNER","__toCommonJS","import_react","import_policy","import_core","ssrFallback","state","w","getRegistered","state","getRegisteredSlots","getRegisteredSections","subscribeRegistry","fn","listeners","store","w","setVariantOverride","componentId","variantId","clearVariantOverride","getOverrides","__spreadValues","store","w","setSlotOverride","slotId","result","clearSlotOverride","getSlotOverrides","__spreadValues","ssrFallback","state","w","setPreviewMode","on","s","fn","getPreviewMode","EVENT","notifyOverridesChanged","_a","w","EVENT","readDevtoolsConfig","_a","import_jsx_runtime","_a","IS_PROD","DEFAULT_API_BASE_URL","LOCAL_MODE_DEVTOOLS_BANNER","applyOutcome","result","_b","id","variantId","setVariantOverride","w","__spreadValues","setPreviewMode","notifyOverridesChanged","readSessionId","match","slotDecls","getRegisteredSlots","s","forcePersonaKeyed","apiKey","apiBaseUrl","persona","res","getRegisteredSections","getRegistered","c","data","__spreadProps","forcePersonaLocal","mod","outcome","resetAll","getOverrides","clearVariantOverride","stale","i","key","e","btn","active","SentientMark","size","AdaptiveDevtools","open","setOpen","activePersona","setActivePersona","mounted","setMounted","force","subscribeRegistry","config","readDevtoolsConfig","useLocalEngine","components","slots","overrides","slotOverrides","getSlotOverrides","maybeExitPreview","choose","resetVariant","chooseSlotArm","arm","setSlotOverride","chooseSlotDim","dim","value","dims","current","next","d","values","resetSlot","clearSlotOverride","choosePersona","getPreviewMode","p","v","ov","o"]}
package/dist/devtools.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  'use client';
2
- "use client";var _=Object.defineProperty;var y=Object.getOwnPropertySymbols;var C=Object.prototype.hasOwnProperty,P=Object.prototype.propertyIsEnumerable;var x=(e,o,i)=>o in e?_(e,o,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[o]=i,w=(e,o)=>{for(var i in o||(o={}))C.call(o,i)&&x(e,i,o[i]);if(y)for(var i of y(o))P.call(o,i)&&x(e,i,o[i]);return e};import{useEffect as I,useReducer as N,useState as D}from"react";var E=new Map,h=new Set;function l(){return[...E.values()]}function R(e){return h.add(e),()=>{h.delete(e)}}function v(){let e=window;return e.__sentient_overrides||(e.__sentient_overrides={}),e.__sentient_overrides}function f(e,o){v()[e]=o}function k(e){delete v()[e]}function m(){return w({},v())}var b=!1,B=new Set;function c(e){if(b!==e){b=e;for(let o of B)o()}}function S(){return b}import{jsx as d,jsxs as s}from"react/jsx-runtime";var O,V=typeof process!="undefined"&&((O=process.env)==null?void 0:O.NODE_ENV)==="production",M=["browsers","buyers","researchers","deal-seekers"];async function A(e,o){let i=l().map(n=>({id:n.id})),a=l().map(n=>({id:n.id,variantIds:n.variantIds})),r=await fetch("/v1/explain",{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e}`},body:JSON.stringify({persona:o,sections:i,components:a})});if(!r.ok)return;let g=await r.json();for(let[n,u]of Object.entries(g.assignments))f(n,u);c(!0)}function X({apiKey:e}={}){let[o,i]=D(!1),[,a]=N(t=>t+1,0);if(I(()=>R(a),[]),V)return null;let r=l(),g=m();function n(t,p){f(t,p),c(!0),a()}function u(t){k(t),Object.keys(m()).length===0&&c(!1),a()}return s("div",{style:{position:"fixed",bottom:16,right:16,zIndex:2147483647,fontFamily:"system-ui"},children:[o&&s("div",{style:{width:300,maxHeight:420,overflowY:"auto",background:"#111",color:"#eee",borderRadius:8,padding:12,marginBottom:8,boxShadow:"0 8px 30px rgba(0,0,0,.4)",fontSize:12},children:[s("div",{style:{opacity:.7,marginBottom:8},children:[r.length," component",r.length===1?"":"s"," \xB7 ",S()?"preview \u2014 writing nothing":"live"]}),e&&s("div",{style:{borderBottom:"1px solid #333",paddingBottom:8,marginBottom:8},children:[d("div",{style:{opacity:.7,marginBottom:4},children:"Preview persona"}),d("div",{style:{display:"flex",flexWrap:"wrap",gap:4},children:M.map(t=>d("button",{onClick:()=>{A(e,t).then(a)},style:{padding:"2px 8px",borderRadius:4,border:"1px solid #444",background:"#222",color:"#eee",cursor:"pointer"},children:t},t))})]}),r.length===0&&d("div",{style:{opacity:.6},children:"No components on this page yet."}),r.map(t=>s("div",{style:{borderTop:"1px solid #333",padding:"8px 0"},children:[s("div",{style:{fontWeight:600},children:[t.id,t.goal?` \xB7 goal: ${t.goal}`:""]}),s("div",{style:{display:"flex",flexWrap:"wrap",gap:4,marginTop:4},children:[t.variantIds.map(p=>d("button",{onClick:()=>n(t.id,p),style:{padding:"2px 8px",borderRadius:4,border:"1px solid #444",background:g[t.id]===p?"#3b82f6":"#222",color:"#eee",cursor:"pointer"},children:p},p)),g[t.id]&&d("button",{onClick:()=>u(t.id),style:{padding:"2px 8px",borderRadius:4,border:"1px solid #444",background:"#222",color:"#aaa",cursor:"pointer"},children:"reset"})]})]},t.id))]}),d("button",{"aria-label":"Sentient DevTools",onClick:()=>i(t=>!t),style:{width:40,height:40,borderRadius:20,border:"none",background:"#3b82f6",color:"#fff",cursor:"pointer",boxShadow:"0 4px 14px rgba(0,0,0,.3)"},children:"\u25E7"})]})}export{X as AdaptiveDevtools};
2
+ "use client";var se=Object.defineProperty,de=Object.defineProperties;var ae=Object.getOwnPropertyDescriptors;var V=Object.getOwnPropertySymbols;var le=Object.prototype.hasOwnProperty,ce=Object.prototype.propertyIsEnumerable;var U=(e,t,o)=>t in e?se(e,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[t]=o,d=(e,t)=>{for(var o in t||(t={}))le.call(t,o)&&U(e,o,t[o]);if(V)for(var o of V(t))ce.call(t,o)&&U(e,o,t[o]);return e},b=(e,t)=>de(e,ae(t));import{useEffect as J,useReducer as fe,useState as T}from"react";import{PERSONAS as ve,PERSONA_DISPLAY as me,confidenceBand as ye}from"@sentientui/policy";import{SNAPSHOT_STORAGE_KEY_PREFIX as _e}from"@sentientui/core";var pe={components:new Map,slots:new Map,sections:[],listeners:new Set};function h(){if(typeof window=="undefined")return pe;let e=window;return e.__sentient_registry||(e.__sentient_registry={components:new Map,slots:new Map,sections:[],listeners:new Set}),e.__sentient_registry}function x(){return[...h().components.values()]}function P(){return[...h().slots.values()]}function E(){return[...h().sections]}function z(e){let t=h().listeners;return t.add(e),()=>{t.delete(e)}}function A(){let e=window;return e.__sentient_overrides||(e.__sentient_overrides={}),e.__sentient_overrides}function L(e,t){A()[e]=t}function W(e){delete A()[e]}function R(){return d({},A())}function D(){let e=window;return e.__sentient_slot_overrides||(e.__sentient_slot_overrides={}),e.__sentient_slot_overrides}function I(e,t){D()[e]=t}function F(e){delete D()[e]}function O(){return d({},D())}var ge={on:!1,listeners:new Set};function G(){if(typeof window=="undefined")return ge;let e=window;return e.__sentient_preview||(e.__sentient_preview={on:!1,listeners:new Set}),e.__sentient_preview}function u(e){let t=G();if(t.on!==e){t.on=e;for(let o of t.listeners)o()}}function H(){return G().on}var ue="sentient:overrides-changed";function p(){var t;if(typeof window=="undefined")return;let e=window;e.__sentient_overrides_version=((t=e.__sentient_overrides_version)!=null?t:0)+1,window.dispatchEvent(new Event(ue))}function Y(){var e;return typeof window=="undefined"?null:(e=window.__sentient_devtools_config)!=null?e:null}import{jsx as i,jsxs as a}from"react/jsx-runtime";var K,we=typeof process!="undefined"&&((K=process.env)==null?void 0:K.NODE_ENV)==="production",be="https://api.sentient-ui.com/v1",Se="Local mode \u2014 decisions are simulated; add a key to learn from real traffic";function X(e){var o,s;for(let[v,m]of Object.entries((o=e.assignments)!=null?o:{}))L(v,m);let t=window;e.layoutOrder&&e.layoutOrder.length>0&&(t.__sentient_layout_override=e.layoutOrder),e.slots&&(t.__sentient_slot_overrides=d(d({},(s=t.__sentient_slot_overrides)!=null?s:{}),e.slots)),e.personaAttributes&&(document.documentElement.dataset.sentientPersona=e.personaAttributes.persona,document.documentElement.dataset.sentientConfidence=e.personaAttributes.confidence),u(!0),p()}function he(){try{let e=document.cookie.match(/(?:^|; )_snt_uid=([^;]*)/);if(e)return decodeURIComponent(e[1])}catch(e){}return"devtools-preview"}function $(){return P().map(e=>d(d({id:e.id},e.arms?{arms:e.arms}:{}),e.dims?{dims:e.dims}:{}))}async function xe(e,t,o){var m;let s=await fetch(`${t}/explain`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e}`},body:JSON.stringify({persona:o,sections:E().map(y=>({id:y})),components:x().map(y=>({id:y.id,variantIds:y.variantIds})),slots:$()})});if(!s.ok)return;let v=await s.json();X(b(d({},v),{personaAttributes:(m=v.personaAttributes)!=null?m:{persona:o,confidence:"high"}}))}async function Re(e){let t=await import("@sentientui/core/local");if(!t.LOCAL_ENGINE_AVAILABLE)return;let o=t.createLocalEngine({sessionId:he(),forcedPersona:e}).decide({sections:E(),components:x().map(s=>({id:s.id,variantIds:s.variantIds})),slots:$()});X({assignments:o.assignments,layoutOrder:o.layoutOrder,slots:o.slots,personaAttributes:{persona:o.persona,confidence:ye(o.confidence)}})}function Oe(){for(let t of Object.keys(R()))W(t);let e=window;delete e.__sentient_layout_override,delete e.__sentient_slot_overrides,delete document.documentElement.dataset.sentientPersona,delete document.documentElement.dataset.sentientConfidence;try{let t=[];for(let o=0;o<localStorage.length;o++){let s=localStorage.key(o);s&&s.startsWith(_e)&&t.push(s)}for(let o of t)localStorage.removeItem(o)}catch(t){}u(!1),p();try{window.location.reload()}catch(t){}}var f=e=>({padding:"2px 8px",borderRadius:4,border:"1px solid #444",background:e?"#3b82f6":"#222",color:"#eee",cursor:"pointer"});function ke({size:e=26}={}){return a("svg",{width:e,height:e,viewBox:"0 0 32 32",fill:"none","aria-hidden":"true",children:[i("path",{d:"M21 9H14C11.2 9 9.8 10.8 9.8 13C9.8 15.4 11.6 16.6 14.5 16.6H18.5C20.5 16.6 20.7 18.2 20.4 19.6",stroke:"#fff",strokeWidth:"2.2",strokeLinecap:"round",strokeLinejoin:"round"}),i("path",{d:"M10 22H17",stroke:"#fff",strokeWidth:"2.2",strokeLinecap:"round"}),i("circle",{cx:"20.6",cy:"22",r:"2.1",fill:"#fff"})]})}function He({apiKey:e}={}){var j;let[t,o]=T(!1),[s,v]=T(null),[m,y]=T(!1),[,g]=fe(n=>n+1,0);if(J(()=>z(g),[]),J(()=>y(!0),[]),we||!m)return null;let _=(j=Y())!=null?j:{apiKey:e!=null?e:"",apiBaseUrl:be,isLocal:!1},q=_.isLocal||!_.apiKey,S=x(),k=P(),C=R(),B=O();function M(){Object.keys(R()).length===0&&Object.keys(O()).length===0&&u(!1)}function Q(n,r){L(n,r),u(!0),p(),g()}function Z(n){W(n),M(),p(),g()}function ee(n,r){I(n,r),u(!0),p(),g()}function te(n,r,l,w){let c=O()[n],N=c&&typeof c=="object"?d({},c):Object.fromEntries(Object.entries(w!=null?w:{}).map(([ie,re])=>[ie,re[0]]));N[r]=l,I(n,N),u(!0),p(),g()}function ne(n){F(n),M(),p(),g()}function oe(n){v(n),(q?Re(n):xe(_.apiKey,_.apiBaseUrl,n)).then(g)}return a("div",{style:{position:"fixed",bottom:16,right:16,zIndex:2147483647,fontFamily:"system-ui"},children:[i("div",{"aria-hidden":!t,style:{position:"absolute",bottom:52,right:0,transformOrigin:"bottom right",transition:"opacity .18s ease, transform .2s cubic-bezier(.16,1,.3,1)",opacity:t?1:0,transform:t?"translateY(0) scale(1)":"translateY(6px) scale(.96)",pointerEvents:t?"auto":"none"},children:a("div",{style:{width:300,maxHeight:460,overflowY:"auto",background:"#111",color:"#eee",borderRadius:8,padding:12,boxShadow:"0 8px 30px rgba(0,0,0,.4)",fontSize:12},children:[_.isLocal&&i("div",{style:{background:"#1e293b",border:"1px solid #334155",borderRadius:4,padding:"6px 8px",marginBottom:8},children:Se}),a("div",{style:{opacity:.7,marginBottom:8},children:[S.length," component",S.length===1?"":"s"," \xB7 ",H()?"preview \u2014 writing nothing":"live"]}),a("div",{style:{borderBottom:"1px solid #333",paddingBottom:8,marginBottom:8},children:[i("div",{style:{opacity:.7,marginBottom:4},children:"Preview persona"}),a("div",{style:{display:"flex",flexWrap:"wrap",gap:4},children:[ve.map(n=>i("button",{onClick:()=>oe(n),style:f(s===n),children:me[n]},n)),(s!==null||Object.keys(C).length>0||Object.keys(B).length>0)&&i("button",{onClick:Oe,style:b(d({},f(!1)),{color:"#aaa"}),children:"Reset"})]})]}),S.length===0&&k.length===0&&i("div",{style:{opacity:.6},children:"No components or slots on this page yet."}),S.map(n=>a("div",{style:{borderTop:"1px solid #333",padding:"8px 0"},children:[a("div",{style:{fontWeight:600},children:[n.id,n.goal?` \xB7 goal: ${n.goal}`:""]}),a("div",{style:{display:"flex",flexWrap:"wrap",gap:4,marginTop:4},children:[n.variantIds.map(r=>i("button",{onClick:()=>Q(n.id,r),style:f(C[n.id]===r),children:r},r)),C[n.id]&&i("button",{onClick:()=>Z(n.id),style:b(d({},f(!1)),{color:"#aaa"}),children:"reset"})]})]},n.id)),k.length>0&&a("div",{style:{borderTop:"1px solid #333",paddingTop:8,marginTop:4},children:[i("div",{style:{opacity:.7,marginBottom:4},children:"Slots"}),k.map(n=>{let r=B[n.id];return a("div",{style:{padding:"6px 0"},children:[i("div",{style:{fontWeight:600},children:n.id}),n.arms&&i("div",{style:{display:"flex",flexWrap:"wrap",gap:4,marginTop:4},children:n.arms.map(l=>i("button",{onClick:()=>ee(n.id,l),style:f(r===l),children:l},l))}),n.dims&&Object.entries(n.dims).map(([l,w])=>a("div",{style:{marginTop:4},children:[i("div",{style:{opacity:.6,fontSize:11},children:l}),i("div",{style:{display:"flex",flexWrap:"wrap",gap:4},children:w.map(c=>i("button",{onClick:()=>te(n.id,l,c,n.dims),style:f(!!r&&typeof r=="object"&&r[l]===c),children:c},c))})]},l)),r!==void 0&&i("button",{onClick:()=>ne(n.id),style:b(d({},f(!1)),{color:"#aaa",marginTop:4}),children:"reset"})]},n.id)})]})]})}),i("button",{"aria-label":"Sentient DevTools","aria-expanded":t,onClick:()=>o(n=>!n),style:{width:44,height:44,borderRadius:12,border:"1px solid #2a2a2a",background:"#000",display:"flex",alignItems:"center",justifyContent:"center",padding:0,cursor:"pointer",boxShadow:"0 6px 18px rgba(0,0,0,.4)"},children:i(ke,{})})]})}export{He as AdaptiveDevtools,Se as LOCAL_MODE_DEVTOOLS_BANNER};
3
3
  //# sourceMappingURL=devtools.mjs.map