dsh-edge 0.9.0 → 0.10.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 (56) hide show
  1. package/THIRD_PARTY_NOTICES.md +1318 -1075
  2. package/dist/assets/index-Df-65__b.js +110 -0
  3. package/dist/assets/index-b24khbeK.css +1 -0
  4. package/dist/assets/langs/{php-DDkx9sim.js → php-DJl5gRdb.js} +2 -2
  5. package/dist/assets/langs/{ruby-DCxyoPen.js → ruby-5eNB0pDK.js} +2 -2
  6. package/dist/assets/vendor-BNsW4eBh.css +1 -0
  7. package/dist/assets/vendor-CCJJTK99.js +411 -0
  8. package/dist/index.html +8 -8
  9. package/dist/plugins/@deepseek-ai/dsh-api-gateway/client.js +1513 -77
  10. package/dist/plugins/@deepseek-ai/dsh-api-remotes/client.js +3608 -757
  11. package/dist/plugins/@deepseek-ai/dsh-api-session-controller/client.js +2777 -0
  12. package/dist/plugins/@deepseek-ai/dsh-api-workspace-controller/client.js +415 -0
  13. package/dist/plugins/@deepseek-ai/dsh-client-connection/client.js +1975 -7466
  14. package/dist/plugins/@deepseek-ai/dsh-client-locale/client.js +225 -76
  15. package/dist/plugins/@deepseek-ai/dsh-client-modules/client.js +67 -15
  16. package/dist/plugins/@deepseek-ai/dsh-client-ui-agent-preset/client.js +270 -460
  17. package/dist/plugins/@deepseek-ai/dsh-client-ui-approval/client.js +292 -0
  18. package/dist/plugins/@deepseek-ai/dsh-client-ui-attachment/client.js +42 -17
  19. package/dist/plugins/@deepseek-ai/dsh-client-ui-brand-official/client.js +7 -9
  20. package/dist/plugins/@deepseek-ai/dsh-client-ui-chat/client.js +8177 -0
  21. package/dist/plugins/@deepseek-ai/dsh-client-ui-commands/client.js +22 -10
  22. package/dist/plugins/@deepseek-ai/dsh-client-ui-conversation/client.js +14950 -8910
  23. package/dist/plugins/@deepseek-ai/dsh-client-ui-deliverables/client.js +161 -137
  24. package/dist/plugins/@deepseek-ai/dsh-client-ui-goal/client.js +6 -7
  25. package/dist/plugins/@deepseek-ai/dsh-client-ui-input-trigger/client.js +268 -40
  26. package/dist/plugins/@deepseek-ai/dsh-client-ui-jobs/client.js +1 -1
  27. package/dist/plugins/@deepseek-ai/dsh-client-ui-layout/client.js +45 -11
  28. package/dist/plugins/@deepseek-ai/dsh-client-ui-message-feedback/client.js +30 -58
  29. package/dist/plugins/@deepseek-ai/dsh-client-ui-model-selection/client.js +188 -89
  30. package/dist/plugins/@deepseek-ai/dsh-client-ui-permission-presets/client.js +105 -75
  31. package/dist/plugins/@deepseek-ai/dsh-client-ui-renderer/client.js +650 -188
  32. package/dist/plugins/@deepseek-ai/dsh-client-ui-schedule/client.js +307 -0
  33. package/dist/plugins/@deepseek-ai/dsh-client-ui-session/client.js +340 -0
  34. package/dist/plugins/@deepseek-ai/dsh-client-ui-settings/client.js +57 -50
  35. package/dist/plugins/@deepseek-ai/dsh-client-ui-settings-general/client.js +134 -69
  36. package/dist/plugins/@deepseek-ai/dsh-client-ui-settings-models/client.js +575 -442
  37. package/dist/plugins/@deepseek-ai/dsh-client-ui-sidebar/client.js +24 -11
  38. package/dist/plugins/@deepseek-ai/dsh-client-ui-skill/client.js +13 -9
  39. package/dist/plugins/@deepseek-ai/dsh-client-ui-subagent/client.js +44 -20
  40. package/dist/plugins/@deepseek-ai/dsh-client-ui-theme/client.js +265 -94
  41. package/dist/plugins/@deepseek-ai/dsh-client-ui-tool/client.js +899 -433
  42. package/dist/plugins/@deepseek-ai/dsh-client-ui-trajectory/client.js +1472 -613
  43. package/dist/plugins/@deepseek-ai/dsh-client-ui-user-questions/client.js +249 -95
  44. package/dist/plugins/@deepseek-ai/dsh-client-ui-workflow-run/client.js +5 -5
  45. package/dist/plugins/@deepseek-ai/dsh-client-ui-workspace/client.js +425 -146
  46. package/dist/plugins/@deepseek-ai/dsh-typert-registry/client.js +29 -14
  47. package/dist/plugins/dsh-edge-client-ui/client.js +28 -26
  48. package/package.json +62 -58
  49. package/scripts/verify-packed.mjs +1 -1
  50. package/worker/direct/index.js +2866 -1466
  51. package/worker/isolated/index.js +2438 -1038
  52. package/dist/assets/index-C6eRlFa6.css +0 -1
  53. package/dist/assets/index-ClqxG24t.js +0 -96
  54. package/dist/assets/vendor-CjyC-hUb.css +0 -1
  55. package/dist/assets/vendor-D22_Mp1f.js +0 -411
  56. package/dist/plugins/@deepseek-ai/dsh-client-runtime/client.js +0 -10574
