sh3-core 0.6.0

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 (242) hide show
  1. package/README.md +9 -0
  2. package/dist/Shell.svelte +283 -0
  3. package/dist/Shell.svelte.d.ts +5 -0
  4. package/dist/api.d.ts +28 -0
  5. package/dist/api.js +50 -0
  6. package/dist/app/admin/ApiKeysView.svelte +169 -0
  7. package/dist/app/admin/ApiKeysView.svelte.d.ts +3 -0
  8. package/dist/app/admin/AuthSettingsView.svelte +105 -0
  9. package/dist/app/admin/AuthSettingsView.svelte.d.ts +3 -0
  10. package/dist/app/admin/SystemView.svelte +73 -0
  11. package/dist/app/admin/SystemView.svelte.d.ts +3 -0
  12. package/dist/app/admin/UsersView.svelte +188 -0
  13. package/dist/app/admin/UsersView.svelte.d.ts +3 -0
  14. package/dist/app/admin/adminApp.d.ts +7 -0
  15. package/dist/app/admin/adminApp.js +25 -0
  16. package/dist/app/admin/adminShard.svelte.d.ts +4 -0
  17. package/dist/app/admin/adminShard.svelte.js +62 -0
  18. package/dist/app/store/InstalledView.svelte +246 -0
  19. package/dist/app/store/InstalledView.svelte.d.ts +3 -0
  20. package/dist/app/store/StoreView.svelte +522 -0
  21. package/dist/app/store/StoreView.svelte.d.ts +3 -0
  22. package/dist/app/store/storeApp.d.ts +10 -0
  23. package/dist/app/store/storeApp.js +26 -0
  24. package/dist/app/store/storeShard.svelte.d.ts +38 -0
  25. package/dist/app/store/storeShard.svelte.js +218 -0
  26. package/dist/apps/lifecycle.d.ts +42 -0
  27. package/dist/apps/lifecycle.js +184 -0
  28. package/dist/apps/registry.svelte.d.ts +40 -0
  29. package/dist/apps/registry.svelte.js +59 -0
  30. package/dist/apps/terminal/manifest.d.ts +8 -0
  31. package/dist/apps/terminal/manifest.js +13 -0
  32. package/dist/apps/terminal/terminal-app.d.ts +7 -0
  33. package/dist/apps/terminal/terminal-app.js +14 -0
  34. package/dist/apps/types.d.ts +93 -0
  35. package/dist/apps/types.js +10 -0
  36. package/dist/artifact.d.ts +32 -0
  37. package/dist/artifact.js +1 -0
  38. package/dist/assets/SH3.png +0 -0
  39. package/dist/assets/icons.svg +1126 -0
  40. package/dist/assets.d.ts +13 -0
  41. package/dist/auth/GuestBanner.svelte +134 -0
  42. package/dist/auth/GuestBanner.svelte.d.ts +3 -0
  43. package/dist/auth/SignInWall.svelte +203 -0
  44. package/dist/auth/SignInWall.svelte.d.ts +7 -0
  45. package/dist/auth/auth.svelte.d.ts +69 -0
  46. package/dist/auth/auth.svelte.js +165 -0
  47. package/dist/auth/index.d.ts +2 -0
  48. package/dist/auth/index.js +1 -0
  49. package/dist/auth/types.d.ts +41 -0
  50. package/dist/auth/types.js +6 -0
  51. package/dist/build.d.ts +49 -0
  52. package/dist/build.js +236 -0
  53. package/dist/contract.d.ts +20 -0
  54. package/dist/contract.js +28 -0
  55. package/dist/createShell.d.ts +24 -0
  56. package/dist/createShell.js +131 -0
  57. package/dist/documents/backends.d.ts +17 -0
  58. package/dist/documents/backends.js +156 -0
  59. package/dist/documents/config.d.ts +7 -0
  60. package/dist/documents/config.js +27 -0
  61. package/dist/documents/handle.d.ts +6 -0
  62. package/dist/documents/handle.js +154 -0
  63. package/dist/documents/http-backend.d.ts +22 -0
  64. package/dist/documents/http-backend.js +78 -0
  65. package/dist/documents/index.d.ts +6 -0
  66. package/dist/documents/index.js +8 -0
  67. package/dist/documents/notifications.d.ts +9 -0
  68. package/dist/documents/notifications.js +39 -0
  69. package/dist/documents/types.d.ts +97 -0
  70. package/dist/documents/types.js +12 -0
  71. package/dist/env/client.d.ts +44 -0
  72. package/dist/env/client.js +106 -0
  73. package/dist/env/index.d.ts +2 -0
  74. package/dist/env/index.js +1 -0
  75. package/dist/env/types.d.ts +12 -0
  76. package/dist/env/types.js +8 -0
  77. package/dist/host-entry.d.ts +13 -0
  78. package/dist/host-entry.js +17 -0
  79. package/dist/host.d.ts +15 -0
  80. package/dist/host.js +86 -0
  81. package/dist/index.d.ts +4 -0
  82. package/dist/index.js +14 -0
  83. package/dist/layout/DragPreview.svelte +63 -0
  84. package/dist/layout/DragPreview.svelte.d.ts +3 -0
  85. package/dist/layout/LayoutRenderer.svelte +262 -0
  86. package/dist/layout/LayoutRenderer.svelte.d.ts +6 -0
  87. package/dist/layout/SlotContainer.svelte +140 -0
  88. package/dist/layout/SlotContainer.svelte.d.ts +8 -0
  89. package/dist/layout/SlotDropZone.svelte +122 -0
  90. package/dist/layout/SlotDropZone.svelte.d.ts +8 -0
  91. package/dist/layout/drag.svelte.d.ts +45 -0
  92. package/dist/layout/drag.svelte.js +200 -0
  93. package/dist/layout/inspection.d.ts +72 -0
  94. package/dist/layout/inspection.js +209 -0
  95. package/dist/layout/ops.d.ts +100 -0
  96. package/dist/layout/ops.js +310 -0
  97. package/dist/layout/slotHostPool.svelte.d.ts +36 -0
  98. package/dist/layout/slotHostPool.svelte.js +229 -0
  99. package/dist/layout/store.svelte.d.ts +39 -0
  100. package/dist/layout/store.svelte.js +153 -0
  101. package/dist/layout/tree-walk.d.ts +15 -0
  102. package/dist/layout/tree-walk.js +33 -0
  103. package/dist/layout/types.d.ts +108 -0
  104. package/dist/layout/types.js +25 -0
  105. package/dist/migrations/shell-rename.d.ts +16 -0
  106. package/dist/migrations/shell-rename.js +48 -0
  107. package/dist/overlays/ModalFrame.svelte +87 -0
  108. package/dist/overlays/ModalFrame.svelte.d.ts +10 -0
  109. package/dist/overlays/PopupFrame.svelte +85 -0
  110. package/dist/overlays/PopupFrame.svelte.d.ts +10 -0
  111. package/dist/overlays/ToastItem.svelte +77 -0
  112. package/dist/overlays/ToastItem.svelte.d.ts +9 -0
  113. package/dist/overlays/focusTrap.d.ts +1 -0
  114. package/dist/overlays/focusTrap.js +64 -0
  115. package/dist/overlays/modal.d.ts +9 -0
  116. package/dist/overlays/modal.js +141 -0
  117. package/dist/overlays/popup.d.ts +9 -0
  118. package/dist/overlays/popup.js +108 -0
  119. package/dist/overlays/roots.d.ts +4 -0
  120. package/dist/overlays/roots.js +31 -0
  121. package/dist/overlays/toast.d.ts +6 -0
  122. package/dist/overlays/toast.js +93 -0
  123. package/dist/overlays/types.d.ts +31 -0
  124. package/dist/overlays/types.js +15 -0
  125. package/dist/platform/index.d.ts +10 -0
  126. package/dist/platform/index.js +33 -0
  127. package/dist/platform/tauri-backend.d.ts +15 -0
  128. package/dist/platform/tauri-backend.js +58 -0
  129. package/dist/primitives/.gitkeep +0 -0
  130. package/dist/primitives/ResizableSplitter.svelte +333 -0
  131. package/dist/primitives/ResizableSplitter.svelte.d.ts +35 -0
  132. package/dist/primitives/TabbedPanel.svelte +305 -0
  133. package/dist/primitives/TabbedPanel.svelte.d.ts +50 -0
  134. package/dist/primitives/base.css +42 -0
  135. package/dist/registry/client.d.ts +74 -0
  136. package/dist/registry/client.js +117 -0
  137. package/dist/registry/index.d.ts +13 -0
  138. package/dist/registry/index.js +14 -0
  139. package/dist/registry/installer.d.ts +53 -0
  140. package/dist/registry/installer.js +168 -0
  141. package/dist/registry/integrity.d.ts +32 -0
  142. package/dist/registry/integrity.js +92 -0
  143. package/dist/registry/loader.d.ts +50 -0
  144. package/dist/registry/loader.js +145 -0
  145. package/dist/registry/schema.d.ts +47 -0
  146. package/dist/registry/schema.js +185 -0
  147. package/dist/registry/storage.d.ts +37 -0
  148. package/dist/registry/storage.js +101 -0
  149. package/dist/registry/types.d.ts +262 -0
  150. package/dist/registry/types.js +14 -0
  151. package/dist/server-shard/types.d.ts +67 -0
  152. package/dist/server-shard/types.js +13 -0
  153. package/dist/sh3core-shard/ShellHome.svelte +192 -0
  154. package/dist/sh3core-shard/ShellHome.svelte.d.ts +3 -0
  155. package/dist/sh3core-shard/ShellTitle.svelte +171 -0
  156. package/dist/sh3core-shard/ShellTitle.svelte.d.ts +3 -0
  157. package/dist/sh3core-shard/sh3coreShard.svelte.d.ts +2 -0
  158. package/dist/sh3core-shard/sh3coreShard.svelte.js +53 -0
  159. package/dist/shards/activate.svelte.d.ts +52 -0
  160. package/dist/shards/activate.svelte.js +186 -0
  161. package/dist/shards/registry.d.ts +4 -0
  162. package/dist/shards/registry.js +28 -0
  163. package/dist/shards/types.d.ts +207 -0
  164. package/dist/shards/types.js +20 -0
  165. package/dist/shell-shard/InputLine.svelte +133 -0
  166. package/dist/shell-shard/InputLine.svelte.d.ts +11 -0
  167. package/dist/shell-shard/ScrollbackView.svelte +47 -0
  168. package/dist/shell-shard/ScrollbackView.svelte.d.ts +7 -0
  169. package/dist/shell-shard/Terminal.svelte +122 -0
  170. package/dist/shell-shard/Terminal.svelte.d.ts +8 -0
  171. package/dist/shell-shard/entries/PromptEntry.svelte +25 -0
  172. package/dist/shell-shard/entries/PromptEntry.svelte.d.ts +7 -0
  173. package/dist/shell-shard/entries/RichEntry.svelte +19 -0
  174. package/dist/shell-shard/entries/RichEntry.svelte.d.ts +8 -0
  175. package/dist/shell-shard/entries/StatusEntry.svelte +22 -0
  176. package/dist/shell-shard/entries/StatusEntry.svelte.d.ts +7 -0
  177. package/dist/shell-shard/entries/TextEntry.svelte +25 -0
  178. package/dist/shell-shard/entries/TextEntry.svelte.d.ts +7 -0
  179. package/dist/shell-shard/manifest.d.ts +2 -0
  180. package/dist/shell-shard/manifest.js +11 -0
  181. package/dist/shell-shard/protocol.d.ts +90 -0
  182. package/dist/shell-shard/protocol.js +11 -0
  183. package/dist/shell-shard/registry.d.ts +69 -0
  184. package/dist/shell-shard/registry.js +47 -0
  185. package/dist/shell-shard/rich/AppCard.svelte +25 -0
  186. package/dist/shell-shard/rich/AppCard.svelte.d.ts +10 -0
  187. package/dist/shell-shard/rich/AppsTable.svelte +29 -0
  188. package/dist/shell-shard/rich/AppsTable.svelte.d.ts +12 -0
  189. package/dist/shell-shard/rich/EnvTable.svelte +27 -0
  190. package/dist/shell-shard/rich/EnvTable.svelte.d.ts +8 -0
  191. package/dist/shell-shard/rich/HelpTable.svelte +29 -0
  192. package/dist/shell-shard/rich/HelpTable.svelte.d.ts +12 -0
  193. package/dist/shell-shard/rich/HistoryList.svelte +37 -0
  194. package/dist/shell-shard/rich/HistoryList.svelte.d.ts +9 -0
  195. package/dist/shell-shard/rich/ShardsTable.svelte +28 -0
  196. package/dist/shell-shard/rich/ShardsTable.svelte.d.ts +12 -0
  197. package/dist/shell-shard/rich/ViewsTable.svelte +31 -0
  198. package/dist/shell-shard/rich/ViewsTable.svelte.d.ts +13 -0
  199. package/dist/shell-shard/rich/ZoneTree.svelte +19 -0
  200. package/dist/shell-shard/rich/ZoneTree.svelte.d.ts +8 -0
  201. package/dist/shell-shard/rich/ZonesTable.svelte +27 -0
  202. package/dist/shell-shard/rich/ZonesTable.svelte.d.ts +11 -0
  203. package/dist/shell-shard/scrollback.svelte.d.ts +36 -0
  204. package/dist/shell-shard/scrollback.svelte.js +43 -0
  205. package/dist/shell-shard/session-client.svelte.d.ts +23 -0
  206. package/dist/shell-shard/session-client.svelte.js +120 -0
  207. package/dist/shell-shard/shellShard.svelte.d.ts +2 -0
  208. package/dist/shell-shard/shellShard.svelte.js +139 -0
  209. package/dist/shell-shard/verbs/apps.d.ts +3 -0
  210. package/dist/shell-shard/verbs/apps.js +50 -0
  211. package/dist/shell-shard/verbs/clear.d.ts +2 -0
  212. package/dist/shell-shard/verbs/clear.js +7 -0
  213. package/dist/shell-shard/verbs/help.d.ts +2 -0
  214. package/dist/shell-shard/verbs/help.js +21 -0
  215. package/dist/shell-shard/verbs/history.d.ts +2 -0
  216. package/dist/shell-shard/verbs/history.js +20 -0
  217. package/dist/shell-shard/verbs/index.d.ts +2 -0
  218. package/dist/shell-shard/verbs/index.js +29 -0
  219. package/dist/shell-shard/verbs/session.d.ts +5 -0
  220. package/dist/shell-shard/verbs/session.js +65 -0
  221. package/dist/shell-shard/verbs/shards.d.ts +2 -0
  222. package/dist/shell-shard/verbs/shards.js +14 -0
  223. package/dist/shell-shard/verbs/views.d.ts +4 -0
  224. package/dist/shell-shard/verbs/views.js +90 -0
  225. package/dist/shell-shard/verbs/zones.d.ts +3 -0
  226. package/dist/shell-shard/verbs/zones.js +38 -0
  227. package/dist/shellRuntime.svelte.d.ts +27 -0
  228. package/dist/shellRuntime.svelte.js +27 -0
  229. package/dist/state/backends.d.ts +26 -0
  230. package/dist/state/backends.js +99 -0
  231. package/dist/state/manage.d.ts +14 -0
  232. package/dist/state/manage.js +40 -0
  233. package/dist/state/types.d.ts +55 -0
  234. package/dist/state/types.js +17 -0
  235. package/dist/state/zones.svelte.d.ts +53 -0
  236. package/dist/state/zones.svelte.js +141 -0
  237. package/dist/theme.d.ts +28 -0
  238. package/dist/theme.js +92 -0
  239. package/dist/tokens.css +102 -0
  240. package/dist/version.d.ts +2 -0
  241. package/dist/version.js +2 -0
  242. package/package.json +60 -0
