anentrypoint-design 0.0.102 → 0.0.103

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 (78) hide show
  1. package/app-shell.css +464 -2005
  2. package/colors_and_type.css +140 -626
  3. package/dist/247420.css +578 -2749
  4. package/dist/247420.js +23 -62
  5. package/package.json +22 -23
  6. package/src/bootstrap.js +5 -18
  7. package/src/components/chat.js +15 -15
  8. package/src/components/community.js +9 -7
  9. package/src/components/content.js +71 -54
  10. package/src/components/files-modals.js +4 -2
  11. package/src/components/files.js +6 -14
  12. package/src/components/freddie/helpers.js +38 -77
  13. package/src/components/freddie.js +32 -16
  14. package/src/components/shell.js +22 -15
  15. package/src/components.js +7 -3
  16. package/src/debug.js +21 -30
  17. package/src/deck-stage.js +10 -6
  18. package/src/highlight.js +25 -11
  19. package/src/index.js +29 -5
  20. package/src/{desktop → kits/os}/freddie/helpers.js +1 -1
  21. package/src/{desktop → kits/os}/freddie/pages-chat.js +2 -2
  22. package/src/{desktop → kits/os}/freddie/pages-core.js +2 -2
  23. package/src/{desktop → kits/os}/freddie/pages-os.js +1 -1
  24. package/src/{desktop → kits/os}/freddie/pages-tools.js +2 -2
  25. package/src/{desktop → kits/os}/freddie-dashboard.js +2 -2
  26. package/src/markdown.js +27 -49
  27. package/src/motion.js +30 -17
  28. package/src/page-html.js +18 -116
  29. package/src/styles.js +14 -22
  30. package/src/web-components/ds-chat.js +24 -56
  31. package/dist/247420.app.js +0 -5
  32. package/dist/fonts/archivo_v25_k3k6o8UDI-1M0wlSV9XAw6lQkqWY8Q82sJaRE-NWIDdgffTT0zRp8A.ttf +0 -0
  33. package/dist/fonts/archivo_v25_k3k6o8UDI-1M0wlSV9XAw6lQkqWY8Q82sJaRE-NWIDdgffTT6jRp8A.ttf +0 -0
  34. package/dist/fonts/archivo_v25_k3k6o8UDI-1M0wlSV9XAw6lQkqWY8Q82sJaRE-NWIDdgffTTBjNp8A.ttf +0 -0
  35. package/dist/fonts/archivo_v25_k3k6o8UDI-1M0wlSV9XAw6lQkqWY8Q82sJaRE-NWIDdgffTTNDNp8A.ttf +0 -0
  36. package/dist/fonts/archivo_v25_k3k6o8UDI-1M0wlSV9XAw6lQkqWY8Q82sJaRE-NWIDdgffTTnTRp8A.ttf +0 -0
  37. package/dist/fonts/archivo_v25_k3k6o8UDI-1M0wlSV9XAw6lQkqWY8Q82sJaRE-NWIDdgffTTtDRp8A.ttf +0 -0
  38. package/dist/fonts/archivonarrow_v35_tss5ApVBdCYD5Q7hcxTE1ArZ0Zz8oY2KRmwvKhhv8laKpA.ttf +0 -0
  39. package/dist/fonts/archivonarrow_v35_tss5ApVBdCYD5Q7hcxTE1ArZ0Zz8oY2KRmwvKhhvHlGKpA.ttf +0 -0
  40. package/dist/fonts/archivonarrow_v35_tss5ApVBdCYD5Q7hcxTE1ArZ0Zz8oY2KRmwvKhhvLFGKpA.ttf +0 -0
  41. package/dist/fonts/archivonarrow_v35_tss5ApVBdCYD5Q7hcxTE1ArZ0Zz8oY2KRmwvKhhvy1aKpA.ttf +0 -0
  42. package/dist/fonts/jetbrainsmono_v24_tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8-qxjPQ.ttf +0 -0
  43. package/dist/fonts/jetbrainsmono_v24_tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8FqtjPQ.ttf +0 -0
  44. package/dist/fonts/jetbrainsmono_v24_tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8L6tjPQ.ttf +0 -0
  45. package/dist/fonts/jetbrainsmono_v24_tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKxjPQ.ttf +0 -0
  46. package/dist/fonts/jetbrainsmono_v24_tDba2o-flEEny0FZhsfKu5WU4xD-IQ-PuZJJXxfpAO-LflOQ.ttf +0 -0
  47. package/dist/fonts/jetbrainsmono_v24_tDba2o-flEEny0FZhsfKu5WU4xD-IQ-PuZJJXxfpAO9seVOQ.ttf +0 -0
  48. package/dist/fonts/spacegrotesk_v22_V8mQoQDjQSkFtoMM3T6r8E7mF71Q-gOoraIAEj42Vksj.ttf +0 -0
  49. package/dist/fonts/spacegrotesk_v22_V8mQoQDjQSkFtoMM3T6r8E7mF71Q-gOoraIAEj4PVksj.ttf +0 -0
  50. package/dist/fonts/spacegrotesk_v22_V8mQoQDjQSkFtoMM3T6r8E7mF71Q-gOoraIAEj7aUUsj.ttf +0 -0
  51. package/dist/fonts/spacegrotesk_v22_V8mQoQDjQSkFtoMM3T6r8E7mF71Q-gOoraIAEj7oUUsj.ttf +0 -0
  52. package/src/app.js +0 -156
  53. package/src/components/freddie/pages-chains.js +0 -168
  54. package/src/components/freddie/pages-chat.js +0 -122
  55. package/src/components/freddie/pages-config-edit.js +0 -174
  56. package/src/components/freddie/pages-config.js +0 -193
  57. package/src/components/freddie/pages-core.js +0 -170
  58. package/src/components/freddie/pages-runtime.js +0 -69
  59. package/src/components/freddie/pages-voice.js +0 -109
  60. package/src/web-components/freddie-chat.js +0 -34
  61. /package/src/{desktop → kits/os}/about-app.js +0 -0
  62. /package/src/{desktop → kits/os}/app-panes.css +0 -0
  63. /package/src/{desktop → kits/os}/browser-app.js +0 -0
  64. /package/src/{desktop → kits/os}/files-app.js +0 -0
  65. /package/src/{desktop → kits/os}/freddie/routes.js +0 -0
  66. /package/src/{desktop → kits/os}/freddie-dashboard.css +0 -0
  67. /package/src/{desktop → kits/os}/icons.js +0 -0
  68. /package/src/{desktop → kits/os}/index.js +0 -0
  69. /package/src/{desktop → kits/os}/launcher.css +0 -0
  70. /package/src/{desktop → kits/os}/launcher.js +0 -0
  71. /package/src/{desktop → kits/os}/monitor-app.js +0 -0
  72. /package/src/{desktop → kits/os}/shell.js +0 -0
  73. /package/src/{desktop → kits/os}/terminal-app.js +0 -0
  74. /package/src/{desktop → kits/os}/theme.css +0 -0
  75. /package/src/{desktop → kits/os}/validate.css +0 -0
  76. /package/src/{desktop → kits/os}/validator-app.js +0 -0
  77. /package/src/{desktop → kits/os}/wm.css +0 -0
  78. /package/src/{desktop → kits/os}/wm.js +0 -0
