@commandgarden/cli 2.14.3 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/node_modules/@commandgarden/app/dist/client/assets/Slides-5KujoV-w.js +30 -0
  2. package/node_modules/@commandgarden/app/dist/client/assets/index-2gEJ4GIc.js +521 -0
  3. package/node_modules/@commandgarden/app/dist/client/assets/{index-rHqHbsBw.css → index-CHt4v0FJ.css} +1 -1
  4. package/node_modules/@commandgarden/app/dist/client/index.html +2 -2
  5. package/node_modules/@commandgarden/app/dist/server/routes/ai-news-cache.d.ts +3 -0
  6. package/node_modules/@commandgarden/app/dist/server/routes/ai-news-cache.js +17 -0
  7. package/node_modules/@commandgarden/app/dist/server/routes/connectors.js +4 -0
  8. package/node_modules/@commandgarden/app/dist/server/routes/index.js +4 -0
  9. package/node_modules/@commandgarden/app/dist/server/routes/roles-cache.d.ts +3 -0
  10. package/node_modules/@commandgarden/app/dist/server/routes/roles-cache.js +17 -0
  11. package/node_modules/@commandgarden/app/dist/server/store.d.ts +12 -0
  12. package/node_modules/@commandgarden/app/dist/server/store.js +44 -0
  13. package/node_modules/@commandgarden/app/skills/cg/SKILL.md +4 -0
  14. package/node_modules/@commandgarden/chrome/dist/service-worker.js +1 -1
  15. package/node_modules/@commandgarden/chrome/dist/service-worker.js.map +2 -2
  16. package/node_modules/@commandgarden/daemon/connectors/alice-role-list.yaml +62 -0
  17. package/node_modules/@commandgarden/daemon/connectors/every-newsletter.eval.js +87 -0
  18. package/node_modules/@commandgarden/daemon/connectors/every-newsletter.yaml +40 -0
  19. package/node_modules/@commandgarden/daemon/connectors/simonwillison-blog.eval.js +39 -0
  20. package/node_modules/@commandgarden/daemon/connectors/simonwillison-blog.yaml +39 -0
  21. package/node_modules/@commandgarden/daemon/connectors/uis-mic-user-information.eval.js +22 -0
  22. package/node_modules/@commandgarden/daemon/connectors/uis-mic-user-information.yaml +54 -0
  23. package/package.json +1 -1
  24. package/node_modules/@commandgarden/app/dist/client/assets/Slides-DMIm_HgI.js +0 -21
  25. package/node_modules/@commandgarden/app/dist/client/assets/index-CupEN1w-.js +0 -511
