@xemahq/ui-kernel 0.25.0 → 0.26.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 (33) hide show
  1. package/README.md +9 -68
  2. package/dist/registry/index.d.ts +5 -1
  3. package/dist/registry/index.d.ts.map +1 -1
  4. package/dist/registry/index.js +5 -1
  5. package/dist/registry/index.js.map +1 -1
  6. package/dist/registry/lib/biome-presence-context.d.ts +8 -0
  7. package/dist/registry/lib/biome-presence-context.d.ts.map +1 -0
  8. package/dist/registry/lib/biome-presence-context.js +22 -0
  9. package/dist/registry/lib/biome-presence-context.js.map +1 -0
  10. package/dist/registry/lib/biome-presence-error-card.d.ts +8 -0
  11. package/dist/registry/lib/biome-presence-error-card.d.ts.map +1 -0
  12. package/dist/registry/lib/biome-presence-error-card.js +7 -0
  13. package/dist/registry/lib/biome-presence-error-card.js.map +1 -0
  14. package/dist/registry/lib/biome-presence-error-title.d.ts +3 -0
  15. package/dist/registry/lib/biome-presence-error-title.d.ts.map +1 -0
  16. package/dist/registry/lib/biome-presence-error-title.js +10 -0
  17. package/dist/registry/lib/biome-presence-error-title.js.map +1 -0
  18. package/dist/registry/lib/biome-presence-gate.d.ts +8 -0
  19. package/dist/registry/lib/biome-presence-gate.d.ts.map +1 -0
  20. package/dist/registry/lib/biome-presence-gate.js +19 -0
  21. package/dist/registry/lib/biome-presence-gate.js.map +1 -0
  22. package/dist/registry/lib/biome-presence.d.ts +28 -0
  23. package/dist/registry/lib/biome-presence.d.ts.map +1 -0
  24. package/dist/registry/lib/biome-presence.js +14 -0
  25. package/dist/registry/lib/biome-presence.js.map +1 -0
  26. package/dist/registry/lib/biome-slot.d.ts.map +1 -1
  27. package/dist/registry/lib/biome-slot.js +31 -10
  28. package/dist/registry/lib/biome-slot.js.map +1 -1
  29. package/package.json +6 -6
  30. package/dist/registry/lib/biome-applicability-context.d.ts +0 -4
  31. package/dist/registry/lib/biome-applicability-context.d.ts.map +0 -1
  32. package/dist/registry/lib/biome-applicability-context.js +0 -8
  33. package/dist/registry/lib/biome-applicability-context.js.map +0 -1
package/README.md CHANGED
@@ -1,49 +1,15 @@
1
- <p align="center">
2
- <svg width="680" height="120" viewBox="0 0 680 120" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="@xemahq/ui-kernel">
3
- <rect width="680" height="120" rx="14" fill="#0B1020"/>
4
- <g transform="translate(28,34)">
5
- <path d="M26 0 L52 15 L52 45 L26 60 L0 45 L0 15 Z" fill="#8B5CF6" opacity="0.18"/>
6
- <path d="M26 12 L41 21 L41 39 L26 48 L11 39 L11 21 Z" fill="#8B5CF6"/>
7
- </g>
8
- <text x="92" y="52" font-family="ui-monospace,SFMono-Regular,Menlo,monospace" font-size="22" fill="#F8FAFC" font-weight="700">@xemahq/ui-kernel</text>
9
- <text x="92" y="80" font-family="ui-sans-serif,system-ui,sans-serif" font-size="15" fill="#94A3B8">Host-agnostic UI kernel for the Xema frontend</text>
10
- <text x="652" y="105" text-anchor="end" font-family="ui-sans-serif,system-ui,sans-serif" font-size="12" fill="#475569">xema.dev</text>
11
- </svg>
12
- </p>
13
-
14
- <p align="center">
15
- <a href="https://xema.dev">Website</a> &middot;
16
- <a href="https://www.npmjs.com/package/@xemahq/ui-kernel">npm</a>
17
- </p>
18
-
19
- <p align="center">
20
- <img alt="npm" src="https://img.shields.io/npm/v/%40xemahq%2Fui-kernel?color=2563eb&label=npm">
21
- <img alt="license" src="https://img.shields.io/npm/l/%40xemahq%2Fui-kernel?color=10b981">
22
- <img alt="types" src="https://img.shields.io/npm/types/%40xemahq%2Fui-kernel?color=3178c6">
23
- </p>
24
-
25
1
  # @xemahq/ui-kernel
