sh3-core 0.1.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 (134) hide show
  1. package/dist/Shell.svelte +185 -0
  2. package/dist/Shell.svelte.d.ts +4 -0
  3. package/dist/api.d.ts +22 -0
  4. package/dist/api.js +45 -0
  5. package/dist/apps/lifecycle.d.ts +37 -0
  6. package/dist/apps/lifecycle.js +153 -0
  7. package/dist/apps/registry.svelte.d.ts +37 -0
  8. package/dist/apps/registry.svelte.js +60 -0
  9. package/dist/apps/types.d.ts +61 -0
  10. package/dist/apps/types.js +10 -0
  11. package/dist/assets/icons.svg +1119 -0
  12. package/dist/auth/auth.svelte.d.ts +44 -0
  13. package/dist/auth/auth.svelte.js +119 -0
  14. package/dist/auth/index.d.ts +1 -0
  15. package/dist/auth/index.js +1 -0
  16. package/dist/build.d.ts +29 -0
  17. package/dist/build.js +85 -0
  18. package/dist/contract.d.ts +20 -0
  19. package/dist/contract.js +28 -0
  20. package/dist/documents/backends.d.ts +17 -0
  21. package/dist/documents/backends.js +156 -0
  22. package/dist/documents/config.d.ts +7 -0
  23. package/dist/documents/config.js +27 -0
  24. package/dist/documents/handle.d.ts +6 -0
  25. package/dist/documents/handle.js +154 -0
  26. package/dist/documents/http-backend.d.ts +22 -0
  27. package/dist/documents/http-backend.js +78 -0
  28. package/dist/documents/index.d.ts +6 -0
  29. package/dist/documents/index.js +8 -0
  30. package/dist/documents/notifications.d.ts +9 -0
  31. package/dist/documents/notifications.js +39 -0
  32. package/dist/documents/types.d.ts +97 -0
  33. package/dist/documents/types.js +12 -0
  34. package/dist/host-entry.d.ts +9 -0
  35. package/dist/host-entry.js +15 -0
  36. package/dist/host.d.ts +13 -0
  37. package/dist/host.js +73 -0
  38. package/dist/index.d.ts +2 -0
  39. package/dist/index.js +13 -0
  40. package/dist/layout/DragPreview.svelte +63 -0
  41. package/dist/layout/DragPreview.svelte.d.ts +3 -0
  42. package/dist/layout/LayoutRenderer.svelte +260 -0
  43. package/dist/layout/LayoutRenderer.svelte.d.ts +6 -0
  44. package/dist/layout/SlotContainer.svelte +140 -0
  45. package/dist/layout/SlotContainer.svelte.d.ts +8 -0
  46. package/dist/layout/SlotDropZone.svelte +122 -0
  47. package/dist/layout/SlotDropZone.svelte.d.ts +8 -0
  48. package/dist/layout/drag.svelte.d.ts +45 -0
  49. package/dist/layout/drag.svelte.js +191 -0
  50. package/dist/layout/inspection.d.ts +52 -0
  51. package/dist/layout/inspection.js +157 -0
  52. package/dist/layout/ops.d.ts +78 -0
  53. package/dist/layout/ops.js +281 -0
  54. package/dist/layout/slotHostPool.svelte.d.ts +36 -0
  55. package/dist/layout/slotHostPool.svelte.js +229 -0
  56. package/dist/layout/store.svelte.d.ts +39 -0
  57. package/dist/layout/store.svelte.js +150 -0
  58. package/dist/layout/tree-walk.d.ts +15 -0
  59. package/dist/layout/tree-walk.js +33 -0
  60. package/dist/layout/types.d.ts +108 -0
  61. package/dist/layout/types.js +25 -0
  62. package/dist/overlays/ModalFrame.svelte +87 -0
  63. package/dist/overlays/ModalFrame.svelte.d.ts +10 -0
  64. package/dist/overlays/PopupFrame.svelte +85 -0
  65. package/dist/overlays/PopupFrame.svelte.d.ts +10 -0
  66. package/dist/overlays/ToastItem.svelte +77 -0
  67. package/dist/overlays/ToastItem.svelte.d.ts +9 -0
  68. package/dist/overlays/focusTrap.d.ts +1 -0
  69. package/dist/overlays/focusTrap.js +64 -0
  70. package/dist/overlays/modal.d.ts +9 -0
  71. package/dist/overlays/modal.js +141 -0
  72. package/dist/overlays/popup.d.ts +9 -0
  73. package/dist/overlays/popup.js +108 -0
  74. package/dist/overlays/roots.d.ts +4 -0
  75. package/dist/overlays/roots.js +31 -0
  76. package/dist/overlays/toast.d.ts +6 -0
  77. package/dist/overlays/toast.js +93 -0
  78. package/dist/overlays/types.d.ts +31 -0
  79. package/dist/overlays/types.js +15 -0
  80. package/dist/primitives/.gitkeep +0 -0
  81. package/dist/primitives/ResizableSplitter.svelte +333 -0
  82. package/dist/primitives/ResizableSplitter.svelte.d.ts +35 -0
  83. package/dist/primitives/TabbedPanel.svelte +305 -0
  84. package/dist/primitives/TabbedPanel.svelte.d.ts +50 -0
  85. package/dist/registry/client.d.ts +74 -0
  86. package/dist/registry/client.js +118 -0
  87. package/dist/registry/index.d.ts +13 -0
  88. package/dist/registry/index.js +14 -0
  89. package/dist/registry/installer.d.ts +53 -0
  90. package/dist/registry/installer.js +170 -0
  91. package/dist/registry/integrity.d.ts +32 -0
  92. package/dist/registry/integrity.js +92 -0
  93. package/dist/registry/loader.d.ts +50 -0
  94. package/dist/registry/loader.js +145 -0
  95. package/dist/registry/schema.d.ts +47 -0
  96. package/dist/registry/schema.js +180 -0
  97. package/dist/registry/storage.d.ts +37 -0
  98. package/dist/registry/storage.js +101 -0
  99. package/dist/registry/types.d.ts +245 -0
  100. package/dist/registry/types.js +14 -0
  101. package/dist/registry-shard/RegistryView.svelte +561 -0
  102. package/dist/registry-shard/RegistryView.svelte.d.ts +3 -0
  103. package/dist/registry-shard/registryApp.d.ts +10 -0
  104. package/dist/registry-shard/registryApp.js +24 -0
  105. package/dist/registry-shard/registryShard.svelte.d.ts +45 -0
  106. package/dist/registry-shard/registryShard.svelte.js +125 -0
  107. package/dist/shards/activate.svelte.d.ts +45 -0
  108. package/dist/shards/activate.svelte.js +124 -0
  109. package/dist/shards/registry.d.ts +4 -0
  110. package/dist/shards/registry.js +28 -0
  111. package/dist/shards/types.d.ts +155 -0
  112. package/dist/shards/types.js +20 -0
  113. package/dist/shell-shard/ShellHome.svelte +285 -0
  114. package/dist/shell-shard/ShellHome.svelte.d.ts +3 -0
  115. package/dist/shell-shard/shellShard.svelte.d.ts +2 -0
  116. package/dist/shell-shard/shellShard.svelte.js +47 -0
  117. package/dist/shellRuntime.svelte.d.ts +27 -0
  118. package/dist/shellRuntime.svelte.js +27 -0
  119. package/dist/state/backends.d.ts +26 -0
  120. package/dist/state/backends.js +99 -0
  121. package/dist/state/types.d.ts +38 -0
  122. package/dist/state/types.js +15 -0
  123. package/dist/state/zones.svelte.d.ts +52 -0
  124. package/dist/state/zones.svelte.js +141 -0
  125. package/dist/store/InstalledView.svelte +201 -0
  126. package/dist/store/InstalledView.svelte.d.ts +3 -0
  127. package/dist/store/StoreView.svelte +470 -0
  128. package/dist/store/StoreView.svelte.d.ts +3 -0
  129. package/dist/store/storeApp.d.ts +11 -0
  130. package/dist/store/storeApp.js +26 -0
  131. package/dist/store/storeShard.svelte.d.ts +29 -0
  132. package/dist/store/storeShard.svelte.js +99 -0
  133. package/dist/tokens.css +79 -0
  134. package/package.json +50 -0