@@ -0,0 +1,62 @@
1
+ site: alice
2
+ name: role-list
3
+ version: "1.0"
4
+ description: "List role assignments for a user from Alice"
5
+ access: read
6
+
7
+ domains:
8
+ - "alice.mercedes-benz.com"
9
+ capabilities:
10
+ - navigate
11
+ - cookie_read
12
+
13
+ args:
14
+ - name: userId
15
+ type: string
16
+ required: true
17
+ help: "User ID to look up (e.g. SATHIEN)"
18
+
19
+ columns:
20
+ - name: roleId
21
+ type: string
22
+ - name: roleName
23
+ type: string
24
+ - name: description
25
+ type: string
26
+ - name: roleType
27
+ type: string
28
+ - name: validFrom
29
+ type: string
30
+ - name: validTo
31
+ type: string
32
+ - name: isSelfRequestable
33
+ type: boolean
34
+ - name: privileged
35
+ type: boolean
36
+ - name: dataClassification
37
+ type: string
38
+
39
+ pipeline:
40
+ - step: navigate
41
+ url: "https://alice.mercedes-benz.com/access"
42
+ - step: wait
43
+ selector: "body"
44
+ timeout: 30000
45
+ - step: fetch
46
+ # Fetches up to 500 roles in a single request; users with more will be truncated
47
+ url: "https://alice.mercedes-benz.com/alice-proxy-v2/gems/users/${{ args.userId }}/roles?withAttachments=false&withCustomScopeLegacy=false&withCustomScopeValues=false&withTermValues=false&withFormValues=false&filter=roleDefinition.isDynamic==false&sort=+roleDefinition.name&offset=0&limit=500"
48
+ method: "GET"
49
+ headers:
50
+ Accept: "application/json"
51
+ dataPath: "roles"
52
+ - step: map
53
+ fields:
54
+ roleId: "${{ row.roleDefinition.id }}"
55
+ roleName: "${{ row.roleDefinition.name }}"
56
+ description: "${{ row.roleDefinition.description }}"
57
+ roleType: "${{ row.roleDefinition.roleType }}"
58
+ validFrom: "${{ row.validFrom | default('') }}"
59
+ validTo: "${{ row.validTo | default('') }}"
60
+ isSelfRequestable: "${{ row.roleDefinition.isSelfRequestable }}"
61
+ privileged: "${{ row.roleDefinition.privileged }}"
62
+ dataClassification: "${{ row.roleDefinition.dataClassification }}"
@@ -0,0 +1,87 @@
1
+ // every-newsletter.eval.js
2
+ // Extracts blog posts from Every's newsletter page.
3
+ // Strategy: try __NEXT_DATA__ first, fall back to DOM scraping.
4
+ // NOTE: No IIFE — evaluateInPage wraps this in AsyncFunction already.
5
+
6
+ function extractFromNextData() {
7
+ const script = document.getElementById('__NEXT_DATA__');
8
+ if (!script) return null;
9
+
10
+ const raw = script.textContent;
11
+ if (!raw) return null;
12
+
13
+ const nextData = JSON.parse(raw);
14
+ const pageProps = nextData?.props?.pageProps;
15
+ if (!pageProps) return null;
16
+
17
+ const posts = pageProps.posts || pageProps.initialPosts || pageProps.articles || pageProps.items;
18
+ if (!Array.isArray(posts) || posts.length === 0) return null;
19
+
20
+ return posts.map((p) => ({
21
+ title: p.title || p.headline || '',
22
+ url: p.url || p.canonical_url || (p.slug ? 'https://every.to/p/' + p.slug : ''),
23
+ published: p.published_at || p.publishedAt || p._firstPublishedAt || p.date || '',
24
+ author:
25
+ (p.authors || []).map((a) => a.name || a.fullName || a.full_name || '').join(', ') ||
26
+ p.author?.name ||
27
+ p.author ||
28
+ '',
29
+ summary: (p.subtitle || p.excerpt || p.description || p.summary || '').slice(0, 300),
30
+ }));
31
+ }
32
+
33
+ function extractFromDOM() {
34
+ const links = document.querySelectorAll('a[href*="/p/"], a[href*="/chain-of-thought/"], a[href*="/context-window/"], a[href*="/source-code/"], a[href*="/working-overtime/"], a[href*="/vibe-check/"], a[href*="/thesis/"], a[href*="/also-true-for-humans/"], a[href*="/on-every/"]');
35
+ if (!links.length) throw new Error('No post links found on page — site structure may have changed');
36
+
37
+ const seen = new Set();
38
+ const rows = [];
39
+
40
+ for (const link of links) {
41
+ const href = link.getAttribute('href');
42
+ if (!href || seen.has(href)) continue;
43
+
44
+ const titleEl = link.querySelector('h2, h3, [class*="title"], [class*="Title"]');
45
+ if (!titleEl) continue;
46
+
47
+ const title = titleEl.textContent.trim();
48
+ if (!title) continue;
49
+ seen.add(href);
50
+
51
+ const url = href.startsWith('http') ? href : 'https://every.to' + href;
52
+
53
+ const card = link.closest('article') || link.parentElement?.closest('div') || link.parentElement;
54
+
55
+ let published = '';
56
+ const timeEl = card?.querySelector('time');
57
+ if (timeEl) {
58
+ published = timeEl.getAttribute('datetime') || timeEl.textContent.trim();
59
+ }
60
+ if (!published) {
61
+ const dateMatch = card?.textContent?.match(/(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+\d{1,2},?\s+\d{4}/);
62
+ if (dateMatch) published = dateMatch[0];
63
+ }
64
+
65
+ let author = '';
66
+ const authorLink = card?.querySelector('a[href*="/@"]');
67
+ if (authorLink) {
68
+ author = authorLink.textContent.trim();
69
+ }
70
+
71
+ let summary = '';
72
+ const subtitleEl = link.querySelector('p, [class*="subtitle"], [class*="Subtitle"], [class*="description"]');
73
+ if (subtitleEl) {
74
+ summary = subtitleEl.textContent.trim().slice(0, 300);
75
+ }
76
+
77
+ rows.push({ title, url, published, author, summary });
78
+ }
79
+
80
+ if (!rows.length) throw new Error('Could not extract posts from DOM — site structure may have changed');
81
+ return rows;
82
+ }
83
+
84
+ const nextDataRows = extractFromNextData();
85
+ if (nextDataRows) return nextDataRows;
86
+
87
+ return extractFromDOM();
@@ -0,0 +1,40 @@
1
+ site: every
2
+ name: newsletter
3
+ version: "1.0"
4
+ description: "Latest blog posts from Every — AI-focused newsletter"
5
+ access: read
6
+
7
+ domains:
8
+ - "every.to"
9
+ capabilities:
10
+ - navigate
11
+ - js_evaluate
12
+
13
+ args:
14
+ - name: sort
15
+ type: string
16
+ required: false
17
+ default: ""
18
+ enum: ["", "popular", "newest", "oldest"]
19
+ help: "Sort order: popular, newest, oldest (default: newest)"
20
+
21
+ columns:
22
+ - name: title
23
+ type: string
24
+ - name: url
25
+ type: string
26
+ - name: published
27
+ type: string
28
+ - name: author
29
+ type: string
30
+ - name: summary
31
+ type: string
32
+
33
+ pipeline:
34
+ - step: navigate
35
+ url: "https://every.to/newsletter?sort=${{ args.sort }}"
36
+ - step: wait
37
+ selector: "body"
38
+ timeout: 15000
39
+ - step: js_evaluate
40
+ file: every-newsletter.eval.js
@@ -0,0 +1,39 @@
1
+ const tagFilter = '${{ args.tag }}';
2
+
3
+ const resp = await fetch('https://simonwillison.net/atom/everything/');
4
+ if (!resp.ok) throw new Error('Failed to fetch Atom feed: ' + resp.status);
5
+
6
+ const xml = await resp.text();
7
+ const doc = new DOMParser().parseFromString(xml, 'application/xml');
8
+
9
+ const parserError = doc.querySelector('parsererror');
10
+ if (parserError) throw new Error('Atom XML parse error: ' + parserError.textContent);
11
+
12
+ const ns = 'http://www.w3.org/2005/Atom';
13
+ const entries = doc.getElementsByTagNameNS(ns, 'entry');
14
+
15
+ const rows = [];
16
+ for (const entry of entries) {
17
+ const categories = Array.from(entry.getElementsByTagNameNS(ns, 'category'));
18
+ const tags = categories.map(c => c.getAttribute('term')).filter(Boolean).join(', ');
19
+
20
+ if (tagFilter && !tags.split(', ').includes(tagFilter)) continue;
21
+
22
+ const title = (entry.getElementsByTagNameNS(ns, 'title')[0]?.textContent ?? '').trim();
23
+
24
+ const linkEl = Array.from(entry.getElementsByTagNameNS(ns, 'link'))
25
+ .find(l => l.getAttribute('rel') === 'alternate');
26
+ const rawUrl = linkEl?.getAttribute('href') ?? '';
27
+ const url = rawUrl.replace(/#atom-everything$/, '');
28
+
29
+ const published = (entry.getElementsByTagNameNS(ns, 'published')[0]?.textContent ?? '').trim();
30
+
31
+ const summaryHtml = entry.getElementsByTagNameNS(ns, 'summary')[0]?.textContent ?? '';
32
+ const tmp = document.createElement('div');
33
+ tmp.innerHTML = summaryHtml;
34
+ const summary = (tmp.textContent ?? '').replace(/\s+/g, ' ').trim().slice(0, 300);
35
+
36
+ rows.push({ title, url, published, summary, tags });
37
+ }
38
+
39
+ return rows;
@@ -0,0 +1,39 @@
1
+ site: simonwillison
2
+ name: blog
3
+ version: "1.0"
4
+ description: "Latest blog posts from Simon Willison's Weblog"
5
+ access: read
6
+
7
+ domains:
8
+ - "simonwillison.net"
9
+ capabilities:
10
+ - navigate
11
+ - js_evaluate
12
+
13
+ args:
14
+ - name: tag
15
+ type: string
16
+ required: false
17
+ default: ""
18
+ help: "Filter by tag (e.g. 'ai', 'python', 'llms')"
19
+
20
+ columns:
21
+ - name: title
22
+ type: string
23
+ - name: url
24
+ type: string
25
+ - name: published
26
+ type: string
27
+ - name: summary
28
+ type: string
29
+ - name: tags
30
+ type: string
31
+
32
+ pipeline:
33
+ - step: navigate
34
+ url: "https://simonwillison.net/"
35
+ - step: wait
36
+ selector: "body"
37
+ timeout: 15000
38
+ - step: js_evaluate
39
+ file: simonwillison-blog.eval.js
@@ -0,0 +1,22 @@
1
+ const resp = await fetch(
2
+ 'https://uis.query.api.dvb.corpinter.net/v1/users/prod/${{ args.userId }}',
3
+ { headers: { Accept: 'application/json' }, credentials: 'include' }
4
+ );
5
+ if (!resp.ok) throw new Error('UIS API returned ' + resp.status + ' — check userId or log in and retry');
6
+ const d = await resp.json();
7
+
8
+ return [{
9
+ uid: d.uid ?? '',
10
+ givenName: d.givenName ?? '',
11
+ familyName: d.familyName ?? '',
12
+ mail: d.mail ?? '',
13
+ department: d.department ?? '',
14
+ supervisor: d.supervisor ?? '',
15
+ usertype: d.usertype ?? '',
16
+ employeeType: d.employeeType ?? '',
17
+ managementlevel: d.managementlevel ?? '',
18
+ active: d.active ?? false,
19
+ isClient: d.isClient ?? false,
20
+ groups: (d.groups || []).join(', '),
21
+ scopes: (d.scopes || []).map(s => s.scope_id).join(', '),
22
+ }];
@@ -0,0 +1,54 @@
1
+ site: uis
2
+ name: mic-user-information
3
+ version: "1.0"
4
+ description: "Show full user identity, department, groups, and scopes from UIS"
5
+ access: read
6
+
7
+ domains:
8
+ - "uis.query.api.dvb.corpinter.net"
9
+ capabilities:
10
+ - navigate
11
+ - js_evaluate
12
+
13
+ args:
14
+ - name: userId
15
+ type: string
16
+ required: true
17
+ help: "User ID to look up (e.g. SATHIEN)"
18
+
19
+ columns:
20
+ - name: uid
21
+ type: string
22
+ - name: givenName
23
+ type: string
24
+ - name: familyName
25
+ type: string
26
+ - name: mail
27
+ type: string
28
+ - name: department
29
+ type: string
30
+ - name: supervisor
31
+ type: string
32
+ - name: usertype
33
+ type: string
34
+ - name: employeeType
35
+ type: string
36
+ - name: managementlevel
37
+ type: string
38
+ - name: active
39
+ type: boolean
40
+ - name: isClient
41
+ type: boolean
42
+ - name: groups
43
+ type: string
44
+ - name: scopes
45
+ type: string
46
+
47
+ pipeline:
48
+ - step: navigate
49
+ url: "https://uis.query.api.dvb.corpinter.net/v1/users/prod/${{ args.userId }}"
50
+ - step: wait
51
+ selector: "body"
52
+ timeout: 30000
53
+ - step: js_evaluate
54
+ file: "uis-mic-user-information.eval.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commandgarden/cli",
3
- "version": "2.14.3",
3
+ "version": "2.15.0",
4
4
  "description": "Enterprise browser automation CLI",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,21 +0,0 @@
1
- import{c as h,r as l,u as y,j as e,C as f,a as k,G as b,b as w,L as g,d as v,T as j,S as N,P as S,F as A,B as M,D as L,e as T,f as E,E as I,g as C}from"./index-CupEN1w-.js";/**
2
- * @license lucide-react v1.25.0 - ISC
3
- *
4
- * This source code is licensed under the ISC license.
5
- * See the LICENSE file in the root directory of this source tree.
6
- */const _=[["path",{d:"M12 8V4H8",key:"hb8ula"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2",key:"enze0r"}],["path",{d:"M2 14h2",key:"vft8re"}],["path",{d:"M20 14h2",key:"4cs60a"}],["path",{d:"M15 13v2",key:"1xurst"}],["path",{d:"M9 13v2",key:"rq6x2g"}]],P=h("bot",_);/**
7
- * @license lucide-react v1.25.0 - ISC
8
- *
9
- * This source code is licensed under the ISC license.
10
- * See the LICENSE file in the root directory of this source tree.
11
- */const D=[["path",{d:"M13.744 17.736a6 6 0 1 1-7.48-7.48",key:"bq4yh3"}],["path",{d:"M15 6h1v4",key:"11y1tn"}],["path",{d:"m6.134 14.768.866-.5 2 3.464",key:"17snzx"}],["circle",{cx:"16",cy:"8",r:"6",key:"14bfc9"}]],O=h("coins",D);/**
12
- * @license lucide-react v1.25.0 - ISC
13
- *
14
- * This source code is licensed under the ISC license.
15
- * See the LICENSE file in the root directory of this source tree.
16
- */const $=[["path",{d:"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49",key:"ct8e1f"}],["path",{d:"M14.084 14.158a3 3 0 0 1-4.242-4.242",key:"151rxh"}],["path",{d:"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143",key:"13bj9a"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]],B=h("eye-off",$);/**
17
- * @license lucide-react v1.25.0 - ISC
18
- *
19
- * This source code is licensed under the ISC license.
20
- * See the LICENSE file in the root directory of this source tree.
21
- */const R=[["path",{d:"M2 13a6 6 0 1 0 12 0 4 4 0 1 0-8 0 2 2 0 0 0 4 0",key:"hneq2s"}],["circle",{cx:"10",cy:"13",r:"8",key:"194lz3"}],["path",{d:"M2 21h12c4.4 0 8-3.6 8-8V7a2 2 0 1 0-4 0v6",key:"ixqyt7"}],["path",{d:"M18 3 19.1 5.2",key:"9tjm43"}],["path",{d:"M22 3 20.9 5.2",key:"j3odrs"}]],F=h("snail",R);function m({children:s,kicker:a,title:t}){return e.jsxs("div",{className:"h-full flex flex-col justify-center px-8 sm:px-16 lg:px-24 max-w-6xl mx-auto mt-16 w-full",children:[e.jsx("div",{className:"font-mono text-xs font-medium opacity-40 uppercase tracking-[0.12em] mb-3",children:a}),e.jsx("h2",{className:"font-display text-3xl sm:text-4xl font-bold uppercase tracking-[0.04em] mb-10",style:{textWrap:"balance"},children:t}),s]})}const q=[{icon:b,headline:"Browsers are the primary data interface",body:"The data you need lives in SaaS dashboards and internal portals, not in APIs. If it's behind a login, agents can't see it.",color:"text-primary",border:"border-primary/20"},{icon:w,headline:"APIs are limited and often unavailable",body:"Most internal tools don't have APIs. When one exists, you need service accounts, OAuth flows, and IT approval before seeing a single row.",color:"text-error",border:"border-error/20"},{icon:g,headline:"Authentication blocks automation",body:"SSO, MFA, session cookies, corporate proxies. You're already logged in. The automation isn't.",color:"text-warning",border:"border-warning/20"},{icon:v,headline:"AI browser automation is slow and burns tokens",body:"Agents re-parse the full page on every call to figure out what's on screen, even when the layout hasn't changed.",color:"text-secondary",border:"border-secondary/20"}];function z(){return e.jsxs(m,{kicker:"Where the data actually lives",title:"The Problem",children:[e.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-5",children:q.map(({icon:s,headline:a,body:t,color:n,border:r})=>e.jsxs("div",{className:`border ${r} p-6 flex gap-4`,children:[e.jsx(s,{className:`w-5 h-5 shrink-0 mt-0.5 ${n}`}),e.jsxs("div",{children:[e.jsx("h3",{className:"font-display font-semibold text-base mb-2",children:a}),e.jsx("p",{className:"text-sm opacity-60 leading-relaxed",children:t})]})]},a))}),e.jsx("p",{className:"text-sm opacity-40 mt-8 max-w-[65ch]",children:"That parsing only needs to happen once."})]})}const x=[{icon:P,headline:"Use AI to navigate the browser",body:"Playwright, Puppeteer, or an LLM-driven agent opens a headless browser and clicks through pages like a user would.",color:"text-primary",border:"border-primary/20"},{icon:g,headline:"Blocked by authentication",body:"Headless browsers start logged out. SSO, MFA, and session cookies don't carry over. You're back to storing credentials or managing auth flows.",color:"text-error",border:"border-error/20"},{icon:F,headline:"Slow and fragile",body:"Each run launches a browser, waits for renders, retries on flaky selectors. A single DOM change can break the whole flow.",color:"text-warning",border:"border-warning/20"},{icon:O,headline:"High token consumption",body:"The agent sends page snapshots to an LLM to decide what to click next. Every interaction costs tokens, even for pages it's seen before.",color:"text-secondary",border:"border-secondary/20"},{icon:B,headline:"Limited visibility into actions",body:"No audit trail. You can't see which pages were visited, what data was read, or whether the agent went somewhere it shouldn't have.",color:"text-error",border:"border-error/20"}];function V(){return e.jsx(m,{kicker:"The existing approach",title:'The "Solution"?',children:e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-5",children:[[x[0]].map(({icon:s,headline:a,body:t,color:n,border:r})=>e.jsxs("div",{className:`border ${r} p-6 flex gap-4 md:col-span-2`,children:[e.jsx(s,{className:`w-5 h-5 shrink-0 mt-0.5 ${n}`}),e.jsxs("div",{children:[e.jsx("h3",{className:"font-display font-semibold text-base mb-2",children:a}),e.jsx("p",{className:"text-sm opacity-60 leading-relaxed",children:t})]})]},a)),x.slice(1).map(({icon:s,headline:a,body:t,color:n,border:r})=>e.jsxs("div",{className:`border ${r} p-6 flex gap-4`,children:[e.jsx(s,{className:`w-5 h-5 shrink-0 mt-0.5 ${n}`}),e.jsxs("div",{children:[e.jsx("h3",{className:"font-display font-semibold text-base mb-2",children:a}),e.jsx("p",{className:"text-sm opacity-60 leading-relaxed",children:t})]})]},a))]})})}const G=[{icon:j,title:"CLI",mono:"cg run · cg list · cg inspect",desc:"Same command for humans and agents. One call in, structured JSON out."},{icon:N,title:"Daemon",mono:"Fastify :9091",desc:"Validates auth, loads the connector registry, routes requests, writes audit log."},{icon:b,title:"Chrome Extension",mono:"Manifest V3",desc:"Runs inside your authenticated browser. Reads cookies, DOM, and network responses."},{icon:S,title:"App Server + GUI",mono:"React SPA :9092",desc:"Dashboard, app pages, connector browser, config management. All on localhost."},{icon:A,title:"Connectors",mono:"13 YAML pipelines",desc:"Declarative recipes: navigate → wait → extract → map. No code unless declared."},{icon:M,title:"Skills",mono:"cg skill · connector-authoring",desc:"Agents discover, inspect, and run connectors. Two bundled skills ship with the CLI."},{icon:L,title:"Audit Log",mono:"SQLite",desc:"Every execution logged: connector, domains, timing, approvals, row counts. Audit-or-fail."},{icon:T,title:"Security Controls",mono:"7 capabilities · 3 risk tiers",desc:"Domain-scoped allowlists, step-by-step approval gates, per-session auth tokens."}],U=[{name:"navigate",risk:"low"},{name:"dom_read",risk:"low"},{name:"cookie_read",risk:"medium"},{name:"dom_write",risk:"medium"},{name:"intercept_response",risk:"medium"},{name:"cookie_write",risk:"high"},{name:"js_evaluate",risk:"high"}],Y={low:"success",medium:"warning",high:"error"};function H(){return e.jsxs(m,{kicker:"Everything ships together",title:"Batteries Included",children:[e.jsx("div",{className:"grid grid-cols-2 lg:grid-cols-4 gap-3 mb-6",children:G.map(({icon:s,title:a,mono:t,desc:n})=>e.jsxs("div",{className:"border border-base-300 p-4 flex flex-col",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(s,{className:"w-4 h-4 shrink-0 opacity-40"}),e.jsx("span",{className:"font-display font-semibold text-sm",children:a})]}),e.jsx("span",{className:"font-mono text-[0.65rem] opacity-35 mb-2 leading-tight",children:t}),e.jsx("p",{className:"text-xs opacity-55 leading-relaxed mt-auto",children:n})]},a))}),e.jsxs("div",{className:"border border-base-300 p-4",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx(E,{className:"w-4 h-4 opacity-40"}),e.jsx("span",{className:"font-display font-semibold text-sm",children:"Capability risk tiers"}),e.jsx(I,{className:"w-3.5 h-3.5 opacity-30 ml-auto"}),e.jsx("span",{className:"text-[0.6rem] font-mono opacity-30",children:"approval gate per step"})]}),e.jsx("div",{className:"flex flex-wrap gap-2",children:U.map(({name:s,risk:a})=>e.jsxs(C,{variant:Y[a],size:"xs",children:[s," ",e.jsx("span",{className:"opacity-50 ml-1",children:a})]},s))})]})]})}const d=[z,V,H];function X(){const[s,a]=l.useState(0),[t,n]=l.useState(!1),r=y(),p=l.useRef(),c=l.useCallback(i=>{i<0||i>=d.length||i===s||t||(n(!0),p.current=setTimeout(()=>{a(i),n(!1)},150))},[s,t]);l.useEffect(()=>()=>clearTimeout(p.current),[]),l.useEffect(()=>{const i=o=>{(o.key==="ArrowRight"||o.key==="ArrowDown")&&(o.preventDefault(),c(s+1)),(o.key==="ArrowLeft"||o.key==="ArrowUp")&&(o.preventDefault(),c(s-1)),o.key==="Escape"&&r("/")};return window.addEventListener("keydown",i),()=>window.removeEventListener("keydown",i)},[c,s,r]);const u=d[s];return e.jsxs("div",{className:"fixed inset-0 z-50 bg-base-100 flex flex-col select-none",children:[e.jsx("div",{className:"flex-1 min-h-0 overflow-y-auto",children:e.jsx("div",{className:`min-h-full flex transition-opacity duration-150 ${t?"opacity-0":"opacity-100"}`,children:e.jsx(u,{})})}),e.jsxs("div",{className:"flex items-center justify-between px-6 py-3 border-t border-base-300 bg-base-100",children:[e.jsxs("button",{className:"btn btn-ghost btn-sm gap-1 font-mono text-xs",onClick:()=>c(s-1),disabled:s===0,children:[e.jsx(f,{className:"w-4 h-4"})," Prev"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[d.map((i,o)=>e.jsx("button",{onClick:()=>c(o),className:`w-2 h-2 transition-colors ${o===s?"bg-primary":"bg-base-300 hover:bg-base-content/20"}`,"aria-label":`Slide ${o+1}`},o)),e.jsxs("span",{className:"font-mono text-[0.65rem] opacity-30 ml-2",children:[s+1," / ",d.length]})]}),e.jsxs("button",{className:"btn btn-ghost btn-sm gap-1 font-mono text-xs",onClick:()=>c(s+1),disabled:s===d.length-1,children:["Next ",e.jsx(k,{className:"w-4 h-4"})]})]})]})}export{X as default};