@@ -1,89 +1,50 @@
1
+ // Freddie helpers — minimal stubs. Real freddie surfaces ship downstream
2
+ // (gm-cc, foph, hermes-fork). The SDK exposes the registry shape and
3
+ // localStorage helpers so consumer pages can wire to existing patterns.
4
+
1
5
  import * as webjsx from '../../../vendor/webjsx/index.js';
2
- import { Receipt, Panel } from '../content.js';
3
- import { Chip } from '../shell.js';
4
6
  const h = webjsx.createElement;
5
7
 
6
- export const skillLabel = s => (s.name||'').replace(/^gm:/,'').replace(/-/g,' ');
7
- export const getRecentPaths = () => { try { return JSON.parse(localStorage.getItem('fd_recent_cwds')||'[]'); } catch { return []; } };
8
- export const saveRecentPath = p => { if (!p) return; const a = getRecentPaths().filter(x=>x!==p); a.unshift(p); localStorage.setItem('fd_recent_cwds', JSON.stringify(a.slice(0,5))); };
8
+ export function renderPageStub({ id, title }) {
9
+ return h('div', { class: 'ds-freddie-stub' },
10
+ h('span', { class: 'eyebrow' }, 'freddie · ' + id),
11
+ h('h2', {}, title || id),
12
+ h('p', { class: 'dim' }, 'this page renderer is a stub. consumers override it on their own freddie router.')
13
+ );
14
+ }
9
15
 
10
- export function tryParseJson(s) { if (typeof s !== 'string') return null; const t = s.trim(); if (!t || (t[0] !== '{' && t[0] !== '[')) return null; try { return JSON.parse(t); } catch { return null; } }
16
+ const SKILL_LABELS = {
17
+ transcribe: 'transcribe',
18
+ summarize: 'summarize',
19
+ translate: 'translate',
20
+ extract: 'extract',
21
+ classify: 'classify',
22
+ };
11
23
 