@@ -0,0 +1,561 @@
1
+ <script lang="ts">
2
+ /*
3
+ * RegistryView — single view for the registry manager shard.
4
+ *
5
+ * Sections: header, collapsible publish form, package card list with
6
+ * inline edit/update/delete actions, empty state, error banner.
7
+ */
8
+
9
+ import { registryContext, type RegistryPackage } from './registryShard.svelte';
10
+
11
+ const ctx = registryContext;
12
+
13
+ // ---- Publish form state ----
14
+ let publishId = $state('');
15
+ let publishType = $state<'shard' | 'app'>('shard');
16
+ let publishLabel = $state('');
17
+ let publishVersion = $state('1.0.0');
18
+ let publishDesc = $state('');
19
+ let publishAuthor = $state('');
20
+ let publishFile = $state<File | null>(null);
21
+ let publishing = $state(false);
22
+ let publishError = $state<string | null>(null);
23
+ let publishSuccess = $state(false);
24
+ let publishDetailsOpen = $state(false);
25
+
26
+ // ---- Card action state ----
27
+ // Only one expanded action at a time. Format: "edit:pkgId" | "update:pkgId" | "delete:pkgId" | null
28
+ let expandedAction = $state<string | null>(null);
29
+
30
+ // ---- Edit form state ----
31
+ let editLabel = $state('');
32
+ let editDesc = $state('');
33
+ let editAuthor = $state('');
34
+ let editSaving = $state(false);
35
+ let editError = $state<string | null>(null);
36
+
37
+ // ---- Update form state ----
38
+ let updateVersion = $state('');
39
+ let updateLabel = $state('');
40
+ let updateDesc = $state('');
41
+ let updateAuthor = $state('');
42
+ let updateFile = $state<File | null>(null);
43
+ let updatePublishing = $state(false);
44
+ let updateError = $state<string | null>(null);
45
+
46
+ // ---- Delete state ----
47
+ let deleteInProgress = $state(false);
48
+ let deleteError = $state<string | null>(null);
49
+
50
+ // ---- Publish handlers ----
51
+ function onPublishFileSelect(e: Event) {
52
+ const input = e.target as HTMLInputElement;
53
+ publishFile = input.files?.[0] ?? null;
54
+ }
55
+
56
+ async function handlePublish() {
57
+ if (!publishFile) return;
58
+ publishing = true;
59
+ publishError = null;
60
+ publishSuccess = false;
61
+
62
+ try {
63
+ const form = new FormData();
64
+ form.append('bundle', publishFile);
65
+ form.append('id', publishId);
66
+ form.append('type', publishType);
67
+ form.append('label', publishLabel);
68
+ form.append('description', publishDesc);
69
+ form.append('version', publishVersion);
70
+ form.append('author', publishAuthor);
71
+
72
+ await ctx.publishPackage(form);
73
+
74
+ // Reset form
75
+ publishId = '';
76
+ publishLabel = '';
77
+ publishDesc = '';
78
+ publishVersion = '1.0.0';
79
+ publishAuthor = '';
80
+ publishFile = null;
81
+ publishSuccess = true;
82
+ publishDetailsOpen = false;
83
+ } catch (err) {
84
+ publishError = err instanceof Error ? err.message : String(err);
85
+ } finally {
86
+ publishing = false;
87
+ }
88
+ }
89
+
90
+ // ---- Edit handlers ----
91
+ function startEdit(pkg: RegistryPackage) {
92
+ expandedAction = `edit:${pkg.id}`;
93
+ editLabel = pkg.label;
94
+ editDesc = pkg.description;
95
+ editAuthor = pkg.author.name;
96
+ editError = null;
97
+ }
98
+
99
+ async function handleEditSave(pkgId: string) {
100
+ editSaving = true;
101
+ editError = null;
102
+ try {
103
+ await ctx.patchPackage(pkgId, {
104
+ label: editLabel,
105
+ description: editDesc,
106
+ author: editAuthor,
107
+ });
108
+ expandedAction = null;
109
+ } catch (err) {
110
+ editError = err instanceof Error ? err.message : String(err);
111
+ } finally {
112
+ editSaving = false;
113
+ }
114
+ }
115
+
116
+ // ---- Update handlers ----
117
+ function startUpdate(pkg: RegistryPackage) {
118
+ expandedAction = `update:${pkg.id}`;
119
+ updateVersion = pkg.versions[0]?.version ?? '1.0.0';
120
+ updateLabel = pkg.label;
121
+ updateDesc = pkg.description;
122
+ updateAuthor = pkg.author.name;
123
+ updateFile = null;
124
+ updateError = null;
125
+ }
126
+
127
+ function onUpdateFileSelect(e: Event) {
128
+ const input = e.target as HTMLInputElement;
129
+ updateFile = input.files?.[0] ?? null;
130
+ }
131
+
132
+ async function handleUpdatePublish(pkg: RegistryPackage) {
133
+ if (!updateFile) return;
134
+ updatePublishing = true;
135
+ updateError = null;
136
+ try {
137
+ const form = new FormData();
138
+ form.append('bundle', updateFile);
139
+ form.append('id', pkg.id);
140
+ form.append('type', pkg.type);
141
+ form.append('label', updateLabel);
142
+ form.append('description', updateDesc);
143
+ form.append('version', updateVersion);
144
+ form.append('author', updateAuthor);
145
+
146
+ await ctx.publishPackage(form);
147
+ expandedAction = null;
148
+ } catch (err) {
149
+ updateError = err instanceof Error ? err.message : String(err);
150
+ } finally {
151
+ updatePublishing = false;
152
+ }
153
+ }
154
+
155
+ // ---- Delete handlers ----
156
+ function startDelete(pkgId: string) {
157
+ expandedAction = `delete:${pkgId}`;
158
+ deleteError = null;
159
+ }
160
+
161
+ async function handleDeleteConfirm(pkgId: string) {
162
+ deleteInProgress = true;
163
+ deleteError = null;
164
+ try {
165
+ await ctx.deletePackage(pkgId);
166
+ expandedAction = null;
167
+ } catch (err) {
168
+ deleteError = err instanceof Error ? err.message : String(err);
169
+ } finally {
170
+ deleteInProgress = false;
171
+ }
172
+ }
173
+
174
+ function cancelAction() {
175
+ expandedAction = null;
176
+ }
177
+ </script>
178
+
179
+ <div class="reg-view">
180
+ <!-- Header -->
181
+ <header class="reg-header">
182
+ <h2>Registry Manager</h2>
183
+ <button
184
+ class="reg-refresh-btn"
185
+ onclick={() => ctx.refreshPackages()}
186
+ disabled={ctx.state.ephemeral.loading}
187
+ >
188
+ {ctx.state.ephemeral.loading ? 'Loading...' : 'Refresh'}
189
+ </button>
190
+ </header>
191
+
192
+ <!-- Global error -->
193
+ {#if ctx.state.ephemeral.error}
194
+ <div class="reg-error">{ctx.state.ephemeral.error}</div>
195
+ {/if}
196
+
197
+ <!-- Publish success -->
198
+ {#if publishSuccess}
199
+ <div class="reg-success">Package published successfully.</div>
200
+ {/if}
201
+
202
+ <!-- Publish New (collapsible) -->
203
+ <details class="reg-publish-section" bind:open={publishDetailsOpen}>
204
+ <summary>Publish New Package</summary>
205
+ <div class="reg-publish-form">
206
+ <div class="reg-form-row">
207
+ <input bind:value={publishId} placeholder="Package ID (e.g. my-shard)" class="reg-input" />
208
+ <select bind:value={publishType} class="reg-select">
209
+ <option value="shard">Shard</option>
210
+ <option value="app">App</option>
211
+ </select>
212
+ </div>
213
+ <div class="reg-form-row">
214
+ <input bind:value={publishLabel} placeholder="Label" class="reg-input" />
215
+ <input bind:value={publishVersion} placeholder="Version" class="reg-input" />
216
+ </div>
217
+ <input bind:value={publishDesc} placeholder="Description" class="reg-input" />
218
+ <input bind:value={publishAuthor} placeholder="Author name" class="reg-input" />
219
+ <div class="reg-form-row">
220
+ <input type="file" accept=".js" onchange={onPublishFileSelect} class="reg-input" />
221
+ <button
222
+ class="reg-btn reg-btn-primary"
223
+ onclick={handlePublish}
224
+ disabled={publishing || !publishFile}
225
+ >
226
+ {publishing ? 'Publishing...' : 'Publish'}
227
+ </button>
228
+ </div>
229
+ {#if publishError}
230
+ <div class="reg-error">{publishError}</div>
231
+ {/if}
232
+ </div>
233
+ </details>
234
+
235
+ <!-- Package list -->
236
+ {#if !ctx.state.ephemeral.loading && ctx.state.ephemeral.packages.length === 0}
237
+ <div class="reg-empty">No packages published.</div>
238
+ {:else}
239
+ <div class="reg-list">
240
+ {#each ctx.state.ephemeral.packages as pkg (pkg.id)}
241
+ <div class="reg-card">
242
+ <div class="reg-card-body">
243
+ <div class="reg-card-title">
244
+ <span class="reg-card-label">{pkg.label}</span>
245
+ <span class="reg-badge" class:badge-shard={pkg.type === 'shard'} class:badge-app={pkg.type === 'app'}>
246
+ {pkg.type}
247
+ </span>
248
+ <span class="reg-card-meta">
249
+ v{pkg.versions[0]?.version} &middot; {pkg.versions.length} version{pkg.versions.length !== 1 ? 's' : ''}
250
+ </span>
251
+ </div>
252
+ <div class="reg-card-desc">{pkg.description}</div>
253
+ <div class="reg-card-author">by {pkg.author.name} &middot; id: {pkg.id}</div>
254
+ </div>
255
+
256
+ <!-- Action buttons (hidden when this card has an expanded action) -->
257
+ {#if !expandedAction?.endsWith(`:${pkg.id}`)}
258
+ <div class="reg-card-actions">
259
+ <button class="reg-btn reg-btn-secondary" onclick={() => startEdit(pkg)}>Edit</button>
260
+ <button class="reg-btn reg-btn-secondary" onclick={() => startUpdate(pkg)}>Update</button>
261
+ <button class="reg-btn reg-btn-danger" onclick={() => startDelete(pkg.id)}>Delete</button>
262
+ </div>
263
+ {/if}
264
+
265
+ <!-- Edit form (inline) -->
266
+ {#if expandedAction === `edit:${pkg.id}`}
267
+ <div class="reg-inline-form">
268
+ <input bind:value={editLabel} placeholder="Label" class="reg-input" />
269
+ <input bind:value={editDesc} placeholder="Description" class="reg-input" />
270
+ <input bind:value={editAuthor} placeholder="Author" class="reg-input" />
271
+ {#if editError}
272
+ <div class="reg-error">{editError}</div>
273
+ {/if}
274
+ <div class="reg-form-row">
275
+ <button class="reg-btn reg-btn-primary" onclick={() => handleEditSave(pkg.id)} disabled={editSaving}>
276
+ {editSaving ? 'Saving...' : 'Save'}
277
+ </button>
278
+ <button class="reg-btn reg-btn-secondary" onclick={cancelAction}>Cancel</button>
279
+ </div>
280
+ </div>
281
+ {/if}
282
+
283
+ <!-- Update form (inline, pre-filled) -->
284
+ {#if expandedAction === `update:${pkg.id}`}
285
+ <div class="reg-inline-form">
286
+ <div class="reg-form-row">
287
+ <input value={pkg.id} disabled class="reg-input" />
288
+ <input value={pkg.type} disabled class="reg-input" />
289
+ </div>
290
+ <div class="reg-form-row">
291
+ <input bind:value={updateLabel} placeholder="Label" class="reg-input" />
292
+ <input bind:value={updateVersion} placeholder="Version" class="reg-input" />
293
+ </div>
294
+ <input bind:value={updateDesc} placeholder="Description" class="reg-input" />
295
+ <input bind:value={updateAuthor} placeholder="Author" class="reg-input" />
296
+ <div class="reg-form-row">
297
+ <input type="file" accept=".js" onchange={onUpdateFileSelect} class="reg-input" />
298
+ <button
299
+ class="reg-btn reg-btn-primary"
300
+ onclick={() => handleUpdatePublish(pkg)}
301
+ disabled={updatePublishing || !updateFile}
302
+ >
303
+ {updatePublishing ? 'Publishing...' : 'Publish Update'}
304
+ </button>
305
+ <button class="reg-btn reg-btn-secondary" onclick={cancelAction}>Cancel</button>
306
+ </div>
307
+ {#if updateError}
308
+ <div class="reg-error">{updateError}</div>
309
+ {/if}
310
+ </div>
311
+ {/if}
312
+
313
+ <!-- Delete confirmation (inline) -->
314
+ {#if expandedAction === `delete:${pkg.id}`}
315
+ <div class="reg-inline-form reg-delete-confirm">
316
+ <span>Delete <strong>{pkg.label}</strong>?</span>
317
+ {#if deleteError}
318
+ <div class="reg-error">{deleteError}</div>
319
+ {/if}
320
+ <div class="reg-form-row">
321
+ <button
322
+ class="reg-btn reg-btn-danger"
323
+ onclick={() => handleDeleteConfirm(pkg.id)}
324
+ disabled={deleteInProgress}
325
+ >
326
+ {deleteInProgress ? 'Deleting...' : 'Confirm'}
327
+ </button>
328
+ <button class="reg-btn reg-btn-secondary" onclick={cancelAction}>Cancel</button>
329
+ </div>
330
+ </div>
331
+ {/if}
332
+ </div>
333
+ {/each}
334
+ </div>
335
+ {/if}
336
+ </div>
337
+
338
+ <style>
339
+ .reg-view {
340
+ font-family: var(--shell-font, system-ui, sans-serif);
341
+ color: var(--shell-fg, #e0e0e0);
342
+ background: var(--shell-bg, #1e1e1e);
343
+ padding: 16px;
344
+ height: 100%;
345
+ overflow-y: auto;
346
+ box-sizing: border-box;
347
+ }
348
+ .reg-header {
349
+ display: flex;
350
+ align-items: center;
351
+ justify-content: space-between;
352
+ margin-bottom: 16px;
353
+ }
354
+ .reg-header h2 {
355
+ margin: 0;
356
+ font-size: 1.25rem;
357
+ font-weight: 600;
358
+ }
359
+ .reg-refresh-btn {
360
+ padding: 6px 14px;
361
+ background: var(--shell-accent, #007acc);
362
+ color: #fff;
363
+ border: none;
364
+ border-radius: 4px;
365
+ cursor: pointer;
366
+ font-family: inherit;
367
+ font-size: 0.875rem;
368
+ }
369
+ .reg-refresh-btn:disabled {
370
+ opacity: 0.6;
371
+ cursor: not-allowed;
372
+ }
373
+ .reg-error {
374
+ padding: 8px 12px;
375
+ margin-bottom: 12px;
376
+ background: color-mix(in srgb, var(--shell-error, #d32f2f) 15%, transparent);
377
+ color: var(--shell-error, #d32f2f);
378
+ border: 1px solid var(--shell-error, #d32f2f);
379
+ border-radius: 4px;
380
+ font-size: 0.8125rem;
381
+ }
382
+ .reg-success {
383
+ padding: 8px 12px;
384
+ margin-bottom: 12px;
385
+ background: color-mix(in srgb, var(--shell-success, #4caf50) 15%, transparent);
386
+ color: var(--shell-success, #4caf50);
387
+ border: 1px solid var(--shell-success, #4caf50);
388
+ border-radius: 4px;
389
+ font-size: 0.8125rem;
390
+ }
391
+ .reg-publish-section {
392
+ padding: 8px 12px;
393
+ border: 1px solid var(--shell-border, #444);
394
+ border-radius: 6px;
395
+ margin-bottom: 16px;
396
+ font-size: 0.875rem;
397
+ }
398
+ .reg-publish-section summary {
399
+ cursor: pointer;
400
+ font-weight: 500;
401
+ padding: 4px 0;
402
+ }
403
+ .reg-publish-form {
404
+ display: flex;
405
+ flex-direction: column;
406
+ gap: 8px;
407
+ margin-top: 10px;
408
+ }
409
+ .reg-form-row {
410
+ display: flex;
411
+ gap: 8px;
412
+ }
413
+ .reg-input {
414
+ flex: 1;
415
+ padding: 6px 10px;
416
+ background: var(--shell-input-bg, #2a2a2a);
417
+ color: var(--shell-fg, #e0e0e0);
418
+ border: 1px solid var(--shell-border, #444);
419
+ border-radius: 4px;
420
+ font-family: inherit;
421
+ font-size: 0.8125rem;
422
+ }
423
+ .reg-input:disabled {
424
+ opacity: 0.5;
425
+ }
426
+ .reg-input::placeholder {
427
+ color: var(--shell-fg-muted, #888);
428
+ }
429
+ .reg-select {
430
+ padding: 6px 10px;
431
+ background: var(--shell-input-bg, #2a2a2a);
432
+ color: var(--shell-fg, #e0e0e0);
433
+ border: 1px solid var(--shell-border, #444);
434
+ border-radius: 4px;
435
+ font-family: inherit;
436
+ font-size: 0.8125rem;
437
+ }
438
+ .reg-btn {
439
+ padding: 6px 14px;
440
+ border: none;
441
+ border-radius: 4px;
442
+ cursor: pointer;
443
+ font-family: inherit;
444
+ font-size: 0.8125rem;
445
+ font-weight: 500;
446
+ white-space: nowrap;
447
+ }
448
+ .reg-btn:disabled {
449
+ opacity: 0.5;
450
+ cursor: not-allowed;
451
+ }
452
+ .reg-btn-primary {
453
+ background: var(--shell-accent, #007acc);
454
+ color: #fff;
455
+ }
456
+ .reg-btn-secondary {
457
+ background: var(--shell-input-bg, #2a2a2a);
458
+ color: var(--shell-fg, #e0e0e0);
459
+ border: 1px solid var(--shell-border, #444);
460
+ }
461
+ .reg-btn-danger {
462
+ background: transparent;
463
+ color: var(--shell-error, #d32f2f);
464
+ border: 1px solid var(--shell-error, #d32f2f);
465
+ }
466
+ .reg-btn-danger:hover:not(:disabled) {
467
+ background: var(--shell-error, #d32f2f);
468
+ color: #fff;
469
+ }
470
+ .reg-list {
471
+ display: flex;
472
+ flex-direction: column;
473
+ gap: 10px;
474
+ }
475
+ .reg-card {
476
+ background: var(--shell-input-bg, #2a2a2a);
477
+ border: 1px solid var(--shell-border, #444);
478
+ border-radius: 6px;
479
+ padding: 14px;
480
+ display: flex;
481
+ flex-direction: column;
482
+ gap: 10px;
483
+ }
484
+ .reg-card:hover {
485
+ border-color: var(--shell-accent, #007acc);
486
+ }
487
+ .reg-card-body {
488
+ display: flex;
489
+ flex-direction: column;
490
+ gap: 4px;
491
+ }
492
+ .reg-card-title {
493
+ display: flex;
494
+ align-items: center;
495
+ gap: 6px;
496
+ flex-wrap: wrap;
497
+ }
498
+ .reg-card-label {
499
+ font-weight: 600;
500
+ font-size: 0.9375rem;
501
+ }
502
+ .reg-badge {
503
+ font-size: 0.6875rem;
504
+ padding: 1px 6px;
505
+ border-radius: 3px;
506
+ text-transform: uppercase;
507
+ font-weight: 600;
508
+ letter-spacing: 0.04em;
509
+ }
510
+ .badge-shard {
511
+ background: color-mix(in srgb, var(--shell-accent, #007acc) 25%, transparent);
512
+ color: var(--shell-accent, #007acc);
513
+ }
514
+ .badge-app {
515
+ background: color-mix(in srgb, var(--shell-success, #4caf50) 25%, transparent);
516
+ color: var(--shell-success, #4caf50);
517
+ }
518
+ .reg-card-meta {
519
+ font-size: 0.75rem;
520
+ color: var(--shell-fg-muted, #888);
521
+ }
522
+ .reg-card-desc {
523
+ font-size: 0.8125rem;
524
+ color: var(--shell-fg-muted, #aaa);
525
+ display: -webkit-box;
526
+ -webkit-line-clamp: 2;
527
+ -webkit-box-orient: vertical;
528
+ overflow: hidden;
529
+ }
530
+ .reg-card-author {
531
+ font-size: 0.75rem;
532
+ color: var(--shell-fg-muted, #777);
533
+ }
534
+ .reg-card-actions {
535
+ display: flex;
536
+ gap: 8px;
537
+ justify-content: flex-end;
538
+ }
539
+ .reg-inline-form {
540
+ display: flex;
541
+ flex-direction: column;
542
+ gap: 8px;
543
+ padding-top: 8px;
544
+ border-top: 1px solid var(--shell-border, #444);
545
+ }
546
+ .reg-delete-confirm {
547
+ flex-direction: row;
548
+ align-items: center;
549
+ flex-wrap: wrap;
550
+ }
551
+ .reg-delete-confirm span {
552
+ flex: 1;
553
+ font-size: 0.875rem;
554
+ }
555
+ .reg-empty {
556
+ text-align: center;
557
+ padding: 32px 16px;
558
+ color: var(--shell-fg-muted, #888);
559
+ font-size: 0.875rem;
560
+ }
561
+ </style>
@@ -0,0 +1,3 @@
1
+ declare const RegistryView: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type RegistryView = ReturnType<typeof RegistryView>;
3
+ export default RegistryView;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Built-in Registry Manager app — composes the sh3-registry shard's
3
+ * manage view into a single-slot admin interface.
4
+ *
5
+ * Framework-shipped: registered in host.ts during bootstrap.
6
+ * Admin-gated: the shell home checks adminAppIds to gate visibility;
7
+ * the AppManifest itself carries no admin flag (ADR-011).
8
+ */
9
+ import type { App } from '../apps/types';
10
+ export declare const registryApp: App;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Built-in Registry Manager app — composes the sh3-registry shard's
3
+ * manage view into a single-slot admin interface.
4
+ *
5
+ * Framework-shipped: registered in host.ts during bootstrap.
6
+ * Admin-gated: the shell home checks adminAppIds to gate visibility;
7
+ * the AppManifest itself carries no admin flag (ADR-011).
8
+ */
9
+ export const registryApp = {
10
+ manifest: {
11
+ id: 'sh3-registry-app',
12
+ label: 'Registry Manager',
13
+ version: '0.1.0',
14
+ requiredShards: ['sh3-registry'],
15
+ layoutVersion: 1,
16
+ },
17
+ initialLayout: {
18
+ type: 'tabs',
19
+ activeTab: 0,
20
+ tabs: [
21
+ { slotId: 'registry.manage', viewId: 'sh3-registry:manage', label: 'Registry' },
22
+ ],
23
+ },
24
+ };
@@ -0,0 +1,45 @@
1
+ import type { Shard } from '../shards/types';
2
+ import type { StateZones } from '../state/zones.svelte';
3
+ /** Registry package shape from the server's registry.json. */
4
+ export interface RegistryPackage {
5
+ id: string;
6
+ type: 'shard' | 'app';
7
+ label: string;
8
+ description: string;
9
+ author: {
10
+ name: string;
11
+ };
12
+ versions: Array<{
13
+ version: string;
14
+ contractVersion: string;
15
+ bundleUrl: string;
16
+ integrity: string;
17
+ }>;
18
+ }
19
+ /** Schema shape for state zone typing. */
20
+ interface RegistryZoneSchema {
21
+ ephemeral: {
22
+ packages: RegistryPackage[];
23
+ loading: boolean;
24
+ error: string | null;
25
+ };
26
+ }
27
+ /** Reactive context exposed to the view component. */
28
+ export interface RegistryContext {
29
+ state: StateZones<RegistryZoneSchema>;
30
+ refreshPackages(): Promise<void>;
31
+ publishPackage(form: FormData): Promise<void>;
32
+ patchPackage(id: string, fields: {
33
+ label?: string;
34
+ description?: string;
35
+ author?: string;
36
+ }): Promise<void>;
37
+ deletePackage(id: string): Promise<void>;
38
+ }
39
+ /**
40
+ * Module-level context set during activate(). Imported by the Svelte
41
+ * view component so it can read/write state and trigger actions.
42
+ */
43
+ export declare let registryContext: RegistryContext;
44
+ export declare const registryShard: Shard;
45
+ export {};