@agent-native/core 0.79.19 → 0.79.21
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +13 -0
- package/corpus/core/docs/content/deployment.md +133 -0
- package/corpus/core/docs/content/multi-app-workspace.md +2 -0
- package/corpus/core/package.json +2 -1
- package/corpus/templates/analytics/app/components/layout/MobileNav.tsx +5 -10
- package/corpus/templates/analytics/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +5 -0
- package/corpus/templates/assets/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/assets/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +5 -0
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +20 -4
- package/corpus/templates/clips/app/hooks/use-desktop-promo.ts +6 -2
- package/corpus/templates/clips/changelog/2026-06-27-clips-no-longer-shows-desktop-app-prompts-on-mobile-screens.md +5 -0
- package/corpus/templates/clips/changelog/2026-06-27-desktop-storage-setup-flow.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-27-recorder-setup-mobile-capture-options.md +5 -0
- package/corpus/templates/clips/desktop/src/app.tsx +32 -3
- package/corpus/templates/clips/desktop/src/styles.css +67 -0
- package/corpus/templates/design/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/design/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +5 -0
- package/corpus/templates/slides/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/slides/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +5 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/docs/content/deployment.md +133 -0
- package/docs/content/multi-app-workspace.md +2 -0
- package/package.json +2 -1
package/corpus/README.md
CHANGED
package/corpus/core/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @agent-native/core
|
|
2
2
|
|
|
3
|
+
## 0.79.21
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 3acd677: Clarify workspace Docker Compose deployment for self-hosted VPS installs.
|
|
8
|
+
|
|
9
|
+
## 0.79.20
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 8bcc21d: Declare the Sentry OpenTelemetry trace dependency directly so the published CLI installs reliably through npx.
|
|
14
|
+
- 8bcc21d: Use a compact popover for the shared language picker so icon-only chrome can style it reliably.
|
|
15
|
+
|
|
3
16
|
## 0.79.19
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
|
@@ -66,6 +66,139 @@ background processors. Local `--build-only` artifact checks still run without it
|
|
|
66
66
|
|
|
67
67
|
Per-app independent deploy is still supported — just `cd apps/<name> && npx @agent-native/core@latest build` like a standalone scaffold.
|
|
68
68
|
|
|
69
|
+
### Self-hosted workspace with Docker Compose {#workspace-docker-compose}
|
|
70
|
+
|
|
71
|
+
The Dockerfile above is for one standalone app. A workspace is not one Nitro
|
|
72
|
+
server process today: each app still builds to its own `.output/` directory and
|
|
73
|
+
runs its own Node/Nitro server. For a VPS, run one container per workspace app,
|
|
74
|
+
point every app at the same Postgres database and shared production secrets, and
|
|
75
|
+
put a reverse proxy in front that routes path prefixes (`/mail`, `/calendar`,
|
|
76
|
+
...) to the matching app container.
|
|
77
|
+
|
|
78
|
+
Build each app with the same base path that the proxy will use at runtime. The
|
|
79
|
+
base path is a build-time input for the client bundle and a runtime input for
|
|
80
|
+
the server:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
APP_BASE_PATH=/mail VITE_APP_BASE_PATH=/mail npx @agent-native/core@latest build
|
|
84
|
+
node .output/server/index.mjs
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
A reusable workspace Dockerfile can take the app name and path prefix as build
|
|
88
|
+
arguments:
|
|
89
|
+
|
|
90
|
+
```dockerfile
|
|
91
|
+
FROM node:24-slim AS build
|
|
92
|
+
WORKDIR /workspace
|
|
93
|
+
RUN corepack enable
|
|
94
|
+
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
|
95
|
+
COPY packages ./packages
|
|
96
|
+
COPY apps ./apps
|
|
97
|
+
ARG APP_NAME
|
|
98
|
+
ARG APP_BASE_PATH
|
|
99
|
+
ENV APP_BASE_PATH=$APP_BASE_PATH
|
|
100
|
+
ENV VITE_APP_BASE_PATH=$APP_BASE_PATH
|
|
101
|
+
RUN pnpm install --frozen-lockfile
|
|
102
|
+
RUN pnpm --dir apps/$APP_NAME build
|
|
103
|
+
|
|
104
|
+
FROM node:24-slim
|
|
105
|
+
WORKDIR /app
|
|
106
|
+
ARG APP_NAME
|
|
107
|
+
ARG APP_BASE_PATH
|
|
108
|
+
ENV NODE_ENV=production
|
|
109
|
+
ENV PORT=3000
|
|
110
|
+
ENV APP_BASE_PATH=$APP_BASE_PATH
|
|
111
|
+
COPY --from=build /workspace/apps/$APP_NAME/.output .output
|
|
112
|
+
EXPOSE 3000
|
|
113
|
+
CMD ["node", ".output/server/index.mjs"]
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Then compose Postgres, the app containers, and your proxy. This example uses
|
|
117
|
+
Caddy because it can terminate HTTP locally or sit behind Cloudflare's SSL
|
|
118
|
+
proxy, but the important part is the path-prefix routing:
|
|
119
|
+
|
|
120
|
+
```yaml
|
|
121
|
+
services:
|
|
122
|
+
postgres:
|
|
123
|
+
image: postgres:17
|
|
124
|
+
restart: unless-stopped
|
|
125
|
+
environment:
|
|
126
|
+
POSTGRES_DB: agent_native
|
|
127
|
+
POSTGRES_USER: agent_native
|
|
128
|
+
POSTGRES_PASSWORD: change-me
|
|
129
|
+
volumes:
|
|
130
|
+
- postgres-data:/var/lib/postgresql/data
|
|
131
|
+
|
|
132
|
+
mail:
|
|
133
|
+
build:
|
|
134
|
+
context: .
|
|
135
|
+
dockerfile: Dockerfile.workspace-app
|
|
136
|
+
args:
|
|
137
|
+
APP_NAME: mail
|
|
138
|
+
APP_BASE_PATH: /mail
|
|
139
|
+
restart: unless-stopped
|
|
140
|
+
environment:
|
|
141
|
+
DATABASE_URL: postgres://agent_native:change-me@postgres:5432/agent_native
|
|
142
|
+
BETTER_AUTH_URL: https://agents.example.com/mail
|
|
143
|
+
BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET}
|
|
144
|
+
A2A_SECRET: ${A2A_SECRET}
|
|
145
|
+
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
|
146
|
+
depends_on:
|
|
147
|
+
- postgres
|
|
148
|
+
|
|
149
|
+
calendar:
|
|
150
|
+
build:
|
|
151
|
+
context: .
|
|
152
|
+
dockerfile: Dockerfile.workspace-app
|
|
153
|
+
args:
|
|
154
|
+
APP_NAME: calendar
|
|
155
|
+
APP_BASE_PATH: /calendar
|
|
156
|
+
restart: unless-stopped
|
|
157
|
+
environment:
|
|
158
|
+
DATABASE_URL: postgres://agent_native:change-me@postgres:5432/agent_native
|
|
159
|
+
BETTER_AUTH_URL: https://agents.example.com/calendar
|
|
160
|
+
BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET}
|
|
161
|
+
A2A_SECRET: ${A2A_SECRET}
|
|
162
|
+
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
|
163
|
+
depends_on:
|
|
164
|
+
- postgres
|
|
165
|
+
|
|
166
|
+
proxy:
|
|
167
|
+
image: caddy:2
|
|
168
|
+
restart: unless-stopped
|
|
169
|
+
ports:
|
|
170
|
+
- "80:80"
|
|
171
|
+
- "443:443"
|
|
172
|
+
volumes:
|
|
173
|
+
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
|
174
|
+
depends_on:
|
|
175
|
+
- mail
|
|
176
|
+
- calendar
|
|
177
|
+
|
|
178
|
+
volumes:
|
|
179
|
+
postgres-data:
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```caddyfile
|
|
183
|
+
agents.example.com {
|
|
184
|
+
reverse_proxy /mail* mail:3000
|
|
185
|
+
reverse_proxy /calendar* calendar:3000
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Notes for this shape:
|
|
190
|
+
|
|
191
|
+
- Keep `DATABASE_URL`, `BETTER_AUTH_SECRET`, `A2A_SECRET`, and other production
|
|
192
|
+
secrets identical across app containers when you want shared auth, shared
|
|
193
|
+
credentials, and cross-app A2A.
|
|
194
|
+
- Set `BETTER_AUTH_URL` to the public URL for that app path. OAuth callback URLs
|
|
195
|
+
should use the same public URL.
|
|
196
|
+
- Do not rely on the container filesystem for production data; use Postgres (or
|
|
197
|
+
another persistent SQL backend) for `DATABASE_URL`.
|
|
198
|
+
- If Cloudflare terminates TLS in front of the VPS, configure Cloudflare to send
|
|
199
|
+
normal `X-Forwarded-Proto` / `X-Forwarded-Host` headers and route the public
|
|
200
|
+
host to the proxy container.
|
|
201
|
+
|
|
69
202
|
## How It Works {#how-it-works}
|
|
70
203
|
|
|
71
204
|
When you run `npx @agent-native/core@latest build`, Nitro builds both the client SPA and the server API into `.output/`:
|
|
@@ -289,6 +289,8 @@ These settings only affect read-only page navigation. Framework tools, agent cha
|
|
|
289
289
|
|
|
290
290
|
Prefer each app on its own domain (`mail.company.com`, `calendar.company.com`)? Every app in the workspace is still an independent deployable — `cd apps/mail && npx @agent-native/core@latest build` behaves exactly like a standalone scaffold. Cross-app A2A then goes through the standard JWT-signed path with a shared `A2A_SECRET`. Cross-domain SSO between separately-deployed apps is handled by identity federation with Dispatch as the hub — see [Cross-App SSO](/docs/cross-app-sso); the unified single-origin deploy avoids needing it.
|
|
291
291
|
|
|
292
|
+
For a self-hosted VPS or Docker Compose setup on one origin, build and run one container per app with its own path prefix (`APP_BASE_PATH=/mail`, `APP_BASE_PATH=/calendar`, ...), then route those prefixes through a reverse proxy. See [Deployment — Self-hosted workspace with Docker Compose](/docs/deployment#workspace-docker-compose) for the Dockerfile and compose example.
|
|
293
|
+
|
|
292
294
|
### Shared database, shared credentials
|
|
293
295
|
|
|
294
296
|
Whatever you pick, point every app at the same `DATABASE_URL` for cross-app state out of the box: one set of user accounts, one set of organizations, one set of shared settings. If each app has its own database, the workspace pattern still works — you just lose that shared-state story.
|
package/corpus/core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.79.
|
|
3
|
+
"version": "0.79.21",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -204,6 +204,7 @@
|
|
|
204
204
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
205
205
|
"@mozilla/readability": "0.6.0",
|
|
206
206
|
"@neondatabase/serverless": "^1.1.0",
|
|
207
|
+
"@opentelemetry/sdk-trace-base": "^2.8.0",
|
|
207
208
|
"@radix-ui/react-dialog": "1.1.15",
|
|
208
209
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
209
210
|
"@radix-ui/react-hover-card": "^1.1.15",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useT } from "@agent-native/core/client";
|
|
2
|
-
import { IconMenu
|
|
2
|
+
import { IconMenu } from "@tabler/icons-react";
|
|
3
3
|
import { useState, useEffect } from "react";
|
|
4
4
|
import { useLocation } from "react-router";
|
|
5
5
|
|
|
@@ -18,7 +18,7 @@ export function MobileNav() {
|
|
|
18
18
|
}, [location.pathname]);
|
|
19
19
|
|
|
20
20
|
return (
|
|
21
|
-
<div className="flex h-12 shrink-0 items-center border-b border-border bg-
|
|
21
|
+
<div className="flex h-12 shrink-0 items-center border-b border-border bg-background px-4 md:hidden">
|
|
22
22
|
<button
|
|
23
23
|
onClick={() => setOpen(true)}
|
|
24
24
|
className="me-3 p-2.5 -ms-1 rounded-md hover:bg-sidebar-accent/50"
|
|
@@ -26,14 +26,9 @@ export function MobileNav() {
|
|
|
26
26
|
>
|
|
27
27
|
<IconMenu className="h-5 w-5 text-foreground" />
|
|
28
28
|
</button>
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
</div>
|
|
33
|
-
<span className="text-base font-bold tracking-tight">
|
|
34
|
-
{t("navigation.brand")}
|
|
35
|
-
</span>
|
|
36
|
-
</div>
|
|
29
|
+
<span className="text-base font-bold tracking-tight">
|
|
30
|
+
{t("navigation.brand")}
|
|
31
|
+
</span>
|
|
37
32
|
|
|
38
33
|
<Sheet open={open} onOpenChange={setOpen}>
|
|
39
34
|
<SheetContent side="left" className="p-0 w-[280px]">
|
|
@@ -87,7 +87,7 @@ export function Layout({ children }: LayoutProps) {
|
|
|
87
87
|
)}
|
|
88
88
|
<div
|
|
89
89
|
className={cn(
|
|
90
|
-
"agent-layout-left-drawer fixed inset-y-0 start-0 z-50 md:static md:z-auto",
|
|
90
|
+
"agent-layout-left-drawer fixed inset-y-0 start-0 z-50 transition-transform duration-200 ease-out md:static md:z-auto md:transition-none",
|
|
91
91
|
mobileSidebarOpen
|
|
92
92
|
? "translate-x-0"
|
|
93
93
|
: "-translate-x-full md:translate-x-0",
|
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
SelectValue,
|
|
42
42
|
} from "@/components/ui/select";
|
|
43
43
|
import { Switch } from "@/components/ui/switch";
|
|
44
|
+
import { useIsMobile } from "@/hooks/use-mobile";
|
|
44
45
|
import {
|
|
45
46
|
loadRecorderPreferences,
|
|
46
47
|
saveRecorderPreferences,
|
|
@@ -192,6 +193,7 @@ export function PreRecordPanel({
|
|
|
192
193
|
error: null,
|
|
193
194
|
hasPreview: false,
|
|
194
195
|
});
|
|
196
|
+
const isMobile = useIsMobile();
|
|
195
197
|
|
|
196
198
|
const modeOptions = useMemo<ModeOption[]>(
|
|
197
199
|
() => [
|
|
@@ -213,6 +215,14 @@ export function PreRecordPanel({
|
|
|
213
215
|
],
|
|
214
216
|
[t],
|
|
215
217
|
);
|
|
218
|
+
const visibleModeOptions = useMemo(
|
|
219
|
+
() =>
|
|
220
|
+
isMobile
|
|
221
|
+
? modeOptions.filter((option) => option.value === "camera")
|
|
222
|
+
: modeOptions,
|
|
223
|
+
[isMobile, modeOptions],
|
|
224
|
+
);
|
|
225
|
+
|
|
216
226
|
const surfaceOptions = useMemo<SurfaceOption[]>(
|
|
217
227
|
() => [
|
|
218
228
|
{
|
|
@@ -238,8 +248,14 @@ export function PreRecordPanel({
|
|
|
238
248
|
);
|
|
239
249
|
|
|
240
250
|
useEffect(() => {
|
|
251
|
+
if (isMobile) {
|
|
252
|
+
// Mobile browsers do not support the screen-capture choices this panel
|
|
253
|
+
// offers on desktop, so keep the setup focused on recording face video.
|
|
254
|
+
setMode("camera");
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
241
257
|
if (initialMode) setMode(initialMode);
|
|
242
|
-
}, [initialMode]);
|
|
258
|
+
}, [initialMode, isMobile]);
|
|
243
259
|
|
|
244
260
|
useEffect(() => {
|
|
245
261
|
if (initialDisplaySurface) setDisplaySurface(initialDisplaySurface);
|
|
@@ -586,7 +602,7 @@ export function PreRecordPanel({
|
|
|
586
602
|
<div className="mx-auto w-full max-w-lg overflow-hidden rounded-2xl border border-border bg-card shadow-lg">
|
|
587
603
|
<div className="p-6">
|
|
588
604
|
<div className="grid gap-2 sm:grid-cols-3">
|
|
589
|
-
{
|
|
605
|
+
{visibleModeOptions.map((opt) => {
|
|
590
606
|
const Icon = opt.icon;
|
|
591
607
|
const active = opt.value === mode;
|
|
592
608
|
return (
|
|
@@ -600,7 +616,7 @@ export function PreRecordPanel({
|
|
|
600
616
|
className={cn(
|
|
601
617
|
"flex min-h-20 min-w-0 flex-col justify-between rounded-xl border p-3 text-start transition-colors",
|
|
602
618
|
active
|
|
603
|
-
? "border-primary bg-primary text-
|
|
619
|
+
? "border-primary/55 bg-primary/[0.12] text-foreground shadow-sm ring-1 ring-primary/15"
|
|
604
620
|
: "border-border bg-background text-foreground hover:border-foreground/30 hover:bg-muted/45",
|
|
605
621
|
)}
|
|
606
622
|
aria-pressed={active}
|
|
@@ -609,7 +625,7 @@ export function PreRecordPanel({
|
|
|
609
625
|
className={cn(
|
|
610
626
|
"mb-3 flex h-9 w-9 items-center justify-center rounded-full",
|
|
611
627
|
active
|
|
612
|
-
? "bg-primary
|
|
628
|
+
? "bg-primary/[0.18] text-foreground"
|
|
613
629
|
: "bg-muted text-muted-foreground",
|
|
614
630
|
)}
|
|
615
631
|
>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { useCallback, useEffect, useState } from "react";
|
|
2
2
|
|
|
3
|
+
import { useIsMobile } from "@/hooks/use-mobile";
|
|
4
|
+
|
|
3
5
|
const DISMISSED_KEY = "clips.desktop-promo.dismissed";
|
|
4
6
|
|
|
5
7
|
function detectDesktopApp(): boolean {
|
|
@@ -17,6 +19,7 @@ function detectDesktopApp(): boolean {
|
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
export function useDesktopPromo() {
|
|
22
|
+
const isMobile = useIsMobile();
|
|
20
23
|
const [isDesktopApp, setIsDesktopApp] = useState(false);
|
|
21
24
|
const [dismissed, setDismissed] = useState(false);
|
|
22
25
|
|
|
@@ -40,8 +43,9 @@ export function useDesktopPromo() {
|
|
|
40
43
|
|
|
41
44
|
return {
|
|
42
45
|
isDesktopApp,
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
isMobile,
|
|
47
|
+
shouldShowPromo: !isMobile && !isDesktopApp && !dismissed,
|
|
48
|
+
shouldShowSidebarLink: !isMobile && !isDesktopApp,
|
|
45
49
|
dismiss,
|
|
46
50
|
};
|
|
47
51
|
}
|
|
@@ -1687,9 +1687,7 @@ export function App() {
|
|
|
1687
1687
|
const openVideoStorageSetup = useCallback(
|
|
1688
1688
|
(targetServerUrl?: string) => {
|
|
1689
1689
|
const base = (targetServerUrl?.trim() || serverUrl).replace(/\/+$/, "");
|
|
1690
|
-
setRecError(
|
|
1691
|
-
"Connect storage before recording from desktop: Builder.io (free tier storage + AI) or S3-compatible storage. Opening storage setup...",
|
|
1692
|
-
);
|
|
1690
|
+
setRecError(STORAGE_SETUP_HELP_TEXT);
|
|
1693
1691
|
void openExternal(`${base}/record`).catch((err) => {
|
|
1694
1692
|
setRecError(
|
|
1695
1693
|
err instanceof Error
|
|
@@ -1924,6 +1922,11 @@ export function App() {
|
|
|
1924
1922
|
setRecError(MACOS_CAPTURE_PERMISSION_MESSAGE);
|
|
1925
1923
|
return;
|
|
1926
1924
|
}
|
|
1925
|
+
if (isStorageSetupFailureMessage(message)) {
|
|
1926
|
+
setRecError(STORAGE_SETUP_HELP_TEXT);
|
|
1927
|
+
openVideoStorageSetup();
|
|
1928
|
+
return;
|
|
1929
|
+
}
|
|
1927
1930
|
setRecError(message);
|
|
1928
1931
|
}
|
|
1929
1932
|
|
|
@@ -2306,6 +2309,8 @@ export function App() {
|
|
|
2306
2309
|
panes={["speech", "microphone"]}
|
|
2307
2310
|
onRetry={handleStartRecording}
|
|
2308
2311
|
/>
|
|
2312
|
+
) : isStorageSetupFailureMessage(recError) ? (
|
|
2313
|
+
<StorageConnectionBanner onConnect={() => openVideoStorageSetup()} />
|
|
2309
2314
|
) : (
|
|
2310
2315
|
<div className="error-banner">{recError}</div>
|
|
2311
2316
|
)
|
|
@@ -2450,6 +2455,30 @@ function PermissionRecoveryBanner({
|
|
|
2450
2455
|
);
|
|
2451
2456
|
}
|
|
2452
2457
|
|
|
2458
|
+
function StorageConnectionBanner({ onConnect }: { onConnect: () => void }) {
|
|
2459
|
+
return (
|
|
2460
|
+
<div className="storage-flow-banner">
|
|
2461
|
+
<div className="storage-flow-icon" aria-hidden>
|
|
2462
|
+
<IconUpload size={17} stroke={1.8} />
|
|
2463
|
+
</div>
|
|
2464
|
+
<div className="storage-flow-copy">
|
|
2465
|
+
<div className="storage-flow-title">
|
|
2466
|
+
Connect storage to keep recording
|
|
2467
|
+
</div>
|
|
2468
|
+
<div className="storage-flow-sub">{STORAGE_SETUP_HELP_TEXT}</div>
|
|
2469
|
+
</div>
|
|
2470
|
+
<button
|
|
2471
|
+
type="button"
|
|
2472
|
+
className="storage-flow-connect"
|
|
2473
|
+
onClick={onConnect}
|
|
2474
|
+
>
|
|
2475
|
+
<IconExternalLink size={14} stroke={2} />
|
|
2476
|
+
Connect
|
|
2477
|
+
</button>
|
|
2478
|
+
</div>
|
|
2479
|
+
);
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2453
2482
|
function PendingUploadBanner({
|
|
2454
2483
|
uploads,
|
|
2455
2484
|
retryingUploadId,
|
|
@@ -1680,6 +1680,73 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
1680
1680
|
background: var(--surface-hover);
|
|
1681
1681
|
}
|
|
1682
1682
|
|
|
1683
|
+
.storage-flow-banner {
|
|
1684
|
+
display: grid;
|
|
1685
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
1686
|
+
align-items: start;
|
|
1687
|
+
gap: 10px;
|
|
1688
|
+
padding: 10px;
|
|
1689
|
+
border: 1px solid #bfdbfe;
|
|
1690
|
+
border-radius: var(--radius);
|
|
1691
|
+
background: #eff6ff;
|
|
1692
|
+
color: #1e3a8a;
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
.storage-flow-icon {
|
|
1696
|
+
width: 28px;
|
|
1697
|
+
height: 28px;
|
|
1698
|
+
display: inline-flex;
|
|
1699
|
+
align-items: center;
|
|
1700
|
+
justify-content: center;
|
|
1701
|
+
border-radius: 8px;
|
|
1702
|
+
background: rgba(59, 130, 246, 0.12);
|
|
1703
|
+
color: #1d4ed8;
|
|
1704
|
+
flex-shrink: 0;
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
.storage-flow-copy {
|
|
1708
|
+
min-width: 0;
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
.storage-flow-title {
|
|
1712
|
+
font-size: 12px;
|
|
1713
|
+
font-weight: 700;
|
|
1714
|
+
line-height: 1.25;
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
.storage-flow-sub {
|
|
1718
|
+
margin-top: 3px;
|
|
1719
|
+
color: #3b5f9a;
|
|
1720
|
+
font-size: 11px;
|
|
1721
|
+
line-height: 1.35;
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
.storage-flow-connect {
|
|
1725
|
+
grid-column: 2;
|
|
1726
|
+
justify-self: start;
|
|
1727
|
+
height: 28px;
|
|
1728
|
+
border: 1px solid #bfdbfe;
|
|
1729
|
+
border-radius: var(--radius-sm);
|
|
1730
|
+
background: white;
|
|
1731
|
+
color: #1d4ed8;
|
|
1732
|
+
cursor: pointer;
|
|
1733
|
+
display: inline-flex;
|
|
1734
|
+
align-items: center;
|
|
1735
|
+
justify-content: center;
|
|
1736
|
+
gap: 5px;
|
|
1737
|
+
padding: 0 9px;
|
|
1738
|
+
font-size: 11px;
|
|
1739
|
+
font-weight: 700;
|
|
1740
|
+
transition:
|
|
1741
|
+
background 120ms,
|
|
1742
|
+
border-color 120ms;
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
.storage-flow-connect:hover {
|
|
1746
|
+
background: #dbeafe;
|
|
1747
|
+
border-color: #93c5fd;
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1683
1750
|
.pending-upload-banner {
|
|
1684
1751
|
display: grid;
|
|
1685
1752
|
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
@@ -120,7 +120,7 @@ export function Layout({ children }: LayoutProps) {
|
|
|
120
120
|
)}
|
|
121
121
|
<div
|
|
122
122
|
className={cn(
|
|
123
|
-
"agent-layout-left-drawer fixed inset-y-0 start-0 z-50 md:static md:z-auto",
|
|
123
|
+
"agent-layout-left-drawer fixed inset-y-0 start-0 z-50 transition-transform duration-200 ease-out md:static md:z-auto md:transition-none",
|
|
124
124
|
mobileSidebarOpen
|
|
125
125
|
? "translate-x-0"
|
|
126
126
|
: "-translate-x-full rtl:translate-x-full md:translate-x-0 md:rtl:translate-x-0",
|
|
@@ -87,7 +87,7 @@ export function Layout({ children }: LayoutProps) {
|
|
|
87
87
|
)}
|
|
88
88
|
<div
|
|
89
89
|
className={cn(
|
|
90
|
-
"agent-layout-left-drawer fixed inset-y-0 start-0 z-50 md:static md:z-auto",
|
|
90
|
+
"agent-layout-left-drawer fixed inset-y-0 start-0 z-50 transition-transform duration-200 ease-out md:static md:z-auto md:transition-none",
|
|
91
91
|
sidebarOpen
|
|
92
92
|
? "translate-x-0"
|
|
93
93
|
: "-translate-x-full rtl:translate-x-full md:translate-x-0 md:rtl:translate-x-0",
|
|
@@ -49,11 +49,11 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
|
|
|
49
49
|
error: string;
|
|
50
50
|
states?: undefined;
|
|
51
51
|
} | {
|
|
52
|
+
error?: undefined;
|
|
52
53
|
states: {
|
|
53
54
|
clientId: number;
|
|
54
55
|
state: string;
|
|
55
56
|
}[];
|
|
56
|
-
error?: undefined;
|
|
57
57
|
}>>;
|
|
58
58
|
/**
|
|
59
59
|
* GET /_agent-native/collab/:docId/users
|
|
@@ -64,10 +64,10 @@ export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("
|
|
|
64
64
|
error: string;
|
|
65
65
|
users?: undefined;
|
|
66
66
|
} | {
|
|
67
|
+
error?: undefined;
|
|
67
68
|
users: {
|
|
68
69
|
clientId: number;
|
|
69
70
|
lastSeen: number;
|
|
70
71
|
}[];
|
|
71
|
-
error?: undefined;
|
|
72
72
|
}>>;
|
|
73
73
|
//# sourceMappingURL=awareness.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"awareness.d.ts","sourceRoot":"","sources":["../../src/collab/awareness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAS3C,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAOD,eAAO,MAAM,sBAAsB,EAAG,kBAA2B,CAAC;AAElE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,kBAAkB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,MAAM,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,wBAAgB,mBAAmB,IAAI,YAAY,CAElD;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EAClD,KAAK,CAAC,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,GACb,IAAI,CAUN;AAKD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAO1E;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,IAAI,CAOnE;AAUD;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa
|
|
1
|
+
{"version":3,"file":"awareness.d.ts","sourceRoot":"","sources":["../../src/collab/awareness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAS3C,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAOD,eAAO,MAAM,sBAAsB,EAAG,kBAA2B,CAAC;AAElE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,kBAAkB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,MAAM,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD,wBAAgB,mBAAmB,IAAI,YAAY,CAElD;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EAClD,KAAK,CAAC,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,GACb,IAAI,CAUN;AAKD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAO1E;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,IAAI,CAOnE;AAUD;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa;;;;;;kBAuCa,MAAM;eAAS,MAAM;;GAa1D,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,cAAc;;;;;;kBAWM,MAAM;kBAAY,MAAM;;GAMvD,CAAC"}
|
|
@@ -41,22 +41,22 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
41
41
|
thumbsUpRate: number;
|
|
42
42
|
avgEvalScore: number;
|
|
43
43
|
} | {
|
|
44
|
+
ok?: undefined;
|
|
44
45
|
summary: import("./types.js").TraceSummary;
|
|
45
46
|
spans: import("./types.js").TraceSpan[];
|
|
46
|
-
ok?: undefined;
|
|
47
47
|
error?: undefined;
|
|
48
48
|
id?: undefined;
|
|
49
49
|
} | {
|
|
50
|
+
ok?: undefined;
|
|
50
51
|
summary?: undefined;
|
|
51
52
|
spans?: undefined;
|
|
52
53
|
id: string;
|
|
53
|
-
ok?: undefined;
|
|
54
54
|
error?: undefined;
|
|
55
55
|
} | {
|
|
56
|
+
ok?: undefined;
|
|
56
57
|
summary?: undefined;
|
|
57
58
|
spans?: undefined;
|
|
58
59
|
error: any;
|
|
59
|
-
ok?: undefined;
|
|
60
60
|
id?: undefined;
|
|
61
61
|
} | {
|
|
62
62
|
summary?: undefined;
|
|
@@ -52,8 +52,8 @@ export declare function handleDeleteResource(event: any): Promise<{
|
|
|
52
52
|
error: string;
|
|
53
53
|
ok?: undefined;
|
|
54
54
|
} | {
|
|
55
|
-
ok: boolean;
|
|
56
55
|
error?: undefined;
|
|
56
|
+
ok: boolean;
|
|
57
57
|
}>;
|
|
58
58
|
/** POST /_agent-native/resources/upload — upload a file as a resource */
|
|
59
59
|
export declare function handleUploadResource(event: any): Promise<import("./store.js").Resource | {
|
|
@@ -73,9 +73,9 @@ export declare function handleUploadResource(event: any): Promise<import("./stor
|
|
|
73
73
|
runId: string | null;
|
|
74
74
|
expiresAt: number | null;
|
|
75
75
|
metadata: string | null;
|
|
76
|
+
error?: undefined;
|
|
76
77
|
url: string;
|
|
77
78
|
provider: string;
|
|
78
|
-
error?: undefined;
|
|
79
79
|
}>;
|
|
80
80
|
export {};
|
|
81
81
|
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -23,10 +23,10 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
|
|
|
23
23
|
error: string;
|
|
24
24
|
}>;
|
|
25
25
|
export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
26
|
+
ok?: undefined;
|
|
26
27
|
error: any;
|
|
27
28
|
key?: undefined;
|
|
28
29
|
scope?: undefined;
|
|
29
|
-
ok?: undefined;
|
|
30
30
|
} | {
|
|
31
31
|
ok: boolean;
|
|
32
32
|
key: string;
|
|
@@ -66,6 +66,139 @@ background processors. Local `--build-only` artifact checks still run without it
|
|
|
66
66
|
|
|
67
67
|
Per-app independent deploy is still supported — just `cd apps/<name> && npx @agent-native/core@latest build` like a standalone scaffold.
|
|
68
68
|
|
|
69
|
+
### Self-hosted workspace with Docker Compose {#workspace-docker-compose}
|
|
70
|
+
|
|
71
|
+
The Dockerfile above is for one standalone app. A workspace is not one Nitro
|
|
72
|
+
server process today: each app still builds to its own `.output/` directory and
|
|
73
|
+
runs its own Node/Nitro server. For a VPS, run one container per workspace app,
|
|
74
|
+
point every app at the same Postgres database and shared production secrets, and
|
|
75
|
+
put a reverse proxy in front that routes path prefixes (`/mail`, `/calendar`,
|
|
76
|
+
...) to the matching app container.
|
|
77
|
+
|
|
78
|
+
Build each app with the same base path that the proxy will use at runtime. The
|
|
79
|
+
base path is a build-time input for the client bundle and a runtime input for
|
|
80
|
+
the server:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
APP_BASE_PATH=/mail VITE_APP_BASE_PATH=/mail npx @agent-native/core@latest build
|
|
84
|
+
node .output/server/index.mjs
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
A reusable workspace Dockerfile can take the app name and path prefix as build
|
|
88
|
+
arguments:
|
|
89
|
+
|
|
90
|
+
```dockerfile
|
|
91
|
+
FROM node:24-slim AS build
|
|
92
|
+
WORKDIR /workspace
|
|
93
|
+
RUN corepack enable
|
|
94
|
+
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
|
95
|
+
COPY packages ./packages
|
|
96
|
+
COPY apps ./apps
|
|
97
|
+
ARG APP_NAME
|
|
98
|
+
ARG APP_BASE_PATH
|
|
99
|
+
ENV APP_BASE_PATH=$APP_BASE_PATH
|
|
100
|
+
ENV VITE_APP_BASE_PATH=$APP_BASE_PATH
|
|
101
|
+
RUN pnpm install --frozen-lockfile
|
|
102
|
+
RUN pnpm --dir apps/$APP_NAME build
|
|
103
|
+
|
|
104
|
+
FROM node:24-slim
|
|
105
|
+
WORKDIR /app
|
|
106
|
+
ARG APP_NAME
|
|
107
|
+
ARG APP_BASE_PATH
|
|
108
|
+
ENV NODE_ENV=production
|
|
109
|
+
ENV PORT=3000
|
|
110
|
+
ENV APP_BASE_PATH=$APP_BASE_PATH
|
|
111
|
+
COPY --from=build /workspace/apps/$APP_NAME/.output .output
|
|
112
|
+
EXPOSE 3000
|
|
113
|
+
CMD ["node", ".output/server/index.mjs"]
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Then compose Postgres, the app containers, and your proxy. This example uses
|
|
117
|
+
Caddy because it can terminate HTTP locally or sit behind Cloudflare's SSL
|
|
118
|
+
proxy, but the important part is the path-prefix routing:
|
|
119
|
+
|
|
120
|
+
```yaml
|
|
121
|
+
services:
|
|
122
|
+
postgres:
|
|
123
|
+
image: postgres:17
|
|
124
|
+
restart: unless-stopped
|
|
125
|
+
environment:
|
|
126
|
+
POSTGRES_DB: agent_native
|
|
127
|
+
POSTGRES_USER: agent_native
|
|
128
|
+
POSTGRES_PASSWORD: change-me
|
|
129
|
+
volumes:
|
|
130
|
+
- postgres-data:/var/lib/postgresql/data
|
|
131
|
+
|
|
132
|
+
mail:
|
|
133
|
+
build:
|
|
134
|
+
context: .
|
|
135
|
+
dockerfile: Dockerfile.workspace-app
|
|
136
|
+
args:
|
|
137
|
+
APP_NAME: mail
|
|
138
|
+
APP_BASE_PATH: /mail
|
|
139
|
+
restart: unless-stopped
|
|
140
|
+
environment:
|
|
141
|
+
DATABASE_URL: postgres://agent_native:change-me@postgres:5432/agent_native
|
|
142
|
+
BETTER_AUTH_URL: https://agents.example.com/mail
|
|
143
|
+
BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET}
|
|
144
|
+
A2A_SECRET: ${A2A_SECRET}
|
|
145
|
+
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
|
146
|
+
depends_on:
|
|
147
|
+
- postgres
|
|
148
|
+
|
|
149
|
+
calendar:
|
|
150
|
+
build:
|
|
151
|
+
context: .
|
|
152
|
+
dockerfile: Dockerfile.workspace-app
|
|
153
|
+
args:
|
|
154
|
+
APP_NAME: calendar
|
|
155
|
+
APP_BASE_PATH: /calendar
|
|
156
|
+
restart: unless-stopped
|
|
157
|
+
environment:
|
|
158
|
+
DATABASE_URL: postgres://agent_native:change-me@postgres:5432/agent_native
|
|
159
|
+
BETTER_AUTH_URL: https://agents.example.com/calendar
|
|
160
|
+
BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET}
|
|
161
|
+
A2A_SECRET: ${A2A_SECRET}
|
|
162
|
+
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
|
163
|
+
depends_on:
|
|
164
|
+
- postgres
|
|
165
|
+
|
|
166
|
+
proxy:
|
|
167
|
+
image: caddy:2
|
|
168
|
+
restart: unless-stopped
|
|
169
|
+
ports:
|
|
170
|
+
- "80:80"
|
|
171
|
+
- "443:443"
|
|
172
|
+
volumes:
|
|
173
|
+
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
|
174
|
+
depends_on:
|
|
175
|
+
- mail
|
|
176
|
+
- calendar
|
|
177
|
+
|
|
178
|
+
volumes:
|
|
179
|
+
postgres-data:
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```caddyfile
|
|
183
|
+
agents.example.com {
|
|
184
|
+
reverse_proxy /mail* mail:3000
|
|
185
|
+
reverse_proxy /calendar* calendar:3000
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Notes for this shape:
|
|
190
|
+
|
|
191
|
+
- Keep `DATABASE_URL`, `BETTER_AUTH_SECRET`, `A2A_SECRET`, and other production
|
|
192
|
+
secrets identical across app containers when you want shared auth, shared
|
|
193
|
+
credentials, and cross-app A2A.
|
|
194
|
+
- Set `BETTER_AUTH_URL` to the public URL for that app path. OAuth callback URLs
|
|
195
|
+
should use the same public URL.
|
|
196
|
+
- Do not rely on the container filesystem for production data; use Postgres (or
|
|
197
|
+
another persistent SQL backend) for `DATABASE_URL`.
|
|
198
|
+
- If Cloudflare terminates TLS in front of the VPS, configure Cloudflare to send
|
|
199
|
+
normal `X-Forwarded-Proto` / `X-Forwarded-Host` headers and route the public
|
|
200
|
+
host to the proxy container.
|
|
201
|
+
|
|
69
202
|
## How It Works {#how-it-works}
|
|
70
203
|
|
|
71
204
|
When you run `npx @agent-native/core@latest build`, Nitro builds both the client SPA and the server API into `.output/`:
|
|
@@ -289,6 +289,8 @@ These settings only affect read-only page navigation. Framework tools, agent cha
|
|
|
289
289
|
|
|
290
290
|
Prefer each app on its own domain (`mail.company.com`, `calendar.company.com`)? Every app in the workspace is still an independent deployable — `cd apps/mail && npx @agent-native/core@latest build` behaves exactly like a standalone scaffold. Cross-app A2A then goes through the standard JWT-signed path with a shared `A2A_SECRET`. Cross-domain SSO between separately-deployed apps is handled by identity federation with Dispatch as the hub — see [Cross-App SSO](/docs/cross-app-sso); the unified single-origin deploy avoids needing it.
|
|
291
291
|
|
|
292
|
+
For a self-hosted VPS or Docker Compose setup on one origin, build and run one container per app with its own path prefix (`APP_BASE_PATH=/mail`, `APP_BASE_PATH=/calendar`, ...), then route those prefixes through a reverse proxy. See [Deployment — Self-hosted workspace with Docker Compose](/docs/deployment#workspace-docker-compose) for the Dockerfile and compose example.
|
|
293
|
+
|
|
292
294
|
### Shared database, shared credentials
|
|
293
295
|
|
|
294
296
|
Whatever you pick, point every app at the same `DATABASE_URL` for cross-app state out of the box: one set of user accounts, one set of organizations, one set of shared settings. If each app has its own database, the workspace pattern still works — you just lose that shared-state story.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.79.
|
|
3
|
+
"version": "0.79.21",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -196,6 +196,7 @@
|
|
|
196
196
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
197
197
|
"@mozilla/readability": "0.6.0",
|
|
198
198
|
"@neondatabase/serverless": "^1.1.0",
|
|
199
|
+
"@opentelemetry/sdk-trace-base": "^2.8.0",
|
|
199
200
|
"@radix-ui/react-dialog": "1.1.15",
|
|
200
201
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
201
202
|
"@radix-ui/react-hover-card": "^1.1.15",
|