@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.
- package/node_modules/@commandgarden/app/dist/client/assets/Slides-5KujoV-w.js +30 -0
- package/node_modules/@commandgarden/app/dist/client/assets/index-2gEJ4GIc.js +521 -0
- package/node_modules/@commandgarden/app/dist/client/assets/{index-rHqHbsBw.css → index-CHt4v0FJ.css} +1 -1
- package/node_modules/@commandgarden/app/dist/client/index.html +2 -2
- package/node_modules/@commandgarden/app/dist/server/routes/ai-news-cache.d.ts +3 -0
- package/node_modules/@commandgarden/app/dist/server/routes/ai-news-cache.js +17 -0
- package/node_modules/@commandgarden/app/dist/server/routes/connectors.js +4 -0
- package/node_modules/@commandgarden/app/dist/server/routes/index.js +4 -0
- package/node_modules/@commandgarden/app/dist/server/routes/roles-cache.d.ts +3 -0
- package/node_modules/@commandgarden/app/dist/server/routes/roles-cache.js +17 -0
- package/node_modules/@commandgarden/app/dist/server/store.d.ts +12 -0
- package/node_modules/@commandgarden/app/dist/server/store.js +44 -0
- package/node_modules/@commandgarden/app/skills/cg/SKILL.md +4 -0
- package/node_modules/@commandgarden/chrome/dist/service-worker.js +1 -1
- package/node_modules/@commandgarden/chrome/dist/service-worker.js.map +2 -2
- package/node_modules/@commandgarden/daemon/connectors/alice-role-list.yaml +62 -0
- package/node_modules/@commandgarden/daemon/connectors/every-newsletter.eval.js +87 -0
- package/node_modules/@commandgarden/daemon/connectors/every-newsletter.yaml +40 -0
- package/node_modules/@commandgarden/daemon/connectors/simonwillison-blog.eval.js +39 -0
- package/node_modules/@commandgarden/daemon/connectors/simonwillison-blog.yaml +39 -0
- package/node_modules/@commandgarden/daemon/connectors/uis-mic-user-information.eval.js +22 -0
- package/node_modules/@commandgarden/daemon/connectors/uis-mic-user-information.yaml +54 -0
- package/package.json +1 -1
- package/node_modules/@commandgarden/app/dist/client/assets/Slides-DMIm_HgI.js +0 -21
- 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,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};
|