@box-kite/react 2.0.1 → 2.2.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 (145) hide show
  1. package/.claude/rules/box-kite-rules.md +24 -2
  2. package/.claude/skills/box-kite/SKILL.md +27 -5
  3. package/.claude/skills/box-kite/references/components.md +8 -3
  4. package/.claude/skills/box-kite/references/patterns.md +24 -1
  5. package/.claude/skills/box-kite/references/styling.md +23 -0
  6. package/.cursor/rules/box-kite.mdc +25 -3
  7. package/AGENTS.md +28 -3
  8. package/BOX_AI_CONTEXT.md +732 -12
  9. package/BOX_KITE_AI_CONTEXT.md +732 -12
  10. package/README.md +41 -9
  11. package/box.cjs +1 -1
  12. package/box.d.ts +13 -2
  13. package/box.mjs +25 -18
  14. package/catalog.cjs +1 -0
  15. package/catalog.d.ts +8 -0
  16. package/catalog.mjs +2347 -0
  17. package/client.cjs +1 -1
  18. package/client.mjs +59 -53
  19. package/components/agent.cjs +1 -0
  20. package/components/agent.d.ts +215 -0
  21. package/components/agent.mjs +405 -0
  22. package/components/button.cjs +1 -1
  23. package/components/button.mjs +10 -14
  24. package/components/chart.d.ts +1 -0
  25. package/components/dashboard.cjs +1 -0
  26. package/components/dashboard.d.ts +121 -0
  27. package/components/dashboard.mjs +690 -0
  28. package/components/dataGrid/components/dataGridBody.d.ts +2 -1
  29. package/components/dataGrid/components/dataGridDetailRow.d.ts +13 -2
  30. package/components/dataGrid/components/dataGridGroupRow.d.ts +13 -2
  31. package/components/dataGrid/components/dataGridRow.d.ts +13 -2
  32. package/components/dataGrid/contracts/dataGridContract.d.ts +66 -2
  33. package/components/dataGrid/models/cellModel.d.ts +3 -0
  34. package/components/dataGrid/models/editModel.d.ts +27 -0
  35. package/components/dataGrid/models/exportModel.d.ts +2 -1
  36. package/components/dataGrid/models/gridModel.d.ts +3 -0
  37. package/components/dataGrid/models/rangeModel.d.ts +119 -0
  38. package/components/dataGrid/models/viewportModel.d.ts +23 -2
  39. package/components/dataGrid/useGridNavigation.d.ts +10 -2
  40. package/components/dataGrid.cjs +4 -1
  41. package/components/dataGrid.d.ts +3 -0
  42. package/components/dataGrid.mjs +1056 -765
  43. package/components/flex.cjs +1 -1
  44. package/components/flex.mjs +10 -13
  45. package/components/form.cjs +1 -1
  46. package/components/form.mjs +7 -7
  47. package/components/grid.cjs +1 -1
  48. package/components/grid.mjs +10 -13
  49. package/components/markdown.cjs +1 -0
  50. package/components/markdown.d.ts +55 -0
  51. package/components/markdown.mjs +179 -0
  52. package/components/menu.cjs +1 -1
  53. package/components/menu.mjs +16 -16
  54. package/components/overlay.cjs +1 -1
  55. package/components/overlay.mjs +35 -34
  56. package/components/popover.cjs +1 -1
  57. package/components/popover.mjs +4 -4
  58. package/components/semantics.cjs +1 -1
  59. package/components/semantics.d.ts +29 -29
  60. package/components/semantics.mjs +9 -13
  61. package/components/skeleton.cjs +1 -0
  62. package/components/skeleton.d.ts +34 -0
  63. package/components/skeleton.mjs +25 -0
  64. package/components/svg.cjs +1 -1
  65. package/components/svg.mjs +38 -44
  66. package/components/textarea.cjs +1 -1
  67. package/components/textarea.mjs +12 -16
  68. package/components/textbox.cjs +1 -1
  69. package/components/textbox.mjs +12 -16
  70. package/components/toaster.cjs +1 -1
  71. package/components/toaster.mjs +42 -43
  72. package/components/visuallyHidden.cjs +1 -1
  73. package/components/visuallyHidden.mjs +10 -13
  74. package/dashboardSchema.cjs +1 -0
  75. package/dashboardSchema.mjs +78 -0
  76. package/docs/a11y.md +2 -3
  77. package/docs/catalog.md +451 -0
  78. package/docs/components.md +4 -0
  79. package/docs/index.md +3 -0
  80. package/docs/interop.md +237 -0
  81. package/docs/mcp.md +70 -0
  82. package/docs/props.md +135 -23
  83. package/interop.cjs +1 -0
  84. package/interop.d.ts +51 -0
  85. package/interop.mjs +454 -0
  86. package/layer.cjs +1 -1
  87. package/layer.mjs +61 -59
  88. package/mcp/src/data.d.ts +88 -0
  89. package/mcp/src/data.test.d.ts +1 -0
  90. package/mcp/src/engine.d.ts +23 -0
  91. package/mcp/src/index.d.ts +1 -0
  92. package/mcp/src/search.d.ts +26 -0
  93. package/mcp/src/search.test.d.ts +1 -0
  94. package/mcp/src/server.d.ts +18 -0
  95. package/mcp/src/server.test.d.ts +1 -0
  96. package/mcp/src/styles.d.ts +27 -0
  97. package/mcp/src/styles.test.d.ts +1 -0
  98. package/mcp/src/tools.d.ts +18 -0
  99. package/mcp/src/vocabulary.d.ts +41 -0
  100. package/package.json +170 -37
  101. package/react/boxComponent.d.ts +10 -0
  102. package/react/popover/useTopLayer.d.ts +17 -0
  103. package/react/spec/renderSpec.d.ts +51 -0
  104. package/react/spec/specBoundary.d.ts +25 -0
  105. package/react/spec/specRegistry.d.ts +42 -0
  106. package/react/spec/specRenderer.d.ts +10 -0
  107. package/react/theme/theme.d.ts +10 -0
  108. package/react/useStyles.d.ts +2 -0
  109. package/react-shared.cjs +1 -1
  110. package/react-shared.mjs +44 -37
  111. package/registry/blocks/dashboard-shell/dashboard-shell.d.ts +22 -0
  112. package/registry/blocks/dashboard-shell/dashboard-stats.d.ts +13 -0
  113. package/registry/blocks/data-grid/invoice-rows.d.ts +15 -0
  114. package/registry/blocks/data-grid/invoices-grid.d.ts +1 -0
  115. package/registry/blocks/settings-form/settings-form.d.ts +17 -0
  116. package/rsc.cjs +1 -1
  117. package/rsc.d.ts +11 -1
  118. package/rsc.mjs +15 -12
  119. package/spec.cjs +2 -0
  120. package/spec.d.ts +12 -0
  121. package/spec.mjs +382 -0
  122. package/specData.cjs +1 -0
  123. package/specData.mjs +69 -0
  124. package/specDefs.cjs +1 -0
  125. package/specDefs.mjs +33 -0
  126. package/specSchema.cjs +1 -0
  127. package/specSchema.mjs +88 -0
  128. package/ssg.cjs +1 -1
  129. package/ssg.d.ts +8 -2
  130. package/ssg.mjs +13 -9
  131. package/utils/agent/agentUtils.d.ts +81 -0
  132. package/utils/catalog/catalogContracts.d.ts +19 -0
  133. package/utils/catalog/catalogManifest.d.ts +8 -0
  134. package/utils/dashboard/dashboardSchema.d.ts +18 -0
  135. package/utils/dashboard/dashboardUtils.d.ts +97 -0
  136. package/utils/environment/environmentUtils.d.ts +5 -0
  137. package/utils/interop/a2uiInterop.d.ts +82 -0
  138. package/utils/interop/assistantUiInterop.d.ts +34 -0
  139. package/utils/interop/toolInterop.d.ts +30 -0
  140. package/utils/spec/specData.d.ts +19 -0
  141. package/utils/spec/specDefs.d.ts +11 -0
  142. package/utils/spec/specProps.d.ts +15 -0
  143. package/utils/spec/specSchema.d.ts +23 -0
  144. package/utils/spec/specTypes.d.ts +71 -0
  145. package/utils/spec/specValidate.d.ts +10 -0