@@ -12,6 +12,7 @@ window.__ModuleLoader__.load({
12
12
  let react_dom_client = require("react-dom/client");
13
13
  let react_jsx_runtime = require("react/jsx-runtime");
14
14
  let _deepseek_ai_dsh_client_ui_slots = require("@deepseek-ai/dsh-client-ui-slots");
15
+ let _deepseek_ai_cordis = require("@deepseek-ai/cordis");
15
16
  //#region ../../../node_modules/.pnpm/use-sync-external-store@1.2.0_react@18.3.1/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.production.min.js
16
17
  /**
17
18
  * @license React
@@ -159,40 +160,45 @@ window.__ModuleLoader__.load({
159
160
  };
160
161
  }
161
162
  //#endregion
162
- //#region lib/types/client/session-provider.js
163
- /** Internal React bindings for the renderer host and active session provide bundle. */
164
- /**
165
- * A missing-provider assembly error: the shell wired the tree wrong. The slot
166
- * error boundary rethrows this class so misassembly stays fail-loud while
167
- * registrant errors (inject factories, entry components) are contained
168
- * per entry.
169
- */
163
+ //#region lib/types/client/bindings.js
164
+ /** Internal React bindings for renderer hosts and standard-source scopes. */
165
+ /** Missing renderer assembly dependency. */
170
166
  var SlotAssemblyError = class extends Error {};
171
167
  /** In-package renderer host context. */
172
168
  const HostContext = (0, react.createContext)(null);
173
169
  /**
174
- * Read the installed renderer host; throws outside the rendered root tree
175
- * (framework components must not render detached from the renderer).
170
+ * Read the installed renderer host.
176
171
  * @returns the host API.
177
172
  */
178
173
  function useHost() {
179
174
  const host = (0, react.useContext)(HostContext);
180
- if (!host) throw new SlotAssemblyError("slot machinery rendered outside the installed renderer tree");
175
+ if (host === null) throw new SlotAssemblyError("slot machinery rendered outside the installed renderer tree");
181
176
  return host;
182
177
  }
183
- const BindingContext = (0, react.createContext)(null);
184
- /** Read the current-session-optional bundle supplied at the root. */
185
- function useSessionMaybeProvideInfo() {
186
- const info = (0, react.useContext)(BindingContext);
187
- if (!info) throw new SlotAssemblyError("session-aware slot rendered outside the root binding provider");
188
- return info;
178
+ const RootBindingContext = (0, react.createContext)(null);
179
+ const ScopeBindingContext = (0, react.createContext)(null);
180
+ /**
181
+ * Read the root standard-source binding.
182
+ * @returns the current root binding.
183
+ */
184
+ function useRootBinding() {
185
+ const binding = (0, react.useContext)(RootBindingContext);
186
+ if (binding === null) throw new SlotAssemblyError("slot rendered outside the root standard-source provider");
187
+ return binding;
189
188
  }
190
189
  /**
191
- * Identity-stable selector hook per host observable. uSES resubscribes when
192
- * the subscribe reference changes, so the bound hook must be created once per
193
- * source — cached here by source identity (sources are host-owned singletons).
194
- * @param source - host-provided observable.
195
- * @returns the cached selector hook.
190
+ * Read the current-session-optional binding.
191
+ * @returns a binding whose key is absent when no Session is selected.
192
+ */
193
+ function useScopeBinding() {
194
+ const binding = (0, react.useContext)(ScopeBindingContext);
195
+ if (binding === null) throw new SlotAssemblyError("scoped slot rendered outside its scope provider");
196
+ return binding;
197
+ }
198
+ /**
199
+ * Bind one observable source to an identity-stable selector Hook.
200
+ * @param source - observable source.
201
+ * @returns cached selector Hook.
196
202
  */
197
203
  function observableHook(source) {
198
204
  let hook = hookCache.get(source);
@@ -207,7 +213,11 @@ window.__ModuleLoader__.load({
207
213
  getSnapshot: () => void 0,
208
214
  subscribe: () => () => {}
209
215
  };
210
- /** Bind a source that disappears with the current session to an optional selector hook. */
216
+ /**
217
+ * Bind an optional source without changing Hook call order.
218
+ * @param source - current source, or absence.
219
+ * @returns selector Hook returning `undefined` while absent.
220
+ */
211
221
  function maybeObservableHook(source) {
212
222
  if (source !== void 0) return observableHook(source);
213
223
  return useAbsentSnapshot;
@@ -216,54 +226,43 @@ window.__ModuleLoader__.load({
216
226
  observableHook(absentSource)(() => void 0);
217
227
  }
218
228
  /**
219
- * The useProjection framework seat (docs/subsystems/session-projection.md), one bound
220
- * function per provide bundle (cached by info identity — components may hold
221
- * it across renders). Key-addressed: the key resolves a per-session value
222
- * face off the projection store; the bound selector hook comes from the same
223
- * per-source cache as every other kit hook, so exactly one uSES subscription
224
- * runs per call and the subscribe reference stays stable per key. A key no
225
- * baseline or frame has carried (or a no-session bundle) reads `undefined` —
226
- * capability absence — keeping the hook order constant.
229
+ * Bind an open-key source family.
230
+ * @param source - keyed resolver, or absence for an optional scope.
231
+ * @returns cached keyed selector Hook.
227
232
  */
228
- function projectionHook(info) {
229
- let hook = projectionHookCache.get(info);
233
+ function keyedObservableHook(source) {
234
+ if (source === void 0) return absentKeyedHook;
235
+ let hook = keyedHookCache.get(source);
230
236
  if (hook === void 0) {
231
- hook = (key, selector, eq) => {
232
- return observableHook(info.projections?.faceOf(key) ?? absentSource)(selector ?? ((value) => value), eq);
237
+ hook = (key, selector, equal) => {
238
+ return observableHook(source(key) ?? absentSource)(selector ?? identity, equal);
233
239
  };
234
- projectionHookCache.set(info, hook);
240
+ keyedHookCache.set(source, hook);
235
241
  }
236
242
  return hook;
237
243
  }
238
- const projectionHookCache = /* @__PURE__ */ new WeakMap();
239
- /**
240
- * Root-level binding provider. It follows current selection without a key;
241
- * per-entry identity is the outlet's adoption bookkeeping (SessionMaybeEntry):
242
- * a blank-born incarnation adopts the first session without remounting, and
243
- * every later transition (switch or loss) remounts like a strict entry.
244
- */
245
- function SessionMaybeProvider({ children }) {
246
- const info = observableHook(useHost().sessions.provideInfo)((s) => s);
247
- return (0, react_jsx_runtime.jsx)(BindingContext.Provider, {
248
- value: info,
244
+ const keyedHookCache = /* @__PURE__ */ new WeakMap();
245
+ const identity = (value) => value;
246
+ const absentKeyedHook = (_key, selector, equal) => observableHook(absentSource)(selector ?? identity, equal);
247
+ /** Subscribe the tree to the atomically assembled root standard-source roster. */
248
+ function RootStandardProvider({ children }) {
249
+ const binding = observableHook(useHost().root)((value) => value);
250
+ return (0, react_jsx_runtime.jsx)(RootBindingContext.Provider, {
251
+ value: binding,
249
252
  children
250
253
  });
251
254
  }
252
- /**
253
- * Framework-wired session area: subscribes to the host's current provide
254
- * source and remounts the body under `key={sessionId}` so a session switch
255
- * rebuilds the session subtree. This dependency-inverted layer uses plain
256
- * string ids; `PropsRuntime` applies the branded type at the component
257
- * boundary.
258
- */
259
- function SessionProvider({ empty, children }) {
260
- const info = observableHook(useHost().sessions.provideInfo)((s) => s);
261
- const id = info.sessionId;
262
- if (id === void 0) return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: empty?.() ?? null });
263
- return (0, react_jsx_runtime.jsx)(BindingContext.Provider, {
264
- value: info,
265
- children: children(id)
266
- }, id);
255
+ /** Subscribe to the scope roster before resolving and binding its current adapter. */
256
+ function ScopeProvider({ scope, children }) {
257
+ const host = useHost();
258
+ observableHook(host.scopeRevision)((value) => value);
259
+ const adapter = host.scope(scope);
260
+ if (adapter === void 0) throw new SlotAssemblyError(`scope '${scope}' rendered without an installed adapter`);
261
+ const binding = observableHook(adapter.current)((value) => value);
262
+ return (0, react_jsx_runtime.jsx)(ScopeBindingContext.Provider, {
263
+ value: binding,
264
+ children
265
+ });
267
266
  }
268
267
  //#endregion
269
268
  //#region lib/types/client/scoped-slots.js
@@ -323,7 +322,7 @@ window.__ModuleLoader__.load({
323
322
  }
324
323
  /**
325
324
  * Inject results cache: root entries per entry, session entries per
326
- * (entry x provide bundle). WeakMap keys are entry/info objects (both
325
+ * (entry x scope binding). WeakMap keys are entry/binding objects (both
327
326
  * identity-stable per registration/session scope), so cache lifetime rides
328
327
  * the same axes as the values it memoizes.
329
328
  */
@@ -331,27 +330,29 @@ window.__ModuleLoader__.load({
331
330
  const sessionInjectCache = /* @__PURE__ */ new WeakMap();
332
331
  const sessionMaybeInjectCache = /* @__PURE__ */ new WeakMap();
333
332
  const EMPTY_INJECTED_PROPS = {};
334
- function runInject(entry, info, actions) {
333
+ function runInject(entry, binding, actions) {
335
334
  const inject = entry.inject;
336
335
  if (!inject) return EMPTY_INJECTED_PROPS;
337
336
  const args = [];
338
- if (info !== void 0) args.push(info.sessionId);
337
+ if (binding !== void 0) args.push(binding.key);
339
338
  if (actions !== void 0) args.push(actions);
340
- return bindInjectHooks(inject(...args));
339
+ return bindInjectSources(inject(...args));
341
340
  }
342
- /**
343
- * Normalize one entry-owned inject face on its existing cache axis. Its hooks
344
- * compartment remains the original Observable-only contract.
345
- */
346
- function bindInjectHooks(face) {
341
+ /** Bind one entry-owned inject face on its existing cache axis. */
342
+ function bindInjectSources(face) {
347
343
  const sources = face["hooks"];
348
- if (sources === void 0) return face;
349
- const { hooks: _hooks, ...rest } = face;
344
+ const keyedSources = face["keyedHooks"];
345
+ if (sources === void 0 && keyedSources === void 0) return face;
346
+ const { hooks: _hooks, keyedHooks: _keyedHooks, ...rest } = face;
350
347
  const bound = rest;
351
- for (const [name, source] of Object.entries(sources)) {
352
- const hookName = `use${name[0]?.toUpperCase() ?? ""}${name.slice(1)}`;
348
+ for (const [name, source] of Object.entries(sources ?? {})) {
349
+ const hookName = (0, _deepseek_ai_dsh_client_ui_slots.standardHookPropName)(name);
353
350
  bound[hookName] = observableHook(source);
354
351
  }
352
+ for (const [name, source] of Object.entries(keyedSources ?? {})) {
353
+ const hookName = (0, _deepseek_ai_dsh_client_ui_slots.standardHookPropName)(name);
354
+ bound[hookName] = keyedObservableHook(source);
355
+ }
355
356
  return bound;
356
357
  }
357
358
  const slotInjectCache = /* @__PURE__ */ new WeakMap();
@@ -371,7 +372,7 @@ window.__ModuleLoader__.load({
371
372
  const props = rest;
372
373
  let factories;
373
374
  for (const [name, definition] of Object.entries(definitions)) {
374
- const hookName = `use${name[0]?.toUpperCase() ?? ""}${name.slice(1)}`;
375
+ const hookName = (0, _deepseek_ai_dsh_client_ui_slots.standardHookPropName)(name);
375
376
  if (typeof definition === "function") {
376
377
  factories ??= {};
377
378
  factories[name] = definition;
@@ -388,7 +389,7 @@ window.__ModuleLoader__.load({
388
389
  function bindSlotHookFactories(factories, standard, hookContext) {
389
390
  const hooks = {};
390
391
  for (const [name, factory] of Object.entries(factories)) {
391
- const hookName = `use${name[0]?.toUpperCase() ?? ""}${name.slice(1)}`;
392
+ const hookName = (0, _deepseek_ai_dsh_client_ui_slots.standardHookPropName)(name);
392
393
  hooks[hookName] = factory(standard, hookContext);
393
394
  }
394
395
  return hooks;
@@ -401,29 +402,29 @@ window.__ModuleLoader__.load({
401
402
  }
402
403
  return props;
403
404
  }
404
- function cachedSessionInject(entry, info, actions) {
405
- let perInfo = sessionInjectCache.get(entry);
406
- if (!perInfo) {
407
- perInfo = /* @__PURE__ */ new WeakMap();
408
- sessionInjectCache.set(entry, perInfo);
405
+ function cachedSessionInject(entry, binding, actions) {
406
+ let perBinding = sessionInjectCache.get(entry);
407
+ if (!perBinding) {
408
+ perBinding = /* @__PURE__ */ new WeakMap();
409
+ sessionInjectCache.set(entry, perBinding);
409
410
  }
410
- let props = perInfo.get(info);
411
+ let props = perBinding.get(binding);
411
412
  if (!props) {
412
- props = runInject(entry, info, actions);
413
- perInfo.set(info, props);
413
+ props = runInject(entry, binding, actions);
414
+ perBinding.set(binding, props);
414
415
  }
415
416
  return props;
416
417
  }
417
- function cachedSessionMaybeInject(entry, info, actions) {
418
- let perInfo = sessionMaybeInjectCache.get(entry);
419
- if (!perInfo) {
420
- perInfo = /* @__PURE__ */ new WeakMap();
421
- sessionMaybeInjectCache.set(entry, perInfo);
418
+ function cachedSessionMaybeInject(entry, binding, actions) {
419
+ let perBinding = sessionMaybeInjectCache.get(entry);
420
+ if (!perBinding) {
421
+ perBinding = /* @__PURE__ */ new WeakMap();
422
+ sessionMaybeInjectCache.set(entry, perBinding);
422
423
  }
423
- let props = perInfo.get(info);
424
+ let props = perBinding.get(binding);
424
425
  if (!props) {
425
- props = runInject(entry, info, actions);
426
- perInfo.set(info, props);
426
+ props = runInject(entry, binding, actions);
427
+ perBinding.set(binding, props);
427
428
  }
428
429
  return props;
429
430
  }
@@ -530,41 +531,59 @@ window.__ModuleLoader__.load({
530
531
  return this.props.children;
531
532
  }
532
533
  };
533
- const standardPropsCache = /* @__PURE__ */ new WeakMap();
534
+ const rootStandardCache = /* @__PURE__ */ new WeakMap();
535
+ const sessionStandardCache = /* @__PURE__ */ new WeakMap();
536
+ const sessionMaybeStandardCache = /* @__PURE__ */ new WeakMap();
537
+ /** Materialize one binding into stable framework Hook and plain-prop seats. */
538
+ function materializeStandardBinding(binding, optional) {
539
+ const standard = { ...binding.props };
540
+ for (const [name, source] of Object.entries(binding.hooks)) {
541
+ if (source === void 0 && !optional) throw new SlotAssemblyError(`strict standard hook '${name}' has no source`);
542
+ standard[(0, _deepseek_ai_dsh_client_ui_slots.standardHookPropName)(name)] = optional ? maybeObservableHook(source) : observableHook(source);
543
+ }
544
+ for (const [name, source] of Object.entries(binding.keyedHooks)) {
545
+ if (source === void 0 && !optional) throw new SlotAssemblyError(`strict keyed standard hook '${name}' has no source resolver`);
546
+ standard[(0, _deepseek_ai_dsh_client_ui_slots.standardHookPropName)(name)] = keyedObservableHook(source);
547
+ }
548
+ return standard;
549
+ }
534
550
  /** Stable official-props object used by contextual Hook factories. */
535
- function standardProps(host, scope, info) {
536
- let cache = standardPropsCache.get(host);
537
- if (cache === void 0) {
538
- cache = {
539
- root: {
540
- useSessions: observableHook(host.sessions.list),
541
- useWorkspaces: observableHook(host.workspaces.list)
542
- },
543
- session: /* @__PURE__ */ new WeakMap(),
544
- sessionMaybe: /* @__PURE__ */ new WeakMap()
545
- };
546
- standardPropsCache.set(host, cache);
551
+ function standardProps(scope, rootBinding, scopeBinding) {
552
+ let root = rootStandardCache.get(rootBinding);
553
+ if (root === void 0) {
554
+ root = materializeStandardBinding(rootBinding, false);
555
+ rootStandardCache.set(rootBinding, root);
547
556
  }
548
- if (scope === "root") return cache.root;
549
- if (info === void 0) throw new SlotAssemblyError(`scope '${scope}' rendered without session provide info`);
550
- const byInfo = scope === "session" ? cache.session : cache.sessionMaybe;
551
- let standard = byInfo.get(info);
552
- if (standard !== void 0) return standard;
553
- standard = { ...cache.root };
554
- for (const [name, source] of Object.entries(info.hooks)) {
555
- const hookName = `use${name[0]?.toUpperCase() ?? ""}${name.slice(1)}`;
556
- if (scope === "session-maybe") standard[hookName] = maybeObservableHook(source);
557
- else {
558
- if (source === void 0) throw new SlotAssemblyError(`strict session hook '${name}' has no source`);
559
- standard[hookName] = observableHook(source);
560
- }
557
+ if (scope === "root") return root;
558
+ if (scopeBinding === void 0) throw new SlotAssemblyError(`scope '${scope}' rendered without a standard-source binding`);
559
+ const cache = scope === "session" ? sessionStandardCache : sessionMaybeStandardCache;
560
+ let perScope = cache.get(rootBinding);
561
+ if (perScope === void 0) {
562
+ perScope = /* @__PURE__ */ new WeakMap();
563
+ cache.set(rootBinding, perScope);
561
564
  }
562
- Object.assign(standard, info.props);
563
- standard["sessionId"] = info.sessionId;
564
- standard["useProjection"] = projectionHook(info);
565
- byInfo.set(info, standard);
565
+ let standard = perScope.get(scopeBinding);
566
+ if (standard !== void 0) return standard;
567
+ standard = {
568
+ ...root,
569
+ ...materializeStandardBinding(scopeBinding, scope === "session-maybe")
570
+ };
571
+ perScope.set(scopeBinding, standard);
566
572
  return standard;
567
573
  }
574
+ const scopeAreaCache = /* @__PURE__ */ new WeakMap();
575
+ /** Bind one domain-owned scope area renderer to the current scope binding. */
576
+ function scopeAreaProvider(adapter) {
577
+ let Provider = scopeAreaCache.get(adapter);
578
+ if (Provider !== void 0) return Provider;
579
+ if (adapter.renderArea === void 0) throw new SlotAssemblyError("scope 'session' adapter does not provide its area renderer");
580
+ const renderArea = adapter.renderArea.bind(adapter);
581
+ Provider = function ScopeAreaProvider(props) {
582
+ return renderArea(useScopeBinding(), props);
583
+ };
584
+ scopeAreaCache.set(adapter, Provider);
585
+ return Provider;
586
+ }
568
587
  /**
569
588
  * Standard-kit synthesis shared by both scope branches: the global
570
589
  * useSessions/useWorkspaces hooks, the per-session provide bundle (every
@@ -577,15 +596,16 @@ window.__ModuleLoader__.load({
577
596
  * per source (observableHook), so spreading a fresh kit object per render
578
597
  * never churns child subscriptions.
579
598
  */
580
- function standardKit(host, entry, scope, info) {
581
- const standard = standardProps(host, scope, info);
599
+ function standardKit(host, entry, scope, rootBinding, scopeBinding) {
600
+ const standard = standardProps(scope, rootBinding, scopeBinding);
582
601
  const kit = { ...standard };
583
602
  if (entry.locale !== void 0) {
584
603
  const face = host.locale;
585
604
  if (face === void 0) throw new SlotAssemblyError(`entry declares locale namespace '${entry.locale}' but no locale face is installed (locale plugin missing from the composition?)`);
586
605
  kit["t"] = localeSeat(face, entry.locale);
587
606
  }
588
- const store = scope === "session-maybe" && info?.sessionId === void 0 ? void 0 : host.storeOf(entry, info?.sessionId);
607
+ const scopedStoreBinding = scopeBinding?.key === void 0 ? void 0 : scopeBinding;
608
+ const store = host.storeOf(entry, scopedStoreBinding);
589
609
  if (store !== void 0) {
590
610
  kit["useStore"] = observableHook(store);
591
611
  kit["actions"] = store.actions;
@@ -593,7 +613,11 @@ window.__ModuleLoader__.load({
593
613
  if (entry.children !== void 0) {
594
614
  kit["renderSlot"] = boundRenderSlot(host, entry);
595
615
  if (Object.values(entry.children).some((spec) => spec.kind === "chain")) kit["renderSlotChain"] = boundRenderSlotChain(host, entry);
596
- if (Object.values(entry.children).some((spec) => spec.scope === "session")) kit["SessionProvider"] = SessionProvider;
616
+ if (Object.values(entry.children).some((spec) => spec.scope === "session")) {
617
+ const adapter = host.scope("session");
618
+ if (adapter === void 0) throw new SlotAssemblyError("entry declares a session child without an installed 'session' scope adapter");
619
+ kit["SessionProvider"] = scopeAreaProvider(adapter);
620
+ }
597
621
  }
598
622
  return {
599
623
  kit,
@@ -644,17 +668,19 @@ window.__ModuleLoader__.load({
644
668
  hasHookContext
645
669
  });
646
670
  }
647
- function SessionEntry({ entry, ownerProps, info, slotKey, slotInjected, hookContext, hasHookContext }) {
671
+ function SessionEntry({ entry, ownerProps, binding, slotKey, slotInjected, hookContext, hasHookContext }) {
648
672
  const host = useHost();
673
+ const rootBinding = useRootBinding();
649
674
  const Comp = entry.component;
650
- const { kit, standard, actions } = standardKit(host, entry, "session", info);
651
- return renderEntry(slotKey, Comp, kit, standard, cachedSessionInject(entry, info, actions), slotInjected, ownerProps, hookContext, hasHookContext);
675
+ const { kit, standard, actions } = standardKit(host, entry, "session", rootBinding, binding);
676
+ return renderEntry(slotKey, Comp, kit, standard, cachedSessionInject(entry, binding, actions), slotInjected, ownerProps, hookContext, hasHookContext);
652
677
  }
653
- function SessionMaybeEntryBody({ entry, ownerProps, info, slotKey, slotInjected, hookContext, hasHookContext }) {
678
+ function SessionMaybeEntryBody({ entry, ownerProps, binding, slotKey, slotInjected, hookContext, hasHookContext }) {
654
679
  const host = useHost();
680
+ const rootBinding = useRootBinding();
655
681
  const Comp = entry.component;
656
- const { kit, standard, actions } = standardKit(host, entry, "session-maybe", info);
657
- return renderEntry(slotKey, Comp, kit, standard, cachedSessionMaybeInject(entry, info, actions), slotInjected, ownerProps, hookContext, hasHookContext);
682
+ const { kit, standard, actions } = standardKit(host, entry, "session-maybe", rootBinding, binding);
683
+ return renderEntry(slotKey, Comp, kit, standard, cachedSessionMaybeInject(entry, binding, actions), slotInjected, ownerProps, hookContext, hasHookContext);
658
684
  }
659
685
  /**
660
686
  * Session-maybe identity: adoption — the ONLY behavior (there is no
@@ -670,23 +696,23 @@ window.__ModuleLoader__.load({
670
696
  * store, hooks) — the existing layering rule, now load-bearing.
671
697
  */
672
698
  function SessionMaybeEntry({ entry, ownerProps, slotKey, slotInjected, hookContext, hasHookContext }) {
673
- const info = useSessionMaybeProvideInfo();
699
+ const binding = useScopeBinding();
674
700
  const [state, setState] = (0, react.useState)(FIRST_INCARNATION);
675
701
  let { adopted, epoch } = state;
676
- if (info.sessionId !== void 0 && adopted === void 0) {
677
- adopted = info.sessionId;
702
+ if (binding.key !== void 0 && adopted === void 0) {
703
+ adopted = binding.key;
678
704
  setState({
679
705
  adopted,
680
706
  epoch
681
707
  });
682
- } else if (adopted !== void 0 && info.sessionId !== void 0 && info.sessionId !== adopted) {
683
- adopted = info.sessionId;
708
+ } else if (adopted !== void 0 && binding.key !== void 0 && binding.key !== adopted) {
709
+ adopted = binding.key;
684
710
  epoch += 1;
685
711
  setState({
686
712
  adopted,
687
713
  epoch
688
714
  });
689
- } else if (adopted !== void 0 && info.sessionId === void 0) {
715
+ } else if (adopted !== void 0 && binding.key === void 0) {
690
716
  adopted = void 0;
691
717
  epoch += 1;
692
718
  setState({
@@ -697,7 +723,7 @@ window.__ModuleLoader__.load({
697
723
  return (0, react_jsx_runtime.jsx)(SessionMaybeEntryBody, {
698
724
  entry,
699
725
  ownerProps,
700
- info,
726
+ binding,
701
727
  slotKey,
702
728
  slotInjected,
703
729
  hookContext,
@@ -710,26 +736,27 @@ window.__ModuleLoader__.load({
710
736
  };
711
737
  function RootEntry({ entry, ownerProps, slotKey, slotInjected, hookContext, hasHookContext }) {
712
738
  const host = useHost();
739
+ const rootBinding = useRootBinding();
713
740
  const Comp = entry.component;
714
- const { kit, standard, actions } = standardKit(host, entry, "root", void 0);
741
+ const { kit, standard, actions } = standardKit(host, entry, "root", rootBinding, void 0);
715
742
  return renderEntry(slotKey, Comp, kit, standard, cachedRootInject(entry, actions), slotInjected, ownerProps, hookContext, hasHookContext);
716
743
  }
717
744
  function StrictSessionEntry({ slotKey, entry, ownerProps, slotInjected, hookContext, hasHookContext, onEntryError }) {
718
- const info = useSessionMaybeProvideInfo();
719
- if (info.sessionId === void 0) return null;
745
+ const binding = useScopeBinding();
746
+ if (binding.key === void 0) throw new SlotAssemblyError(`strict session slot '${slotKey}' rendered without a scope binding`);
720
747
  return (0, react_jsx_runtime.jsx)(SlotErrorBoundary, {
721
748
  slotKey,
722
749
  onEntryError,
723
750
  children: (0, react_jsx_runtime.jsx)(SessionEntry, {
724
751
  entry,
725
752
  ownerProps,
726
- info,
753
+ binding,
727
754
  slotKey,
728
755
  slotInjected,
729
756
  hookContext,
730
757
  hasHookContext
731
758
  })
732
- }, info.sessionId);
759
+ }, binding.key);
733
760
  }
734
761
  /**
735
762
  * Anchor style shared by every outlet wrapper: `display:contents` keeps the
@@ -745,16 +772,16 @@ window.__ModuleLoader__.load({
745
772
  return (0, react_jsx_runtime.jsx)("div", {
746
773
  "data-slot": slotKey,
747
774
  style: ANCHOR_STYLE,
748
- children: renderOutletContent(host, slotKey, ownerProps, opts, useSessionMaybeProvideInfo())
775
+ children: renderOutletContent(host, slotKey, ownerProps, opts, useScopeBinding())
749
776
  });
750
777
  }
751
778
  /** Kind dispatch behind the outlet anchor (single/keyed/list/chain, fallbacks, crash faces). */
752
- function renderOutletContent(host, slotKey, ownerProps, opts, sessionInfo) {
779
+ function renderOutletContent(host, slotKey, ownerProps, opts, scopeBinding) {
753
780
  const spec = host.specOf(slotKey);
754
781
  if (!spec) return null;
755
- const strictSessionAbsent = spec.scope === "session" && sessionInfo.sessionId === void 0;
756
- if (strictSessionAbsent && (spec.kind !== "chain" || !opts?.overlay)) return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: opts?.fallback ?? null });
757
- const entries = strictSessionAbsent ? [] : host.entriesOf(slotKey);
782
+ if (spec.kind === "chain" && opts?.fallbackOnly === true) return renderChainResult(slotKey, null, opts);
783
+ if (spec.scope === "session" && scopeBinding.key === void 0) throw new SlotAssemblyError(`strict session slot '${slotKey}' rendered without a scope binding`);
784
+ const entries = host.entriesOf(slotKey);
758
785
  const slotInjected = cachedSlotInject(spec.inject);
759
786
  const guarded = (entry, key, owner = ownerProps) => {
760
787
  const hasHookContext = opts !== void 0 && Object.hasOwn(opts, "hookContext");
@@ -819,12 +846,7 @@ window.__ModuleLoader__.load({
819
846
  break;
820
847
  }
821
848
  }
822
- if (opts?.overlay) return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
823
- "data-chain-overlay-fallback": slotKey,
824
- style: { display: elected === null ? "contents" : "none" },
825
- children: opts.fallback ?? null
826
- }), elected] });
827
- return elected ?? (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: opts?.fallback ?? null });
849
+ return renderChainResult(slotKey, elected, opts);
828
850
  }
829
851
  const rows = host.entriesOfSlot(slotKey).map((entry) => ({
830
852
  entry,
@@ -846,6 +868,15 @@ window.__ModuleLoader__.load({
846
868
  if (list.length === 0) return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: opts?.fallback ?? null });
847
869
  return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: list.map((item, i) => item.entry !== void 0 ? guarded(item.entry, `e${entryKeyOf(item.entry)}`) : (0, react_jsx_runtime.jsx)("div", { "data-slot-error": slotKey }, `x${item.id ?? i}`)) });
848
870
  }
871
+ /** Render a chain election while preserving the overlay fallback's tree position. */
872
+ function renderChainResult(slotKey, elected, opts) {
873
+ if (!opts?.overlay) return elected ?? (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: opts?.fallback ?? null });
874
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
875
+ "data-chain-overlay-fallback": slotKey,
876
+ style: { display: elected === null ? "contents" : "none" },
877
+ children: opts.fallback ?? null
878
+ }), elected] });
879
+ }
849
880
  /** Root outlet: the shell's single ctx-level render entry — an unregistered 'root' is a boot-order failure, never a silent blank. */
850
881
  function RootOutlet({ ownerProps }) {
851
882
  const host = useHost();
@@ -876,7 +907,7 @@ window.__ModuleLoader__.load({
876
907
  });
877
908
  }
878
909
  /**
879
- * Build the renderer the shell installs into the runtime SlotRegistry
910
+ * Build the renderer installed into the `ui-renderer` SlotRegistry
880
911
  * (ctx.slots.install(createSlotRenderer()) at boot; the service owns the
881
912
  * install/renderSlot contract and the double-install/not-installed throws).
882
913
  * @returns the renderer.
@@ -885,29 +916,14 @@ window.__ModuleLoader__.load({
885
916
  return { renderRoot(host, ownerProps) {
886
917
  return (0, react_jsx_runtime.jsx)(HostContext.Provider, {
887
918
  value: host,
888
- children: (0, react_jsx_runtime.jsx)(SessionMaybeProvider, { children: (0, react_jsx_runtime.jsx)(RootOutlet, { ownerProps }) })
919
+ children: (0, react_jsx_runtime.jsx)(RootStandardProvider, { children: (0, react_jsx_runtime.jsx)(ScopeProvider, {
920
+ scope: "session-maybe",
921
+ children: (0, react_jsx_runtime.jsx)(RootOutlet, { ownerProps })
922
+ }) })
889
923
  });
890
924
  } };
891
925
  }
892
926
  //#endregion
893
- //#region lib/types/client/DocumentTitle.js
894
- /**
895
- * Project the selected durable session title into the browser title and
896
- * restore the build-selected product title when unmounted.
897
- * @param props - Selected session title projection.
898
- * @returns No rendered content.
899
- */
900
- function DocumentTitle({ title }) {
901
- const productTitle = "DeepSeek Harness";
902
- (0, react.useEffect)(() => {
903
- document.title = title === void 0 ? productTitle : `${title} — ${productTitle}`;
904
- return () => {
905
- document.title = productTitle;
906
- };
907
- }, [productTitle, title]);
908
- return null;
909
- }
910
- //#endregion
911
927
  //#region lib/types/client/app.js
912
928
  /**
913
929
  * Build the assembled application factory.
@@ -916,18 +932,463 @@ window.__ModuleLoader__.load({
916
932
  */
917
933
  function buildRenderApp(deps) {
918
934
  const { ctx } = deps;
919
- const sessions = ctx.get("sessions");
920
- if (sessions === void 0) throw new Error("ui renderer: sessions service unavailable");
921
- const useSessions = bindSnapshotSelector(sessions.list);
922
- const SessionDocumentTitle = () => {
923
- const title = useSessions((state) => {
924
- const id = state.current;
925
- return id === void 0 ? void 0 : state.byId[id]?.title;
926
- });
927
- return (0, react_jsx_runtime.jsx)(DocumentTitle, { ...title === void 0 ? {} : { title } });
935
+ return () => ctx.slots.renderSlot("root", {});
936
+ }
937
+ //#endregion
938
+ //#region lib/types/client/registry.js
939
+ /**
940
+ * SlotRegistry: the renderer-owned Cordis service over the pure
941
+ * SlotCore (ui-slots owns registration semantics, the declaration ledger,
942
+ * the load-time validations, and the unload cascade). This layer owns what
943
+ * needs a live application: the 'slots/changed' event bridge, register and
944
+ * declaration injection through the caller's ctx.effect (fiber unload
945
+ * collects both), the renderer installation contract (install()/renderSlot('root') +
946
+ * the SlotRendererHost face), and the store INSTANCE axis — handle x scope
947
+ * key -> create/cache, dropped with the last holding entry, session instances
948
+ * cleared (with persisted state) on scope death.
949
+ */
950
+ /** Instance key for root-scoped store records (session records key by session id, so the literal cannot collide). */
951
+ const ROOT_INSTANCE_KEY = "root";
952
+ /** cordis Service layer of the slot system; see the module doc for the split with SlotCore. */
953
+ var SlotRegistry = class extends _deepseek_ai_cordis.Service {
954
+ _core = new _deepseek_ai_dsh_client_ui_slots.SlotCore();
955
+ /** Store-instance axis: handle -> mounted scope, refcount, resolved instances. */
956
+ _stores = /* @__PURE__ */ new Map();
957
+ /** Latest live Context generation for each scoped store key. */
958
+ _storeScopeOwners = /* @__PURE__ */ new Map();
959
+ _renderer;
960
+ _locale;
961
+ _host;
962
+ _rootContributions = [];
963
+ _rootListeners = /* @__PURE__ */ new Set();
964
+ _rootBinding = {
965
+ key: void 0,
966
+ hooks: {},
967
+ keyedHooks: {},
968
+ props: {}
969
+ };
970
+ _rootSource = {
971
+ getSnapshot: () => this._rootBinding,
972
+ subscribe: (listener) => {
973
+ this._rootListeners.add(listener);
974
+ return () => {
975
+ this._rootListeners.delete(listener);
976
+ };
977
+ }
978
+ };
979
+ _scopes = /* @__PURE__ */ new Map();
980
+ _scopeRevision = 0;
981
+ _scopeListeners = /* @__PURE__ */ new Set();
982
+ _scopeRevisionSource = {
983
+ getSnapshot: () => this._scopeRevision,
984
+ subscribe: (listener) => {
985
+ this._scopeListeners.add(listener);
986
+ return () => {
987
+ this._scopeListeners.delete(listener);
988
+ };
989
+ }
928
990
  };
929
- return () => (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(SessionDocumentTitle, {}), ctx.slots.renderSlot("root", {})] });
991
+ /**
992
+ * @param ctx - owning root context.
993
+ */
994
+ constructor(ctx) {
995
+ super(ctx, "slots");
996
+ this._core.onMutate((key) => {
997
+ ctx.emit("slots/changed", key);
998
+ });
999
+ }
1000
+ /**
1001
+ * Install an effect for each declaration lifetime of a slot. The callback
1002
+ * runs synchronously when the declaration already exists; otherwise it runs
1003
+ * inside the declaring `register()` call after the declaration is committed.
1004
+ * Collapse disposes the effect and a later declaration runs it again.
1005
+ * Callback effects are synchronous disposers; iterable effects install
1006
+ * transactionally and dispose in reverse order. The controller belongs to
1007
+ * the caller's fiber, so plugin unload cancels a pending wait and removes any
1008
+ * active contribution.
1009
+ *
1010
+ * @param key - declared SlotMap key to depend on.
1011
+ * @param callback - creates one disposer or an iterable of disposers.
1012
+ * @returns idempotent disposer for the wait and active effect.
1013
+ * @throws callback setup failures synchronously when the slot is already declared.
1014
+ */
1015
+ inject(key, callback) {
1016
+ const ctx = this.ctx;
1017
+ const disposeController = ctx.effect(() => {
1018
+ let active;
1019
+ let activeEpoch;
1020
+ let stopped = false;
1021
+ let unsubscribe = () => {};
1022
+ const stop = () => {
1023
+ if (stopped) return;
1024
+ stopped = true;
1025
+ unsubscribe();
1026
+ const dispose = active;
1027
+ active = void 0;
1028
+ activeEpoch = void 0;
1029
+ dispose?.();
1030
+ };
1031
+ const reconcile = () => {
1032
+ if (stopped) return;
1033
+ const spec = this._core.specDynamic(key);
1034
+ const epoch = this._core.declarationEpoch(key);
1035
+ if (active !== void 0 && activeEpoch === epoch) return;
1036
+ const dispose = active;
1037
+ active = void 0;
1038
+ activeEpoch = void 0;
1039
+ dispose?.();
1040
+ if (spec === void 0) return;
1041
+ const disposeEffect = ctx.effect(callback, `slots.inject(${JSON.stringify(key)}): declaration`);
1042
+ active = () => {
1043
+ disposeEffect();
1044
+ };
1045
+ activeEpoch = epoch;
1046
+ };
1047
+ const changed = () => {
1048
+ try {
1049
+ reconcile();
1050
+ } catch (error) {
1051
+ if (error?.code === "INACTIVE_EFFECT") {
1052
+ stop();
1053
+ return;
1054
+ }
1055
+ stop();
1056
+ const failure = error instanceof Error ? error : new Error(String(error));
1057
+ queueMicrotask(() => {
1058
+ throw failure;
1059
+ });
1060
+ }
1061
+ };
1062
+ unsubscribe = this._core.subscribeDeclaration(key, changed);
1063
+ try {
1064
+ reconcile();
1065
+ } catch (error) {
1066
+ stop();
1067
+ throw error;
1068
+ }
1069
+ return stop;
1070
+ }, `slots.inject(${JSON.stringify(key)})`);
1071
+ return () => {
1072
+ disposeController();
1073
+ };
1074
+ }
1075
+ /**
1076
+ * Install the shell's renderer (ui-renderer's createSlotRenderer product).
1077
+ * Boot-once: a second install throws. Runs through the caller's ctx.effect,
1078
+ * so shell fiber unload uninstalls the renderer.
1079
+ * @param renderer - the outlet machinery implementing SlotRenderer.
1080
+ */
1081
+ install(renderer) {
1082
+ if (this._renderer !== void 0) throw new Error("slot renderer already installed (install() is boot-once)");
1083
+ this.ctx.effect(() => {
1084
+ this._renderer = renderer;
1085
+ return () => {
1086
+ if (this._renderer === renderer) this._renderer = void 0;
1087
+ };
1088
+ }, "slots.install()");
1089
+ }
1090
+ /**
1091
+ * Install the locale face backing the `t` standard seat (the locale
1092
+ * plugin's product; same boot-once discipline as the renderer install).
1093
+ * Runs through the caller's ctx.effect, so the installing fiber's unload
1094
+ * uninstalls the face.
1095
+ * @param face - namespace binder + revision observable.
1096
+ */
1097
+ installLocale(face) {
1098
+ if (this._locale !== void 0) throw new Error("locale face already installed (installLocale() is boot-once)");
1099
+ this.ctx.effect(() => {
1100
+ this._locale = face;
1101
+ return () => {
1102
+ if (this._locale === face) this._locale = void 0;
1103
+ };
1104
+ }, "slots.installLocale()");
1105
+ }
1106
+ /**
1107
+ * Contribute domain-owned root data. Hook names must be globally unique;
1108
+ * registration and disposal republish one atomic root binding.
1109
+ * @param contribution - bare sources and stable props.
1110
+ * @returns disposer owned by the caller's Cordis fiber.
1111
+ */
1112
+ provideRoot(contribution) {
1113
+ const dispose = this.ctx.effect(() => {
1114
+ this._rootContributions.push(contribution);
1115
+ try {
1116
+ this.rebuildRootBinding();
1117
+ } catch (error) {
1118
+ this._rootContributions.pop();
1119
+ throw error;
1120
+ }
1121
+ return () => {
1122
+ const index = this._rootContributions.indexOf(contribution);
1123
+ if (index === -1) return;
1124
+ this._rootContributions.splice(index, 1);
1125
+ this.rebuildRootBinding();
1126
+ };
1127
+ }, "slots.provideRoot()");
1128
+ return () => {
1129
+ dispose();
1130
+ };
1131
+ }
1132
+ /**
1133
+ * Install the owner adapter for one strict scope. Its optional counterpart
1134
+ * resolves through the same adapter.
1135
+ * @param scope - strict scope name.
1136
+ * @param adapter - current/resolved binding source and release notifications.
1137
+ */
1138
+ installScope(scope, adapter) {
1139
+ if (this._scopes.has(scope)) throw new Error(`slot scope '${scope}' already has an adapter`);
1140
+ this.ctx.effect(() => {
1141
+ this._scopes.set(scope, adapter);
1142
+ this.publishScopeRevision();
1143
+ return () => {
1144
+ if (this._scopes.get(scope) === adapter) {
1145
+ this._scopes.delete(scope);
1146
+ this.publishScopeRevision();
1147
+ }
1148
+ };
1149
+ }, `slots.installScope(${JSON.stringify(scope)})`);
1150
+ }
1151
+ /**
1152
+ * Bind all scoped Store handles to one owner Context lifetime. The cleanup
1153
+ * materializes an otherwise-unused handle before clearing it, because a
1154
+ * previous application run may have persisted state for a Slot that this
1155
+ * scope never rendered. Rebinding the same key transfers cleanup ownership
1156
+ * to the newest Context generation.
1157
+ *
1158
+ * @param binding - materialized scope identity and its owning Context.
1159
+ */
1160
+ bindStoreScope(binding) {
1161
+ if (this._storeScopeOwners.get(binding.key) === binding.ctx) return;
1162
+ this._storeScopeOwners.set(binding.key, binding.ctx);
1163
+ binding.ctx.effect(() => () => {
1164
+ if (this._storeScopeOwners.get(binding.key) !== binding.ctx) return;
1165
+ this._storeScopeOwners.delete(binding.key);
1166
+ this.clearStoreScope(binding.key);
1167
+ }, `slots: store scope ${binding.key}`);
1168
+ }
1169
+ /**
1170
+ * The single ctx-level render entry: the shell renders 'root'; every other
1171
+ * key renders inside components through the props renderSlot face. All
1172
+ * three guards are fail-loud boot-order checks, no fallback.
1173
+ * @param key - must be 'root' (runtime-enforced for dynamically composed callers).
1174
+ * @param owner - owner share for the root entry (the shell supplies {}).
1175
+ * @returns the rendered root tree.
1176
+ */
1177
+ renderSlot(key, owner) {
1178
+ if (key !== "root") throw new Error(`ctx-level renderSlot only renders 'root' (got "${key}"); child slots render through the component props face`);
1179
+ if (this._renderer === void 0) throw new Error("slot renderer not installed — boot must call ctx.slots.install(createSlotRenderer()) before rendering 'root'");
1180
+ if (this._core.entries("root").length === 0) throw new Error("'root' has no registration — a layout entry must register into 'root' before the shell renders it");
1181
+ return this._renderer.renderRoot(this.hostFace(), owner);
1182
+ }
1183
+ /**
1184
+ * Snapshot entries for a key (render-erased view; stable reference between mutations).
1185
+ * @param key - SlotMap key.
1186
+ * @returns registered entries.
1187
+ */
1188
+ entries(key) {
1189
+ return this._core.entries(key);
1190
+ }
1191
+ /**
1192
+ * Shadowing winners per cell for a key: the first live (non-abdicated)
1193
+ * entry of each cell in priority order — what outlets render; chain keys
1194
+ * pass through unchanged (election consumes every entry). The raw
1195
+ * {@link SlotsService.entries} view stays the inspection surface. Fresh
1196
+ * array per call, not a uSES getSnapshot source.
1197
+ * @param key - SlotMap key.
1198
+ * @returns the winning entry per occupied cell.
1199
+ */
1200
+ entriesOfSlot(key) {
1201
+ return this._core.entriesOfSlot(key);
1202
+ }
1203
+ /**
1204
+ * Export the current JSON-safe Slot declaration tree for read-only inspection.
1205
+ * @param root - exact live Slot root; omitted returns all roots.
1206
+ * @returns selected Slot trees.
1207
+ */
1208
+ snapshot(root) {
1209
+ return this._core.snapshot(root);
1210
+ }
1211
+ /**
1212
+ * Observe entry boundary crashes (every render-time entry failure the
1213
+ * boundaries contain, abdicating or not) — the supervision seam for
1214
+ * plugins mirroring contribution health. Fires synchronously per report,
1215
+ * after the registry mutated for abdicating crashes. Callers own the
1216
+ * disposer (wire it through ctx.effect for fiber-lifetime cleanup, as with
1217
+ * {@link SlotsService.subscribe}).
1218
+ * @param fn - called with the slot key, the crashed entry, the crash
1219
+ * cause, and `abdicated`: whether the crash retired the entry from its cell.
1220
+ * @returns unsubscribe.
1221
+ */
1222
+ onEntryError(fn) {
1223
+ return this._core.onEntryError(fn);
1224
+ }
1225
+ /**
1226
+ * Look up a declared spec (register-declared or the built-in 'root').
1227
+ * @param key - SlotMap key.
1228
+ * @returns spec or undefined.
1229
+ */
1230
+ spec(key) {
1231
+ return this._core.spec(key);
1232
+ }
1233
+ /**
1234
+ * Subscribe to a key's registration changes (microtask-batched).
1235
+ * @param key - SlotMap key.
1236
+ * @param fn - change callback.
1237
+ * @returns unsubscribe.
1238
+ */
1239
+ subscribe(key, fn) {
1240
+ return this._core.subscribe(key, fn);
1241
+ }
1242
+ /**
1243
+ * Version counter for uSES pairing.
1244
+ * @param key - SlotMap key.
1245
+ * @returns current version.
1246
+ */
1247
+ getVersion(key) {
1248
+ return this._core.getVersion(key);
1249
+ }
1250
+ /** Delegating registration path: factory minting + registrant stamp + core write + instance-axis bookkeeping. */
1251
+ _register(options, component) {
1252
+ const store = typeof options.store === "function" ? options.store() : options.store;
1253
+ const registrant = options.registrant ?? this.ctx.fiber?.name;
1254
+ const erased = {
1255
+ ...options,
1256
+ ...store !== void 0 ? { store } : {},
1257
+ ...registrant !== void 0 ? { registrant } : {}
1258
+ };
1259
+ const dispose = this._core.register(erased, component);
1260
+ if (store !== void 0) {
1261
+ const scope = this._core.specDynamic(options.name).scope;
1262
+ this._acquire(store, scope);
1263
+ }
1264
+ let disposed = false;
1265
+ return () => {
1266
+ if (disposed) return;
1267
+ disposed = true;
1268
+ dispose();
1269
+ if (store !== void 0) this._release(store);
1270
+ };
1271
+ }
1272
+ /** Build the domain-neutral host face once; installed adapters remain live through getters. */
1273
+ hostFace() {
1274
+ if (this._host !== void 0) return this._host;
1275
+ const service = this;
1276
+ this._host = {
1277
+ subscribe: (key, fn) => this._core.subscribe(key, fn),
1278
+ getVersion: (key) => this._core.getVersion(key),
1279
+ entriesOf: (key) => this._core.entries(key),
1280
+ entriesOfSlot: (key) => this._core.entriesOfSlot(key),
1281
+ reportEntryError: (key, entry, error, info) => {
1282
+ this._core.reportEntryError(key, entry, error, info);
1283
+ },
1284
+ specOf: (key) => this._core.specDynamic(key),
1285
+ isLive: (entry) => this._core.isLive(entry),
1286
+ storeOf: (entry, scopeBinding) => entry.store === void 0 ? void 0 : this.resolveStore(entry.store, scopeBinding),
1287
+ root: this._rootSource,
1288
+ scopeRevision: this._scopeRevisionSource,
1289
+ scope: (scope) => service._scopes.get(scope === "session-maybe" ? "session" : scope),
1290
+ get locale() {
1291
+ return service._locale;
1292
+ }
1293
+ };
1294
+ return this._host;
1295
+ }
1296
+ /** Validate and atomically publish the current root contribution roster. */
1297
+ rebuildRootBinding() {
1298
+ const hooks = {};
1299
+ const keyedHooks = {};
1300
+ const props = {};
1301
+ const finalProps = /* @__PURE__ */ new Set();
1302
+ for (const contribution of this._rootContributions) {
1303
+ copyUnique("hook", hooks, contribution.hooks, finalProps, _deepseek_ai_dsh_client_ui_slots.standardHookPropName);
1304
+ copyUnique("keyed hook", keyedHooks, contribution.keyedHooks, finalProps, _deepseek_ai_dsh_client_ui_slots.standardHookPropName);
1305
+ copyUnique("prop", props, contribution.props, finalProps, (name) => name);
1306
+ }
1307
+ this._rootBinding = {
1308
+ key: void 0,
1309
+ hooks,
1310
+ keyedHooks,
1311
+ props
1312
+ };
1313
+ for (const listener of [...this._rootListeners]) try {
1314
+ listener();
1315
+ } catch (error) {
1316
+ console.error("root standard-source subscriber failed:", error);
1317
+ }
1318
+ }
1319
+ /** Publish one installed-scope roster transition after the map is authoritative. */
1320
+ publishScopeRevision() {
1321
+ this._scopeRevision += 1;
1322
+ for (const listener of [...this._scopeListeners]) try {
1323
+ listener();
1324
+ } catch (error) {
1325
+ console.error("scope-adapter subscriber failed:", error);
1326
+ }
1327
+ }
1328
+ /** Resolve (create or reuse) the store instance for a registered handle under a scope key. */
1329
+ resolveStore(handle, scopeBinding) {
1330
+ const record = this._stores.get(handle);
1331
+ if (record === void 0) throw new Error("store handle is not registered (entry unloaded, or the handle never went through register)");
1332
+ let key;
1333
+ if (record.scope === "root") key = ROOT_INSTANCE_KEY;
1334
+ else {
1335
+ if (scopeBinding === void 0) throw new Error(`${record.scope} store resolution requires a session id`);
1336
+ key = scopeBinding.key;
1337
+ this.bindStoreScope(scopeBinding);
1338
+ }
1339
+ let instance = record.instances.get(key);
1340
+ if (instance === void 0) {
1341
+ instance = record.scope === "root" ? handle.create() : handle.create(key);
1342
+ record.instances.set(key, instance);
1343
+ }
1344
+ return instance;
1345
+ }
1346
+ /** Clear every live non-root Store handle for one dead scope key. */
1347
+ clearStoreScope(key) {
1348
+ for (const [handle, record] of this._stores) {
1349
+ if (record.scope === "root") continue;
1350
+ (record.instances.get(key) ?? handle.create(key)).clearPersisted();
1351
+ record.instances.delete(key);
1352
+ }
1353
+ }
1354
+ /** Bind (or re-reference) a handle on the axis; cross-scope conflicts already threw in the core. */
1355
+ _acquire(handle, scope) {
1356
+ const record = this._stores.get(handle);
1357
+ if (record === void 0) {
1358
+ this._stores.set(handle, {
1359
+ scope,
1360
+ refs: 1,
1361
+ instances: /* @__PURE__ */ new Map()
1362
+ });
1363
+ return;
1364
+ }
1365
+ record.refs += 1;
1366
+ }
1367
+ /** Drop one reference; the last holder's unload drops the record (instances go with it — engine stores need no explicit dispose). */
1368
+ _release(handle) {
1369
+ const record = this._stores.get(handle);
1370
+ /* v8 ignore next -- defensive: release only runs from a disposer whose
1371
+ * register acquired the same handle, so the record must exist; kept so a
1372
+ * future call site cannot underflow the axis. */
1373
+ if (record === void 0) return;
1374
+ record.refs -= 1;
1375
+ if (record.refs !== 0) return;
1376
+ this._stores.delete(handle);
1377
+ }
1378
+ };
1379
+ function copyUnique(kind, target, values, finalProps, propNameOf) {
1380
+ if (values === void 0) return;
1381
+ for (const [name, value] of Object.entries(values)) {
1382
+ const propName = propNameOf(name);
1383
+ if (finalProps.has(propName)) throw new Error(`duplicate root standard ${kind} '${name}' at prop '${propName}'`);
1384
+ finalProps.add(propName);
1385
+ target[name] = value;
1386
+ }
930
1387
  }
1388
+ SlotRegistry.prototype.register = function register(rawOptions, component) {
1389
+ const options = rawOptions;
1390
+ return this.ctx.effect(() => this["_register"](options, component), "slots.register()");
1391
+ };
931
1392
  //#endregion
932
1393
  //#region lib/types/client/index.js
933
1394
  /**
@@ -936,7 +1397,7 @@ window.__ModuleLoader__.load({
936
1397
  * kernel after the complete client roster settles.
937
1398
  */
938
1399
  /** Services required before application assembly. */
939
- const inject = ["slots", "sessions"];
1400
+ const inject = [];
940
1401
  /** Hydrate the kernel-owned loading DOM before replacing it with the application. */
941
1402
  function BootHandoff(props) {
942
1403
  const [ready, setReady] = (0, react.useState)(false);
@@ -971,7 +1432,7 @@ window.__ModuleLoader__.load({
971
1432
  * @param ctx - Plugin context.
972
1433
  */
973
1434
  function apply(ctx) {
974
- ctx.slots.install(createSlotRenderer());
1435
+ new SlotRegistry(ctx).install(createSlotRenderer());
975
1436
  ctx.reflect.provide("uiRenderer", { mount: (container) => {
976
1437
  const root = mountApp(container, buildRenderApp({ ctx }));
977
1438
  return () => {
@@ -980,6 +1441,7 @@ window.__ModuleLoader__.load({
980
1441
  } });
981
1442
  }
982
1443
  //#endregion
1444
+ exports.SlotRegistry = SlotRegistry;
983
1445
  exports.apply = apply;
984
1446
  exports.inject = inject;
985
1447
  return module.exports;