26
2
 
27
3
  > Host-agnostic UI kernel for the Xema frontend
28
4
 
29
5
  ## Overview
30
6
 
31
- The host-framework-agnostic UI kernel every frontend biome composes against. It
32
- defines the system bus — the orchestration contract for capability invocation,
33
- cross-biome intents, the command palette, deeplinks, and window management — and
34
- the biome-host contract surface, including the frontend-biome and host-bridge
35
- shapes, the singleton biome registry, and session contributions. React is the
36
- shared component model, but the kernel carries no router, bundler, or
37
- host-specific wiring; concrete host adapters live in separate packages. The
38
- system bus is pure orchestration — it never authorizes; policy is enforced by
39
- the backend.
7
+ The host-agnostic UI kernel that Xema frontend biomes are built on. It provides `defineWebBiome` for declaring pages, the biome registry, the system bus for capability invocation, intents, the command palette and deeplinks, and the shared design system under `@xemahq/ui-kernel/ui`. The bus only orchestrates; the backend enforces policy.
40
8
 
41
9
  ## When to use it
42
10
 
43
- - Use it to author a frontend biome against the shared host contracts and
44
- register it with the biome registry.
45
- - Reach for the system bus to dispatch capability invocations, intents, or
46
- deeplinks across biomes.
11
+ - You are authoring a frontend biome and registering it with the host.
12
+ - You need the shared components so a biome looks identical to built-in ones.
47
13
 
48
14
  ## Installation
49
15
 
@@ -53,10 +19,6 @@ pnpm add @xemahq/ui-kernel
53
19
 
54
20
  ## Usage
55
21
 
56
- Author a web biome with `defineWebBiome` — a declarative page list where each
57
- `slug` single-sources both the nav route and the route path, and each page
58
- declares its menu `category` (the host owns where that category renders):
59
-
60
22
  ```tsx
61
23
  import { defineWebBiome } from '@xemahq/ui-kernel';
62
24
  import { Layers } from 'lucide-react';
@@ -76,45 +38,24 @@ export default defineWebBiome({
76
38
  });
77
39
  ```
78
40
 
79
- The helper emits the nav item + route (wrapping the lazily-loaded page in a
80
- `<Suspense>` boundary) and passes through `init`/`panels`/`session` for bespoke
81
- biomes. Pass a per-page `id` to keep a short nav id distinct from the route
82
- slug, or `navHidden: true` to register a route with no nav item.
41
+ Each page's `slug` sets both its nav route and its path. Use a per-page `id` for a short nav id, or `navHidden: true` for a route with no nav item.
83
42
 
84
- Lower-level building blocks are also exported:
43
+ Lower-level pieces:
85
44
 
86
45
  ```ts
87
46
  import { buildSystemBus, biomeRegistry } from '@xemahq/ui-kernel';
88
47
 
89
48
  const bus = buildSystemBus(hostPorts);
90
-
91
- // Register a frontend biome so the host can render its contributions:
92
49
  biomeRegistry.registerBiome(myBiome);
93
50
  ```
94
51
 
95
- ## UI components
96
-
97
- Build your pages with the shared design system from `@xemahq/ui-kernel/ui` so a
98
- third-party biome renders pixel-identical to a built-in one (they resolve
99
- against the host theme at render):
100
-
101
- ```tsx
102
- import {
103
- Button, Badge, Input, Select, Dialog, Card, Tabs, Table, // primitives
104
- PageShell, PageHeader, EmptyState, ErrorCard, StateCard, LoadingState, AsyncBoundary,
105
- StatusBadge, ScopeBadge, ConfirmDeleteDialog, FormStepper, AsyncCombobox,
106
- getStatusStyle, cn,
107
- } from '@xemahq/ui-kernel/ui';
108
- ```
109
-
110
- Host-service hooks (toast, error copy, URL-backed page state) come from the
111
- `HostBridge` — e.g. `useMutationWithErrorToast`, `usePageState` from
112
- `@xemahq/ui-kernel` — so biomes never import host internals directly.
52
+ Components come from `@xemahq/ui-kernel/ui` (for example `Button`, `Card`, `Table`, `PageShell`). Host hooks such as `useMutationWithErrorToast` and `usePageState` come from `@xemahq/ui-kernel`.
113
53
 
114
54
  ## Peer requirements
115
55
 
