anentrypoint-design 0.0.374 → 0.0.375

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anentrypoint-design",
3
- "version": "0.0.374",
3
+ "version": "0.0.375",
4
4
  "description": "247420 design system SDK — webjsx + modified ripple-ui, single-file ESM bundle for reproducible use of the AnEntrypoint design.",
5
5
  "type": "module",
6
6
  "main": "./dist/247420.js",
@@ -17,6 +17,7 @@ import { Btn, Icon } from './shell.js';
17
17
  import { BreadcrumbPath } from './files.js';
18
18
  import { SplitPanel } from './editor-primitives.js';
19
19
  import { initializeCachesEagerly } from '../markdown-cache.js';
20
+ import { ChatMinimap } from './chat-minimap.js';
20
21
 
21
22
  const h = webjsx.createElement;
22
23
 
@@ -224,6 +225,17 @@ export function AgentChat(props = {}) {
224
225
  onPasteFiles, onDropFiles, onEmoji,
225
226
  shownMessages, onShowEarlier,
226
227
  streamingSince, detectAttachment,
228
+ // @-mention file autocomplete in the composer — a flat list of file paths
229
+ // the host already has (e.g. its Files tab data source). Purely forwarded
230
+ // to ChatComposer; omitting it keeps every existing caller unchanged (no
231
+ // mention affordance appears without it).
232
+ mentionFiles,
233
+ // Optional scroll-position minimap alongside the thread (ChatMinimap).
234
+ // false/omitted keeps every existing caller byte-identical (no minimap
235
+ // column at all). true renders the strip using this component's own
236
+ // thread ref via a shared getter — no extra DOM wiring needed from the
237
+ // host beyond passing showMinimap.
238
+ showMinimap = false,
227
239
  // Optional inline content viewer beside the thread (a docstudio-cue
228
240
  // addition: its chat view keeps a live document/PDF preview open next to
229
241
  // the conversation instead of forcing a separate tab/window). The host
@@ -414,6 +426,7 @@ export function AgentChat(props = {}) {
414
426
  onEmoji,
415
427
  streamingSince,
416
428
  detectAttachment,
429
+ mentionFiles,
417
430
  });
418
431
 
419
432
  // Contextual follow-up chips below the last SETTLED assistant turn (claude.ai/
@@ -472,8 +485,18 @@ export function AgentChat(props = {}) {
472
485
  : null)
473
486
  : null;
474
487
 
