@agent-native/core 0.188.0-nightly-20260925170533 → 0.188.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/corpus/README.md +1 -1
- package/corpus/templates/analytics/CHANGELOG.md +3 -0
- package/corpus/templates/assets/CHANGELOG.md +11 -0
- package/corpus/templates/calendar/CHANGELOG.md +7 -0
- package/corpus/templates/calendar/changelog/2026-09-24-calendar-no-longer-shows-an-internal-server-error-banner-whe.md +6 -0
- package/corpus/templates/calendar/server/handlers/events.ts +0 -163
- package/corpus/templates/calendar/server/lib/google-calendar.ts +40 -5
- package/corpus/templates/clips/CHANGELOG.md +18 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +110 -28
- package/corpus/templates/clips/changelog/2026-09-25-shared-clips-remember-your-sidebar-choice-and-help-new-viewe.md +6 -0
- package/corpus/templates/content/CHANGELOG.md +4 -0
- package/corpus/templates/design/CHANGELOG.md +30 -0
- package/corpus/templates/mail/CHANGELOG.md +12 -0
- package/corpus/templates/slides/CHANGELOG.md +26 -0
- package/dist/automation/index.d.ts +1 -1
- package/dist/client/auth/AuthPage.d.ts +1 -0
- package/dist/client/auth/AuthPage.js +10 -4
- package/dist/client/org/OrgSwitcher.d.ts +1 -1
- package/dist/client/org/OrgSwitcher.js +3 -3
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
- package/dist/server/onboarding-html.js +56 -0
- package/docs/content/cross-app-sso.mdx +27 -15
- package/package.json +4 -4
package/corpus/README.md
CHANGED
|
@@ -7,10 +7,13 @@ time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
|
7
7
|
|
|
8
8
|
### Improved
|
|
9
9
|
|
|
10
|
+
- Analytics sidebar navigation and footer controls align consistently, with full-width dividers.
|
|
10
11
|
- The Sessions list hides 0m recordings by default, with a filter to include them.
|
|
11
12
|
|
|
12
13
|
### Fixed
|
|
13
14
|
|
|
15
|
+
- Dashboard emails now match the live dashboard's stacked area chart totals.
|
|
16
|
+
- Editing a dashboard panel no longer brings back a panel you just deleted, and conflicting saves now show a clear error instead of a server error
|
|
14
17
|
- Session recordings no longer cut off partway through when the daily recording budget runs low; new recordings wait for room instead.
|
|
15
18
|
|
|
16
19
|
## 2026-09-23
|
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable user-facing changes to Assets are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-09-24
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- Builder-connected workspaces can generate brand-safe images and videos in Assets.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Video generation avoids duplicate Gemini jobs when a start response is lost
|
|
15
|
+
- Video generation runs recover after temporary provider or storage failures.
|
|
16
|
+
|
|
6
17
|
## 2026-09-23
|
|
7
18
|
|
|
8
19
|
### Fixed
|
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
All notable user-facing changes to Agent-Native Calendar are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-09-24
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- Calendar no longer shows an internal server error banner when a shared workspace Google connection can't be authorized
|
|
11
|
+
- Guest inputs wrap beneath existing guests so the active input stays visible
|
|
12
|
+
|
|
6
13
|
## 2026-09-23
|
|
7
14
|
|
|
8
15
|
### Improved
|
|
@@ -1,20 +1,11 @@
|
|
|
1
|
-
import { emit } from "@agent-native/core/event-bus";
|
|
2
1
|
import { readBody, getSession } from "@agent-native/core/server";
|
|
3
2
|
import {
|
|
4
3
|
defineEventHandler,
|
|
5
|
-
getQuery,
|
|
6
4
|
getRouterParam,
|
|
7
5
|
setResponseStatus,
|
|
8
|
-
setResponseHeader,
|
|
9
6
|
type H3Event,
|
|
10
7
|
} from "h3";
|
|
11
8
|
|
|
12
|
-
import { ensureOrganizerInAttendees } from "../../actions/event-action-helpers.js";
|
|
13
|
-
import type { CalendarEvent } from "../../shared/api.js";
|
|
14
|
-
import {
|
|
15
|
-
prepareZoomMeetingPatch,
|
|
16
|
-
shouldAutoAddGoogleMeet,
|
|
17
|
-
} from "../lib/event-video-conferencing.js";
|
|
18
9
|
import * as googleCalendar from "../lib/google-calendar.js";
|
|
19
10
|
|
|
20
11
|
async function uEmail(event: H3Event): Promise<string> {
|
|
@@ -65,160 +56,6 @@ function handleError(event: H3Event, error: any) {
|
|
|
65
56
|
return { error: error.message };
|
|
66
57
|
}
|
|
67
58
|
|
|
68
|
-
export const listEvents = defineEventHandler(async (event: H3Event) => {
|
|
69
|
-
try {
|
|
70
|
-
const email = await uEmail(event);
|
|
71
|
-
const query = getQuery(event);
|
|
72
|
-
const from = query.from as string | undefined;
|
|
73
|
-
const to = query.to as string | undefined;
|
|
74
|
-
const connected = await googleCalendar.isConnected(email);
|
|
75
|
-
|
|
76
|
-
if (!connected) {
|
|
77
|
-
return [];
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (!from || !to) {
|
|
81
|
-
return [];
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const overlayEmailsParam = query.overlayEmails as string | undefined;
|
|
85
|
-
|
|
86
|
-
const { events: googleEvents, errors } = await googleCalendar.listEvents(
|
|
87
|
-
from,
|
|
88
|
-
to,
|
|
89
|
-
email,
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
if (googleEvents.length === 0 && errors.length > 0) {
|
|
93
|
-
setResponseStatus(event, 502);
|
|
94
|
-
return {
|
|
95
|
-
error: errors.map((e) => `${e.email}: ${e.error}`).join("; "),
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Fetch overlay people's events in parallel
|
|
100
|
-
let allEvents = googleEvents;
|
|
101
|
-
if (overlayEmailsParam) {
|
|
102
|
-
const overlayEmails = overlayEmailsParam
|
|
103
|
-
.split(",")
|
|
104
|
-
.filter(Boolean)
|
|
105
|
-
.slice(0, 10);
|
|
106
|
-
if (overlayEmails.length > 0) {
|
|
107
|
-
const { events: overlayEvents } =
|
|
108
|
-
await googleCalendar.listOverlayEvents(
|
|
109
|
-
from,
|
|
110
|
-
to,
|
|
111
|
-
overlayEmails,
|
|
112
|
-
email,
|
|
113
|
-
);
|
|
114
|
-
allEvents = [...googleEvents, ...overlayEvents];
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
let events = allEvents;
|
|
119
|
-
if (from) {
|
|
120
|
-
const fromDate = new Date(from);
|
|
121
|
-
events = events.filter((e) => new Date(e.end) >= fromDate);
|
|
122
|
-
}
|
|
123
|
-
if (to) {
|
|
124
|
-
const toDate = new Date(to);
|
|
125
|
-
events = events.filter((e) => new Date(e.start) <= toDate);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
events.sort(
|
|
129
|
-
(a, b) => new Date(a.start).getTime() - new Date(b.start).getTime(),
|
|
130
|
-
);
|
|
131
|
-
if (errors.length > 0) {
|
|
132
|
-
setResponseHeader(event, "X-Account-Errors", JSON.stringify(errors));
|
|
133
|
-
}
|
|
134
|
-
return events;
|
|
135
|
-
} catch (error: any) {
|
|
136
|
-
console.error("[listEvents] Error:", error.message);
|
|
137
|
-
setResponseStatus(event, 500);
|
|
138
|
-
return { error: error.message };
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
export const createEvent = defineEventHandler(async (event: H3Event) => {
|
|
143
|
-
try {
|
|
144
|
-
const email = await uEmail(event);
|
|
145
|
-
const body = await readBody(event);
|
|
146
|
-
|
|
147
|
-
if (!(await googleCalendar.isConnected(email))) {
|
|
148
|
-
setResponseStatus(event, 400);
|
|
149
|
-
return {
|
|
150
|
-
error: "Google Calendar not connected. Connect via Settings first.",
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const acctEmail = await resolveAccountEmail(body.accountEmail, email);
|
|
155
|
-
|
|
156
|
-
const { addGoogleMeet, addZoom, ...eventBody } = body;
|
|
157
|
-
if (addGoogleMeet === true && addZoom === true) {
|
|
158
|
-
setResponseStatus(event, 400);
|
|
159
|
-
return { error: "Choose either Google Meet or Zoom, not both." };
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const calEvent: CalendarEvent = {
|
|
163
|
-
...eventBody,
|
|
164
|
-
id: "",
|
|
165
|
-
source: "google",
|
|
166
|
-
accountEmail: acctEmail,
|
|
167
|
-
// Match Google Calendar UI: when inviting guests, include the
|
|
168
|
-
// organizer/self email in attendees so they appear in Guests.
|
|
169
|
-
attendees: ensureOrganizerInAttendees(eventBody.attendees, acctEmail),
|
|
170
|
-
createdAt: new Date().toISOString(),
|
|
171
|
-
updatedAt: new Date().toISOString(),
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
let zoomMeetingLink: string | undefined;
|
|
175
|
-
if (addZoom === true) {
|
|
176
|
-
const zoom = await prepareZoomMeetingPatch(email, calEvent);
|
|
177
|
-
zoomMeetingLink = zoom.meetingLink;
|
|
178
|
-
Object.assign(calEvent, zoom.patch);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const result = await googleCalendar.createEvent(calEvent, {
|
|
182
|
-
account: { ownerEmail: email, accountEmail: acctEmail },
|
|
183
|
-
addGoogleMeet: shouldAutoAddGoogleMeet(calEvent, {
|
|
184
|
-
addGoogleMeet:
|
|
185
|
-
typeof addGoogleMeet === "boolean" ? addGoogleMeet : undefined,
|
|
186
|
-
addZoom: addZoom === true,
|
|
187
|
-
}),
|
|
188
|
-
});
|
|
189
|
-
if (result.id) {
|
|
190
|
-
calEvent.id = `google-${result.id}`;
|
|
191
|
-
calEvent.googleEventId = result.id;
|
|
192
|
-
}
|
|
193
|
-
if (result.htmlLink) calEvent.htmlLink = result.htmlLink;
|
|
194
|
-
if (result.meetLink) calEvent.hangoutLink = result.meetLink;
|
|
195
|
-
if (result.conferenceData) calEvent.conferenceData = result.conferenceData;
|
|
196
|
-
if (zoomMeetingLink) calEvent.meetingLink = zoomMeetingLink;
|
|
197
|
-
|
|
198
|
-
try {
|
|
199
|
-
emit(
|
|
200
|
-
"calendar.event.created",
|
|
201
|
-
{
|
|
202
|
-
eventId: calEvent.id,
|
|
203
|
-
title: calEvent.title || eventBody.title || "",
|
|
204
|
-
startTime: calEvent.start,
|
|
205
|
-
endTime: calEvent.end,
|
|
206
|
-
attendees: calEvent.attendees ?? [],
|
|
207
|
-
createdBy: email,
|
|
208
|
-
},
|
|
209
|
-
{ owner: email },
|
|
210
|
-
);
|
|
211
|
-
} catch {
|
|
212
|
-
// best-effort
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
setResponseStatus(event, 201);
|
|
216
|
-
return calEvent;
|
|
217
|
-
} catch (error: any) {
|
|
218
|
-
return handleError(event, error);
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
|
|
222
59
|
export const rsvpEvent = defineEventHandler(async (event: H3Event) => {
|
|
223
60
|
try {
|
|
224
61
|
const email = await uEmail(event);
|
|
@@ -74,6 +74,26 @@ async function resolveManagedCalendarClient(): Promise<ManagedCalendarClient | n
|
|
|
74
74
|
return { email: credential.accountId, accessToken: credential.accessToken };
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
/**
|
|
78
|
+
* A workspace connection can be registered and marked "connected" while its
|
|
79
|
+
* token still can't be resolved (revoked, mid-authorization, misconfigured
|
|
80
|
+
* credential). Callers that only need a yes/no read of connection status must
|
|
81
|
+
* see that as "not connected", not as a thrown error — otherwise a single
|
|
82
|
+
* flaky managed-token resolution turns every read action (list-events
|
|
83
|
+
* included) into a 500 instead of the same not-connected state the UI already
|
|
84
|
+
* shows.
|
|
85
|
+
*/
|
|
86
|
+
async function resolveManagedCalendarClientOrNull(): Promise<ManagedCalendarClient | null> {
|
|
87
|
+
try {
|
|
88
|
+
return await resolveManagedCalendarClient();
|
|
89
|
+
} catch {
|
|
90
|
+
// coercion-ok: null is the same typed "not connected" result callers
|
|
91
|
+
// already get for "no managed connection configured" - isConnected and
|
|
92
|
+
// getConnectedAccounts never distinguish it from a genuine read success.
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
77
97
|
const SCOPES = [
|
|
78
98
|
"https://www.googleapis.com/auth/calendar.readonly",
|
|
79
99
|
"https://www.googleapis.com/auth/calendar.events",
|
|
@@ -975,7 +995,20 @@ export async function getClientsForAccountsWithErrors(
|
|
|
975
995
|
(account) => hasCalendarScope(account.tokens),
|
|
976
996
|
);
|
|
977
997
|
if (accounts.length === 0) {
|
|
978
|
-
|
|
998
|
+
// Unlike isConnected()/getAuthStatus() - plain status reads with nowhere
|
|
999
|
+
// to put a reason - this function already has an `errors` channel its
|
|
1000
|
+
// callers (listEvents, listGoogleCalendars) use to distinguish an empty
|
|
1001
|
+
// calendar from a read failure. Preserve the failure there instead of
|
|
1002
|
+
// coercing it into the same silent-empty shape as "no managed connection
|
|
1003
|
+
// configured", matching the sibling fallback in getClientsWithErrors.
|
|
1004
|
+
let managed: ManagedCalendarClient | null = null;
|
|
1005
|
+
let managedError: string | undefined;
|
|
1006
|
+
try {
|
|
1007
|
+
managed = await resolveManagedCalendarClient();
|
|
1008
|
+
} catch (err: any) {
|
|
1009
|
+
managedError =
|
|
1010
|
+
err?.message || "Workspace Google Calendar connection failed";
|
|
1011
|
+
}
|
|
979
1012
|
if (!managed) {
|
|
980
1013
|
if (accountEmails?.length) {
|
|
981
1014
|
throw new Error(
|
|
@@ -984,7 +1017,9 @@ export async function getClientsForAccountsWithErrors(
|
|
|
984
1017
|
}
|
|
985
1018
|
return {
|
|
986
1019
|
clients: [],
|
|
987
|
-
errors:
|
|
1020
|
+
errors: managedError
|
|
1021
|
+
? [{ email: "workspace", error: managedError }]
|
|
1022
|
+
: [],
|
|
988
1023
|
requestedAccounts: [],
|
|
989
1024
|
resolvedAccounts: [],
|
|
990
1025
|
};
|
|
@@ -1225,7 +1260,7 @@ export async function isConnected(forEmail?: string): Promise<boolean> {
|
|
|
1225
1260
|
if (!forEmail) return false;
|
|
1226
1261
|
const accounts = await listOAuthAccountsByOwner("google", forEmail);
|
|
1227
1262
|
if (accounts.some((account) => hasCalendarScope(account.tokens))) return true;
|
|
1228
|
-
return Boolean(await
|
|
1263
|
+
return Boolean(await resolveManagedCalendarClientOrNull());
|
|
1229
1264
|
}
|
|
1230
1265
|
|
|
1231
1266
|
export async function getConnectedAccounts(
|
|
@@ -1236,7 +1271,7 @@ export async function getConnectedAccounts(
|
|
|
1236
1271
|
(account) => hasCalendarScope(account.tokens),
|
|
1237
1272
|
);
|
|
1238
1273
|
if (accounts.length > 0) return accounts.map((a) => a.accountId);
|
|
1239
|
-
const managed = await
|
|
1274
|
+
const managed = await resolveManagedCalendarClientOrNull();
|
|
1240
1275
|
return managed ? [managed.email] : [];
|
|
1241
1276
|
}
|
|
1242
1277
|
|
|
@@ -1276,7 +1311,7 @@ export async function getAuthStatus(
|
|
|
1276
1311
|
);
|
|
1277
1312
|
|
|
1278
1313
|
if (oauthAccounts.length === 0) {
|
|
1279
|
-
const managed = await
|
|
1314
|
+
const managed = await resolveManagedCalendarClientOrNull();
|
|
1280
1315
|
return managed
|
|
1281
1316
|
? { connected: true, accounts: [{ email: managed.email, shared: true }] }
|
|
1282
1317
|
: { connected: false, accounts: [] };
|
|
@@ -3,6 +3,24 @@
|
|
|
3
3
|
All notable user-facing changes to Clips are documented here. Open it any time
|
|
4
4
|
from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-09-25
|
|
7
|
+
|
|
8
|
+
### Improved
|
|
9
|
+
|
|
10
|
+
- Shared clips remember your sidebar choice and help new viewers understand why to sign up.
|
|
11
|
+
|
|
12
|
+
## 2026-09-24
|
|
13
|
+
|
|
14
|
+
### Improved
|
|
15
|
+
|
|
16
|
+
- Recording actions are easier to find and align clearly.
|
|
17
|
+
- Share links appear after uploads finish, when clips are ready to view.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Signed-in viewers see shared recordings in the Clips app shell with library breadcrumbs.
|
|
22
|
+
- The camera bubble stays visible while you reposition it before recording, then the popover resumes its inactive auto-hide after the drag ends.
|
|
23
|
+
|
|
6
24
|
## 2026-09-23
|
|
7
25
|
|
|
8
26
|
### Improved
|
|
@@ -359,6 +359,10 @@ const messages = {
|
|
|
359
359
|
downloadForWindows: "Download for Windows",
|
|
360
360
|
downloadForLinux: "Download for Linux",
|
|
361
361
|
downloadDesktopApp: "Download desktop app",
|
|
362
|
+
commentSignupTitle: "Give your AI agent the full picture",
|
|
363
|
+
commentSignupContext: "Share transcript and timestamped frames in one link",
|
|
364
|
+
commentSignupFeedback: "Turn recorded feedback into clear next steps",
|
|
365
|
+
commentSignupDebug: "Capture console errors and failed requests",
|
|
362
366
|
agentEmptyTitle: "Join the conversation",
|
|
363
367
|
agentEmptyDescription:
|
|
364
368
|
"Create a free Clips account to comment, react, and ask about this clip.",
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
DefaultSpinner,
|
|
18
18
|
EnvironmentBadge,
|
|
19
19
|
} from "@agent-native/core/client/ui";
|
|
20
|
+
import { usePersistentSidebarCollapsed } from "@agent-native/toolkit/app-shell";
|
|
20
21
|
import {
|
|
21
22
|
IconAlertTriangle,
|
|
22
23
|
IconDeviceDesktop,
|
|
@@ -543,7 +544,10 @@ export default function ShareRoute() {
|
|
|
543
544
|
// viewer. Its own tab strip is the only panel navigation; the page toolbar
|
|
544
545
|
// stays focused on recording actions.
|
|
545
546
|
const [panel, setPanel] = useState<SharePanel>("comments");
|
|
546
|
-
const
|
|
547
|
+
const { collapsed: sidePanelCollapsed, setCollapsed: setSidePanelCollapsed } =
|
|
548
|
+
usePersistentSidebarCollapsed({
|
|
549
|
+
storageKey: "clips:share-sidebar-collapsed",
|
|
550
|
+
});
|
|
547
551
|
const [descriptionExpanded, setDescriptionExpanded] = useState(false);
|
|
548
552
|
const commentsSectionRef = useRef<HTMLElement | null>(null);
|
|
549
553
|
const selectCommentsPanel = useCallback(() => {
|
|
@@ -555,7 +559,7 @@ export default function ShareRoute() {
|
|
|
555
559
|
block: "start",
|
|
556
560
|
});
|
|
557
561
|
});
|
|
558
|
-
}, []);
|
|
562
|
+
}, [setSidePanelCollapsed]);
|
|
559
563
|
const [downloading, setDownloading] = useState(false);
|
|
560
564
|
const [accessRequestSent, setAccessRequestSent] = useState(false);
|
|
561
565
|
const [accessRequestError, setAccessRequestError] = useState<string | null>(
|
|
@@ -1837,32 +1841,49 @@ export default function ShareRoute() {
|
|
|
1837
1841
|
ref={commentsSectionRef}
|
|
1838
1842
|
className="flex min-h-0 flex-1 flex-col overflow-hidden px-3 pb-3 pt-2"
|
|
1839
1843
|
>
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1844
|
+
{!session &&
|
|
1845
|
+
sessionStatus !== "loading" &&
|
|
1846
|
+
sessionStatus !== "signing-out" &&
|
|
1847
|
+
comments.length === 0 ? (
|
|
1848
|
+
<PublicCommentsEmptyState
|
|
1849
|
+
signInHref={signInHref}
|
|
1850
|
+
onSignUp={() => {
|
|
1851
|
+
fireShareCtaClick("signup");
|
|
1852
|
+
openCreateAccount("comment");
|
|
1853
|
+
}}
|
|
1854
|
+
onSignIn={() => fireShareCtaClick("signin")}
|
|
1855
|
+
/>
|
|
1856
|
+
) : (
|
|
1857
|
+
<CommentsPanel
|
|
1858
|
+
recordingId={recording.id}
|
|
1859
|
+
comments={comments}
|
|
1860
|
+
currentMs={playbackMs}
|
|
1861
|
+
getCurrentMs={resolvePlaybackMs}
|
|
1862
|
+
currentUserEmail={session?.email}
|
|
1863
|
+
currentUserName={session?.name}
|
|
1864
|
+
enableComments={recording.enableComments}
|
|
1865
|
+
canComment={viewerCanComment}
|
|
1866
|
+
onSeek={(ms) => playerRef.current?.seek(ms)}
|
|
1867
|
+
onUnauthenticated={requireSignIn}
|
|
1868
|
+
queryKey={[
|
|
1869
|
+
"public-recording",
|
|
1870
|
+
shareId,
|
|
1871
|
+
password,
|
|
1872
|
+
agentAccessToken,
|
|
1873
|
+
session?.email ?? null,
|
|
1874
|
+
]}
|
|
1875
|
+
selectComments={(d: any) => d?.data?.comments}
|
|
1876
|
+
applyComments={(d: any, next) =>
|
|
1877
|
+
d
|
|
1878
|
+
? {
|
|
1879
|
+
...d,
|
|
1880
|
+
data: { ...(d.data ?? {}), comments: next },
|
|
1881
|
+
}
|
|
1882
|
+
: d
|
|
1883
|
+
}
|
|
1884
|
+
presentation="inline"
|
|
1885
|
+
/>
|
|
1886
|
+
)}
|
|
1866
1887
|
</section>
|
|
1867
1888
|
</TabsContent>
|
|
1868
1889
|
) : null}
|
|
@@ -2010,6 +2031,67 @@ function formatRecordedOn(
|
|
|
2010
2031
|
}).format(date);
|
|
2011
2032
|
}
|
|
2012
2033
|
|
|
2034
|
+
function PublicCommentsEmptyState({
|
|
2035
|
+
signInHref,
|
|
2036
|
+
onSignUp,
|
|
2037
|
+
onSignIn,
|
|
2038
|
+
}: {
|
|
2039
|
+
signInHref: string;
|
|
2040
|
+
onSignUp: () => void;
|
|
2041
|
+
onSignIn: () => void;
|
|
2042
|
+
}) {
|
|
2043
|
+
const t = useT();
|
|
2044
|
+
|
|
2045
|
+
return (
|
|
2046
|
+
<div className="mx-auto flex min-h-0 w-full max-w-md flex-1 flex-col justify-center gap-5 overflow-y-auto px-5 py-6">
|
|
2047
|
+
<div className="flex size-10 items-center justify-center rounded-lg bg-primary/10 text-primary">
|
|
2048
|
+
<IconDeviceDesktop aria-hidden="true" className="size-5" />
|
|
2049
|
+
</div>
|
|
2050
|
+
<h2 className="text-base font-semibold tracking-tight">
|
|
2051
|
+
{t("sharePage.commentSignupTitle")}
|
|
2052
|
+
</h2>
|
|
2053
|
+
<ul className="space-y-3 text-sm leading-5 text-muted-foreground">
|
|
2054
|
+
<li className="flex items-start gap-3">
|
|
2055
|
+
<span
|
|
2056
|
+
aria-hidden="true"
|
|
2057
|
+
className="mt-2 size-1.5 shrink-0 rounded-full bg-primary"
|
|
2058
|
+
/>
|
|
2059
|
+
<span>{t("sharePage.commentSignupContext")}</span>
|
|
2060
|
+
</li>
|
|
2061
|
+
<li className="flex items-start gap-3">
|
|
2062
|
+
<span
|
|
2063
|
+
aria-hidden="true"
|
|
2064
|
+
className="mt-2 size-1.5 shrink-0 rounded-full bg-primary"
|
|
2065
|
+
/>
|
|
2066
|
+
<span>{t("sharePage.commentSignupFeedback")}</span>
|
|
2067
|
+
</li>
|
|
2068
|
+
<li className="flex items-start gap-3">
|
|
2069
|
+
<span
|
|
2070
|
+
aria-hidden="true"
|
|
2071
|
+
className="mt-2 size-1.5 shrink-0 rounded-full bg-primary"
|
|
2072
|
+
/>
|
|
2073
|
+
<span>{t("sharePage.commentSignupDebug")}</span>
|
|
2074
|
+
</li>
|
|
2075
|
+
</ul>
|
|
2076
|
+
<div className="space-y-3">
|
|
2077
|
+
<Button type="button" className="w-full" onClick={onSignUp}>
|
|
2078
|
+
{t("signInPrompt.createAccount")}
|
|
2079
|
+
</Button>
|
|
2080
|
+
<p className="text-center text-xs text-muted-foreground">
|
|
2081
|
+
{t("sharePage.agentEmptySignInPrompt")}{" "}
|
|
2082
|
+
<a
|
|
2083
|
+
href={signInHref}
|
|
2084
|
+
onClick={onSignIn}
|
|
2085
|
+
className="font-medium text-foreground underline underline-offset-4 hover:no-underline"
|
|
2086
|
+
>
|
|
2087
|
+
{t("signInPrompt.signIn")}
|
|
2088
|
+
</a>
|
|
2089
|
+
</p>
|
|
2090
|
+
</div>
|
|
2091
|
+
</div>
|
|
2092
|
+
);
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2013
2095
|
function PublicAgentEmptyState({
|
|
2014
2096
|
signupHref,
|
|
2015
2097
|
signInHref,
|
|
@@ -27,6 +27,10 @@ time from the command menu (Cmd+K → "What's new").
|
|
|
27
27
|
|
|
28
28
|
## 2026-09-21
|
|
29
29
|
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- Choose Tabler icons, any emoji, or uploaded images for pages, collections, properties, views, callouts, and workspaces.
|
|
33
|
+
|
|
30
34
|
### Improved
|
|
31
35
|
|
|
32
36
|
- Search now ranks exact and partial title matches above incidental matches in document bodies.
|
|
@@ -3,14 +3,44 @@
|
|
|
3
3
|
All notable user-facing changes to Design are documented here. Open it any time
|
|
4
4
|
from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-09-25
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- Cross-screen moves preserve Flex and Grid sizing through undo and redo.
|
|
11
|
+
- Moving a layer from one live app screen into another now lands it instead of failing with "Could not move that layer", and a failed move no longer leaves the layer stuck to the cursor.
|
|
12
|
+
|
|
6
13
|
## 2026-09-24
|
|
7
14
|
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- CSS margins can be adjusted on the canvas and in the layout inspector.
|
|
18
|
+
- Organization admins can review agent runs and summarize linked designs, slide decks, and analytics from Settings.
|
|
19
|
+
- Resized vectors can be point-edited, and the K scale tool shows a Scale section with a live factor.
|
|
20
|
+
- Share editable live canvases and apply collaborators' visual changes
|
|
21
|
+
|
|
8
22
|
### Improved
|
|
9
23
|
|
|
24
|
+
- A vector's stroke row shows Position beside Weight instead of a lone Weight field.
|
|
25
|
+
- Design reviews show the real canvas beside its conversation.
|
|
26
|
+
- Local visual edits stay scoped to the right design and recover cleanly when a screen reloads.
|
|
10
27
|
- Pasted images now expose their sizing and adjustment controls in the inspector
|
|
11
28
|
|
|
12
29
|
### Fixed
|
|
13
30
|
|
|
31
|
+
- Double-clicking text or a vector on the board starts editing it, and clicking empty canvas deselects it.
|
|
32
|
+
- Interact opens a focused responsive preview without reloading the running design.
|
|
33
|
+
- Interrupted cross-screen moves now restore the layer and leave the canvas ready for the next edit.
|
|
34
|
+
- Keep gradient values visible and limit canvas paints to supported backgrounds
|
|
35
|
+
- Open pen paths no longer paint a filled triangle after Shift+X, matching Figma.
|
|
36
|
+
- Open Pen paths preserve their fill opacity when you finish editing them.
|
|
37
|
+
- Pen path edits save without being blocked by delayed local retry storage.
|
|
38
|
+
- Re-clicking the active responsive preview returns to the canvas even with pending edits
|
|
39
|
+
- SVG paste handles mixed-case markup safely and preserves opacity edits on open Pen paths
|
|
40
|
+
- SVG pastes keep valid namespace and fill data, and closing open paths preserves authored transparency.
|
|
41
|
+
- Text selection remains available during line-height editing, and pasted SVGs have unsafe external styles removed.
|
|
42
|
+
- Visual edit handoffs now accept current edit revisions reliably
|
|
43
|
+
- While editing text, click to place the caret and double-click a word to restyle just that word.
|
|
14
44
|
- Editing a vector path preserves its fill and stroke when reopened or closed.
|
|
15
45
|
- Pasted images, SVGs, and Design layers preserve more of their original content and placement.
|
|
16
46
|
|
|
@@ -7,8 +7,20 @@ time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
|
7
7
|
|
|
8
8
|
### Improved
|
|
9
9
|
|
|
10
|
+
- Add an All inbox tab that shows every inbox thread and can be hidden in tab settings.
|
|
11
|
+
- Priority sort keeps results when switching inbox tabs, and loading tabs show a skeleton
|
|
12
|
+
- The composer keeps its taller layout in a narrower window.
|
|
10
13
|
- The compose window opens larger, leaving more room to write with quieter toolbar icons.
|
|
11
14
|
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Gmail inboxes refresh reliably when push notifications are delayed.
|
|
18
|
+
- Priority sorting stays in place when you return to the inbox
|
|
19
|
+
|
|
20
|
+
### Security
|
|
21
|
+
|
|
22
|
+
- Mail automations no longer fall back to shared deployment LLM keys; connect a provider in Settings to enable them.
|
|
23
|
+
|
|
12
24
|
## 2026-09-23
|
|
13
25
|
|
|
14
26
|
### Improved
|
|
@@ -3,6 +3,30 @@
|
|
|
3
3
|
All notable user-facing changes to Agent-Native Slides are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new").
|
|
5
5
|
|
|
6
|
+
## 2026-09-25
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- Word document imports now complete successfully.
|
|
11
|
+
|
|
12
|
+
## 2026-09-24
|
|
13
|
+
|
|
14
|
+
### Improved
|
|
15
|
+
|
|
16
|
+
- Slides completes multi-slide edits with fewer rounds of work
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Answering or skipping setup questions keeps deck generation in its original chat.
|
|
21
|
+
- Deck generation progress follows its own run instead of unrelated chats.
|
|
22
|
+
- Editing text on a slide no longer rewrites or restyles the rest of the slide, and clicking into text without typing no longer saves anything. Clicking text on a Markdown-layout slide no longer converts the slide to HTML; ask the agent to edit that text for now.
|
|
23
|
+
- Guided questions stay available when a deck continuation cannot be delivered.
|
|
24
|
+
- Restyling slides preserves their text and layout
|
|
25
|
+
|
|
26
|
+
### Security
|
|
27
|
+
|
|
28
|
+
- Slides image generation uses credentials saved for your account or workspace, not a shared deployment key.
|
|
29
|
+
|
|
6
30
|
## 2026-09-23
|
|
7
31
|
|
|
8
32
|
### Improved
|
|
@@ -11,6 +35,8 @@ time from the command menu (Cmd+K → "What's new").
|
|
|
11
35
|
|
|
12
36
|
### Fixed
|
|
13
37
|
|
|
38
|
+
- Decks opened from a link or reload no longer get stuck on the generating screen when no generation is running
|
|
39
|
+
- Decks with no design system now follow a theme chosen for their subject instead of a fixed default palette
|
|
14
40
|
- Deck access errors leave the loading state and explain that the deck is unavailable.
|
|
15
41
|
- Slide chat follows the current selection, and loaded slides remain visible when a background refresh fails
|
|
16
42
|
- Slides home retries failed deck-list reads sooner.
|
|
@@ -186,8 +186,8 @@ export declare function createAutomationCallbackHandler(runtime: AutomationRunti
|
|
|
186
186
|
duplicate?: undefined;
|
|
187
187
|
eventId?: undefined;
|
|
188
188
|
} | {
|
|
189
|
+
error?: undefined;
|
|
189
190
|
accepted: boolean;
|
|
190
191
|
duplicate: boolean;
|
|
191
192
|
eventId: string;
|
|
192
|
-
error?: undefined;
|
|
193
193
|
}>;
|
|
@@ -483,9 +483,11 @@ export function shouldStartWithLocalDev(pathname, search) {
|
|
|
483
483
|
!path.endsWith("/sign-in"));
|
|
484
484
|
}
|
|
485
485
|
export function AuthPage(props) {
|
|
486
|
-
const { authMode, googleOnly, initialPrompt, appBasePath, homePath, workspaceRuntime, trackingApp, defaultLocale, localeStorageKey, locales, localeMetadata, localeOptions, marketing, marketingLocales, brandMarkSrc, brandMarkLightSrc, githubUrl, showGoogle, organizationSsoEnabled = false, googleViaIdentitySso = false, signupLegalNotice, signupLocalModeNote, docsAuthUrl, identitySsoEnabled = false, identitySsoAuto = false, publicOAuthOrigin, workspaceGatewayReturnOrigin, googleAuthMode, builderPreviewLocalDevEnabled, } = props;
|
|
486
|
+
const { authMode, googleOnly, initialPrompt, appBasePath, homePath, initialResumeHref, workspaceRuntime, trackingApp, defaultLocale, localeStorageKey, locales, localeMetadata, localeOptions, marketing, marketingLocales, brandMarkSrc, brandMarkLightSrc, githubUrl, showGoogle, organizationSsoEnabled = false, googleViaIdentitySso = false, signupLegalNotice, signupLocalModeNote, docsAuthUrl, identitySsoEnabled = false, identitySsoAuto = false, publicOAuthOrigin, workspaceGatewayReturnOrigin, googleAuthMode, builderPreviewLocalDevEnabled, } = props;
|
|
487
487
|
const [localePreference, setLocalePreference] = React.useState("system");
|
|
488
488
|
const [locale, setLocale] = React.useState(defaultLocale);
|
|
489
|
+
const [browserLocationReady, setBrowserLocationReady] = React.useState(false);
|
|
490
|
+
React.useEffect(() => setBrowserLocationReady(true), []);
|
|
489
491
|
const [localeMenuOpen, setLocaleMenuOpen] = React.useState(false);
|
|
490
492
|
const [view, setView] = React.useState(props.initialView);
|
|
491
493
|
const [messages, setMessages] = React.useState({});
|
|
@@ -544,9 +546,9 @@ export function AuthPage(props) {
|
|
|
544
546
|
const apiPath = React.useCallback((path) => `${runtimeAppBasePath}${toPublicFrameworkPath(path, { publicPrefix: frameworkRoutePrefix() })}`, [runtimeAppBasePath]);
|
|
545
547
|
const identityHref = React.useMemo(() => apiPath("/_agent-native/identity/login"), [apiPath]);
|
|
546
548
|
const journey = React.useCallback(() => {
|
|
547
|
-
if (typeof window === "undefined") {
|
|
549
|
+
if (typeof window === "undefined" || !browserLocationReady) {
|
|
548
550
|
return signInJourney({
|
|
549
|
-
at: `${runtimeAppBasePath}/`,
|
|
551
|
+
at: initialResumeHref ?? `${runtimeAppBasePath}/`,
|
|
550
552
|
basePath: runtimeAppBasePath,
|
|
551
553
|
homePath,
|
|
552
554
|
});
|
|
@@ -560,8 +562,9 @@ export function AuthPage(props) {
|
|
|
560
562
|
basePath: runtimeAppBasePath,
|
|
561
563
|
homePath,
|
|
562
564
|
});
|
|
563
|
-
}, [homePath, runtimeAppBasePath]);
|
|
565
|
+
}, [browserLocationReady, homePath, initialResumeHref, runtimeAppBasePath]);
|
|
564
566
|
const resumeHref = React.useCallback(() => journey().resumeHref, [journey]);
|
|
567
|
+
const identityLoginHref = React.useMemo(() => `${identityHref}?${new URLSearchParams({ return: resumeHref() }).toString()}`, [identityHref, resumeHref]);
|
|
565
568
|
const identityBootstrapHref = React.useCallback((target) => {
|
|
566
569
|
const safeTarget = target || resumeHref();
|
|
567
570
|
if (!identitySsoEnabled || isAgentNativeDesktop())
|
|
@@ -1976,6 +1979,9 @@ export function AuthPage(props) {
|
|
|
1976
1979
|
? false
|
|
1977
1980
|
: shouldHideAuthSubtitle(view, localDevAvailable) }, usesMarketingWelcome ? t("welcomeSubtitle") : t(keys.subtitle)),
|
|
1978
1981
|
React.createElement("p", { className: `upgrade-note ${upgradeVisible ? "show" : ""}`, id: "upgrade-note", "data-upgrade-copy": t("upgradeCopy"), "data-i18n-data-upgrade-copy": "upgradeCopy" }, upgradeVisible ? t("upgradeCopy") : null),
|
|
1982
|
+
identitySsoEnabled && !googleOnly ? (React.createElement("div", { className: "identity-sso-entry", id: "identity-sso-entry" },
|
|
1983
|
+
React.createElement("a", { className: "btn-primary btn-identity-sso", id: "identity-sso-btn", href: identityLoginHref, "aria-describedby": "identity-sso-hint", "data-i18n": "continueWithAgentNative" }, t("continueWithAgentNative")),
|
|
1984
|
+
React.createElement("p", { className: "identity-sso-hint", id: "identity-sso-hint", "data-i18n": "identitySsoHint" }, t("identitySsoHint")))) : null,
|
|
1979
1985
|
React.createElement("div", { className: "local-dev-signin", id: "local-dev-signin", hidden: !localDevAvailable },
|
|
1980
1986
|
React.createElement("button", { type: "button", className: "btn-local-dev btn-primary", id: "local-dev-btn", title: t("localDevDescription"), "data-i18n": "localDevButton", "data-i18n-title": "localDevDescription", "aria-describedby": "local-dev-description", disabled: localDevBusy, onClick: () => void handleLocalDev() }, localDevBusy ? t("localDevSigningIn") : t("localDevButton")),
|
|
1981
1987
|
React.createElement("p", { className: "local-dev-description", id: "local-dev-description" },
|
|
@@ -10,7 +10,7 @@ export interface OrgSwitcherProps {
|
|
|
10
10
|
className?: string;
|
|
11
11
|
/** Hide entirely when the user only belongs to one org. Default: false. */
|
|
12
12
|
hideWhenSingle?: boolean;
|
|
13
|
-
/** Keep the switcher's
|
|
13
|
+
/** Keep the switcher's slot reserved when there is no organization to show. */
|
|
14
14
|
reserveSpace?: boolean;
|
|
15
15
|
/**
|
|
16
16
|
* Icon-only trigger for collapsed sidebar rails. The popover — and with it
|
|
@@ -42,8 +42,8 @@ function organizationSettingsPath(path) {
|
|
|
42
42
|
function ReservedOrgSwitcherSpace({ className }) {
|
|
43
43
|
return _jsx("div", { "aria-hidden": "true", className: `h-8 ${className ?? ""}` });
|
|
44
44
|
}
|
|
45
|
-
function OrgSwitcherLoadingPlaceholder({ className }) {
|
|
46
|
-
return (
|
|
45
|
+
function OrgSwitcherLoadingPlaceholder({ className, compact, }) {
|
|
46
|
+
return (_jsx("button", { type: "button", disabled: true, "aria-label": "Loading organization", className: `${compact ? COMPACT_SWITCHER_BUTTON_CLASS : SWITCHER_BUTTON_CLASS} animate-pulse ${className ?? ""}`, children: compact ? (_jsx("span", { className: "size-3.5 rounded-sm bg-muted-foreground/20" })) : (_jsxs(_Fragment, { children: [_jsx(IconBriefcase, { className: "h-3.5 w-3.5 shrink-0 opacity-60" }), _jsx("span", { className: "h-3 min-w-0 flex-1 rounded-sm bg-muted-foreground/20" }), _jsx(IconSelector, { className: "h-3 w-3 shrink-0 opacity-30" })] })) }));
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
49
49
|
* Compact org switcher button. Shows the active org (or "Personal" when the
|
|
@@ -83,7 +83,7 @@ export function OrgSwitcher({ className, hideWhenSingle, reserveSpace, compact,
|
|
|
83
83
|
await signOut();
|
|
84
84
|
};
|
|
85
85
|
if (!org) {
|
|
86
|
-
return
|
|
86
|
+
return isLoading ? (_jsx(OrgSwitcherLoadingPlaceholder, { className: className, compact: compact })) : null;
|
|
87
87
|
}
|
|
88
88
|
const orgs = org.orgs ?? [];
|
|
89
89
|
const pendingInvitations = org.pendingInvitations ?? [];
|
|
@@ -44,9 +44,9 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
44
44
|
url: string;
|
|
45
45
|
id: string;
|
|
46
46
|
provider: string;
|
|
47
|
-
error?: undefined;
|
|
48
47
|
configured?: undefined;
|
|
49
48
|
connectPath?: undefined;
|
|
49
|
+
error?: undefined;
|
|
50
50
|
} | {
|
|
51
51
|
url?: undefined;
|
|
52
52
|
id?: undefined;
|
|
@@ -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;
|
|
15
14
|
count: number;
|
|
16
15
|
updated?: undefined;
|
|
16
|
+
error?: undefined;
|
|
17
17
|
ok?: undefined;
|
|
18
18
|
} | {
|
|
19
|
-
error?: undefined;
|
|
20
19
|
count?: undefined;
|
|
21
20
|
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;
|
|
30
29
|
count?: undefined;
|
|
31
30
|
updated?: undefined;
|
|
31
|
+
error?: undefined;
|
|
32
32
|
ok: boolean;
|
|
33
33
|
}>>;
|
package/dist/secrets/routes.d.ts
CHANGED
|
@@ -60,17 +60,17 @@ export declare function createWriteSecretHandler(): import("h3").EventHandlerWit
|
|
|
60
60
|
ok?: undefined;
|
|
61
61
|
status?: undefined;
|
|
62
62
|
} | {
|
|
63
|
+
error?: undefined;
|
|
63
64
|
ok: boolean;
|
|
64
65
|
status: string;
|
|
65
|
-
error?: undefined;
|
|
66
66
|
} | {
|
|
67
67
|
ok?: undefined;
|
|
68
68
|
error: string;
|
|
69
69
|
removed?: undefined;
|
|
70
70
|
} | {
|
|
71
|
+
error?: undefined;
|
|
71
72
|
ok: boolean;
|
|
72
73
|
removed: boolean;
|
|
73
|
-
error?: undefined;
|
|
74
74
|
}>>;
|
|
75
75
|
/**
|
|
76
76
|
* POST /_agent-native/secrets/:key/test — validate an optional candidate value
|
|
@@ -81,13 +81,13 @@ export declare function createTestSecretHandler(): import("h3").EventHandlerWith
|
|
|
81
81
|
error: string;
|
|
82
82
|
note?: undefined;
|
|
83
83
|
} | {
|
|
84
|
+
error?: undefined;
|
|
84
85
|
ok: boolean;
|
|
85
86
|
note?: undefined;
|
|
86
|
-
error?: undefined;
|
|
87
87
|
} | {
|
|
88
|
+
error?: undefined;
|
|
88
89
|
ok: boolean;
|
|
89
90
|
note: string;
|
|
90
|
-
error?: undefined;
|
|
91
91
|
} | {
|
|
92
92
|
note?: undefined;
|
|
93
93
|
ok: boolean;
|
|
@@ -119,11 +119,11 @@ export interface AdHocSecretPayload {
|
|
|
119
119
|
export declare function createAdHocSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<AdHocSecretPayload[] | {
|
|
120
120
|
error: string;
|
|
121
121
|
} | {
|
|
122
|
+
error?: undefined;
|
|
122
123
|
ok: boolean;
|
|
123
124
|
key: string;
|
|
124
|
-
error?: undefined;
|
|
125
125
|
} | {
|
|
126
|
+
error?: undefined;
|
|
126
127
|
ok: boolean;
|
|
127
128
|
removed: boolean;
|
|
128
|
-
error?: undefined;
|
|
129
129
|
}>>;
|
|
@@ -17,6 +17,7 @@ import { NATIVE_AUTH_COPY } from "../shared/auth-copy.js";
|
|
|
17
17
|
import { docsUrl } from "../shared/docs-url.js";
|
|
18
18
|
import { BETA_FORCE_QUERY_PARAM, BETA_FORCE_SESSION_STORAGE_KEY, BETA_OPT_OUT_DURATION_MS, BETA_OPT_OUT_QUERY_PARAM, BETA_OPT_OUT_STORAGE_KEY, ENVIRONMENT_BETA_HOSTS, } from "../shared/environment-lanes.js";
|
|
19
19
|
import { PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, } from "../shared/password-policy.js";
|
|
20
|
+
import { signInJourney } from "../shared/sign-in-journey.js";
|
|
20
21
|
import { AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, withAgentNativeSocialImageCacheBuster, } from "../shared/social-meta.js";
|
|
21
22
|
import { getAppBasePathFromViteEnv, normalizeAppBasePath, } from "./app-base-path.js";
|
|
22
23
|
import { AUTH_MARKETING_LOCALE_COPY, } from "./auth-marketing-locales.js";
|
|
@@ -119,6 +120,8 @@ const EN_AUTH_COPY = {
|
|
|
119
120
|
localDevSigningIn: "Signing in locally…",
|
|
120
121
|
localDevFailed: "Local development sign-in is unavailable.",
|
|
121
122
|
localDevFullOptions: "Show full sign in options",
|
|
123
|
+
continueWithAgentNative: "Continue with Agent-Native",
|
|
124
|
+
identitySsoHint: "Use the same verified email you use in your other Agent-Native apps.",
|
|
122
125
|
openSource: "FREE & OPEN SOURCE",
|
|
123
126
|
learnMore: "Learn more",
|
|
124
127
|
useOwnGoogleClient: "Use your own Google OAuth client:",
|
|
@@ -192,6 +195,8 @@ const AUTH_LOCALE_COPY = {
|
|
|
192
195
|
localDevSigningIn: "正在本地登录…",
|
|
193
196
|
localDevFailed: "本地开发登录不可用。",
|
|
194
197
|
localDevFullOptions: "显示完整登录选项",
|
|
198
|
+
continueWithAgentNative: "使用 Agent-Native 继续",
|
|
199
|
+
identitySsoHint: "使用你在其他 Agent-Native 应用中验证过的相同邮箱。",
|
|
195
200
|
openSource: "100% 免费且开源",
|
|
196
201
|
learnMore: "了解更多",
|
|
197
202
|
useOwnGoogleClient: "使用你自己的 Google OAuth 客户端:",
|
|
@@ -263,6 +268,8 @@ const AUTH_LOCALE_COPY = {
|
|
|
263
268
|
localDevSigningIn: "正在本機登入…",
|
|
264
269
|
localDevFailed: "本機開發登入無法使用。",
|
|
265
270
|
localDevFullOptions: "顯示完整登入選項",
|
|
271
|
+
continueWithAgentNative: "使用 Agent-Native 繼續",
|
|
272
|
+
identitySsoHint: "請使用你在其他 Agent-Native 應用中驗證過的相同電子郵件。",
|
|
266
273
|
openSource: "100% 免費且開源",
|
|
267
274
|
learnMore: "深入瞭解",
|
|
268
275
|
useOwnGoogleClient: "使用你自己的 Google OAuth 用戶端:",
|
|
@@ -334,6 +341,8 @@ const AUTH_LOCALE_COPY = {
|
|
|
334
341
|
localDevSigningIn: "Iniciando sesión localmente…",
|
|
335
342
|
localDevFailed: "El inicio de sesión de desarrollo local no está disponible.",
|
|
336
343
|
localDevFullOptions: "Mostrar todas las opciones de inicio de sesión",
|
|
344
|
+
continueWithAgentNative: "Continuar con Agent-Native",
|
|
345
|
+
identitySsoHint: "Usa el mismo correo verificado que en tus otras apps de Agent-Native.",
|
|
337
346
|
openSource: "100% gratis y de código abierto",
|
|
338
347
|
learnMore: "Más información",
|
|
339
348
|
useOwnGoogleClient: "Usa tu propio cliente de Google OAuth:",
|
|
@@ -405,6 +414,8 @@ const AUTH_LOCALE_COPY = {
|
|
|
405
414
|
localDevSigningIn: "Connexion locale…",
|
|
406
415
|
localDevFailed: "La connexion de développement local est indisponible.",
|
|
407
416
|
localDevFullOptions: "Afficher toutes les options de connexion",
|
|
417
|
+
continueWithAgentNative: "Continuer avec Agent-Native",
|
|
418
|
+
identitySsoHint: "Utilisez la même adresse e-mail vérifiée que dans vos autres applications Agent-Native.",
|
|
408
419
|
openSource: "100 % gratuit et open source",
|
|
409
420
|
learnMore: "En savoir plus",
|
|
410
421
|
useOwnGoogleClient: "Utilisez votre propre client Google OAuth :",
|
|
@@ -476,6 +487,8 @@ const AUTH_LOCALE_COPY = {
|
|
|
476
487
|
localDevSigningIn: "Lokale Anmeldung…",
|
|
477
488
|
localDevFailed: "Die lokale Entwicklungsanmeldung ist nicht verfügbar.",
|
|
478
489
|
localDevFullOptions: "Alle Anmeldeoptionen anzeigen",
|
|
490
|
+
continueWithAgentNative: "Mit Agent-Native fortfahren",
|
|
491
|
+
identitySsoHint: "Verwende dieselbe bestätigte E-Mail-Adresse wie in deinen anderen Agent-Native-Apps.",
|
|
479
492
|
openSource: "100 % kostenlos und Open Source",
|
|
480
493
|
learnMore: "Mehr erfahren",
|
|
481
494
|
useOwnGoogleClient: "Eigenen Google-OAuth-Client verwenden:",
|
|
@@ -547,6 +560,8 @@ const AUTH_LOCALE_COPY = {
|
|
|
547
560
|
localDevSigningIn: "ローカルでサインイン中…",
|
|
548
561
|
localDevFailed: "ローカル開発のサインインは利用できません。",
|
|
549
562
|
localDevFullOptions: "完全なサインイン オプションを表示",
|
|
563
|
+
continueWithAgentNative: "Agent-Native で続行",
|
|
564
|
+
identitySsoHint: "他の Agent-Native アプリで確認済みの同じメールアドレスを使用してください。",
|
|
550
565
|
openSource: "100% 無料でオープンソース",
|
|
551
566
|
learnMore: "詳細を見る",
|
|
552
567
|
useOwnGoogleClient: "自分の Google OAuth クライアントを使用:",
|
|
@@ -618,6 +633,8 @@ const AUTH_LOCALE_COPY = {
|
|
|
618
633
|
localDevSigningIn: "로컬로 로그인하는 중…",
|
|
619
634
|
localDevFailed: "로컬 개발 로그인을 사용할 수 없습니다.",
|
|
620
635
|
localDevFullOptions: "전체 로그인 옵션 보기",
|
|
636
|
+
continueWithAgentNative: "Agent-Native로 계속",
|
|
637
|
+
identitySsoHint: "다른 Agent-Native 앱에서 인증한 것과 같은 이메일 주소를 사용하세요.",
|
|
621
638
|
openSource: "100% 무료 오픈 소스",
|
|
622
639
|
learnMore: "자세히 알아보기",
|
|
623
640
|
useOwnGoogleClient: "내 Google OAuth 클라이언트 사용:",
|
|
@@ -689,6 +706,8 @@ const AUTH_LOCALE_COPY = {
|
|
|
689
706
|
localDevSigningIn: "Entrando localmente…",
|
|
690
707
|
localDevFailed: "O login de desenvolvimento local não está disponível.",
|
|
691
708
|
localDevFullOptions: "Mostrar todas as opções de login",
|
|
709
|
+
continueWithAgentNative: "Continuar com Agent-Native",
|
|
710
|
+
identitySsoHint: "Use o mesmo email verificado nos outros apps Agent-Native.",
|
|
692
711
|
openSource: "100% grátis e open source",
|
|
693
712
|
learnMore: "Saiba mais",
|
|
694
713
|
useOwnGoogleClient: "Use seu próprio cliente Google OAuth:",
|
|
@@ -760,6 +779,8 @@ const AUTH_LOCALE_COPY = {
|
|
|
760
779
|
localDevSigningIn: "स्थानीय रूप से साइन इन हो रहा है…",
|
|
761
780
|
localDevFailed: "स्थानीय विकास साइन-इन उपलब्ध नहीं है।",
|
|
762
781
|
localDevFullOptions: "साइन-इन के सभी विकल्प दिखाएं",
|
|
782
|
+
continueWithAgentNative: "Agent-Native के साथ जारी रखें",
|
|
783
|
+
identitySsoHint: "दूसरे Agent-Native ऐप्स में सत्यापित किया गया वही ईमेल इस्तेमाल करें।",
|
|
763
784
|
openSource: "100% मुफ्त और open source",
|
|
764
785
|
learnMore: "और जानें",
|
|
765
786
|
useOwnGoogleClient: "अपना Google OAuth client उपयोग करें:",
|
|
@@ -831,6 +852,8 @@ const AUTH_LOCALE_COPY = {
|
|
|
831
852
|
localDevSigningIn: "جارٍ تسجيل الدخول محليًا…",
|
|
832
853
|
localDevFailed: "تسجيل دخول التطوير المحلي غير متاح.",
|
|
833
854
|
localDevFullOptions: "عرض خيارات تسجيل الدخول الكاملة",
|
|
855
|
+
continueWithAgentNative: "المتابعة باستخدام Agent-Native",
|
|
856
|
+
identitySsoHint: "استخدم عنوان البريد الإلكتروني نفسه الذي تم التحقق منه في تطبيقات Agent-Native الأخرى.",
|
|
834
857
|
openSource: "مجاني ومفتوح المصدر 100%",
|
|
835
858
|
learnMore: "معرفة المزيد",
|
|
836
859
|
useOwnGoogleClient: "استخدم عميل Google OAuth الخاص بك:",
|
|
@@ -948,6 +971,18 @@ export function getOnboardingHtml(opts = {}) {
|
|
|
948
971
|
const configuredAppBasePath = getAppBasePathFromViteEnv();
|
|
949
972
|
const appBasePath = configuredAppBasePath || workspaceBasePathFromRequest(opts.requestPath);
|
|
950
973
|
const appHomePath = resolveAppHomePath(getAppConfig().app, getAppConfig().workspace);
|
|
974
|
+
const requestUrl = new URL(opts.requestPath || `${appBasePath}/`, "https://agent-native.local");
|
|
975
|
+
const requestPathname = requestUrl.pathname;
|
|
976
|
+
const isRootRequest = requestPathname === appBasePath || requestPathname === `${appBasePath}/`;
|
|
977
|
+
const initialResumeHref = signInJourney({
|
|
978
|
+
at: isRootRequest
|
|
979
|
+
? `${appBasePath}/`
|
|
980
|
+
: `${requestPathname}${requestUrl.search}${requestUrl.hash}`,
|
|
981
|
+
continuation: isRootRequest ? null : requestUrl.searchParams.get("c"),
|
|
982
|
+
legacyReturn: isRootRequest ? null : requestUrl.searchParams.get("return"),
|
|
983
|
+
basePath: appBasePath,
|
|
984
|
+
homePath: appHomePath,
|
|
985
|
+
}).resumeHref;
|
|
951
986
|
const workspaceRuntime = isWorkspaceRuntime();
|
|
952
987
|
const trackingApp = getAppConfig().app.slug ??
|
|
953
988
|
getAppConfig().app.template ??
|
|
@@ -1399,6 +1434,7 @@ export function getOnboardingHtml(opts = {}) {
|
|
|
1399
1434
|
initialView: initialAuthView(opts, authMode, googleOnly),
|
|
1400
1435
|
appBasePath,
|
|
1401
1436
|
homePath: appHomePath,
|
|
1437
|
+
initialResumeHref,
|
|
1402
1438
|
workspaceRuntime,
|
|
1403
1439
|
trackingApp,
|
|
1404
1440
|
defaultLocale: DEFAULT_LOCALE,
|
|
@@ -1694,6 +1730,7 @@ export function getOnboardingHtml(opts = {}) {
|
|
|
1694
1730
|
.card.verifying #google-btn,
|
|
1695
1731
|
.card.verifying #google-err,
|
|
1696
1732
|
.card.verifying #auth-divider,
|
|
1733
|
+
.card.verifying #identity-sso-entry,
|
|
1697
1734
|
.card.verifying #upgrade-note {
|
|
1698
1735
|
display: none;
|
|
1699
1736
|
}
|
|
@@ -1800,6 +1837,24 @@ export function getOnboardingHtml(opts = {}) {
|
|
|
1800
1837
|
.local-dev-full-options[hidden] { display: none; }
|
|
1801
1838
|
.full-auth-options { margin-top: 1rem; }
|
|
1802
1839
|
.full-auth-options[hidden] { display: none; }
|
|
1840
|
+
.identity-sso-entry { margin: 1rem 0; }
|
|
1841
|
+
.btn-identity-sso {
|
|
1842
|
+
display: flex;
|
|
1843
|
+
align-items: center;
|
|
1844
|
+
justify-content: center;
|
|
1845
|
+
min-height: 2.75rem;
|
|
1846
|
+
padding: 0.75rem;
|
|
1847
|
+
text-align: center;
|
|
1848
|
+
text-decoration: none;
|
|
1849
|
+
}
|
|
1850
|
+
.identity-sso-hint {
|
|
1851
|
+
margin: 0.5rem 0 0;
|
|
1852
|
+
color: color-mix(in srgb, currentColor 50%, transparent);
|
|
1853
|
+
font-size: 0.75rem;
|
|
1854
|
+
line-height: 1.45;
|
|
1855
|
+
text-align: center;
|
|
1856
|
+
}
|
|
1857
|
+
html[data-agent-native-embedded="1"] #identity-sso-entry { display: none; }
|
|
1803
1858
|
.sso-signin { margin-top: 0.75rem; }
|
|
1804
1859
|
.legal-note {
|
|
1805
1860
|
margin-top: 0.375rem;
|
|
@@ -1979,6 +2034,7 @@ export function getOnboardingHtml(opts = {}) {
|
|
|
1979
2034
|
.card.magic-link-complete #google-signin,
|
|
1980
2035
|
.card.magic-link-complete #auth-divider,
|
|
1981
2036
|
.card.magic-link-complete #auth-tabs,
|
|
2037
|
+
.card.magic-link-complete #identity-sso-entry,
|
|
1982
2038
|
.card.magic-link-complete #upgrade-note,
|
|
1983
2039
|
.card.magic-link-complete .form {
|
|
1984
2040
|
display: none;
|
|
@@ -49,8 +49,13 @@ eligibility check is unavailable, ordinary per-app sign-in remains available.
|
|
|
49
49
|
|
|
50
50
|
### Server-side federation
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
Canonical Agent-Native sign-in pages expose an explicit **Continue with
|
|
53
|
+
Agent-Native** action. It starts the same short-lived, server-verified protocol
|
|
54
|
+
used by broker and server-side callers. A person with an active Dispatch
|
|
55
|
+
session can continue; otherwise, Dispatch asks them to authenticate there. On
|
|
56
|
+
first use, they may need to establish a Dispatch identity. The target app then
|
|
57
|
+
links or creates its local user using the verified email and issues its own
|
|
58
|
+
session.
|
|
54
59
|
|
|
55
60
|
1. The caller requests an exact registered app binding.
|
|
56
61
|
2. Dispatch authenticates the workspace identity and returns a short-lived,
|
|
@@ -100,10 +105,11 @@ credentials.
|
|
|
100
105
|
|
|
101
106
|
<code>AGENT_NATIVE_IDENTITY_HUB_URL</code> identifies the hub for the
|
|
102
107
|
server-side and browser paths when a self-hosted app needs an explicit Dispatch
|
|
103
|
-
deployment.
|
|
104
|
-
|
|
105
|
-
<code>prompt=none</code>
|
|
106
|
-
|
|
108
|
+
deployment. Exact registered first-party apps can show the explicit browser
|
|
109
|
+
action. The <code>browser.identity-sso</code> rollout flag controls silent
|
|
110
|
+
<code>prompt=none</code> sign-in and post-local-login bootstrap; keep that
|
|
111
|
+
automatic path limited to the selected rollout cohort. The local sign-in form
|
|
112
|
+
remains available as a fallback.
|
|
107
113
|
|
|
108
114
|
For a self-hosted Dispatch deployment, register every custom app with its
|
|
109
115
|
exact app ID, client ID, HTTPS origin, callback path, and
|
|
@@ -138,22 +144,27 @@ After deployment:
|
|
|
138
144
|
|
|
139
145
|
1. Verify that normal email, password, magic-link, and configured provider
|
|
140
146
|
sign-in continue to work in a browser.
|
|
141
|
-
2. With <code>browser.identity-sso</code> off, verify
|
|
142
|
-
With it on, verify the silent
|
|
143
|
-
fallback without introducing a
|
|
147
|
+
2. With <code>browser.identity-sso</code> off, verify the explicit Continue with
|
|
148
|
+
Agent-Native action and ordinary local sign-in. With it on, verify the silent
|
|
149
|
+
<code>prompt=none</code> probe and local-form fallback without introducing a
|
|
150
|
+
wildcard cookie.
|
|
144
151
|
3. If Desktop workspace SSO is enabled, verify one exact registered app from
|
|
145
152
|
the explicit Desktop Settings action.
|
|
146
153
|
4. If organization federation is enabled, verify the exact organization ID
|
|
147
154
|
and membership role in the target app.
|
|
148
155
|
|
|
149
|
-
To roll back the
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
156
|
+
To roll back the silent browser or Desktop path, disable its feature flag. To
|
|
157
|
+
remove the explicit browser action from a self-hosted app, remove
|
|
158
|
+
|
|
159
|
+
<code>AGENT_NATIVE_IDENTITY_HUB_URL</code> or its exact app registration, then
|
|
160
|
+
redeploy. Local sign-in remains available, and additive identity and
|
|
161
|
+
organization records remain intact.
|
|
153
162
|
|
|
154
163
|
## Browser identity SSO rollout runbook
|
|
155
164
|
|
|
156
|
-
The browser path is intentionally a rollout, not a default switch in
|
|
165
|
+
The silent browser path is intentionally a rollout, not a default switch in
|
|
166
|
+
core. The explicit Continue with Agent-Native action is available to exact
|
|
167
|
+
registered first-party clients and does not enable silent sign-in.
|
|
157
168
|
For one canonical `*.agent-native.com` app:
|
|
158
169
|
|
|
159
170
|
1. Keep `browser.identity-sso` disabled for the general population and enable
|
|
@@ -162,7 +173,8 @@ For one canonical `*.agent-native.com` app:
|
|
|
162
173
|
Confirm the silent `prompt=none` probe returns the same verified account and
|
|
163
174
|
that the app lands in its normal local session.
|
|
164
175
|
3. Repeat with no active hub session. Confirm `login_required` returns to the
|
|
165
|
-
ordinary local sign-in form
|
|
176
|
+
ordinary local sign-in form and the explicit action still lets a person
|
|
177
|
+
authenticate with Dispatch when they choose it.
|
|
166
178
|
4. Widen the cohort only after checking that logout and revocation behave as
|
|
167
179
|
expected. The first enablement may require one-time revocation of existing
|
|
168
180
|
sessions so stale local sessions do not mask the probe result.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.188.0
|
|
3
|
+
"version": "0.188.0",
|
|
4
4
|
"description": "The agentic application framework for building autonomous agents with intuitive UIs",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -508,9 +508,9 @@
|
|
|
508
508
|
"yaml": "^2.9.0",
|
|
509
509
|
"yjs": "^13.6.32",
|
|
510
510
|
"zod": "^4.3.6",
|
|
511
|
-
"@agent-native/
|
|
512
|
-
"@agent-native/
|
|
513
|
-
"@agent-native/
|
|
511
|
+
"@agent-native/agentkit": "^0.2.10",
|
|
512
|
+
"@agent-native/recap-cli": "0.5.40",
|
|
513
|
+
"@agent-native/toolkit": "^0.21.0"
|
|
514
514
|
},
|
|
515
515
|
"devDependencies": {
|
|
516
516
|
"@ai-sdk/anthropic": "^3.0.71",
|