116
- - `react` — the shared component model.
117
- - `@tanstack/react-query` — async state for host data hooks.
56
+ - `react` `^18.3.1`
57
+ - `@tanstack/react-query` `^5.0.0`
58
+ - `@xemahq/contracts` `>=0.4.0`
118
59
 
119
60
  ## License
120
61
 
@@ -1,7 +1,11 @@
1
1
  export * from './lib/extension-points';
2
2
  export * from './lib/agent-validation-host';
3
3
  export * from './lib/biome-slot';
4
- export * from './lib/biome-applicability-context';
4
+ export * from './lib/biome-presence';
5
+ export * from './lib/biome-presence-context';
6
+ export * from './lib/biome-presence-error-card';
7
+ export * from './lib/biome-presence-error-title';
8
+ export * from './lib/biome-presence-gate';
5
9
  export * from './lib/biomes-enabled-context';
6
10
  export * from './lib/session-selectors';
7
11
  export * from './lib/session-context-builder';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/registry/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,mCAAmC,CAAC;AAClD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/registry/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,kCAAkC,CAAC;AACjD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kBAAkB,CAAC"}
@@ -1,7 +1,11 @@
1
1
  export * from './lib/extension-points';
2
2
  export * from './lib/agent-validation-host';
3
3
  export * from './lib/biome-slot';
4
- export * from './lib/biome-applicability-context';
4
+ export * from './lib/biome-presence';
5
+ export * from './lib/biome-presence-context';
6
+ export * from './lib/biome-presence-error-card';
7
+ export * from './lib/biome-presence-error-title';
8
+ export * from './lib/biome-presence-gate';
5
9
  export * from './lib/biomes-enabled-context';
6
10
  export * from './lib/session-selectors';
7
11
  export * from './lib/session-context-builder';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/registry/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,mCAAmC,CAAC;AAClD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/registry/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,kCAAkC,CAAC;AACjD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { BiomePresenceAnswer, BiomePresenceLookup } from './biome-presence';
