anentrypoint-design 0.0.399 → 0.0.400

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,12 +1,23 @@
1
1
  {
2
2
  "name": "anentrypoint-design",
3
- "version": "0.0.399",
3
+ "version": "0.0.400",
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",
7
7
  "module": "./dist/247420.js",
8
+ "types": "./types/index.d.ts",
9
+ "sideEffects": [
10
+ "*.css",
11
+ "./src/index.js",
12
+ "./src/styles.js",
13
+ "./src/markdown-cache.js",
14
+ "./src/components/chat/stats.js",
15
+ "./src/web-components/freddie-chat.js",
16
+ "./dist/247420.js"
17
+ ],
8
18
  "exports": {
9
19
  ".": {
20
+ "types": "./types/index.d.ts",
10
21
  "import": "./dist/247420.js",
11
22
  "default": "./dist/247420.js"
12
23
  },
@@ -72,6 +83,7 @@
72
83
  "files": [
73
84
  "dist",
74
85
  "src",
86
+ "types",
75
87
  "scripts/lint-glyphs.mjs",
76
88
  "scripts/lint-null-children.mjs",
77
89
  "scripts/lint-shared.mjs",
@@ -97,6 +109,8 @@
97
109
  "sitemap": "node scripts/generate-sitemap.mjs",
98
110
  "docs:components": "node scripts/generate-component-docs.mjs",
99
111
  "lint:component-docs": "node scripts/generate-component-docs.mjs --check",
112
+ "types:components": "node scripts/generate-component-types.mjs",
113
+ "lint:component-types": "node scripts/generate-component-types.mjs --check",
100
114
  "generate:ui-kits": "node scripts/generate-ui-kit-scaffolds.mjs",
101
115
  "generate:preview-index": "node scripts/generate-preview-index.mjs",
102
116
  "a11y": "node scripts/a11y-audit.mjs",
@@ -18,7 +18,11 @@ const root = path.resolve(__dirname, '..');
18
18
  // Directories scanned recursively for source files. dist/ is generated,
19
19
  // node_modules/ is vendored, vendor/ is third-party (webjsx), .gm/ is the
20
20
  // plugkit spool — none are hand-authored design surfaces.
21
- const SCAN_DIRS = ['src', 'ui_kits', 'slides', 'site'];
21
+ // `preview` added 2026-07-28. It had been missing while EXEMPT_FILES below
22
+ // already carried a `preview/icons-unicode.html` entry — an exemption for a
23
+ // directory the walk never entered, i.e. dead code that read as coverage. The
24
+ // preview/ tree ships and is exactly where glyphs accumulate unnoticed.
25
+ const SCAN_DIRS = ['src', 'ui_kits', 'slides', 'site', 'preview'];
22
26
  const SCAN_EXT = new Set(['.js', '.mjs', '.css', '.html']);
23
27
  // The bundled root CSS files (app-shell.css, chat.css, etc.) are the design
24
28
  // system's shipped styling but live at the repo root, outside SCAN_DIRS — they
@@ -22,7 +22,13 @@ import { walkFiles } from './lint-shared.mjs';
22
22
 
23
23
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
24
24
  const root = path.resolve(__dirname, '..');
25
- const SCAN_DIRS = ['src'];
25
+ // `ui_kits`, `site`, `preview`, `slides` added 2026-07-28. The bug this gate
26
+ // catches is a webjsx applyDiff crash on a children array holding a null/false
27
+ // hole, so its true scope is "everywhere h() is called" — and h() is called in
28
+ // 20 files outside src/ (every ui_kits/*/app.js, site/theme.mjs,
29
+ // preview/data-density.js). Scanning only src/ meant the gate never looked at
30
+ // the consumer code most likely to hand-roll a conditional child.
31
+ const SCAN_DIRS = ['src', 'ui_kits', 'site', 'preview', 'slides'];
26
32
  const SCAN_EXT = new Set(['.js', '.mjs']);
27
33
  const SKIP_DIRS = new Set(['node_modules', 'vendor']);
28
34
 
@@ -23,6 +23,35 @@ const h = webjsx.createElement;
23
23
  // CAP and a "show N more" row, mirroring the History tab's "load N older".
24
24
  const FILE_GRID_CAP = 200;
25
25
 
26
+ /**
27
+ * The directory listing.
28
+ *
29
+ * `loading` and `busy` are NOT two spellings of one state -- they are the two
30
+ * halves of this SDK's standing distinction, and FileGrid is the component
31
+ * that takes both because it is the one place both are in play at once:
32
+ *
33
+ * loading -- a DATA FETCH is in flight. Owns which SHAPE renders: with no
34
+ * rows yet it is a cold load and the whole grid is replaced by
35
+ * FileSkeleton; with rows already on screen it is a refresh and
36
+ * the existing rows stay mounted and dim (is-refreshing), because
37
+ * flashing a populated directory back to shimmer reads as data
38
+ * loss.
39
+ * busy -- a USER ACTION is in flight (a rename/move/delete round-trip).
40
+ * Owns INTERACTIVITY, not shape: it is forwarded to each FileRow
41
+ * as `busy`, which disables that row's open + mutation controls
42
+ * so a second click cannot fire the same mutation twice.
43
+ *
44
+ * A grid can be `busy` while not `loading` (a delete is posting, rows fully
45
+ * rendered) and `loading` while not `busy` (a plain refresh). Passing one for
46
+ * the other is a real bug, not a style choice, so they are deliberately not
47
+ * merged and neither is an alias of the other.
48
+ *
49
+ * @param {Array} [files=[]] - the directory entries to render.
50
+ * @param {boolean} [loading=false] - a data fetch is in flight (skeleton when cold, dim when refreshing).
51
+ * @param {boolean} [busy] - a user-initiated mutation is in flight; disables every row's controls. Per-entry `f.busy` is used when this is not passed.
52
+ * @param {string} [emptyText='No files here yet'] - copy for the empty/filtered-miss state.
53
+ * @param {'list'|'compact'|'thumb'} [density='list'] - row density; 'thumb' switches to the multi-column cell grid.
54
+ */
26
55
  export function FileGrid({ files = [], onOpen, onAction, onUp, emptyText = 'No files here yet', emptyAction,
27
56
  sort, filter, loading = false,
28
57
  shown, onShowMore, actions, busy,
@@ -55,7 +55,8 @@ export function SessionDashboard({ sessions = [], onStop, onOpen, onView, onStop
55
55
  sort, filter, errorsOnly = false, onErrorsOnly,
56
56
  selectable = false, selected, onToggleSelect, onSelectAll, onClearSelection,
57
57
  activeSid, streamState,
58
- emptyText = 'No live sessions', emptyAction, offline = false } = {}) {
58
+ emptyText = 'No live sessions', emptyAction, offline = false,
59
+ density = 'comfortable' } = {}) {
59
60
  if (offline) {
60
61
  return h('div', { class: 'ds-dash-state ds-dash-state-error', role: 'status' }, 'Backend offline — live sessions unavailable');
61
62
  }
@@ -171,7 +172,7 @@ export function SessionDashboard({ sessions = [], onStop, onOpen, onView, onStop
171
172
  const grouped = !sort || !sort.value || sort.value === 'status';
172
173
  const cardOf = (s) => h('div', { key: s.sid, role: 'listitem' },
173
174
  SessionCard({ session: s, onStop, onOpen, onView, active: s.sid === activeSid,
174
- selectable, selected: selSet.has(s.sid), onToggleSelect }));
175
+ selectable, selected: selSet.has(s.sid), onToggleSelect, density }));
175
176
  // ONE stable body wrapper across every state (empty / grouped / flat), with
176
177
  // KEYED children - the ConversationList stable-keyed-body rule. Diffing
177
178
  // happens on the children, never by swapping the container's shape.
@@ -193,9 +194,9 @@ export function SessionDashboard({ sessions = [], onStop, onOpen, onView, onStop
193
194
  ].filter((b) => b.rows.length);
194
195
  bodyKids = buckets.map((b) => h('div', { key: 'grp' + b.key, class: 'ds-dash-group', role: 'group', 'aria-label': b.label + ' sessions' },
195
196
  h('div', { key: 'gl', class: 'ds-dash-group-label' }, b.label + ' · ' + b.rows.length),
196
- h('div', { key: 'gg', class: 'ds-dash-grid', role: 'list', 'aria-label': b.label + ' sessions' }, ...b.rows.map(cardOf))));
197
+ h('div', { key: 'gg', class: 'ds-dash-grid' + (density === 'compact' ? ' is-compact' : ''), role: 'list', 'aria-label': b.label + ' sessions' }, ...b.rows.map(cardOf))));
197
198
  } else {
198
- bodyKids = [h('div', { key: 'flat', class: 'ds-dash-grid', role: 'list', 'aria-label': 'live sessions' }, ...sessions.map(cardOf))];
199
+ bodyKids = [h('div', { key: 'flat', class: 'ds-dash-grid' + (density === 'compact' ? ' is-compact' : ''), role: 'list', 'aria-label': 'live sessions' }, ...sessions.map(cardOf))];
199
200
  }
200
201
  const body = h('div', { key: 'body', class: 'ds-dash-groups' }, ...bodyKids);
201
202
  return h('div', { class: 'ds-dash' }, header, body);
@@ -28,9 +28,21 @@ const h = webjsx.createElement;
28
28
  // the card heading so the rail row and its dashboard card share one identity.
29
29
  // `session.elapsedMs` (raw ms) is formatted internally via fmtDuration; the
30
30
  // pre-formatted `elapsed` string remains as a legacy fallback.
31
+ // `density` trades vertical space for scannability, the same list/compact axis
32
+ // FileGrid already exposes:
33
+ // 'comfortable' (default) — the full card: title, head, meta, per-card actions.
34
+ // 'compact' — one line per session. Measured on a real 16-session
35
+ // dashboard the comfortable card renders 208px tall,
36
+ // so a 439px viewport shows two sessions; the point of
37
+ // a command center is scanning many at once. Compact
38
+ // keeps every FACT (status, agent, cwd, elapsed,
39
+ // activity) and drops only the per-card action row,
40
+ // which is reachable by opening the session.
31
41
  export function SessionCard({ session = {}, onStop, onOpen, onView, active = false,
32
- selectable = false, selected = false, onToggleSelect } = {}) {
42
+ selectable = false, selected = false, onToggleSelect,
43
+ density = 'comfortable' } = {}) {
33
44
  const s = session;
45
+ const compact = density === 'compact';
34
46
  const st = s.stopping ? 'stopping' : (s.status === 'error' ? 'error' : (s.status === 'stale' ? 'stale' : 'running'));
35
47
  // The stat line composes elapsed + live counter; the activity line carries the
36
48
  // last-activity time and the current tool so a card shows MOTION, not just a
@@ -47,7 +59,7 @@ export function SessionCard({ session = {}, onStop, onOpen, onView, active = fal
47
59
  s.currentTool ? 'running: ' + s.currentTool : null,
48
60
  s.lastActivity ? 'last ' + s.lastActivity : null,
49
61
  ].filter(Boolean);
50
- const cls = 'ds-dash-card is-' + st + (active ? ' is-active' : '') + (selected ? ' is-selected' : '') + (s.external ? ' is-external' : '') + (s.isNew ? ' is-new' : '');
62
+ const cls = 'ds-dash-card is-' + st + (compact ? ' is-compact' : '') + (active ? ' is-active' : '') + (selected ? ' is-selected' : '') + (s.external ? ' is-external' : '') + (s.isNew ? ' is-new' : '');
51
63
  // EVERY children array is filter(Boolean)'d: webjsx applyDiff crashes
52
64
  // (reading 'key') on a bare null among VElement siblings, so a null cwd /
53
65
  // model / external flag must never reach a positional child slot.
@@ -84,9 +96,15 @@ export function SessionCard({ session = {}, onStop, onOpen, onView, active = fal
84
96
  onClick: () => !s.stopping && onStop(s),
85
97
  children: [Icon('square', { size: 14 }), h('span', {}, s.stopping ? 'stopping…' : 'stop')] }) : null,
86
98
  ].filter(Boolean));
99
+ // Compact keeps head + meta on ONE row and drops the action group; the title
100
+ // rides as the element's own accessible name (already set below) rather than
101
+ // taking a line of its own, so nothing is lost, only re-laid-out.
102
+ const children = compact
103
+ ? [head, meta].filter(Boolean)
104
+ : [
105
+ s.title ? h('div', { class: 'ds-dash-title', title: s.title }, s.title) : null,
106
+ head, meta, actions,
107
+ ].filter(Boolean);
87
108
  return h('div', { class: cls, role: 'group', 'aria-label': 'session ' + (s.title || s.agent || s.sid), 'aria-current': active ? 'true' : null },
88
- ...[
89
- s.title ? h('div', { class: 'ds-dash-title', title: s.title }, s.title) : null,
90
- head, meta, actions,
91
- ].filter(Boolean));
109
+ ...children);
92
110
  }