@@ -0,0 +1,81 @@
1
+ /**
2
+ * The model behind the agent chrome — `<ToolCallCard>`, `<ApprovalCard>`, `<Reasoning>` and
3
+ * `<StreamingText>`. Four judgements, none of which needs React: what a status is *called*, how long a
4
+ * thought took in words, how a value a model invented becomes text that is safe to put on a page, and
5
+ * which part of a message arrived since the last render.
6
+ *
7
+ * The third is the reason this file exists. A tool's arguments are whatever the model produced —
8
+ * possibly circular, possibly a `BigInt`, possibly a megabyte — and `JSON.stringify` answers those three
9
+ * with a throw, a throw and a frozen tab. Components render, models decide.
10
+ */
11
+ /**
12
+ * Where a tool call is. The four states every agent runtime reports under its own spelling: AI SDK's
13
+ * `input-streaming`/`input-available`/`output-available`/`output-error`, and the plainer words the card
14
+ * shows. Declared out here rather than inside the namespace so a prop naming it resolves to its values —
15
+ * a catalog that printed the alias would constrain nothing.
16
+ */
17
+ export type ToolCallStatus = 'pending' | 'running' | 'success' | 'error';
18
+ /** What was decided about an action the agent asked permission for. `null` is "not yet". */
19
+ export type ApprovalDecision = 'approved' | 'rejected';
20
+ declare namespace AgentUtils {
21
+ function statusLabel(status: ToolCallStatus): string;
22
+ function decisionLabel(decision: ApprovalDecision): string;
23
+ /**
24
+ * How much of a value the card will show. Past this the text is cut and a line says how much was left —
25
+ * a model that returned a 4 MB tool result should cost a scroll bar, not the frame it is painted in.
26
+ */
27
+ const VALUE_LIMIT = 20000;
28
+ interface FormattedValue {
29
+ text: string;
30
+ /** How many characters were cut, or `0`. The card says so rather than showing text that stops. */
31
+ truncated: number;
32
+ }
33
+ /** A tool's input, output or error as text, capped. The one place a model's own data becomes a page. */
34
+ function formatValue(value: unknown, limit?: number): FormattedValue;
35
+ /** Whether there is anything to show at all — `null` and `undefined` are absence, `0` and `''` are not. */
36
+ function hasValue(value: unknown): boolean;
37
+ /**
38
+ * A count with its thousands grouped, done here rather than with `toLocaleString`: the number lands in
39
+ * prerendered HTML, and a separator that differs between the server's locale and the reader's is a
40
+ * hydration mismatch nobody would look for.
41
+ */
42
+ function formatCount(value: number): string;
43
+ /**
44
+ * How long a thought took, in the units a reader thinks in: milliseconds under a second, then seconds,
45
+ * then minutes and seconds. Rounded down for the minutes so "1m 0s" is a minute rather than two.
46
+ */
47
+ function formatDuration(milliseconds: number): string;
48
+ /**
49
+ * One run of text that arrived together, and the identity React keys it by. Keys are never reused, so a
50
+ * run that is still fading is never handed a different run's text half way through its entrance.
51
+ */
52
+ interface StreamSegment {
53
+ key: number;
54
+ text: string;
55
+ }
56
+ /**
57
+ * A streaming message between two renders: the text that has settled, and the last few runs to arrive,
58
+ * which are the ones still fading in.
59
+ */
60
+ interface StreamState {
61
+ settled: string;
62
+ segments: readonly StreamSegment[];
63
+ /** Monotone, and carried across a reset — a key a fading run still holds is never handed out twice. */
64
+ nextKey: number;
65
+ }
66
+ /**
67
+ * How many runs stay animated at once. The rest settle, so a message of any length is one text node plus
68
+ * this many spans — the reason the entrance costs the same at the first token and the ten-thousandth.
69
+ */
70
+ const STREAM_WINDOW = 8;
71
+ /** A message that is already whole: all of it settled, none of it animating. */
72
+ function initialStream(text: string): StreamState;
73
+ /** Everything on the page, settled and still arriving. */
74
+ function streamText(state: StreamState): string;
75
+ /**
76
+ * The next state for the text as it now stands. Pure, and keyed on the text itself rather than on a
77
+ * counter, so advancing twice with the same message is the same as advancing once.
78
+ */
79
+ function advanceStream(state: StreamState, text: string, window?: number): StreamState;
80
+ }
81
+ export default AgentUtils;
@@ -0,0 +1,19 @@
1
+ import { CatalogContract } from '@box-kite/core';
2
+ /**
3
+ * The props that are a *shape* rather than a value — a grid's columns, a dashboard's layout — as the JSON
4
+ * Schema a generated spec is judged against. Written here rather than extracted because the manifest maps
5
+ * types, and half of each of these shapes is React: a `Cell` renderer, an `onCellEdit`, a `ReactNode`. A
6
+ * mapping has to drop such a prop whole, which is what left the catalog able to place a dashboard and not
7
+ * to say what was in it — `<DataGrid>` arrived with no `def` at all, and `def` is required.
8
+ *
9
+ * Every key is typed against the interface it mirrors, so a prop renamed in the component is a compile
10
+ * error here rather than a constraint that silently stops matching anything.
11
+ */
12
+ declare namespace CatalogContracts {
13
+ /**
14
+ * Component name → the props of it a manifest entry cannot describe. Merged over the generated entry, so
15
+ * a prop that appears in both is this one: the curated shape is the narrower of the two by construction.
16
+ */
17
+ const CONTRACTS: Record<string, CatalogContract>;
18
+ }
19
+ export default CatalogContracts;
@@ -0,0 +1,8 @@
1
+ import { CatalogManifest } from '@box-kite/core';
2
+ /**
3
+ * Generated by `npm run docs:catalog` — never edited by hand. What a prop *means*, extracted from the
4
+ * same JSDoc the reference and the AI context come from; what it *accepts* is read off the live engine,
5
+ * so this file says nothing that could go stale against a `Box.extend()`.
6
+ */
7
+ declare const catalogManifest: CatalogManifest;
8
+ export default catalogManifest;
@@ -0,0 +1,18 @@
1
+ import { CatalogSchema } from '@box-kite/core';
2
+ /**
3
+ * The layout's own shape, as a schema and the two numbers it quotes. Its own module because both the
4
+ * dashboard and `catalog()` want it and only one of them wants the model around it: reaching it through
5
+ * `dashboardUtils` would put the compaction, the drag arithmetic and the parser in the catalog entry.
6
+ * Plain exports rather than a namespace, so neither entry carries a wrapper for four constants.
7
+ */
8
+ /** The layout format's own version, bumped when its shape changes and never when a dashboard does. */
9
+ export declare const LAYOUT_VERSION = 1;
10
+ /** Both ends of the column space a layout may declare, so a generated `columns: 400` cannot be rendered. */
11
+ export declare const MIN_COLUMNS = 1;
12
+ export declare const MAX_COLUMNS = 24;
13
+ /**
14
+ * The layout as JSON Schema — what a model generates a dashboard under, and the half of the contract a
15
+ * prompt cannot carry. Deliberately inside the subset `catalog()` emits and `<SpecRenderer>` validates,
16
+ * so a host can hand it to the same machinery: the schema says the shape and `parse` says the sense.
17
+ */
18
+ export declare const LAYOUT_SCHEMA: CatalogSchema;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Where a widget sits, in cells. The unit is the whole point: a layout written in cells is the same
3
+ * layout at any width, and a drag moves by one of them rather than by a pixel somebody measured.
4
+ */
5
+ export interface DashboardItem {
6
+ /** What this place belongs to — the `id` of the widget that fills it. */
7
+ id: string;
8
+ /** Column and row, both zero-based. */
9
+ x: number;
10
+ y: number;
11
+ /** How many columns and rows it spans, at least one of each. */
12
+ w: number;
13
+ h: number;
14
+ minW?: number;
15
+ minH?: number;
16
+ maxW?: number;
17
+ maxH?: number;
18
+ /** Never moved and never resized — the rest of the layout flows around it. */
19
+ fixed?: boolean;
20
+ }
21
+ /**
22
+ * The artifact: one column space, one list of places, and a version in front of both. It is what a model
23
+ * emits, what a host stores and what a drag reports back, which is why it is plain JSON with no
24
+ * component, no callback and no measurement anywhere in it.
25
+ */
26
+ export interface DashboardLayout {
27
+ version: number;
28
+ /** The space the items are written in. A narrower container renders a projection of it. */
29
+ columns: number;
30
+ items: DashboardItem[];
31
+ }
32
+ /** What a layout that arrived as JSON got wrong, in the shape the spec renderer reports issues in. */
33
+ export interface DashboardIssue {
34
+ code: 'not-an-object' | 'version' | 'columns' | 'items' | 'invalid-item' | 'duplicate-id';
35
+ /** Where it happened, printable: `items.2.w`. */
36
+ path: string;
37
+ message: string;
38
+ }
39
+ /** The pixel a cell steps by on each axis — one cell plus the gap after it. Measured once per drag. */
40
+ export interface DashboardStep {
41
+ x: number;
42
+ y: number;
43
+ }
44
+ declare namespace DashboardUtils {
45
+ const VERSION = 1;
46
+ const MIN_COLUMNS = 1;
47
+ const MAX_COLUMNS = 24;
48
+ /** Whether two places want the same cell. Touching edges do not overlap — `x + w` is the first column past it. */
49
+ function overlaps(left: DashboardItem, right: DashboardItem): boolean;
50
+ /**
51
+ * Every item clamped, then floated up and pushed down until nothing overlaps — so a layout has no holes
52
+ * and a widget cannot be parked in mid-air. That is what makes two dashboards of the same items compare
53
+ * equal, and it is why a drop below a neighbour rises to meet it.
54
+ *
55
+ * It is reading order and nothing else. A widget a drag is holding gets no priority here: settling it
56
+ * first floats it to the top of a board with nothing on it yet, which is every drag's opening frame
57
+ * (#183). Where a drop lands on an occupied cell it is `displace` that decides, before this runs.
58
+ */
59
+ function resolve(items: readonly DashboardItem[], columns: number): DashboardItem[];
60
+ /** The same, as a layout. Every function here returns one of these: a change is always the whole artifact. */
61
+ function normalize(layout: DashboardLayout): DashboardLayout;
62
+ function itemOf(layout: DashboardLayout, id: string): DashboardItem | undefined;
63
+ /** Where a widget sits in reading order, which is the order a stacked dashboard renders in. */
64
+ function ranks(layout: DashboardLayout): Map<string, number>;
65
+ /** A widget sent to a cell. The rest of the layout moves around it rather than refusing the move. */
66
+ function moveTo(layout: DashboardLayout, id: string, x: number, y: number): DashboardLayout;
67
+ /** A widget given a size. Its own minimum and maximum are applied by `resolve`, so this only asks. */
68
+ function resizeTo(layout: DashboardLayout, id: string, w: number, h: number): DashboardLayout;
69
+ /** A widget added where there is room for it: under everything, which compaction then floats up. */
70
+ function add(layout: DashboardLayout, item: Omit<DashboardItem, 'x' | 'y'> & Partial<DashboardItem>): DashboardLayout;
71
+ function remove(layout: DashboardLayout, id: string): DashboardLayout;
72
+ /**
73
+ * The same layout in a narrower space — arithmetic, not a measurement, which is what lets every
74
+ * projection be a class the browser chooses between. Widths scale and round up to a cell, so a widget
75
+ * never projects to nothing; the compaction afterwards is what closes the holes that leaves.
76
+ */
77
+ function project(layout: DashboardLayout, columns: number): DashboardLayout;
78
+ /** Whether a layout says anything new — so a drag that crossed no cell costs no render and no callback. */
79
+ function same(left: DashboardLayout, right: DashboardLayout): boolean;
80
+ /** How many cells a pointer has travelled, rounded to the nearest one. The step is a cell plus its gap. */
81
+ function cellsMoved(dx: number, dy: number, step: DashboardStep): {
82
+ columns: number;
83
+ rows: number;
84
+ };
85
+ /**
86
+ * A layout read from somewhere it could be anything: a model's answer, a `localStorage` string, a
87
+ * column of a database written by a version that has since moved on. Everything unusable is dropped and
88
+ * reported rather than thrown — a dashboard missing one widget is a dashboard, and an exception is not.
89
+ */
90
+ function parse(value: unknown, fallbackColumns?: number): {
91
+ layout: DashboardLayout;
92
+ issues: DashboardIssue[];
93
+ };
94
+ /** The layout as JSON Schema: what a model generates a dashboard under, and what `<SpecRenderer>` validates. */
95
+ const SCHEMA: import("../../core").CatalogSchema;
96
+ }
97
+ export default DashboardUtils;
@@ -6,6 +6,11 @@
6
6
  */
