@agent-native/core 0.168.10 → 0.168.12
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/templates/clips/changelog/2026-08-19-desktop-settings-are-tighter-with-a-new-advanced-tab.md +6 -0
- package/corpus/templates/clips/desktop/README.md +79 -1
- package/corpus/templates/clips/desktop/components.json +20 -0
- package/corpus/templates/clips/desktop/package.json +10 -1
- package/corpus/templates/clips/desktop/src/app.tsx +1812 -1994
- package/corpus/templates/clips/desktop/src/components/ReadinessPanel.tsx +23 -65
- package/corpus/templates/clips/desktop/src/components/settings/settings-ui.tsx +399 -0
- package/corpus/templates/clips/desktop/src/components/ui/alert-dialog.tsx +166 -0
- package/corpus/templates/clips/desktop/src/components/ui/button.tsx +57 -0
- package/corpus/templates/clips/desktop/src/components/ui/empty.tsx +104 -0
- package/corpus/templates/clips/desktop/src/components/ui/input.tsx +22 -0
- package/corpus/templates/clips/desktop/src/components/ui/popover.tsx +38 -0
- package/corpus/templates/clips/desktop/src/components/ui/select.tsx +164 -0
- package/corpus/templates/clips/desktop/src/components/ui/skeleton.tsx +15 -0
- package/corpus/templates/clips/desktop/src/components/ui/spinner.tsx +17 -0
- package/corpus/templates/clips/desktop/src/components/ui/switch.tsx +27 -0
- package/corpus/templates/clips/desktop/src/components/ui/textarea.tsx +22 -0
- package/corpus/templates/clips/desktop/src/dev/browser-preview.ts +65 -0
- package/corpus/templates/clips/desktop/src/hooks/useSystemAccessRows.ts +128 -0
- package/corpus/templates/clips/desktop/src/hooks/useWhisperSettings.ts +0 -2
- package/corpus/templates/clips/desktop/src/lib/permission-status.ts +84 -0
- package/corpus/templates/clips/desktop/src/lib/rewind-status.ts +6 -5
- package/corpus/templates/clips/desktop/src/lib/settings-navigation.ts +18 -5
- package/corpus/templates/clips/desktop/src/lib/utils.ts +6 -0
- package/corpus/templates/clips/desktop/src/main.tsx +31 -4
- package/corpus/templates/clips/desktop/src/overlays/finalizing.tsx +2 -2
- package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +2 -2
- package/corpus/templates/clips/desktop/src/styles.css +75 -1427
- package/corpus/templates/clips/desktop/src/tailwind.css +282 -0
- package/corpus/templates/clips/desktop/tsconfig.json +4 -1
- package/corpus/templates/clips/desktop/vite.config.ts +7 -1
- package/corpus/templates/design/app/components/layout/Layout.tsx +38 -14
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/action-routes.js +3 -2
- package/dist/server/request-origin.d.ts +6 -0
- package/dist/server/request-origin.js +12 -0
- package/package.json +1 -1
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tailwind + shadcn/ui for the Clips tray app.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately imports `theme` and `utilities` but NOT `preflight`. The tray
|
|
5
|
+
* predates this layer: `styles.css` hand-styles every overlay (pill, bubble,
|
|
6
|
+
* toolbar, countdown, onboarding) against unreset browser defaults, so
|
|
7
|
+
* preflight's reset would silently break all of them. Surfaces move onto
|
|
8
|
+
* Tailwind one at a time; when the last hand-written rule is gone, swap these
|
|
9
|
+
* two imports for plain `@import "tailwindcss"` and delete this comment.
|
|
10
|
+
*/
|
|
11
|
+
/* Layer order decides who wins, and it has to be declared before the imports.
|
|
12
|
+
`styles.css` is unlayered CSS, and unlayered always beats a layer — including
|
|
13
|
+
bare element rules like `button { font-size: inherit }`, which would quietly
|
|
14
|
+
defeat every `text-sm` on a shadcn Button. Pulling it into `legacy` puts it
|
|
15
|
+
below `utilities` so Tailwind can do its job, while keeping the tray's own
|
|
16
|
+
cascade intact for the surfaces still using it. */
|
|
17
|
+
@layer legacy, theme, utilities;
|
|
18
|
+
|
|
19
|
+
@import "./styles.css" layer(legacy);
|
|
20
|
+
@import "tailwindcss/theme.css" layer(theme);
|
|
21
|
+
@import "tailwindcss/utilities.css" layer(utilities);
|
|
22
|
+
@import "tw-animate-css";
|
|
23
|
+
|
|
24
|
+
@source "./**/*.{ts,tsx}";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The parts of preflight a Tailwind-era surface cannot live without, scoped to
|
|
28
|
+
* subtrees marked `data-tw-surface` so the hand-written tray surfaces keep the
|
|
29
|
+
* UA defaults their CSS was written against.
|
|
30
|
+
*
|
|
31
|
+
* Every rule here exists because a shadcn component assumes preflight already
|
|
32
|
+
* ran. Skipping it cost us, in order: phantom UA margins under headings, the
|
|
33
|
+
* native grey `ButtonFace` box behind `ghost` variants, `currentColor` borders
|
|
34
|
+
* painting black instead of a hairline, and icons riding ~2px high because an
|
|
35
|
+
* un-reset `svg` is an inline box on a text baseline. If a shadcn primitive
|
|
36
|
+
* looks subtly wrong here, suspect this list before editing the primitive.
|
|
37
|
+
*
|
|
38
|
+
* In `theme` so every utility still wins. Portaled shadcn content (popover and
|
|
39
|
+
* select) carries the attribute itself, since it renders outside the subtree.
|
|
40
|
+
*/
|
|
41
|
+
@layer theme {
|
|
42
|
+
[data-tw-surface] :is(h1, h2, h3, h4, h5, h6, p, figure, blockquote) {
|
|
43
|
+
margin: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Icons are laid out as boxes, not as glyphs on a baseline. Without this an
|
|
47
|
+
`svg` stays `display: inline` and sits ~2px above the centre of whatever
|
|
48
|
+
flex row is meant to be centring it — visible on every checkmark, chevron,
|
|
49
|
+
and button icon. */
|
|
50
|
+
[data-tw-surface] :is(img, svg, video, canvas, audio, iframe, embed, object) {
|
|
51
|
+
display: block;
|
|
52
|
+
vertical-align: middle;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* Tailwind's `border` utility sets width only — preflight is what gives every
|
|
56
|
+
element a default border COLOR. Without it a bare `border` (shadcn's
|
|
57
|
+
popover and select content, among others) falls back to `currentColor` and
|
|
58
|
+
paints a hard near-black rule instead of a hairline. */
|
|
59
|
+
[data-tw-surface],
|
|
60
|
+
[data-tw-surface] *,
|
|
61
|
+
[data-tw-surface] *::before,
|
|
62
|
+
[data-tw-surface] *::after {
|
|
63
|
+
border-color: hsl(var(--ui-border));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
[data-tw-surface] :is(button, input, optgroup, select, textarea) {
|
|
67
|
+
appearance: none;
|
|
68
|
+
margin: 0;
|
|
69
|
+
padding: 0;
|
|
70
|
+
border: 0;
|
|
71
|
+
border-radius: 0;
|
|
72
|
+
background-color: transparent;
|
|
73
|
+
color: inherit;
|
|
74
|
+
font: inherit;
|
|
75
|
+
letter-spacing: inherit;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
[data-tw-surface] :is(button, [role="button"]) {
|
|
79
|
+
cursor: pointer;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
[data-tw-surface] :is(button, input, select, textarea):disabled {
|
|
83
|
+
cursor: not-allowed;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
[data-tw-surface] :is(input, textarea)::placeholder {
|
|
87
|
+
color: hsl(var(--ui-muted-foreground));
|
|
88
|
+
opacity: 1;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* The remainder of preflight, ported in one pass rather than discovered one
|
|
92
|
+
bug at a time. Headings keep UA size/weight without this, lists keep their
|
|
93
|
+
markers and indent, links keep browser blue — each of which would read as
|
|
94
|
+
a broken shadcn component rather than a missing reset. */
|
|
95
|
+
[data-tw-surface] :is(h1, h2, h3, h4, h5, h6) {
|
|
96
|
+
font-size: inherit;
|
|
97
|
+
font-weight: inherit;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
[data-tw-surface] :is(dl, dd, hr, pre, fieldset, legend) {
|
|
101
|
+
margin: 0;
|
|
102
|
+
padding: 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
[data-tw-surface] :is(ol, ul, menu) {
|
|
106
|
+
list-style: none;
|
|
107
|
+
margin: 0;
|
|
108
|
+
padding: 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
[data-tw-surface] a {
|
|
112
|
+
color: inherit;
|
|
113
|
+
text-decoration: inherit;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
[data-tw-surface] :is(code, kbd, samp, pre) {
|
|
117
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
118
|
+
font-size: 1em;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
[data-tw-surface] hr {
|
|
122
|
+
height: 0;
|
|
123
|
+
color: inherit;
|
|
124
|
+
border-top-width: 1px;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
[data-tw-surface] table {
|
|
128
|
+
text-indent: 0;
|
|
129
|
+
border-color: inherit;
|
|
130
|
+
border-collapse: collapse;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
[data-tw-surface] :is(img, video) {
|
|
134
|
+
max-width: 100%;
|
|
135
|
+
height: auto;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
[data-tw-surface] textarea {
|
|
139
|
+
resize: vertical;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
[data-tw-surface] summary {
|
|
143
|
+
display: list-item;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
[data-tw-surface] [hidden]:not([hidden="until-found"]) {
|
|
147
|
+
display: none !important;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* The tray follows the OS, so dark mode is a media query rather than the web
|
|
152
|
+
app's `.dark` class. Both resolve the same token names. */
|
|
153
|
+
@custom-variant dark (@media (prefers-color-scheme: dark));
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* shadcn/ui semantic tokens, expressed as HSL triplets as in the web app's
|
|
157
|
+
* `app/global.css` so a primitive copied between the two renders the same.
|
|
158
|
+
* The values are the tray's own palette — a menu-bar window sits on the
|
|
159
|
+
* desktop, not on a page, so it stays slightly darker and flatter than web.
|
|
160
|
+
*
|
|
161
|
+
* Every token is `--ui-`-prefixed because this block is UNLAYERED and legacy
|
|
162
|
+
* `styles.css` (layered) defines full-color tokens under the bare names —
|
|
163
|
+
* an unprefixed `--border: 0 0% 90%` here would beat legacy's full-color
|
|
164
|
+
* `--border` and expand its 27 `var(--border)` borders to an invalid
|
|
165
|
+
* color. Only tailwind.css maps these into Tailwind's namespace.
|
|
166
|
+
*/
|
|
167
|
+
:root {
|
|
168
|
+
--ui-background: 0 0% 100%;
|
|
169
|
+
--ui-foreground: 0 0% 9%;
|
|
170
|
+
--ui-card: 0 0% 100%;
|
|
171
|
+
--ui-card-foreground: 0 0% 9%;
|
|
172
|
+
--ui-popover: 0 0% 100%;
|
|
173
|
+
--ui-popover-foreground: 0 0% 9%;
|
|
174
|
+
--ui-primary: 0 0% 10%;
|
|
175
|
+
--ui-primary-foreground: 0 0% 100%;
|
|
176
|
+
--ui-secondary: 0 0% 97%;
|
|
177
|
+
--ui-secondary-foreground: 0 0% 10%;
|
|
178
|
+
--ui-muted: 0 0% 96%;
|
|
179
|
+
--ui-muted-foreground: 0 0% 45%;
|
|
180
|
+
--ui-accent: 0 0% 94%;
|
|
181
|
+
--ui-accent-foreground: 0 0% 10%;
|
|
182
|
+
--ui-destructive: 0 72% 51%;
|
|
183
|
+
--ui-destructive-foreground: 0 0% 98%;
|
|
184
|
+
--ui-border: 0 0% 90%;
|
|
185
|
+
--ui-input: 0 0% 87%;
|
|
186
|
+
--ui-ring: 0 0% 40%;
|
|
187
|
+
/* macOS convention for an engaged switch, and the one accent the tray uses. */
|
|
188
|
+
--ui-success: 142 71% 45%;
|
|
189
|
+
/* Reserved for "there is something new here" — the Settings dot, nothing else. */
|
|
190
|
+
--ui-info: 217 91% 55%;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
@media (prefers-color-scheme: dark) {
|
|
194
|
+
:root {
|
|
195
|
+
--ui-background: 0 0% 13%;
|
|
196
|
+
--ui-foreground: 0 0% 96%;
|
|
197
|
+
--ui-card: 0 0% 15%;
|
|
198
|
+
--ui-card-foreground: 0 0% 96%;
|
|
199
|
+
--ui-popover: 0 0% 15%;
|
|
200
|
+
--ui-popover-foreground: 0 0% 96%;
|
|
201
|
+
--ui-primary: 0 0% 96%;
|
|
202
|
+
--ui-primary-foreground: 0 0% 10%;
|
|
203
|
+
--ui-secondary: 0 0% 18%;
|
|
204
|
+
--ui-secondary-foreground: 0 0% 96%;
|
|
205
|
+
--ui-muted: 0 0% 16%;
|
|
206
|
+
--ui-muted-foreground: 0 0% 64%;
|
|
207
|
+
--ui-accent: 0 0% 20%;
|
|
208
|
+
--ui-accent-foreground: 0 0% 96%;
|
|
209
|
+
--ui-destructive: 0 72% 58%;
|
|
210
|
+
--ui-destructive-foreground: 0 0% 98%;
|
|
211
|
+
--ui-border: 0 0% 24%;
|
|
212
|
+
--ui-input: 0 0% 32%;
|
|
213
|
+
--ui-ring: 0 0% 60%;
|
|
214
|
+
--ui-success: 142 60% 52%;
|
|
215
|
+
--ui-info: 217 91% 65%;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
@theme inline {
|
|
220
|
+
/**
|
|
221
|
+
* Absolute, not rem. The tray sets `:root { font-size: 13px }`, so every
|
|
222
|
+
* rem-based Tailwind scale silently computed ~19% small against it —
|
|
223
|
+
* `text-xs` landed at 9.75px and `h-8` at 26px, which is what made control
|
|
224
|
+
* typography look off next to the px-based rest of the app. Pinning these to
|
|
225
|
+
* px makes the utility scale mean the same thing here as in the web app.
|
|
226
|
+
*/
|
|
227
|
+
--spacing: 4px;
|
|
228
|
+
/* Softer than shadcn's 8px default: a 32px-tall control wants ~10px to read
|
|
229
|
+
as the rounded pill the rest of this product uses. */
|
|
230
|
+
--radius: 10px;
|
|
231
|
+
|
|
232
|
+
/* One scale, anchored on the tray's 13px baseline. `text-base` is body copy,
|
|
233
|
+
`text-sm` is every in-row control, `text-xs` is the grounding line. */
|
|
234
|
+
--text-2xs: 10px;
|
|
235
|
+
--text-2xs--line-height: 1.4;
|
|
236
|
+
--text-xs: 11px;
|
|
237
|
+
--text-xs--line-height: 1.45;
|
|
238
|
+
--text-sm: 12px;
|
|
239
|
+
--text-sm--line-height: 1.4;
|
|
240
|
+
--text-base: 13px;
|
|
241
|
+
--text-base--line-height: 1.45;
|
|
242
|
+
--text-lg: 15px;
|
|
243
|
+
--text-lg--line-height: 1.35;
|
|
244
|
+
--text-xl: 17px;
|
|
245
|
+
--text-xl--line-height: 1.3;
|
|
246
|
+
--text-2xl: 20px;
|
|
247
|
+
--text-2xl--line-height: 1.2;
|
|
248
|
+
|
|
249
|
+
--color-border: hsl(var(--ui-border));
|
|
250
|
+
--color-input: hsl(var(--ui-input));
|
|
251
|
+
--color-ring: hsl(var(--ui-ring));
|
|
252
|
+
--color-background: hsl(var(--ui-background));
|
|
253
|
+
--color-foreground: hsl(var(--ui-foreground));
|
|
254
|
+
|
|
255
|
+
--color-primary: hsl(var(--ui-primary));
|
|
256
|
+
--color-primary-foreground: hsl(var(--ui-primary-foreground));
|
|
257
|
+
|
|
258
|
+
--color-secondary: hsl(var(--ui-secondary));
|
|
259
|
+
--color-secondary-foreground: hsl(var(--ui-secondary-foreground));
|
|
260
|
+
|
|
261
|
+
--color-destructive: hsl(var(--ui-destructive));
|
|
262
|
+
--color-destructive-foreground: hsl(var(--ui-destructive-foreground));
|
|
263
|
+
|
|
264
|
+
--color-muted: hsl(var(--ui-muted));
|
|
265
|
+
--color-muted-foreground: hsl(var(--ui-muted-foreground));
|
|
266
|
+
|
|
267
|
+
--color-accent: hsl(var(--ui-accent));
|
|
268
|
+
--color-accent-foreground: hsl(var(--ui-accent-foreground));
|
|
269
|
+
|
|
270
|
+
--color-popover: hsl(var(--ui-popover));
|
|
271
|
+
--color-popover-foreground: hsl(var(--ui-popover-foreground));
|
|
272
|
+
|
|
273
|
+
--color-card: hsl(var(--ui-card));
|
|
274
|
+
--color-card-foreground: hsl(var(--ui-card-foreground));
|
|
275
|
+
|
|
276
|
+
--color-success: hsl(var(--ui-success));
|
|
277
|
+
--color-info: hsl(var(--ui-info));
|
|
278
|
+
|
|
279
|
+
--radius-lg: var(--radius);
|
|
280
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
281
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
282
|
+
}
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
"skipLibCheck": true,
|
|
13
13
|
"resolveJsonModule": true,
|
|
14
14
|
"isolatedModules": true,
|
|
15
|
-
"noEmit": true
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
"paths": {
|
|
17
|
+
"@/*": ["./src/*"]
|
|
18
|
+
}
|
|
16
19
|
},
|
|
17
20
|
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
|
18
21
|
"exclude": ["src/**/*.test.ts", "src/**/*.spec.ts"]
|
|
@@ -2,6 +2,7 @@ import { readFileSync } from "node:fs";
|
|
|
2
2
|
import { dirname, resolve } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
|
|
5
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
5
6
|
import react from "@vitejs/plugin-react";
|
|
6
7
|
import { defineConfig } from "vite";
|
|
7
8
|
|
|
@@ -77,7 +78,12 @@ function resolveSentryEnvironment(): string {
|
|
|
77
78
|
// still picks up `.rs` / `tauri.conf.json` / `capabilities/*.json`
|
|
78
79
|
// changes and rebuilds the app.
|
|
79
80
|
export default defineConfig({
|
|
80
|
-
plugins: [react()],
|
|
81
|
+
plugins: [react(), tailwindcss()],
|
|
82
|
+
resolve: {
|
|
83
|
+
alias: {
|
|
84
|
+
"@": resolve(root, "src"),
|
|
85
|
+
},
|
|
86
|
+
},
|
|
81
87
|
clearScreen: false,
|
|
82
88
|
define: {
|
|
83
89
|
__CLIPS_DESKTOP_SENTRY_DSN__: JSON.stringify(resolveSentryDsn()),
|
|
@@ -48,26 +48,51 @@ export function useOpenMobileSidebar() {
|
|
|
48
48
|
const BARE_PREFIXES = ["/present/"];
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
|
-
* Routes where the page renders its own toolbar instead of the global Header
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* chrome). The editor owns its agent surface inside its Figma-style left rail.
|
|
51
|
+
* Routes where the page renders its own toolbar instead of the global Header
|
|
52
|
+
* on a standalone page. Embedded app surfaces keep the global shell so the
|
|
53
|
+
* host-provided chat rail can still be reopened from the app header.
|
|
55
54
|
*/
|
|
56
55
|
const EDITOR_PREFIXES = ["/design/", "/visual-edit/", "/extensions"];
|
|
57
56
|
|
|
57
|
+
type DesignLayoutMode = "host-bare" | "standalone-editor" | "app-shell";
|
|
58
|
+
|
|
59
|
+
function resolveDesignLayoutMode(input: {
|
|
60
|
+
builderHostEmbed: boolean;
|
|
61
|
+
embedded: boolean;
|
|
62
|
+
hasSession: boolean;
|
|
63
|
+
isDesignEditor: boolean;
|
|
64
|
+
}): DesignLayoutMode {
|
|
65
|
+
if (
|
|
66
|
+
input.builderHostEmbed ||
|
|
67
|
+
(input.isDesignEditor && !input.hasSession && !input.embedded)
|
|
68
|
+
) {
|
|
69
|
+
return "host-bare";
|
|
70
|
+
}
|
|
71
|
+
if (input.isDesignEditor && !input.embedded) return "standalone-editor";
|
|
72
|
+
return "app-shell";
|
|
73
|
+
}
|
|
74
|
+
|
|
58
75
|
export function Layout({ children }: LayoutProps) {
|
|
59
76
|
const location = useLocation();
|
|
60
77
|
const t = useT();
|
|
61
78
|
const { session } = useSession();
|
|
62
79
|
const hasSession = Boolean(session?.email);
|
|
80
|
+
const builderHostEmbed = isBuilderHostEmbed();
|
|
63
81
|
// The shell canvas is embedded without a session, so this cannot be the token
|
|
64
82
|
// check alone or it renders Design's own nav inside Builder.
|
|
65
|
-
const embedded =
|
|
83
|
+
const embedded = builderHostEmbed || isEmbedAuthActive();
|
|
66
84
|
useNavigationState(hasSession);
|
|
67
85
|
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
|
|
68
86
|
const openMobileSidebar = useCallback(() => setMobileSidebarOpen(true), []);
|
|
69
87
|
const isDesignEditor = isDesignEditorRoute(location.pathname);
|
|
70
|
-
const
|
|
88
|
+
const layoutMode = resolveDesignLayoutMode({
|
|
89
|
+
builderHostEmbed,
|
|
90
|
+
embedded,
|
|
91
|
+
hasSession,
|
|
92
|
+
isDesignEditor,
|
|
93
|
+
});
|
|
94
|
+
const standaloneEditor = layoutMode === "standalone-editor";
|
|
95
|
+
const showMobileTopBar = !standaloneEditor;
|
|
71
96
|
const browserTabId = getBrowserTabId();
|
|
72
97
|
const {
|
|
73
98
|
link: detectedFigmaComposerLink,
|
|
@@ -109,11 +134,10 @@ export function Layout({ children }: LayoutProps) {
|
|
|
109
134
|
return <>{children}</>;
|
|
110
135
|
}
|
|
111
136
|
|
|
112
|
-
const hideHeader =
|
|
113
|
-
location.pathname.startsWith(p)
|
|
114
|
-
);
|
|
137
|
+
const hideHeader =
|
|
138
|
+
!embedded && EDITOR_PREFIXES.some((p) => location.pathname.startsWith(p));
|
|
115
139
|
|
|
116
|
-
if (
|
|
140
|
+
if (layoutMode === "host-bare") {
|
|
117
141
|
return (
|
|
118
142
|
<HeaderActionsProvider>
|
|
119
143
|
<MobileSidebarContext.Provider value={null}>
|
|
@@ -132,7 +156,7 @@ export function Layout({ children }: LayoutProps) {
|
|
|
132
156
|
);
|
|
133
157
|
}
|
|
134
158
|
|
|
135
|
-
if (
|
|
159
|
+
if (layoutMode === "standalone-editor") {
|
|
136
160
|
return (
|
|
137
161
|
<HeaderActionsProvider>
|
|
138
162
|
<MobileSidebarContext.Provider value={null}>
|
|
@@ -151,7 +175,7 @@ export function Layout({ children }: LayoutProps) {
|
|
|
151
175
|
return (
|
|
152
176
|
<HeaderActionsProvider>
|
|
153
177
|
<MobileSidebarContext.Provider
|
|
154
|
-
value={
|
|
178
|
+
value={standaloneEditor ? null : openMobileSidebar}
|
|
155
179
|
>
|
|
156
180
|
<AgentSidebar
|
|
157
181
|
position="right"
|
|
@@ -178,13 +202,13 @@ export function Layout({ children }: LayoutProps) {
|
|
|
178
202
|
}
|
|
179
203
|
>
|
|
180
204
|
<div className="agent-layout-shell flex h-dvh w-full overflow-hidden bg-background text-foreground">
|
|
181
|
-
{!
|
|
205
|
+
{!standaloneEditor && mobileSidebarOpen && (
|
|
182
206
|
<div
|
|
183
207
|
className="fixed inset-0 z-40 bg-black/50 md:hidden"
|
|
184
208
|
onClick={() => setMobileSidebarOpen(false)}
|
|
185
209
|
/>
|
|
186
210
|
)}
|
|
187
|
-
{!
|
|
211
|
+
{!standaloneEditor && (
|
|
188
212
|
<div
|
|
189
213
|
className={cn(
|
|
190
214
|
"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 motion-reduce:transition-none",
|
|
@@ -62,11 +62,11 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
|
|
|
62
62
|
error: string;
|
|
63
63
|
states?: undefined;
|
|
64
64
|
} | {
|
|
65
|
+
error?: undefined;
|
|
65
66
|
states: {
|
|
66
67
|
clientId: number;
|
|
67
68
|
state: string;
|
|
68
69
|
}[];
|
|
69
|
-
error?: undefined;
|
|
70
70
|
}>>;
|
|
71
71
|
/**
|
|
72
72
|
* GET /_agent-native/collab/:docId/users
|
|
@@ -77,9 +77,9 @@ export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("
|
|
|
77
77
|
error: string;
|
|
78
78
|
users?: undefined;
|
|
79
79
|
} | {
|
|
80
|
+
error?: undefined;
|
|
80
81
|
users: {
|
|
81
82
|
clientId: number;
|
|
82
83
|
lastSeen: number;
|
|
83
84
|
}[];
|
|
84
|
-
error?: undefined;
|
|
85
85
|
}>>;
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
|
|
|
26
26
|
* Body: { update: string (base64), requestSource?: string }
|
|
27
27
|
*/
|
|
28
28
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
29
|
-
ok?: undefined;
|
|
30
29
|
error: string;
|
|
30
|
+
ok?: undefined;
|
|
31
31
|
} | {
|
|
32
32
|
error?: undefined;
|
|
33
33
|
ok: boolean;
|
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
* DELETE /_agent-native/notifications/:id — delete
|
|
12
12
|
*/
|
|
13
13
|
export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
|
|
14
|
+
error?: undefined;
|
|
14
15
|
count: number;
|
|
15
16
|
updated?: undefined;
|
|
16
|
-
error?: undefined;
|
|
17
17
|
ok?: undefined;
|
|
18
18
|
} | {
|
|
19
|
+
error?: undefined;
|
|
19
20
|
count?: undefined;
|
|
20
21
|
updated: number;
|
|
21
|
-
error?: undefined;
|
|
22
22
|
ok?: undefined;
|
|
23
23
|
} | {
|
|
24
24
|
count?: undefined;
|
|
@@ -26,8 +26,8 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
|
|
|
26
26
|
error: string;
|
|
27
27
|
ok?: undefined;
|
|
28
28
|
} | {
|
|
29
|
+
error?: undefined;
|
|
29
30
|
count?: undefined;
|
|
30
31
|
updated?: undefined;
|
|
31
|
-
error?: undefined;
|
|
32
32
|
ok: boolean;
|
|
33
33
|
}>>;
|
|
@@ -48,8 +48,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
|
|
|
48
48
|
}>;
|
|
49
49
|
/** DELETE /_agent-native/resources/:id — delete a resource */
|
|
50
50
|
export declare function handleDeleteResource(event: any): Promise<{
|
|
51
|
-
ok?: undefined;
|
|
52
51
|
error: string;
|
|
52
|
+
ok?: undefined;
|
|
53
53
|
} | {
|
|
54
54
|
error?: undefined;
|
|
55
55
|
ok: boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createError, defineEventHandler, setResponseStatus, setResponseHeader, getMethod, getQuery, getHeader,
|
|
1
|
+
import { createError, defineEventHandler, setResponseStatus, setResponseHeader, getMethod, getQuery, getHeader, } from "h3";
|
|
2
2
|
import { verifyA2ATokenWithClaims } from "../a2a-claims.js";
|
|
3
3
|
import { isActionContractError, isAgentActionStopError } from "../action.js";
|
|
4
4
|
import { isTransientDatabaseError } from "../db/client.js";
|
|
@@ -15,6 +15,7 @@ import { getAllowedCorsOrigin as resolveAllowedCorsOrigin, readCorsAllowedOrigin
|
|
|
15
15
|
import { resolveEmbedSessionFromRequest, resolvedEmbedCapabilityScope, } from "./embed-session.js";
|
|
16
16
|
import { getHttpRequestTelemetryId } from "./http-response-telemetry.js";
|
|
17
17
|
import { consumeOneTimeJti } from "./identity-sso-store.js";
|
|
18
|
+
import { getForwardedRequestOrigin } from "./request-origin.js";
|
|
18
19
|
function requiredClientCompatibilityVersion() {
|
|
19
20
|
const configured = typeof __AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__ === "string"
|
|
20
21
|
? __AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__
|
|
@@ -410,7 +411,7 @@ export function mountActionRoutes(nitroApp, actions, options) {
|
|
|
410
411
|
timezone,
|
|
411
412
|
browserSessionId,
|
|
412
413
|
clientPlatform,
|
|
413
|
-
requestOrigin:
|
|
414
|
+
requestOrigin: getForwardedRequestOrigin(event),
|
|
414
415
|
// Captured here because this is the last layer that still holds
|
|
415
416
|
// the h3 event; everything below reads it off the request store.
|
|
416
417
|
isLoopbackRequest: isLoopbackRequest(event),
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { type H3Event } from "h3";
|
|
2
|
+
/**
|
|
3
|
+
* Browser-visible origin from proxy-forwarded headers. Unlike `getOrigin()`,
|
|
4
|
+
* this ignores OAuth callback and configured-public-origin overrides so action
|
|
5
|
+
* CSRF checks match the Referer the browser actually sent.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getForwardedRequestOrigin(event: H3Event): string;
|
|
2
8
|
/**
|
|
3
9
|
* Reject cross-site POSTs. Cookies are `SameSite=None; Secure` over HTTPS so
|
|
4
10
|
* the browser would otherwise attach the session to a forged form submission
|
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
import { getRequestHeader } from "h3";
|
|
2
|
+
/**
|
|
3
|
+
* Browser-visible origin from proxy-forwarded headers. Unlike `getOrigin()`,
|
|
4
|
+
* this ignores OAuth callback and configured-public-origin overrides so action
|
|
5
|
+
* CSRF checks match the Referer the browser actually sent.
|
|
6
|
+
*/
|
|
7
|
+
export function getForwardedRequestOrigin(event) {
|
|
8
|
+
const headerHost = getRequestHeader(event, "x-forwarded-host") ||
|
|
9
|
+
getRequestHeader(event, "host");
|
|
10
|
+
const isProd = process.env.NODE_ENV === "production";
|
|
11
|
+
const headerProto = getRequestHeader(event, "x-forwarded-proto") || (isProd ? "https" : "http");
|
|
12
|
+
return `${headerProto}://${headerHost ?? "localhost"}`;
|
|
13
|
+
}
|
|
2
14
|
function isLoopbackHost(host) {
|
|
3
15
|
return host.startsWith("localhost:") || host.startsWith("127.0.0.1:");
|
|
4
16
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.168.
|
|
3
|
+
"version": "0.168.12",
|
|
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": {
|