@@ -165,6 +165,15 @@
165
165
  .chip.tone-wip, .chip.tone-neutral {
166
166
  background: var(--bg-3); color: var(--fg-2);
167
167
  }
168
+ /* tone-dim was applied by five kits (aicat, project_page, signin, system_primer,
169
+ terminal) with no rule anywhere, so a "dim" chip rendered byte-identical to a
170
+ plain one — measured at rgb(234,230,218) on rgb(31,31,38), same opacity. It is
171
+ the recede-into-the-row tone: the tier-3 foreground on the same recessed
172
+ surface tone-wip uses, which is quieter than the default --fg-2 without
173
+ dropping to an opacity fade that would take the border and background with it. */
174
+ .chip.tone-dim {
175
+ background: var(--bg-3); color: var(--fg-3);
176
+ }
168
177
  .chip.tone-purple { background: var(--purple-tint); color: var(--purple-deep); }
169
178
  .chip.tone-mascot { background: var(--mascot-tint); color: var(--ink); }
170
179
  .chip.tone-sun, .chip.tone-yellow {
@@ -23,6 +23,7 @@ let _initPromise = null;
23
23
  let _renderCache = new Map();
24
24
  let _stats = {
25
25
  markdownInitMs: 0,
26
+ totalInitMs: 0,
26
27
  prismInitMs: 0,
27
28
  renderCount: 0,
28
29
  renderTimes: [],
@@ -59,8 +60,13 @@ export async function initializeCachesEagerly() {
59
60
  })(),
60
61
  ]);