7
7
  /** A browser: a window with a document. What an effect that touches layout needs to exist. */
8
8
  export declare function isBrowser(): boolean;
9
+ /**
10
+ * Development, unless the bundler or the process says production. Spelled out so a bundler replaces it;
11
+ * a page with no bundler has no `process` at all and counts as production.
12
+ */
13
+ export declare function isDevelopment(): boolean;
9
14
  /** Whether there is a document at all — false during a server render. */
10
15
  export declare function hasDocument(): boolean;
11
16
  /** The document, or null when there is none, so a caller can `?.` instead of branching. */
@@ -0,0 +1,82 @@
1
+ import { BoxCatalog, CatalogSchema } from '@box-kite/core';
2
+ import { SpecNode } from '../spec/specTypes';
3
+ /** One component of a surface, flattened to v0.9's shape whichever version it arrived in. */
4
+ export interface A2uiComponent {
5
+ id: string;
6
+ component: string;
7
+ [prop: string]: unknown;
8
+ }
9
+ /** One surface: its components, its own data model, and what the agent said about rendering it. */
10
+ export interface A2uiSurface {
11
+ id: string;
12
+ catalogId?: string;
13
+ /** v0.8 names the root in its `beginRendering`; v0.9 settles it by convention, which is the id `root`. */
14
+ root?: string;
15
+ theme?: Record<string, unknown>;
16
+ components: Record<string, A2uiComponent>;
17
+ data: Record<string, unknown>;
18
+ }
19
+ /** Every surface an agent has opened, in the order it opened them. */
20
+ export interface A2uiState {
21
+ surfaces: Record<string, A2uiSurface>;
22
+ order: string[];
23
+ }
24
+ export interface A2uiSpecOptions {
25
+ /** Which component to start from. Otherwise the surface's own root, and then the id `root`. */
26
+ root?: string;
27
+ /**
28
+ * `catalog()`, where the agent generated against this library's own components: a prop the catalog
29
+ * lists as an event becomes an `on` binding rather than a value. Without one, only A2UI's `action` is.
30
+ */
31
+ catalog?: {
32
+ components: Record<string, {
33
+ events?: string[];
34
+ }>;
35
+ };
36
+ }
37
+ export interface A2uiCatalogOptions {
38
+ /** The document's own id, which is what an agent's `createSurface.catalogId` names. */
39
+ catalogId?: string;
40
+ title?: string;
41
+ description?: string;
42
+ }
43
+ declare namespace A2uiInterop {
44
+ /** The id v0.9 settles the root by, since its `createSurface` does not carry one. */
45
+ const ROOT_ID = "root";
46
+ /** The surface a message means when it names none, which is what the published renderers call it. */
47
+ const DEFAULT_SURFACE = "main";
48
+ const EMPTY: A2uiState;
49
+ /**
50
+ * One message, whichever of v0.8 and v0.9 it is written in. The same state comes back where the
51
+ * message changed nothing or is not an A2UI message at all — a transport carries plenty that is not.
52
+ */
53
+ function apply(state: A2uiState, message: unknown): A2uiState;
54
+ /** A whole stream, oldest first. A JSONL transport is `applyAll(state, lines.map(JSON.parse))`. */
55
+ function applyAll(state: A2uiState, messages: readonly unknown[]): A2uiState;
56
+ /** A surface by id, or the first one opened — which is the whole of it for an agent that opens one. */
57
+ function surface(state: A2uiState, id?: string): A2uiSurface | null;
58
+ /**
59
+ * A surface as one `<SpecRenderer>` tree. A component nothing reaches from the root is not rendered —
60
+ * an agent streams a leaf before the branch that holds it, so a half-arrived surface is the ordinary
61
+ * case rather than an error, and the node appears when the message naming it does.
62
+ */
63
+ function toSpec(surface: A2uiSurface | null, options?: A2uiSpecOptions): SpecNode | null;
64
+ /**
65
+ * `catalog()` as an A2UI catalog document. The components and the values their props take are the
66
+ * same ones; what changes is the shape around them — a component carries its own `id`, its type is a
67
+ * property rather than the key above it, and its children are **ids** rather than nested nodes, which
68
+ * is the whole of what an adjacency list is.
69
+ *
70
+ * Every event the catalog names becomes a string, because a JSON message cannot carry a function: what
71
+ * an agent writes is the name of an action, and `onAction` is where the host decides what it does.
72
+ */
73
+ /**
74
+ * One component of a catalog document, self-contained. A `$ref` resolves against the *document*, so a
75
+ * component lifted out of one on its own points at nothing — which is what every consumer that
76
+ * converts a component at a time does (`z.fromJSONSchema` for CopilotKit's renderer and json-render
77
+ * alike). Measured against zod 4.6: it throws `Reference not found: #/$defs/color`.
78
+ */
79
+ function componentSchema(document: Record<string, unknown>, name: string): CatalogSchema | null;
80
+ function catalogDocument(catalog: BoxCatalog, options?: A2uiCatalogOptions): Record<string, unknown>;
81
+ }
82
+ export default A2uiInterop;
@@ -0,0 +1,34 @@
1
+ import { SpecNode } from '../spec/specTypes';
2
+ /** assistant-ui's node: a string renders as text, an object is a component. */
3
+ export type GenerativeUiNode = string | {
4
+ component: string;
5
+ props?: Record<string, unknown>;
6
+ children?: readonly GenerativeUiNode[];
7
+ key?: string;
8
+ };
9
+ /** assistant-ui's root, which is one node or several. */
10
+ export interface GenerativeUiSpec {
11
+ root: GenerativeUiNode | readonly GenerativeUiNode[];
12
+ }
13
+ /** What `fromSpec` could not carry across, since their spec has nowhere to put it. */
14
+ export interface GenerativeUiLoss {
15
+ /** `data-binding`, `repeat` or `event` — the three things their shape has no room for. */
16
+ code: 'data-binding' | 'repeat' | 'event';
17
+ path: string;
18
+ }
19
+ declare namespace AssistantUiInterop {
20
+ /**
21
+ * Their spec as ours. Several roots become the children of nothing, so a multi-root spec is rendered
22
+ * by mapping this over `spec.root` rather than being wrapped in a container nobody asked for.
23
+ */
24
+ function toSpec(spec: GenerativeUiSpec | null | undefined): SpecNode[];
25
+ /**
26
+ * Ours as theirs, with what could not come along reported rather than dropped in silence. A named
27
+ * slot has no counterpart either and is left out with the rest — their nodes have one children list.
28
+ */
29
+ function fromSpec(spec: SpecNode | readonly SpecNode[]): {
30
+ spec: GenerativeUiSpec;
31
+ losses: GenerativeUiLoss[];
32
+ };
33
+ }
34
+ export default AssistantUiInterop;
@@ -0,0 +1,30 @@
1
+ import { ApprovalDecision, ToolCallStatus } from '../agent/agentUtils';
2
+ /** Which of the two cards a part belongs to. A call is shown; a question is answered. */
3
+ export type ToolPartKind = 'call' | 'approval';
4
+ /** A tool call in this library's words, whichever runtime's words arrived. */
5
+ export interface ToolPart {
6
+ kind: ToolPartKind;
7
+ /** Where the call is, for `<ToolCallCard status>`. An approval waiting on a person is `pending`. */
8
+ status: ToolCallStatus;
9
+ /** What was decided, for `<ApprovalCard decision>`. `null` is a question nobody has answered yet. */
10
+ decision: ApprovalDecision | null;
11
+ /** The arguments, where the part carried them under any of its runtimes' names. */
12
+ input?: unknown;
13
+ output?: unknown;
14
+ /** The failure, as text, where the part reported one. */
15
+ error?: string;
16
+ }
17
+ declare namespace ToolInterop {
18
+ /**
19
+ * A part from any of the three runtimes that hand you one, in this library's words. `null` is a value
20
+ * that is not a tool part at all — the caller decides what that means, since a half-streamed message
21
+ * carrying nothing yet is ordinary.
22
+ */
23
+ function toolPart(value: unknown): ToolPart | null;
24
+ /**
25
+ * AG-UI is the odd one out: it reports *events*, not parts, so a card needs a fold rather than a
26
+ * mapping. One call per event, oldest first, keyed by `toolCallId`.
27
+ */
28
+ function applyEvent(parts: Readonly<Record<string, ToolPart>>, event: unknown): Record<string, ToolPart>;
29
+ }
30
+ export default ToolInterop;
@@ -0,0 +1,19 @@
1
+ import { SpecRef, SpecScope } from './specTypes';
2
+ declare namespace SpecData {
3
+ /** A reference is a plain object carrying exactly one of the three keys, and nothing beside it. */
4
+ function isRef(value: unknown): value is SpecRef;
5
+ /** What a reference points at, and whether it pointed at anything — `undefined` is an answer either way. */
6
+ function resolve(ref: SpecRef, scope: SpecScope): {
7
+ value: unknown;
8
+ found: boolean;
9
+ };
10
+ /** The text of a reference, for the message that says it resolved to nothing. */
11
+ function pathOf(ref: SpecRef): string;
12
+ /**
13
+ * A value with every reference inside it resolved — a prop is `{ $data: … }`, an array of them, or an
14
+ * object with one in a corner (a gradient's stops, a chart's series). Reported rather than dropped:
15
+ * the caller decides, because a reference that resolves to nothing mid-stream is ordinary.
16
+ */
17
+ function deep(value: unknown, scope: SpecScope, onMissing?: (path: string) => void, depth?: number): unknown;
18
+ }
19
+ export default SpecData;
@@ -0,0 +1,11 @@
1
+ import { CatalogSchema } from '@box-kite/core';
2
+ declare namespace SpecDefs {
3
+ /**
4
+ * A component's props, with its local `$defs` lifted into `defs` (which is mutated). The colour grammar
5
+ * is the same object for every component, so the twenty-six colour props across a whole catalog share
6
+ * one definition — and a host's custom schema that happens to name `color` something else is renamed
7
+ * rather than silently taking the palette's meaning.
8
+ */
9
+ function hoist(props: CatalogSchema, defs: Record<string, CatalogSchema>): CatalogSchema;
10
+ }
11
+ export default SpecDefs;
@@ -0,0 +1,15 @@
1
+ import { SpecAction, SpecIssue, SpecRules, SpecScope } from './specTypes';
2
+ declare namespace SpecProps {
3
+ interface Resolved {
4
+ /** Everything the schema allowed, resolved. */
5
+ props: Record<string, unknown>;
6
+ /** The events the node bound, for the renderer to turn into functions. */
7
+ actions: Record<string, SpecAction>;
8
+ issues: SpecIssue[];
9
+ /** Required props that did not arrive, or were refused. A node with any of these cannot render. */
10
+ missing: string[];
11
+ }
12
+ /** The props pass for one node: resolved, validated, and an issue for everything left out. */
13
+ function resolve(node: Record<string, unknown>, rules: SpecRules, scope: SpecScope, path: string): Resolved;
14
+ }
15
+ export default SpecProps;
@@ -0,0 +1,23 @@
1
+ import { CatalogSchema } from '@box-kite/core';
2
+ /** A component, as much of it as a tree schema needs. A `catalog()` entry is one of these already. */
3
+ export interface SpecSchemaComponent {
4
+ description?: string;
5
+ props?: CatalogSchema;
6
+ slots?: string[];
7
+ events?: string[];
8
+ }
9
+ export interface SpecSchemaSource {
10
+ components: Record<string, SpecSchemaComponent>;
11
+ }
12
+ export interface SpecSchemaOptions {
13
+ /** Which components may be the root of the tree. Every one of them by default. */
14
+ root?: string[];
15
+ /**
16
+ * Whether a prop may be a `{ $data: … }` reference and a node may `repeat`. Off by default: it widens
17
+ * every prop in the document with an `anyOf`, which is a cost a static view should not pay.
18
+ */
19
+ bindings?: boolean;
20
+ }
21
+ /** The JSON Schema a generated view has to conform to: a tree of the components this source allows. */
22
+ export declare function specSchema(source: SpecSchemaSource, options?: SpecSchemaOptions): CatalogSchema;
23
+ export default specSchema;
@@ -0,0 +1,71 @@
1
+ import { CatalogSchema } from '@box-kite/core';
2
+ /** A value read out of the data the spec is rendered against: `{ $data: 'user.name' }`. */
3
+ export interface SpecDataRef {
4
+ /** A dot path (`stats.revenue.0`) or a JSON Pointer (`/stats/revenue/0`). Empty is the whole of it. */
5
+ $data: string;
6
+ }
7
+ /** The current item of the enclosing `repeat`. `{ $item: '' }` is the item itself. */
8
+ export interface SpecItemRef {
9
+ $item: string;
10
+ }
11
+ /** The current index of the enclosing `repeat`, from zero. */
12
+ export interface SpecIndexRef {
13
+ $index: true;
14
+ }
15
+ /** Anywhere a value can stand, a reference to one can stand instead. */
16
+ export type SpecRef = SpecDataRef | SpecItemRef | SpecIndexRef;
17
+ /** What an event does: it tells the host, which is the only thing that may decide what happens next. */
18
+ export interface SpecAction {
19
+ action: string;
20
+ /** Sent back with the action, resolved the way a prop is. */
21
+ payload?: unknown;
22
+ }
23
+ /** One node of a generated tree, or a leaf that is text. */
24
+ export type SpecChild = SpecNode | SpecRef | string | number | boolean | null;
25
+ export interface SpecNode {
26
+ /** The component to render. A name the registry does not hold renders nothing. */
27
+ type: string;
28
+ /** React's key, where the host wants a node's identity to survive a re-order. */
29
+ key?: string;
30
+ /** Everything the component's own schema allows, and nothing else. */
31
+ props?: Record<string, unknown>;
32
+ /** The default slot. */
33
+ children?: SpecChild | SpecChild[];
34
+ /** The component's named slots — `Tooltip`'s `content`, a form control's `label`. */
35
+ slots?: Record<string, SpecChild | SpecChild[]>;
36
+ /** An event prop bound to an action the host handles: `{ onClick: 'refresh' }`. */
37
+ on?: Record<string, SpecAction | string>;
38
+ /** Render this node once per item of an array. `$item` and `$index` address the item inside it. */
39
+ repeat?: SpecRef;
40
+ }
41
+ /** Why a node, a prop or a child did not render. Advisory: the tree renders around every one of them. */
42
+ export type SpecIssueCode = 'unknown-component' | 'unknown-prop' | 'invalid-prop' | 'missing-prop' | 'unknown-slot' | 'unknown-event' | 'unresolved-data' | 'invalid-child' | 'invalid-repeat' | 'too-deep' | 'too-many-nodes' | 'render-error';
43
+ export interface SpecIssue {
44
+ code: SpecIssueCode;
45
+ /** Where in the spec it happened, as a path that can be printed: `children.1.props.bgColor`. */
46
+ path: string;
47
+ message: string;
48
+ /** The component the node named, where it named one. */
49
+ component?: string;
50
+ prop?: string;
51
+ }
52
+ /** What the renderer needs to know about one component. The implementation is the registry's half. */
53
+ export interface SpecRules {
54
+ /** What its props may be. No schema at all means no props: a component is opened up on purpose. */
55
+ props?: CatalogSchema;
56
+ /** Where children may go. `default` is the ordinary children slot. */
57
+ slots: string[];
58
+ /** The props a spec may bind an action to. Nothing else can ever become a function. */
59
+ events: string[];
60
+ description?: string;
61
+ }
62
+ /** The data a reference is resolved against, plus whatever `repeat` put in scope. */
63
+ export interface SpecScope {
64
+ data?: unknown;
65
+ item?: unknown;
66
+ index?: number;
67
+ /** Whether an `$item`/`$index` reference means anything here at all. */
68
+ repeating?: boolean;
69
+ }
70
+ /** The ordinary children slot, under the name the catalog gives it. */
71
+ export declare const DEFAULT_SLOT = "default";
@@ -0,0 +1,10 @@
1
+ import { CatalogSchema } from '@box-kite/core';
2
+ declare namespace SpecValidate {
3
+ /** A name a spec may set at all. */
4
+ function isSafeKey(key: string): boolean;
5
+ /** An object a spec could have written: `JSON.parse` produces these and nothing else. */
6
+ function isPlainObject(value: unknown): value is Record<string, unknown>;
7
+ /** Whether a value is one this schema allows. The whole of it: an invalid part makes the value invalid. */
8
+ function matches(schema: CatalogSchema, value: unknown, root?: CatalogSchema): boolean;
9
+ }
10
+ export default SpecValidate;