@agent-native/core 0.146.0 → 0.146.1
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/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/analytics/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/analytics/actions/compose-dashboard.ts +2 -27
- package/corpus/templates/analytics/actions/get-sql-dashboard.ts +7 -8
- package/corpus/templates/analytics/actions/migrate-first-party-analytics-to-bigquery.ts +18 -2
- package/corpus/templates/analytics/actions/mutate-dashboard.ts +16 -24
- package/corpus/templates/analytics/actions/rename-dashboard.ts +2 -24
- package/corpus/templates/analytics/actions/reorder-dashboard-panels.ts +2 -24
- package/corpus/templates/analytics/actions/restore-dashboard-revision.ts +2 -25
- package/corpus/templates/analytics/actions/update-dashboard.ts +4 -32
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +1 -40
- package/corpus/templates/analytics/changelog/2026-08-07-language-selection-now-lives-in-settings-instead-of-the-comm.md +6 -0
- package/corpus/templates/analytics/netlify.toml +7 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +13 -13
- package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +4 -2
- package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +0 -35
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +5 -3
- package/corpus/templates/analytics/server/lib/dashboard-collab-sync.ts +77 -0
- package/corpus/templates/analytics/server/lib/demo-dashboards.ts +2 -23
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +28 -74
- package/corpus/templates/analytics/server/routes/api/dashboard-agent-context.json.get.ts +5 -9
- package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/assets/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/brain/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/clips/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +1 -1
- package/corpus/templates/clips/changelog/2026-08-07-fixed-trimmed-clips-durations-so-the-main-player-display-mat.md +6 -0
- package/corpus/templates/clips/chrome-extension/STORE_DRAFT.md +1 -1
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
- package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/content/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/crm/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/design/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/dispatch/changelog/2026-08-07-language-selection-now-lives-in-settings-instead-of-the-disp.md +6 -0
- package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/factory/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +59 -22
- package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/forms/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/macros/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/mail/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/plan/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/slides/.agents/skills/image-generation-via-a2a/SKILL.md +10 -1
- package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +10 -3
- package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/slides/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/corpus/templates/slides/actions/generate-image-api.ts +123 -0
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +10 -2
- package/corpus/templates/slides/app/components/editor/ImageGenPanel.tsx +1 -1
- package/corpus/templates/slides/changelog/2026-08-07-deleting-a-deck-no-longer-freezes-the-slides-browser.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-07-slides-verify-generated-images-are-persisted-on-the-target-s.md +6 -0
- package/corpus/templates/slides/server/lib/slide-image-insertion.ts +141 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/dist/client/AgentPanel.d.ts +10 -4
- package/dist/client/AgentPanel.js +29 -82
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/migrations.js +22 -4
- package/dist/deploy/build.d.ts +1 -0
- package/dist/deploy/build.js +27 -22
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/builder-browser.d.ts +34 -0
- package/dist/server/builder-browser.js +179 -0
- package/dist/server/core-routes-plugin.d.ts +5 -0
- package/dist/server/core-routes-plugin.js +24 -8
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/shared/cache-control.d.ts +2 -2
- package/dist/shared/cache-control.js +2 -2
- package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/dist/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/dist/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/dist/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/dist/vite/client.js +13 -1
- package/docs/content/drop-in-agent.mdx +3 -3
- package/docs/content/getting-started-actions.mdx +1 -2
- package/docs/content/getting-started-pages.mdx +1 -2
- package/docs/content/getting-started.mdx +0 -4
- package/docs/content/what-is-agent-native.mdx +4 -4
- package/package.json +3 -3
- package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/src/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/src/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/src/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +4 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
- package/docs/content/getting-started-database.mdx +0 -173
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
interface InsertSlideImageOptions {
|
|
2
|
+
alt?: string;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function cleanAlt(value: string | undefined): string {
|
|
6
|
+
return (value || "Uploaded image").replace(/\s+/g, " ").trim();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function escapeAttribute(value: string): string {
|
|
10
|
+
return value
|
|
11
|
+
.replace(/&/g, "&")
|
|
12
|
+
.replace(/"/g, """)
|
|
13
|
+
.replace(/</g, "<")
|
|
14
|
+
.replace(/>/g, ">");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function decodeHtml(value: string): string {
|
|
18
|
+
return value
|
|
19
|
+
.replace(/"/gi, '"')
|
|
20
|
+
.replace(/'/gi, "'")
|
|
21
|
+
.replace(/</gi, "<")
|
|
22
|
+
.replace(/>/gi, ">")
|
|
23
|
+
.replace(/&/gi, "&");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function textContent(html: string): string {
|
|
27
|
+
return decodeHtml(html.replace(/<[^>]+>/g, " "))
|
|
28
|
+
.replace(/\s+/g, " ")
|
|
29
|
+
.trim();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function attribute(attributes: string, name: string): string | null {
|
|
33
|
+
const match = attributes.match(
|
|
34
|
+
new RegExp(`\\b${name}\\s*=\\s*(["'])([\\s\\S]*?)\\1`, "i"),
|
|
35
|
+
);
|
|
36
|
+
return match ? match[2] : null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function hasStyleProperty(style: string, property: string): boolean {
|
|
40
|
+
return new RegExp(`(?:^|;)\\s*${property}\\s*:`, "i").test(style);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function appendImageStyle(baseStyle: string): string {
|
|
44
|
+
const declarations = [baseStyle.trim().replace(/;+\s*$/, "")].filter(Boolean);
|
|
45
|
+
if (!hasStyleProperty(baseStyle, "display"))
|
|
46
|
+
declarations.push("display: block");
|
|
47
|
+
if (!hasStyleProperty(baseStyle, "object-fit")) {
|
|
48
|
+
declarations.push("object-fit: cover");
|
|
49
|
+
}
|
|
50
|
+
if (!hasStyleProperty(baseStyle, "min-width"))
|
|
51
|
+
declarations.push("min-width: 0");
|
|
52
|
+
return declarations.length > 0 ? `${declarations.join("; ")};` : "";
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function imageHtml(src: string, alt: string, style: string): string {
|
|
56
|
+
return `<img src="${escapeAttribute(src)}" alt="${escapeAttribute(alt)}" class="fmd-img-uploaded"${style ? ` style="${escapeAttribute(style)}"` : ""}>`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Server-safe counterpart to the editor's image replacement helper. It uses
|
|
61
|
+
* deterministic string transforms because DOMParser is not available in the
|
|
62
|
+
* server runtime that executes actions.
|
|
63
|
+
*/
|
|
64
|
+
export function insertImageIntoSlideHtml(
|
|
65
|
+
content: string,
|
|
66
|
+
src: string,
|
|
67
|
+
options: InsertSlideImageOptions = {},
|
|
68
|
+
): string {
|
|
69
|
+
const openingTags = /<([a-z][\w:-]*)([^>]*)>/gi;
|
|
70
|
+
for (const match of content.matchAll(openingTags)) {
|
|
71
|
+
const className = attribute(match[2], "class") || "";
|
|
72
|
+
if (!/(?:^|\s)fmd-img-placeholder(?:\s|$)/.test(className)) continue;
|
|
73
|
+
|
|
74
|
+
const closingTag = new RegExp(`</${match[1]}\\s*>`, "gi");
|
|
75
|
+
closingTag.lastIndex = (match.index ?? 0) + match[0].length;
|
|
76
|
+
const closing = closingTag.exec(content);
|
|
77
|
+
if (!closing || match.index === undefined) continue;
|
|
78
|
+
|
|
79
|
+
const style = appendImageStyle(
|
|
80
|
+
attribute(match[2], "style") ||
|
|
81
|
+
"width: 100%; height: 100%; border-radius: 8px; object-fit: cover;",
|
|
82
|
+
);
|
|
83
|
+
const replacement = imageHtml(
|
|
84
|
+
src,
|
|
85
|
+
cleanAlt(
|
|
86
|
+
options.alt ||
|
|
87
|
+
textContent(
|
|
88
|
+
content.slice(match.index + match[0].length, closing.index),
|
|
89
|
+
) ||
|
|
90
|
+
"Uploaded image",
|
|
91
|
+
),
|
|
92
|
+
style,
|
|
93
|
+
);
|
|
94
|
+
return `${content.slice(0, match.index)}${replacement}${content.slice(closing.index + closing[0].length)}`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const fullBleed = imageHtml(
|
|
98
|
+
src,
|
|
99
|
+
cleanAlt(options.alt),
|
|
100
|
+
"position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -1;",
|
|
101
|
+
);
|
|
102
|
+
const slideRoot =
|
|
103
|
+
/<([a-z][\w:-]*)([^>]*\bclass\s*=\s*(["'])[^"']*\bfmd-slide\b[^"']*\3[^>]*)>/i.exec(
|
|
104
|
+
content,
|
|
105
|
+
);
|
|
106
|
+
if (!slideRoot || slideRoot.index === undefined)
|
|
107
|
+
return `${fullBleed}${content}`;
|
|
108
|
+
|
|
109
|
+
let openingTag = slideRoot[0];
|
|
110
|
+
const style = attribute(slideRoot[2], "style") || "";
|
|
111
|
+
if (!hasStyleProperty(style, "position")) {
|
|
112
|
+
const nextStyle =
|
|
113
|
+
`${style.trim().replace(/;+\s*$/, "")}; position: relative;`.replace(
|
|
114
|
+
/^;\s*/,
|
|
115
|
+
"",
|
|
116
|
+
);
|
|
117
|
+
if (/\bstyle\s*=\s*(["'])/i.test(openingTag)) {
|
|
118
|
+
openingTag = openingTag.replace(
|
|
119
|
+
/\bstyle\s*=\s*(["'])[^"']*\1/i,
|
|
120
|
+
`style="${escapeAttribute(nextStyle)}"`,
|
|
121
|
+
);
|
|
122
|
+
} else {
|
|
123
|
+
openingTag = openingTag.replace(
|
|
124
|
+
/>$/,
|
|
125
|
+
` style="${escapeAttribute(nextStyle)}">`,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return `${content.slice(0, slideRoot.index)}${openingTag}${fullBleed}${content.slice(slideRoot.index + slideRoot[0].length)}`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function slideHtmlContainsImageSource(
|
|
133
|
+
html: string,
|
|
134
|
+
src: string,
|
|
135
|
+
): boolean {
|
|
136
|
+
const images = /<img\b([^>]*)>/gi;
|
|
137
|
+
for (const match of html.matchAll(images)) {
|
|
138
|
+
if (decodeHtml(attribute(match[1], "src") || "") === src) return true;
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
@@ -62,6 +62,8 @@ Layout-fit workflow is strict. When the user asks to fix overflow, first call vi
|
|
|
62
62
|
|
|
63
63
|
Fit means the main content fits the native content area. A small outer-wrapper spill is tolerated by the measurement, but cards, text, columns, and other visible content must fit. Never use zoom, transform: scale(), overflow: hidden/scroll, clipping, or a smaller-than-16px body font to hide overflow. Preserve manually positioned freeform objects and their data-slide-object-id values; repair normal-flow structure, copy, gaps, or slide padding instead. A successful action result must include the affected slide IDs; if it does not, report that no verified write occurred.
|
|
64
64
|
|
|
65
|
+
Image workflow is strict. For direct insertion, call generate-image-api with insertIntoSlide: true plus deckId and slideId. Claim that an image was added only when that action returns inserted: true; a preview URL or completed generation alone is not a slide edit. For preview-only variations, call generate-image-api without insertIntoSlide, then use update-slide to place the chosen URL and re-read the target with get-deck to confirm its persisted HTML contains that image source before claiming success.
|
|
66
|
+
|
|
65
67
|
Provider-specific Slides actions are shortcuts, not limits. If a first-class action cannot express the exact Google Drive endpoint, file metadata field, export format, query, request body, pagination mode, payload shape, or API version needed, call provider-api-catalog and provider-api-docs as needed, then call provider-api-request against the real provider API. Use the raw provider API escape hatch instead of weakening the answer or claiming Slides cannot do something the underlying Google Drive API can do.
|
|
66
68
|
|
|
67
69
|
Slides' Google Drive provider API uses the user's connected Google Docs OAuth account. The drive.file scope is intentionally limited to files the user selected or the app created. For large Drive file lists or metadata sweeps, pass stageAs and pagination options to provider-api-request, then use query-staged-dataset to count, filter, group, or project the staged rows.
|
|
@@ -27,6 +27,10 @@ The build location depends on the host. Treat this as a hard routing rule:
|
|
|
27
27
|
`resourceIds` when available. This is the Builder handoff.
|
|
28
28
|
- Do not substitute the generic `create_workspace_app` MCP tool in an online
|
|
29
29
|
host. That tool is a local workspace scaffolder, not the Builder handoff.
|
|
30
|
+
- Connect the Agent-Native Dispatch MCP connector only. Dispatch uses the
|
|
31
|
+
authenticated Builder Projects API to reuse or provision the workspace
|
|
32
|
+
project before starting the Builder Cloud Agent; a separate Builder CMS MCP
|
|
33
|
+
connection is not required for this workflow.
|
|
30
34
|
- If `start-workspace-app-creation` is not available or Dispatch is not
|
|
31
35
|
authenticated, stop with the connector setup needed. Do not fall back to a
|
|
32
36
|
local build or claim that the app exists.
|
|
@@ -50,6 +50,14 @@ skills. For a ChatGPT Project or any host that exposes only the MCP connector,
|
|
|
50
50
|
also place the skill instructions or this reference in the Project
|
|
51
51
|
instructions/knowledge files. Then add and authenticate the Dispatch MCP
|
|
52
52
|
connector from the packaged `adapters/chatgpt-mcp/connector.json`.
|
|
53
|
+
This single connector is enough: Dispatch provisions or reuses the Builder
|
|
54
|
+
project through the Builder Projects API, so do not ask the user to add a
|
|
55
|
+
separate Builder CMS MCP for app creation.
|
|
56
|
+
Builder's separate Fusion MCP is available as a custom remote connector at
|
|
57
|
+
`https://mcp.builder.io/mcp/fusion` for direct Builder work. It can run an
|
|
58
|
+
existing project, but it cannot provision the repo-backed Agent-Native
|
|
59
|
+
workspace project, so it is optional and not a replacement for the Dispatch
|
|
60
|
+
handoff in this skill. Do not add Builder's CMS MCP for this workflow.
|
|
53
61
|
|
|
54
62
|
For Claude Web, ChatGPT Web, and their web Projects, the host is an
|
|
55
63
|
orchestrator, not the build environment. After forming the source brief, call
|
|
@@ -38,7 +38,13 @@ export declare function shouldShowAgentPanelSidebarChatTabs(tabs: MultiTabAssist
|
|
|
38
38
|
export declare function shouldShowAgentPanelPageNewChatButton(tabs: MultiTabAssistantChatHeaderProps["tabs"], activeTabId: string, activeTabMessageCount: number): boolean;
|
|
39
39
|
export declare function shouldShowAgentPanelCliTabBar(cliTabs: string[]): boolean;
|
|
40
40
|
export declare function shouldShowAgentPanelModeButtons(isSidebar: boolean): boolean;
|
|
41
|
-
export declare function shouldShowAgentPanelFullViewAction(agentPageHref: string | undefined, mode: PanelMode, isSidebar?: boolean): boolean;
|
|
41
|
+
export declare function shouldShowAgentPanelFullViewAction(agentPageHref: string | undefined, mode: PanelMode, isSidebar?: boolean, currentPath?: string): boolean;
|
|
42
|
+
export declare function getAgentPanelShortcutHints(isMac: boolean): {
|
|
43
|
+
closeTab: string;
|
|
44
|
+
closeAllTabs: string;
|
|
45
|
+
toggleSidebar: string;
|
|
46
|
+
widenChat: string;
|
|
47
|
+
};
|
|
42
48
|
export interface AgentPanelCodeAccess {
|
|
43
49
|
/** Whether this surface can safely edit source and run shell commands. */
|
|
44
50
|
enabled: boolean;
|
|
@@ -68,7 +74,7 @@ export interface AgentPanelProps extends Omit<AssistantChatProps, "onSwitchToCli
|
|
|
68
74
|
onCollapse?: () => void;
|
|
69
75
|
/** Whether the panel is currently in fullscreen (Claude-style centered) mode. */
|
|
70
76
|
isFullscreen?: boolean;
|
|
71
|
-
/**
|
|
77
|
+
/** @deprecated Fullscreen sidebar controls are no longer rendered. */
|
|
72
78
|
onToggleFullscreen?: () => void;
|
|
73
79
|
/** Called when the user asks the sidebar to use the wide chat width preset. */
|
|
74
80
|
onSnapTo75Percent?: () => void;
|
|
@@ -180,7 +186,7 @@ export interface AgentSidebarProps {
|
|
|
180
186
|
storageKey?: string;
|
|
181
187
|
/** Open the sidebar when a chat run is active or reconnects. */
|
|
182
188
|
openOnChatRunning?: boolean;
|
|
183
|
-
/**
|
|
189
|
+
/** @deprecated Fullscreen sidebar actions are no longer rendered. */
|
|
184
190
|
onFullscreenRequest?: () => void;
|
|
185
191
|
/** Ambient resource context rendered as a composer chip. */
|
|
186
192
|
scope?: import("./use-chat-threads.js").ChatThreadScope | null;
|
|
@@ -199,7 +205,7 @@ export interface AgentSidebarProps {
|
|
|
199
205
|
* Wraps app content with a toggleable agent sidebar.
|
|
200
206
|
* Use AgentToggleButton in your header to open/close it.
|
|
201
207
|
*/
|
|
202
|
-
export declare function AgentSidebar({ children, emptyStateText, suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position, defaultOpen, animateMobile, animateDesktop, chatViewTransition, chatViewTransitionHandoff, storageKey, openOnChatRunning,
|
|
208
|
+
export declare function AgentSidebar({ children, emptyStateText, suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position, defaultOpen, animateMobile, animateDesktop, chatViewTransition, chatViewTransitionHandoff, storageKey, openOnChatRunning, scope, showScopeBadge, browserTabId, threadUrlSync, agentPageHref, suppressFirstRunOnboarding, }: AgentSidebarProps): React.JSX.Element;
|
|
203
209
|
/**
|
|
204
210
|
* Focus the agent chat composer input.
|
|
205
211
|
* Opens the sidebar if closed, then focuses the text input.
|
|
@@ -22,7 +22,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
22
22
|
* <AgentChatSurface mode="page" className="h-screen" />
|
|
23
23
|
*/
|
|
24
24
|
import { Tooltip as DesignSystemTooltip } from "@agent-native/toolkit/design-system";
|
|
25
|
-
import { IconMessageCircle, IconMessageDots, IconTerminal2, IconSettings, IconLayoutSidebarRightCollapse, IconLayoutGrid, IconCheck, IconPlus, IconX, IconDotsVertical, IconHistory, IconArrowsHorizontal, IconArrowsMaximize,
|
|
25
|
+
import { IconMessageCircle, IconMessageDots, IconTerminal2, IconSettings, IconLayoutSidebarRightCollapse, IconLayoutGrid, IconCheck, IconPlus, IconX, IconDotsVertical, IconHistory, IconArrowsHorizontal, IconArrowsMaximize, IconExternalLink, } from "@tabler/icons-react";
|
|
26
26
|
import React, { useState, useEffect, useRef, useCallback, useMemo, lazy, Suspense, startTransition, } from "react";
|
|
27
27
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, } from "./components/ui/dropdown-menu.js";
|
|
28
28
|
import { normalizeTooltipText } from "./components/ui/tooltip.js";
|
|
@@ -240,10 +240,19 @@ export function shouldShowAgentPanelCliTabBar(cliTabs) {
|
|
|
240
240
|
export function shouldShowAgentPanelModeButtons(isSidebar) {
|
|
241
241
|
return !isSidebar;
|
|
242
242
|
}
|
|
243
|
-
export function shouldShowAgentPanelFullViewAction(agentPageHref, mode, isSidebar = false) {
|
|
243
|
+
export function shouldShowAgentPanelFullViewAction(agentPageHref, mode, isSidebar = false, currentPath) {
|
|
244
244
|
return (Boolean(agentPageHref) &&
|
|
245
|
+
currentPath !== agentPageHref &&
|
|
245
246
|
(isSidebar || mode === "resources" || mode === "settings"));
|
|
246
247
|
}
|
|
248
|
+
export function getAgentPanelShortcutHints(isMac) {
|
|
249
|
+
return {
|
|
250
|
+
closeTab: isMac ? "⌃W" : "⌥W",
|
|
251
|
+
closeAllTabs: isMac ? "⌃⌥W" : "^⌥W",
|
|
252
|
+
toggleSidebar: isMac ? "⌘\\" : "^\\",
|
|
253
|
+
widenChat: isMac ? "⌘⇧\\" : "^⇧\\",
|
|
254
|
+
};
|
|
255
|
+
}
|
|
247
256
|
function useBuilderConnectUrl() {
|
|
248
257
|
const [connectUrl, setConnectUrl] = useState(null);
|
|
249
258
|
const [configured, setConfigured] = useState(false);
|
|
@@ -391,6 +400,7 @@ function CodeAccessUnavailablePanel({ title, description, ctaLabel, ctaHref, sec
|
|
|
391
400
|
function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, emptyStateText, emptyStateAddon, suggestions, dynamicSuggestions, showHeader = true, onCollapse, isFullscreen, onToggleFullscreen, onSnapTo75Percent, isWideDrawer, onExitWideDrawer, devAppUrl, storageKey, restoreActiveThread = true, scope, showScopeBadge, browserTabId, threadUrlSync, chatNotice, showTabBar = true, showPageNewChatButton = false, allowSettingsMode = true, chatOnly = false, agentPageHref, codeAccess, ...assistantChatProps }) {
|
|
392
401
|
const t = useT();
|
|
393
402
|
const navigate = useNavigate();
|
|
403
|
+
const location = useLocation();
|
|
394
404
|
const mounted = useClientOnly();
|
|
395
405
|
const onboardingPreviewMode = useOnboardingPreviewMode();
|
|
396
406
|
const showFirstRunOnboarding = SHOW_FIRST_RUN_ONBOARDING || onboardingPreviewMode;
|
|
@@ -402,11 +412,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
402
412
|
const panelModeKey = `agent-native-panel-mode${keyPrefix}`;
|
|
403
413
|
const isMac = useMemo(() => typeof navigator !== "undefined" &&
|
|
404
414
|
/Mac|iPhone|iPad/.test(navigator.userAgent), []);
|
|
405
|
-
const closeTabHint
|
|
406
|
-
const closeAllTabsHint = isMac ? "\u2303\u2325W" : "Ctrl+Alt+W";
|
|
407
|
-
const toggleSidebarHint = isMac ? "\u2318\\" : "Ctrl+\\";
|
|
408
|
-
const widenChatHint = isMac ? "\u2318\u21e7\\" : "Ctrl+Shift+\\";
|
|
409
|
-
const fullscreenHint = isMac ? "\u2318\u21e7F" : "Ctrl+Shift+F";
|
|
415
|
+
const { closeTab: closeTabHint, closeAllTabs: closeAllTabsHint, toggleSidebar: toggleSidebarHint, widenChat: widenChatHint, } = getAgentPanelShortcutHints(isMac);
|
|
410
416
|
const [execMode, setExecMode] = useState(() => {
|
|
411
417
|
try {
|
|
412
418
|
const saved = localStorage.getItem(execModeKey);
|
|
@@ -651,7 +657,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
651
657
|
const wideDrawerAction = isWideDrawer ? onExitWideDrawer : onSnapTo75Percent;
|
|
652
658
|
const wideDrawerLabel = t(isWideDrawer ? "agentPanel.returnChatToLayout" : "agentPanel.widenChat");
|
|
653
659
|
const showFullViewAction = Boolean(agentPageHref &&
|
|
654
|
-
shouldShowAgentPanelFullViewAction(agentPageHref, mode, chatOnly));
|
|
660
|
+
shouldShowAgentPanelFullViewAction(agentPageHref, mode, chatOnly, location.pathname));
|
|
655
661
|
useEffect(() => {
|
|
656
662
|
const handleKeyDown = (event) => {
|
|
657
663
|
if (!(event.metaKey || event.ctrlKey) ||
|
|
@@ -667,14 +673,10 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
667
673
|
wideDrawerAction();
|
|
668
674
|
return;
|
|
669
675
|
}
|
|
670
|
-
if (event.code === "KeyF" && onToggleFullscreen) {
|
|
671
|
-
event.preventDefault();
|
|
672
|
-
onToggleFullscreen();
|
|
673
|
-
}
|
|
674
676
|
};
|
|
675
677
|
document.addEventListener("keydown", handleKeyDown);
|
|
676
678
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
677
|
-
}, [mode, onCollapse,
|
|
679
|
+
}, [mode, onCollapse, wideDrawerAction]);
|
|
678
680
|
const renderHeaderActions = useCallback(({ activeChatSessionId, activeTabId, activeTabMessageCount, addTab, clearActiveTab, closeAllTabs, closeOtherTabs, closeTab, showHistory, tabs, toggleHistory, }) => (_jsxs("div", { className: "relative flex shrink-0 items-center gap-0.5", children: [!onCollapse && SHOW_ONBOARDING && (_jsx(Suspense, { fallback: null, children: _jsx(SetupButton, {}) })), !onCollapse &&
|
|
679
681
|
(() => {
|
|
680
682
|
const activeTab = mode === "chat" && activeChatSessionId
|
|
@@ -686,11 +688,8 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
686
688
|
}
|
|
687
689
|
return (_jsx(ShareButton, { resourceType: "chat_thread", resourceId: activeTab.id, resourceTitle: activeTab.label || "Chat", shareUrl: getChatThreadShareUrl(activeTab.id), trigger: "icon", triggerClassName: "h-7 w-7" }));
|
|
688
690
|
})(), feedbackEnabled ? (_jsx(FeedbackButton, { variant: "icon", side: "bottom", align: "end", chatSessionId: activeChatSessionId, chatStorageKey: storageKey, open: feedbackOpen, onOpenChange: setFeedbackOpen, trigger: _jsx("button", { type: "button", tabIndex: -1, "aria-hidden": "true", className: "pointer-events-none absolute end-0 top-full h-px w-px opacity-0" }) })) : null, mode === "chat" && (_jsx(IconTooltip, { content: t("agentPanel.newChat"), children: _jsx("button", { onClick: addTab, "aria-label": t("agentPanel.newChat"), className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconPlus, { size: 14 }) }) })), !onCollapse && mode === "cli" && canUseCodeTools && (_jsx(IconTooltip, { content: t("agentPanel.newTerminal"), children: _jsx("button", { onClick: addCliTab, "aria-label": t("agentPanel.newTerminal"), className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconPlus, { size: 14 }) }) })), _jsxs(DropdownMenu, { open: headerMenuOpen, onOpenChange: setHeaderMenuOpen, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { className: cn("flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", (headerMenuOpen || mode === "settings") &&
|
|
689
|
-
"bg-accent text-foreground"), "aria-label": t("agentPanel.panelOptions"), children: _jsx(IconDotsVertical, { size: 14 }) }) }), _jsxs(DropdownMenuContent, { align: "end", sideOffset: 6, className: "w-48", children: [onCollapse && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: onCollapse, children: [_jsx(IconLayoutSidebarRightCollapse, { size: 14, className: "shrink-0" }), t("agentPanel.collapseSidebar"), _jsx(DropdownMenuShortcut, { children: toggleSidebarHint })] }), _jsx(DropdownMenuSeparator, {})] })), onCollapse && mode === "chat" && wideDrawerAction ? (_jsxs(DropdownMenuItem, { onSelect: wideDrawerAction, children: [_jsx(IconArrowsHorizontal, { size: 14, className: "shrink-0" }), wideDrawerLabel, _jsx(DropdownMenuShortcut, { children: widenChatHint })] })) : null, showFullViewAction && agentPageHref ? (_jsx(DropdownMenuItem, { asChild: true, children: _jsxs(Link, { to: agentPageHref, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] }) })) : null,
|
|
690
|
-
|
|
691
|
-
: t("agentPanel.fullscreen"), _jsx(DropdownMenuShortcut, { children: fullscreenHint })] })), (onCollapse && mode === "chat" && wideDrawerAction) ||
|
|
692
|
-
showFullViewAction ||
|
|
693
|
-
onToggleFullscreen ? (_jsx(DropdownMenuSeparator, {})) : null, onCollapse && mode === "chat" && (_jsxs(DropdownMenuItem, { onSelect: addTab, children: [_jsx(IconPlus, { size: 14, className: "shrink-0" }), t("agentPanel.newChat")] })), mode === "chat" && toggleHistory && (_jsxs(DropdownMenuItem, { onSelect: toggleHistory, children: [_jsx(IconHistory, { size: 14, className: "shrink-0" }), showHistory
|
|
691
|
+
"bg-accent text-foreground"), "aria-label": t("agentPanel.panelOptions"), children: _jsx(IconDotsVertical, { size: 14 }) }) }), _jsxs(DropdownMenuContent, { align: "end", sideOffset: 6, className: "w-48", children: [onCollapse && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: onCollapse, children: [_jsx(IconLayoutSidebarRightCollapse, { size: 14, className: "shrink-0" }), t("agentPanel.collapseSidebar"), _jsx(DropdownMenuShortcut, { children: toggleSidebarHint })] }), _jsx(DropdownMenuSeparator, {})] })), onCollapse && mode === "chat" && wideDrawerAction ? (_jsxs(DropdownMenuItem, { onSelect: wideDrawerAction, children: [_jsx(IconArrowsHorizontal, { size: 14, className: "shrink-0" }), wideDrawerLabel, _jsx(DropdownMenuShortcut, { children: widenChatHint })] })) : null, showFullViewAction && agentPageHref ? (_jsx(DropdownMenuItem, { asChild: true, children: _jsxs(Link, { to: agentPageHref, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] }) })) : null, (onCollapse && mode === "chat" && wideDrawerAction) ||
|
|
692
|
+
showFullViewAction ? (_jsx(DropdownMenuSeparator, {})) : null, onCollapse && mode === "chat" && (_jsxs(DropdownMenuItem, { onSelect: addTab, children: [_jsx(IconPlus, { size: 14, className: "shrink-0" }), t("agentPanel.newChat")] })), mode === "chat" && toggleHistory && (_jsxs(DropdownMenuItem, { onSelect: toggleHistory, children: [_jsx(IconHistory, { size: 14, className: "shrink-0" }), showHistory
|
|
694
693
|
? t("agentPanel.hideChats")
|
|
695
694
|
: t("agentPanel.allChats")] })), mode === "chat" && (_jsx(RunsTrayMenuItem, { pollMs: 0, limit: 12, showRecent: true, onOpenThread: openRunThread })), mode === "chat" && _jsx(DropdownMenuSeparator, {}), mode === "cli" && availableClis.length > 0 && (_jsxs(_Fragment, { children: [availableClis.map((cli) => (_jsxs(DropdownMenuItem, { onSelect: () => selectCli(cli.command), className: cn(cli.command === selectedCli
|
|
696
695
|
? "font-medium"
|
|
@@ -715,14 +714,12 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
715
714
|
feedbackEnabled,
|
|
716
715
|
getChatThreadShareUrl,
|
|
717
716
|
headerMenuOpen,
|
|
718
|
-
isFullscreen,
|
|
719
717
|
isWideDrawer,
|
|
720
718
|
mode,
|
|
721
719
|
agentPageHref,
|
|
722
720
|
onCollapse,
|
|
723
721
|
onExitWideDrawer,
|
|
724
722
|
onSnapTo75Percent,
|
|
725
|
-
onToggleFullscreen,
|
|
726
723
|
openRunThread,
|
|
727
724
|
selectCli,
|
|
728
725
|
selectedCli,
|
|
@@ -732,7 +729,6 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
732
729
|
wideDrawerAction,
|
|
733
730
|
wideDrawerLabel,
|
|
734
731
|
widenChatHint,
|
|
735
|
-
fullscreenHint,
|
|
736
732
|
showFullViewAction,
|
|
737
733
|
]);
|
|
738
734
|
const renderPageChatOverlay = useCallback(({ activeTabId, activeTabMessageCount, addTab, tabs, }) => {
|
|
@@ -939,13 +935,11 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
939
935
|
}
|
|
940
936
|
// ─── Resize handle ──────────────────────────────────────────────────────────
|
|
941
937
|
const SIDEBAR_STORAGE_KEY = "agent-native-sidebar-width";
|
|
942
|
-
const SIDEBAR_FULLSCREEN_KEY = "agent-native-sidebar-fullscreen";
|
|
943
938
|
const SIDEBAR_DRAWER_KEY = "agent-native-sidebar-wide-drawer";
|
|
944
939
|
const SIDEBAR_DRAWER_PLACEHOLDER_KEY = "agent-native-sidebar-drawer-placeholder-width";
|
|
945
940
|
const SIDEBAR_ANIMATION_MS = 260;
|
|
946
941
|
const SIDEBAR_OVERLAY_Z_INDEX = 70;
|
|
947
942
|
const SIDEBAR_DRAWER_Z_INDEX = 80;
|
|
948
|
-
const SIDEBAR_FULLSCREEN_Z_INDEX = 90;
|
|
949
943
|
const SIDEBAR_DRAWER_VIEW_TRANSITION_NAME = "agent-native-sidebar-drawer";
|
|
950
944
|
/** Shared max width of the centered fullscreen chat column and composer. */
|
|
951
945
|
const FULLSCREEN_CHAT_COLUMN_MAX_PX = 684;
|
|
@@ -1365,7 +1359,7 @@ export function AgentChatSurface({ mode = "panel", className, defaultMode = "cha
|
|
|
1365
1359
|
* Wraps app content with a toggleable agent sidebar.
|
|
1366
1360
|
* Use AgentToggleButton in your header to open/close it.
|
|
1367
1361
|
*/
|
|
1368
|
-
export function AgentSidebar({ children, emptyStateText = "How can I help you?", suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position = "right", defaultOpen = false, animateMobile = true, animateDesktop = true, chatViewTransition = false, chatViewTransitionHandoff = false, storageKey, openOnChatRunning = false,
|
|
1362
|
+
export function AgentSidebar({ children, emptyStateText = "How can I help you?", suggestions, dynamicSuggestions, composerToolbarSlot, composerSlot, onComposerTextChange, imageModelMenu, threadFooterSlot, defaultSidebarWidth, sidebarWidth, position = "right", defaultOpen = false, animateMobile = true, animateDesktop = true, chatViewTransition = false, chatViewTransitionHandoff = false, storageKey, openOnChatRunning = false, scope, showScopeBadge, browserTabId, threadUrlSync, agentPageHref, suppressFirstRunOnboarding = false, }) {
|
|
1369
1363
|
const onboardingPreviewMode = useOnboardingPreviewMode();
|
|
1370
1364
|
const showFirstRunOnboarding = !suppressFirstRunOnboarding &&
|
|
1371
1365
|
(SHOW_FIRST_RUN_ONBOARDING || onboardingPreviewMode);
|
|
@@ -1399,20 +1393,6 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
|
|
|
1399
1393
|
});
|
|
1400
1394
|
const drawerExitTimerRef = useRef(null);
|
|
1401
1395
|
const [isResizing, setIsResizing] = useState(false);
|
|
1402
|
-
const [fullscreen, setFullscreen] = useState(() => {
|
|
1403
|
-
// Force-disable on mobile: a Claude-style centered column makes no sense
|
|
1404
|
-
// when the sidebar already covers most of the viewport.
|
|
1405
|
-
if (typeof window !== "undefined" &&
|
|
1406
|
-
window.matchMedia("(max-width: 767px)").matches) {
|
|
1407
|
-
return false;
|
|
1408
|
-
}
|
|
1409
|
-
try {
|
|
1410
|
-
return localStorage.getItem(SIDEBAR_FULLSCREEN_KEY) === "true";
|
|
1411
|
-
}
|
|
1412
|
-
catch {
|
|
1413
|
-
return false;
|
|
1414
|
-
}
|
|
1415
|
-
});
|
|
1416
1396
|
// Track mobile viewport so we can switch to overlay mode.
|
|
1417
1397
|
const [isMobile, setIsMobile] = useState(() => typeof window !== "undefined" &&
|
|
1418
1398
|
window.matchMedia("(max-width: 767px)").matches);
|
|
@@ -1458,16 +1438,6 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
|
|
|
1458
1438
|
if (openOnChatRunning)
|
|
1459
1439
|
setOpen(true);
|
|
1460
1440
|
}, [openOnChatRunning]);
|
|
1461
|
-
const toggleFullscreen = useCallback(() => {
|
|
1462
|
-
setFullscreen((prev) => {
|
|
1463
|
-
const next = !prev;
|
|
1464
|
-
try {
|
|
1465
|
-
localStorage.setItem(SIDEBAR_FULLSCREEN_KEY, String(next));
|
|
1466
|
-
}
|
|
1467
|
-
catch { }
|
|
1468
|
-
return next;
|
|
1469
|
-
});
|
|
1470
|
-
}, []);
|
|
1471
1441
|
// Track whether the frame is controlling the sidebar (code mode = frame active).
|
|
1472
1442
|
// Default to true when inside an iframe — assume the frame sidebar is active
|
|
1473
1443
|
// until told otherwise. This prevents both sidebars flashing after hot reloads.
|
|
@@ -1769,13 +1739,9 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
|
|
|
1769
1739
|
const handleResizeStart = useCallback(() => setIsResizing(true), []);
|
|
1770
1740
|
const handleResizeEnd = useCallback(() => setIsResizing(false), []);
|
|
1771
1741
|
const isLeft = position === "left";
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
const effectiveFullscreen = !onFullscreenRequest && fullscreen && !isMobile;
|
|
1776
|
-
const wideDrawerEnabled = isWideDrawer && !isMobile && !effectiveFullscreen;
|
|
1777
|
-
const mobileAnimationEnabled = !presentationMode && !effectiveFullscreen && isMobile && animateMobile;
|
|
1778
|
-
const desktopAnimationEnabled = !presentationMode && !effectiveFullscreen && !isMobile && animateDesktop;
|
|
1742
|
+
const wideDrawerEnabled = isWideDrawer && !isMobile;
|
|
1743
|
+
const mobileAnimationEnabled = !presentationMode && isMobile && animateMobile;
|
|
1744
|
+
const desktopAnimationEnabled = !presentationMode && !isMobile && animateDesktop;
|
|
1779
1745
|
const sidebarAnimationEnabled = mobileAnimationEnabled || desktopAnimationEnabled;
|
|
1780
1746
|
const [renderAnimatedPanel, setRenderAnimatedPanel] = useState(shouldMountPanel);
|
|
1781
1747
|
useEffect(() => {
|
|
@@ -1804,17 +1770,15 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
|
|
|
1804
1770
|
const panelOpen = open && shouldMountPanel;
|
|
1805
1771
|
const panelLayout = isMobile
|
|
1806
1772
|
? "mobile"
|
|
1807
|
-
:
|
|
1808
|
-
? "
|
|
1809
|
-
:
|
|
1810
|
-
? "drawer"
|
|
1811
|
-
: "desktop";
|
|
1773
|
+
: wideDrawerEnabled
|
|
1774
|
+
? "drawer"
|
|
1775
|
+
: "desktop";
|
|
1812
1776
|
// On desktop the resize handle is also the visual divider. Avoid painting a
|
|
1813
1777
|
// second panel border next to it.
|
|
1814
|
-
const showResizeHandle = !isMobile && !
|
|
1778
|
+
const showResizeHandle = !isMobile && !wideDrawerEnabled && panelOpen;
|
|
1815
1779
|
// On mobile the sidebar floats as a fixed overlay so the content below isn't
|
|
1816
|
-
// squashed. On desktop it participates in the flex layout
|
|
1817
|
-
//
|
|
1780
|
+
// squashed. On desktop it participates in the flex layout or becomes a
|
|
1781
|
+
// fixed-width drawer when the user asks for more room.
|
|
1818
1782
|
let panelStyle;
|
|
1819
1783
|
if (isMobile) {
|
|
1820
1784
|
panelStyle = {
|
|
@@ -1836,18 +1800,6 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
|
|
|
1836
1800
|
pointerEvents: mobileAnimationEnabled && !panelOpen ? "none" : undefined,
|
|
1837
1801
|
};
|
|
1838
1802
|
}
|
|
1839
|
-
else if (effectiveFullscreen) {
|
|
1840
|
-
panelStyle = {
|
|
1841
|
-
...AGENT_PANEL_ROOT_STYLE,
|
|
1842
|
-
position: "fixed",
|
|
1843
|
-
inset: 0,
|
|
1844
|
-
width: "100%",
|
|
1845
|
-
maxHeight: "var(--agent-native-viewport-height, 100vh)",
|
|
1846
|
-
zIndex: SIDEBAR_FULLSCREEN_Z_INDEX,
|
|
1847
|
-
background: "hsl(var(--background))",
|
|
1848
|
-
display: open ? "flex" : "none",
|
|
1849
|
-
};
|
|
1850
|
-
}
|
|
1851
1803
|
else if (wideDrawerEnabled) {
|
|
1852
1804
|
panelStyle = {
|
|
1853
1805
|
...AGENT_PANEL_ROOT_STYLE,
|
|
@@ -1898,16 +1850,11 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
|
|
|
1898
1850
|
? "desktop"
|
|
1899
1851
|
: undefined, "data-agent-sidebar-layout": panelLayout, "data-agent-sidebar-position": position, "data-agent-sidebar-state": panelOpen ? "open" : "closed", "data-agent-sidebar-resizing": isResizing ? "true" : undefined, "data-agent-sidebar-chat-handoff": chatViewTransitionHandoff ? "true" : undefined, style: chatViewTransition
|
|
1900
1852
|
? getAgentChatViewTransitionStyle(panelStyle)
|
|
1901
|
-
: panelStyle, inert: sidebarAnimationEnabled && !panelOpen ? true : undefined, "aria-hidden": sidebarAnimationEnabled && !panelOpen ? true : undefined, children: _jsx("div", { className: "agent-sidebar-panel-inner flex min-h-0 flex-1 flex-col", children: _jsx(AgentPanel, { emptyStateText: emptyStateText, suggestions: suggestions, dynamicSuggestions: dynamicSuggestions, composerToolbarSlot: composerToolbarSlot, composerSlot: composerSlot, onComposerTextChange: onComposerTextChange, imageModelMenu: imageModelMenu, threadFooterSlot: threadFooterSlot, missingApiKeySetupLayout: "sidebar", onCollapse: () => setOpenPersisted(false),
|
|
1853
|
+
: panelStyle, inert: sidebarAnimationEnabled && !panelOpen ? true : undefined, "aria-hidden": sidebarAnimationEnabled && !panelOpen ? true : undefined, children: _jsx("div", { className: "agent-sidebar-panel-inner flex min-h-0 flex-1 flex-col", children: _jsx(AgentPanel, { emptyStateText: emptyStateText, suggestions: suggestions, dynamicSuggestions: dynamicSuggestions, composerToolbarSlot: composerToolbarSlot, composerSlot: composerSlot, onComposerTextChange: onComposerTextChange, imageModelMenu: imageModelMenu, threadFooterSlot: threadFooterSlot, missingApiKeySetupLayout: "sidebar", onCollapse: () => setOpenPersisted(false), onSnapTo75Percent: isMobile ? undefined : snapTo75Percent, isWideDrawer: isMobile ? false : isWideDrawer, onExitWideDrawer: isMobile ? undefined : exitWideDrawer, storageKey: storageKey, scope: scope, showScopeBadge: showScopeBadge, browserTabId: browserTabId, threadUrlSync: threadUrlSync, agentPageHref: agentPageHref, allowSettingsMode: false, chatOnly: true }) }) }), showResizeHandle && isLeft && (_jsx(ResizeHandle, { position: position, onDrag: handleDrag, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd }))] })) : null;
|
|
1902
1854
|
const drawerPlaceholder = wideDrawerEnabled && !presentationMode && shouldRenderPanel ? (_jsx("div", { "aria-hidden": "true", className: "agent-sidebar-drawer-placeholder shrink-0", "data-agent-sidebar-placeholder": "true", style: { width: drawerPlaceholderWidth + 1 } })) : null;
|
|
1903
1855
|
return (_jsx(AgentSidebarOnboardingContext.Provider, { value: true, children: _jsxs(RealtimeVoiceModeProvider, { browserTabId: browserTabId, children: [showFirstRunOnboarding && (_jsx(Suspense, { fallback: null, children: _jsx(FirstRunOnboarding, {}) })), _jsxs("div", { className: "agent-sidebar-shell flex min-w-0 flex-1 h-screen overflow-hidden", "data-agent-sidebar-position": position, "data-agent-sidebar-resizing": isResizing ? "true" : undefined, children: [isMobile &&
|
|
1904
1856
|
!presentationMode &&
|
|
1905
|
-
(mobileAnimationEnabled ? shouldRenderPanel : open) && (_jsx("div", { className: cn("agent-sidebar-backdrop fixed inset-0 bg-foreground/40", mobileAnimationEnabled && !panelOpen && "pointer-events-none"), "data-agent-sidebar-animation": mobileAnimationEnabled ? "mobile" : undefined, "data-agent-sidebar-state": panelOpen ? "open" : "closed", style: { zIndex: SIDEBAR_OVERLAY_Z_INDEX - 1 }, onClick: () => setOpenPersisted(false) })), shouldMountPanel ? _jsx(URLSync, { browserTabId: browserTabId }) : null, isLeft && !presentationMode ? sidebar : null, isLeft && !presentationMode ? drawerPlaceholder : null, _jsx("div", { className: "agent-sidebar-main-surface flex flex-1 flex-col overflow-auto min-w-0", "data-agent-sidebar-main-position": position, "data-agent-sidebar-main-state": !isMobile &&
|
|
1906
|
-
!effectiveFullscreen &&
|
|
1907
|
-
!presentationMode &&
|
|
1908
|
-
panelOpen
|
|
1909
|
-
? "open"
|
|
1910
|
-
: "closed", "data-agent-sidebar-resizing": isResizing ? "true" : undefined, children: _jsx(ScreenRefreshBoundary, { children: children }) }), !isLeft && !presentationMode ? drawerPlaceholder : null, !isLeft && !presentationMode ? sidebar : null] })] }) }));
|
|
1857
|
+
(mobileAnimationEnabled ? shouldRenderPanel : open) && (_jsx("div", { className: cn("agent-sidebar-backdrop fixed inset-0 bg-foreground/40", mobileAnimationEnabled && !panelOpen && "pointer-events-none"), "data-agent-sidebar-animation": mobileAnimationEnabled ? "mobile" : undefined, "data-agent-sidebar-state": panelOpen ? "open" : "closed", style: { zIndex: SIDEBAR_OVERLAY_Z_INDEX - 1 }, onClick: () => setOpenPersisted(false) })), shouldMountPanel ? _jsx(URLSync, { browserTabId: browserTabId }) : null, isLeft && !presentationMode ? sidebar : null, isLeft && !presentationMode ? drawerPlaceholder : null, _jsx("div", { className: "agent-sidebar-main-surface flex flex-1 flex-col overflow-auto min-w-0", "data-agent-sidebar-main-position": position, "data-agent-sidebar-main-state": !isMobile && !presentationMode && panelOpen ? "open" : "closed", "data-agent-sidebar-resizing": isResizing ? "true" : undefined, children: _jsx(ScreenRefreshBoundary, { children: children }) }), !isLeft && !presentationMode ? drawerPlaceholder : null, !isLeft && !presentationMode ? sidebar : null] })] }) }));
|
|
1911
1858
|
}
|
|
1912
1859
|
/**
|
|
1913
1860
|
* Focus the agent chat composer input.
|
|
@@ -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;
|
|
66
65
|
states: {
|
|
67
66
|
clientId: number;
|
|
68
67
|
state: string;
|
|
69
68
|
}[];
|
|
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;
|
|
81
80
|
users: {
|
|
82
81
|
clientId: number;
|
|
83
82
|
lastSeen: number;
|
|
84
83
|
}[];
|
|
84
|
+
error?: undefined;
|
|
85
85
|
}>>;
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
|
|
14
14
|
*/
|
|
15
15
|
export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
16
|
-
error: string;
|
|
17
16
|
ok?: undefined;
|
|
17
|
+
error: string;
|
|
18
18
|
} | {
|
|
19
19
|
error?: undefined;
|
|
20
20
|
ok: boolean;
|
package/dist/db/migrations.js
CHANGED
|
@@ -245,11 +245,28 @@ function isServerlessRequestRuntime() {
|
|
|
245
245
|
process.env.VERCEL === "1");
|
|
246
246
|
}
|
|
247
247
|
/**
|
|
248
|
-
*
|
|
249
|
-
*
|
|
248
|
+
* Whether this app migrates at RELEASE time, so skipping on the request path
|
|
249
|
+
* is safe.
|
|
250
250
|
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
251
|
+
* Without this, "skip in serverless" silently means "never migrate" for any app
|
|
252
|
+
* that has no release entrypoint — and at the time this was written exactly one
|
|
253
|
+
* of seventeen templates had one. Existing tables keep working, so nothing
|
|
254
|
+
* fails; a newly added migration just never applies, and a fresh deploy comes
|
|
255
|
+
* up with missing tables. That is a skip indistinguishable from success, which
|
|
256
|
+
* is the failure mode this repo bans.
|
|
257
|
+
*
|
|
258
|
+
* So the request-path skip is opt-in per app. An app sets this once it owns a
|
|
259
|
+
* release migration step (see templates/analytics/scripts/migrate-production.ts
|
|
260
|
+
* and the `migrate:production` build step in its netlify.toml).
|
|
261
|
+
*/
|
|
262
|
+
function appMigratesAtRelease() {
|
|
263
|
+
const raw = process.env.AGENT_NATIVE_RELEASE_MIGRATIONS?.trim();
|
|
264
|
+
return !!raw && ["1", "true", "yes", "on"].includes(raw.toLowerCase());
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* A runtime that is ALLOWED to migrate: release scripts, scheduled jobs, and
|
|
268
|
+
* durable background workers, which are off the request path and may take as
|
|
269
|
+
* long as they need. Claimed with {@link withMigrationRuntime}.
|
|
253
270
|
*/
|
|
254
271
|
function isMigrationAuthorizedRuntime() {
|
|
255
272
|
return (globalThis.__AGENT_NATIVE_MIGRATION_RUNTIME__ === true);
|
|
@@ -322,6 +339,7 @@ export function runMigrations(migrations, options) {
|
|
|
322
339
|
// the explicit opt-in for a caller that genuinely cannot defer.
|
|
323
340
|
if (options?.runInServerlessRequest !== true &&
|
|
324
341
|
isServerlessRequestRuntime() &&
|
|
342
|
+
appMigratesAtRelease() &&
|
|
325
343
|
!isMigrationAuthorizedRuntime()) {
|
|
326
344
|
console.info(`[migrations] Skipping "${table}" migrations in a serverless request runtime`);
|
|
327
345
|
return;
|
package/dist/deploy/build.d.ts
CHANGED
|
@@ -312,3 +312,4 @@ export declare function resolveNitroBundledYjsEntry(): string;
|
|
|
312
312
|
* the small set above bundled to keep their package manifests traceable.
|
|
313
313
|
*/
|
|
314
314
|
export declare function nitroNoExternalsForPreset(targetPreset: string): true | readonly string[];
|
|
315
|
+
export declare function resolveNitroBuildReplacements(env?: NodeJS.ProcessEnv): Record<string, string>;
|