2
+ export declare const BiomePresenceContext: import("react").Context<BiomePresenceLookup | null>;
3
+ export declare class MissingBiomePresenceProviderError extends Error {
4
+ constructor();
5
+ }
6
+ export declare function useBiomePresenceLookup(): BiomePresenceLookup;
7
+ export declare function useBiomePresence(biomeId: string): BiomePresenceAnswer;
8
+ //# sourceMappingURL=biome-presence-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"biome-presence-context.d.ts","sourceRoot":"","sources":["../../../src/registry/lib/biome-presence-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AA4BjF,eAAO,MAAM,oBAAoB,qDAAkD,CAAC;AAIpF,qBAAa,iCAAkC,SAAQ,KAAK;;CAS3D;AAOD,wBAAgB,sBAAsB,IAAI,mBAAmB,CAM5D;AAOD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB,CAErE"}
@@ -0,0 +1,22 @@
1
+ import { createContext, useContext } from 'react';
2
+ export const BiomePresenceContext = createContext(null);
3
+ BiomePresenceContext.displayName = 'BiomePresenceContext';
4
+ export class MissingBiomePresenceProviderError extends Error {
5
+ constructor() {
6
+ super('No BiomePresenceContext provider: BiomeSlot, BiomePresenceGate and useBiomePresence ' +
7
+ 'need the host to mount <BiomePresenceContext.Provider> with its installed-set lookup ' +
8
+ 'above them.');
9
+ this.name = 'MissingBiomePresenceProviderError';
10
+ }
11
+ }
12
+ export function useBiomePresenceLookup() {
13
+ const lookup = useContext(BiomePresenceContext);
14
+ if (lookup === null) {
15
+ throw new MissingBiomePresenceProviderError();
16
+ }
17
+ return lookup;
18
+ }
19
+ export function useBiomePresence(biomeId) {
20
+ return useBiomePresenceLookup()(biomeId);
21
+ }
22
+ //# sourceMappingURL=biome-presence-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"biome-presence-context.js","sourceRoot":"","sources":["../../../src/registry/lib/biome-presence-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AA8BlD,MAAM,CAAC,MAAM,oBAAoB,GAAG,aAAa,CAA6B,IAAI,CAAC,CAAC;AACpF,oBAAoB,CAAC,WAAW,GAAG,sBAAsB,CAAC;AAG1D,MAAM,OAAO,iCAAkC,SAAQ,KAAK;IAC1D;QACE,KAAK,CACH,sFAAsF;YACpF,uFAAuF;YACvF,aAAa,CAChB,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,mCAAmC,CAAC;IAClD,CAAC;CACF;AAOD,MAAM,UAAU,sBAAsB;IACpC,MAAM,MAAM,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAC;IAChD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,MAAM,IAAI,iCAAiC,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAOD,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,OAAO,sBAAsB,EAAE,CAAC,OAAO,CAAC,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type BiomePresenceError } from './biome-presence';
2
+ import type { ReactElement } from 'react';
3
+ export interface BiomePresenceErrorCardProps {
4
+ readonly biomeId: string;
5
+ readonly answer: BiomePresenceError;
6
+ }
7
+ export declare function BiomePresenceErrorCard({ biomeId, answer, }: BiomePresenceErrorCardProps): ReactElement;
8
+ //# sourceMappingURL=biome-presence-error-card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"biome-presence-error-card.d.ts","sourceRoot":"","sources":["../../../src/registry/lib/biome-presence-error-card.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAI3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAE1C,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;CACrC;AAMD,wBAAgB,sBAAsB,CAAC,EACrC,OAAO,EACP,MAAM,GACP,EAAE,2BAA2B,GAAG,YAAY,CAE5C"}
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { biomePresenceErrorTitle } from './biome-presence-error-title';
3
+ import ErrorCard from '../../ui/chrome/ErrorCard';
4
+ export function BiomePresenceErrorCard({ biomeId, answer, }) {
5
+ return _jsx(ErrorCard, { title: biomePresenceErrorTitle(biomeId, answer.reason), error: answer.error });
6
+ }
7
+ //# sourceMappingURL=biome-presence-error-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"biome-presence-error-card.js","sourceRoot":"","sources":["../../../src/registry/lib/biome-presence-error-card.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,SAAS,MAAM,2BAA2B,CAAC;AAalD,MAAM,UAAU,sBAAsB,CAAC,EACrC,OAAO,EACP,MAAM,GACsB;IAC5B,OAAO,KAAC,SAAS,IAAC,KAAK,EAAE,uBAAuB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,GAAI,CAAC;AACpG,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { BiomePresenceErrorReason } from './biome-presence';
2
+ export declare function biomePresenceErrorTitle(biomeId: string, reason: BiomePresenceErrorReason): string;
3
+ //# sourceMappingURL=biome-presence-error-title.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"biome-presence-error-title.d.ts","sourceRoot":"","sources":["../../../src/registry/lib/biome-presence-error-title.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAY5D,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,wBAAwB,GAAG,MAAM,CAEjG"}
@@ -0,0 +1,10 @@
1
+ import { BiomePresenceErrorReason } from './biome-presence';
2
+ const TITLE_BY_REASON = {
3
+ [BiomePresenceErrorReason.LookupFailed]: (biomeId) => `Couldn't check whether ${biomeId} is installed`,
4
+ [BiomePresenceErrorReason.ProviderUnavailable]: (biomeId) => `${biomeId} is installed but unavailable`,
5
+ [BiomePresenceErrorReason.AuthorizationDenied]: (biomeId) => `You don't have access to check whether ${biomeId} is installed`,
6
+ };
7
+ export function biomePresenceErrorTitle(biomeId, reason) {
8
+ return TITLE_BY_REASON[reason](biomeId);
9
+ }
10
+ //# sourceMappingURL=biome-presence-error-title.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"biome-presence-error-title.js","sourceRoot":"","sources":["../../../src/registry/lib/biome-presence-error-title.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,MAAM,eAAe,GAA4E;IAC/F,CAAC,wBAAwB,CAAC,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CACnD,0BAA0B,OAAO,eAAe;IAClD,CAAC,wBAAwB,CAAC,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CAC1D,GAAG,OAAO,+BAA+B;IAC3C,CAAC,wBAAwB,CAAC,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CAC1D,0CAA0C,OAAO,eAAe;CACnE,CAAC;AAGF,MAAM,UAAU,uBAAuB,CAAC,OAAe,EAAE,MAAgC;IACvF,OAAO,eAAe,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ReactElement, ReactNode } from 'react';
2
+ export interface BiomePresenceGateProps {
3
+ readonly biomeId: string;
4
+ readonly children: ReactNode;
5
+ readonly loading?: ReactNode;
6
+ }
7
+ export declare function BiomePresenceGate({ biomeId, children, loading, }: BiomePresenceGateProps): ReactElement | null;
8
+ //# sourceMappingURL=biome-presence-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"biome-presence-gate.d.ts","sourceRoot":"","sources":["../../../src/registry/lib/biome-presence-gate.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAErD,MAAM,WAAW,sBAAsB;IAErC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAE7B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;CAC9B;AAWD,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,QAAQ,EACR,OAAO,GACR,EAAE,sBAAsB,GAAG,YAAY,GAAG,IAAI,CAY9C"}
@@ -0,0 +1,19 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { BiomePresence } from './biome-presence';
3
+ import { useBiomePresence } from './biome-presence-context';
4
+ import { BiomePresenceErrorCard } from './biome-presence-error-card';
5
+ import LoadingState from '../../ui/chrome/LoadingState';
6
+ export function BiomePresenceGate({ biomeId, children, loading, }) {
7
+ const answer = useBiomePresence(biomeId);
8
+ switch (answer.presence) {
9
+ case BiomePresence.Installed:
10
+ return _jsx(_Fragment, { children: children });
11
+ case BiomePresence.Loading:
12
+ return _jsx(_Fragment, { children: loading ?? _jsx(LoadingState, {}) });
13
+ case BiomePresence.Absent:
14
+ return null;
15
+ case BiomePresence.Error:
16
+ return _jsx(BiomePresenceErrorCard, { biomeId: biomeId, answer: answer });
17
+ }
18
+ }
19
+ //# sourceMappingURL=biome-presence-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"biome-presence-gate.js","sourceRoot":"","sources":["../../../src/registry/lib/biome-presence-gate.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,YAAY,MAAM,8BAA8B,CAAC;AAsBxD,MAAM,UAAU,iBAAiB,CAAC,EAChC,OAAO,EACP,QAAQ,EACR,OAAO,GACgB;IACvB,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACzC,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,aAAa,CAAC,SAAS;YAC1B,OAAO,4BAAG,QAAQ,GAAI,CAAC;QACzB,KAAK,aAAa,CAAC,OAAO;YACxB,OAAO,4BAAG,OAAO,IAAI,KAAC,YAAY,KAAG,GAAI,CAAC;QAC5C,KAAK,aAAa,CAAC,MAAM;YACvB,OAAO,IAAI,CAAC;QACd,KAAK,aAAa,CAAC,KAAK;YACtB,OAAO,KAAC,sBAAsB,IAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAI,CAAC;IACxE,CAAC;AACH,CAAC"}
@@ -0,0 +1,28 @@
1
+ export declare enum BiomePresence {
2
+ Loading = "loading",
3
+ Installed = "installed",
4
+ Absent = "absent",
5
+ Error = "error"
6
+ }
7
+ export declare enum BiomePresenceErrorReason {
8
+ LookupFailed = "lookup_failed",
9
+ ProviderUnavailable = "provider_unavailable",
10
+ AuthorizationDenied = "authorization_denied"
11
+ }
12
+ export interface BiomePresenceLoading {
13
+ readonly presence: BiomePresence.Loading;
14
+ }
15
+ export interface BiomePresenceInstalled {
16
+ readonly presence: BiomePresence.Installed;
17
+ }
18
+ export interface BiomePresenceAbsent {
19
+ readonly presence: BiomePresence.Absent;
20
+ }
21
+ export interface BiomePresenceError {
22
+ readonly presence: BiomePresence.Error;
23
+ readonly reason: BiomePresenceErrorReason;
24
+ readonly error: unknown;
25
+ }
26
+ export type BiomePresenceAnswer = BiomePresenceLoading | BiomePresenceInstalled | BiomePresenceAbsent | BiomePresenceError;
27
+ export type BiomePresenceLookup = (biomeId: string) => BiomePresenceAnswer;
28
+ //# sourceMappingURL=biome-presence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"biome-presence.d.ts","sourceRoot":"","sources":["../../../src/registry/lib/biome-presence.ts"],"names":[],"mappings":"AA+BA,oBAAY,aAAa;IAEvB,OAAO,YAAY;IAEnB,SAAS,cAAc;IAEvB,MAAM,WAAW;IAEjB,KAAK,UAAU;CAChB;AAGD,oBAAY,wBAAwB;IAElC,YAAY,kBAAkB;IAE9B,mBAAmB,yBAAyB;IAE5C,mBAAmB,yBAAyB;CAC7C;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC;CAC1C;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,SAAS,CAAC;CAC5C;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC;CACzC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,KAAK,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;IAE1C,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAGD,MAAM,MAAM,mBAAmB,GAC3B,oBAAoB,GACpB,sBAAsB,GACtB,mBAAmB,GACnB,kBAAkB,CAAC;AAGvB,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,mBAAmB,CAAC"}
@@ -0,0 +1,14 @@
1
+ export var BiomePresence;
2
+ (function (BiomePresence) {
3
+ BiomePresence["Loading"] = "loading";
4
+ BiomePresence["Installed"] = "installed";
5
+ BiomePresence["Absent"] = "absent";
6
+ BiomePresence["Error"] = "error";
7
+ })(BiomePresence || (BiomePresence = {}));
8
+ export var BiomePresenceErrorReason;
9
+ (function (BiomePresenceErrorReason) {
10
+ BiomePresenceErrorReason["LookupFailed"] = "lookup_failed";
11
+ BiomePresenceErrorReason["ProviderUnavailable"] = "provider_unavailable";
12
+ BiomePresenceErrorReason["AuthorizationDenied"] = "authorization_denied";
13
+ })(BiomePresenceErrorReason || (BiomePresenceErrorReason = {}));
14
+ //# sourceMappingURL=biome-presence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"biome-presence.js","sourceRoot":"","sources":["../../../src/registry/lib/biome-presence.ts"],"names":[],"mappings":"AA+BA,MAAM,CAAN,IAAY,aASX;AATD,WAAY,aAAa;IAEvB,oCAAmB,CAAA;IAEnB,wCAAuB,CAAA;IAEvB,kCAAiB,CAAA;IAEjB,gCAAe,CAAA;AACjB,CAAC,EATW,aAAa,KAAb,aAAa,QASxB;AAGD,MAAM,CAAN,IAAY,wBAOX;AAPD,WAAY,wBAAwB;IAElC,0DAA8B,CAAA;IAE9B,wEAA4C,CAAA;IAE5C,wEAA4C,CAAA;AAC9C,CAAC,EAPW,wBAAwB,KAAxB,wBAAwB,QAOnC"}
@@ -1 +1 @@
1
- {"version":3,"file":"biome-slot.d.ts","sourceRoot":"","sources":["../../../src/registry/lib/biome-slot.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,YAAY,EAAE,MAAM,OAAO,CAAC;AAMpD,MAAM,WAAW,cAAc;IAE7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CACzC;AAqBD,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,YAAY,GAAG,IAAI,CAqCpE"}
1
+ {"version":3,"file":"biome-slot.d.ts","sourceRoot":"","sources":["../../../src/registry/lib/biome-slot.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,YAAY,EAAE,MAAM,OAAO,CAAC;AAWhE,MAAM,WAAW,cAAc;IAE7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CACzC;AAwBD,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,YAAY,GAAG,IAAI,CAkEpE"}
@@ -1,21 +1,42 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Fragment } from 'react';
3
- import { useBiomeApplicability } from './biome-applicability-context';
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Fragment, useContext } from 'react';
3
+ import { BiomePresence } from './biome-presence';
4
+ import { BiomePresenceContext, MissingBiomePresenceProviderError, } from './biome-presence-context';
5
+ import { BiomePresenceErrorCard } from './biome-presence-error-card';
4
6
  import { useBiomesEnabled } from './biomes-enabled-context';
