@agent-native/core 0.136.5 → 0.137.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/app/components/AgentCompletionSound.tsx +105 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +44 -35
- package/corpus/templates/analytics/app/i18n-data.ts +38 -0
- package/corpus/templates/analytics/app/pages/Settings.tsx +53 -1
- package/corpus/templates/analytics/app/pages/settings/settings-search.ts +6 -0
- package/corpus/templates/analytics/changelog/2026-08-04-choose-whether-analytics-plays-a-bell-when-the-agent-finishe.md +6 -0
- package/corpus/templates/analytics/shared/analytics-user-prefs.ts +2 -0
- package/corpus/templates/clips/app/components/import-menu.tsx +109 -0
- package/corpus/templates/clips/app/components/library/library-grid.tsx +8 -18
- package/corpus/templates/clips/app/components/library/library-layout.tsx +14 -50
- package/corpus/templates/clips/app/components/library/sort-menu.tsx +20 -6
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +10 -34
- package/corpus/templates/clips/app/routes/_app.library._index.tsx +0 -2
- package/corpus/templates/clips/changelog/2026-08-04-cleaner-library-controls-with-an-icon-only-sort-button.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-04-upload-and-loom-imports-now-live-under-one-import-menu.md +6 -0
- package/corpus/templates/content/actions/_database-utils.ts +6 -0
- package/corpus/templates/content/actions/bind-content-database-source-field.ts +273 -97
- package/corpus/templates/content/actions/change-content-database-source-role.ts +65 -29
- package/corpus/templates/content/actions/configure-document-property.ts +113 -32
- package/corpus/templates/content/actions/delete-content-database.ts +5 -7
- package/corpus/templates/content/actions/delete-document-property.ts +109 -62
- package/corpus/templates/content/actions/delete-document.ts +178 -36
- package/corpus/templates/content/actions/duplicate-database-item.ts +27 -0
- package/corpus/templates/content/actions/duplicate-database-items.ts +31 -1
- package/corpus/templates/content/actions/permanently-delete-document.ts +4 -6
- package/corpus/templates/content/actions/remove-database-items.ts +13 -0
- package/corpus/templates/content/actions/set-document-property.ts +69 -1
- package/corpus/templates/content/actions/upsert-database-item-by-key.ts +814 -0
- package/corpus/templates/content/parity/matrix.md +1 -1
- package/corpus/templates/content/parity/matrix.ts +1 -0
- package/corpus/templates/content/server/db/schema.ts +27 -0
- package/corpus/templates/content/server/plugins/db.ts +24 -0
- package/corpus/templates/design/app/components/design/BreakpointBar.tsx +122 -114
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +2 -2
- package/corpus/templates/design/app/components/design/EditPanel.tsx +68 -34
- package/corpus/templates/design/app/components/design/KeyboardShortcutsPanel.tsx +78 -4
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +8 -0
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +5 -2
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +10 -9
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +31 -69
- package/corpus/templates/design/app/components/design/inspector/design-icons.tsx +80 -106
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +4 -0
- package/corpus/templates/design/app/hooks/use-editor-preferences.ts +75 -0
- package/corpus/templates/design/app/i18n-data.ts +8 -0
- package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +61 -0
- package/corpus/templates/design/app/pages/design-editor/editor-preferences.ts +98 -0
- package/corpus/templates/design/app/pages/design-editor/nudge-intent.ts +491 -0
- package/corpus/templates/design/app/pages/design-editor/paste-placement.ts +133 -0
- package/corpus/templates/design/app/pages/design-editor/png-export-render.ts +8 -0
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -12
- package/corpus/templates/design/changelog/2026-08-03-arrow-keys-now-reorder-a-layer-inside-an-auto-layout-frame.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-auto-layout-flow-icons-show-the-direction-at-a-glance-instea.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-auto-layout-icons-share-one-outlined-square-style-so-flow-ga.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-export-has-a-named-preview-section-you-can-expand-replacing-.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-export-preview-shows-the-selected-element-instead-of-the-who.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-inspector-sections-show-an-expand-indicator-so-it-is-clear-w.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-paste-lands-inside-a-selected-frame-instead-of-beside-it.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-the-add-breakpoint-button-sits-outside-the-breakpoint-select.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-the-agent-s-follow-up-questions-keep-space-below-the-continu.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-the-agent-s-follow-up-questions-share-the-chat-panel-s-backg.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-the-export-panel-no-longer-stacks-a-duplicate-export-block-o.md +6 -0
- package/corpus/templates/design/changelog/2026-08-03-the-text-tool-uses-a-t-icon-matching-the-letter-it-inserts.md +6 -0
- package/corpus/templates/factory/.env.example +17 -0
- package/corpus/templates/factory/AGENTS.md +27 -17
- package/corpus/templates/factory/README.md +19 -9
- package/corpus/templates/factory/actions/get-slack-feedback-context.ts +90 -0
- package/corpus/templates/factory/actions/get-triage-config.ts +14 -3
- package/corpus/templates/factory/actions/govern-agent-native-pull-request.ts +386 -0
- package/corpus/templates/factory/actions/list-factory-automations.ts +53 -0
- package/corpus/templates/factory/actions/list-triage-items.ts +7 -2
- package/corpus/templates/factory/actions/poll-github-sources.ts +203 -0
- package/corpus/templates/factory/actions/poll-sentry-errors.ts +161 -0
- package/corpus/templates/factory/actions/poll-slack-channel.ts +4 -2
- package/corpus/templates/factory/actions/run-factory-automation.ts +42 -0
- package/corpus/templates/factory/actions/save-factory-automation.ts +69 -0
- package/corpus/templates/factory/actions/save-triage-config.ts +28 -2
- package/corpus/templates/factory/actions/start-builder-for-item.ts +411 -0
- package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +14 -3
- package/corpus/templates/factory/app/components/ui/checkbox.tsx +1 -0
- package/corpus/templates/factory/app/hooks/use-navigation-state.ts +7 -0
- package/corpus/templates/factory/app/i18n/en-US.ts +35 -1
- package/corpus/templates/factory/app/routes/factory.tsx +462 -9
- package/corpus/templates/factory/changelog/2026-08-04-added-organization-owned-factory-automations-for-slack-bug-t.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-04-automation-editor-controls-and-model-picker.md +6 -0
- package/corpus/templates/factory/netlify.toml +2 -2
- package/corpus/templates/factory/server/connectors/credentials.ts +6 -5
- package/corpus/templates/factory/server/connectors/slack.ts +133 -5
- package/corpus/templates/factory/server/db/schema.ts +6 -0
- package/corpus/templates/factory/server/lib/require-factory-automation.ts +65 -0
- package/corpus/templates/factory/server/plugins/agent-chat.ts +29 -11
- package/corpus/templates/factory/server/plugins/auth.ts +1 -0
- package/corpus/templates/factory/server/plugins/factory-migrations.ts +12 -0
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +218 -67
- package/corpus/templates/factory/server/triage/builder-executor.ts +4 -0
- package/corpus/templates/factory/server/triage/contracts.ts +14 -1
- package/corpus/templates/factory/server/triage/github-client.ts +404 -0
- package/corpus/templates/factory/server/triage/metadata.ts +44 -0
- package/corpus/templates/factory/server/triage/pr-babysit.ts +5 -5
- package/corpus/templates/factory/server/triage/pr-policy.ts +144 -0
- package/corpus/templates/factory/server/triage/sentry-client.ts +180 -0
- package/corpus/templates/factory/server/triage/slack-client.ts +43 -0
- package/corpus/templates/factory/server/triage/slack-poller.ts +9 -2
- package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +27 -0
- package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +14 -4
- package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +7 -0
- package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +7 -0
- package/corpus/templates/plan/actions/create-plan-design.ts +8 -6
- package/corpus/templates/plan/actions/create-prototype-plan.ts +8 -6
- package/corpus/templates/plan/actions/create-ui-plan.ts +7 -7
- package/corpus/templates/plan/actions/get-plan-blocks.ts +7 -1
- package/corpus/templates/plan/actions/validate-plan-input.ts +39 -0
- package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +167 -11
- package/corpus/templates/plan/app/i18n/en-US.ts +1 -0
- package/corpus/templates/plan/changelog/2026-08-04-canvas-zoom-controls-now-explain-the-command-ctrl-plus-scrol.md +6 -0
- package/corpus/templates/plan/changelog/2026-08-04-pinch-to-zoom-is-now-supported-on-touchscreens-in-visual-pla.md +6 -0
- package/corpus/templates/plan/shared/plan-content.ts +17 -2
- package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +321 -0
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +32 -11
- package/corpus/templates/slides/app/lib/recent-references.ts +82 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +3 -0
- package/corpus/templates/slides/app/pages/Index.tsx +236 -181
- package/dist/cli/skills-content/canvas.d.ts +3 -3
- package/dist/cli/skills-content/canvas.js +16 -5
- package/dist/cli/skills-content/visual-plan-skill.d.ts +1 -1
- package/dist/cli/skills-content/visual-plan-skill.js +27 -0
- package/dist/cli/skills-content/wireframe.d.ts +2 -2
- package/dist/cli/skills-content/wireframe.js +7 -0
- package/dist/client/AgentPanel.js +23 -8
- package/dist/client/DefaultSpinner.d.ts +0 -12
- package/dist/client/DefaultSpinner.js +22 -2
- package/dist/client/api-path.d.ts +6 -0
- package/dist/client/api-path.js +55 -0
- package/dist/client/onboarding/FirstRunOnboarding.d.ts +3 -0
- package/dist/client/onboarding/FirstRunOnboarding.js +93 -0
- package/dist/client/onboarding/first-run-enabled.d.ts +2 -0
- package/dist/client/onboarding/first-run-enabled.js +9 -0
- package/dist/client/onboarding/index.d.ts +2 -1
- package/dist/client/onboarding/index.js +1 -0
- package/dist/client/onboarding/use-onboarding.d.ts +6 -1
- package/dist/client/onboarding/use-onboarding.js +35 -1
- package/dist/client/route-state.js +10 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +4 -4
- package/dist/connections/catalog.js +3 -3
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +1 -1
- package/dist/deploy/build.js +2 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +1 -1
- package/dist/onboarding/app-profile.d.ts +4 -0
- package/dist/onboarding/app-profile.js +378 -0
- package/dist/onboarding/index.d.ts +2 -1
- package/dist/onboarding/index.js +1 -0
- package/dist/onboarding/plugin.d.ts +2 -0
- package/dist/onboarding/plugin.js +21 -1
- package/dist/onboarding/types.d.ts +19 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
- package/dist/provider-api/actions/provider-api.d.ts +12 -12
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/auth.js +21 -1
- package/dist/server/better-auth-instance.d.ts +3 -2
- package/dist/server/better-auth-instance.js +9 -7
- package/dist/server/email-markdown.js +3 -8
- package/dist/shared/first-run-onboarding.d.ts +3 -0
- package/dist/shared/first-run-onboarding.js +3 -0
- package/dist/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +25 -9
- package/dist/triggers/index.d.ts +3 -0
- package/dist/triggers/index.js +5 -0
- package/docs/content/cross-app-sso.mdx +26 -0
- package/package.json +1 -1
- package/src/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +25 -9
|
@@ -42,7 +42,7 @@ import { Link, useLocation, useNavigate } from "react-router";
|
|
|
42
42
|
import { withBuilderUtmTrackingParams } from "../shared/builder-link-tracking.js";
|
|
43
43
|
import { consumeAgentSidebarUrlOpenOverride, dispatchAgentSidebarStateChange, getInitialAgentSidebarOpen, setAgentSidebarOpenPreference, subscribeAgentSidebarUrlChanges, SIDEBAR_STATE_CHANGE_EVENT, } from "./agent-sidebar-state.js";
|
|
44
44
|
import { trackEvent } from "./analytics.js";
|
|
45
|
-
import { agentNativePath, appPath } from "./api-path.js";
|
|
45
|
+
import { agentNativePath, appPath, isWorkspaceAppPath } from "./api-path.js";
|
|
46
46
|
import { readClientAppState } from "./application-state.js";
|
|
47
47
|
import { assistantUiRecoverableRenderErrorKind } from "./assistant-ui-recovery.js";
|
|
48
48
|
import { shouldParentFrameOwnAgentPanel } from "./builder-frame.js";
|
|
@@ -51,6 +51,7 @@ import { fetchBuilderStatus } from "./client-status-requests.js";
|
|
|
51
51
|
import { RealtimeVoiceModeProvider } from "./composer/index.js";
|
|
52
52
|
import { getFramePostMessageTargetOrigin, isTrustedFrameMessage, } from "./frame.js";
|
|
53
53
|
import { useT } from "./i18n.js";
|
|
54
|
+
import { isFirstRunOnboardingEnabled } from "./onboarding/first-run-enabled.js";
|
|
54
55
|
import { recoverFromStaleChunkError } from "./route-chunk-recovery.js";
|
|
55
56
|
import { AgentNativeRouteWarmup } from "./route-warmup.js";
|
|
56
57
|
import { withBuilderConnectTrackingParams } from "./settings/useBuilderStatus.js";
|
|
@@ -103,6 +104,9 @@ const SettingsPanel = lazy(() => import("./settings/index.js").then((m) => ({
|
|
|
103
104
|
const OnboardingPanel = lazy(() => import("./onboarding/OnboardingPanel.js").then((m) => ({
|
|
104
105
|
default: m.OnboardingPanel,
|
|
105
106
|
})));
|
|
107
|
+
const FirstRunOnboarding = lazy(() => import("./onboarding/FirstRunOnboarding.js").then((m) => ({
|
|
108
|
+
default: m.FirstRunOnboarding,
|
|
109
|
+
})));
|
|
106
110
|
// Lazy-load SetupButton — the header entry-point that re-opens the
|
|
107
111
|
// onboarding panel after the user has dismissed it.
|
|
108
112
|
const SetupButton = lazy(() => import("./onboarding/SetupButton.js").then((m) => ({
|
|
@@ -113,6 +117,8 @@ const SetupButton = lazy(() => import("./onboarding/SetupButton.js").then((m) =>
|
|
|
113
117
|
// GitHub, etc.) is surfaced in better places (the settings panel and the
|
|
114
118
|
// per-feature setup affordances). Keep this off; do not re-enable globally.
|
|
115
119
|
const SHOW_ONBOARDING = false;
|
|
120
|
+
const SHOW_FIRST_RUN_ONBOARDING = isFirstRunOnboardingEnabled();
|
|
121
|
+
const AgentSidebarOnboardingContext = React.createContext(false);
|
|
116
122
|
const CLI_STORAGE_KEY = "agent-native-cli-command";
|
|
117
123
|
const CLI_DEFAULT = "claude";
|
|
118
124
|
const EXEC_MODE_KEY = "agent-native-exec-mode";
|
|
@@ -385,6 +391,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
385
391
|
const t = useT();
|
|
386
392
|
const navigate = useNavigate();
|
|
387
393
|
const mounted = useClientOnly();
|
|
394
|
+
const insideAgentSidebar = React.useContext(AgentSidebarOnboardingContext);
|
|
388
395
|
const feedbackEnabled = resolveFeedbackUrl(undefined, mounted ? undefined : null) !== null;
|
|
389
396
|
const keyPrefix = storageKey ? `:${storageKey}` : "";
|
|
390
397
|
const execModeKey = `${EXEC_MODE_KEY}${keyPrefix}`;
|
|
@@ -863,7 +870,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
863
870
|
`[data-agent-fullscreen='true'] .agent-plan-mode-callout{` +
|
|
864
871
|
`max-width:${FULLSCREEN_CHAT_COLUMN_MAX_PX}px;` +
|
|
865
872
|
`margin-left:auto;margin-right:auto;width:100%;}`,
|
|
866
|
-
} }), SHOW_ONBOARDING && mounted && (_jsx(Suspense, { fallback: null, children: _jsx(OnboardingPanel, {}) })), _jsx("div", { className: cn("flex flex-col min-h-0", mode === "chat" ? "flex-1" : "shrink-0"), children: mounted && (_jsx(Suspense, { fallback: _jsx(ChatLoadingSkeleton, { renderHeader: showHeader ? renderChatHeader : undefined, centerComposerWhenEmpty: assistantChatProps.centerComposerWhenEmpty, composerSlot: assistantChatProps.composerSlot, composerAreaClassName: assistantChatProps.composerAreaClassName, composerLayoutVariant: assistantChatProps.composerLayoutVariant }), children: _jsx(MultiTabAssistantChatLazy, { ...assistantChatProps, agentChatSurface: effectiveAgentChatSurface, apiUrl: apiUrl, showHeader: false, renderHeader: showHeader ? renderChatHeader : undefined, showTabBar: showTabBar, renderOverlay: showPageNewChatButton && !showHeader
|
|
873
|
+
} }), SHOW_ONBOARDING && mounted && (_jsx(Suspense, { fallback: null, children: _jsx(OnboardingPanel, {}) })), SHOW_FIRST_RUN_ONBOARDING && mounted && !insideAgentSidebar && (_jsx(Suspense, { fallback: null, children: _jsx(FirstRunOnboarding, {}) })), _jsx("div", { className: cn("flex flex-col min-h-0", mode === "chat" ? "flex-1" : "shrink-0"), children: mounted && (_jsx(Suspense, { fallback: _jsx(ChatLoadingSkeleton, { renderHeader: showHeader ? renderChatHeader : undefined, centerComposerWhenEmpty: assistantChatProps.centerComposerWhenEmpty, composerSlot: assistantChatProps.composerSlot, composerAreaClassName: assistantChatProps.composerAreaClassName, composerLayoutVariant: assistantChatProps.composerLayoutVariant }), children: _jsx(MultiTabAssistantChatLazy, { ...assistantChatProps, agentChatSurface: effectiveAgentChatSurface, apiUrl: apiUrl, showHeader: false, renderHeader: showHeader ? renderChatHeader : undefined, showTabBar: showTabBar, renderOverlay: showPageNewChatButton && !showHeader
|
|
867
874
|
? renderPageChatOverlay
|
|
868
875
|
: undefined, contentHidden: mode !== "chat", emptyStateText: emptyStateText, emptyStateAddon: emptyStateAddon, suggestions: suggestions, dynamicSuggestions: dynamicSuggestions, onSwitchToCli: () => switchMode("cli"), execMode: execMode, onExecModeChange: switchExecMode, storageKey: storageKey, restoreActiveThread: restoreActiveThread, scope: scope, showScopeBadge: showScopeBadge, browserTabId: browserTabId, threadUrlSync: threadUrlSync }) })) }), canUseCodeTools
|
|
869
876
|
? mode === "cli" &&
|
|
@@ -1139,7 +1146,12 @@ function URLSync({ browserTabId }) {
|
|
|
1139
1146
|
// Replace rather than push so repeated agent URL updates don't
|
|
1140
1147
|
// clutter the history stack and can't trigger extra remounts from
|
|
1141
1148
|
// router navigation lifecycle.
|
|
1142
|
-
|
|
1149
|
+
if (isWorkspaceAppPath(url)) {
|
|
1150
|
+
window.location.replace(url);
|
|
1151
|
+
}
|
|
1152
|
+
else {
|
|
1153
|
+
window.setTimeout(() => navigate(url, { replace: true }), 0);
|
|
1154
|
+
}
|
|
1143
1155
|
}
|
|
1144
1156
|
catch {
|
|
1145
1157
|
// Malformed command — ignore.
|
|
@@ -1723,11 +1735,14 @@ export function AgentSidebar({ children, emptyStateText = "How can I help you?",
|
|
|
1723
1735
|
: 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
|
|
1724
1736
|
? getAgentChatViewTransitionStyle(panelStyle)
|
|
1725
1737
|
: 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), isFullscreen: effectiveFullscreen, onToggleFullscreen: isMobile ? undefined : (onFullscreenRequest ?? toggleFullscreen), 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;
|
|
1726
|
-
return (_jsx(RealtimeVoiceModeProvider, { browserTabId: browserTabId, children: _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: [_jsx(AgentNativeRouteWarmup, {}), isMobile &&
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1738
|
+
return (_jsx(AgentSidebarOnboardingContext.Provider, { value: true, children: _jsxs(RealtimeVoiceModeProvider, { browserTabId: browserTabId, children: [SHOW_FIRST_RUN_ONBOARDING && (_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: [_jsx(AgentNativeRouteWarmup, {}), isMobile &&
|
|
1739
|
+
!presentationMode &&
|
|
1740
|
+
(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, _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 &&
|
|
1741
|
+
!effectiveFullscreen &&
|
|
1742
|
+
!presentationMode &&
|
|
1743
|
+
panelOpen
|
|
1744
|
+
? "open"
|
|
1745
|
+
: "closed", "data-agent-sidebar-resizing": isResizing ? "true" : undefined, children: _jsx(ScreenRefreshBoundary, { children: children }) }), !isLeft && !presentationMode ? sidebar : null] })] }) }));
|
|
1731
1746
|
}
|
|
1732
1747
|
/**
|
|
1733
1748
|
* Focus the agent chat composer input.
|
|
@@ -1,14 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Full-screen loading spinner rendered during SSR and initial hydration.
|
|
3
|
-
* Uses inline SVG + styles because Tailwind may not be loaded yet on the server.
|
|
4
|
-
* Respects the user's OS color scheme so dark-mode users don't get a white flash.
|
|
5
|
-
*
|
|
6
|
-
* The stall hint is revealed by a pure-CSS `animation-delay`, never a timer:
|
|
7
|
-
* the states that strand a user here (hydration never runs, the route module
|
|
8
|
-
* 404s, a cold dev-server compile) are exactly the states where no JS of ours
|
|
9
|
-
* executes, so a `setTimeout` fallback would never fire. A featureless spinner
|
|
10
|
-
* is indistinguishable from a blank screen, and reads as "the app is broken"
|
|
11
|
-
* rather than "look at the terminal" — that mis-read is what this text buys.
|
|
12
|
-
*/
|
|
13
1
|
export declare function DefaultSpinner(): import("react").JSX.Element;
|
|
14
2
|
//# sourceMappingURL=DefaultSpinner.d.ts.map
|
|
@@ -1,17 +1,33 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
2
3
|
/**
|
|
3
4
|
* Full-screen loading spinner rendered during SSR and initial hydration.
|
|
4
5
|
* Uses inline SVG + styles because Tailwind may not be loaded yet on the server.
|
|
5
6
|
* Respects the user's OS color scheme so dark-mode users don't get a white flash.
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
+
* In development builds, the stall hint is revealed by a pure-CSS
|
|
9
|
+
* `animation-delay`, never a timer:
|
|
8
10
|
* the states that strand a user here (hydration never runs, the route module
|
|
9
11
|
* 404s, a cold dev-server compile) are exactly the states where no JS of ours
|
|
10
12
|
* executes, so a `setTimeout` fallback would never fire. A featureless spinner
|
|
11
13
|
* is indistinguishable from a blank screen, and reads as "the app is broken"
|
|
12
14
|
* rather than "look at the terminal" — that mis-read is what this text buys.
|
|
13
15
|
*/
|
|
16
|
+
function isDevelopmentBuild() {
|
|
17
|
+
if (typeof process !== "undefined" &&
|
|
18
|
+
process.env?.NODE_ENV === "production") {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
const viteEnv = import.meta.env;
|
|
22
|
+
if (viteEnv?.PROD === true)
|
|
23
|
+
return false;
|
|
24
|
+
return viteEnv?.DEV === true;
|
|
25
|
+
}
|
|
14
26
|
export function DefaultSpinner() {
|
|
27
|
+
const [showStallHint, setShowStallHint] = useState(false);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
setShowStallHint(isDevelopmentBuild());
|
|
30
|
+
}, []);
|
|
15
31
|
return (_jsxs("div", { style: {
|
|
16
32
|
display: "flex",
|
|
17
33
|
flexDirection: "column",
|
|
@@ -20,8 +36,10 @@ export function DefaultSpinner() {
|
|
|
20
36
|
gap: 16,
|
|
21
37
|
height: "100vh",
|
|
22
38
|
width: "100%",
|
|
23
|
-
}, children: [_jsx("svg", { role: "status", "aria-label": "Loading", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: { animation: "an-spin 1s linear infinite", opacity: 0.7 }, children: _jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) }), _jsx("p", { className: "an-stall-hint", children: "Still loading. A first run compiles dependencies and can take a minute \u2014 if it does not finish, check the terminal running the dev server for errors." }), _jsx("style", { children: `
|
|
39
|
+
}, children: [_jsx("svg", { role: "status", "aria-label": "Loading", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: { animation: "an-spin 1s linear infinite", opacity: 0.7 }, children: _jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) }), showStallHint && (_jsx("p", { className: "an-stall-hint", children: "Still loading. A first run compiles dependencies and can take a minute \u2014 if it does not finish, check the terminal running the dev server for errors." })), _jsx("style", { children: `
|
|
24
40
|
@keyframes an-spin { to { transform: rotate(360deg) } }
|
|
41
|
+
${showStallHint
|
|
42
|
+
? `
|
|
25
43
|
@keyframes an-stall-in { to { opacity: 0.6 } }
|
|
26
44
|
.an-stall-hint {
|
|
27
45
|
opacity: 0;
|
|
@@ -37,6 +55,8 @@ export function DefaultSpinner() {
|
|
|
37
55
|
@media (prefers-reduced-motion: reduce) {
|
|
38
56
|
.an-stall-hint { animation-duration: 0s }
|
|
39
57
|
}
|
|
58
|
+
`
|
|
59
|
+
: ""}
|
|
40
60
|
html {
|
|
41
61
|
background: hsl(var(--background, 0 0% 100%));
|
|
42
62
|
color: hsl(var(--foreground, 240 10% 3.9%));
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
export declare function appBasePath(): string;
|
|
2
|
+
/**
|
|
3
|
+
* Returns true for a same-origin path mounted at a sibling workspace app.
|
|
4
|
+
* React Router treats root paths as local to its basename, so these targets
|
|
5
|
+
* must use the browser location instead of the app-local router.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isWorkspaceAppPath(path: string): boolean;
|
|
2
8
|
export declare function appPath(path: string): string;
|
|
3
9
|
export declare function appApiPath(path: string): string;
|
|
4
10
|
export declare function agentNativePath(path: string): string;
|
package/dist/client/api-path.js
CHANGED
|
@@ -88,6 +88,61 @@ export function appBasePath() {
|
|
|
88
88
|
// app build into another. Prefer the live mount path when they disagree.
|
|
89
89
|
return derived || workspacePathBasePath() || configured;
|
|
90
90
|
}
|
|
91
|
+
function workspaceAppMountPaths() {
|
|
92
|
+
const raw = clientEnv()?.VITE_AGENT_NATIVE_WORKSPACE_APPS_JSON;
|
|
93
|
+
if (typeof raw !== "string" || !raw.trim())
|
|
94
|
+
return null;
|
|
95
|
+
try {
|
|
96
|
+
const parsed = JSON.parse(raw);
|
|
97
|
+
const entries = Array.isArray(parsed)
|
|
98
|
+
? parsed
|
|
99
|
+
: parsed && typeof parsed === "object" && "apps" in parsed
|
|
100
|
+
? parsed.apps
|
|
101
|
+
: null;
|
|
102
|
+
if (!Array.isArray(entries))
|
|
103
|
+
return null;
|
|
104
|
+
const paths = entries
|
|
105
|
+
.map((entry) => {
|
|
106
|
+
if (!entry || typeof entry !== "object")
|
|
107
|
+
return null;
|
|
108
|
+
const record = entry;
|
|
109
|
+
const rawPath = typeof record.path === "string"
|
|
110
|
+
? record.path
|
|
111
|
+
: typeof record.id === "string"
|
|
112
|
+
? `/${record.id}`
|
|
113
|
+
: null;
|
|
114
|
+
return rawPath?.startsWith("/") ? normalizeBasePath(rawPath) : null;
|
|
115
|
+
})
|
|
116
|
+
.filter((path) => Boolean(path));
|
|
117
|
+
return paths.length ? new Set(paths) : null;
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// coercion-ok: malformed manifests cannot authorize cross-app navigation
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Returns true for a same-origin path mounted at a sibling workspace app.
|
|
126
|
+
* React Router treats root paths as local to its basename, so these targets
|
|
127
|
+
* must use the browser location instead of the app-local router.
|
|
128
|
+
*/
|
|
129
|
+
export function isWorkspaceAppPath(path) {
|
|
130
|
+
if (typeof window === "undefined" || !path.startsWith("/"))
|
|
131
|
+
return false;
|
|
132
|
+
if (!isWorkspaceRuntime())
|
|
133
|
+
return false;
|
|
134
|
+
const targetPath = path.split(/[?#]/, 1)[0] || "/";
|
|
135
|
+
const basePath = appBasePath();
|
|
136
|
+
if (!basePath)
|
|
137
|
+
return false;
|
|
138
|
+
if (targetPath === basePath || targetPath.startsWith(`${basePath}/`)) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
const mounts = workspaceAppMountPaths();
|
|
142
|
+
if (!mounts)
|
|
143
|
+
return false;
|
|
144
|
+
return [...mounts].some((mount) => targetPath === mount || targetPath.startsWith(`${mount}/`));
|
|
145
|
+
}
|
|
91
146
|
export function appPath(path) {
|
|
92
147
|
if (!path.startsWith("/"))
|
|
93
148
|
return path;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Skeleton } from "@agent-native/toolkit/ui/skeleton";
|
|
3
|
+
import { IconArrowRight, IconBrandGithub, IconCheck, IconExternalLink, IconInfoCircle, IconKey, IconLoader2, } from "@tabler/icons-react";
|
|
4
|
+
import React, { useMemo, useState } from "react";
|
|
5
|
+
import { appPath } from "../api-path.js";
|
|
6
|
+
import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
|
|
7
|
+
import { useBuilderConnectFlow } from "../settings/useBuilderStatus.js";
|
|
8
|
+
import { cn } from "../utils.js";
|
|
9
|
+
import { useOnboarding } from "./use-onboarding.js";
|
|
10
|
+
const BUILDER_MORE_SERVICES = [
|
|
11
|
+
"Voice input",
|
|
12
|
+
"Background agents",
|
|
13
|
+
"Image generation",
|
|
14
|
+
"Video generation",
|
|
15
|
+
"Connected agents",
|
|
16
|
+
"Hosting and deployment",
|
|
17
|
+
"Browser automation",
|
|
18
|
+
"Embeddings",
|
|
19
|
+
];
|
|
20
|
+
export function FirstRunOnboarding() {
|
|
21
|
+
const { firstRun, loading, error, profile, completeFirstRun } = useOnboarding();
|
|
22
|
+
const [screen, setScreen] = useState("intro");
|
|
23
|
+
const showReady = () => setScreen("ready");
|
|
24
|
+
const connectFlow = useBuilderConnectFlow({
|
|
25
|
+
enabled: firstRun,
|
|
26
|
+
trackingSource: "first_run_onboarding",
|
|
27
|
+
trackingFlow: "connect_llm",
|
|
28
|
+
onConnected: showReady,
|
|
29
|
+
});
|
|
30
|
+
if (!firstRun)
|
|
31
|
+
return null;
|
|
32
|
+
if (error) {
|
|
33
|
+
return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-md flex-col items-center gap-4 text-center", children: [_jsx("h1", { className: "text-xl font-semibold tracking-[-0.03em]", children: "Setup is almost ready." }), _jsx("p", { className: "text-sm text-muted-foreground", children: "We could not load the connection options yet." }), _jsx("button", { type: "button", className: primaryButtonClass, onClick: () => window.location.reload(), children: "Try again" })] }) }));
|
|
34
|
+
}
|
|
35
|
+
if (loading || !profile) {
|
|
36
|
+
return _jsx(OnboardingSkeleton, {});
|
|
37
|
+
}
|
|
38
|
+
const builderCapabilities = profile.capabilities.filter((capability) => capability.builderIncluded);
|
|
39
|
+
const handleBuilder = () => {
|
|
40
|
+
if (connectFlow.hasFetchedStatus && connectFlow.configured) {
|
|
41
|
+
showReady();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
setScreen("connecting");
|
|
45
|
+
connectFlow.start({
|
|
46
|
+
trackingSource: "first_run_onboarding",
|
|
47
|
+
trackingFlow: "connect_llm",
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
const handleOpenSettings = async () => {
|
|
51
|
+
window.dispatchEvent(new CustomEvent("agent-panel:open-settings", {
|
|
52
|
+
detail: { section: "connections" },
|
|
53
|
+
}));
|
|
54
|
+
await completeFirstRun();
|
|
55
|
+
};
|
|
56
|
+
const handleFinish = async () => {
|
|
57
|
+
await completeFirstRun();
|
|
58
|
+
};
|
|
59
|
+
if (screen === "intro") {
|
|
60
|
+
return (_jsx(OnboardingShell, { profile: profile, screen: "intro", children: _jsxs("div", { className: "mx-auto flex w-full max-w-lg flex-col items-center text-center", children: [_jsxs("h1", { className: "text-3xl font-semibold tracking-[-0.05em] sm:text-4xl", children: ["Free forever.", _jsx("br", {}), _jsx("span", { className: "text-primary", children: "Open source for life." })] }), _jsxs("div", { className: "mt-7 grid w-full gap-2 text-left sm:grid-cols-3", children: [_jsxs("div", { className: "rounded-lg border border-border bg-card px-3 py-3", children: [_jsx("p", { className: "text-xs font-medium", children: "Fully customizable" }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: "Change the UI, code, and behavior." })] }), _jsxs("div", { className: "rounded-lg border border-border bg-card px-3 py-3", children: [_jsx("p", { className: "text-xs font-medium", children: "Bring your own keys" }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: "Use your own providers and accounts." })] }), _jsxs("div", { className: "rounded-lg border border-border bg-card px-3 py-3", children: [_jsx("p", { className: "text-xs font-medium", children: "Build your own" }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: "Mix and match toolkit pieces in your own apps." })] })] }), _jsxs("button", { type: "button", className: cn(primaryButtonClass, "mt-6"), onClick: () => setScreen("choice"), children: ["Continue", _jsx(IconArrowRight, { size: 15 })] }), _jsxs("a", { href: "https://github.com/builderio/agent-native", target: "_blank", rel: "noreferrer", className: "mt-3 inline-flex items-center gap-1.5 text-xs text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [_jsx(IconBrandGithub, { size: 14 }), _jsx("span", { children: "View source" }), _jsx(IconExternalLink, { size: 13 })] })] }) }));
|
|
61
|
+
}
|
|
62
|
+
if (screen === "choice") {
|
|
63
|
+
return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-4", children: [_jsx("h1", { className: "text-center text-xl font-semibold tracking-[-0.04em] sm:text-2xl", children: "Choose your setup." }), _jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [_jsxs("section", { className: "rounded-xl border border-primary/50 bg-primary/[0.06] p-4 shadow-sm", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold", children: "Connect Builder.io" }), _jsxs("p", { className: "mt-1 max-w-xs text-xs leading-5 text-muted-foreground", children: ["One click connects", " ", _jsx("a", { href: "https://www.builder.io/", target: "_blank", rel: "noreferrer", className: "text-foreground underline decoration-border underline-offset-2 hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: "Builder.io's free tier" }), " ", "with the services this app needs."] })] }), _jsx(IconArrowRight, { className: "mt-0.5 text-primary", size: 17 })] }), _jsxs("div", { className: "mt-5 border-t border-primary/15 pt-3", children: [_jsx("p", { className: "text-[11px] font-medium text-muted-foreground", children: "Includes on the free tier" }), _jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-1.5 gap-y-1 text-[11px]", children: [builderCapabilities.map((capability, index) => (_jsxs(React.Fragment, { children: [index > 0 && (_jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u00B7" })), _jsx("span", { children: capability.label })] }, capability.id))), _jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u00B7" }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "text-primary underline-offset-2 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": `See ${BUILDER_MORE_SERVICES.length} more Builder.io services`, children: ["+", BUILDER_MORE_SERVICES.length, " more"] }) }), _jsxs(TooltipContent, { side: "top", className: "max-w-sm text-xs", children: [_jsx("p", { className: "font-medium", children: "Also included with Builder.io" }), _jsx("p", { className: "mt-1 leading-5", children: BUILDER_MORE_SERVICES.join(" · ") })] })] })] })] }), _jsxs("button", { type: "button", "data-testid": "first-run-connect-builder", className: cn(primaryButtonClass, "mt-5 w-full"), onClick: handleBuilder, children: ["Connect Builder.io", _jsx(IconArrowRight, { size: 15 })] })] }), _jsxs("div", { role: "button", tabIndex: 0, "aria-label": "Use my own keys", "data-testid": "first-run-use-own-keys", className: "rounded-xl border border-border bg-card p-4 text-left transition-colors hover:border-foreground/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: () => setScreen("manual"), onKeyDown: (event) => {
|
|
64
|
+
if (event.key !== "Enter" && event.key !== " ")
|
|
65
|
+
return;
|
|
66
|
+
event.preventDefault();
|
|
67
|
+
setScreen("manual");
|
|
68
|
+
}, children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold", children: "Use my own keys" }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "See what this app needs" })] }), _jsx(IconKey, { className: "text-muted-foreground", size: 17 })] }), _jsx(CapabilityList, { capabilities: profile.capabilities, compact: true, className: "mt-5 border-t border-border pt-3" })] })] })] }) }));
|
|
69
|
+
}
|
|
70
|
+
if (screen === "manual") {
|
|
71
|
+
return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-xl flex-col gap-4", children: [_jsxs("div", { children: [_jsx("button", { type: "button", className: "mb-4 text-xs text-muted-foreground hover:text-foreground", onClick: () => setScreen("choice"), children: "Back" }), _jsx("h1", { className: "text-xl font-semibold tracking-[-0.04em] sm:text-2xl", children: "Your keys" })] }), _jsxs("div", { className: "rounded-xl border border-border bg-card p-4", children: [_jsx(CapabilityList, { capabilities: profile.capabilities }), _jsxs("div", { className: "mt-5 flex flex-col-reverse gap-2 border-t border-border pt-4 sm:flex-row sm:justify-between", children: [_jsx("button", { type: "button", className: secondaryButtonClass, onClick: () => setScreen("choice"), children: "Back" }), _jsxs("button", { type: "button", className: primaryButtonClass, onClick: handleOpenSettings, children: ["Open key settings", _jsx(IconArrowRight, { size: 15 })] })] })] })] }) }));
|
|
72
|
+
}
|
|
73
|
+
if (screen === "connecting") {
|
|
74
|
+
return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-md flex-col items-center text-center", children: [_jsx("div", { className: "flex size-10 items-center justify-center rounded-full bg-primary/10 text-primary", children: _jsx(IconLoader2, { className: "animate-spin", size: 19 }) }), _jsx("h1", { className: "mt-5 text-xl font-semibold tracking-[-0.04em]", children: "Connecting Builder.io" }), _jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Finish the one-click connection in the new window." }), _jsxs("div", { className: "mt-7 w-full rounded-xl border border-border bg-card p-4 text-left", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx(Skeleton, { className: "h-3 w-28" }), _jsx(Skeleton, { className: "h-5 w-16 rounded-full" })] }), _jsx(Skeleton, { className: "mt-4 h-8 w-full" }), _jsxs("div", { className: "mt-3 grid grid-cols-3 gap-2", children: [_jsx(Skeleton, { className: "h-7 w-full" }), _jsx(Skeleton, { className: "h-7 w-full" }), _jsx(Skeleton, { className: "h-7 w-full" })] })] }), connectFlow.error && (_jsxs("div", { className: "mt-4 flex flex-col items-center gap-2", children: [_jsx("p", { className: "text-xs text-destructive", children: connectFlow.error }), _jsx("button", { type: "button", className: secondaryButtonClass, onClick: () => setScreen("choice"), children: "Try again" })] }))] }) }));
|
|
75
|
+
}
|
|
76
|
+
return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-md flex-col items-center text-center", children: [_jsx("div", { className: "flex size-10 items-center justify-center rounded-full bg-primary/10 text-primary", children: _jsx(IconCheck, { size: 20 }) }), _jsx("h1", { className: "mt-5 text-xl font-semibold tracking-[-0.04em]", children: "Ready to go." }), _jsxs("button", { type: "button", "data-testid": "first-run-open-app", className: cn(primaryButtonClass, "mt-7"), onClick: handleFinish, children: ["Open app", _jsx(IconArrowRight, { size: 15 })] })] }) }));
|
|
77
|
+
}
|
|
78
|
+
function OnboardingShell({ profile, screen, children, }) {
|
|
79
|
+
return (_jsxs("div", { className: "fixed inset-0 z-[100] flex min-h-screen flex-col bg-background text-foreground", "data-onboarding-screen": screen, role: "dialog", "aria-modal": "true", "aria-label": `${profile?.appName ?? "Your app"} setup`, children: [_jsxs("header", { className: "flex items-center justify-between border-b border-border px-5 py-4 text-xs text-muted-foreground sm:px-8", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("img", { src: appPath("/agent-native-icon-dark.svg"), alt: "", "aria-hidden": "true", className: "h-4 w-auto shrink-0" }), _jsx("span", { className: "font-medium text-foreground", children: profile?.appName ?? "Your app" })] }), _jsx("span", { children: screen === "intro" ? "1 / 2" : "2 / 2" })] }), _jsx("div", { className: "h-0.5 bg-muted", children: _jsx("div", { className: "h-full bg-primary transition-[width] duration-200", style: { width: screen === "intro" ? "50%" : "100%" } }) }), _jsx("main", { className: "flex min-h-0 flex-1 items-center overflow-y-auto px-5 py-10 sm:px-8", children: _jsx("div", { className: "mx-auto w-full max-w-3xl", children: children }) })] }));
|
|
80
|
+
}
|
|
81
|
+
function OnboardingSkeleton() {
|
|
82
|
+
return (_jsxs("div", { className: "fixed inset-0 z-[100] flex min-h-screen flex-col bg-background px-5 py-5 sm:px-8", "data-onboarding-loading": "true", "aria-busy": "true", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Skeleton, { className: "h-4 w-20" }), _jsx(Skeleton, { className: "h-3 w-8" })] }), _jsx(Skeleton, { className: "mt-5 h-0.5 w-full" }), _jsxs("div", { className: "mx-auto flex w-full max-w-lg flex-1 flex-col items-center justify-center", children: [_jsx(Skeleton, { className: "h-10 w-64" }), _jsx(Skeleton, { className: "mt-3 h-10 w-52" }), _jsx(Skeleton, { className: "mt-7 h-3 w-44" }), _jsx(Skeleton, { className: "mt-7 h-10 w-24 rounded-lg" })] })] }));
|
|
83
|
+
}
|
|
84
|
+
function CapabilityList({ capabilities, compact = false, className, }) {
|
|
85
|
+
const visibleCapabilities = useMemo(() => (compact ? capabilities.slice(0, 4) : capabilities), [capabilities, compact]);
|
|
86
|
+
return (_jsxs("div", { className: cn("grid", className), children: [!compact && (_jsx("p", { className: "mb-2 text-xs font-medium text-muted-foreground", children: "Keys and connections" })), _jsx("div", { className: "divide-y divide-border", children: visibleCapabilities.map((capability) => (_jsx(CapabilityRow, { capability: capability, compact: compact }, capability.id))) })] }));
|
|
87
|
+
}
|
|
88
|
+
function CapabilityRow({ capability, compact, }) {
|
|
89
|
+
return (_jsxs("div", { className: cn("flex items-start justify-between gap-3", compact ? "py-2" : "py-3"), children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: cn("font-medium", compact ? "text-[11px]" : "text-sm"), children: capability.label }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": `Why ${capability.label} is needed`, className: "inline-flex size-4 items-center justify-center rounded-full text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: _jsx(IconInfoCircle, { size: 13 }) }) }), _jsx(TooltipContent, { side: "top", className: "max-w-xs text-xs", children: capability.why })] })] }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: capability.keySummary })] }), _jsx("span", { className: cn("shrink-0 text-[10px] uppercase tracking-[0.08em]", capability.required ? "text-primary" : "text-muted-foreground"), children: capability.required ? "Required" : "Optional" })] }));
|
|
90
|
+
}
|
|
91
|
+
const primaryButtonClass = "inline-flex min-h-9 items-center justify-center gap-2 rounded-lg bg-primary px-4 text-xs font-medium text-primary-foreground shadow-sm transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
|
|
92
|
+
const secondaryButtonClass = "inline-flex min-h-9 items-center justify-center gap-2 rounded-lg border border-border bg-background px-4 text-xs font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
|
|
93
|
+
//# sourceMappingURL=FirstRunOnboarding.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const FIRST_RUN_ONBOARDING_ENV_KEY = "VITE_AGENT_NATIVE_FIRST_RUN_ONBOARDING";
|
|
2
|
+
export function isFirstRunOnboardingEnabled(env = (import.meta.env ??
|
|
3
|
+
{})) {
|
|
4
|
+
const value = env[FIRST_RUN_ONBOARDING_ENV_KEY];
|
|
5
|
+
return (value === true ||
|
|
6
|
+
(typeof value === "string" &&
|
|
7
|
+
["1", "true"].includes(value.trim().toLowerCase())));
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=first-run-enabled.js.map
|
|
@@ -8,6 +8,7 @@ export { useOnboardingPreviewMode, ONBOARDING_PREVIEW_STORAGE_KEY, } from "./use
|
|
|
8
8
|
export { OnboardingPanel } from "./OnboardingPanel.js";
|
|
9
9
|
export { OnboardingBanner } from "./OnboardingBanner.js";
|
|
10
10
|
export { SetupButton } from "./SetupButton.js";
|
|
11
|
-
export
|
|
11
|
+
export { FirstRunOnboarding } from "./FirstRunOnboarding.js";
|
|
12
|
+
export type { OnboardingStep, OnboardingMethod, OnboardingMethodBadge, OnboardingFormField, OnboardingStepStatus, OnboardingCapability, OnboardingAppProfile, } from "../../onboarding/types.js";
|
|
12
13
|
export { registerOnboardingStep, listOnboardingSteps, } from "../../onboarding/registry.js";
|
|
13
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -8,5 +8,6 @@ export { useOnboardingPreviewMode, ONBOARDING_PREVIEW_STORAGE_KEY, } from "./use
|
|
|
8
8
|
export { OnboardingPanel } from "./OnboardingPanel.js";
|
|
9
9
|
export { OnboardingBanner } from "./OnboardingBanner.js";
|
|
10
10
|
export { SetupButton } from "./SetupButton.js";
|
|
11
|
+
export { FirstRunOnboarding } from "./FirstRunOnboarding.js";
|
|
11
12
|
export { registerOnboardingStep, listOnboardingSteps, } from "../../onboarding/registry.js";
|
|
12
13
|
//# sourceMappingURL=index.js.map
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
* No polling — onboarding state changes are user-driven, so a poll loop just
|
|
7
7
|
* burns the DB and amplifies transient network errors.
|
|
8
8
|
*/
|
|
9
|
-
import type { OnboardingMethod, OnboardingStepStatus } from "../../onboarding/types.js";
|
|
9
|
+
import type { OnboardingAppProfile, OnboardingMethod, OnboardingStepStatus } from "../../onboarding/types.js";
|
|
10
10
|
export interface UseOnboardingResult {
|
|
11
11
|
steps: OnboardingStepStatus[];
|
|
12
|
+
profile: OnboardingAppProfile | null;
|
|
12
13
|
loading: boolean;
|
|
13
14
|
error: string | null;
|
|
14
15
|
/** Active step = first required+incomplete, else first incomplete. */
|
|
@@ -27,6 +28,10 @@ export interface UseOnboardingResult {
|
|
|
27
28
|
dismiss: () => Promise<void>;
|
|
28
29
|
/** Re-open the panel after dismissal. */
|
|
29
30
|
reopen: () => Promise<void>;
|
|
31
|
+
/** True until the post-signup full-screen flow is completed. */
|
|
32
|
+
firstRun: boolean;
|
|
33
|
+
/** Clear the post-signup full-screen flow marker. */
|
|
34
|
+
completeFirstRun: () => Promise<void>;
|
|
30
35
|
}
|
|
31
36
|
export declare function useOnboarding(options?: {
|
|
32
37
|
preview?: boolean;
|
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { FIRST_RUN_ONBOARDING_COOKIE } from "../../shared/first-run-onboarding.js";
|
|
2
3
|
import { agentNativePath } from "../api-path.js";
|
|
4
|
+
function hasFirstRunCookie() {
|
|
5
|
+
if (typeof document === "undefined")
|
|
6
|
+
return false;
|
|
7
|
+
return document.cookie
|
|
8
|
+
.split(";")
|
|
9
|
+
.some((part) => part.trim().startsWith(`${FIRST_RUN_ONBOARDING_COOKIE}=`));
|
|
10
|
+
}
|
|
3
11
|
export function useOnboarding(options = {}) {
|
|
4
12
|
const preview = options.preview === true;
|
|
5
13
|
const [steps, setSteps] = useState([]);
|
|
14
|
+
const [profile, setProfile] = useState(null);
|
|
6
15
|
const [loading, setLoading] = useState(true);
|
|
7
16
|
const [error, setError] = useState(null);
|
|
8
17
|
const [dismissed, setDismissed] = useState(false);
|
|
18
|
+
const [firstRun, setFirstRun] = useState(hasFirstRunCookie);
|
|
9
19
|
const mountedRef = useRef(true);
|
|
10
20
|
const fetchAll = useCallback(async () => {
|
|
11
21
|
try {
|
|
12
22
|
const stepsUrl = agentNativePath(preview
|
|
13
23
|
? "/_agent-native/onboarding/steps?preview=1"
|
|
14
24
|
: "/_agent-native/onboarding/steps");
|
|
15
|
-
const [stepsRes, dismissRes] = await Promise.all([
|
|
25
|
+
const [stepsRes, dismissRes, profileRes] = await Promise.all([
|
|
16
26
|
fetch(stepsUrl),
|
|
17
27
|
fetch(agentNativePath("/_agent-native/onboarding/dismissed")),
|
|
28
|
+
fetch(agentNativePath("/_agent-native/onboarding/profile")),
|
|
18
29
|
]);
|
|
19
30
|
if (!mountedRef.current)
|
|
20
31
|
return;
|
|
@@ -23,6 +34,10 @@ export function useOnboarding(options = {}) {
|
|
|
23
34
|
}
|
|
24
35
|
const stepsData = await stepsRes.json();
|
|
25
36
|
setSteps(stepsData);
|
|
37
|
+
if (!profileRes.ok) {
|
|
38
|
+
throw new Error(`profile: ${profileRes.status}`);
|
|
39
|
+
}
|
|
40
|
+
setProfile((await profileRes.json()));
|
|
26
41
|
if (dismissRes.ok) {
|
|
27
42
|
const d = (await dismissRes.json());
|
|
28
43
|
setDismissed(!!d.dismissed);
|
|
@@ -83,6 +98,22 @@ export function useOnboarding(options = {}) {
|
|
|
83
98
|
});
|
|
84
99
|
await fetchAll();
|
|
85
100
|
}, [fetchAll]);
|
|
101
|
+
const completeFirstRun = useCallback(async () => {
|
|
102
|
+
const response = await fetch(agentNativePath("/_agent-native/onboarding/first-run/complete"), {
|
|
103
|
+
method: "POST",
|
|
104
|
+
headers: { "Content-Type": "application/json" },
|
|
105
|
+
body: "{}",
|
|
106
|
+
});
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
setError(`first-run completion: ${response.status}`);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
setFirstRun(false);
|
|
112
|
+
if (typeof window !== "undefined") {
|
|
113
|
+
window.dispatchEvent(new CustomEvent("agent-native:first-run-completed"));
|
|
114
|
+
}
|
|
115
|
+
await fetchAll();
|
|
116
|
+
}, [fetchAll]);
|
|
86
117
|
const totalCount = steps.length;
|
|
87
118
|
const completeCount = steps.filter((s) => s.complete).length;
|
|
88
119
|
const allComplete = steps.filter((s) => s.required).every((s) => s.complete);
|
|
@@ -91,6 +122,7 @@ export function useOnboarding(options = {}) {
|
|
|
91
122
|
null;
|
|
92
123
|
return {
|
|
93
124
|
steps,
|
|
125
|
+
profile,
|
|
94
126
|
loading,
|
|
95
127
|
error,
|
|
96
128
|
currentStepId,
|
|
@@ -102,6 +134,8 @@ export function useOnboarding(options = {}) {
|
|
|
102
134
|
complete,
|
|
103
135
|
dismiss,
|
|
104
136
|
reopen,
|
|
137
|
+
firstRun,
|
|
138
|
+
completeFirstRun,
|
|
105
139
|
};
|
|
106
140
|
}
|
|
107
141
|
//# sourceMappingURL=use-onboarding.js.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
3
3
|
import { useLocation, useNavigate, } from "react-router";
|
|
4
|
+
import { isWorkspaceAppPath } from "./api-path.js";
|
|
4
5
|
import { deleteClientAppState, readClientAppState, setClientAppState, } from "./application-state.js";
|
|
5
6
|
import { navigateWithAgentChatViewTransition, } from "./chat-view-transition.js";
|
|
6
7
|
const SAFE_BROWSER_TAB_ID_RE = /^[A-Za-z0-9_-]{1,96}$/;
|
|
@@ -207,6 +208,15 @@ export function useAgentRouteState(options) {
|
|
|
207
208
|
const resolvedOptions = typeof navigateOptions === "function"
|
|
208
209
|
? navigateOptions(command)
|
|
209
210
|
: navigateOptions;
|
|
211
|
+
if (isWorkspaceAppPath(path)) {
|
|
212
|
+
if (resolvedOptions?.replace) {
|
|
213
|
+
window.location.replace(path);
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
window.location.assign(path);
|
|
217
|
+
}
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
210
220
|
const transitionOptions = resolveAgentChatViewTransitionOption(options.agentChatViewTransition, command, path);
|
|
211
221
|
const runNavigate = () => navigate(path, resolvedOptions);
|
|
212
222
|
if (transitionOptions) {
|
|
@@ -62,11 +62,11 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
|
|
|
62
62
|
error: string;
|
|
63
63
|
states?: undefined;
|
|
64
64
|
} | {
|
|
65
|
+
error?: undefined;
|
|
65
66
|
states: {
|
|
66
67
|
clientId: number;
|
|
67
68
|
state: string;
|
|
68
69
|
}[];
|
|
69
|
-
error?: undefined;
|
|
70
70
|
}>>;
|
|
71
71
|
/**
|
|
72
72
|
* GET /_agent-native/collab/:docId/users
|
|
@@ -77,10 +77,10 @@ export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("
|
|
|
77
77
|
error: string;
|
|
78
78
|
users?: undefined;
|
|
79
79
|
} | {
|
|
80
|
+
error?: undefined;
|
|
80
81
|
users: {
|
|
81
82
|
clientId: number;
|
|
82
83
|
lastSeen: number;
|
|
83
84
|
}[];
|
|
84
|
-
error?: undefined;
|
|
85
85
|
}>>;
|
|
86
86
|
//# sourceMappingURL=awareness.d.ts.map
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
|
|
|
26
26
|
* Body: { update: string (base64), requestSource?: string }
|
|
27
27
|
*/
|
|
28
28
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
29
|
-
ok?: undefined;
|
|
30
29
|
error: string;
|
|
30
|
+
ok?: undefined;
|
|
31
31
|
} | {
|
|
32
32
|
error?: undefined;
|
|
33
33
|
ok: boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type WorkspaceConnectionCapability = "search" | "import" | "messages" | "meetings" | "crm" | "code" | "docs";
|
|
2
|
-
export type WorkspaceConnectionTemplateUse = "analytics" | "brain" | "calendar" | "clips" | "content" | "crm" | "design" | "dispatch" | "forms" | "mail" | "slides";
|
|
2
|
+
export type WorkspaceConnectionTemplateUse = "analytics" | "brain" | "calendar" | "clips" | "content" | "crm" | "design" | "dispatch" | "factory" | "forms" | "mail" | "slides";
|
|
3
3
|
export type WorkspaceConnectionProviderId = "slack" | "github" | "figma" | "notion" | "gmail" | "google_drive" | "hubspot" | "salesforce" | "jira" | "sentry" | "granola" | "clips" | "generic";
|
|
4
4
|
export interface WorkspaceConnectionCredentialKey {
|
|
5
5
|
key: string;
|
|
@@ -39,7 +39,7 @@ export declare const WORKSPACE_CONNECTION_PROVIDERS: readonly [{
|
|
|
39
39
|
readonly required: true;
|
|
40
40
|
}];
|
|
41
41
|
readonly capabilities: readonly ["search", "import", "messages"];
|
|
42
|
-
readonly recommendedTemplateUses: readonly ["brain", "dispatch", "analytics"];
|
|
42
|
+
readonly recommendedTemplateUses: readonly ["brain", "dispatch", "analytics", "factory"];
|
|
43
43
|
}, {
|
|
44
44
|
readonly id: "github";
|
|
45
45
|
readonly label: "GitHub";
|
|
@@ -57,7 +57,7 @@ export declare const WORKSPACE_CONNECTION_PROVIDERS: readonly [{
|
|
|
57
57
|
readonly scopes: readonly ["repo", "read:org", "read:user", "user:email"];
|
|
58
58
|
};
|
|
59
59
|
readonly capabilities: readonly ["search", "import", "code", "docs"];
|
|
60
|
-
readonly recommendedTemplateUses: readonly ["brain", "analytics", "dispatch"];
|
|
60
|
+
readonly recommendedTemplateUses: readonly ["brain", "analytics", "dispatch", "factory"];
|
|
61
61
|
}, {
|
|
62
62
|
readonly id: "figma";
|
|
63
63
|
readonly label: "Figma";
|
|
@@ -217,7 +217,7 @@ export declare const WORKSPACE_CONNECTION_PROVIDERS: readonly [{
|
|
|
217
217
|
readonly scopes: readonly ["org:read", "project:read", "event:read", "team:read"];
|
|
218
218
|
};
|
|
219
219
|
readonly capabilities: readonly ["search", "import", "docs"];
|
|
220
|
-
readonly recommendedTemplateUses: readonly ["analytics", "brain", "dispatch"];
|
|
220
|
+
readonly recommendedTemplateUses: readonly ["analytics", "brain", "dispatch", "factory"];
|
|
221
221
|
}, {
|
|
222
222
|
readonly id: "granola";
|
|
223
223
|
readonly label: "Granola";
|
|
@@ -15,7 +15,7 @@ export const WORKSPACE_CONNECTION_PROVIDERS = [
|
|
|
15
15
|
},
|
|
16
16
|
],
|
|
17
17
|
capabilities: ["search", "import", "messages"],
|
|
18
|
-
recommendedTemplateUses: ["brain", "dispatch", "analytics"],
|
|
18
|
+
recommendedTemplateUses: ["brain", "dispatch", "analytics", "factory"],
|
|
19
19
|
}),
|
|
20
20
|
defineWorkspaceConnectionProvider({
|
|
21
21
|
id: "github",
|
|
@@ -36,7 +36,7 @@ export const WORKSPACE_CONNECTION_PROVIDERS = [
|
|
|
36
36
|
scopes: ["repo", "read:org", "read:user", "user:email"],
|
|
37
37
|
},
|
|
38
38
|
capabilities: ["search", "import", "code", "docs"],
|
|
39
|
-
recommendedTemplateUses: ["brain", "analytics", "dispatch"],
|
|
39
|
+
recommendedTemplateUses: ["brain", "analytics", "dispatch", "factory"],
|
|
40
40
|
}),
|
|
41
41
|
defineWorkspaceConnectionProvider({
|
|
42
42
|
id: "figma",
|
|
@@ -243,7 +243,7 @@ export const WORKSPACE_CONNECTION_PROVIDERS = [
|
|
|
243
243
|
scopes: ["org:read", "project:read", "event:read", "team:read"],
|
|
244
244
|
},
|
|
245
245
|
capabilities: ["search", "import", "docs"],
|
|
246
|
-
recommendedTemplateUses: ["analytics", "brain", "dispatch"],
|
|
246
|
+
recommendedTemplateUses: ["analytics", "brain", "dispatch", "factory"],
|
|
247
247
|
}),
|
|
248
248
|
defineWorkspaceConnectionProvider({
|
|
249
249
|
id: "granola",
|