agentgui 1.0.911 → 1.0.913

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.
@@ -1,6 +1,6 @@
1
1
  // Stream plugin - session management, streaming execution, rate limiting
2
2
 
3
- import { v4 as uuidv4 } from 'uuid';
3
+ import { randomUUID as uuidv4 } from 'crypto';
4
4
 
5
5
  export default {
6
6
  name: 'stream',
@@ -29,17 +29,24 @@ const spawnNpmInstall = (pkg, onProgress) => new Promise((resolve) => {
29
29
  proc.on('error', (err) => { clearTimeout(timer); if (!completed) { completed = true; resolve({ success: false, error: err.message }); } });
30
30
  });
31
31
 
32
- const spawnBunxProc = (pkg, onProgress) => new Promise((resolve) => {
33
- const cmd = isWindows ? 'bun.cmd' : 'bun';
32
+ const BUNX_RUNNERS = [
33
+ { cmd: isWindows ? 'bun.cmd' : 'bun', args: (pkg) => ['x', pkg] },
34
+ { cmd: isWindows ? 'npx.cmd' : 'npx', args: (pkg) => ['-y', pkg] },
35
+ ];
36
+
37
+ const isMissingCmdError = (s) => /not recognized|ENOENT|command not found|cannot find/i.test(s || '');
38
+
39
+ const spawnBunxOnce = (runner, pkg, onProgress) => new Promise((resolve) => {
40
+ const cmd = runner.cmd;
34
41
  let completed = false, stderr = '', stdout = '';
35
42
  let lastDataTime = Date.now();
36
43
  let proc;
37
44
  try {
38
- proc = spawn(cmd, ['x', pkg], { stdio: ['pipe', 'pipe', 'pipe'], timeout: 300000, shell: isWindows, windowsHide: true });
45
+ proc = spawn(cmd, runner.args(pkg), { stdio: ['pipe', 'pipe', 'pipe'], timeout: 300000, shell: isWindows, windowsHide: true });
39
46
  } catch (err) {
40
- return resolve({ success: false, error: `Failed to spawn bun x: ${err.message}` });
47
+ return resolve({ success: false, error: `Failed to spawn ${cmd}: ${err.message}`, missing: isMissingCmdError(err.message) });
41
48
  }
42
- if (!proc) return resolve({ success: false, error: 'Failed to spawn bun x process' });
49
+ if (!proc) return resolve({ success: false, error: `Failed to spawn ${cmd} process`, missing: true });
43
50
 
44
51
  const timer = setTimeout(() => {
45
52
  if (!completed) { completed = true; try { proc.kill('SIGKILL'); } catch (_) {} resolve({ success: false, error: 'Timeout (5min)' }); }
@@ -48,7 +55,7 @@ const spawnBunxProc = (pkg, onProgress) => new Promise((resolve) => {
48
55
  const heartbeatTimer = setInterval(() => {
49
56
  if (completed) { clearInterval(heartbeatTimer); return; }
50
57
  const elapsed = Date.now() - lastDataTime;
51
- if (elapsed > 30000) console.warn(`[tool-manager] No output from bun x ${pkg} for ${elapsed}ms - process may be hung`);
58
+ if (elapsed > 30000) console.warn(`[tool-manager] No output from ${cmd} ${pkg} for ${elapsed}ms - process may be hung`);
52
59
  }, 30000);
53
60
 
54
61
  const onData = (d) => { lastDataTime = Date.now(); if (onProgress) onProgress({ type: 'progress', data: d.toString() }); };
@@ -64,16 +71,27 @@ const spawnBunxProc = (pkg, onProgress) => new Promise((resolve) => {
64
71
  const ok = [code === 0, output.includes('upgraded'), output.includes('registered'),
65
72
  output.includes('Hooks registered'), output.includes('successfully'),
66
73
  output.includes('Done'), code === 0 && !output.includes('error')].some(Boolean);
67
- resolve(ok ? { success: true, error: null, pkg } : { success: false, error: output.substring(0, 1000) || 'Failed' });
74
+ resolve(ok ? { success: true, error: null, pkg } : { success: false, error: output.substring(0, 1000) || 'Failed', missing: isMissingCmdError(output) });
68
75
  });
69
76
 
70
77
  proc.on('error', (err) => {
71
78
  clearTimeout(timer);
72
79
  clearInterval(heartbeatTimer);
73
- if (!completed) { completed = true; resolve({ success: false, error: `Process error: ${err.message}` }); }
80
+ if (!completed) { completed = true; resolve({ success: false, error: `Process error: ${err.message}`, missing: isMissingCmdError(err.message) }); }
74
81
  });
75
82
  });
76
83
 
84
+ const spawnBunxProc = async (pkg, onProgress) => {
85
+ let lastResult = null;
86
+ for (const runner of BUNX_RUNNERS) {
87
+ const result = await spawnBunxOnce(runner, pkg, onProgress);
88
+ if (result.success) return result;
89
+ lastResult = result;
90
+ if (!result.missing) return result;
91
+ }
92
+ return lastResult || { success: false, error: 'No runner available' };
93
+ };
94
+
77
95
  function spawnForTool(tool, onProgress) {
78
96
  const pkg = tool.installPkg || tool.pkg;
79
97
  return tool.category === 'cli' ? spawnNpmInstall(pkg, onProgress) : spawnBunxProc(pkg, onProgress);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.911",
3
+ "version": "1.0.913",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "electron/main.js",
package/site/theme.mjs CHANGED
@@ -1,7 +1,10 @@
1
1
  // AnEntrypoint design-system theme for flatspace.
2
- // Renders site chrome via anentrypoint-design SDK using REAL SDK components.
3
- // theme.mjs emits HTML shell + bootstrap that consumes YAML baked into <script id="__site__">.
4
- // SDK provides ALL styling via installStyles(); plus a tiny inline body-margin reset.
2
+ // Renders SDK chrome around home (landing) AND legacy docs/* pages
3
+ // (each rendered as an iframe of the original, preserving scripts/styles).
4
+
5
+ import { readFileSync, existsSync } from 'fs';
6
+ import { resolve, dirname } from 'path';
7
+ import { fileURLToPath } from 'url';
5
8
 
6
9
  const escapeHtml = (s) => String(s ?? '')
7
10
  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
@@ -12,36 +15,36 @@ const escapeJson = (obj) => JSON.stringify(obj)
12
15
  .replace(new RegExp('\\u2028', 'g'), '\\u2028').replace(new RegExp('\\u2029', 'g'), '\\u2029');
13
16
 
14
17
  const SDK_URL = 'https://unpkg.com/anentrypoint-design@latest/dist/247420.js';
18
+ const THIS_DIR = dirname(fileURLToPath(import.meta.url));
15
19
 
16
- const clientScript = `
20
+ const landingClient = `
17
21
  import { h, applyDiff, installStyles, components as C } from 'anentrypoint-design';
18
22
  installStyles();
19
23
  document.documentElement.classList.add('ds-247420');
20
-
21
24
  const data = JSON.parse(document.getElementById('__site__').textContent);
22
- const { site, nav, home } = data;
25
+ const { site, nav, page } = data;
23
26
 
24
27
  function Hero() {
25
- if (!home || !home.hero) return null;
28
+ if (!page || !page.hero) return null;
26
29
  return C.Panel({
27
30
  style: 'margin:8px',
28
31
  children: h('div', { style: 'padding:24px 22px' },
29
- C.Heading({ level: 1, style: 'margin:0 0 8px 0', children: home.hero.heading || site.title }),
30
- home.hero.subheading ? C.Lede({ children: home.hero.subheading }) : null,
31
- home.hero.body ? h('p', { style: 'margin:8px 0 16px 0;color:var(--panel-text-2);max-width:64ch' }, home.hero.body) : null,
32
- (home.hero.badges && home.hero.badges.length) ? h('div', { style: 'display:flex;gap:6px;flex-wrap:wrap;margin:0 0 12px 0' },
33
- ...home.hero.badges.map((b, i) => C.Chip({ key: 'b' + i, children: b.label }))
32
+ C.Heading({ level: 1, style: 'margin:0 0 8px 0', children: page.hero.heading || site.title }),
33
+ page.hero.subheading ? C.Lede({ children: page.hero.subheading }) : null,
34
+ page.hero.body ? h('p', { style: 'margin:8px 0 16px 0;color:var(--panel-text-2);max-width:64ch' }, page.hero.body) : null,
35
+ (page.hero.badges && page.hero.badges.length) ? h('div', { style: 'display:flex;gap:6px;flex-wrap:wrap;margin:0 0 12px 0' },
36
+ ...page.hero.badges.map((b, i) => C.Chip({ key: 'b' + i, children: b.label }))
34
37
  ) : null,
35
- (home.hero.ctas && home.hero.ctas.length) ? h('div', { style: 'display:flex;gap:8px;flex-wrap:wrap' },
36
- ...home.hero.ctas.map((c, i) => C.Btn({ key: 'c' + i, href: c.href, primary: c.primary, children: c.label }))
38
+ (page.hero.ctas && page.hero.ctas.length) ? h('div', { style: 'display:flex;gap:8px;flex-wrap:wrap' },
39
+ ...page.hero.ctas.map((c, i) => C.Btn({ key: 'c' + i, href: c.href, primary: c.primary, children: c.label }))
37
40
  ) : null
38
41
  )
39
42
  });
40
43
  }
41
44
 
42
45
  function Features() {
43
- if (!home || !home.features || !home.features.items || !home.features.items.length) return null;
44
- const rows = home.features.items.map((it, i) => C.RowLink({
46
+ if (!page || !page.features || !page.features.items || !page.features.items.length) return null;
47
+ const rows = page.features.items.map((it, i) => C.RowLink({
45
48
  key: 'f' + i,
46
49
  code: String(i + 1).padStart(2, '0'),
47
50
  title: it.name,
@@ -50,15 +53,15 @@ function Features() {
50
53
  href: it.href || '#'
51
54
  }));
52
55
  return C.Panel({
53
- title: home.features.heading || 'features',
56
+ title: page.features.heading || 'features',
54
57
  style: 'margin:8px',
55
58
  children: rows
56
59
  });
57
60
  }
58
61
 
59
62
  function Quickstart() {
60
- if (!home || !home.quickstart || !home.quickstart.lines || !home.quickstart.lines.length) return null;
61
- const lineNodes = home.quickstart.lines.map((l, i) => {
63
+ if (!page || !page.quickstart || !page.quickstart.lines || !page.quickstart.lines.length) return null;
64
+ const lineNodes = page.quickstart.lines.map((l, i) => {
62
65
  const isComment = l.kind === 'cmt';
63
66
  return h('div', { key: 'q' + i, class: 'cli' },
64
67
  h('span', { class: 'prompt' }, isComment ? '#' : '$'),
@@ -66,28 +69,12 @@ function Quickstart() {
66
69
  );
67
70
  });
68
71
  return C.Panel({
69
- title: home.quickstart.heading || 'quick start',
72
+ title: page.quickstart.heading || 'quick start',
70
73
  style: 'margin:8px',
71
74
  children: h('div', { style: 'padding:16px 22px' }, ...lineNodes)
72
75
  });
73
76
  }
74
77
 
75
- function Examples() {
76
- if (!home || !home.examples || !home.examples.items || !home.examples.items.length) return null;
77
- const rows = home.examples.items.map((it, i) => C.RowLink({
78
- key: 'e' + i,
79
- title: it.name,
80
- sub: it.desc || '',
81
- meta: it.cta || 'open',
82
- href: it.href || '#'
83
- }));
84
- return C.Panel({
85
- title: home.examples.heading || 'examples',
86
- style: 'margin:8px',
87
- children: rows
88
- });
89
- }
90
-
91
78
  function Footer() {
92
79
  return h('footer', { class: 'app-status' },
93
80
  h('span', { class: 'item' }, 'styled with '),
@@ -102,64 +89,95 @@ function Footer() {
102
89
  const navItems = (nav && nav.links ? nav.links : []).map(l => [String(l.label || ''), l.href]);
103
90
 
104
91
  const App = C.AppShell({
105
- topbar: C.Topbar({
106
- brand: '247420',
107
- leaf: site.title || '',
108
- items: navItems
109
- }),
110
- crumb: C.Crumb({
111
- trail: ['247420'],
112
- leaf: site.title || ''
113
- }),
114
- main: h('div', {},
115
- Hero(),
116
- Features(),
117
- Quickstart(),
118
- Examples()
119
- ),
92
+ topbar: C.Topbar({ brand: '247420', leaf: site.title || '', items: navItems }),
93
+ crumb: C.Crumb({ trail: ['247420'], leaf: site.title || '' }),
94
+ main: h('div', {}, Hero(), Features(), Quickstart()),
120
95
  status: Footer()
121
96
  });
97
+ applyDiff(document.getElementById('app'), [App]);
98
+ `;
122
99
 
100
+ const embedClient = `
101
+ import { h, applyDiff, installStyles, components as C } from 'anentrypoint-design';
102
+ installStyles();
103
+ document.documentElement.classList.add('ds-247420');
104
+ const data = JSON.parse(document.getElementById('__site__').textContent);
105
+ const { site, nav, page } = data;
106
+ const navItems = (nav && nav.links ? nav.links : []).map(l => [String(l.label || ''), l.href]);
107
+
108
+ function Footer() {
109
+ return h('footer', { class: 'app-status' },
110
+ h('span', { class: 'item' }, 'styled with '),
111
+ h('a', { class: 'item', href: 'https://anentrypoint.github.io/design/' }, 'anentrypoint-design'),
112
+ h('span', { class: 'item' }, '·'),
113
+ h('a', { class: 'item', href: 'https://247420.xyz' }, '247420.xyz'),
114
+ h('span', { class: 'spread' }),
115
+ site.repo ? h('a', { class: 'item', href: site.repo }, 'source ↗') : null
116
+ );
117
+ }
118
+
119
+ const App = C.AppShell({
120
+ topbar: C.Topbar({ brand: '247420', leaf: site.title || '', items: navItems }),
121
+ crumb: C.Crumb({ trail: ['247420', site.title || ''], leaf: page.title || '' }),
122
+ main: C.Panel({
123
+ style: 'margin:8px',
124
+ children: h('iframe', {
125
+ src: page.embedSrc,
126
+ style: 'width:100%;height:calc(100vh - 180px);min-height:520px;border:0;border-radius:6px;background:var(--panel-1);display:block',
127
+ title: page.title || ''
128
+ })
129
+ }),
130
+ status: Footer()
131
+ });
123
132
  applyDiff(document.getElementById('app'), [App]);
124
133
  `;
125
134
 
126
- const html = ({ site, nav, home }) => `<!DOCTYPE html>
135
+ const renderHtml = ({ site, nav, page, clientScript }) => `<!DOCTYPE html>
127
136
  <html lang="en" class="ds-247420">
128
137
  <head>
129
138
  <meta charset="UTF-8" />
130
139
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
131
- <title>${escapeHtml(site.title)}${site.tagline ? ' — ' + escapeHtml(site.tagline) : ''}</title>
132
- <meta name="description" content="${escapeHtml(site.description || site.tagline || site.title)}" />
133
- <meta property="og:title" content="${escapeHtml(site.title)}" />
134
- <meta property="og:description" content="${escapeHtml(site.description || site.tagline || '')}" />
135
- <meta property="og:url" content="${escapeHtml(site.url || '')}" />
136
- <link rel="canonical" href="${escapeHtml(site.url || '')}" />
137
- <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ctext y='26' font-size='26'%3E${encodeURIComponent(site.glyph || '◆')}%3C/text%3E%3C/svg%3E" />
140
+ <title>${escapeHtml(page.title || site.title)}${site.tagline ? ' — ' + escapeHtml(site.tagline) : ''}</title>
141
+ <meta name="description" content="${escapeHtml(page.description || site.description || site.tagline || site.title)}" />
138
142
  <script type="importmap">{"imports":{"anentrypoint-design":"${SDK_URL}"}}</script>
139
143
  <style>html,body{margin:0;padding:0}body{background:var(--app-bg,#FBF6EB);color:var(--ink,#1F1B16);font-family:var(--ff-ui,'Nunito',system-ui,sans-serif)}</style>
140
144
  </head>
141
145
  <body>
142
146
  <div id="app"></div>
143
- <script type="application/json" id="__site__">${escapeJson({ site, nav, home })}</script>
147
+ <script type="application/json" id="__site__">${escapeJson({ site, nav, page })}</script>
144
148
  <script type="module">${clientScript}</script>
145
149
  </body>
146
150
  </html>
147
151
  `;
148
152
 
149
153
  export default {
154
+ // Copy original docs/* into dist/_legacy/* so iframes can load them.
150
155
  assets: {
151
- '../docs/demo.html': 'demo.html',
156
+ '../docs/demo.html': '_legacy/demo.html',
152
157
  '../docs/screenshots': 'screenshots',
153
158
  },
154
159
  render: async (ctx) => {
155
160
  const site = ctx.readGlobal('site') || {};
156
161
  const nav = ctx.readGlobal('navigation') || { links: [] };
157
- const homeDoc = ctx.read('pages').docs.find(p => p.id === 'home');
158
- if (!homeDoc) throw new Error('config/pages/home.yaml missing or has no id: home');
162
+ const docs = ctx.read('pages').docs;
163
+ const homeDoc = docs.find(p => p.id === 'home');
164
+ if (!homeDoc) throw new Error('site/content/pages/home.yaml missing or has no id: home');
159
165
 
160
- return [{
166
+ const outputs = [{
161
167
  path: 'index.html',
162
- html: html({ site, nav, home: homeDoc })
168
+ html: renderHtml({ site, nav, page: homeDoc, clientScript: landingClient })
163
169
  }];
170
+
171
+ // Wrapped legacy pages: SDK chrome + iframe of original.
172
+ const embeds = [
173
+ { path: 'demo.html', title: 'demo', embedSrc: './_legacy/demo.html' },
174
+ ];
175
+ for (const e of embeds) {
176
+ outputs.push({
177
+ path: e.path,
178
+ html: renderHtml({ site, nav, page: e, clientScript: embedClient })
179
+ });
180
+ }
181
+ return outputs;
164
182
  }
165
183
  };