anentrypoint-design 0.0.121 → 0.0.124

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 (202) hide show
  1. package/README.md +253 -253
  2. package/app-shell.css +931 -594
  3. package/colors_and_type.css +226 -226
  4. package/community.css +817 -1222
  5. package/dist/247420.css +2202 -2084
  6. package/dist/247420.js +13 -13
  7. package/package.json +80 -80
  8. package/src/bootstrap.js +25 -25
  9. package/src/components/chat.js +199 -199
  10. package/src/components/community.js +190 -208
  11. package/src/components/content.js +269 -269
  12. package/src/components/editor-primitives.js +100 -0
  13. package/src/components/files-modals.js +107 -107
  14. package/src/components/files.js +118 -118
  15. package/src/components/freddie/helpers.js +50 -50
  16. package/src/components/freddie.js +33 -33
  17. package/src/components/shell.js +117 -117
  18. package/src/components/theme-toggle.js +70 -70
  19. package/src/components.js +59 -57
  20. package/src/debug.js +30 -30
  21. package/src/deck-stage.js +21 -21
  22. package/src/highlight.js +65 -32
  23. package/src/index.js +86 -86
  24. package/src/kits/os/about-app.js +52 -52
  25. package/src/kits/os/app-panes.css +152 -152
  26. package/src/kits/os/browser-app.js +58 -58
  27. package/src/kits/os/files-app.js +44 -44
  28. package/src/kits/os/freddie/helpers.js +59 -59
  29. package/src/kits/os/freddie/pages-chat.js +143 -143
  30. package/src/kits/os/freddie/pages-core.js +101 -101
  31. package/src/kits/os/freddie/pages-os.js +51 -51
  32. package/src/kits/os/freddie/pages-tools.js +183 -183
  33. package/src/kits/os/freddie/routes.js +24 -24
  34. package/src/kits/os/freddie-dashboard.css +51 -51
  35. package/src/kits/os/freddie-dashboard.js +101 -101
  36. package/src/kits/os/icons.js +17 -17
  37. package/src/kits/os/index.js +17 -17
  38. package/src/kits/os/launcher.css +61 -61
  39. package/src/kits/os/launcher.js +79 -79
  40. package/src/kits/os/monitor-app.js +34 -34
  41. package/src/kits/os/shell.js +214 -214
  42. package/src/kits/os/terminal-app.js +45 -45
  43. package/src/kits/os/theme.css +450 -450
  44. package/src/kits/os/validate.css +19 -19
  45. package/src/kits/os/validator-app.js +55 -55
  46. package/src/kits/os/wm.css +115 -115
  47. package/src/kits/os/wm.js +111 -111
  48. package/src/markdown.js +39 -39
  49. package/src/motion.js +35 -35
  50. package/src/page-html.js +196 -196
  51. package/src/styles.js +25 -25
  52. package/src/theme.js +99 -99
  53. package/src/web-components/ds-chat.js +116 -116
  54. package/dist/.nojekyll +0 -0
  55. package/dist/app-shell.css +0 -594
  56. package/dist/colors_and_type.css +0 -197
  57. package/dist/favicon.svg +0 -1
  58. package/dist/index.html +0 -308
  59. package/dist/preview/buttons.html +0 -28
  60. package/dist/preview/colors-core.html +0 -45
  61. package/dist/preview/colors-lore.html +0 -28
  62. package/dist/preview/colors-semantic.html +0 -34
  63. package/dist/preview/dateline.html +0 -19
  64. package/dist/preview/dropzone.html +0 -30
  65. package/dist/preview/file-grid.html +0 -19
  66. package/dist/preview/file-row.html +0 -20
  67. package/dist/preview/file-toolbar.html +0 -40
  68. package/dist/preview/file-viewer.html +0 -31
  69. package/dist/preview/header.html +0 -24
  70. package/dist/preview/icons-unicode.html +0 -26
  71. package/dist/preview/index-row.html +0 -25
  72. package/dist/preview/inputs.html +0 -22
  73. package/dist/preview/manifesto.html +0 -52
  74. package/dist/preview/motion-default.js +0 -106
  75. package/dist/preview/rules.html +0 -16
  76. package/dist/preview/spacing.html +0 -18
  77. package/dist/preview/stamps-lore.html +0 -20
  78. package/dist/preview/stamps.html +0 -14
  79. package/dist/preview/theme-ink.html +0 -15
  80. package/dist/preview/type-display.html +0 -16
  81. package/dist/preview/type-mono.html +0 -15
  82. package/dist/preview/type-prose.html +0 -11
  83. package/dist/preview/type-scale.html +0 -20
  84. package/dist/preview/wordmarks.html +0 -28
  85. package/dist/robots.txt +0 -8
  86. package/dist/site/content/globals/navigation.yaml +0 -5
  87. package/dist/site/content/globals/site.yaml +0 -16
  88. package/dist/site/content/pages/freddie.yaml +0 -88
  89. package/dist/site/content/pages/home.yaml +0 -190
  90. package/dist/site/theme.mjs +0 -368
  91. package/dist/sitemap.xml +0 -31
  92. package/dist/slides/deck-stage-overlay.js +0 -63
  93. package/dist/slides/deck-stage-state.js +0 -81
  94. package/dist/slides/deck-stage-style.js +0 -117
  95. package/dist/slides/deck-stage.js +0 -159
  96. package/dist/slides/index.html +0 -276
  97. package/dist/src/bootstrap.js +0 -25
  98. package/dist/src/components/chat.js +0 -199
  99. package/dist/src/components/community.js +0 -167
  100. package/dist/src/components/content.js +0 -213
  101. package/dist/src/components/files-modals.js +0 -107
  102. package/dist/src/components/files.js +0 -118
  103. package/dist/src/components/freddie/helpers.js +0 -50
  104. package/dist/src/components/freddie.js +0 -33
  105. package/dist/src/components/shell.js +0 -117
  106. package/dist/src/components/theme-toggle.js +0 -70
  107. package/dist/src/components.js +0 -52
  108. package/dist/src/debug.js +0 -30
  109. package/dist/src/deck-stage.js +0 -21
  110. package/dist/src/highlight.js +0 -32
  111. package/dist/src/index.js +0 -86
  112. package/dist/src/kits/os/about-app.js +0 -52
  113. package/dist/src/kits/os/app-panes.css +0 -152
  114. package/dist/src/kits/os/browser-app.js +0 -58
  115. package/dist/src/kits/os/files-app.js +0 -44
  116. package/dist/src/kits/os/freddie/helpers.js +0 -59
  117. package/dist/src/kits/os/freddie/pages-chat.js +0 -143
  118. package/dist/src/kits/os/freddie/pages-core.js +0 -101
  119. package/dist/src/kits/os/freddie/pages-os.js +0 -51
  120. package/dist/src/kits/os/freddie/pages-tools.js +0 -183
  121. package/dist/src/kits/os/freddie/routes.js +0 -24
  122. package/dist/src/kits/os/freddie-dashboard.css +0 -51
  123. package/dist/src/kits/os/freddie-dashboard.js +0 -101
  124. package/dist/src/kits/os/icons.js +0 -17
  125. package/dist/src/kits/os/index.js +0 -5
  126. package/dist/src/kits/os/launcher.css +0 -61
  127. package/dist/src/kits/os/launcher.js +0 -79
  128. package/dist/src/kits/os/monitor-app.js +0 -34
  129. package/dist/src/kits/os/shell.js +0 -214
  130. package/dist/src/kits/os/terminal-app.js +0 -45
  131. package/dist/src/kits/os/theme.css +0 -412
  132. package/dist/src/kits/os/validate.css +0 -19
  133. package/dist/src/kits/os/validator-app.js +0 -55
  134. package/dist/src/kits/os/wm.css +0 -115
  135. package/dist/src/kits/os/wm.js +0 -111
  136. package/dist/src/markdown.js +0 -39
  137. package/dist/src/motion.js +0 -35
  138. package/dist/src/page-html.js +0 -196
  139. package/dist/src/styles.js +0 -25
  140. package/dist/src/theme.js +0 -99
  141. package/dist/src/web-components/ds-chat.js +0 -45
  142. package/dist/ui_kits/aicat/README.md +0 -7
  143. package/dist/ui_kits/aicat/app.js +0 -156
  144. package/dist/ui_kits/aicat/index.html +0 -26
  145. package/dist/ui_kits/aicat/sample-square.png +0 -0
  146. package/dist/ui_kits/aicat/sample-svg.svg +0 -1
  147. package/dist/ui_kits/aicat/sample.pdf +0 -32
  148. package/dist/ui_kits/blog/README.md +0 -3
  149. package/dist/ui_kits/blog/index.html +0 -90
  150. package/dist/ui_kits/chat/README.md +0 -5
  151. package/dist/ui_kits/chat/app.js +0 -110
  152. package/dist/ui_kits/chat/index.html +0 -26
  153. package/dist/ui_kits/chat/sample-square.png +0 -0
  154. package/dist/ui_kits/chat/sample-svg.svg +0 -1
  155. package/dist/ui_kits/chat/sample.pdf +0 -32
  156. package/dist/ui_kits/community/app.js +0 -134
  157. package/dist/ui_kits/community/index.html +0 -24
  158. package/dist/ui_kits/dashboard/app.js +0 -92
  159. package/dist/ui_kits/dashboard/index.html +0 -26
  160. package/dist/ui_kits/docs/README.md +0 -3
  161. package/dist/ui_kits/docs/index.html +0 -123
  162. package/dist/ui_kits/error_404/app.js +0 -56
  163. package/dist/ui_kits/error_404/index.html +0 -26
  164. package/dist/ui_kits/file_browser/README.md +0 -48
  165. package/dist/ui_kits/file_browser/app.js +0 -231
  166. package/dist/ui_kits/file_browser/index.html +0 -33
  167. package/dist/ui_kits/gallery/app.js +0 -121
  168. package/dist/ui_kits/gallery/index.html +0 -26
  169. package/dist/ui_kits/homepage/README.md +0 -7
  170. package/dist/ui_kits/homepage/app.js +0 -167
  171. package/dist/ui_kits/homepage/index.html +0 -46
  172. package/dist/ui_kits/project_page/README.md +0 -3
  173. package/dist/ui_kits/project_page/app.js +0 -154
  174. package/dist/ui_kits/project_page/index.html +0 -45
  175. package/dist/ui_kits/search/app.js +0 -107
  176. package/dist/ui_kits/search/index.html +0 -26
  177. package/dist/ui_kits/settings/app.js +0 -133
  178. package/dist/ui_kits/settings/index.html +0 -26
  179. package/dist/ui_kits/signin/app.js +0 -115
  180. package/dist/ui_kits/signin/index.html +0 -26
  181. package/dist/ui_kits/slide_deck/app.js +0 -174
  182. package/dist/ui_kits/slide_deck/index.html +0 -26
  183. package/dist/ui_kits/system_primer/app.js +0 -152
  184. package/dist/ui_kits/system_primer/index.html +0 -26
  185. package/dist/ui_kits/terminal/app.js +0 -150
  186. package/dist/ui_kits/terminal/index.html +0 -26
  187. package/dist/vendor/webjsx/applyDiff.js +0 -182
  188. package/dist/vendor/webjsx/attributes.js +0 -154
  189. package/dist/vendor/webjsx/constants.js +0 -4
  190. package/dist/vendor/webjsx/createDOMElement.js +0 -52
  191. package/dist/vendor/webjsx/createElement.js +0 -75
  192. package/dist/vendor/webjsx/elementTags.js +0 -115
  193. package/dist/vendor/webjsx/factory.js +0 -6
  194. package/dist/vendor/webjsx/index.js +0 -6
  195. package/dist/vendor/webjsx/jsx-dev-runtime.js +0 -2
  196. package/dist/vendor/webjsx/jsx-runtime.js +0 -30
  197. package/dist/vendor/webjsx/jsx.js +0 -2
  198. package/dist/vendor/webjsx/package.json +0 -39
  199. package/dist/vendor/webjsx/renderSuspension.js +0 -25
  200. package/dist/vendor/webjsx/types.js +0 -5
  201. package/dist/vendor/webjsx/utils.js +0 -84
  202. package/src/components/overlays.js +0 -151