@@ -0,0 +1,522 @@
1
+ <script lang="ts">
2
+ /*
3
+ * StoreView — browse catalog view for the store shard.
4
+ *
5
+ * Displays a searchable, filterable grid of packages from configured
6
+ * registries. Each card shows package metadata and an install button.
7
+ */
8
+
9
+ import { storeContext } from './storeShard.svelte';
10
+ import { fetchBundle, buildPackageMeta } from '../../registry/client';
11
+ import { installPackage } from '../../registry/installer';
12
+ import { serverInstallPackage } from '../../env/client';
13
+ import { contract } from '../../contract';
14
+ import type { ResolvedPackage } from '../../registry/client';
15
+ import type { InstalledPackage } from '../../registry/types';
16
+
17
+ let search = $state('');
18
+ let typeFilter = $state<'all' | 'shard' | 'app'>('all');
19
+ let installingIds = $state<Set<string>>(new Set());
20
+ let updatingIds = $state<Set<string>>(new Set());
21
+ let installError = $state<string | null>(null);
22
+ let newRegistryUrl = $state('');
23
+
24
+ const ctx = storeContext;
25
+
26
+ async function handleAddRegistry() {
27
+ const url = newRegistryUrl.trim();
28
+ if (!url) return;
29
+ if (ctx.env.registries.includes(url)) return;
30
+ try {
31
+ await ctx.addRegistry(url);
32
+ newRegistryUrl = '';
33
+ ctx.refreshCatalog();
34
+ ctx.refreshInstalled();
35
+ } catch (err) {
36
+ installError = err instanceof Error ? err.message : String(err);
37
+ }
38
+ }
39
+
40
+ async function handleRemoveRegistry(url: string) {
41
+ try {
42
+ await ctx.removeRegistry(url);
43
+ ctx.refreshCatalog();
44
+ } catch (err) {
45
+ installError = err instanceof Error ? err.message : String(err);
46
+ }
47
+ }
48
+
49
+ const filtered = $derived.by(() => {
50
+ const q = search.toLowerCase().trim();
51
+ return ctx.state.ephemeral.catalog.filter((pkg: ResolvedPackage) => {
52
+ if (typeFilter !== 'all' && pkg.entry.type !== typeFilter) return false;
53
+ if (!q) return true;
54
+ return (
55
+ pkg.entry.id.toLowerCase().includes(q) ||
56
+ pkg.entry.label.toLowerCase().includes(q) ||
57
+ pkg.entry.description.toLowerCase().includes(q)
58
+ );
59
+ });
60
+ });
61
+
62
+ function isInstalled(id: string): boolean {
63
+ return ctx.state.ephemeral.installed.some((p: InstalledPackage) => p.id === id);
64
+ }
65
+
66
+ function hasContractMismatch(pkg: ResolvedPackage): boolean {
67
+ return String(pkg.latest.contractVersion) !== String(contract.version);
68
+ }
69
+
70
+ function hasUpdate(id: string): boolean {
71
+ return id in ctx.state.ephemeral.updatable;
72
+ }
73
+
74
+ function installedVersion(id: string): string {
75
+ return ctx.state.ephemeral.installed.find((p: InstalledPackage) => p.id === id)?.version ?? '';
76
+ }
77
+
78
+ async function handleUpdate(id: string) {
79
+ if (updatingIds.has(id)) return;
80
+
81
+ updatingIds = new Set([...updatingIds, id]);
82
+ installError = null;
83
+
84
+ try {
85
+ await ctx.updatePackage(id);
86
+ } catch (err) {
87
+ installError = err instanceof Error ? err.message : String(err);
88
+ } finally {
89
+ const next = new Set(updatingIds);
90
+ next.delete(id);
91
+ updatingIds = next;
92
+ }
93
+ }
94
+
95
+ async function handleInstall(pkg: ResolvedPackage) {
96
+ const id = pkg.entry.id;
97
+ if (installingIds.has(id)) return;
98
+
99
+ installingIds = new Set([...installingIds, id]);
100
+ installError = null;
101
+
102
+ try {
103
+ // 1. Fetch and integrity-verify the bundle from the registry.
104
+ const bundle = await fetchBundle(pkg.latest, pkg.sourceRegistry);
105
+ const meta = buildPackageMeta(pkg, pkg.latest);
106
+
107
+ // 2. Upload to server for persistent storage.
108
+ const manifest = {
109
+ id: meta.id,
110
+ type: meta.type,
111
+ label: pkg.entry.label,
112
+ version: meta.version,
113
+ contractVersion: meta.contractVersion,
114
+ sourceRegistry: meta.sourceRegistry,
115
+ installedAt: new Date().toISOString(),
116
+ };
117
+ const serverResult = await serverInstallPackage(manifest, bundle);
118
+ if (!serverResult.ok) {
119
+ installError = serverResult.error ?? 'Server install failed';
120
+ return;
121
+ }
122
+
123
+ // 3. Also install locally for immediate hot-load.
124
+ const result = await installPackage(bundle, meta);
125
+ if (!result.success) {
126
+ console.warn(`[sh3-store] Server install ok but local hot-load failed: ${result.error}`);
127
+ }
128
+
129
+ await ctx.refreshInstalled();
130
+ } catch (err) {
131
+ installError = err instanceof Error ? err.message : String(err);
132
+ } finally {
133
+ const next = new Set(installingIds);
134
+ next.delete(id);
135
+ installingIds = next;
136
+ }
137
+ }
138
+
139
+ function handleRefresh() {
140
+ ctx.refreshCatalog();
141
+ ctx.refreshInstalled();
142
+ }
143
+ </script>
144
+
145
+ <div class="store-view">
146
+ <header class="store-header">
147
+ <h2>Package Store</h2>
148
+ <div class="store-controls">
149
+ <input
150
+ class="store-search"
151
+ type="text"
152
+ placeholder="Search packages..."
153
+ bind:value={search}
154
+ />
155
+ <select class="store-filter" bind:value={typeFilter}>
156
+ <option value="all">All</option>
157
+ <option value="shard">Shards</option>
158
+ <option value="app">Apps</option>
159
+ </select>
160
+ <button
161
+ class="store-refresh"
162
+ onclick={handleRefresh}
163
+ disabled={ctx.state.ephemeral.loading}
164
+ >
165
+ {ctx.state.ephemeral.loading ? 'Loading...' : 'Refresh'}
166
+ </button>
167
+ </div>
168
+ </header>
169
+
170
+ {#if ctx.isAdmin && ctx.env.registries.length > 0}
171
+ <div class="store-registries">
172
+ {#each ctx.env.registries as url}
173
+ <div class="store-registry-entry">
174
+ <span class="store-registry-url">{url}</span>
175
+ <button class="store-registry-remove" onclick={() => handleRemoveRegistry(url)}>
176
+ Remove
177
+ </button>
178
+ </div>
179
+ {/each}
180
+ </div>
181
+ {/if}
182
+
183
+ {#if ctx.isAdmin}
184
+ <form class="store-add-registry" onsubmit={(e) => { e.preventDefault(); handleAddRegistry(); }}>
185
+ <input
186
+ class="store-registry-input"
187
+ type="url"
188
+ placeholder="Registry URL (e.g. https://sh3.example.com/registry.json)"
189
+ bind:value={newRegistryUrl}
190
+ />
191
+ <button type="submit" class="store-add-btn" disabled={!newRegistryUrl.trim()}>
192
+ Add
193
+ </button>
194
+ </form>
195
+ {/if}
196
+
197
+ {#if ctx.state.ephemeral.error}
198
+ <div class="store-error">{ctx.state.ephemeral.error}</div>
199
+ {/if}
200
+
201
+ {#if installError}
202
+ <div class="store-error">{installError}</div>
203
+ {/if}
204
+
205
+ <div class="store-grid">
206
+ {#each filtered as pkg (pkg.entry.id)}
207
+ {@const installed = isInstalled(pkg.entry.id)}
208
+ {@const mismatch = hasContractMismatch(pkg)}
209
+ {@const installing = installingIds.has(pkg.entry.id)}
210
+ {@const updatable = hasUpdate(pkg.entry.id)}
211
+ {@const updating = updatingIds.has(pkg.entry.id)}
212
+ <div class="store-card">
213
+ <div class="store-card-header">
214
+ <div class="store-card-icon">
215
+ {#if pkg.entry.icon}
216
+ <img src={pkg.entry.icon} alt="" class="store-icon-img" />
217
+ {:else}
218
+ <span class="store-icon-placeholder">
219
+ {pkg.entry.type === 'shard' ? 'S' : 'A'}
220
+ </span>
221
+ {/if}
222
+ </div>
223
+ <div class="store-card-title">
224
+ <span class="store-card-label">{pkg.entry.label}</span>
225
+ <span class="store-card-badge" class:badge-shard={pkg.entry.type === 'shard'} class:badge-app={pkg.entry.type === 'app'}>
226
+ {pkg.entry.type}
227
+ </span>
228
+ <span class="store-card-version">{pkg.latest.version}</span>
229
+ </div>
230
+ </div>
231
+ <p class="store-card-desc">{pkg.entry.description}</p>
232
+ <div class="store-card-author">{pkg.entry.author.name}</div>
233
+ {#if mismatch}
234
+ <div class="store-card-warning">
235
+ Contract mismatch: package targets v{pkg.latest.contractVersion}, running v{contract.version}
236
+ </div>
237
+ {/if}
238
+ <div class="store-card-actions">
239
+ {#if installed && updatable}
240
+ <button
241
+ class="store-update-btn"
242
+ onclick={() => handleUpdate(pkg.entry.id)}
243
+ disabled={updating}
244
+ >
245
+ {updating ? 'Updating...' : `Update ${installedVersion(pkg.entry.id)} -> ${pkg.latest.version}`}
246
+ </button>
247
+ {:else if installed}
248
+ <span class="store-installed-label">Installed</span>
249
+ {:else}
250
+ <button
251
+ class="store-install-btn"
252
+ onclick={() => handleInstall(pkg)}
253
+ disabled={installing}
254
+ >
255
+ {installing ? 'Installing...' : 'Install'}
256
+ </button>
257
+ {/if}
258
+ </div>
259
+ </div>
260
+ {/each}
261
+ </div>
262
+
263
+ {#if !ctx.state.ephemeral.loading && filtered.length === 0}
264
+ <div class="store-empty">
265
+ {#if ctx.env.registries.length === 0}
266
+ No packages found. {#if ctx.isAdmin}Add a registry URL above to get started.{:else}No registries configured.{/if}
267
+ {:else}
268
+ No packages match the current filter.
269
+ {/if}
270
+ </div>
271
+ {/if}
272
+ </div>
273
+
274
+ <style>
275
+ .store-view {
276
+ font-family: var(--shell-font-ui);
277
+ color: var(--shell-fg, #e0e0e0);
278
+ background: var(--shell-bg, #1e1e1e);
279
+ padding: 16px;
280
+ height: 100%;
281
+ overflow-y: auto;
282
+ box-sizing: border-box;
283
+ }
284
+ .store-header {
285
+ margin-bottom: 16px;
286
+ }
287
+ .store-header h2 {
288
+ margin: 0 0 8px 0;
289
+ font-size: 1.25rem;
290
+ font-weight: 600;
291
+ }
292
+ .store-controls {
293
+ display: flex;
294
+ gap: 8px;
295
+ flex-wrap: wrap;
296
+ }
297
+ .store-search {
298
+ flex: 1;
299
+ min-width: 160px;
300
+ padding: 6px 10px;
301
+ background: var(--shell-input-bg, #2a2a2a);
302
+ color: var(--shell-fg, #e0e0e0);
303
+ border: 1px solid var(--shell-border, #444);
304
+ border-radius: var(--shell-radius);
305
+ font-family: inherit;
306
+ font-size: 0.875rem;
307
+ }
308
+ .store-search::placeholder {
309
+ color: var(--shell-fg-muted, #888);
310
+ }
311
+ .store-filter {
312
+ padding: 6px 10px;
313
+ background: var(--shell-input-bg, #2a2a2a);
314
+ color: var(--shell-fg, #e0e0e0);
315
+ border: 1px solid var(--shell-border, #444);
316
+ border-radius: var(--shell-radius);
317
+ font-family: inherit;
318
+ font-size: 0.875rem;
319
+ }
320
+ .store-refresh:disabled {
321
+ opacity: 0.6;
322
+ cursor: not-allowed;
323
+ }
324
+ .store-error {
325
+ padding: 8px 12px;
326
+ margin-bottom: 12px;
327
+ background: color-mix(in srgb, var(--shell-error, #d32f2f) 15%, transparent);
328
+ color: var(--shell-error, #d32f2f);
329
+ border: 1px solid var(--shell-error, #d32f2f);
330
+ border-radius: var(--shell-radius);
331
+ font-size: 0.8125rem;
332
+ }
333
+ .store-grid {
334
+ display: grid;
335
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
336
+ gap: 12px;
337
+ }
338
+ .store-card {
339
+ background: var(--shell-input-bg, #2a2a2a);
340
+ border: 1px solid var(--shell-border, #444);
341
+ border-radius: var(--shell-radius-md);
342
+ padding: 14px;
343
+ display: flex;
344
+ flex-direction: column;
345
+ gap: 8px;
346
+ }
347
+ .store-card:hover {
348
+ border-color: var(--shell-accent, #007acc);
349
+ }
350
+ .store-card-header {
351
+ display: flex;
352
+ align-items: center;
353
+ gap: 10px;
354
+ }
355
+ .store-card-icon {
356
+ width: 36px;
357
+ height: 36px;
358
+ flex-shrink: 0;
359
+ display: flex;
360
+ align-items: center;
361
+ justify-content: center;
362
+ }
363
+ .store-icon-img {
364
+ width: 36px;
365
+ height: 36px;
366
+ border-radius: var(--shell-radius);
367
+ object-fit: cover;
368
+ }
369
+ .store-icon-placeholder {
370
+ width: 36px;
371
+ height: 36px;
372
+ display: flex;
373
+ align-items: center;
374
+ justify-content: center;
375
+ background: var(--shell-accent, #007acc);
376
+ color: #fff;
377
+ border-radius: var(--shell-radius);
378
+ font-weight: 700;
379
+ font-size: 1rem;
380
+ }
381
+ .store-card-title {
382
+ display: flex;
383
+ align-items: center;
384
+ gap: 6px;
385
+ flex-wrap: wrap;
386
+ }
387
+ .store-card-label {
388
+ font-weight: 600;
389
+ font-size: 0.9375rem;
390
+ }
391
+ .store-card-badge {
392
+ font-size: 0.6875rem;
393
+ padding: 1px 6px;
394
+ border-radius: var(--shell-radius-sm);
395
+ text-transform: uppercase;
396
+ font-weight: 600;
397
+ letter-spacing: 0.04em;
398
+ }
399
+ .badge-shard {
400
+ background: color-mix(in srgb, var(--shell-accent, #007acc) 25%, transparent);
401
+ color: var(--shell-accent, #007acc);
402
+ }
403
+ .badge-app {
404
+ background: color-mix(in srgb, var(--shell-success, #4caf50) 25%, transparent);
405
+ color: var(--shell-success, #4caf50);
406
+ }
407
+ .store-card-version {
408
+ font-size: 0.75rem;
409
+ color: var(--shell-fg-muted, #888);
410
+ }
411
+ .store-card-desc {
412
+ margin: 0;
413
+ font-size: 0.8125rem;
414
+ color: var(--shell-fg-muted, #888);
415
+ line-height: 1.4;
416
+ }
417
+ .store-card-author {
418
+ font-size: 0.75rem;
419
+ color: var(--shell-fg-muted, #888);
420
+ }
421
+ .store-card-warning {
422
+ font-size: 0.75rem;
423
+ color: var(--shell-warning, #ff9800);
424
+ padding: 4px 8px;
425
+ background: color-mix(in srgb, var(--shell-warning, #ff9800) 10%, transparent);
426
+ border-radius: var(--shell-radius-sm);
427
+ }
428
+ .store-card-actions {
429
+ margin-top: auto;
430
+ display: flex;
431
+ justify-content: flex-end;
432
+ }
433
+ .store-install-btn {
434
+ padding: 5px 14px;
435
+ font-size: 0.8125rem;
436
+ }
437
+ .store-install-btn:disabled {
438
+ opacity: 0.6;
439
+ cursor: not-allowed;
440
+ }
441
+ .store-installed-label {
442
+ font-size: 0.8125rem;
443
+ color: var(--shell-success, #4caf50);
444
+ font-weight: 600;
445
+ }
446
+ .store-update-btn {
447
+ padding: 5px 14px;
448
+ background: var(--shell-warning, #ff9800);
449
+ font-size: 0.8125rem;
450
+ }
451
+ .store-update-btn:hover:not(:disabled) {
452
+ filter: brightness(1.1);
453
+ }
454
+ .store-update-btn:disabled {
455
+ opacity: 0.6;
456
+ cursor: not-allowed;
457
+ }
458
+ .store-empty {
459
+ text-align: center;
460
+ padding: 32px 16px;
461
+ color: var(--shell-fg-muted, #888);
462
+ font-size: 0.875rem;
463
+ }
464
+ .store-registries {
465
+ display: flex;
466
+ flex-direction: column;
467
+ gap: 4px;
468
+ margin-bottom: 8px;
469
+ }
470
+ .store-registry-entry {
471
+ display: flex;
472
+ align-items: center;
473
+ justify-content: space-between;
474
+ padding: 4px 8px;
475
+ background: var(--shell-input-bg, #2a2a2a);
476
+ border: 1px solid var(--shell-border, #444);
477
+ border-radius: var(--shell-radius);
478
+ font-size: 0.8125rem;
479
+ }
480
+ .store-registry-url {
481
+ overflow: hidden;
482
+ text-overflow: ellipsis;
483
+ white-space: nowrap;
484
+ color: var(--shell-fg-muted, #888);
485
+ }
486
+ .store-registry-remove {
487
+ padding: 2px 8px;
488
+ background: transparent;
489
+ color: var(--shell-error, #d32f2f);
490
+ border: 1px solid var(--shell-error, #d32f2f);
491
+ border-radius: var(--shell-radius-sm);
492
+ font-size: 0.75rem;
493
+ flex-shrink: 0;
494
+ margin-left: 8px;
495
+ }
496
+ .store-add-registry {
497
+ display: flex;
498
+ gap: 8px;
499
+ margin-bottom: 12px;
500
+ }
501
+ .store-registry-input {
502
+ flex: 1;
503
+ padding: 6px 10px;
504
+ background: var(--shell-input-bg, #2a2a2a);
505
+ color: var(--shell-fg, #e0e0e0);
506
+ border: 1px solid var(--shell-border, #444);
507
+ border-radius: var(--shell-radius);
508
+ font-family: inherit;
509
+ font-size: 0.8125rem;
510
+ }
511
+ .store-registry-input::placeholder {
512
+ color: var(--shell-fg-muted, #888);
513
+ }
514
+ .store-add-btn {
515
+ font-size: 0.8125rem;
516
+ white-space: nowrap;
517
+ }
518
+ .store-add-btn:disabled {
519
+ opacity: 0.6;
520
+ cursor: not-allowed;
521
+ }
522
+ </style>
@@ -0,0 +1,3 @@
1
+ declare const StoreView: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type StoreView = ReturnType<typeof StoreView>;
3
+ export default StoreView;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Built-in Store app — composes the sh3-store shard views into a
3
+ * management interface for browsing, installing, and uninstalling
4
+ * packages.
5
+ *
6
+ * Framework-shipped: registered in host.ts during bootstrap.
7
+ * Admin-gated via manifest flag (ADR-011).
8
+ */
9
+ import type { App } from '../../apps/types';
10
+ export declare const storeApp: App;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Built-in Store app — composes the sh3-store shard views into a
3
+ * management interface for browsing, installing, and uninstalling
4
+ * packages.
5
+ *
6
+ * Framework-shipped: registered in host.ts during bootstrap.
7
+ * Admin-gated via manifest flag (ADR-011).
8
+ */
9
+ export const storeApp = {
10
+ manifest: {
11
+ id: 'sh3-store-app',
12
+ label: 'Package Store',
13
+ version: '0.2.1',
14
+ requiredShards: ['sh3-store'],
15
+ layoutVersion: 1,
16
+ admin: true,
17
+ },
18
+ initialLayout: {
19
+ type: 'tabs',
20
+ activeTab: 0,
21
+ tabs: [
22
+ { slotId: 'store.browse', viewId: 'sh3-store:browse', label: 'Browse' },
23
+ { slotId: 'store.installed', viewId: 'sh3-store:installed', label: 'Installed' },
24
+ ],
25
+ },
26
+ };
@@ -0,0 +1,38 @@
1
+ import type { Shard } from '../../shards/types';
2
+ import type { StateZones } from '../../state/zones.svelte';
3
+ import type { ResolvedPackage } from '../../registry/client';
4
+ import type { InstalledPackage } from '../../registry/types';
5
+ import type { EnvState } from '../../env/types';
6
+ /** Env state shape — server-authoritative config. */
7
+ interface StoreEnvSchema {
8
+ [key: string]: unknown;
9
+ registries: string[];
10
+ }
11
+ /** Schema shape for state zone typing. */
12
+ interface StoreZoneSchema {
13
+ ephemeral: {
14
+ catalog: ResolvedPackage[];
15
+ installed: InstalledPackage[];
16
+ updatable: Record<string, ResolvedPackage>;
17
+ loading: boolean;
18
+ error: string | null;
19
+ };
20
+ }
21
+ /** Reactive context exposed to the view components. */
22
+ export interface StoreContext {
23
+ env: EnvState<StoreEnvSchema>;
24
+ state: StateZones<StoreZoneSchema>;
25
+ isAdmin: boolean;
26
+ refreshCatalog(): Promise<void>;
27
+ refreshInstalled(): Promise<void>;
28
+ updatePackage(id: string): Promise<void>;
29
+ addRegistry(url: string): Promise<void>;
30
+ removeRegistry(url: string): Promise<void>;
31
+ }
32
+ /**
33
+ * Module-level context set during activate(). Imported by the Svelte
34
+ * view components so they can read/write store state and trigger refreshes.
35
+ */
36
+ export declare let storeContext: StoreContext;
37
+ export declare const storeShard: Shard;
38
+ export {};