@webmcp-auto-ui/ui 2.5.27 → 2.5.29
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 +18 -5
- package/src/agent/LLMSelector.svelte +11 -3
- package/src/agent/ModelCacheManager.svelte +359 -0
- package/src/index.ts +42 -30
- package/src/theme/scale.ts +128 -0
- package/src/widgets/WidgetRenderer.svelte +144 -107
- package/src/widgets/export-widget.ts +28 -1
- package/src/widgets/helpers/safe-image.ts +78 -0
- package/src/widgets/notebook/.gitkeep +0 -0
- package/src/widgets/notebook/chart-renderer.ts +63 -0
- package/src/widgets/notebook/executors/.gitkeep +1 -0
- package/src/widgets/notebook/executors/index.ts +4 -0
- package/src/widgets/notebook/executors/js-worker.ts +269 -0
- package/src/widgets/notebook/executors/sql.ts +206 -0
- package/src/widgets/notebook/import-modals.ts +560 -0
- package/src/widgets/notebook/left-pane.ts +256 -0
- package/src/widgets/notebook/notebook.ts +930 -0
- package/src/widgets/notebook/prose.ts +615 -0
- package/src/widgets/notebook/recipe-browser.ts +350 -0
- package/src/widgets/notebook/recipes/notebook.md +124 -0
- package/src/widgets/notebook/resource-extractor.ts +162 -0
- package/src/widgets/notebook/share-handlers.ts +222 -0
- package/src/widgets/notebook/shared.ts +1633 -0
- package/src/widgets/rich/cards.ts +181 -0
- package/src/widgets/rich/carousel.ts +319 -0
- package/src/widgets/rich/chart-rich.ts +386 -0
- package/src/widgets/rich/d3.ts +503 -0
- package/src/widgets/rich/data-table.ts +342 -0
- package/src/widgets/rich/gallery.ts +350 -0
- package/src/widgets/rich/grid-data.ts +173 -0
- package/src/widgets/rich/hemicycle.ts +313 -0
- package/src/widgets/rich/js-sandbox.ts +122 -0
- package/src/widgets/rich/json-viewer.ts +202 -0
- package/src/widgets/rich/log.ts +143 -0
- package/src/widgets/rich/map.ts +218 -0
- package/src/widgets/rich/profile.ts +256 -0
- package/src/widgets/rich/sankey.ts +257 -0
- package/src/widgets/rich/stat-card.ts +125 -0
- package/src/widgets/rich/timeline.ts +179 -0
- package/src/widgets/rich/trombinoscope.ts +246 -0
- package/src/widgets/simple/actions.ts +89 -0
- package/src/widgets/simple/alert.ts +100 -0
- package/src/widgets/simple/chart.ts +189 -0
- package/src/widgets/simple/code.ts +79 -0
- package/src/widgets/simple/kv.ts +68 -0
- package/src/widgets/simple/list.ts +89 -0
- package/src/widgets/simple/stat.ts +58 -0
- package/src/widgets/simple/tags.ts +125 -0
- package/src/widgets/simple/text.ts +198 -0
- package/src/widgets/SafeImage.svelte +0 -76
- package/src/widgets/rich/Cards.svelte +0 -39
- package/src/widgets/rich/Carousel.svelte +0 -88
- package/src/widgets/rich/Chart.svelte +0 -142
- package/src/widgets/rich/D3Widget.svelte +0 -378
- package/src/widgets/rich/DataTable.svelte +0 -62
- package/src/widgets/rich/Gallery.svelte +0 -94
- package/src/widgets/rich/GridData.svelte +0 -44
- package/src/widgets/rich/Hemicycle.svelte +0 -78
- package/src/widgets/rich/JsSandbox.svelte +0 -51
- package/src/widgets/rich/JsonViewer.svelte +0 -42
- package/src/widgets/rich/LogViewer.svelte +0 -24
- package/src/widgets/rich/MapView.svelte +0 -140
- package/src/widgets/rich/ProfileCard.svelte +0 -59
- package/src/widgets/rich/Sankey.svelte +0 -56
- package/src/widgets/rich/StatCard.svelte +0 -35
- package/src/widgets/rich/Timeline.svelte +0 -43
- package/src/widgets/rich/Trombinoscope.svelte +0 -48
- package/src/widgets/simple/ActionsBlock.svelte +0 -15
- package/src/widgets/simple/AlertBlock.svelte +0 -11
- package/src/widgets/simple/ChartBlock.svelte +0 -21
- package/src/widgets/simple/CodeBlock.svelte +0 -11
- package/src/widgets/simple/KVBlock.svelte +0 -16
- package/src/widgets/simple/ListBlock.svelte +0 -17
- package/src/widgets/simple/StatBlock.svelte +0 -14
- package/src/widgets/simple/TagsBlock.svelte +0 -15
- package/src/widgets/simple/TextBlock.svelte +0 -122
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webmcp-auto-ui/ui",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.29",
|
|
4
4
|
"description": "Svelte 5 UI components — primitives, widgets, window manager",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"type": "module",
|
|
@@ -15,7 +15,12 @@
|
|
|
15
15
|
"./canvas": {
|
|
16
16
|
"svelte": "./src/stores/canvas.svelte.ts",
|
|
17
17
|
"import": "./src/stores/canvas.svelte.ts"
|
|
18
|
-
}
|
|
18
|
+
},
|
|
19
|
+
"./widgets/notebook/*": {
|
|
20
|
+
"svelte": "./src/widgets/notebook/*",
|
|
21
|
+
"import": "./src/widgets/notebook/*"
|
|
22
|
+
},
|
|
23
|
+
"./widgets/notebook/recipes/*": "./src/widgets/notebook/recipes/*"
|
|
19
24
|
},
|
|
20
25
|
"scripts": {
|
|
21
26
|
"build": "svelte-package -i src",
|
|
@@ -25,7 +30,13 @@
|
|
|
25
30
|
"peerDependencies": {
|
|
26
31
|
"d3": "^7.9.0",
|
|
27
32
|
"leaflet": ">=1.9.0",
|
|
28
|
-
"svelte": "^5.0.0"
|
|
33
|
+
"svelte": "^5.0.0",
|
|
34
|
+
"vega-embed": "^6.24.0"
|
|
35
|
+
},
|
|
36
|
+
"peerDependenciesMeta": {
|
|
37
|
+
"vega-embed": {
|
|
38
|
+
"optional": true
|
|
39
|
+
}
|
|
29
40
|
},
|
|
30
41
|
"devDependencies": {
|
|
31
42
|
"@sveltejs/package": "^2.3.0",
|
|
@@ -46,14 +57,16 @@
|
|
|
46
57
|
"auto-ui"
|
|
47
58
|
],
|
|
48
59
|
"dependencies": {
|
|
49
|
-
"@webmcp-auto-ui/sdk": "*",
|
|
50
60
|
"@types/d3": "^7.4.3",
|
|
61
|
+
"@webmcp-auto-ui/core": "*",
|
|
62
|
+
"@webmcp-auto-ui/sdk": "*",
|
|
51
63
|
"bits-ui": "^2.17.2",
|
|
52
64
|
"clsx": "^2.1.1",
|
|
53
65
|
"highlight.js": "^11.10.0",
|
|
54
66
|
"html-to-image": "^1.11.13",
|
|
55
67
|
"marked": "^14.1.3",
|
|
56
68
|
"tailwind-merge": "^3.5.0",
|
|
57
|
-
"tailwind-variants": "^3.2.2"
|
|
69
|
+
"tailwind-variants": "^3.2.2",
|
|
70
|
+
"turndown": "^7.2.4"
|
|
58
71
|
}
|
|
59
72
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { listTransformersModels } from '@webmcp-auto-ui/agent';
|
|
2
|
+
import { listTransformersModels, listHawkModels } from '@webmcp-auto-ui/agent';
|
|
3
3
|
|
|
4
4
|
export interface ModelOption {
|
|
5
5
|
value: string;
|
|
6
6
|
label: string;
|
|
7
|
-
group: 'remote' | 'wasm' | 'transformers' | 'local';
|
|
7
|
+
group: 'remote' | 'wasm' | 'transformers' | 'local' | 'hawk';
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
const transformersOptions: ModelOption[] = listTransformersModels().map(({ id, entry }) => ({
|
|
@@ -13,15 +13,23 @@
|
|
|
13
13
|
group: 'transformers' as const,
|
|
14
14
|
}));
|
|
15
15
|
|
|
16
|
+
const hawkOptions: ModelOption[] = listHawkModels().map(m => ({
|
|
17
|
+
value: `hawk-${m.id}`,
|
|
18
|
+
label: m.label,
|
|
19
|
+
group: 'hawk' as const,
|
|
20
|
+
}));
|
|
21
|
+
|
|
16
22
|
const DEFAULT_MODELS: ModelOption[] = [
|
|
17
23
|
{ value: 'haiku', label: 'claude-haiku-4-5', group: 'remote' },
|
|
18
24
|
{ value: 'gemma-e2b', label: 'Gemma E2B (MediaPipe)', group: 'wasm' },
|
|
19
25
|
{ value: 'gemma-e4b', label: 'Gemma E4B (MediaPipe)', group: 'wasm' },
|
|
20
26
|
...transformersOptions,
|
|
27
|
+
...hawkOptions,
|
|
21
28
|
];
|
|
22
29
|
|
|
23
30
|
const GROUP_LABELS: Record<string, string> = {
|
|
24
31
|
remote: 'Remote',
|
|
32
|
+
hawk: 'Remote (Hawk)',
|
|
25
33
|
wasm: 'In-Browser (MediaPipe)',
|
|
26
34
|
transformers: 'In-Browser (Transformers.js)',
|
|
27
35
|
local: 'Local',
|
|
@@ -36,7 +44,7 @@
|
|
|
36
44
|
let { value, onchange, models = DEFAULT_MODELS, class: cls = '' }: Props = $props();
|
|
37
45
|
|
|
38
46
|
const groups = $derived(
|
|
39
|
-
['remote', 'wasm', 'transformers', 'local'].filter(g => models.some(m => m.group === g))
|
|
47
|
+
['remote', 'hawk', 'wasm', 'transformers', 'local'].filter(g => models.some(m => m.group === g))
|
|
40
48
|
);
|
|
41
49
|
</script>
|
|
42
50
|
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
listCachedModels, clearModelCache, clearAllModelCaches, type CachedModelInfo,
|
|
4
|
+
listAllStorage, deleteStorageEntry, clearAllStorage, type StorageEntry,
|
|
5
|
+
} from '@webmcp-auto-ui/agent';
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
class?: string;
|
|
9
|
+
}
|
|
10
|
+
let { class: cls = '' }: Props = $props();
|
|
11
|
+
|
|
12
|
+
let models = $state<CachedModelInfo[]>([]);
|
|
13
|
+
let storage = $state<StorageEntry[]>([]);
|
|
14
|
+
let usage = $state<number | null>(null);
|
|
15
|
+
let quota = $state<number | null>(null);
|
|
16
|
+
let loading = $state(true);
|
|
17
|
+
let supported = $state(true);
|
|
18
|
+
let busy = $state<string | null>(null);
|
|
19
|
+
let collapsed = $state(true);
|
|
20
|
+
|
|
21
|
+
let opfsCollapsed = $state(false);
|
|
22
|
+
let cacheCollapsed = $state(true);
|
|
23
|
+
let idbCollapsed = $state(true);
|
|
24
|
+
|
|
25
|
+
const totalSize = $derived(models.reduce((s, m) => s + m.size, 0));
|
|
26
|
+
const usagePct = $derived(quota && quota > 0 && usage !== null ? Math.min(100, (usage / quota) * 100) : 0);
|
|
27
|
+
|
|
28
|
+
const opfsExtras = $derived(storage.filter((e) => e.source === 'opfs'));
|
|
29
|
+
const cacheEntries = $derived(storage.filter((e) => e.source === 'cache-storage'));
|
|
30
|
+
const idbEntries = $derived(storage.filter((e) => e.source === 'indexeddb'));
|
|
31
|
+
|
|
32
|
+
const cacheTotalSize = $derived(cacheEntries.reduce((s, e) => s + e.size, 0));
|
|
33
|
+
const opfsExtrasTotalSize = $derived(opfsExtras.reduce((s, e) => s + e.size, 0));
|
|
34
|
+
|
|
35
|
+
function formatBytes(n: number): string {
|
|
36
|
+
if (!Number.isFinite(n) || n <= 0) return '0 B';
|
|
37
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
38
|
+
let v = n;
|
|
39
|
+
let i = 0;
|
|
40
|
+
while (v >= 1024 && i < units.length - 1) { v /= 1024; i++; }
|
|
41
|
+
return `${v.toFixed(v >= 100 || i === 0 ? 0 : v >= 10 ? 1 : 2)} ${units[i]}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function formatDate(ms: number): string {
|
|
45
|
+
if (!ms) return '—';
|
|
46
|
+
const d = new Date(ms);
|
|
47
|
+
return d.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function formatSize(e: StorageEntry): string {
|
|
51
|
+
if (!e.sizeKnown) return 'taille inconnue';
|
|
52
|
+
return formatBytes(e.size);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function refresh() {
|
|
56
|
+
loading = true;
|
|
57
|
+
try {
|
|
58
|
+
if (typeof navigator === 'undefined' || !navigator.storage?.getDirectory) {
|
|
59
|
+
supported = false;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
supported = true;
|
|
63
|
+
const [ms, sto] = await Promise.all([listCachedModels(), listAllStorage()]);
|
|
64
|
+
models = ms;
|
|
65
|
+
storage = sto;
|
|
66
|
+
try {
|
|
67
|
+
const est = await navigator.storage.estimate();
|
|
68
|
+
usage = est.usage ?? null;
|
|
69
|
+
quota = est.quota ?? null;
|
|
70
|
+
} catch {
|
|
71
|
+
usage = null;
|
|
72
|
+
quota = null;
|
|
73
|
+
}
|
|
74
|
+
} finally {
|
|
75
|
+
loading = false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function deleteOne(repo: string) {
|
|
80
|
+
if (!confirm(`Supprimer le cache "${repo}" ?`)) return;
|
|
81
|
+
busy = `opfs:${repo}`;
|
|
82
|
+
try {
|
|
83
|
+
await clearModelCache(repo);
|
|
84
|
+
await refresh();
|
|
85
|
+
} finally {
|
|
86
|
+
busy = null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function deleteAll() {
|
|
91
|
+
if (!confirm(`Supprimer TOUS les modèles en cache (${models.length} repo·s, ${formatBytes(totalSize)}) ?`)) return;
|
|
92
|
+
busy = '__opfs_all__';
|
|
93
|
+
try {
|
|
94
|
+
await clearAllModelCaches();
|
|
95
|
+
await refresh();
|
|
96
|
+
} finally {
|
|
97
|
+
busy = null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function deleteEntry(e: StorageEntry) {
|
|
102
|
+
const label = `${e.source} · ${e.key}`;
|
|
103
|
+
if (!confirm(`Supprimer ${label} ?`)) return;
|
|
104
|
+
busy = `${e.source}:${e.key}`;
|
|
105
|
+
try {
|
|
106
|
+
await deleteStorageEntry(e);
|
|
107
|
+
await refresh();
|
|
108
|
+
} finally {
|
|
109
|
+
busy = null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function deleteSource(source: 'opfs' | 'cache-storage' | 'indexeddb', count: number) {
|
|
114
|
+
if (!confirm(`Supprimer TOUT le ${source} (${count} entrée·s) ?`)) return;
|
|
115
|
+
busy = `__${source}_all__`;
|
|
116
|
+
try {
|
|
117
|
+
await clearAllStorage(source);
|
|
118
|
+
await refresh();
|
|
119
|
+
} finally {
|
|
120
|
+
busy = null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
$effect(() => { refresh(); });
|
|
125
|
+
</script>
|
|
126
|
+
|
|
127
|
+
<div class="flex flex-col gap-2 {cls}">
|
|
128
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
129
|
+
<div class="flex items-center gap-1 cursor-pointer select-none"
|
|
130
|
+
onclick={() => collapsed = !collapsed}>
|
|
131
|
+
<span class="text-[9px] font-mono text-text2 uppercase tracking-wider">Model cache (OPFS)</span>
|
|
132
|
+
<span class="text-[9px] text-text2/60 font-mono">
|
|
133
|
+
{#if !supported}(n/a){:else if loading}(…){:else}({models.length} · {formatBytes(totalSize)}){/if}
|
|
134
|
+
</span>
|
|
135
|
+
<span class="text-[10px] text-text2 ml-auto transition-transform {collapsed ? '' : 'rotate-90'}">{@html '▶'}</span>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
{#if !collapsed}
|
|
139
|
+
<div class="text-[9px] font-mono text-text2/50 -mt-1">OPFS + Cache Storage + IndexedDB</div>
|
|
140
|
+
|
|
141
|
+
{#if !supported}
|
|
142
|
+
<div class="text-[10px] font-mono text-text2/60 p-2 border border-border2 rounded">
|
|
143
|
+
OPFS indisponible dans ce navigateur.
|
|
144
|
+
</div>
|
|
145
|
+
{:else if loading}
|
|
146
|
+
<div class="text-[10px] font-mono text-text2/60">Lecture du cache…</div>
|
|
147
|
+
{:else}
|
|
148
|
+
{#if quota !== null && usage !== null}
|
|
149
|
+
<div class="flex flex-col gap-1">
|
|
150
|
+
<div class="flex items-center justify-between font-mono text-[10px] text-text2">
|
|
151
|
+
<span>{formatBytes(usage)} / {formatBytes(quota)}</span>
|
|
152
|
+
<span class="text-text2/60">origine entière · {usagePct.toFixed(1)}%</span>
|
|
153
|
+
</div>
|
|
154
|
+
<div class="h-1 bg-surface2 rounded overflow-hidden">
|
|
155
|
+
<div class="h-full bg-teal transition-all" style="width: {usagePct}%"></div>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
{/if}
|
|
159
|
+
|
|
160
|
+
<!-- ── LLM models (OPFS webmcp-models) ───────────────────────────── -->
|
|
161
|
+
<div class="flex flex-col gap-1">
|
|
162
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
163
|
+
<div class="flex items-center gap-1 cursor-pointer select-none"
|
|
164
|
+
onclick={() => opfsCollapsed = !opfsCollapsed}>
|
|
165
|
+
<span class="text-[9px] font-mono text-text2 uppercase tracking-wider">LLM models (OPFS)</span>
|
|
166
|
+
<span class="text-[9px] text-text2/60 font-mono">({models.length} · {formatBytes(totalSize)})</span>
|
|
167
|
+
<span class="text-[10px] text-text2 ml-auto transition-transform {opfsCollapsed ? '' : 'rotate-90'}">{@html '▶'}</span>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
{#if !opfsCollapsed}
|
|
171
|
+
<div class="flex items-center justify-between">
|
|
172
|
+
<span class="font-mono text-[10px] text-text2">
|
|
173
|
+
Modèles : <span class="text-text1">{models.length}</span> · {formatBytes(totalSize)}
|
|
174
|
+
</span>
|
|
175
|
+
{#if models.length > 0}
|
|
176
|
+
<button
|
|
177
|
+
class="font-mono text-[10px] h-6 px-2 rounded border border-accent2/40 text-accent2 hover:bg-accent2/10 transition-colors disabled:opacity-40"
|
|
178
|
+
disabled={busy !== null}
|
|
179
|
+
onclick={deleteAll}
|
|
180
|
+
>
|
|
181
|
+
{busy === '__opfs_all__' ? 'Suppression…' : 'Tout supprimer'}
|
|
182
|
+
</button>
|
|
183
|
+
{/if}
|
|
184
|
+
</div>
|
|
185
|
+
|
|
186
|
+
{#if models.length === 0}
|
|
187
|
+
<div class="text-[10px] font-mono text-text2/60 p-2 border border-dashed border-border2 rounded text-center">
|
|
188
|
+
Aucun modèle en cache.
|
|
189
|
+
</div>
|
|
190
|
+
{:else}
|
|
191
|
+
<ul class="flex flex-col gap-1">
|
|
192
|
+
{#each models as m (m.repo)}
|
|
193
|
+
<li class="flex items-center gap-2 p-2 rounded border border-border2 bg-surface2/40">
|
|
194
|
+
<div class="flex-1 min-w-0 flex flex-col gap-0.5">
|
|
195
|
+
<span class="font-mono text-[11px] text-text1 truncate" title={m.repo}>{m.repo}</span>
|
|
196
|
+
<span class="font-mono text-[9px] text-text2/60">
|
|
197
|
+
{formatBytes(m.size)} · {m.fileCount} fichier{m.fileCount > 1 ? 's' : ''} · {formatDate(m.lastModified)}
|
|
198
|
+
</span>
|
|
199
|
+
</div>
|
|
200
|
+
<button
|
|
201
|
+
class="font-mono text-[10px] h-6 px-2 rounded border border-accent2/30 text-accent2 hover:bg-accent2/10 transition-colors disabled:opacity-40 flex-shrink-0"
|
|
202
|
+
disabled={busy !== null}
|
|
203
|
+
onclick={() => deleteOne(m.repo)}
|
|
204
|
+
title="Supprimer ce cache"
|
|
205
|
+
>
|
|
206
|
+
{busy === `opfs:${m.repo}` ? '…' : 'Supprimer'}
|
|
207
|
+
</button>
|
|
208
|
+
</li>
|
|
209
|
+
{/each}
|
|
210
|
+
</ul>
|
|
211
|
+
{/if}
|
|
212
|
+
|
|
213
|
+
{#if opfsExtras.length > 0}
|
|
214
|
+
<div class="text-[9px] font-mono text-text2/50 mt-1">Autres OPFS : {opfsExtras.length} · {formatBytes(opfsExtrasTotalSize)}</div>
|
|
215
|
+
<ul class="flex flex-col gap-1">
|
|
216
|
+
{#each opfsExtras as e (e.key)}
|
|
217
|
+
<li class="flex items-center gap-2 p-2 rounded border border-border2 bg-surface2/40">
|
|
218
|
+
<div class="flex-1 min-w-0 flex flex-col gap-0.5">
|
|
219
|
+
<span class="font-mono text-[11px] text-text1 truncate flex items-center gap-1" title={e.key}>
|
|
220
|
+
{#if e.modelLike}<span class="text-accent text-[9px]">model</span>{/if}
|
|
221
|
+
{e.key}
|
|
222
|
+
</span>
|
|
223
|
+
<span class="font-mono text-[9px] text-text2/60">
|
|
224
|
+
{formatSize(e)} · {e.itemCount} fichier{e.itemCount > 1 ? 's' : ''} · {formatDate(e.lastModified)}
|
|
225
|
+
</span>
|
|
226
|
+
</div>
|
|
227
|
+
<button
|
|
228
|
+
class="font-mono text-[10px] h-6 px-2 rounded border border-accent2/30 text-accent2 hover:bg-accent2/10 transition-colors disabled:opacity-40 flex-shrink-0"
|
|
229
|
+
disabled={busy !== null}
|
|
230
|
+
onclick={() => deleteEntry(e)}
|
|
231
|
+
title="Supprimer ce répertoire OPFS"
|
|
232
|
+
>
|
|
233
|
+
{busy === `opfs:${e.key}` ? '…' : 'Supprimer'}
|
|
234
|
+
</button>
|
|
235
|
+
</li>
|
|
236
|
+
{/each}
|
|
237
|
+
</ul>
|
|
238
|
+
{/if}
|
|
239
|
+
{/if}
|
|
240
|
+
</div>
|
|
241
|
+
|
|
242
|
+
<!-- ── Cache Storage ─────────────────────────────────────────────── -->
|
|
243
|
+
<div class="flex flex-col gap-1">
|
|
244
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
245
|
+
<div class="flex items-center gap-1 cursor-pointer select-none"
|
|
246
|
+
onclick={() => cacheCollapsed = !cacheCollapsed}>
|
|
247
|
+
<span class="text-[9px] font-mono text-text2 uppercase tracking-wider">Cache Storage</span>
|
|
248
|
+
<span class="text-[9px] text-text2/60 font-mono">({cacheEntries.length} · {formatBytes(cacheTotalSize)})</span>
|
|
249
|
+
<span class="text-[10px] text-text2 ml-auto transition-transform {cacheCollapsed ? '' : 'rotate-90'}">{@html '▶'}</span>
|
|
250
|
+
</div>
|
|
251
|
+
|
|
252
|
+
{#if !cacheCollapsed}
|
|
253
|
+
<div class="flex items-center justify-between">
|
|
254
|
+
<span class="font-mono text-[10px] text-text2">
|
|
255
|
+
Caches : <span class="text-text1">{cacheEntries.length}</span> · {formatBytes(cacheTotalSize)}
|
|
256
|
+
</span>
|
|
257
|
+
{#if cacheEntries.length > 0}
|
|
258
|
+
<button
|
|
259
|
+
class="font-mono text-[10px] h-6 px-2 rounded border border-accent2/40 text-accent2 hover:bg-accent2/10 transition-colors disabled:opacity-40"
|
|
260
|
+
disabled={busy !== null}
|
|
261
|
+
onclick={() => deleteSource('cache-storage', cacheEntries.length)}
|
|
262
|
+
>
|
|
263
|
+
{busy === '__cache-storage_all__' ? 'Suppression…' : 'Tout supprimer'}
|
|
264
|
+
</button>
|
|
265
|
+
{/if}
|
|
266
|
+
</div>
|
|
267
|
+
|
|
268
|
+
{#if cacheEntries.length === 0}
|
|
269
|
+
<div class="text-[10px] font-mono text-text2/60 p-2 border border-dashed border-border2 rounded text-center">
|
|
270
|
+
Aucun cache.
|
|
271
|
+
</div>
|
|
272
|
+
{:else}
|
|
273
|
+
<ul class="flex flex-col gap-1">
|
|
274
|
+
{#each cacheEntries as e (e.key)}
|
|
275
|
+
<li class="flex items-center gap-2 p-2 rounded border border-border2 bg-surface2/40">
|
|
276
|
+
<div class="flex-1 min-w-0 flex flex-col gap-0.5">
|
|
277
|
+
<span class="font-mono text-[11px] text-text1 truncate flex items-center gap-1" title={e.key}>
|
|
278
|
+
{#if e.modelLike}<span class="text-accent text-[9px]">model</span>{/if}
|
|
279
|
+
{e.key}
|
|
280
|
+
</span>
|
|
281
|
+
<span class="font-mono text-[9px] text-text2/60">
|
|
282
|
+
{formatSize(e)} · {e.itemCount} item{e.itemCount > 1 ? 's' : ''} · {formatDate(e.lastModified)}
|
|
283
|
+
</span>
|
|
284
|
+
</div>
|
|
285
|
+
<button
|
|
286
|
+
class="font-mono text-[10px] h-6 px-2 rounded border border-accent2/30 text-accent2 hover:bg-accent2/10 transition-colors disabled:opacity-40 flex-shrink-0"
|
|
287
|
+
disabled={busy !== null}
|
|
288
|
+
onclick={() => deleteEntry(e)}
|
|
289
|
+
title="Supprimer ce cache"
|
|
290
|
+
>
|
|
291
|
+
{busy === `cache-storage:${e.key}` ? '…' : 'Supprimer'}
|
|
292
|
+
</button>
|
|
293
|
+
</li>
|
|
294
|
+
{/each}
|
|
295
|
+
</ul>
|
|
296
|
+
{/if}
|
|
297
|
+
{/if}
|
|
298
|
+
</div>
|
|
299
|
+
|
|
300
|
+
<!-- ── IndexedDB ─────────────────────────────────────────────────── -->
|
|
301
|
+
<div class="flex flex-col gap-1">
|
|
302
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
303
|
+
<div class="flex items-center gap-1 cursor-pointer select-none"
|
|
304
|
+
onclick={() => idbCollapsed = !idbCollapsed}>
|
|
305
|
+
<span class="text-[9px] font-mono text-text2 uppercase tracking-wider">IndexedDB</span>
|
|
306
|
+
<span class="text-[9px] text-text2/60 font-mono">({idbEntries.length})</span>
|
|
307
|
+
<span class="text-[10px] text-text2 ml-auto transition-transform {idbCollapsed ? '' : 'rotate-90'}">{@html '▶'}</span>
|
|
308
|
+
</div>
|
|
309
|
+
|
|
310
|
+
{#if !idbCollapsed}
|
|
311
|
+
<div class="flex items-center justify-between">
|
|
312
|
+
<span class="font-mono text-[10px] text-text2">
|
|
313
|
+
Bases : <span class="text-text1">{idbEntries.length}</span> · taille inconnue
|
|
314
|
+
</span>
|
|
315
|
+
{#if idbEntries.length > 0}
|
|
316
|
+
<button
|
|
317
|
+
class="font-mono text-[10px] h-6 px-2 rounded border border-accent2/40 text-accent2 hover:bg-accent2/10 transition-colors disabled:opacity-40"
|
|
318
|
+
disabled={busy !== null}
|
|
319
|
+
onclick={() => deleteSource('indexeddb', idbEntries.length)}
|
|
320
|
+
>
|
|
321
|
+
{busy === '__indexeddb_all__' ? 'Suppression…' : 'Tout supprimer'}
|
|
322
|
+
</button>
|
|
323
|
+
{/if}
|
|
324
|
+
</div>
|
|
325
|
+
|
|
326
|
+
{#if idbEntries.length === 0}
|
|
327
|
+
<div class="text-[10px] font-mono text-text2/60 p-2 border border-dashed border-border2 rounded text-center">
|
|
328
|
+
Aucune base IndexedDB.
|
|
329
|
+
</div>
|
|
330
|
+
{:else}
|
|
331
|
+
<ul class="flex flex-col gap-1">
|
|
332
|
+
{#each idbEntries as e (e.key)}
|
|
333
|
+
<li class="flex items-center gap-2 p-2 rounded border border-border2 bg-surface2/40">
|
|
334
|
+
<div class="flex-1 min-w-0 flex flex-col gap-0.5">
|
|
335
|
+
<span class="font-mono text-[11px] text-text1 truncate flex items-center gap-1" title={e.key}>
|
|
336
|
+
{#if e.modelLike}<span class="text-accent text-[9px]">model</span>{/if}
|
|
337
|
+
{e.key}
|
|
338
|
+
</span>
|
|
339
|
+
<span class="font-mono text-[9px] text-text2/60">
|
|
340
|
+
taille inconnue · version {e.itemCount}
|
|
341
|
+
</span>
|
|
342
|
+
</div>
|
|
343
|
+
<button
|
|
344
|
+
class="font-mono text-[10px] h-6 px-2 rounded border border-accent2/30 text-accent2 hover:bg-accent2/10 transition-colors disabled:opacity-40 flex-shrink-0"
|
|
345
|
+
disabled={busy !== null}
|
|
346
|
+
onclick={() => deleteEntry(e)}
|
|
347
|
+
title="Supprimer cette base"
|
|
348
|
+
>
|
|
349
|
+
{busy === `indexeddb:${e.key}` ? '…' : 'Supprimer'}
|
|
350
|
+
</button>
|
|
351
|
+
</li>
|
|
352
|
+
{/each}
|
|
353
|
+
</ul>
|
|
354
|
+
{/if}
|
|
355
|
+
{/if}
|
|
356
|
+
</div>
|
|
357
|
+
{/if}
|
|
358
|
+
{/if}
|
|
359
|
+
</div>
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,8 @@ export { default as ThemeProvider, getTheme } from './theme/ThemeProvider.svelte
|
|
|
5
5
|
export type { ThemeJSON } from './theme/ThemeProvider.svelte';
|
|
6
6
|
export { DARK_TOKENS, LIGHT_TOKENS, THEME_MAP } from './theme/tokens.js';
|
|
7
7
|
export type { ThemeMode, ThemeOverrides, ThemeTokens } from './theme/tokens.js';
|
|
8
|
+
export { getUIScale, setUIScale, toggleUIScale, initUIScale, isUIScaled } from './theme/scale.js';
|
|
9
|
+
export type { UIScale, UIScaleKey } from './theme/scale.js';
|
|
8
10
|
|
|
9
11
|
// Primitives
|
|
10
12
|
export { default as Card } from './primitives/Card.svelte';
|
|
@@ -16,38 +18,47 @@ export { default as MarkdownView } from './primitives/MarkdownView.svelte';
|
|
|
16
18
|
export { default as CodeView } from './primitives/CodeView.svelte';
|
|
17
19
|
export { renderMarkdown, highlightCode, createMarkdownRenderer } from './primitives/markdown-renderer.js';
|
|
18
20
|
|
|
19
|
-
// Simple widgets (
|
|
20
|
-
export {
|
|
21
|
-
export {
|
|
22
|
-
export {
|
|
23
|
-
export {
|
|
24
|
-
export {
|
|
25
|
-
export {
|
|
26
|
-
export {
|
|
27
|
-
export {
|
|
28
|
-
export {
|
|
21
|
+
// Simple widgets (vanilla renderers) — contract: render(container, data): () => void
|
|
22
|
+
export { render as renderStat } from './widgets/simple/stat.js';
|
|
23
|
+
export { render as renderKv } from './widgets/simple/kv.js';
|
|
24
|
+
export { render as renderList } from './widgets/simple/list.js';
|
|
25
|
+
export { render as renderChart } from './widgets/simple/chart.js';
|
|
26
|
+
export { render as renderAlert } from './widgets/simple/alert.js';
|
|
27
|
+
export { render as renderCode } from './widgets/simple/code.js';
|
|
28
|
+
export { render as renderText } from './widgets/simple/text.js';
|
|
29
|
+
export { render as renderActions } from './widgets/simple/actions.js';
|
|
30
|
+
export { render as renderTags } from './widgets/simple/tags.js';
|
|
29
31
|
|
|
30
|
-
// Rich widgets (
|
|
31
|
-
export {
|
|
32
|
-
export {
|
|
33
|
-
export {
|
|
34
|
-
export {
|
|
35
|
-
export {
|
|
36
|
-
export {
|
|
37
|
-
export {
|
|
38
|
-
export {
|
|
39
|
-
export {
|
|
40
|
-
export {
|
|
41
|
-
export {
|
|
42
|
-
export {
|
|
43
|
-
export {
|
|
44
|
-
export {
|
|
45
|
-
export {
|
|
46
|
-
export {
|
|
47
|
-
export {
|
|
32
|
+
// Rich widgets (vanilla renderers)
|
|
33
|
+
export { render as renderStatCard } from './widgets/rich/stat-card.js';
|
|
34
|
+
export { render as renderDataTable } from './widgets/rich/data-table.js';
|
|
35
|
+
export { render as renderTimeline } from './widgets/rich/timeline.js';
|
|
36
|
+
export { render as renderProfile } from './widgets/rich/profile.js';
|
|
37
|
+
export { render as renderTrombinoscope } from './widgets/rich/trombinoscope.js';
|
|
38
|
+
export { render as renderJsonViewer } from './widgets/rich/json-viewer.js';
|
|
39
|
+
export { render as renderHemicycle } from './widgets/rich/hemicycle.js';
|
|
40
|
+
export { render as renderChartRich } from './widgets/rich/chart-rich.js';
|
|
41
|
+
export { render as renderCards } from './widgets/rich/cards.js';
|
|
42
|
+
export { render as renderGridData } from './widgets/rich/grid-data.js';
|
|
43
|
+
export { render as renderSankey } from './widgets/rich/sankey.js';
|
|
44
|
+
export { render as renderMap } from './widgets/rich/map.js';
|
|
45
|
+
export { render as renderD3 } from './widgets/rich/d3.js';
|
|
46
|
+
export { render as renderJsSandbox } from './widgets/rich/js-sandbox.js';
|
|
47
|
+
export { render as renderLog } from './widgets/rich/log.js';
|
|
48
|
+
export { render as renderGallery } from './widgets/rich/gallery.js';
|
|
49
|
+
export { render as renderCarousel } from './widgets/rich/carousel.js';
|
|
48
50
|
|
|
49
|
-
//
|
|
50
|
-
export {
|
|
51
|
+
// Notebook widget renderer (vanilla)
|
|
52
|
+
export { render as renderNotebook } from './widgets/notebook/notebook.js';
|
|
53
|
+
export { render as renderRecipeBrowserWidget } from './widgets/notebook/recipe-browser.js';
|
|
54
|
+
// Notebook types (optional public API)
|
|
55
|
+
export type { NotebookState, NotebookCell } from './widgets/notebook/shared.js';
|
|
56
|
+
// Notebook cell extractors (for hosts that build notebooks from recipes/tools)
|
|
57
|
+
export { extractCellsFromRecipe, extractCellsFromTool, extractCellFromMarkdown, extractCellFromFence } from './widgets/notebook/resource-extractor.js';
|
|
58
|
+
|
|
59
|
+
// Safe image helper (URL validation + error fallback)
|
|
60
|
+
export { createSafeImage } from './widgets/helpers/safe-image.js';
|
|
61
|
+
export type { SafeImageOptions } from './widgets/helpers/safe-image.js';
|
|
51
62
|
|
|
52
63
|
// Widget export utility
|
|
53
64
|
export { exportWidget, getExportFormats, exportWidgetAs } from './widgets/export-widget.js';
|
|
@@ -90,6 +101,7 @@ export { default as ModelLoader } from './agent/ModelLoader.svelte';
|
|
|
90
101
|
/** @deprecated Use ModelLoader instead. Alias maintained for backward compatibility. */
|
|
91
102
|
export { default as GemmaLoader } from './agent/ModelLoader.svelte';
|
|
92
103
|
export { default as McpStatus } from './agent/McpStatus.svelte';
|
|
104
|
+
export { default as ModelCacheManager } from './agent/ModelCacheManager.svelte';
|
|
93
105
|
export { default as AgentProgress } from './agent/AgentProgress.svelte';
|
|
94
106
|
export { default as McpConnector } from './agent/McpConnector.svelte';
|
|
95
107
|
export { default as ChatPanel } from './agent/ChatPanel.svelte';
|