sh3-core 0.5.2 → 0.5.4

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/dist/Shell.svelte CHANGED
@@ -160,7 +160,7 @@
160
160
  background: transparent;
161
161
  color: var(--shell-fg-muted);
162
162
  border: 1px solid var(--shell-border);
163
- border-radius: 4px;
163
+ border-radius: var(--shell-radius);
164
164
  cursor: pointer;
165
165
  }
166
166
  .shell-tabbar-home-button:hover {
@@ -180,6 +180,6 @@
180
180
  color: #fff;
181
181
  background: var(--shell-accent);
182
182
  padding: 1px 6px;
183
- border-radius: 8px;
183
+ border-radius: var(--shell-radius-lg);
184
184
  }
185
185
  </style>
@@ -31,7 +31,12 @@ export declare function unloadApp(id: string): void;
31
31
  * refcount hold intact, and its view containers stay alive in the pool.
32
32
  * Launching the same app again is a root swap only.
33
33
  *
34
+ * Fires `suspend` hooks on all required shards (in order), then on the
35
+ * app itself. Any hook returning `false` cancels navigation — the user
36
+ * stays in the app. Returns `true` if navigation succeeded, `false` if
37
+ * cancelled.
38
+ *
34
39
  * Writes `null` to `__shell__:last-app` so reloading the page while on
35
40
  * home lands on home, not on the formerly-active app.
36
41
  */
37
- export declare function returnToHome(): void;
42
+ export declare function returnToHome(): Promise<boolean>;
@@ -12,7 +12,7 @@
12
12
  * return-to-home (null). Boot reads it to decide whether to auto-launch.
13
13
  */
14
14
  import { createStateZones } from '../state/zones.svelte';
15
- import { activateShard, deactivateShard, registeredShards, } from '../shards/activate.svelte';
15
+ import { activateShard, deactivateShard, getShardContext, registeredShards, } from '../shards/activate.svelte';
16
16
  import { attachApp, detachApp, switchToApp, switchToHome, } from '../layout/store.svelte';
17
17
  import { activeApp, getRegisteredApp } from './registry.svelte';
18
18
  import { createZoneManager } from '../state/manage';