488
+ // ChatMinimap needs a getter that resolves the live thread element lazily
489
+ // (it may mount before the thread's own ref fires). A holder object keeps
490
+ // the element across re-renders without introducing component state.
491
+ const threadElHolder = { el: null };
492
+ const combinedThreadRef = (el) => {
493
+ threadElHolder.el = el;
494
+ const dispose = threadRef(messages.length)(el);
495
+ return dispose;
496
+ };
497
+
475
498
  const threadBody = h('div', { class: 'agentchat-thread-wrap' },
476
- h('div', { class: 'agentchat-thread', ref: threadRef(messages.length), role: 'log', 'aria-label': 'conversation', 'aria-live': 'polite', 'aria-relevant': 'additions' },
499
+ h('div', { class: 'agentchat-thread', ref: combinedThreadRef, role: 'log', 'aria-label': 'conversation', 'aria-live': 'polite', 'aria-relevant': 'additions' },
477
500
  emptyState,
478
501
  earlierRow,
479
502
  ...rows.filter(Boolean),
@@ -488,7 +511,12 @@ export function AgentChat(props = {}) {
488
511
  // stateless chrome, so the host needn't thread scroll state through state.
489
512
  h('button', { class: 'agentchat-jump', type: 'button', 'aria-label': 'jump to latest', title: 'jump to latest',
490
513
  onclick: (e) => scrollThreadToBottom(e.currentTarget) },
491
- Icon('arrow-down', { size: 16 }), h('span', { class: 'agentchat-jump-label' }, 'latest')));
514
+ Icon('arrow-down', { size: 16 }), h('span', { class: 'agentchat-jump-label' }, 'latest')),
515
+ // Optional scroll-position overview strip, sharing the same live thread
516
+ // element the auto-scroll/jump logic already resolves via threadElHolder.
517
+ showMinimap
518
+ ? ChatMinimap({ messages, getThreadEl: () => threadElHolder.el })
519
+ : null);
492
520
 
493
521
  const mainColumn = h('div', { class: 'agentchat-main-col' },
494
522
  h('div', { class: 'agentchat-head' },
@@ -14,6 +14,9 @@ import { register as registerDebug, unregister as unregisterDebug } from '../deb
14
14
  import { queueMessage, watchReconnect, isOnline } from '../idb-outbox.js';
15
15
  import { ChatMessage, ChatComposer } from './chat.js';
16
16
  import { fmtTime, fmtAgo } from './sessions.js';
17
+ import { ModelsConfig } from './models-config.js';
18
+ import { SkillsConfig } from './skills-config.js';
19
+ import { PluginsConfig } from './plugins-config.js';
17
20
  import { createVirtualizer, measureRef } from '../virtual-scroll.js';
18
21
  import { GitStatusPanel, GitDiffView } from './git-status.js';
19
22
  import { WorktreeSwitcher } from './worktree-switcher.js';
@@ -364,44 +367,34 @@ export const analytics = makePage((ctx) => {
364
367
  // ---- models ----------------------------------------------------------------
365
368
 
366
369
  export const models = makePage((ctx) => {
367
- Object.assign(ctx.state, { discovering: false });
370
+ Object.assign(ctx.state, { rebuilding: false, selectedProviderId: null, selectedModel: null });
371
+ // GET /api/models/availability — the real per-(provider x model x mode)
372
+ // availability matrix (plugins/gui-models-discover), per freddie's AGENTS.md
373
+ // "Model availability matrix" section. 404 with {error,hint} when the
374
+ // matrix file hasn't been built yet — ModelsConfig itself renders that
375
+ // as an empty state with a "build availability matrix" action.
368
376
  async function load() {
369
- try {
370
- const [providers, cached, sampler] = await Promise.all([
371
- api('/api/models/providers').catch(() => []),
372
- api('/api/models/cached').catch(() => ({})),
373
- api('/api/models/sampler').catch(() => ({})),
374
- ]);
375
- ctx.set({ loading: false, providers, cached, sampler, error: null });
376
- } catch (e) { ctx.set({ loading: false, error: e }); }
377
+ try { ctx.set({ loading: false, data: await api('/api/models/availability'), error: null }); }
378
+ catch (e) { ctx.set({ loading: false, data: null, error: (e && e.body) || e }); }
377
379
  }
378
- async function discover() {
379
- if (ctx.state.discovering) return;
380
- ctx.set({ discovering: true });
381
- try { await api('/api/models/discover', { method: 'POST', body: {} }); await load(); }
382
- catch (e) { ctx.set({ error: e }); }
383
- ctx.set({ discovering: false });
380
+ async function rebuild() {
381
+ if (ctx.state.rebuilding) return;
382
+ ctx.set({ rebuilding: true, rebuildError: null });
383
+ try { await api('/api/models/availability/rebuild', { method: 'POST', body: {} }); await load(); }
384
+ catch (e) { ctx.set({ rebuildError: e }); }
385
+ ctx.set({ rebuilding: false });
384
386
  }
385
387
  load();
386
388
  return () => {
387
389
  const s = ctx.state;
388
- if (s.loading) return loadingState('loading models…');
389
- if (s.error && !s.providers) return errorState(s.error, load);
390
- const providers = Array.isArray(s.providers) ? s.providers : [];
391
- const cached = s.cached || {};
392
- const status = s.sampler?.status || {};
393
390
  return [
394
- PageHeader({ eyebrow: 'freddie', title: 'models', lede: providers.length + ' providers', right: Btn({ variant: 'primary', disabled: s.discovering, children: s.discovering ? 'discovering…' : 'discover', onClick: discover }) }),
395
- liveRegion(s.discovering ? 'discovering models' : ''),
396
- section('providers', providers.length ? Table({
397
- headers: ['provider', 'sampler', 'cached models'],
398
- rows: providers.map(p => {
399
- const name = typeof p === 'string' ? p : p.id || p.provider;
400
- const st = status[name];
401
- const cm = (cached[name] || []);
402
- return [name, st ? (st.available === false ? Chip({ tone: 'miss', children: 'down' }) : Chip({ tone: 'ok', children: 'up' })) : '—', Array.isArray(cm) ? cm.length : '—'];
403
- }),
404
- }) : emptyState('no providers; set provider API keys')),
391
+ PageHeader({ eyebrow: 'freddie', title: 'models', lede: s.data ? (s.data.summary?.total_models ?? 0) + ' models across ' + (s.data.summary?.total_providers ?? 0) + ' providers' : 'model availability matrix' }),
392
+ ModelsConfig({
393
+ data: s.data, loading: s.loading, error: s.error,
394
+ selectedProviderId: s.selectedProviderId, onSelectProvider: (id) => ctx.set({ selectedProviderId: id, selectedModel: null }),
395
+ selectedModel: s.selectedModel, onSelectModel: (m) => ctx.set({ selectedModel: m }),
396
+ onRefresh: load, onRebuild: rebuild, rebuilding: s.rebuilding, rebuildError: s.rebuildError,
397
+ }),
405
398
  ];
406
399
  };
407
400
  });
@@ -444,22 +437,59 @@ export const cron = makePage((ctx) => {
444
437
  // ---- skills ----------------------------------------------------------------
445
438
 
446
439
  export const skills = makePage((ctx) => {
447
- Object.assign(ctx.state, { open: null });
440
+ Object.assign(ctx.state, { selected: null, query: '', busyName: null });
448
441
  async function load() { try { ctx.set({ loading: false, list: await api('/api/skills'), error: null }); } catch (e) { ctx.set({ loading: false, error: e }); } }
449
442
  load();
450
443
  return () => {
451
444
  const s = ctx.state;
452
- if (s.loading) return loadingState('loading skills…');
453
- if (s.error) return errorState(s.error, load);
454
- const list = Array.isArray(s.list) ? s.list : (s.list?.skills || []);
445
+ // GET /api/skills returns {home:[...], bundled:[...], skillState} —
446
+ // two source lists (user ~/.freddie/skills vs bundled skills/ dirs)
447
+ // plus a per-skill enabled/disabled state map, not a flat array.
448
+ // Concat both sources (home overrides bundled on name collision,
449
+ // matching src/skills/index.js's own findSkill() precedence) and
450
+ // resolve enabled state from skillState (default true when absent).
451
+ const raw = s.list && typeof s.list === 'object' ? s.list : {};
452
+ const rawList = Array.isArray(raw) ? raw : [...(raw.bundled || []), ...(raw.home || [])];
453
+ const skillState = raw.skillState || {};
454
+ const mapped = rawList.map((sk) => ({
455
+ file: sk.file || sk.path || sk.name,
456
+ name: sk.name,
457
+ description: sk.description || (sk.frontmatter && sk.frontmatter.description) || '',
458
+ platforms: sk.platforms || (sk.frontmatter && sk.frontmatter.platforms),
459
+ enabled: skillState[sk.name] !== false,
460
+ }));
455
461
  return [
456
- PageHeader({ eyebrow: 'freddie', title: 'skills', lede: list.length + ' skills' }),
457
- section('skills', list.length ? list.map((sk, i) => h('div', { key: i },
458
- Row({ code: (sk.source || 'fs').slice(0, 3), title: sk.name, sub: trunc(sk.description, TRUNC_DESC).text,
459
- onClick: () => ctx.set({ open: s.open === i ? null : i }), active: s.open === i }),
460
- s.open === i ? h('pre', { class: 'fd-pre fd-skill-body' }, sk.body || sk.content || '(no body)') : null,
461
- )) : emptyState('no skills')),
462
- ].filter(Boolean);
462
+ PageHeader({ eyebrow: 'freddie', title: 'skills', lede: mapped.length + ' skills' }),
463
+ SkillsConfig({
464
+ skills: mapped, selected: s.selected, loading: s.loading, error: s.error,
465
+ busyName: s.busyName, query: s.query, onQuery: (q) => ctx.set({ query: q }),
466
+ onSelect: (name) => ctx.set({ selected: s.selected === name ? null : name }),
467
+ }),
468
+ ];
469
+ };
470
+ });
471
+
472
+ // ---- plugins -----------------------------------------------------------------
473
+
474
+ export const plugins = makePage((ctx) => {
475
+ Object.assign(ctx.state, { selected: null });
476
+ // GET /api/plugins — flat {name,version,surfaces,requires,source,enabled}
477
+ // list, per plugins/gui-plugins-list/plugin.js (distinct from
478
+ // /api/plugin-graph's D3 {nodes,edges} shape built for the dependency
479
+ // visualization, not a flat list UI).
480
+ async function load() { try { ctx.set({ loading: false, list: await api('/api/plugins'), error: null }); } catch (e) { ctx.set({ loading: false, error: e }); } }
481
+ load();
482
+ return () => {
483
+ const s = ctx.state;
484
+ const list = Array.isArray(s.list) ? s.list : (s.list?.plugins || []);
485
+ return [
486
+ PageHeader({ eyebrow: 'freddie', title: 'plugins', lede: list.length + ' plugins loaded' }),
487
+ PluginsConfig({
488
+ plugins: list, selected: s.selected, loading: s.loading, error: s.error,
489
+ onSelect: (name) => ctx.set({ selected: s.selected === name ? null : name }),
490
+ onReload: load,
491
+ }),
492
+ ];
463
493
  };
464
494
  });
465
495
 
@@ -950,7 +980,7 @@ export const git = makePage((ctx) => {
950
980
 
951
981
  export const FREDDIE_PAGES = {
952
982
  home, chat, voice, sessions, projects, agents, analytics,
953
- models, cron, skills, config, env, tools, batch, gateway, chains,
983
+ models, cron, skills, plugins, config, env, tools, batch, gateway, chains,
954
984
  machines, health, debug, logs, git,
955
985
  };
956
986