61
62
 
62
- const totalMs = performance.now() - startTime;
63
- console.debug(`[247420] markdown/prism caches initialized in ${totalMs.toFixed(1)}ms (markdown: ${_stats.markdownInitMs.toFixed(1)}ms, prism: ${_stats.prismInitMs.toFixed(1)}ms)`);
63
+ // Recorded, not printed. This is library code, so an unconditional
64
+ // console.debug writes into every consuming application's console on
65
+ // every init. The same numbers are already live-inspectable through
66
+ // window.__debug['markdown-cache'] (registered at the bottom of this
67
+ // file), which is the repo's own observability channel and the one a
68
+ // consumer can actually opt into.
69
+ _stats.totalInitMs = performance.now() - startTime;
64
70
 
65
71
  return { markdown: mdOk, prism: prismOk };
66
72
  })();
@@ -140,6 +146,11 @@ export function getCacheStats() {
140
146
  initMs: {
141
147
  markdown: _stats.markdownInitMs,
142
148
  prism: _stats.prismInitMs,
149
+ // Wall-clock for the whole init, which is not the sum of the two
150
+ // above: they run concurrently under Promise.all, so total is the
151
+ // slower of the pair plus overhead. Previously only ever printed
152
+ // to console.debug; exposed here so it is inspectable instead.
153
+ total: _stats.totalInitMs,
143
154
  },
144
155
  renderStats: {
145
156
  count: _stats.renderCount,
@@ -171,6 +182,7 @@ export function resetCacheState() {
171
182
  _renderCache.clear();
172
183
  _stats = {
173
184
  markdownInitMs: 0,
185
+ totalInitMs: 0,
174
186
  prismInitMs: 0,
175
187
  renderCount: 0,
176
188
  renderTimes: [],