@@ -1,58 +0,0 @@
1
- // Browser-pane paint surface — URL bar + iframe slot + status row. Consumer owns iframe.
2
- // renderBrowserPane({initialUrl, callbacks: {onNavigate, onReload, onBack, onForward}})
3
- // -> {node, slot, setUrl, setStatus, dispose}.
4
- // slot is the container the consumer should append its iframe to.
5
-
6
- export function renderBrowserPane(opts = {}) {
7
- const { initialUrl = 'about:blank', callbacks = {} } = opts;
8
- const node = document.createElement('div');
9
- node.className = 'app-pane browser-app';
10
- node.dataset.component = 'browser-app';
11
-
12
- const bar = document.createElement('div');
13
- bar.className = 'browser-app-bar';
14
-
15
- const mkBtn = (label, role) => {
16
- const b = document.createElement('button');
17
- b.type = 'button';
18
- b.className = 'browser-app-btn';
19
- b.dataset.role = role;
20
- b.textContent = label;
21
- return b;
22
- };
23
- const backBtn = mkBtn('<', 'back');
24
- const fwdBtn = mkBtn('>', 'forward');
25
- const reloadBtn = mkBtn('reload', 'reload');
26
-
27
- const urlInput = document.createElement('input');
28
- urlInput.type = 'text';
29
- urlInput.className = 'browser-app-url';
30
- urlInput.value = initialUrl;
31
- urlInput.spellcheck = false;
32
- urlInput.addEventListener('keydown', (e) => {
33
- if (e.key === 'Enter' && callbacks.onNavigate) callbacks.onNavigate(urlInput.value);
34
- });
35
- backBtn.addEventListener('click', () => callbacks.onBack && callbacks.onBack());
36
- fwdBtn.addEventListener('click', () => callbacks.onForward && callbacks.onForward());
37
- reloadBtn.addEventListener('click', () => callbacks.onReload && callbacks.onReload());
38
-
39
- bar.append(backBtn, fwdBtn, reloadBtn, urlInput);
40
-
41
- const slot = document.createElement('div');
42
- slot.className = 'browser-app-slot';
43
- slot.dataset.role = 'iframe-mount';
44
-
45
- const status = document.createElement('div');
46
- status.className = 'browser-app-status';
47
- status.textContent = '';
48
-
49
- node.append(bar, slot, status);
50
-
51
- return {
52
- node,
53
- get slot() { return slot; },
54
- setUrl(u) { urlInput.value = u; },
55
- setStatus(s) { status.textContent = s; },
56
- dispose() {},
57
- };
58
- }
@@ -1,44 +0,0 @@
1
- // Files-app paint surface — bible classes, pure DOM. Consumer provides callbacks.
2
- // renderFilesApp({list, readFile}) -> {node, refresh, dispose}.
3
- // list() -> Promise<string[]>; readFile(path) -> Promise<string|Uint8Array>.
4
- // Header text comes from {label} (consumer assembles "<id> — N files").
5
-
6
- export function renderFilesApp(opts = {}) {
7
- const { list, readFile, label = '', pollMs = 2000 } = opts;
8
- const node = document.createElement('div');
9
- node.className = 'app-pane mono';
10
- node.dataset.component = 'files-app';
11
-
12
- let preview = null;
13
- async function refresh() {
14
- const items = await list();
15
- node.innerHTML = '';
16
- const head = document.createElement('div');
17
- head.className = 'head';
18
- head.textContent = (label ? label + ' — ' : '') + items.length + ' files';
19
- node.appendChild(head);
20
- for (const p of items) {
21
- const row = document.createElement('div');
22
- row.className = 'row';
23
- row.textContent = p;
24
- row.addEventListener('click', async () => {
25
- const body = await readFile(p);
26
- if (preview) preview.remove();
27
- preview = document.createElement('pre');
28
- preview.textContent = String(body);
29
- node.appendChild(preview);
30
- });
31
- node.appendChild(row);
32
- }
33
- }
34
-
35
- let timer = null;
36
- refresh().catch(() => {});
37
- if (pollMs > 0) timer = setInterval(() => refresh().catch(() => {}), pollMs);
38
-
39
- return {
40
- node,
41
- refresh,
42
- dispose() { if (timer) clearInterval(timer); },
43
- };
44
- }
@@ -1,59 +0,0 @@
1
- import * as webjsx from '../../../../vendor/webjsx/index.js';
2
- const h = webjsx.createElement;
3
-
4
- export function pre(obj) {
5
- return h('pre', { class: 'fd-pre' }, typeof obj === 'string' ? obj : JSON.stringify(obj, null, 2));
6
- }
7
-
8
- export function form(opts) {
9
- const { fields = [], submit = 'submit', onSubmit } = opts;
10
- return h('form', { class: 'row-form', onsubmit: (ev) => { ev.preventDefault(); onSubmit && onSubmit(ev); } },
11
- ...fields.map(f => f.kind === 'textarea'
12
- ? h('textarea', { name: f.name, placeholder: f.placeholder || '', rows: f.rows || 4 })
13
- : h('input', { name: f.name, type: f.type || 'text', placeholder: f.placeholder || '', value: f.value || '', required: f.required ? 'true' : null })),
14
- h('button', { type: 'submit', class: 'btn-primary' }, submit));
15
- }
16
-
17
- export function getRecentPaths() {
18
- try { return JSON.parse(localStorage.getItem('fd_recent_cwds') || '[]'); } catch { return []; }
19
- }
20
-
21
- export function saveRecentPath(p) {
22
- if (!p) return;
23
- try {
24
- const prev = getRecentPaths().filter(x => x !== p);
25
- localStorage.setItem('fd_recent_cwds', JSON.stringify([p, ...prev].slice(0, 5)));
26
- } catch {}
27
- }
28
-
29
- export function skillLabel(s) {
30
- if (s.shortName) return s.shortName;
31
- const n = s.name || '';
32
- return n.replace(/^gm:/, '').replace(/^software-development$/, 'software dev').replace(/-/g, ' ');
33
- }
34
-
35
- export function renderChatMessages(container, messages) {
36
- if (!container) return;
37
- container.innerHTML = '';
38
- for (const m of messages) {
39
- if (m.role === 'tool') {
40
- const det = document.createElement('details');
41
- det.className = 'fd-chatlog-tool';
42
- const sum = document.createElement('summary');
43
- sum.className = 'fd-chatlog-tool-sum';
44
- sum.textContent = '⚒ ' + m.name + (m.argsSummary ? ' ' + m.argsSummary : '');
45
- det.appendChild(sum);
46
- const body = document.createElement('pre');
47
- body.className = 'fd-chatlog-tool-body';
48
- body.textContent = m.content || '';
49
- det.appendChild(body);
50
- container.appendChild(det);
51
- } else {
52
- const el = document.createElement('div');
53
- el.className = 'fd-chatlog-msg fd-chatlog-' + (m.role === 'assistant' ? 'assistant' : 'user');
54
- el.textContent = (m.role === 'assistant' ? '◈ ' : '▷ ') + (m.content || '');
55
- container.appendChild(el);
56
- }
57
- }
58
- container.scrollTop = container.scrollHeight;
59
- }
@@ -1,143 +0,0 @@
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';
4
- import { getRecentPaths, saveRecentPath, skillLabel, renderChatMessages } from './helpers.js';
5
-
6
- const h = webjsx.createElement;
7
- const { Panel, Receipt, Chip } = components;
8
-
9
- function parseSseEvents(text) {
10
- const events = [];
11
- let curEvent = null, curData = '';
12
- for (const line of text.split('\n')) {
13
- if (line.startsWith('event: ')) { curEvent = line.slice(7).trim(); }
14
- else if (line.startsWith('data: ')) { curData = line.slice(6).trim(); }
15
- else if (line === '' && curEvent) {
16
- try { events.push({ event: curEvent, data: JSON.parse(curData) }); } catch {}
17
- curEvent = null; curData = '';
18
- }
19
- }
20
- return events;
21
- }
22
-
23
- export function makeChatPage(ctx) {
24
- return async function chat(h0) {
25
- const root = ctx.root;
26
- const skills = [...h0.pi.skills.values()];
27
- const providers = await fetch('/api/providers').then(r => r.json()).catch(() => []);
28
- const configuredProviders = providers.filter(p => p.configured);
29
-
30
- const chatState = window.__fd_chatState = window.__fd_chatState || {
31
- cwd: '', skill: '', provider: '', model: '', messages: [], busy: false, sessionId: null,
32
- };
33
- if (!chatState.cwd) chatState.cwd = (getRecentPaths()[0] || '');
34
-
35
- const getMsgsContainer = () => root.querySelector('#fd-chat-msgs');
36
-
37
- const newSession = () => {
38
- if (chatState.busy) return;
39
- chatState.messages = [];
40
- chatState.sessionId = null;
41
- renderChatMessages(getMsgsContainer(), chatState.messages);
42
- };
43
-
44
- const sendChat = async (ev) => {
45
- ev.preventDefault();
46
- if (chatState.busy) return;
47
- const promptEl = ev.target.elements.prompt;
48
- const prompt = promptEl.value.trim();
49
- if (!prompt) return;
50
- chatState.messages.push({ role: 'user', content: prompt });
51
- promptEl.value = '';
52
- promptEl.style.height = 'auto';
53
- chatState.busy = true;
54
- saveRecentPath(chatState.cwd);
55
- renderChatMessages(getMsgsContainer(), chatState.messages);
56
- try {
57
- const body = { prompt, cwd: chatState.cwd || undefined, skill: chatState.skill || undefined, provider: chatState.provider || undefined, model: chatState.model || undefined, sessionId: chatState.sessionId || undefined };
58
- const resp = await fetch('/api/chat', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) });
59
- const text = await resp.text();
60
- const events = parseSseEvents(text);
61
- let assistantContent = '';
62
- for (const { event, data } of events) {
63
- if (event === 'start' && data.sessionId) chatState.sessionId = data.sessionId;
64
- if (event === 'done' && data.sessionId) chatState.sessionId = data.sessionId;
65
- if (event === 'message') {
66
- const role = data.role;
67
- if (role === 'assistant') {
68
- const content = Array.isArray(data.content) ? data.content : [{ type: 'text', text: String(data.content || '') }];
69
- for (const block of content) {
70
- if (block.type === 'text') assistantContent += block.text;
71
- if (block.type === 'tool_use') {
72
- if (assistantContent) { chatState.messages.push({ role: 'assistant', content: assistantContent }); assistantContent = ''; }
73
- const argsSummary = JSON.stringify(block.input || {}).slice(0, 60);
74
- chatState.messages.push({ role: 'tool', name: block.name, argsSummary, content: JSON.stringify(block.input || {}, null, 2) });
75
- }
76
- }
77
- } else if (role === 'tool') {
78
- const tc = Array.isArray(data.content) ? data.content[0] : data;
79
- chatState.messages.push({ role: 'tool', name: 'result', argsSummary: '', content: String(tc?.content || tc?.text || JSON.stringify(tc)) });
80
- }
81
- }
82
- if (event === 'done' && data.result) { if (!assistantContent) assistantContent = data.result; }
83
- if (event === 'error') assistantContent = 'error: ' + (data.error || 'unknown');
84
- }
85
- if (assistantContent) chatState.messages.push({ role: 'assistant', content: assistantContent });
86
- if (!events.length) chatState.messages.push({ role: 'assistant', content: '(no response)' });
87
- } catch (e) {
88
- chatState.messages.push({ role: 'assistant', content: 'error: ' + e.message });
89
- }
90
- chatState.busy = false;
91
- renderChatMessages(getMsgsContainer(), chatState.messages);
92
- };
93
-
94
- const recentPaths = getRecentPaths();
95
- const datalistId = 'fd-cwd-list';
96
- const byCat = skills.reduce((a, s) => { const c = s.category || 'other'; (a[c] = a[c] || []).push(s); return a; }, {});
97
-
98
- setTimeout(() => renderChatMessages(getMsgsContainer(), chatState.messages), 50);
99
-
100
- const selSkill = h('select', { name: 'skill', onchange: (ev) => { chatState.skill = ev.target.value; } },
101
- h('option', { value: '' }, '— no skill —'),
102
- ...Object.entries(byCat).map(([cat, ss]) =>
103
- h('optgroup', { label: cat },
104
- ...ss.map(s => h('option', { value: s.name, selected: chatState.skill === s.name ? 'true' : null, title: s.description || s.name }, skillLabel(s)))
105
- )));
106
-
107
- const selProv = h('select', { name: 'provider', onchange: (ev) => { chatState.provider = ev.target.value; } },
108
- h('option', { value: '' }, configuredProviders.length ? '— auto —' : '— no providers configured —'),
109
- ...configuredProviders.map(p => h('option', { value: p.name, selected: chatState.provider === p.name ? 'true' : null }, (p.available ? '● ' : '○ ') + p.name)));
110
-
111
- return [
112
- Panel({
113
- title: 'chat',
114
- right: h('button', { class: 'btn-primary fd-btn-mini', onclick: (ev) => { ev.preventDefault(); newSession(); }, disabled: chatState.busy ? 'true' : null }, '+ new session'),
115
- children: [
116
- h('datalist', { id: datalistId }, ...recentPaths.map(p => h('option', { value: p }))),
117
- h('form', { class: 'row-form fd-chat-form', onsubmit: sendChat },
118
- h('div', { class: 'fd-chat-field' },
119
- h('label', {}, 'working directory'),
120
- h('input', { name: 'cwd', type: 'text', placeholder: 'e.g. C:/dev/myproject or /home/user/project', value: chatState.cwd, list: datalistId, oninput: (ev) => { chatState.cwd = ev.target.value; } })),
121
- h('div', { class: 'fd-chat-row' },
122
- h('div', { class: 'fd-chat-field fd-chat-field-grow' }, h('label', {}, 'skill'), selSkill),
123
- h('div', { class: 'fd-chat-field fd-chat-field-grow' }, h('label', {}, 'provider'), selProv),
124
- h('div', { class: 'fd-chat-field fd-chat-field-grow' }, h('label', {}, 'model (optional)'),
125
- h('input', { name: 'model', type: 'text', placeholder: configuredProviders.find(p => p.name === chatState.provider)?.defaultModel || 'default', value: chatState.model, oninput: (ev) => { chatState.model = ev.target.value; } }))),
126
- h('div', { class: 'fd-chat-submit' },
127
- h('textarea', { name: 'prompt', placeholder: 'describe what you want to do in the working directory…', rows: 4,
128
- oninput: (ev) => { ev.target.style.height = 'auto'; ev.target.style.height = Math.min(ev.target.scrollHeight, 240) + 'px'; } }),
129
- h('button', { type: 'submit', class: 'btn-primary', disabled: chatState.busy ? 'true' : null }, chatState.busy ? '…' : 'send'))),
130
- h('div', { id: 'fd-chat-msgs', class: 'fd-chatlog' }),
131
- ],
132
- }),
133
- configuredProviders.length === 0
134
- ? Panel({ title: 'no providers configured', children: Receipt({ rows: [
135
- ['set API key', 'go to keys tab, click a provider chip to set its key'],
136
- ['then reload', 'refresh this page to see providers here'],
137
- ['or use acptoapi', 'run acptoapi server on localhost:4800 for local LLMs'],
138
- ] }) })
139
- : Panel({ title: 'configured providers', children: h('div', { class: 'fd-chip-wrap' },
140
- ...providers.map(p => Chip({ tone: p.configured ? (p.available ? 'ok' : 'warn') : 'miss', children: p.name + (p.configured ? (p.available ? ' ●' : ' ○') : '') }))) }),
141
- ];
142
- };
143
- }
@@ -1,101 +0,0 @@
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';
4
- import { pre, form, skillLabel } from './helpers.js';
5
-
6
- const h = webjsx.createElement;
7
- const { Panel, Row, Hero, Receipt, Kpi, Table, EmptyState } = components;
8
-
9
- export function makeCorePages(ctx) {
10
- return {
11
- async projects(h0) {
12
- const list = h0.pi.projects.list();
13
- const activeProj = (typeof h0.pi.projects.active === 'function') ? h0.pi.projects.active() : null;
14
- const rows = list.map(p => Row({
15
- key: p.name,
16
- code: p.name === activeProj?.name ? '●' : '○',
17
- title: p.name + (p.name === activeProj?.name ? ' (active)' : ''),
18
- meta: p.path,
19
- onClick: () => { if (p.name !== activeProj?.name) try { h0.pi.projects.setActive(p.name); ctx.rerender(); } catch (e) { alert(e.message); } },
20
- }));
21
- return [
22
- Hero({ title: 'projects', body: 'each project is its own ~/.freddie home: separate sessions, agents, skills, config, env, cron, batches.', accent: activeProj ? 'active · ' + activeProj.name : 'no active project' }),
23
- Kpi({ items: [[list.length, 'projects'], [activeProj?.name || '—', 'active'], [activeProj?.path?.length > 30 ? '…' + activeProj.path.slice(-28) : (activeProj?.path || '—'), 'path']] }),
24
- Panel({ title: 'add a project', children: form({
25
- fields: [{ name: 'name', placeholder: 'project name', required: true }, { name: 'path', placeholder: '/abs/path' }],
26
- submit: 'add',
27
- onSubmit: (ev) => { try { h0.pi.projects.create({ name: ev.target.elements.name.value, path: ev.target.elements.path.value }); ctx.rerender(); } catch (e) { alert(e.message); } },
28
- }) }),
29
- Panel({ title: 'all projects', count: list.length, children: rows.length ? rows : EmptyState({ text: 'no projects', glyph: '◆' }) }),
30
- Panel({ title: 'how encapsulation works', children: Receipt({ rows: [
31
- ['sessions db', '<project>/sessions.db'],
32
- ['config', '<project>/config.json'],
33
- ['skills', '<project>/skills/'],
34
- ['plugins', '<project>/plugins/'],
35
- ['cron', '<project>/cron.db'],
36
- ['batches', '<project>/batches/'],
37
- ['logs', '<project>/logs/'],
38
- ['auth', '<project>/auth.json'],
39
- ] }) }),
40
- ];
41
- },
42
- async home(h0) {
43
- const sessions = await h0.pi.sessions.list();
44
- const tools = h0.pi.tools.size;
45
- const skills = h0.pi.skills.size;
46
- const health = (typeof h0.pi.health === 'function') ? h0.pi.health() : { ok: true };
47
- return [
48
- Hero({ title: 'freddie', body: 'open js agent harness — pi-mono · xstate · floosie · anentrypoint-design.', accent: h0.version || 'web' }),
49
- Kpi({ items: [[sessions.length, 'sessions'], [tools, 'tools'], [skills, 'skills']] }),
50
- Panel({ title: 'quick start', children: Receipt({ rows: [
51
- ['open chat', "click 'chat' in sidebar — set a working directory and pick a skill"],
52
- ['pick skill', "software dev, research, planning — shown with descriptions"],
53
- ['pick model', "select a configured provider + model in the chat bar"],
54
- ['list tools', '/tools in chat → tools tab'],
55
- ['set api key', 'keys tab → click chip to set value'],
56
- ['add cron', 'cron tab → form'],
57
- ] }) }),
58
- Panel({ title: 'host', children: Receipt({ rows: Object.entries(health).map(([k, v]) => [k, String(v)]) }) }),
59
- ];
60
- },
61
- async sessions(h0) {
62
- const list = await h0.pi.sessions.list();
63
- const rows = list.map(s => {
64
- const cont = h('button', {
65
- class: 'btn-primary fd-btn-mini',
66
- onclick: async () => {
67
- const msgs = await h0.pi.sessions.getMessages(s.id);
68
- const cs = window.__fd_chatState = window.__fd_chatState || { messages: [], busy: false, sessionId: null, cwd: '', skill: '', provider: '', model: '' };
69
- cs.sessionId = s.id;
70
- cs.messages = msgs.map(m => ({ role: m.role, content: String(m.content || '') }));
71
- if (s.cwd) cs.cwd = s.cwd;
72
- if (s.skill) cs.skill = s.skill;
73
- if (typeof window.__fd_nav === 'function') window.__fd_nav('chat');
74
- },
75
- }, 'continue');
76
- return [(s.id || '').slice(0, 8), s.title || '—', s.platform || '—', s.model || '—', s.cwd ? s.cwd.slice(-30) : '—', s.skill ? skillLabel({ name: s.skill }) : '—', cont];
77
- });
78
- return [
79
- Kpi({ items: [[list.length, 'sessions']] }),
80
- Panel({ title: 'recent sessions', count: list.length, children: list.length === 0
81
- ? EmptyState({ text: 'no sessions yet — open chat and send a message', glyph: '✉' })
82
- : Table({ headers: ['id', 'title', 'platform', 'model', 'cwd', 'skill', ''], rows }) }),
83
- ];
84
- },
85
- async agents(h0) {
86
- const a = (typeof h0.pi.agents === 'function') ? await h0.pi.agents() : { count: 0, turns: 0, active: null };
87
- return [
88
- Kpi({ items: [[a.count || 0, 'active'], [a.turns || 0, 'turns']] }),
89
- Panel({ title: 'agent overview', children: Receipt({ rows: [
90
- ['total turns', String(a.turns || 0)],
91
- ['active session', a.active || '(none)'],
92
- ['last activity', a.last_activity ? new Date(a.last_activity).toLocaleString() : '—'],
93
- ] }) }),
94
- ];
95
- },
96
- async logs(h0) {
97
- const dbg = (typeof h0.pi.debug === 'function') ? h0.pi.debug() : { note: 'no debug surface' };
98
- return [Panel({ title: 'host debug snapshot', children: pre(dbg) })];
99
- },
100
- };
101
- }
@@ -1,51 +0,0 @@
1
- // OS-overlay freddie pages, only mounted when osSurfaces is provided.
2
- import * as components from '../../../components.js';
3
- import { pre } from './helpers.js';
4
-
5
- const { Panel, Kpi, Table, EmptyState } = components;
6
-
7
- export function makeOsPages(ctx) {
8
- const { osSurfaces, instance } = ctx;
9
- return {
10
- async ['os-instances']() {
11
- const list = (osSurfaces && osSurfaces.instances && osSurfaces.instances()) || [];
12
- const activeId = osSurfaces && osSurfaces.activeInstanceId && osSurfaces.activeInstanceId();
13
- return [
14
- Kpi({ items: [[list.length, 'instances'], [activeId || '—', 'active']] }),
15
- Panel({ title: 'instances', count: list.length, children: list.length === 0
16
- ? EmptyState({ text: 'no instances', glyph: '◫' })
17
- : Table({ headers: ['id', 'active', 'shells', 'windows'],
18
- rows: list.map(i => [i.id, i.id === activeId ? '●' : '', String((i.shells || []).length), String((i.windows || []).length)]) }) }),
19
- ];
20
- },
21
- async ['os-windows']() {
22
- const wins = (osSurfaces && osSurfaces.wm && osSurfaces.wm.list && osSurfaces.wm.list()) || [];
23
- const focused = osSurfaces && osSurfaces.wm && osSurfaces.wm.focused;
24
- return [
25
- Kpi({ items: [[wins.length, 'windows'], [focused ? (focused.id || focused.title || '?') : '—', 'focused']] }),
26
- Panel({ title: 'windows', count: wins.length, children: wins.length === 0
27
- ? EmptyState({ text: 'no windows open', glyph: '▭' })
28
- : Table({ headers: ['id', 'title', 'min', 'max', 'pos'],
29
- rows: wins.map(w => [w.id || '?', w.title || '', w.min ? '●' : '', w.max ? '●' : '',
30
- (w.el ? `${w.el.offsetLeft},${w.el.offsetTop} ${w.el.offsetWidth}×${w.el.offsetHeight}` : '')]) }) }),
31
- ];
32
- },
33
- async ['os-x']() {
34
- const x = osSurfaces && osSurfaces.xServer && osSurfaces.xServer();
35
- if (!x) return [Panel({ title: 'x-server', children: EmptyState({ text: 'x-server not running in this instance', glyph: '✕' }) })];
36
- return [
37
- Kpi({ items: [[x.windows, 'windows'], [x.pixmaps, 'pixmaps'], [x.gcs, 'gcs'], [x.atoms, 'atoms'], [x.cursors, 'cursors']] }),
38
- Panel({ title: 'display', children: pre(x) }),
39
- ];
40
- },
41
- async ['os-fs']() {
42
- const list = await instance.fs.list('/');
43
- return [
44
- Kpi({ items: [[list.length, 'paths'], [instance.id, 'instance']] }),
45
- Panel({ title: 'paths', count: list.length, children: list.length === 0
46
- ? EmptyState({ text: 'empty fs', glyph: '📁' })
47
- : pre(list.join('\n')) }),
48
- ];
49
- },
50
- };
51
- }
@@ -1,183 +0,0 @@
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';
4
- import { pre, form, skillLabel } from './helpers.js';
5
-
6
- const h = webjsx.createElement;
7
- const { Panel, Row, Receipt, Kpi, Table, Section, EmptyState, Chip } = components;
8
-
9
- export function makeToolsPages(ctx) {
10
- const { rerender } = ctx;
11
- return {
12
- async analytics(h0) {
13
- const list = await h0.pi.sessions.list();
14
- const tools = [...h0.pi.tools.values()];
15
- const byPlatform = list.reduce((a, s) => { const k = s.platform || '?'; a[k] = (a[k] || 0) + 1; return a; }, {});
16
- const byModel = list.reduce((a, s) => { const k = s.model || '?'; a[k] = (a[k] || 0) + 1; return a; }, {});
17
- const byToolset = tools.reduce((a, t) => { (a[t.toolset || 'core'] = a[t.toolset || 'core'] || []).push(t.name); return a; }, {});
18
- return [
19
- Kpi({ items: [[list.length, 'sessions'], [tools.length, 'tools']] }),
20
- Panel({ title: 'sessions by platform', children: Object.keys(byPlatform).length === 0
21
- ? EmptyState({ text: 'no data', glyph: '◉' })
22
- : Table({ headers: ['platform', 'count'], rows: Object.entries(byPlatform).sort((a, b) => b[1] - a[1]) }) }),
23
- Panel({ title: 'sessions by model', children: Object.keys(byModel).length === 0
24
- ? EmptyState({ text: 'no data', glyph: '◎' })
25
- : Table({ headers: ['model', 'count'], rows: Object.entries(byModel).sort((a, b) => b[1] - a[1]) }) }),
26
- Panel({ title: 'tool distribution', children: Table({ headers: ['toolset', 'count', 'tools'],
27
- rows: Object.entries(byToolset).map(([k, v]) => [k, v.length, v.slice(0, 4).join(', ') + (v.length > 4 ? '…' : '')]) }) }),
28
- ];
29
- },
30
- async models(h0) {
31
- const cfg = (typeof h0.pi.config?.load === 'function') ? await h0.pi.config.load() : {};
32
- const agent = cfg.agent || {};
33
- const providers = await fetch('/api/providers').then(r => r.json()).catch(() => []);
34
- return [
35
- Kpi({ items: [[agent.provider || '—', 'provider'], [agent.model || '—', 'model']] }),
36
- Panel({ title: 'active model', children: Receipt({ rows: [
37
- ['provider', agent.provider || '(unset)'],
38
- ['model', agent.model || '(unset)'],
39
- ['max_iterations', String(agent.max_iterations || '—')],
40
- ['max_tokens', String(agent.max_tokens || '—')],
41
- ['temperature', String(agent.temperature ?? '—')],
42
- ] }) }),
43
- Panel({ title: 'change model', children: form({
44
- fields: [{ name: 'provider', placeholder: 'provider', value: agent.provider || '' }, { name: 'model', placeholder: 'model id', value: agent.model || '' }],
45
- submit: 'update',
46
- onSubmit: async (ev) => {
47
- await h0.pi.config.saveValue('agent.provider', ev.target.elements.provider.value);
48
- await h0.pi.config.saveValue('agent.model', ev.target.elements.model.value);
49
- rerender();
50
- },
51
- }) }),
52
- Panel({ title: 'provider availability', children: h('div', { class: 'fd-chip-wrap' },
53
- ...providers.map(p => Chip({ tone: p.configured ? (p.available ? 'ok' : 'warn') : 'miss', children: p.name + (p.configured ? (p.available ? ' ●' : ' ○') : ' ·') }))
54
- ) }),
55
- ];
56
- },
57
- async cron(h0) {
58
- const list = await h0.pi.cron.list();
59
- return [
60
- Kpi({ items: [[list.length, 'cron jobs']] }),
61
- Panel({ title: 'add job', children: form({
62
- fields: [{ name: 'cron', placeholder: '* * * * *', required: true }, { name: 'prompt', placeholder: 'prompt', required: true }],
63
- submit: 'create',
64
- onSubmit: async (ev) => { try { await h0.pi.cron.create({ cron: ev.target.elements.cron.value, prompt: ev.target.elements.prompt.value }); rerender(); } catch (e) { alert(e.message); } },
65
- }) }),
66
- Panel({ title: 'scheduled jobs', count: list.length, children: list.length === 0
67
- ? EmptyState({ text: 'no cron jobs — add one above', glyph: '◷' })
68
- : Table({ headers: ['id', 'cron', 'prompt', 'enabled'],
69
- rows: list.map(j => [j.id, j.cron, (j.prompt || '').slice(0, 40), j.enabled ? 'yes' : 'no']) }) }),
70
- ];
71
- },
72
- async skills(h0) {
73
- const list = [...h0.pi.skills.values()];
74
- const byCat = list.reduce((a, s) => { (a[s.category || 'other'] = a[s.category || 'other'] || []).push(s); return a; }, {});
75
- return [
76
- Kpi({ items: [[list.length, 'skills'], [Object.keys(byCat).length, 'categories']] }),
77
- list.length === 0 ? EmptyState({ text: 'no skills loaded — add SKILL.md files to ~/.freddie/skills/', glyph: '◈' }) : null,
78
- ...Object.entries(byCat).map(([cat, ss]) => Panel({ title: cat, count: ss.length,
79
- children: ss.length === 0 ? EmptyState({ text: 'none', glyph: '◈' })
80
- : Table({ headers: ['name', 'description'], rows: ss.map(s => [skillLabel(s), (s.description || '').slice(0, 120)]) }) })),
81
- ].filter(Boolean);
82
- },
83
- async config(h0) {
84
- const cfg = (typeof h0.pi.config?.load === 'function') ? await h0.pi.config.load() : {};
85
- const profiles = (typeof h0.pi.profiles?.list === 'function') ? h0.pi.profiles.list() : [];
86
- const commands = (typeof h0.pi.commands?.list === 'function') ? h0.pi.commands.list() : [];
87
- return [
88
- Kpi({ items: [[profiles.length, 'profiles'], [commands.length, 'commands'], [cfg._config_version || 0, 'config version']] }),
89
- Panel({ title: 'set config value', children: form({
90
- fields: [{ name: 'key', placeholder: 'dotted.key (e.g. agent.model)', required: true }, { name: 'value', placeholder: 'value (json or string)', required: true }],
91
- submit: 'save',
92
- onSubmit: async (ev) => {
93
- let v = ev.target.elements.value.value;
94
- try { v = JSON.parse(v); } catch {}
95
- await h0.pi.config.saveValue(ev.target.elements.key.value, v);
96
- rerender();
97
- },
98
- }) }),
99
- Panel({ title: 'commands', count: commands.length,
100
- children: Table({ headers: ['name', 'category', 'description'], rows: commands.map(c => [c.name, c.category || '', c.description || '']) }) }),
101
- Panel({ title: 'active config', children: pre(cfg) }),
102
- ];
103
- },
104
- async env(h0) {
105
- const list = (typeof h0.pi.env?.list === 'function') ? h0.pi.env.list() : [];
106
- const setCount = list.filter(k => k.set).length;
107
- const chipNodes = list.map(k => h(
108
- 'span',
109
- {
110
- key: k.key,
111
- class: 'fd-env-chip',
112
- onclick: () => {
113
- const v = prompt('set ' + k.key + ' (empty to unset):');
114
- if (v == null) return;
115
- if (typeof h0.pi.env.set === 'function') { h0.pi.env.set(k.key, v); rerender(); }
116
- },
117
- },
118
- Chip({ tone: k.set ? 'ok' : 'miss', children: k.key + (k.set ? ' ✓' : ' ·') })
119
- ));
120
- return [
121
- Kpi({ items: [[setCount, 'set'], [list.length - setCount, 'missing'], [list.length, 'total known']] }),
122
- Panel({
123
- title: 'environment variables',
124
- right: h('span', {}, Chip({ tone: 'ok', children: setCount + ' set' }), ' ', Chip({ tone: 'miss', children: (list.length - setCount) + ' missing' })),
125
- children: h('div', { class: 'fd-chip-wrap fd-chip-wrap-padded' }, ...chipNodes),
126
- }),
127
- ];
128
- },
129
- async tools(h0) {
130
- const list = [...h0.pi.tools.values()];
131
- const byToolset = list.reduce((a, t) => { (a[t.toolset || 'core'] = a[t.toolset || 'core'] || []).push(t); return a; }, {});
132
- return [
133
- Kpi({ items: [[list.length, 'tools'], [Object.keys(byToolset).length, 'toolsets']] }),
134
- ...Object.entries(byToolset).map(([ts, items]) => Panel({ title: 'toolset · ' + ts, count: items.length,
135
- children: items.map(t => Row({ key: t.name, code: '⚒', title: t.name, sub: (t.description || (t.schema && t.schema.description) || '').slice(0, 80) })) })),
136
- ];
137
- },
138
- async batch(h0) {
139
- const out = h('div', { id: 'fd-batch-out' });
140
- const root = ctx.root;
141
- return [
142
- Section({ title: '// batch runner', children: [
143
- Panel({ title: 'run prompts', children: form({
144
- fields: [{ name: 'prompts', kind: 'textarea', placeholder: 'one prompt per line' }, { name: 'concurrency', type: 'number', value: '4' }],
145
- submit: 'run',
146
- onSubmit: async (ev) => {
147
- const prompts = ev.target.elements.prompts.value.split('\n').map(s => s.trim()).filter(Boolean);
148
- if (!prompts.length) return;
149
- const node = root.querySelector('#fd-batch-out');
150
- if (node) node.textContent = 'running…';
151
- try {
152
- const r = await h0.pi.batch.run({ prompts, concurrency: Number(ev.target.elements.concurrency.value) || 4 });
153
- if (node) { node.innerHTML = ''; node.appendChild(document.createTextNode(JSON.stringify(r, null, 2))); }
154
- } catch (e) { if (node) node.textContent = 'error: ' + (e.message || e); }
155
- },
156
- }) }),
157
- Panel({ title: 'results', children: out }),
158
- Panel({ title: 'cli usage', children: Receipt({ rows: [
159
- ['run batch file', 'freddie batch prompts.txt'],
160
- ['set concurrency', 'freddie batch prompts.txt --concurrency 8'],
161
- ['jsonl output', 'freddie batch prompts.txt > out.jsonl'],
162
- ] }) }),
163
- ] }),
164
- ];
165
- },
166
- async gateway(h0) {
167
- const platforms = (typeof h0.pi.gateway?.platforms === 'function') ? h0.pi.gateway.platforms() : [];
168
- const active = platforms.filter(p => p.enabled);
169
- return [
170
- Kpi({ items: [[platforms.length, 'platforms'], [active.length, 'active']] }),
171
- Panel({ title: 'platforms', count: platforms.length,
172
- right: active.length > 0 ? Chip({ tone: 'ok', children: active.length + ' active' }) : Chip({ tone: 'miss', children: 'none active' }),
173
- children: platforms.length === 0 ? EmptyState({ text: 'no platforms registered', glyph: '⇌' })
174
- : platforms.map(p => Row({ key: p.name, code: p.enabled ? '●' : '○', title: p.name, sub: p.note || '', meta: p.enabled ? 'enabled' : '' })) }),
175
- Panel({ title: 'start gateway', children: Receipt({ rows: [
176
- ['webhook + api_server', 'freddie gateway --port 3000'],
177
- ['specific platform', 'TELEGRAM_BOT_TOKEN=… freddie gateway'],
178
- ['all platforms', 'set env vars per platform, then freddie gateway'],
179
- ] }) }),
180
- ];
181
- },
182
- };
183
- }