@box-kite/react 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/rules/box-kite-rules.md +16 -0
- package/.claude/skills/box-kite/SKILL.md +16 -0
- package/.claude/skills/box-kite/references/components.md +8 -3
- package/.claude/skills/box-kite/references/patterns.md +23 -0
- package/.cursor/rules/box-kite.mdc +16 -0
- package/AGENTS.md +19 -0
- package/BOX_AI_CONTEXT.md +562 -1
- package/BOX_KITE_AI_CONTEXT.md +562 -1
- package/README.md +39 -7
- package/catalog.cjs +1 -0
- package/catalog.d.ts +8 -0
- package/catalog.mjs +2333 -0
- package/client.cjs +1 -1
- package/client.mjs +40 -42
- package/components/agent.cjs +1 -0
- package/components/agent.d.ts +215 -0
- package/components/agent.mjs +405 -0
- package/components/chart.d.ts +1 -0
- package/components/dashboard.cjs +1 -0
- package/components/dashboard.d.ts +121 -0
- package/components/dashboard.mjs +690 -0
- package/components/dataGrid/components/dataGridBody.d.ts +2 -1
- package/components/dataGrid/components/dataGridDetailRow.d.ts +13 -2
- package/components/dataGrid/components/dataGridGroupRow.d.ts +13 -2
- package/components/dataGrid/components/dataGridRow.d.ts +13 -2
- package/components/dataGrid/contracts/dataGridContract.d.ts +66 -2
- package/components/dataGrid/models/cellModel.d.ts +3 -0
- package/components/dataGrid/models/editModel.d.ts +27 -0
- package/components/dataGrid/models/exportModel.d.ts +2 -1
- package/components/dataGrid/models/gridModel.d.ts +3 -0
- package/components/dataGrid/models/rangeModel.d.ts +119 -0
- package/components/dataGrid/models/viewportModel.d.ts +23 -2
- package/components/dataGrid/useGridNavigation.d.ts +10 -2
- package/components/dataGrid.cjs +4 -1
- package/components/dataGrid.d.ts +3 -0
- package/components/dataGrid.mjs +1056 -765
- package/components/markdown.cjs +1 -0
- package/components/markdown.d.ts +55 -0
- package/components/markdown.mjs +179 -0
- package/components/semantics.d.ts +29 -29
- package/components/skeleton.cjs +1 -0
- package/components/skeleton.d.ts +34 -0
- package/components/skeleton.mjs +25 -0
- package/dashboardSchema.cjs +1 -0
- package/dashboardSchema.mjs +78 -0
- package/docs/a11y.md +2 -3
- package/docs/catalog.md +451 -0
- package/docs/components.md +4 -0
- package/docs/index.md +3 -0
- package/docs/interop.md +237 -0
- package/docs/mcp.md +69 -0
- package/docs/props.md +3 -3
- package/interop.cjs +1 -0
- package/interop.d.ts +51 -0
- package/interop.mjs +454 -0
- package/mcp/src/data.d.ts +88 -0
- package/mcp/src/data.test.d.ts +1 -0
- package/mcp/src/engine.d.ts +23 -0
- package/mcp/src/index.d.ts +1 -0
- package/mcp/src/search.d.ts +26 -0
- package/mcp/src/search.test.d.ts +1 -0
- package/mcp/src/server.d.ts +18 -0
- package/mcp/src/server.test.d.ts +1 -0
- package/mcp/src/styles.d.ts +27 -0
- package/mcp/src/styles.test.d.ts +1 -0
- package/mcp/src/tools.d.ts +18 -0
- package/mcp/src/vocabulary.d.ts +41 -0
- package/package.json +124 -17
- package/react/spec/renderSpec.d.ts +51 -0
- package/react/spec/specBoundary.d.ts +25 -0
- package/react/spec/specRegistry.d.ts +42 -0
- package/react/spec/specRenderer.d.ts +10 -0
- package/registry/blocks/dashboard-shell/dashboard-shell.d.ts +22 -0
- package/registry/blocks/dashboard-shell/dashboard-stats.d.ts +13 -0
- package/registry/blocks/data-grid/invoice-rows.d.ts +15 -0
- package/registry/blocks/data-grid/invoices-grid.d.ts +1 -0
- package/registry/blocks/settings-form/settings-form.d.ts +17 -0
- package/spec.cjs +2 -0
- package/spec.d.ts +12 -0
- package/spec.mjs +382 -0
- package/specData.cjs +1 -0
- package/specData.mjs +69 -0
- package/specDefs.cjs +1 -0
- package/specDefs.mjs +33 -0
- package/specSchema.cjs +1 -0
- package/specSchema.mjs +88 -0
- package/utils/agent/agentUtils.d.ts +81 -0
- package/utils/catalog/catalogContracts.d.ts +19 -0
- package/utils/catalog/catalogManifest.d.ts +8 -0
- package/utils/dashboard/dashboardSchema.d.ts +18 -0
- package/utils/dashboard/dashboardUtils.d.ts +97 -0
- package/utils/interop/a2uiInterop.d.ts +82 -0
- package/utils/interop/assistantUiInterop.d.ts +34 -0
- package/utils/interop/toolInterop.d.ts +30 -0
- package/utils/spec/specData.d.ts +19 -0
- package/utils/spec/specDefs.d.ts +11 -0
- package/utils/spec/specProps.d.ts +15 -0
- package/utils/spec/specSchema.d.ts +23 -0
- package/utils/spec/specTypes.d.ts +71 -0
- package/utils/spec/specValidate.d.ts +10 -0
package/docs/interop.md
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# Ecosystem interop
|
|
2
|
+
|
|
3
|
+
`@box-kite/react/interop` is this library's shapes and four other runtimes' shapes, mapped onto each
|
|
4
|
+
other. It is framework-free, carries no engine, and depends on none of them — an adapter that imported a
|
|
5
|
+
runtime would be choosing it for the app, and the app has already chosen.
|
|
6
|
+
|
|
7
|
+
There are two things every agentic runtime describes, in words of its own:
|
|
8
|
+
|
|
9
|
+
- **A tool call.** Where it is, what it was given, what it answered, and whether it is waiting on a
|
|
10
|
+
person. `<ToolCallCard>` and `<ApprovalCard>` (`components/agent`) draw the two halves of it.
|
|
11
|
+
- **A tree of components.** A name resolved against an allow-list the app owns, JSON props, children.
|
|
12
|
+
`catalog()` says what may be in it and `<SpecRenderer>` renders it.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { toolPart, a2uiApplyAll, a2uiSurface, a2uiToSpec, a2uiCatalog } from '@box-kite/react/interop';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## The tool state, in one vocabulary
|
|
19
|
+
|
|
20
|
+
`toolPart(part)` reads a part from AI SDK, assistant-ui or CopilotKit and answers in this library's
|
|
21
|
+
words: `{ kind, status, decision, input, output, error }`, where `kind` is `'call'` or `'approval'` and
|
|
22
|
+
`status` is the `pending`/`running`/`success`/`error` a `<ToolCallCard>` takes.
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { toolPart } from '@box-kite/react/interop';
|
|
26
|
+
import { ToolCallCard, ApprovalCard } from '@box-kite/react/components/agent';
|
|
27
|
+
|
|
28
|
+
function Part({ part }: { part: unknown }) {
|
|
29
|
+
const mapped = toolPart(part);
|
|
30
|
+
|
|
31
|
+
if (!mapped) return null;
|
|
32
|
+
if (mapped.kind === 'approval') return <ApprovalCard title="Approve this call?" onDecisionChange={respond} />;
|
|
33
|
+
|
|
34
|
+
return <ToolCallCard name="searchOrders" status={mapped.status} input={mapped.input} output={mapped.output} />;
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**A decision is not a stage a call passes through, it is a question somebody answers** — which is why
|
|
39
|
+
two components cover what AI SDK reports as six states, and why the runtimes that report four are the
|
|
40
|
+
ones whose human-in-the-loop lives on a second channel:
|
|
41
|
+
|
|
42
|
+
| Runtime | What it reports | Where the question is |
|
|
43
|
+
| ------------ | -------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
|
|
44
|
+
| AI SDK 6/7 | `input-streaming`, `input-available`, `output-available`, `output-error`, `approval-requested`, `approval-responded` | Two of the six states, with `approval.approved` |
|
|
45
|
+
| assistant-ui | `status: { type: 'running' \| 'complete' \| 'incomplete' \| 'requires-action' }` | `requires-action`, under either of its two reasons |
|
|
46
|
+
| CopilotKit | `status: 'inProgress' \| 'executing' \| 'complete'` | `renderAndWaitForResponse`, which hands you `respond` |
|
|
47
|
+
| AG-UI | `TOOL_CALL_START` / `_ARGS` / `_END` / `_RESULT` events | `INTERRUPT` |
|
|
48
|
+
|
|
49
|
+
**AG-UI is the odd one out, and it is worth knowing why**: it reports _events_, not parts, so its cards
|
|
50
|
+
need a fold rather than a mapping. `applyToolEvent(parts, event)` is that fold — one call per event,
|
|
51
|
+
oldest first, keyed by `toolCallId`.
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { applyToolEvent } from '@box-kite/react/interop';
|
|
55
|
+
|
|
56
|
+
const parts = events.reduce(applyToolEvent, {});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## A2UI
|
|
60
|
+
|
|
61
|
+
[A2UI](https://a2ui.org/) is the declarative UI protocol Google published, and the one CopilotKit and
|
|
62
|
+
Oracle converged on. Its wire shape is the only one in this family that is genuinely different: a **flat
|
|
63
|
+
adjacency list** of components referring to each other by id, arriving one message at a time, with a data
|
|
64
|
+
model of its own per surface. `<SpecRenderer>` renders a tree, so this is a real adapter rather than a
|
|
65
|
+
rename.
|
|
66
|
+
|
|
67
|
+
### Their messages, rendered here
|
|
68
|
+
|
|
69
|
+
`a2uiApplyAll` folds a message stream into the surfaces it names, and `a2uiToSpec` turns one surface's
|
|
70
|
+
adjacency list into the tree the renderer takes. Both v0.8 and v0.9 are read; the fold is **pure and
|
|
71
|
+
hands the same state back when a message changed nothing**, so holding it in `useState` re-renders when
|
|
72
|
+
the surface moved and not when a message arrived for a different one.
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { useState } from 'react';
|
|
76
|
+
import { a2uiApply, a2uiEmpty, a2uiSurface, a2uiToSpec } from '@box-kite/react/interop';
|
|
77
|
+
import SpecRenderer from '@box-kite/react/spec';
|
|
78
|
+
|
|
79
|
+
function Surface({ registry, catalog }) {
|
|
80
|
+
const [state, setState] = useState(a2uiEmpty);
|
|
81
|
+
|
|
82
|
+
useA2uiStream((message) => setState((current) => a2uiApply(current, message)));
|
|
83
|
+
|
|
84
|
+
const surface = a2uiSurface(state);
|
|
85
|
+
|
|
86
|
+
return <SpecRenderer spec={a2uiToSpec(surface, { catalog })} registry={registry} data={surface?.data} onAction={run} />;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Three things the two models already agreed on, each a special case that did not have to be written:
|
|
91
|
+
|
|
92
|
+
- **A2UI's data binding is already ours.** `{ "path": "/user/email" }` is a JSON Pointer, and `$data` has
|
|
93
|
+
taken a JSON Pointer since it was written, so a binding is a rename rather than a parse. The surface's
|
|
94
|
+
own data model is what goes in `<SpecRenderer data>`.
|
|
95
|
+
- **A template is a `repeat`.** `children: { componentId, path }` is one node per item of an array, which
|
|
96
|
+
is exactly what `repeat` means, so a list that streams costs nothing extra.
|
|
97
|
+
- **A half-arrived surface is the ordinary case.** An agent streams a leaf before the branch that holds
|
|
98
|
+
it; a component nothing reaches from the root is simply not rendered yet, and appears when the message
|
|
99
|
+
naming it does. A cycle in the id graph is cut rather than walked.
|
|
100
|
+
|
|
101
|
+
What A2UI owns rather than the component — `id`, `component`, `child`, `children`, `action` — never
|
|
102
|
+
reaches the registry as a prop. **`action` becomes an `on` binding under that name**, because what it
|
|
103
|
+
means belongs to the component it lands on: an app registering Box components under A2UI's own names
|
|
104
|
+
(`Text`, `Button`, `Row`) declares `events: ['action']` on them.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
createSpecRegistry({
|
|
108
|
+
components: {
|
|
109
|
+
Button: { component: Button, events: ['action'], props: BUTTON_PROPS },
|
|
110
|
+
Column: { component: Flex, props: COLUMN_PROPS },
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Where the agent generated against _this library's_ catalog instead, pass it — then a prop the catalog
|
|
116
|
+
calls an event is bound as one and the rest are values:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
a2uiToSpec(surface, { catalog: catalog({ include: ['Flex', 'H2', 'Button'] }) });
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Our components, generated for
|
|
123
|
+
|
|
124
|
+
`a2uiCatalog(catalog())` is `catalog()` as an A2UI catalog document — the same components and the same
|
|
125
|
+
values their props take, in the shape around them that an adjacency list needs: a component carries its
|
|
126
|
+
own `id`, its type is a property rather than the key above it, and its children are **ids** rather than
|
|
127
|
+
nested nodes. Every event becomes a string, because a JSON message cannot carry a function: what an agent
|
|
128
|
+
writes is the name of an action, and `onAction` is where the host decides what it does.
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { catalog } from '@box-kite/react/catalog';
|
|
132
|
+
import { a2uiCatalog } from '@box-kite/react/interop';
|
|
133
|
+
|
|
134
|
+
export const document = a2uiCatalog(catalog({ include: ['Flex', 'H2', 'Sparkline'], styleProps: ['p', 'gap', 'bgColor'] }), {
|
|
135
|
+
catalogId: 'https://example.com/a2ui/box-kite.json',
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Serve it at the `catalogId` you gave it**, which is what an agent's `createSurface` names.
|
|
140
|
+
|
|
141
|
+
## CopilotKit
|
|
142
|
+
|
|
143
|
+
Two surfaces, and they want opposite directions.
|
|
144
|
+
|
|
145
|
+
**Its A2UI renderer** (`@copilotkit/a2ui-renderer`) takes a catalog built from Zod schemas and React
|
|
146
|
+
renderers. `z.fromJSONSchema` is the whole of the bridge — which is why `catalog()` emits JSON Schema at
|
|
147
|
+
all. One trap, measured against zod 4.6: **a `$ref` resolves against the document, not against the piece
|
|
148
|
+
you lifted out of it**, so converting a component on its own throws `Reference not found: #/$defs/color`.
|
|
149
|
+
`a2uiComponentSchema(document, name)` is that component with the document's definitions attached.
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
import { createCatalog } from '@copilotkit/a2ui-renderer';
|
|
153
|
+
import * as z from 'zod';
|
|
154
|
+
import { a2uiCatalog, a2uiComponentSchema } from '@box-kite/react/interop';
|
|
155
|
+
|
|
156
|
+
const document = a2uiCatalog(catalog({ include: ['Flex', 'H2', 'P'] }));
|
|
157
|
+
const names = Object.keys(document.components);
|
|
158
|
+
|
|
159
|
+
const definitions = Object.fromEntries(
|
|
160
|
+
names.map((name) => [name, { props: z.fromJSONSchema(a2uiComponentSchema(document, name)), description: '' }]),
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// Their renderer hands a component its resolved props and a `children(id)` — the adjacency list again.
|
|
164
|
+
const renderers = { Flex: ({ props, children }) => <Flex {...props}>{props.children?.map(children)}</Flex> };
|
|
165
|
+
|
|
166
|
+
export const boxKiteCatalog = createCatalog(definitions, renderers, { catalogId: document.catalogId });
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Its actions** (`useCopilotAction`) take a render function, so the cards go in as they are. `render` is a
|
|
170
|
+
call being shown; `renderAndWaitForResponse` is a question, and the `respond` it hands you is what
|
|
171
|
+
`onDecisionChange` calls.
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
useCopilotAction({
|
|
175
|
+
name: 'refundOrder',
|
|
176
|
+
parameters: [{ name: 'orderId', type: 'number' }],
|
|
177
|
+
renderAndWaitForResponse: ({ args, respond }) => (
|
|
178
|
+
<ApprovalCard title={`Refund order ${args.orderId}`} onDecisionChange={(decision) => respond?.(decision === 'approved')} />
|
|
179
|
+
),
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## assistant-ui
|
|
184
|
+
|
|
185
|
+
Its `GenerativeUISpec` and this library's `SpecNode` are the same idea arrived at twice. Three
|
|
186
|
+
differences, and they are the whole adapter: the name is `component` rather than `type`, a child may be a
|
|
187
|
+
bare string that renders as text, and their nodes carry no data binding, no repeat and no action channel
|
|
188
|
+
— in their design those are the tool's job rather than the spec's.
|
|
189
|
+
|
|
190
|
+
`fromGenerativeUi(spec)` reads theirs and gives back an array of `SpecNode` (several roots stay several
|
|
191
|
+
roots; wrapping them in a container nobody asked for would change the layout). `toGenerativeUi(spec)`
|
|
192
|
+
goes the other way, and **reports what it could not carry** rather than emitting a tree that renders half
|
|
193
|
+
a view in silence:
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
const { spec, losses } = toGenerativeUi(node);
|
|
197
|
+
// losses: [{ code: 'data-binding' | 'repeat' | 'event', path }]
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Its Tool UI** is a component per tool name, and the cards go in as they are:
|
|
201
|
+
|
|
202
|
+
```tsx
|
|
203
|
+
import { makeAssistantToolUI } from '@assistant-ui/react';
|
|
204
|
+
import { ToolCallCard } from '@box-kite/react/components/agent';
|
|
205
|
+
import { toolPart } from '@box-kite/react/interop';
|
|
206
|
+
|
|
207
|
+
export const SearchOrdersUI = makeAssistantToolUI({
|
|
208
|
+
toolName: 'searchOrders',
|
|
209
|
+
render: (part) => <ToolCallCard name="searchOrders" {...toolPart(part)} />,
|
|
210
|
+
});
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## json-render
|
|
214
|
+
|
|
215
|
+
[`@json-render/react`](https://json-render.dev) wants a Zod schema per component, and `z.fromJSONSchema`
|
|
216
|
+
is again the whole adapter — the recipe is in
|
|
217
|
+
[generative-ui.md](generative-ui.md#rendering-it-somewhere-else-json-render), with the measured caveat
|
|
218
|
+
that its own `validate` lets any props through once a catalog holds more than one component, so each
|
|
219
|
+
node still wants checking against its own schema.
|
|
220
|
+
|
|
221
|
+
## What is verified, and how
|
|
222
|
+
|
|
223
|
+
Every runtime named here is a devDependency of this repository, and `src/interop.test.tsx` runs the
|
|
224
|
+
adapters against the published packages rather than against a memory of them:
|
|
225
|
+
|
|
226
|
+
| Claim | Checked against |
|
|
227
|
+
| ------------------------------------------------------------ | ------------------------------------------------ |
|
|
228
|
+
| `toGenerativeUi` emits their `GenerativeUISpec` | `@assistant-ui/core`'s own type |
|
|
229
|
+
| `fromGenerativeUi` reads their `GenerativeUINode` | the same |
|
|
230
|
+
| every member of their `ToolCallMessagePartStatus` union maps | the same |
|
|
231
|
+
| `a2uiCatalog` is a document their `createCatalog` accepts | `@copilotkit/a2ui-renderer`'s published function |
|
|
232
|
+
| a surface generated against it renders here | the fold and `a2uiToSpec`, end to end |
|
|
233
|
+
| the catalog is one json-render accepts, and validates a spec | `@json-render/react`, in `src/catalog.test.tsx` |
|
|
234
|
+
|
|
235
|
+
The two cases A2UI's own conformance suite keeps for a message processor — that an update lands on the
|
|
236
|
+
surface it names and nowhere else, and that each surface owns its data model — are in
|
|
237
|
+
`src/utils/interop/a2uiInterop.test.ts` in the vocabulary that suite uses.
|
package/docs/mcp.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# @box-kite/mcp
|
|
2
|
+
|
|
3
|
+
The [Box Kite](https://www.box-kite.dev) MCP server: the retrieval channel for an agent writing Box
|
|
4
|
+
Kite code. Six tools, at capability level — what may I write, what does this component take, and the
|
|
5
|
+
one no documentation mirror can answer: **does this value actually work.**
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @box-kite/mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
No key, no network, no state. Everything it answers with was built into it from the library's own
|
|
12
|
+
repository at the version you install, including the styling engine itself.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
**Claude Code**
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
claude mcp add box-kite -- npx -y @box-kite/mcp
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Cursor, VS Code, Codex, Zed** — anything that speaks stdio:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"mcpServers": {
|
|
27
|
+
"box-kite": { "command": "npx", "args": ["-y", "@box-kite/mcp"] }
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## The tools
|
|
33
|
+
|
|
34
|
+
| tool | what it answers |
|
|
35
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
36
|
+
| `search_docs` | The prop, component, nesting key or rule for what you are trying to build — ranked across all four, so a goal finds the answer without its name. |
|
|
37
|
+
| `get_props` | A style prop's whole record: the CSS it writes, every value it accepts, a measured example, and for a numeric prop its scale measured at 1/2/4/8. |
|
|
38
|
+
| `get_component` | One component's contract: props and defaults, sub-parts, the keyboard map and the ARIA it writes. |
|
|
39
|
+
| `check_styles` | A prop bag through the real engine: the CSS each prop writes, or why it wrote none. |
|
|
40
|
+
| `get_rules` | The rules the library is written by, as an index or in full. |
|
|
41
|
+
| `get_blocks` | Whole sections the `shadcn` CLI installs — a data-grid page, a settings form, a dashboard shell. |
|
|
42
|
+
|
|
43
|
+
## Why `check_styles` exists
|
|
44
|
+
|
|
45
|
+
Box Kite accepts a closed set of values per prop, and **a value it does not accept produces no rule
|
|
46
|
+
and no class name** — silently, by design, because a typo must not emit a broken declaration. That is
|
|
47
|
+
the right behaviour and it is invisible, so the only honest way to answer "does `bgColor="blue-550"`
|
|
48
|
+
work" is to hand it to the engine:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
check_styles { "props": { "p": 4, "bgColor": "blue-550", "fontSize": 14, "href": "/about" } }
|
|
52
|
+
|
|
53
|
+
✅ `p` → `.p-4{padding:1rem}`
|
|
54
|
+
❌ `bgColor` does not accept "blue-550" — no rule and no class name were written.
|
|
55
|
+
✅ `fontSize` → `.fontSize-14{font-size:0.875rem}`
|
|
56
|
+
⚠️ `href` an HTML attribute, not a style prop. It goes in `props={{ "href": … }}`.
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The dividers differ per prop — spacing is ÷4, `fontSize` is ÷16, border width is direct px — which is
|
|
60
|
+
why `get_props` measures a scale rather than describing one.
|
|
61
|
+
|
|
62
|
+
## What else the library ships for agents
|
|
63
|
+
|
|
64
|
+
- `AGENTS.md` and `docs/` inside the published `@box-kite/react` package
|
|
65
|
+
- The skill and rules file: `npx skills add box-kite/box-kite`
|
|
66
|
+
- Every documentation page as markdown at `https://www.box-kite.dev/<route>.md`, indexed by
|
|
67
|
+
[llms.txt](https://www.box-kite.dev/llms.txt)
|
|
68
|
+
|
|
69
|
+
MIT © Box Kite
|
package/docs/props.md
CHANGED
|
@@ -282,7 +282,7 @@ The border-left-width CSS property sets the width of the left border of an eleme
|
|
|
282
282
|
|
|
283
283
|
### `blur`
|
|
284
284
|
|
|
285
|
-
How far the element's own pixels are blurred: a step of
|
|
285
|
+
How far the element's own pixels are blurred: a step of the named scale (`xs` 4px through `xxxl` 64px) or a radius in px. One of nine functions that compose into a single `filter`, so a blur and a `brightness` coexist; `none` clears this one and leaves the rest.
|
|
286
286
|
|
|
287
287
|
- Writes: `--boxBlur`, `filter`
|
|
288
288
|
- Values: `xs` · `sm` · `md` · `lg` · `xl` · `xxl` · `xxxl` · `none`, a number
|
|
@@ -1386,7 +1386,7 @@ A hard-edged shadow outside the border box, in px — `ring={2}`. Unlike `outlin
|
|
|
1386
1386
|
|
|
1387
1387
|
### `ringColor`
|
|
1388
1388
|
|
|
1389
|
-
What colour `ring` draws in. `currentColor` otherwise
|
|
1389
|
+
What colour `ring` draws in. `currentColor` otherwise.
|
|
1390
1390
|
|
|
1391
1391
|
- Writes: `--boxRingColor`
|
|
1392
1392
|
- Values: 304 named values, anything else the types allow
|
|
@@ -1474,7 +1474,7 @@ How far the element is pushed towards sepia, as a percentage.
|
|
|
1474
1474
|
|
|
1475
1475
|
### `shadow`
|
|
1476
1476
|
|
|
1477
|
-
The elevation of the box: `xxs` through `xxl` on
|
|
1477
|
+
The elevation of the box: `xxs` through `xxl` on the elevation scale, or one of the three original presets (`small`, `medium`, `large`, which carry their own colour). `shadowColor` recolours the scale, and the shadow stacks with `ring`, `insetRing` and `insetShadow` rather than replacing them.
|
|
1478
1478
|
|
|
1479
1479
|
- Writes: `--boxShadow`, `box-shadow`
|
|
1480
1480
|
- Values: `xxs` · `xs` · `sm` · `md` · `lg` · `xl` · `xxl` · `none` · `small` · `medium` · `large`
|
package/interop.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./specDefs.cjs"),t=require("./specData.cjs");var n;(function(e){let t={"input-streaming":`pending`,"input-available":`running`,"output-available":`success`,"output-error":`error`,"approval-requested":`approval`,"approval-responded":`approval`},n={inProgress:`pending`,executing:`running`,complete:`success`},r={running:`running`,complete:`success`,incomplete:`error`,"requires-action":`pending`};function i(e){return typeof e==`object`&&e&&!Array.isArray(e)?e:null}function a(e){return typeof e==`string`&&e!==``?e:void 0}function o(e){return e.input??e.args??e.argsText}function s(e){return e.output??e.result}function c(e){let c=i(e);if(c===null)return null;let l=o(c),u=s(c),d=a(c.state);if(d!==void 0&&d in t){let e=t[d];if(e!==`approval`)return{kind:`call`,status:e,decision:null,input:l,output:u,error:a(c.errorText)};let n=i(c.approval)?.approved;return{kind:`approval`,status:`pending`,decision:typeof n==`boolean`?n?`approved`:`rejected`:null,input:l}}let f=c.status,p=i(f);if(p!==null){let e=a(p.type)??``;return{kind:e===`requires-action`?`approval`:`call`,status:r[e]??`pending`,decision:null,input:l,output:u,error:a(i(p.error)?.message)??a(p.error)}}let m=a(f);if(m!==void 0&&m in n){let e=typeof c.respond==`function`&&m===`executing`;return{kind:e?`approval`:`call`,status:e?`pending`:n[m],decision:null,input:l,output:u}}return null}e.toolPart=c;function l(e,t){let n=i(t),r=a(n?.toolCallId);if(n===null||r===void 0)return e;let o=a(n.type),s=e[r]??{kind:`call`,status:`pending`,decision:null};return o===`TOOL_CALL_START`?{...e,[r]:{...s,kind:`call`,status:`pending`}}:o===`TOOL_CALL_ARGS`?{...e,[r]:{...s,status:`pending`}}:o===`TOOL_CALL_END`?{...e,[r]:{...s,status:`running`}}:o===`TOOL_CALL_RESULT`?{...e,[r]:{...s,status:`success`,output:n.content??n.result}}:o===`INTERRUPT`||o===`RUN_INTERRUPT`?{...e,[r]:{...s,kind:`approval`,status:`pending`}}:o===`RUN_ERROR`?{...e,[r]:{...s,status:`error`,error:a(n.message)}}:e}e.applyEvent=l})(n||={});var r=n,i;(function(t){let n=t.ROOT_ID=`root`,r=t.DEFAULT_SURFACE=`main`;t.EMPTY={surfaces:{},order:[]};function i(e){return typeof e==`object`&&e&&!Array.isArray(e)?e:null}function a(e){return typeof e==`string`&&e!==``?e:void 0}function o(e){return{id:e,components:{},data:{}}}function s(e,t,n){return{surfaces:{...e.surfaces,[t]:n},order:e.order.includes(t)?e.order:[...e.order,t]}}function c(e){let t=i(e),n=a(t?.id);if(t===null||n===void 0)return null;let r=t.component;if(typeof r==`string`){let{id:e,component:i,...a}=t;return{id:n,component:r,...a}}let o=i(r),[s]=o?Object.keys(o):[];return o===null||s===void 0?null:{id:n,component:s,...i(o[s])??{}}}function l(e){return e.replace(/~1/g,`/`).replace(/~0/g,`~`)}function u(e){return e===void 0||e===``||e===`/`?[]:(e.startsWith(`/`)?e.slice(1):e).split(`/`).map(l)}function d(e,t){return t.reduce((e,t)=>i(e)?.[t],e)}function f(e,t,n){if(t.length===0)return n;let[r,...a]=t,o=i(e)??{};if(a.length>0)return{...o,[r]:f(o[r],a,n)};if(n!==void 0)return{...o,[r]:n};let{[r]:s,...c}=o;return c}function p(e){if(!Array.isArray(e))return{};let t={};for(let n of e){let e=i(n),r=a(e?.key);e!==null&&r!==void 0&&(`valueString`in e?t[r]=e.valueString:`valueNumber`in e?t[r]=e.valueNumber:`valueBoolean`in e?t[r]=e.valueBoolean:`valueMap`in e&&(t[r]=p(e.valueMap)))}return t}function m(e,t){let n=i(t);if(n===null)return e;let l=i(n.createSurface)??i(n.beginRendering);if(l!==null){let t=a(l.surfaceId)??r,n=e.surfaces[t]??o(t);return s(e,t,{...n,catalogId:a(l.catalogId)??n.catalogId,root:a(l.root)??n.root,theme:i(l.theme)??i(l.styles)??n.theme})}let m=i(n.updateComponents)??i(n.surfaceUpdate);if(m!==null){let t=a(m.surfaceId)??r,n=e.surfaces[t]??o(t),i={...n.components},l=!1;for(let e of Array.isArray(m.components)?m.components:[]){let t=c(e);t!==null&&(i[t.id]=t,l=!0)}return l||!e.surfaces[t]?s(e,t,{...n,components:i}):e}let h=i(n.updateDataModel)??i(n.dataModelUpdate);if(h!==null){let t=a(h.surfaceId)??r,n=e.surfaces[t]??o(t),c=u(a(h.path)),l=`contents`in h?{...i(d(n.data,c))??{},...p(h.contents)}:void 0,m=f(n.data,c,l??h.value);return s(e,t,{...n,data:i(m)??{}})}let g=i(n.deleteSurface);if(g!==null){let t=a(g.surfaceId)??r;if(!e.surfaces[t])return e;let{[t]:n,...i}=e.surfaces;return{surfaces:i,order:e.order.filter(e=>e!==t)}}return e}t.apply=m;function h(e,t){return t.reduce(m,e)}t.applyAll=h;function g(e,t){return t===void 0?e.surfaces[e.order[0]]??null:e.surfaces[t]??null}t.surface=g;function _(e){let t=i(e);return t===null?e:`literalString`in t?t.literalString:`literalNumber`in t?t.literalNumber:`literalBoolean`in t?t.literalBoolean:typeof t.path==`string`?{$data:t.path}:e}function v(e){let t=i(e);return t===null?a(e):a(i(t.event)?.name)??a(t.name)}function y(e){let t=a(e.child);if(t!==void 0)return{ids:[t]};let n=e.children;if(Array.isArray(n))return{ids:n.filter(e=>typeof e==`string`)};let r=i(n);if(r===null)return{ids:[]};if(Array.isArray(r.explicitList))return{ids:r.explicitList.filter(e=>typeof e==`string`)};let o=i(r.template)??r,s=a(o.componentId),c=a(o.path)??a(o.dataBinding);return s!==void 0&&c!==void 0?{ids:[],template:{componentId:s,path:c}}:{ids:[]}}let b=new Set([`id`,`component`,`child`,`children`,`action`]);function x(e,t,n,r,i){let a=e.components[t];if(a===void 0||i>32||r.has(t))return null;let o=new Set(n.catalog?.components[a.component]?.events??[]),s={},c={};for(let[e,t]of Object.entries(a)){if(b.has(e))continue;if(!o.has(e)){s[e]=_(t);continue}let n=v(t);n!==void 0&&(c[e]=n)}let l=v(a.action);l!==void 0&&(c.action=l);let{ids:u,template:d}=y(a),f=new Set([...r,t]),p=[];for(let t of u){let r=x(e,t,n,f,i+1);r!==null&&p.push(r)}if(d!==void 0){let t=x(e,d.componentId,n,f,i+1);t!==null&&p.push({...t,repeat:{$data:d.path}})}return{type:a.component,key:t,...Object.keys(s).length?{props:s}:{},...p.length?{children:p}:{},...Object.keys(c).length?{on:c}:{}}}function S(e,t={}){return e===null?null:x(e,t.root??e.root??n,t,new Set,0)}t.toSpec=S;let C={type:`array`,items:{type:`string`},description:`The ids of this component’s children, each a component of its own in the same surface.`},w={type:`string`,description:`The name of an action the host handles.`};function T(e,t){let n=i(i(e.components)?.[t]);if(n===null)return null;let r=i(e.$defs);return r===null?n:{...n,$defs:r}}t.componentSchema=T;function E(t,n={}){let r=n.catalogId??`urn:box-kite:catalog:${t.version}`,i={},a={};for(let[n,r]of Object.entries(t.components)){let t=e.t.hoist(r.props,i);a[n]={type:`object`,description:r.description,properties:{id:{type:`string`,description:`This component’s id, unique within the surface.`},component:{type:`string`,enum:[n]},...t.properties??{},...Object.fromEntries(r.events.map(e=>[e,w])),...r.slots.length?{children:C}:{}},required:[`id`,`component`,...t.required??[]],additionalProperties:!1}}return{$schema:`https://json-schema.org/draft/2020-12/schema`,$id:r,catalogId:r,title:n.title??`${t.library} catalog`,description:n.description??t.rules.join(` `),...Object.keys(i).length?{$defs:i}:{},components:a}}t.catalogDocument=E})(i||={});var a=i,o;(function(e){function n(e,t){if(typeof e==`string`)return e;if(t>32||typeof e!=`object`||!e||typeof e.component!=`string`)return null;let r=(e.children??[]).map(e=>n(e,t+1)).filter(e=>e!==null);return{type:e.component,...e.key===void 0?{}:{key:e.key},...e.props?{props:e.props}:{},...r.length?{children:r}:{}}}function r(e){return e==null?[]:(Array.isArray(e.root)?e.root:[e.root]).map(e=>n(e,0)).filter(e=>typeof e==`object`&&!!e)}e.toSpec=r;function i(e,n,r,a){if(e==null)return null;if(typeof e==`string`)return e;if(typeof e==`number`||typeof e==`boolean`)return String(e);if(t.t.isRef(e))return r.push({code:`data-binding`,path:n}),null;if(a>32||typeof e.type!=`string`)return null;let o=e;if(o.repeat&&r.push({code:`repeat`,path:n}),o.on)for(let e of Object.keys(o.on))r.push({code:`event`,path:`${n}.on.${e}`});let s=(o.children===void 0?[]:Array.isArray(o.children)?o.children:[o.children]).map((e,t)=>i(e,`${n}.children.${t}`,r,a+1)).filter(e=>e!==null);return{component:o.type,...o.key===void 0?{}:{key:o.key},...o.props?{props:o.props}:{},...s.length?{children:s}:{}}}function a(e){let t=[];return{spec:{root:(Array.isArray(e)?e:[e]).map((e,n)=>i(e,`root.${n}`,t,0)).filter(e=>e!==null)},losses:t}}e.fromSpec=a})(o||={});var s=o,c=r.toolPart,l=r.applyEvent,u=a.apply,d=a.applyAll,f=a.surface,p=a.toSpec,m=a.catalogDocument,h=a.componentSchema,g=a.EMPTY,_=s.toSpec,v=s.fromSpec;exports.A2uiInterop=a,exports.AssistantUiInterop=s,exports.ToolInterop=r,exports.a2uiApply=u,exports.a2uiApplyAll=d,exports.a2uiCatalog=m,exports.a2uiComponentSchema=h,exports.a2uiEmpty=g,exports.a2uiSurface=f,exports.a2uiToSpec=p,exports.applyToolEvent=l,exports.fromGenerativeUi=_,exports.toGenerativeUi=v,exports.toolPart=c;
|
package/interop.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { default as A2uiInterop } from './utils/interop/a2uiInterop';
|
|
2
|
+
import { default as AssistantUiInterop } from './utils/interop/assistantUiInterop';
|
|
3
|
+
import { default as ToolInterop } from './utils/interop/toolInterop';
|
|
4
|
+
/**
|
|
5
|
+
* `@box-kite/react/interop` — the agentic runtimes, in this library's shapes.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { toolPart, a2uiSurface, a2uiToSpec } from '@box-kite/react/interop';
|
|
9
|
+
*
|
|
10
|
+
* const part = toolPart(message); // AI SDK, assistant-ui or CopilotKit
|
|
11
|
+
* const spec = a2uiToSpec(a2uiSurface(state), { catalog }); // an A2UI stream, as a <SpecRenderer> tree
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Four runtimes generate UI and ask for permission, and every one of them describes the same two things
|
|
15
|
+
* — a tool call, and a tree of components — in words of its own. What ships here is the half this
|
|
16
|
+
* library owns: the mapping, framework-free, with no dependency on any of them. An adapter that pulled
|
|
17
|
+
* in a runtime would be choosing it for the app, and the app has already chosen.
|
|
18
|
+
*
|
|
19
|
+
* Its own entry, and it carries neither the engine nor React: a route handler building an agent's
|
|
20
|
+
* catalog and a client folding its messages both import from here, and neither pays for the other.
|
|
21
|
+
*
|
|
22
|
+
* `docs/interop.md` has the recipe per runtime, json-render and AG-UI included.
|
|
23
|
+
*/
|
|
24
|
+
export { default as ToolInterop } from './utils/interop/toolInterop';
|
|
25
|
+
export type { ToolPart, ToolPartKind } from './utils/interop/toolInterop';
|
|
26
|
+
export { default as A2uiInterop } from './utils/interop/a2uiInterop';
|
|
27
|
+
export type { A2uiCatalogOptions, A2uiComponent, A2uiSpecOptions, A2uiState, A2uiSurface } from './utils/interop/a2uiInterop';
|
|
28
|
+
export { default as AssistantUiInterop } from './utils/interop/assistantUiInterop';
|
|
29
|
+
export type { GenerativeUiLoss, GenerativeUiNode, GenerativeUiSpec } from './utils/interop/assistantUiInterop';
|
|
30
|
+
export type { ApprovalDecision, ToolCallStatus } from './utils/agent/agentUtils';
|
|
31
|
+
export type { SpecNode } from './utils/spec/specTypes';
|
|
32
|
+
/** Where a tool call is, from whichever of the three runtimes handed you the part. */
|
|
33
|
+
export declare const toolPart: typeof ToolInterop.toolPart;
|
|
34
|
+
/** AG-UI reports events rather than parts, so its cards are a fold: one call per event, oldest first. */
|
|
35
|
+
export declare const applyToolEvent: typeof ToolInterop.applyEvent;
|
|
36
|
+
/** One A2UI message folded into the surfaces it names. Pure, and the same state back when nothing moved. */
|
|
37
|
+
export declare const a2uiApply: typeof A2uiInterop.apply;
|
|
38
|
+
export declare const a2uiApplyAll: typeof A2uiInterop.applyAll;
|
|
39
|
+
/** A surface by id, or the first one the agent opened. */
|
|
40
|
+
export declare const a2uiSurface: typeof A2uiInterop.surface;
|
|
41
|
+
/** A surface's adjacency list as one `<SpecRenderer>` tree. */
|
|
42
|
+
export declare const a2uiToSpec: typeof A2uiInterop.toSpec;
|
|
43
|
+
/** `catalog()` as an A2UI catalog document — what an agent generates against. */
|
|
44
|
+
export declare const a2uiCatalog: typeof A2uiInterop.catalogDocument;
|
|
45
|
+
/** One component of that document, self-contained: a `$ref` resolves against the document, not the part. */
|
|
46
|
+
export declare const a2uiComponentSchema: typeof A2uiInterop.componentSchema;
|
|
47
|
+
/** The state an A2UI fold starts from. */
|
|
48
|
+
export declare const a2uiEmpty: import('./interop').A2uiState;
|
|
49
|
+
/** assistant-ui's generative-UI spec as ours, and back. */
|
|
50
|
+
export declare const fromGenerativeUi: typeof AssistantUiInterop.toSpec;
|
|
51
|
+
export declare const toGenerativeUi: typeof AssistantUiInterop.fromSpec;
|