5
7
  import { biomeRegistry, useBiomeRegistryRevision } from '../../index';
6
8
  export function BiomeSlot(props) {
7
9
  useBiomeRegistryRevision();
8
10
  const enabled = useBiomesEnabled();
9
- const applies = useBiomeApplicability();
11
+ const presenceOf = useContext(BiomePresenceContext);
10
12
  if (!enabled) {
11
13
  return props.fallback ?? null;
12
14
  }
13
- const entries = biomeRegistry
14
- .panelEntriesForSlot(props.name)
15
- .filter((entry) => applies(entry.biomeId));
16
- if (entries.length === 0) {
17
- return props.fallback ?? null;
15
+ if (presenceOf === null) {
16
+ throw new MissingBiomePresenceProviderError();
17
+ }
18
+ const installed = [];
19
+ const failed = [];
20
+ let unresolved = false;
21
+ for (const entry of biomeRegistry.panelEntriesForSlot(props.name)) {
22
+ const answer = presenceOf(entry.biomeId);
23
+ switch (answer.presence) {
24
+ case BiomePresence.Installed:
25
+ installed.push({ key: entry.panel.id, node: _jsx(_Fragment, { children: entry.panel.render() }) });
26
+ break;
27
+ case BiomePresence.Error:
28
+ failed.push({ key: entry.panel.id, biomeId: entry.biomeId, answer });
29
+ break;
30
+ case BiomePresence.Loading:
31
+ unresolved = true;
32
+ break;
33
+ case BiomePresence.Absent:
34
+ break;
35
+ }
36
+ }
37
+ if (installed.length === 0 && failed.length === 0) {
38
+ return unresolved ? null : (props.fallback ?? null);
18
39
  }
19
- return (_jsx(Fragment, { children: entries.map((entry) => (_jsx(Fragment, { children: entry.panel.render() }, entry.panel.id))) }));
40
+ return (_jsxs(Fragment, { children: [installed.map(({ key, node }) => (_jsx(Fragment, { children: node }, key))), failed.map(({ key, biomeId, answer }) => (_jsx(BiomePresenceErrorCard, { biomeId: biomeId, answer: answer }, key)))] }));
20
41
  }
21
42
  //# sourceMappingURL=biome-slot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"biome-slot.js","sourceRoot":"","sources":["../../../src/registry/lib/biome-slot.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAqB,MAAM,OAAO,CAAC;AAEpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AA4BtE,MAAM,UAAU,SAAS,CAAC,KAAqB;IAE7C,wBAAwB,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;IAInC,MAAM,OAAO,GAAG,qBAAqB,EAAE,CAAC;IACxC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC;IAChC,CAAC;IAcD,MAAM,OAAO,GAAG,aAAa;SAC1B,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC;SAC/B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC;IAChC,CAAC;IACD,OAAO,CACL,KAAC,QAAQ,cACN,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACtB,KAAC,QAAQ,cAAuB,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,IAArC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAmC,CACjE,CAAC,GACO,CACZ,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"biome-slot.js","sourceRoot":"","sources":["../../../src/registry/lib/biome-slot.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAqB,MAAM,OAAO,CAAC;AAEhE,OAAO,EAAE,aAAa,EAA2B,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EACL,oBAAoB,EACpB,iCAAiC,GAClC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AA+BtE,MAAM,UAAU,SAAS,CAAC,KAAqB;IAE7C,wBAAwB,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;IAMnC,MAAM,UAAU,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAC;IACpD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC;IAChC,CAAC;IACD,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACxB,MAAM,IAAI,iCAAiC,EAAE,CAAC;IAChD,CAAC;IAmBD,MAAM,SAAS,GAA4D,EAAE,CAAC;IAC9E,MAAM,MAAM,GAA8F,EAAE,CAAC;IAC7G,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,KAAK,MAAM,KAAK,IAAI,aAAa,CAAC,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAClE,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACzC,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;YACxB,KAAK,aAAa,CAAC,SAAS;gBAC1B,SAAS,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,4BAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,GAAI,EAAE,CAAC,CAAC;gBAC3E,MAAM;YACR,KAAK,aAAa,CAAC,KAAK;gBACtB,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;gBACrE,MAAM;YACR,KAAK,aAAa,CAAC,OAAO;gBACxB,UAAU,GAAG,IAAI,CAAC;gBAClB,MAAM;YACR,KAAK,aAAa,CAAC,MAAM;gBACvB,MAAM;QACV,CAAC;IACH,CAAC;IACD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,OAAO,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,CACL,MAAC,QAAQ,eACN,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAChC,KAAC,QAAQ,cAAY,IAAI,IAAV,GAAG,CAAmB,CACtC,CAAC,EACD,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CACxC,KAAC,sBAAsB,IAAW,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,IAArC,GAAG,CAAsC,CACvE,CAAC,IACO,CACZ,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@xemahq/ui-kernel",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
- "description": "Host-framework-agnostic UI kernel for the Xema OS. Defines the SystemBus orchestration contract (capability.invoke, cross-biome intents, command palette, xema:// deeplinks, window manager) AND the biome-host contract surface (FrontendBiome/FrontendBiomeFactory, HostBridge, the singleton biomeRegistry, session contributions) that every frontend biome composes against. No Vite, Next.js, or React-Router — React itself IS allowed as the shared component model (the contracts traffic in ReactNode/ComponentType and a React context). Concrete host adapters (router/auth/toast wiring) live in separate packages that consume this kernel. The SystemBus is pure orchestration: it never authorizes, the backend capability-router enforces all policy.",
6
+ "description": "Host-framework-agnostic UI kernel for Xema. Defines the SystemBus orchestration contract (capability.invoke, cross-biome intents, command palette, xema:// deeplinks, window manager) AND the biome-host contract surface (FrontendBiome/FrontendBiomeFactory, HostBridge, the singleton biomeRegistry, session contributions) that every frontend biome composes against. No Vite, Next.js, or React-Router — React itself IS allowed as the shared component model (the contracts traffic in ReactNode/ComponentType and a React context). Concrete host adapters (router/auth/toast wiring) live in separate packages that consume this kernel. The SystemBus is pure orchestration: it never authorizes, the backend capability-router enforces all policy.",
7
7
  "keywords": [
8
8
  "xema",
9
9
  "xema-platform",
@@ -50,7 +50,7 @@
50
50
  "@radix-ui/react-switch": "^1.2.5",
51
51
  "@radix-ui/react-tabs": "^1.1.12",
52
52
  "@radix-ui/react-tooltip": "^1.2.7",
53
- "@xemahq/registry": "^0.1.4",
53
+ "@xemahq/registry": "^0.1.7",
54
54
  "class-variance-authority": "^0.7.1",
55
55
  "clsx": "^2.1.1",
56
56
  "lucide-react": "^0.462.0",
@@ -74,14 +74,14 @@
74
74
  "@types/node": "25.2.3",
75
75
  "@types/react": "^18.3.30",
76
76
  "@types/react-dom": "^18.3.7",
77
- "@xemahq/contracts": "^0.75.0",
77
+ "@xemahq/contracts": "^0.86.0",
78
78
  "eslint": "^9.39.4",
79
79
  "prettier": "3.6.2",
80
80
  "react": "^18.3.1",
81
81
  "react-dom": "^18.3.1",
82
82
  "typescript": "5.9.3",
83
83
  "vitest": "^3.2.4",
84
- "@xemahq/eslint-config": "0.13.0"
84
+ "@xemahq/eslint-config": "0.14.1"
85
85
  },
86
86
  "exports": {
87
87
  ".": {
@@ -119,6 +119,6 @@
119
119
  "typecheck": "tsc -p tsconfig.lint.json --noEmit"
120
120
  },
121
121
  "xemaRelease": {
122
- "sourceDigest": "sha256:532fe368e3a30f6d1ba2a687296d7fc7143e1d7f6fe21e8f0591db7d8a8a50ed"
122
+ "sourceDigest": "sha256:2cf465cfa890df410258d5fbb90287f63096f7a31b5d20456b54a1d3082c3cb0"
123
123
  }
124
124
  }
@@ -1,4 +0,0 @@
1
- export type BiomeApplicability = (biomeId: string) => boolean;
2
- export declare const BiomeApplicabilityContext: import("react").Context<BiomeApplicability>;
3
- export declare function useBiomeApplicability(): BiomeApplicability;
4
- //# sourceMappingURL=biome-applicability-context.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"biome-applicability-context.d.ts","sourceRoot":"","sources":["../../../src/registry/lib/biome-applicability-context.ts"],"names":[],"mappings":"AAwCA,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;AAI9D,eAAO,MAAM,yBAAyB,6CACoB,CAAC;AAG3D,wBAAgB,qBAAqB,IAAI,kBAAkB,CAE1D"}
@@ -1,8 +0,0 @@
1
- import { createContext, useContext } from 'react';
2
- const APPLIES_TO_EVERYTHING = () => true;
3
- export const BiomeApplicabilityContext = createContext(APPLIES_TO_EVERYTHING);
4
- BiomeApplicabilityContext.displayName = 'BiomeApplicabilityContext';
5
- export function useBiomeApplicability() {
6
- return useContext(BiomeApplicabilityContext);
7
- }
8
- //# sourceMappingURL=biome-applicability-context.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"biome-applicability-context.js","sourceRoot":"","sources":["../../../src/registry/lib/biome-applicability-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AA0ClD,MAAM,qBAAqB,GAAuB,GAAG,EAAE,CAAC,IAAI,CAAC;AAE7D,MAAM,CAAC,MAAM,yBAAyB,GACpC,aAAa,CAAqB,qBAAqB,CAAC,CAAC;AAC3D,yBAAyB,CAAC,WAAW,GAAG,2BAA2B,CAAC;AAEpE,MAAM,UAAU,qBAAqB;IACnC,OAAO,UAAU,CAAC,yBAAyB,CAAC,CAAC;AAC/C,CAAC"}