@@ -69,7 +69,7 @@ function getOrCreateAppContext(appId) {
69
69
  * @throws If the app is not registered or a required shard is not registered.
70
70
  */
71
71
  export async function launchApp(id) {
72
- var _a;
72
+ var _a, _b, _c;
73
73
  const app = getRegisteredApp(id);
74
74
  if (!app) {
75
75
  throw new Error(`Cannot launch app "${id}": not registered`);
@@ -82,6 +82,14 @@ export async function launchApp(id) {
82
82
  unloadApp(activeApp.id);
83
83
  }
84
84
  else if (activeApp.id === id) {
85
+ // Re-entering the same app from Home — fire resume hooks.
86
+ for (const shardId of app.manifest.requiredShards) {
87
+ const shard = registeredShards.get(shardId);
88
+ const shardCtx = getShardContext(shardId);
89
+ if (shard && shardCtx)
90
+ void ((_a = shard.resume) === null || _a === void 0 ? void 0 : _a.call(shard, shardCtx));
91
+ }
92
+ void ((_b = app.resume) === null || _b === void 0 ? void 0 : _b.call(app, getOrCreateAppContext(id)));
85
93
  switchToApp();
86
94
  writeLastApp(id);
87
95
  return;
@@ -99,7 +107,7 @@ export async function launchApp(id) {
99
107
  // Attach the layout (creates the workspace-zone proxy with version
100
108
  // gate) and run the app's optional activate hook.
101
109
  attachApp(app);
102
- void ((_a = app.activate) === null || _a === void 0 ? void 0 : _a.call(app, getOrCreateAppContext(id)));
110
+ void ((_c = app.activate) === null || _c === void 0 ? void 0 : _c.call(app, getOrCreateAppContext(id)));
103
111
  activeApp.id = id;
104
112
  switchToApp();
105
113
  writeLastApp(id);
@@ -151,10 +159,26 @@ export function unloadApp(id) {
151
159
  * refcount hold intact, and its view containers stay alive in the pool.
152
160
  * Launching the same app again is a root swap only.
153
161
  *
162
+ * Fires `suspend` hooks on all required shards (in order), then on the
163
+ * app itself. Any hook returning `false` cancels navigation — the user
164
+ * stays in the app. Returns `true` if navigation succeeded, `false` if
165
+ * cancelled.
166
+ *
154
167
  * Writes `null` to `__shell__:last-app` so reloading the page while on
155
168
  * home lands on home, not on the formerly-active app.
156
169
  */
157
- export function returnToHome() {
170
+ export async function returnToHome() {
171
+ const app = activeApp.id ? getRegisteredApp(activeApp.id) : null;
172
+ if (app) {
173
+ for (const shardId of app.manifest.requiredShards) {
174
+ const shard = registeredShards.get(shardId);
175
+ if ((shard === null || shard === void 0 ? void 0 : shard.suspend) && (await shard.suspend()) === false)
176
+ return false;
177
+ }
178
+ if (app.suspend && (await app.suspend()) === false)
179
+ return false;
180
+ }
158
181
  switchToHome();
159
182
  writeLastApp(null);
183
+ return true;
160
184
  }
@@ -14,8 +14,11 @@ export declare const activeApp: {
14
14
  id: string | null;
15
15
  };
16
16
  /**
17
- * Register an app with the framework. Must be called before `launchApp`.
18
- * Throws if an app with the same id is already registered.
17
+ * Register (or re-register) an app with the framework.
18
+ *
19
+ * If an app with the same id already exists it is silently replaced,
20
+ * which is the expected path during package updates — the new bundle is
21
+ * loaded and re-registered without requiring a full page reload.
19
22
  *
20
23
  * @param app - The app module to register.
21
24
  */
@@ -21,17 +21,16 @@ export const registeredApps = $state(new Map());
21
21
  */
22
22
  export const activeApp = $state({ id: null });
23
23
  /**
24
- * Register an app with the framework. Must be called before `launchApp`.
25
- * Throws if an app with the same id is already registered.
24
+ * Register (or re-register) an app with the framework.
25
+ *
26
+ * If an app with the same id already exists it is silently replaced,
27
+ * which is the expected path during package updates — the new bundle is
28
+ * loaded and re-registered without requiring a full page reload.
26
29
  *
27
30
  * @param app - The app module to register.
28
31
  */
29
32
  export function registerApp(app) {
30
- const id = app.manifest.id;
31
- if (registeredApps.has(id)) {
32
- throw new Error(`App "${id}" is already registered`);
33
- }
34
- registeredApps.set(id, app);
33
+ registeredApps.set(app.manifest.id, app);
35
34
  }
36
35
  /**
37
36
  * Reactive snapshot of all registered app manifests. Shell home iterates
@@ -77,4 +77,17 @@ export interface App {
77
77
  activate?(ctx: AppContext): void | Promise<void>;
78
78
  /** Optional hook called before the app's shards are deactivated and the layout is detached. */
79
79
  deactivate?(): void | Promise<void>;
80
+ /**
81
+ * Called when the user navigates to Home while the app is active. The
82
+ * app's shards, state, and pooled views remain alive. Return `false`
83
+ * (sync or async) to cancel the navigation — useful for "unsaved
84
+ * changes" confirmation modals.
85
+ */
86
+ suspend?(): void | false | Promise<void | false>;
87
+ /**
88
+ * Called when the app is re-entered from Home (root swap back to app).
89
+ * Does NOT fire on first launch — that is `activate`. Receives the
90
+ * same `AppContext` that `activate` received.
91
+ */
92
+ resume?(ctx: AppContext): void | Promise<void>;
80
93
  }
@@ -73,7 +73,7 @@
73
73
  background: var(--shell-accent-muted);
74
74
  color: var(--shell-fg);
75
75
  border: 1px solid var(--shell-border-strong);
76
- border-radius: 3px;
76
+ border-radius: var(--shell-radius-sm);
77
77
  cursor: pointer;
78
78
  }
79
79
  button:hover { background: var(--shell-accent); }
@@ -49,7 +49,7 @@
49
49
  background: var(--shell-grad-bg-elevated, var(--shell-bg-elevated));
50
50
  color: var(--shell-fg);
51
51
  border: 1px solid var(--shell-accent);
52
- border-radius: 3px;
52
+ border-radius: var(--shell-radius-sm);
53
53
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
54
54
  font-size: 12px;
55
55
  font-family: var(--shell-font-ui);
@@ -76,7 +76,7 @@
76
76
  background: var(--shell-grad-bg-elevated, var(--shell-bg-elevated));
77
77
  color: var(--shell-fg);
78
78
  border: 1px solid var(--shell-border-strong);
79
- border-radius: 4px;
79
+ border-radius: var(--shell-radius);
80
80
  min-width: 320px;
81
81
  max-width: min(640px, 90vw);
82
82
  max-height: 90vh;
@@ -76,7 +76,7 @@
76
76
  background: var(--shell-grad-bg-elevated, var(--shell-bg-elevated));
77
77
  color: var(--shell-fg);
78
78
  border: 1px solid var(--shell-border-strong);
79
- border-radius: 3px;
79
+ border-radius: var(--shell-radius-sm);
80
80
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
81
81
  min-width: 120px;
82
82
  outline: none;
@@ -48,7 +48,7 @@
48
48
  color: var(--shell-fg);
49
49
  border: 1px solid var(--shell-border-strong);
50
50
  border-left-width: 3px;
51
- border-radius: 3px;
51
+ border-radius: var(--shell-radius-sm);
52
52
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
53
53
  font-size: 12px;
54
54
  min-width: 220px;
@@ -265,7 +265,7 @@
265
265
  font-size: 10px;
266
266
  line-height: 1;
267
267
  padding: 2px;
268
- border-radius: 3px;
268
+ border-radius: var(--shell-radius-sm);
269
269
  color: var(--shell-fg-muted);
270
270
  cursor: pointer;
271
271
  flex-shrink: 0;
@@ -97,8 +97,6 @@ export async function installPackage(bundle, meta) {
97
97
  registerApp(app);
98
98
  }
99
99
  catch (err) {
100
- // Registration failure (e.g. duplicate id) -- the package is persisted
101
- // but not usable until reload. Log and continue.
102
100
  console.warn(`[sh3] Package "${meta.id}" installed but registration failed (will retry on next boot):`, err instanceof Error ? err.message : err);
103
101
  hotLoaded = false;
104
102
  }
@@ -1,4 +1,4 @@
1
- import type { Shard } from './types';
1
+ import type { Shard, ShardContext } from './types';
2
2
  /**
3
3
  * Reactive registry of every shard known to the host. Keys are shard ids.
4
4
  * Populated once at boot by the glob-discovery loop in main.ts (through
@@ -10,12 +10,14 @@ import type { Shard } from './types';
10
10
  export declare const registeredShards: Map<string, Shard>;
11
11
  export declare const activeShards: Map<string, Shard>;
12
12
  /**
13
- * Register a shard with the framework so it can later be activated. Records
14
- * the shard in `registeredShards` but does not run `activate` — that happens
15
- * at app launch (or immediately for self-starting shards).
13
+ * Register (or re-register) a shard with the framework so it can later be
14
+ * activated. Records the shard in `registeredShards` but does not run
15
+ * `activate` — that happens at app launch (or for self-starting shards).
16
16
  *
17
- * @param shard - The shard module to register. `shard.manifest.id` must be unique.
18
- * @throws If a shard with the same id is already registered.
17
+ * If a shard with the same id already exists it is silently replaced,
18
+ * which is the expected path during package updates. If the old shard was
19
+ * active it is deactivated first so the new version can be cleanly
20
+ * activated on next launch.
19
21
  */
20
22
  export declare function registerShard(shard: Shard): void;
21
23
  /**
@@ -43,3 +45,8 @@ export declare function deactivateShard(id: string): void;
43
45
  * @param id - The `ShardManifest.id` to check.
44
46
  */
45
47
  export declare function isActive(id: string): boolean;
48
+ /**
49
+ * Return the ShardContext for an active shard, or undefined if not active.
50
+ * Used by lifecycle.ts to pass context to `shard.resume()`.
51
+ */
52
+ export declare function getShardContext(id: string): ShardContext | undefined;
@@ -39,17 +39,19 @@ export const registeredShards = $state(new Map());
39
39
  const active = new Map();
40
40
  export const activeShards = $state(new Map());
41
41
  /**
42
- * Register a shard with the framework so it can later be activated. Records
43
- * the shard in `registeredShards` but does not run `activate` — that happens
44
- * at app launch (or immediately for self-starting shards).
42
+ * Register (or re-register) a shard with the framework so it can later be
43
+ * activated. Records the shard in `registeredShards` but does not run
44
+ * `activate` — that happens at app launch (or for self-starting shards).
45
45
  *
46
- * @param shard - The shard module to register. `shard.manifest.id` must be unique.
47
- * @throws If a shard with the same id is already registered.
46
+ * If a shard with the same id already exists it is silently replaced,
47
+ * which is the expected path during package updates. If the old shard was
48
+ * active it is deactivated first so the new version can be cleanly
49
+ * activated on next launch.
48
50
  */
49
51
  export function registerShard(shard) {
50
52
  const id = shard.manifest.id;
51
- if (registeredShards.has(id)) {
52
- throw new Error(`Shard "${id}" is already registered`);
53
+ if (registeredShards.has(id) && activeShards.has(id)) {
54
+ deactivateShard(id);
53
55
  }
54
56
  registeredShards.set(id, shard);
55
57
  }
@@ -73,7 +75,7 @@ export async function activateShard(id) {
73
75
  // and is now being required by an app). Idempotent — no error.
74
76
  return;
75
77
  }
76
- const entry = { shard, viewIds: new Set(), cleanupFns: [] };
78
+ const entry = { shard, ctx: undefined, viewIds: new Set(), cleanupFns: [] };
77
79
  // envState holds the reactive env data for this shard.
78
80
  // Must be declared with $state at variable declaration time (Svelte 5 rule).
79
81
  const envState = $state({
@@ -122,6 +124,7 @@ export async function activateShard(id) {
122
124
  ? createZoneManager()
123
125
  : undefined,
124
126
  };
127
+ entry.ctx = ctx;
125
128
  active.set(id, entry);
126
129
  activeShards.set(id, shard);
127
130
  await shard.activate(ctx);
@@ -173,3 +176,11 @@ export function deactivateShard(id) {
173
176
  export function isActive(id) {
174
177
  return active.has(id);
175
178
  }
179
+ /**
180
+ * Return the ShardContext for an active shard, or undefined if not active.
181
+ * Used by lifecycle.ts to pass context to `shard.resume()`.
182
+ */
183
+ export function getShardContext(id) {
184
+ var _a;
185
+ return (_a = active.get(id)) === null || _a === void 0 ? void 0 : _a.ctx;
186
+ }
@@ -193,4 +193,15 @@ export interface Shard {
193
193
  autostart?(ctx: ShardContext): void | Promise<void>;
194
194
  /** Optional cleanup hook called when the shard is deactivated. Release timers, subscriptions, and external resources here. */
195
195
  deactivate?(): void | Promise<void>;
196
+ /**
197
+ * Called when the owning app is suspended (Home button). The shard
198
+ * remains active; its views and state are preserved. Return `false`
199
+ * (sync or async) to cancel the navigation.
200
+ */
201
+ suspend?(): void | false | Promise<void | false>;
202
+ /**
203
+ * Called when the owning app resumes from Home. Receives the same
204
+ * `ShardContext` that `activate` received.
205
+ */
206
+ resume?(ctx: ShardContext): void | Promise<void>;
196
207
  }
@@ -203,7 +203,7 @@
203
203
  padding: 14px 18px;
204
204
  background: var(--shell-grad-bg-elevated, var(--shell-bg-elevated));
205
205
  border: 1px solid var(--shell-border);
206
- border-radius: 6px;
206
+ border-radius: var(--shell-radius-md);
207
207
  }
208
208
  .shell-home-entry-label {
209
209
  grid-column: 1;
@@ -223,7 +223,7 @@
223
223
  background: var(--shell-accent);
224
224
  color: var(--shell-bg);
225
225
  border: none;
226
- border-radius: 4px;
226
+ border-radius: var(--shell-radius);
227
227
  font-weight: 600;
228
228
  cursor: pointer;
229
229
  }
@@ -235,7 +235,7 @@
235
235
  background: transparent;
236
236
  color: var(--shell-fg-subtle);
237
237
  border: 1px solid var(--shell-border);
238
- border-radius: 4px;
238
+ border-radius: var(--shell-radius);
239
239
  cursor: pointer;
240
240
  font-size: 12px;
241
241
  }
@@ -258,7 +258,7 @@
258
258
  background: var(--shell-grad-bg-elevated, var(--shell-bg-elevated));
259
259
  color: var(--shell-fg);
260
260
  border: 1px solid var(--shell-border);
261
- border-radius: 4px;
261
+ border-radius: var(--shell-radius);
262
262
  font-family: monospace;
263
263
  font-size: 13px;
264
264
  }
@@ -270,7 +270,7 @@
270
270
  background: var(--shell-accent);
271
271
  color: var(--shell-bg);
272
272
  border: none;
273
- border-radius: 4px;
273
+ border-radius: var(--shell-radius);
274
274
  font-weight: 600;
275
275
  cursor: pointer;
276
276
  white-space: nowrap;
@@ -285,6 +285,6 @@
285
285
  font-size: 12px;
286
286
  color: var(--shell-error, #d32f2f);
287
287
  background: color-mix(in srgb, var(--shell-error, #d32f2f) 10%, transparent);
288
- border-radius: 4px;
288
+ border-radius: var(--shell-radius);
289
289
  }
290
290
  </style>
@@ -125,7 +125,7 @@
125
125
 
126
126
  <style>
127
127
  .installed-view {
128
- font-family: var(--shell-font, system-ui, sans-serif);
128
+ font-family: var(--shell-font-ui);
129
129
  color: var(--shell-fg, #e0e0e0);
130
130
  background: var(--shell-bg, #1e1e1e);
131
131
  padding: 16px;
@@ -149,7 +149,7 @@
149
149
  background: var(--shell-accent, #007acc);
150
150
  color: #fff;
151
151
  border: none;
152
- border-radius: 4px;
152
+ border-radius: var(--shell-radius);
153
153
  cursor: pointer;
154
154
  font-family: inherit;
155
155
  font-size: 0.875rem;
@@ -171,7 +171,7 @@
171
171
  .installed-item {
172
172
  background: var(--shell-input-bg, #2a2a2a);
173
173
  border: 1px solid var(--shell-border, #444);
174
- border-radius: 6px;
174
+ border-radius: var(--shell-radius-md);
175
175
  padding: 12px 14px;
176
176
  display: flex;
177
177
  flex-direction: column;
@@ -189,7 +189,7 @@
189
189
  .installed-item-badge {
190
190
  font-size: 0.6875rem;
191
191
  padding: 1px 6px;
192
- border-radius: 3px;
192
+ border-radius: var(--shell-radius-sm);
193
193
  text-transform: uppercase;
194
194
  font-weight: 600;
195
195
  letter-spacing: 0.04em;
@@ -223,7 +223,7 @@
223
223
  background: transparent;
224
224
  color: var(--shell-error, #d32f2f);
225
225
  border: 1px solid var(--shell-error, #d32f2f);
226
- border-radius: 4px;
226
+ border-radius: var(--shell-radius);
227
227
  cursor: pointer;
228
228
  font-family: inherit;
229
229
  font-size: 0.8125rem;
@@ -240,7 +240,7 @@
240
240
  background: var(--shell-warning, #ff9800);
241
241
  color: #fff;
242
242
  border: none;
243
- border-radius: 4px;
243
+ border-radius: var(--shell-radius);
244
244
  cursor: pointer;
245
245
  font-family: inherit;
246
246
  font-size: 0.8125rem;
@@ -258,7 +258,7 @@
258
258
  background: color-mix(in srgb, var(--shell-error, #d32f2f) 15%, transparent);
259
259
  color: var(--shell-error, #d32f2f);
260
260
  border: 1px solid var(--shell-error, #d32f2f);
261
- border-radius: 4px;
261
+ border-radius: var(--shell-radius);
262
262
  font-size: 0.8125rem;
263
263
  }
264
264
  </style>
@@ -273,7 +273,7 @@
273
273
 
274
274
  <style>
275
275
  .store-view {
276
- font-family: var(--shell-font, system-ui, sans-serif);
276
+ font-family: var(--shell-font-ui);
277
277
  color: var(--shell-fg, #e0e0e0);
278
278
  background: var(--shell-bg, #1e1e1e);
279
279
  padding: 16px;
@@ -301,7 +301,7 @@
301
301
  background: var(--shell-input-bg, #2a2a2a);
302
302
  color: var(--shell-fg, #e0e0e0);
303
303
  border: 1px solid var(--shell-border, #444);
304
- border-radius: 4px;
304
+ border-radius: var(--shell-radius);
305
305
  font-family: inherit;
306
306
  font-size: 0.875rem;
307
307
  }
@@ -313,7 +313,7 @@
313
313
  background: var(--shell-input-bg, #2a2a2a);
314
314
  color: var(--shell-fg, #e0e0e0);
315
315
  border: 1px solid var(--shell-border, #444);
316
- border-radius: 4px;
316
+ border-radius: var(--shell-radius);
317
317
  font-family: inherit;
318
318
  font-size: 0.875rem;
319
319
  }
@@ -322,7 +322,7 @@
322
322
  background: var(--shell-accent, #007acc);
323
323
  color: #fff;
324
324
  border: none;
325
- border-radius: 4px;
325
+ border-radius: var(--shell-radius);
326
326
  cursor: pointer;
327
327
  font-family: inherit;
328
328
  font-size: 0.875rem;
@@ -337,7 +337,7 @@
337
337
  background: color-mix(in srgb, var(--shell-error, #d32f2f) 15%, transparent);
338
338
  color: var(--shell-error, #d32f2f);
339
339
  border: 1px solid var(--shell-error, #d32f2f);
340
- border-radius: 4px;
340
+ border-radius: var(--shell-radius);
341
341
  font-size: 0.8125rem;
342
342
  }
343
343
  .store-grid {
@@ -348,7 +348,7 @@
348
348
  .store-card {
349
349
  background: var(--shell-input-bg, #2a2a2a);
350
350
  border: 1px solid var(--shell-border, #444);
351
- border-radius: 6px;
351
+ border-radius: var(--shell-radius-md);
352
352
  padding: 14px;
353
353
  display: flex;
354
354
  flex-direction: column;
@@ -373,7 +373,7 @@
373
373
  .store-icon-img {
374
374
  width: 36px;
375
375
  height: 36px;
376
- border-radius: 4px;
376
+ border-radius: var(--shell-radius);
377
377
  object-fit: cover;
378
378
  }
379
379
  .store-icon-placeholder {
@@ -384,7 +384,7 @@
384
384
  justify-content: center;
385
385
  background: var(--shell-accent, #007acc);
386
386
  color: #fff;
387
- border-radius: 4px;
387
+ border-radius: var(--shell-radius);
388
388
  font-weight: 700;
389
389
  font-size: 1rem;
390
390
  }
@@ -401,7 +401,7 @@
401
401
  .store-card-badge {
402
402
  font-size: 0.6875rem;
403
403
  padding: 1px 6px;
404
- border-radius: 3px;
404
+ border-radius: var(--shell-radius-sm);
405
405
  text-transform: uppercase;
406
406
  font-weight: 600;
407
407
  letter-spacing: 0.04em;
@@ -433,7 +433,7 @@
433
433
  color: var(--shell-warning, #ff9800);
434
434
  padding: 4px 8px;
435
435
  background: color-mix(in srgb, var(--shell-warning, #ff9800) 10%, transparent);
436
- border-radius: 3px;
436
+ border-radius: var(--shell-radius-sm);
437
437
  }
438
438
  .store-card-actions {
439
439
  margin-top: auto;
@@ -445,7 +445,7 @@
445
445
  background: var(--shell-accent, #007acc);
446
446
  color: #fff;
447
447
  border: none;
448
- border-radius: 4px;
448
+ border-radius: var(--shell-radius);
449
449
  cursor: pointer;
450
450
  font-family: inherit;
451
451
  font-size: 0.8125rem;
@@ -464,7 +464,7 @@
464
464
  background: var(--shell-warning, #ff9800);
465
465
  color: #fff;
466
466
  border: none;
467
- border-radius: 4px;
467
+ border-radius: var(--shell-radius);
468
468
  cursor: pointer;
469
469
  font-family: inherit;
470
470
  font-size: 0.8125rem;
@@ -495,7 +495,7 @@
495
495
  padding: 4px 8px;
496
496
  background: var(--shell-input-bg, #2a2a2a);
497
497
  border: 1px solid var(--shell-border, #444);
498
- border-radius: 4px;
498
+ border-radius: var(--shell-radius);
499
499
  font-size: 0.8125rem;
500
500
  }
501
501
  .store-registry-url {
@@ -509,7 +509,7 @@
509
509
  background: transparent;
510
510
  color: var(--shell-error, #d32f2f);
511
511
  border: 1px solid var(--shell-error, #d32f2f);
512
- border-radius: 3px;
512
+ border-radius: var(--shell-radius-sm);
513
513
  cursor: pointer;
514
514
  font-size: 0.75rem;
515
515
  flex-shrink: 0;
@@ -526,7 +526,7 @@
526
526
  background: var(--shell-input-bg, #2a2a2a);
527
527
  color: var(--shell-fg, #e0e0e0);
528
528
  border: 1px solid var(--shell-border, #444);
529
- border-radius: 4px;
529
+ border-radius: var(--shell-radius);
530
530
  font-family: inherit;
531
531
  font-size: 0.8125rem;
532
532
  }
@@ -538,7 +538,7 @@
538
538
  background: var(--shell-accent, #007acc);
539
539
  color: #fff;
540
540
  border: none;
541
- border-radius: 4px;
541
+ border-radius: var(--shell-radius);
542
542
  cursor: pointer;
543
543
  font-family: inherit;
544
544
  font-size: 0.8125rem;
@@ -10,7 +10,7 @@ export const storeApp = {
10
10
  manifest: {
11
11
  id: 'sh3-store-app',
12
12
  label: 'Package Store',
13
- version: '0.2.0',
13
+ version: '0.2.1',
14
14
  requiredShards: ['sh3-store'],
15
15
  layoutVersion: 1,
16
16
  admin: true,
@@ -48,7 +48,7 @@ export const storeShard = {
48
48
  manifest: {
49
49
  id: 'sh3-store',
50
50
  label: 'Package Store',
51
- version: '0.2.0',
51
+ version: '0.2.1',
52
52
  views: [
53
53
  { id: 'sh3-store:browse', label: 'Store' },
54
54
  { id: 'sh3-store:installed', label: 'Installed' },
@@ -208,10 +208,11 @@ export const storeShard = {
208
208
  };
209
209
  ctx.registerView('sh3-store:browse', browseFactory);
210
210
  ctx.registerView('sh3-store:installed', installedFactory);
211
+ // refreshInstalled can run immediately (hits server, no env needed).
212
+ refreshInstalled();
211
213
  },
212
214
  autostart() {
213
- // Intentionally empty. Defining autostart puts the store shard on
214
- // the self-starting path at boot so its views are available from
215
- // the launcher without requiring an app to declare it.
215
+ // Runs after env hydration, so registries are populated.
216
+ storeContext.refreshCatalog();
216
217
  },
217
218
  };
package/dist/tokens.css CHANGED
@@ -32,12 +32,26 @@
32
32
  --shell-accent: #6ea8fe;
33
33
  --shell-accent-muted: #3a5580;
34
34
 
35
+ /* Inputs */
36
+ --shell-input-bg: #2a2a2a;
37
+
38
+ /* Semantic */
39
+ --shell-error: #f87171;
40
+ --shell-warning: #fbbf24;
41
+ --shell-success: #34d399;
42
+
35
43
  /* Typography */
36
44
  --shell-font-ui: system-ui, -apple-system, "Segoe UI", sans-serif;
37
45
  --shell-font-mono: ui-monospace, "Cascadia Code", "Consolas", monospace;
38
46
  --shell-font-size: 13px;
39
47
  --shell-line: 1.45;
40
48
 
49
+ /* Radius */
50
+ --shell-radius-sm: 3px;
51
+ --shell-radius: 4px;
52
+ --shell-radius-md: 6px;
53
+ --shell-radius-lg: 8px;
54
+
41
55
  /* Spacing */
42
56
  --shell-pad-xs: 2px;
43
57
  --shell-pad-sm: 4px;
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** sh3-core package version. Keep in sync with package.json. */
2
- export declare const VERSION = "0.5.1";
2
+ export declare const VERSION = "0.5.4";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /** sh3-core package version. Keep in sync with package.json. */
2
- export const VERSION = '0.5.1';
2
+ export const VERSION = '0.5.4';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh3-core",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"