12
- export function flattenKv(obj, prefix='') {
13
- const rows = [];
14
- for (const [k, v] of Object.entries(obj || {})) {
15
- const key = prefix ? prefix+'.'+k : k;
16
- if (v === null || v === undefined) rows.push([key, '—']);
17
- else if (typeof v === 'object' && !Array.isArray(v)) rows.push(...flattenKv(v, key));
18
- else if (Array.isArray(v)) rows.push([key, v.length === 0 ? '—' : v.map(x => typeof x === 'object' ? '{…}' : String(x)).join(', ')]);
19
- else rows.push([key, String(v)]);
20
- }
21
- return rows;
24
+ export function skillLabel(slug) {
25
+ return SKILL_LABELS[slug] || slug;
22
26
  }
23
27
 
24
- export function renderConfigSections(cfg) {
25
- const sections = [];
26
- for (const [k, v] of Object.entries(cfg || {})) {
27
- if (v && typeof v === 'object' && !Array.isArray(v)) {
28
- sections.push(Panel({ title: k, children: Receipt({ rows: flattenKv(v) }) }));
29
- }
30
- }
31
- const scalars = Object.entries(cfg || {}).filter(([_, v]) => !(v && typeof v === 'object' && !Array.isArray(v))).map(([k, v]) => [k, Array.isArray(v) ? '['+v.length+']' : String(v ?? '—')]);
32
- if (scalars.length) sections.unshift(Panel({ title: 'top-level', children: Receipt({ rows: scalars }) }));
33
- return sections;
28
+ const RECENT_KEY = 'ds247420.recent.paths';
29
+
30
+ export function getRecentPaths() {
31
+ if (typeof localStorage === 'undefined') return [];
32
+ try { return JSON.parse(localStorage.getItem(RECENT_KEY) || '[]'); }
33
+ catch { return []; }
34
34
  }
35
35
 
36
- export function renderToolArgs(args) {
37
- if (!args || typeof args !== 'object') return h('span', { class: 'fd-muted' }, '(no args)');
38
- const rows = flattenKv(args);
39
- if (!rows.length) return h('span', { class: 'fd-muted' }, '(empty)');
40
- return h('table', { class: 'kv fd-tool-kv' }, h('tbody', {},
41
- ...rows.map(([k, v], i) => h('tr', { key: i },
42
- h('td', {}, k),
43
- h('td', {}, String(v).length > 200 ? String(v).slice(0,200)+'…' : String(v))
44
- ))
45
- ));
36
+ export function saveRecentPath(path) {
37
+ if (typeof localStorage === 'undefined' || !path) return;
38
+ const list = getRecentPaths().filter(p => p !== path);
39
+ list.unshift(path);
40
+ try { localStorage.setItem(RECENT_KEY, JSON.stringify(list.slice(0, 10))); } catch {}
46
41
  }
47
42
 
48
- export function renderChatMessages(el, msgs) {
49
- if (!el) return; el.innerHTML = '';
50
- for (const m of msgs) {
51
- const div = document.createElement('div');
52
- div.className = 'fd-msg' + (m.role === 'assistant' ? ' fd-msg-assistant' : m.role === 'tool' ? ' fd-msg-tool' : '');
53
- if (m.role === 'tool') {
54
- const det = document.createElement('details');
55
- det.className = 'fd-tool-call';
56
- const sum = document.createElement('summary');
57
- sum.textContent = (m.name || 'tool') + (m.argsSummary ? ' · '+m.argsSummary : '');
58
- det.appendChild(sum);
59
- const body = document.createElement('div');
60
- body.className = 'fd-tool-body';
61
- const parsedArgs = tryParseJson(m.content);
62
- if (parsedArgs && typeof parsedArgs === 'object') {
63
- const tbl = document.createElement('table');
64
- tbl.className = 'kv fd-tool-kv';
65
- const tb = document.createElement('tbody');
66
- for (const [k, v] of flattenKv(parsedArgs)) {
67
- const tr = document.createElement('tr');
68
- const tdK = document.createElement('td'); tdK.textContent = k;
69
- const tdV = document.createElement('td'); tdV.textContent = String(v).length > 240 ? String(v).slice(0,240)+'…' : String(v);
70
- tr.appendChild(tdK); tr.appendChild(tdV); tb.appendChild(tr);
71
- }
72
- tbl.appendChild(tb); body.appendChild(tbl);
73
- } else {
74
- const pre = document.createElement('pre');
75
- pre.className = 'fd-pre';
76
- pre.textContent = m.content || '';
77
- body.appendChild(pre);
78
- }
79
- det.appendChild(body); div.appendChild(det);
80
- } else {
81
- const pre = document.createElement('pre');
82
- pre.className = 'fd-pre';
83
- pre.textContent = m.content || '';
84
- div.appendChild(pre);
85
- }
86
- el.appendChild(div);
87
- }
88
- el.scrollTop = el.scrollHeight;
43
+ // Helper used by consumers that want to render chat-message arrays with
44
+ // our ChatMessage factory but pre-formatted for freddie's data shape.
45
+ export function renderChatMessages(messages = [], opts = {}) {
46
+ // Import lazily to keep this module light.
47
+ return import('../chat.js').then(({ ChatMessage }) =>
48
+ messages.map((m, i) => ChatMessage({ ...m, key: m.key != null ? m.key : i, ...opts }))
49
+ );
89
50
  }
@@ -1,17 +1,33 @@
1
- export { skillLabel, getRecentPaths, saveRecentPath, renderChatMessages } from './freddie/helpers.js';
2
- export { home, sessions, projects, agents, analytics } from './freddie/pages-core.js';
3
- export { chat } from './freddie/pages-chat.js';
4
- export { models, cron, skills, env, tools } from './freddie/pages-config.js';
5
- export { batch, gateway } from './freddie/pages-runtime.js';
6
- export { config } from './freddie/pages-config-edit.js';
7
- export { voice } from './freddie/pages-voice.js';
8
- export { chains } from './freddie/pages-chains.js';
1
+ // Freddie page registry. Matches upstream shape:
2
+ // FREDDIE_PAGES is an OBJECT mapping id page-renderer fn (not an array).
3
+ // Per-page renderer functions are stubs by default — consumers (gm-cc,
4
+ // foph, hermes-fork, etc.) provide their own page bodies or import the
5
+ // richer upstream renderers.
9
6
 
10
- import { home, sessions, projects, agents, analytics } from './freddie/pages-core.js';
11
- import { chat } from './freddie/pages-chat.js';
12
- import { models, cron, skills, env, tools } from './freddie/pages-config.js';
13
- import { batch, gateway } from './freddie/pages-runtime.js';
14
- import { config } from './freddie/pages-config-edit.js';
15
- import { voice } from './freddie/pages-voice.js';
16
- import { chains } from './freddie/pages-chains.js';
17
- export const FREDDIE_PAGES = { home, chat, voice, sessions, projects, agents, analytics, models, cron, skills, config, env, tools, batch, gateway, chains };
7
+ import { renderPageStub, getRecentPaths, saveRecentPath, skillLabel, renderChatMessages } from './freddie/helpers.js';
8
+
9
+ const make = (label) => (props) => renderPageStub({ id: label, ...props });
10
+
11
+ export const home = make('home');
12
+ export const chat = make('chat');
13
+ export const voice = make('voice');
14
+ export const sessions = make('sessions');
15
+ export const projects = make('projects');
16
+ export const agents = make('agents');
17
+ export const analytics = make('analytics');
18
+ export const models = make('models');
19
+ export const cron = make('cron');
20
+ export const skills = make('skills');
21
+ export const config = make('config');
22
+ export const env = make('env');
23
+ export const tools = make('tools');
24
+ export const batch = make('batch');
25
+ export const gateway = make('gateway');
26
+ export const chains = make('chains');
27
+
28
+ export const FREDDIE_PAGES = {
29
+ home, chat, voice, sessions, projects, agents, analytics,
30
+ models, cron, skills, config, env, tools, batch, gateway, chains
31
+ };
32
+
33
+ export { skillLabel, getRecentPaths, saveRecentPath, renderChatMessages };
@@ -1,3 +1,7 @@
1
+ // Chrome: Topbar, Crumb, Side, Status, AppShell, plus primitives
2
+ // (Brand, Chip, Btn, Glyph, Heading, Lede). Pure factories — props in,
3
+ // webjsx vnode out. CSS in app-shell.css uses these class names.
4
+
1
5
  import * as webjsx from '../../vendor/webjsx/index.js';
2
6
  const h = webjsx.createElement;
3
7
 
@@ -8,15 +12,12 @@ export function Brand({ name = '247420', leaf } = {}) {
8
12
  }
9
13
 
10
14
  export function Chip({ tone = '', children }) {
11
- return h('span', { class: 'chip' + (tone ? ' ' + tone : '') }, children);
15
+ return h('span', { class: 'chip' + (tone ? ' tone-' + tone : '') }, children);
12
16
  }
13
17
 
14
- export function Btn({ href = '#', primary, children, onClick }) {
15
- return h('a', {
16
- class: primary ? 'btn-primary' : 'btn',
17
- href,
18
- onclick: onClick
19
- }, children);
18
+ export function Btn({ href = '#', primary, ghost, children, onClick }) {
19
+ const cls = primary ? 'btn-primary' : (ghost ? 'btn-ghost' : 'btn');
20
+ return h('a', { class: cls, href, onclick: onClick }, children);
20
21
  }
21
22
 
22
23
  export function Glyph({ children, color }) {
@@ -29,16 +30,16 @@ export function Topbar({ brand = '247420', leaf = '', items = [], active = '', o
29
30
  search ? h('label', { class: 'app-search' },
30
31
  h('span', { class: 'icon' }, '⌕'),
31
32
  h('input', { type: 'search', placeholder: search, 'aria-label': 'search' })
32
- ) : null,
33
+ ) : h('span', {}),
33
34
  h('nav', {}, ...items.map(([label, href]) =>
34
35
  h('a', {
35
36
  key: label,
36
37
  href,
37
- class: active === label.replace(' ↗', '') ? 'active' : '',
38
+ class: active === String(label).replace(' ↗', '') ? 'active' : '',
38
39
  onclick: (e) => {
39
40
  if (!String(href).startsWith('http') && onNav) {
40
41
  e.preventDefault();
41
- onNav(label.replace(' ↗', ''));
42
+ onNav(String(label).replace(' ↗', ''));
42
43
  }
43
44
  }
44
45
  }, label)
@@ -68,7 +69,7 @@ export function Side({ sections = [] } = {}) {
68
69
  class: active ? 'active' : '',
69
70
  onclick: onClick
70
71
  },
71
- glyph != null ? Glyph({ children: glyph, color }) : null,
72
+ glyph != null ? Glyph({ children: glyph, color }) : h('span', { class: 'glyph' }),
72
73
  h('span', {}, label),
73
74
  count != null ? h('span', { class: 'count' }, String(count)) : null
74
75
  );
@@ -86,10 +87,7 @@ export function Status({ left = [], right = [] } = {}) {
86
87
 
87
88
  export function AppShell({ topbar, crumb, side, main, status, narrow } = {}) {
88
89
  const hasSide = Boolean(side);
89
- const sideNode = hasSide
90
- ? side
91
- : h('aside', { class: 'app-side', 'aria-hidden': 'true' });
92
-
90
+ const sideNode = hasSide ? side : h('aside', { class: 'app-side', 'aria-hidden': 'true' });
93
91
  return h('div', { class: 'app' },
94
92
  topbar || null,
95
93
  crumb || null,
@@ -108,3 +106,12 @@ export function Heading({ level = 1, children, style = '' }) {
108
106
  export function Lede({ children }) {
109
107
  return h('p', { class: 'lede' }, children);
110
108
  }
109
+
110
+ export function Dot({ tone = 'live' }) {
111
+ const cls = tone === 'live' ? 'ds-dot-live' : 'ds-dot-idle';
112
+ return h('span', { class: cls }, tone === 'live' ? '●' : '○');
113
+ }
114
+
115
+ export function Rail({ tone = 'green' }) {
116
+ return h('span', { class: 'ds-rail tone-' + tone, 'aria-hidden': 'true' });
117
+ }
package/src/components.js CHANGED
@@ -1,10 +1,12 @@
1
+ // Component barrel — matches upstream export surface 1:1.
2
+
1
3
  import * as webjsx from '../vendor/webjsx/index.js';
2
4
  export const h = webjsx.createElement;
3
5
 
4
6
  export {
5
7
  Brand, Chip, Btn, Glyph,
6
8
  Topbar, Crumb, Side, Status, AppShell,
7
- Heading, Lede
9
+ Heading, Lede, Dot, Rail
8
10
  } from './components/shell.js';
9
11
 
10
12
  export {
@@ -41,6 +43,8 @@ export {
41
43
  } from './components/community.js';
42
44
 
43
45
  export {
44
- home, chat, sessions, projects, agents, analytics, models, cron, skills, config, env, tools, batch, gateway, chains,
45
- skillLabel, getRecentPaths, saveRecentPath, renderChatMessages, FREDDIE_PAGES
46
+ FREDDIE_PAGES,
47
+ home, chat, voice, sessions, projects, agents, analytics,
48
+ models, cron, skills, config, env, tools, batch, gateway, chains,
49
+ skillLabel, getRecentPaths, saveRecentPath, renderChatMessages
46
50
  } from './components/freddie.js';
package/src/debug.js CHANGED
@@ -1,39 +1,30 @@
1
- const registry = new Map();
1
+ // Lightweight client-side registry. Subsystems register a snapshot fn;
2
+ // `window.__debug` exposes them all for live inspection.
2
3
 
3
- export function register(name, snapshot) {
4
- if (typeof name !== 'string' || !name) throw new Error('debug.register: name required');
5
- if (typeof snapshot !== 'function') throw new Error('debug.register: snapshot fn required');
6
- registry.set(name, snapshot);
7
- expose();
8
- }
9
-
10
- export function unregister(name) { registry.delete(name); expose(); }
4
+ const _registry = new Map();
11
5
 
12
- export function list() { return [...registry.keys()]; }
6
+ export function register(name, snapshotFn) {
7
+ if (typeof name !== 'string' || typeof snapshotFn !== 'function') return;
8
+ _registry.set(name, snapshotFn);
9
+ if (typeof window !== 'undefined') {
10
+ if (!window.__debug) window.__debug = {};
11
+ Object.defineProperty(window.__debug, name, {
12
+ get() { try { return snapshotFn(); } catch (e) { return { error: String(e) }; } },
13
+ configurable: true,
14
+ enumerable: true,
15
+ });
16
+ }
17
+ }
13
18
 
14
- export function snapshot(name) {
15
- const fn = registry.get(name);
16
- if (!fn) return null;
17
- try { return fn(); } catch (e) { return { error: String(e && e.message || e) }; }
19
+ export function unregister(name) {
20
+ _registry.delete(name);
21
+ if (typeof window !== 'undefined' && window.__debug) delete window.__debug[name];
18
22
  }
19
23
 
20
- export function snapshotAll() {
24
+ export function snapshot() {
21
25
  const out = {};
22
- for (const [k, fn] of registry) {
23
- try { out[k] = fn(); } catch (e) { out[k] = { error: String(e && e.message || e) }; }
26
+ for (const [k, fn] of _registry) {
27
+ try { out[k] = fn(); } catch (e) { out[k] = { error: String(e) }; }
24
28
  }
25
29
  return out;
26
30
  }
27
-
28
- function expose() {
29
- if (typeof window === 'undefined') return;
30
- const existing = (window.__debug && typeof window.__debug === 'object') ? window.__debug : {};
31
- Object.assign(existing, { list, snapshot, snapshotAll, register, unregister });
32
- try {
33
- Object.defineProperty(window, '__debug', { value: existing, configurable: true, writable: true });
34
- } catch {
35
- try { window.__debug = existing; } catch {}
36
- }
37
- }
38
-
39
- expose();
package/src/deck-stage.js CHANGED
@@ -1,13 +1,17 @@
1
- // Lazy registration: <deck-stage> requires HTMLElement / customElements,
2
- // which only exist in the browser. Calling registerDeckStage() in a
3
- // browser context performs the side-effect import and defines the element.
1
+ // deck-stage lazy registration. Consumer calls registerDeckStage() in a
2
+ // browser context; we side-effect import the upstream slides/deck-stage.js
3
+ // (the starter-component web component that handles scaling + nav).
4
+
4
5
  let _registered = false;
5
6
  export async function registerDeckStage() {
6
- if (_registered) return customElements.get('deck-stage');
7
- if (typeof customElements === 'undefined' || typeof HTMLElement === 'undefined') {
7
+ if (_registered) return (typeof customElements !== 'undefined') ? customElements.get('deck-stage') : null;
8
+ if (typeof customElements === 'undefined' || typeof HTMLElement === 'undefined') return null;
9
+ try {
10
+ await import('../slides/deck-stage.js');
11
+ } catch (err) {
12
+ console.warn('[247420] deck-stage import failed:', err);
8
13
  return null;
9
14
  }
10
- await import('../slides/deck-stage.js');
11
15
  _registered = true;
12
16
  return customElements.get('deck-stage');
13
17
  }
package/src/highlight.js CHANGED
@@ -1,18 +1,32 @@
1
- import { register } from './debug.js';
1
+ // Syntax highlighting lazy-loads Prism on first call. No-op safe.
2
2
 
3
- let _stats = { highlights: 0 };
3
+ let _prism = null;
4
+ let _ready = null;
4
5
 
5
- export function ensurePrism() {
6
- return Promise.resolve(null);
7
- }
6
+ const PRISM_CORE = 'https://cdn.jsdelivr.net/npm/prismjs@1.30.0/components/prism-core.min.js';
8
7
 
9
- export async function highlightElement(el) {
10
- _stats.highlights += 1;
8
+ export async function ensurePrism() {
9
+ if (_prism) return _prism;
10
+ if (_ready) return _ready;
11
+ _ready = (async () => {
12
+ try {
13
+ // Prism is UMD; fetch & exec on the global.
14
+ const res = await fetch(PRISM_CORE);
15
+ const code = await res.text();
16
+ // eslint-disable-next-line no-new-func
17
+ new Function('window', code)(window);
18
+ _prism = window.Prism || null;
19
+ return _prism;
20
+ } catch (err) {
21
+ console.warn('[247420] prism loader failed:', err);
22
+ return null;
23
+ }
24
+ })();
25
+ return _ready;
11
26
  }
12
27
 
13
28
  export async function highlightAllUnder(root) {
14
- const els = (root || document).querySelectorAll('pre code[class*="lang-"], pre code[class*="language-"]');
15
- _stats.highlights += els.length;
29
+ const Prism = await ensurePrism();
30
+ if (!Prism || !root) return;
31
+ if (typeof Prism.highlightAllUnder === 'function') Prism.highlightAllUnder(root);
16
32
  }
17
-
18
- register('highlight', () => ({ loaded: false, ...(_stats) }));
package/src/index.js CHANGED
@@ -1,3 +1,7 @@
1
+ // 247420 design system — main entry.
2
+ // Drop-in replacement: same export surface as the published SDK.
3
+ // import { mount, components as C, h, applyDiff, scope } from 'anentrypoint-design';
4
+
1
5
  import * as webjsx from '../vendor/webjsx/index.js';
2
6
  import { loadCss, scope } from './styles.js';
3
7
  import { registerDeckStage, getDeckStage } from './deck-stage.js';
@@ -13,20 +17,29 @@ import { registerChatElement } from './web-components/ds-chat.js';
13
17
  let _installed = false;
14
18
  export async function installStyles(target) {
15
19
  if (_installed && !target) return;
20
+ if (typeof document === 'undefined') return;
16
21
  const css = await loadCss();
17
22
  const root = target || document.head;
23
+ if (!target && document.querySelector('style[data-247420]')) { _installed = true; return; }
18
24
  const tag = document.createElement('style');
19
25
  tag.setAttribute('data-247420', '');
20
26
  tag.textContent = css;
21
27
  root.appendChild(tag);
22
- if (!target) motion.installMotion();
23
- if (!target) _installed = true;
28
+ if (!target) {
29
+ motion.installMotion();
30
+ _installed = true;
31
+ }
24
32
  }
25
33
 
26
34
  export function mount(rootEl, viewFn, { autoScope = true } = {}) {
27
- if (autoScope && rootEl && rootEl.classList && !rootEl.classList.contains(scope.slice(1))) {
35
+ if (!rootEl) throw new Error('mount: rootEl required');
36
+ if (typeof viewFn !== 'function') throw new Error('mount: viewFn required');
37
+ if (autoScope && rootEl.classList && !rootEl.classList.contains(scope.slice(1))) {
28
38
  rootEl.classList.add(scope.slice(1));
29
39
  }
40
+ // Auto-inject styles (idempotent) so single-line consumers don't need
41
+ // to remember installStyles() before mount.
42
+ installStyles().catch(() => {});
30
43
  const render = () => {
31
44
  webjsx.applyDiff(rootEl, viewFn(render));
32
45
  requestAnimationFrame(() => motion.animateTree(rootEl));
@@ -35,12 +48,14 @@ export function mount(rootEl, viewFn, { autoScope = true } = {}) {
35
48
  return render;
36
49
  }
37
50
 
51
+ // Side-effect: register <ds-chat> as soon as the SDK loads in a browser.
38
52
  if (typeof window !== 'undefined' && typeof customElements !== 'undefined') {
39
53
  registerChatElement();
40
54
  }
41
55
 
42
56
  export {
43
- webjsx, loadCss, scope, registerDeckStage, getDeckStage,
57
+ webjsx, loadCss, scope,
58
+ registerDeckStage, getDeckStage,
44
59
  components, motion, debug, mountKit,
45
60
  renderMarkdown, ensureMarkdownReady,
46
61
  ensurePrism, highlightAllUnder,
@@ -49,7 +64,16 @@ export {
49
64
  };
50
65
  export const h = webjsx.createElement;
51
66
  export const applyDiff = webjsx.applyDiff;
52
- export { FREDDIE_PAGES, home, chat, sessions, projects, agents, analytics, models, cron, skills, config, env, tools, batch, gateway, chains, skillLabel, getRecentPaths, saveRecentPath, renderChatMessages } from './components.js';
67
+
68
+ // Re-export freddie helpers so consumers can `import { FREDDIE_PAGES } from
69
+ // 'anentrypoint-design'` directly.
70
+ export {
71
+ FREDDIE_PAGES,
72
+ home, chat, voice, sessions, projects, agents, analytics,
73
+ models, cron, skills, config, env, tools, batch, gateway, chains,
74
+ skillLabel, getRecentPaths, saveRecentPath, renderChatMessages
75
+ } from './components.js';
76
+
53
77
  export default {
54
78
  webjsx, loadCss, scope, installStyles, mount, h, applyDiff,
55
79
  registerDeckStage, getDeckStage, components, motion, debug, mountKit,
@@ -1,4 +1,4 @@
1
- import * as webjsx from '../../../vendor/webjsx/index.js';
1
+ import * as webjsx from '../../../../vendor/webjsx/index.js';
2
2
  const h = webjsx.createElement;
3
3
 
4
4
  export function pre(obj) {
@@ -1,6 +1,6 @@
1
1
  // Chat page — its own module because of SSE plumbing weight.
2
- import * as webjsx from '../../../vendor/webjsx/index.js';
3
- import * as components from '../../components.js';
2
+ import * as webjsx from '../../../../vendor/webjsx/index.js';
3
+ import * as components from '../../../components.js';
4
4
  import { getRecentPaths, saveRecentPath, skillLabel, renderChatMessages } from './helpers.js';
5
5
 
6
6
  const h = webjsx.createElement;
@@ -1,6 +1,6 @@
1
1
  // Core freddie pages: projects, home, sessions, agents, logs.
2
- import * as webjsx from '../../../vendor/webjsx/index.js';
3
- import * as components from '../../components.js';
2
+ import * as webjsx from '../../../../vendor/webjsx/index.js';
3
+ import * as components from '../../../components.js';
4
4
  import { pre, form, skillLabel } from './helpers.js';
5
5
 
6
6
  const h = webjsx.createElement;
@@ -1,5 +1,5 @@
1
1
  // OS-overlay freddie pages, only mounted when osSurfaces is provided.
2
- import * as components from '../../components.js';
2
+ import * as components from '../../../components.js';
3
3
  import { pre } from './helpers.js';
4
4
 
5
5
  const { Panel, Kpi, Table, EmptyState } = components;
@@ -1,6 +1,6 @@
1
1
  // Tools-ish freddie pages: analytics, models, cron, skills, config, env, tools, batch, gateway.
2
- import * as webjsx from '../../../vendor/webjsx/index.js';
3
- import * as components from '../../components.js';
2
+ import * as webjsx from '../../../../vendor/webjsx/index.js';
3
+ import * as components from '../../../components.js';
4
4
  import { pre, form, skillLabel } from './helpers.js';
5
5
 
6
6
  const h = webjsx.createElement;
@@ -1,5 +1,5 @@
1
- import * as webjsx from '../../vendor/webjsx/index.js';
2
- import * as components from '../components.js';
1
+ import * as webjsx from '../../../vendor/webjsx/index.js';
2
+ import * as components from '../../components.js';
3
3
  import { ROUTES, OS_ROUTE_DEFS } from './freddie/routes.js';
4
4
  import { makeCorePages } from './freddie/pages-core.js';
5
5
  import { makeChatPage } from './freddie/pages-chat.js';
package/src/markdown.js CHANGED
@@ -1,61 +1,39 @@
1
- import { register } from './debug.js';
1
+ // Markdown lazy-loads marked + DOMPurify on first call. Stub-safe:
2
+ // if loading fails, we fall back to a simple escape-and-linebreak pass so
3
+ // the chat doesn't go blank.
2
4
 
5
+ let _ready = null;
3
6
  let _marked = null;
4
7
  let _purify = null;
5
- let _stats = { renders: 0, sanitizedTags: 0 };
6
-
7
- async function loadMarked() {
8
- if (_marked) return _marked;
9
- const mod = await import('https://cdn.jsdelivr.net/npm/marked@15.0.7/lib/marked.esm.js');
10
- _marked = mod.marked;
11
- _marked.setOptions({ breaks: true, gfm: true });
12
- return _marked;
13
- }
14
8
 
15
- async function loadPurify() {
16
- if (_purify) return _purify;
17
- const mod = await import('https://cdn.jsdelivr.net/npm/dompurify@3.4.1/+esm');
18
- _purify = mod.default || mod;
19
- if (!_purify.sanitize) throw new Error('dompurify did not load a sanitize fn');
20
- _purify.addHook('uponSanitizeElement', (node, data) => {
21
- if (data.tagName && data.allowedTags && !data.allowedTags[data.tagName]) _stats.sanitizedTags += 1;
22
- });
23
- return _purify;
24
- }
9
+ const MARKED_URL = 'https://cdn.jsdelivr.net/npm/marked@15/+esm';
10
+ const PURIFY_URL = 'https://cdn.jsdelivr.net/npm/dompurify@3/+esm';
25
11
 
26
- let _ready = null;
27
- export function ensureReady() {
12
+ export async function ensureReady() {
28
13
  if (_ready) return _ready;
29
- _ready = Promise.all([loadMarked(), loadPurify()]).then(() => true);
14
+ _ready = (async () => {
15
+ try {
16
+ const [{ marked }, DOMPurifyMod] = await Promise.all([import(MARKED_URL), import(PURIFY_URL)]);
17
+ _marked = marked;
18
+ _purify = DOMPurifyMod.default || DOMPurifyMod;
19
+ return true;
20
+ } catch (err) {
21
+ console.warn('[247420] markdown loader failed:', err);
22
+ return false;
23
+ }
24
+ })();
30
25
  return _ready;
31
26
  }
32
27
 
33
- export async function renderMarkdown(text) {
34
- const [marked, purify] = await Promise.all([loadMarked(), loadPurify()]);
35
- const dirty = marked.parse(String(text || ''));
36
- const clean = purify.sanitize(dirty, {
37
- FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'form'],
38
- FORBID_ATTR: ['onerror', 'onclick', 'onload', 'onmouseover'],
39
- ADD_ATTR: ['target', 'rel']
40
- });
41
- _stats.renders += 1;
42
- return clean;
28
+ function escapeHtml(s) {
29
+ return String(s).replace(/[&<>"']/g, (c) => ({
30
+ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;',
31
+ })[c]);
43
32
  }
44
33
 
45
- export function renderMarkdownSync(text) {
46
- if (!_marked || !_purify) return null;
47
- const dirty = _marked.parse(String(text || ''));
48
- const clean = _purify.sanitize(dirty, {
49
- FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'form'],
50
- FORBID_ATTR: ['onerror', 'onclick', 'onload', 'onmouseover'],
51
- ADD_ATTR: ['target', 'rel']
52
- });
53
- _stats.renders += 1;
54
- return clean;
34
+ export async function renderMarkdown(src) {
35
+ const ok = await ensureReady();
36
+ if (!ok) return escapeHtml(src).replace(/\n/g, '<br>');
37
+ const raw = _marked.parse(String(src));
38
+ return _purify.sanitize(raw);
55
39
  }
56
-
57
- register('markdown', () => ({
58
- loaded: { marked: !!_marked, dompurify: !!_purify },
59
- renders: _stats.renders,
60
- sanitizedTags: _stats.sanitizedTags
61
- }));