@agent-native/core 0.141.5 → 0.141.7
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/dashboard-management/SKILL.md +3 -14
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +20 -8
- package/corpus/templates/analytics/.agents/skills/prometheus/SKILL.md +5 -5
- package/corpus/templates/analytics/AGENTS.md +2 -2
- package/corpus/templates/analytics/actions/compose-dashboard.ts +1 -1
- package/corpus/templates/analytics/actions/get-first-party-analytics-health.ts +15 -1
- package/corpus/templates/analytics/actions/migrate-first-party-analytics-to-bigquery.ts +135 -0
- package/corpus/templates/analytics/actions/navigate.ts +1 -1
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +2 -2
- package/corpus/templates/analytics/actions/update-dashboard.ts +0 -1
- package/corpus/templates/analytics/actions/view-screen.ts +0 -20
- package/corpus/templates/analytics/app/components/layout/Header.tsx +0 -1
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +5 -5
- package/corpus/templates/analytics/app/i18n-data.ts +330 -90
- package/corpus/templates/analytics/app/pages/Agents.tsx +0 -3
- package/corpus/templates/analytics/app/pages/DataSources.tsx +66 -30
- package/corpus/templates/analytics/app/pages/Settings.tsx +22 -43
- package/corpus/templates/analytics/app/pages/settings/settings-search.ts +23 -20
- package/corpus/templates/analytics/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/analytics/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/analytics/app/routes/team.tsx +1 -1
- package/corpus/templates/analytics/changelog/2026-08-05-historical-analytics-rollups-now-repair-automatically-after-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-05-settings-no-longer-includes-an-unnecessary-about-section.md +6 -0
- package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +1 -1
- package/corpus/templates/analytics/netlify.toml +4 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +109 -0
- package/corpus/templates/analytics/scripts/first-party-analytics-bigquery.sql +104 -0
- package/corpus/templates/analytics/server/jobs/analytics-rollup-backfill.ts +342 -0
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +0 -2
- package/corpus/templates/analytics/server/lib/analytics-rollup-lock.ts +8 -0
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +11 -29
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +55 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +1058 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-health.ts +151 -46
- package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +15 -9
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +59 -17
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +1 -3
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +2 -4
- package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +61 -0
- package/corpus/templates/analytics/server/plugins/db.ts +58 -187
- package/corpus/templates/analytics/server/routes/api/analytics-rollups/backfill.post.ts +53 -0
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +8 -6
- package/corpus/templates/assets/.agents/skills/library-management/SKILL.md +16 -1
- package/corpus/templates/assets/AGENTS.md +1 -0
- package/corpus/templates/assets/actions/_helpers.ts +12 -0
- package/corpus/templates/assets/actions/generate-image.ts +9 -3
- package/corpus/templates/assets/actions/import-style-from-url.ts +115 -0
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +3 -1
- package/corpus/templates/assets/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/assets/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/assets/app/routes/settings.tsx +5 -0
- package/corpus/templates/assets/app/routes/team.tsx +1 -1
- package/corpus/templates/assets/changelog/2026-08-05-brand-kits-can-import-a-website-s-hydrated-visual-language-a.md +6 -0
- package/corpus/templates/assets/changelog/2026-08-05-generated-images-now-hand-off-embeddable-previews-to-other-w.md +6 -0
- package/corpus/templates/assets/server/lib/generation.ts +58 -0
- package/corpus/templates/assets/shared/api.ts +12 -0
- package/corpus/templates/brain/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/brain/app/routes/team.tsx +1 -1
- package/corpus/templates/brain/app/routes.ts +1 -1
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +3 -1
- package/corpus/templates/calendar/app/routes/_app.extensions._index.tsx +1 -1
- package/corpus/templates/calendar/app/routes/_app.settings.$.tsx +1 -0
- package/corpus/templates/calendar/app/routes/_app.team.tsx +1 -1
- package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/chat/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/chat/app/root.tsx +1 -1
- package/corpus/templates/chat/app/routes/agent.tsx +7 -7
- package/corpus/templates/chat/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/chat/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/chat/app/routes/team.tsx +1 -1
- package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +1 -1
- package/corpus/templates/clips/app/components/recorder/storage-setup-card.tsx +1 -1
- package/corpus/templates/clips/app/routes/_app.extensions._index.tsx +1 -1
- package/corpus/templates/clips/app/routes/_app.settings.$.tsx +1 -0
- package/corpus/templates/clips/changelog/2026-08-05-clips-overlays-now-use-clean-surfaces-without-clipped-shadow.md +6 -0
- package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +2 -2
- package/corpus/templates/clips/desktop/src/styles.css +3 -54
- package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +3 -3
- package/corpus/templates/content/app/routes/_app.extensions._index.tsx +1 -1
- package/corpus/templates/content/app/routes/_app.settings.$.tsx +1 -0
- package/corpus/templates/content/app/routes/_app.team.tsx +1 -1
- package/corpus/templates/content/e2e/global-setup.ts +1 -1
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +6 -1
- package/corpus/templates/design/actions/analyze-brand-assets.ts +7 -7
- package/corpus/templates/design/actions/get-design-system.ts +3 -1
- package/corpus/templates/design/actions/import-from-url.ts +6 -5
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +2 -2
- package/corpus/templates/design/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/design/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/design/app/routes/team.tsx +1 -1
- package/corpus/templates/design/changelog/2026-08-05-missing-design-systems-now-return-a-clear-not-found-response.md +6 -0
- package/corpus/templates/design/changelog/2026-08-05-website-url-imports-now-capture-hydrated-browser-computed-de.md +6 -0
- package/corpus/templates/design/e2e/global-setup.ts +1 -1
- package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/dispatch/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/team.tsx +1 -1
- package/corpus/templates/factory/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/factory/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/factory/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/factory/app/routes/team.tsx +1 -1
- package/corpus/templates/forms/app/routes/_app.extensions._index.tsx +1 -1
- package/corpus/templates/forms/app/routes/_app.settings.$.tsx +1 -0
- package/corpus/templates/forms/app/routes/_app.team.tsx +1 -1
- package/corpus/templates/forms/shared/navigation.ts +1 -1
- package/corpus/templates/macros/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/macros/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/macros/app/routes/team.tsx +1 -1
- package/corpus/templates/mail/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/mail/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/plan/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/plan/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/plan/app/routes/team.tsx +1 -1
- package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +3 -1
- package/corpus/templates/slides/actions/analyze-brand-assets.ts +7 -7
- package/corpus/templates/slides/actions/import-from-url.ts +6 -6
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +2 -2
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +3 -0
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1 -1
- package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +9 -3
- package/corpus/templates/slides/app/context/DeckContext.tsx +71 -20
- package/corpus/templates/slides/app/global.css +6 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +5 -5
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +9 -5
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +17 -0
- package/corpus/templates/slides/app/pages/Index.tsx +16 -5
- package/corpus/templates/slides/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/slides/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/slides/app/routes/team.tsx +1 -1
- package/corpus/templates/slides/changelog/2026-08-05-failed-deck-creation-and-reference-uploads-now-recover-clean.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-05-new-presentation-prompts-now-clearly-describe-presentation-g.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-05-slides-recover-completed-generation-results-after-a-sync-hic.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-05-website-url-imports-now-capture-hydrated-browser-computed-st.md +6 -0
- package/corpus/templates/tasks/app/components/layout/Header.tsx +3 -1
- package/corpus/templates/tasks/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/tasks/app/routes/settings.$.tsx +1 -0
- package/dist/agent/engine/ai-sdk-engine.js +49 -3
- package/dist/agent/production-agent.d.ts +1 -0
- package/dist/agent/production-agent.js +8 -0
- package/dist/agent/types.d.ts +7 -0
- package/dist/client/AssistantChat.js +1 -1
- package/dist/client/agent-chat-adapter.d.ts +1 -1
- package/dist/client/agent-chat-adapter.js +30 -3
- package/dist/client/agent-page/AgentWorkspaceContent.d.ts +1 -1
- package/dist/client/agent-page/AgentWorkspaceContent.js +13 -13
- package/dist/client/chat/run-recovery.d.ts +2 -1
- package/dist/client/chat/run-recovery.js +14 -3
- package/dist/client/embed-auth.js +6 -2
- package/dist/client/error-format.d.ts +1 -0
- package/dist/client/error-format.js +16 -2
- package/dist/client/integrations/IntegrationsPanel.js +40 -6
- package/dist/client/org/OrgSwitcher.js +2 -2
- package/dist/client/org/TeamPage.js +92 -72
- package/dist/client/require-session.d.ts +1 -1
- package/dist/client/require-session.js +3 -3
- package/dist/client/resources/use-mcp-servers.d.ts +5 -0
- package/dist/client/resources/use-mcp-servers.js +36 -0
- package/dist/client/settings/AccountSettingsCard.js +40 -35
- package/dist/client/settings/AutomationsSection.js +1 -1
- package/dist/client/settings/DemoModeSection.d.ts +3 -1
- package/dist/client/settings/DemoModeSection.js +4 -1
- package/dist/client/settings/ExtensionsSettingsContent.js +1 -1
- package/dist/client/settings/SchedulingTimezoneField.d.ts +3 -1
- package/dist/client/settings/SchedulingTimezoneField.js +9 -5
- package/dist/client/settings/SettingsPanel.d.ts +4 -1
- package/dist/client/settings/SettingsPanel.js +21 -21
- package/dist/client/settings/SettingsTabsPage.d.ts +2 -2
- package/dist/client/settings/SettingsTabsPage.js +98 -45
- package/dist/client/settings/VoiceTranscriptionSection.js +6 -1
- package/dist/client/settings/useSettingsPanelController.js +47 -8
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/ingestion/website.d.ts +30 -0
- package/dist/localization/default-messages.d.ts +5 -0
- package/dist/localization/default-messages.js +5 -0
- package/dist/mcp-client/oauth-routes.js +1 -1
- package/dist/mcp-client/routes.d.ts +1 -0
- package/dist/mcp-client/routes.js +49 -0
- package/dist/navigation/index.js +16 -5
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +13 -13
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/scripts/call-agent.js +11 -0
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.js +9 -7
- package/dist/server/identity-sso.js +2 -1
- package/dist/server/onboarding-html.js +57 -34
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/server/workspace-provider-oauth.js +1 -1
- package/dist/setup-connections/onboarding.js +1 -1
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/shared/sign-in-journey.d.ts +5 -2
- package/dist/shared/sign-in-journey.js +10 -4
- package/dist/templates/chat/app/components/layout/Layout.tsx +1 -1
- package/dist/templates/chat/app/hooks/use-navigation-state.ts +1 -1
- package/dist/templates/chat/app/root.tsx +1 -1
- package/dist/templates/chat/app/routes/agent.tsx +7 -7
- package/dist/templates/chat/app/routes/extensions._index.tsx +1 -1
- package/dist/templates/chat/app/routes/settings.$.tsx +1 -0
- package/dist/templates/chat/app/routes/team.tsx +1 -1
- package/dist/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +37 -6
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +4 -2
- package/docs/content/authentication.mdx +4 -5
- package/docs/content/template-analytics-developers.mdx +1 -1
- package/docs/content/template-calendar-developers.mdx +1 -1
- package/docs/content/template-chat-developers.mdx +2 -2
- package/docs/content/template-content-developers.mdx +1 -1
- package/docs/content/template-mail-developers.mdx +1 -1
- package/docs/content/template-plan-developers.mdx +1 -1
- package/docs/content/toolkit-command-navigation.mdx +6 -6
- package/docs/content/toolkit-org-team.mdx +1 -1
- package/docs/content/toolkit-settings.mdx +8 -8
- package/docs/content/toolkit-setup-connections.mdx +1 -1
- package/package.json +1 -1
- package/src/templates/chat/app/components/layout/Layout.tsx +1 -1
- package/src/templates/chat/app/hooks/use-navigation-state.ts +1 -1
- package/src/templates/chat/app/root.tsx +1 -1
- package/src/templates/chat/app/routes/agent.tsx +7 -7
- package/src/templates/chat/app/routes/extensions._index.tsx +1 -1
- package/src/templates/chat/app/routes/settings.$.tsx +1 -0
- package/src/templates/chat/app/routes/team.tsx +1 -1
- package/src/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +37 -6
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +4 -2
- package/corpus/templates/analytics/.agents/skills/dashboard-management/references/template-catalog-and-demo.md +0 -62
- package/corpus/templates/analytics/actions/install-dashboard-template.ts +0 -369
- package/corpus/templates/analytics/actions/list-dashboard-templates.ts +0 -47
- package/corpus/templates/analytics/actions/list-native-v2-dashboard-templates.ts +0 -34
- package/corpus/templates/analytics/app/routes/catalog.tsx +0 -240
- package/corpus/templates/analytics/changelog/2026-08-05-historical-analytics-rollups-stay-complete-and-atomic.md +0 -6
- package/corpus/templates/analytics/changelog/2026-08-05-historical-rollups-stay-complete-while-live-events-arrive.md +0 -6
- package/src/templates/default/actions/navigate.spec.ts +0 -53
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Tabs, useDesignSystem } from "@agent-native/toolkit/design-system";
|
|
3
|
-
import {
|
|
3
|
+
import { IconArrowUpRight, IconHistory, IconSearch, IconSettings, IconUserCircle, IconUsers, IconX, } from "@tabler/icons-react";
|
|
4
4
|
import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
5
5
|
import { Link } from "react-router";
|
|
6
|
+
import { buildSettingsRoute } from "../../navigation/index.js";
|
|
6
7
|
import { cn } from "../utils.js";
|
|
7
8
|
function normalizeTabId(value) {
|
|
8
9
|
let decoded = value?.replace(/^#/, "").trim() ?? "";
|
|
@@ -61,17 +62,52 @@ function resolveTabId(tabs, value) {
|
|
|
61
62
|
}
|
|
62
63
|
return null;
|
|
63
64
|
}
|
|
64
|
-
function
|
|
65
|
+
function activeTabFromLocation(tabs, defaultTab) {
|
|
65
66
|
if (typeof window === "undefined")
|
|
66
67
|
return defaultTab;
|
|
68
|
+
const settingsPrefix = "/settings";
|
|
69
|
+
if (window.location.pathname === settingsPrefix) {
|
|
70
|
+
return resolveTabId(tabs, window.location.hash) ?? defaultTab;
|
|
71
|
+
}
|
|
72
|
+
if (window.location.pathname.startsWith(`${settingsPrefix}/`)) {
|
|
73
|
+
const segments = window.location.pathname
|
|
74
|
+
.slice(`${settingsPrefix}/`.length)
|
|
75
|
+
.split("/")
|
|
76
|
+
.filter(Boolean)
|
|
77
|
+
.map((segment) => {
|
|
78
|
+
try {
|
|
79
|
+
return decodeURIComponent(segment);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return segment;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
for (let length = segments.length; length > 0; length -= 1) {
|
|
86
|
+
const tabId = resolveTabId(tabs, segments.slice(0, length).join(":"));
|
|
87
|
+
if (tabId)
|
|
88
|
+
return tabId;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
67
91
|
return resolveTabId(tabs, window.location.hash) ?? defaultTab;
|
|
68
92
|
}
|
|
69
|
-
function
|
|
93
|
+
function buildSettingsEntryRoute(tabId, section) {
|
|
94
|
+
const normalizedSection = section?.replace(/^#/, "").trim();
|
|
95
|
+
if (!normalizedSection || normalizedSection === tabId) {
|
|
96
|
+
return buildSettingsRoute(tabId);
|
|
97
|
+
}
|
|
98
|
+
if (normalizedSection.startsWith("agent:")) {
|
|
99
|
+
return buildSettingsRoute(normalizedSection);
|
|
100
|
+
}
|
|
101
|
+
if (normalizedSection.startsWith(`${tabId}:`)) {
|
|
102
|
+
return buildSettingsRoute(normalizedSection);
|
|
103
|
+
}
|
|
104
|
+
return buildSettingsRoute(`${tabId}:${normalizedSection}`);
|
|
105
|
+
}
|
|
106
|
+
function updateRouteForTab(tabId, section) {
|
|
70
107
|
if (typeof window === "undefined")
|
|
71
108
|
return;
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
window.history.pushState(null, "", `${pathname}${search}${hash}`);
|
|
109
|
+
const route = buildSettingsEntryRoute(tabId, section);
|
|
110
|
+
window.history.pushState(null, "", `${route}${window.location.search}`);
|
|
75
111
|
}
|
|
76
112
|
function isEditableElement(element) {
|
|
77
113
|
if (!(element instanceof HTMLElement))
|
|
@@ -82,7 +118,7 @@ function isEditableElement(element) {
|
|
|
82
118
|
tagName === "select" ||
|
|
83
119
|
element.isContentEditable);
|
|
84
120
|
}
|
|
85
|
-
export function SettingsTabsPage({ general, account, team, whatsNew, extraTabs = [], generalLabel = "General", accountLabel = "Account", teamLabel = "Team", whatsNewLabel = "What's new", ariaLabel = "Settings sections", defaultTab = "
|
|
121
|
+
export function SettingsTabsPage({ general, account, team, whatsNew, extraTabs = [], generalLabel = "General", accountLabel = "Account", teamLabel = "Team", whatsNewLabel = "What's new", ariaLabel = "Settings sections", defaultTab = "general", className, navClassName, contentClassName, enableSearch = true, searchPlaceholder = "Search settings", searchEntries, generalSearchEntries, value, onValueChange, }) {
|
|
86
122
|
const rootRef = useRef(null);
|
|
87
123
|
const searchInputRef = useRef(null);
|
|
88
124
|
const autoFocusedSearchRef = useRef(false);
|
|
@@ -166,7 +202,7 @@ export function SettingsTabsPage({ general, account, team, whatsNew, extraTabs =
|
|
|
166
202
|
agent: "Agent",
|
|
167
203
|
};
|
|
168
204
|
const isControlled = value !== undefined;
|
|
169
|
-
const [internalTab, setInternalTab] = useState(() =>
|
|
205
|
+
const [internalTab, setInternalTab] = useState(() => activeTabFromLocation(tabs, fallbackTab));
|
|
170
206
|
const activeTab = isControlled ? value : internalTab;
|
|
171
207
|
const [query, setQuery] = useState("");
|
|
172
208
|
const designSystem = useDesignSystem();
|
|
@@ -186,39 +222,55 @@ export function SettingsTabsPage({ general, account, team, whatsNew, extraTabs =
|
|
|
186
222
|
setInternalTab(fallbackTab);
|
|
187
223
|
}, [fallbackTab, internalTab, isControlled, tabs]);
|
|
188
224
|
useEffect(() => {
|
|
189
|
-
// Hash-driven tab tracking only applies to the uncontrolled mode. Only
|
|
190
|
-
// react to hashes that name a top-level tab. Section-level hashes
|
|
191
|
-
// (e.g. `#llm`, `#secrets`) are consumed by the inner panels, so leave
|
|
192
|
-
// the active tab untouched to avoid bouncing back to General.
|
|
193
225
|
if (isControlled)
|
|
194
226
|
return;
|
|
195
|
-
const
|
|
196
|
-
const
|
|
197
|
-
if (
|
|
198
|
-
setInternalTab(
|
|
199
|
-
|
|
227
|
+
const syncLocation = () => {
|
|
228
|
+
const fromPath = activeTabFromLocation(tabs, fallbackTab);
|
|
229
|
+
if (fromPath)
|
|
230
|
+
setInternalTab(fromPath);
|
|
231
|
+
if (window.location.pathname.startsWith("/settings/"))
|
|
232
|
+
return;
|
|
233
|
+
const hashValue = window.location.hash.replace(/^#/, "");
|
|
234
|
+
const fromHash = resolveTabId(tabs, hashValue);
|
|
235
|
+
if (!fromHash || !hashValue)
|
|
236
|
+
return;
|
|
237
|
+
const isTabHash = fromHash === hashValue;
|
|
238
|
+
updateRouteForTab(fromHash, isTabHash ? undefined : hashValue);
|
|
239
|
+
};
|
|
240
|
+
syncLocation();
|
|
241
|
+
window.addEventListener("hashchange", syncLocation);
|
|
242
|
+
window.addEventListener("popstate", syncLocation);
|
|
243
|
+
return () => {
|
|
244
|
+
window.removeEventListener("hashchange", syncLocation);
|
|
245
|
+
window.removeEventListener("popstate", syncLocation);
|
|
200
246
|
};
|
|
201
|
-
|
|
202
|
-
return () => window.removeEventListener("hashchange", handleHashChange);
|
|
203
|
-
}, [isControlled, tabs]);
|
|
247
|
+
}, [fallbackTab, isControlled, tabs]);
|
|
204
248
|
useEffect(() => {
|
|
205
|
-
// Controlled pages retain ownership of their active state, but shared
|
|
206
|
-
// organization navigation uses a hash deep link. Report only recognized
|
|
207
|
-
// top-level tab hashes; section hashes remain available to inner panels.
|
|
208
249
|
if (!isControlled)
|
|
209
250
|
return;
|
|
210
|
-
const
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
251
|
+
const syncControlledLocation = () => {
|
|
252
|
+
const fromPath = window.location.pathname.startsWith("/settings/")
|
|
253
|
+
? activeTabFromLocation(tabs, defaultTab)
|
|
254
|
+
: null;
|
|
255
|
+
const hashValue = window.location.hash.replace(/^#/, "");
|
|
256
|
+
const fromHash = hashValue ? resolveTabId(tabs, hashValue) : null;
|
|
257
|
+
const next = fromPath ?? fromHash;
|
|
258
|
+
const key = `${window.location.pathname}${window.location.hash}`;
|
|
259
|
+
if (!next || next === value || controlledHashRef.current === key) {
|
|
260
|
+
controlledHashRef.current = key;
|
|
214
261
|
return;
|
|
215
|
-
|
|
216
|
-
|
|
262
|
+
}
|
|
263
|
+
controlledHashRef.current = key;
|
|
264
|
+
onValueChange?.(next);
|
|
265
|
+
};
|
|
266
|
+
syncControlledLocation();
|
|
267
|
+
window.addEventListener("hashchange", syncControlledLocation);
|
|
268
|
+
window.addEventListener("popstate", syncControlledLocation);
|
|
269
|
+
return () => {
|
|
270
|
+
window.removeEventListener("hashchange", syncControlledLocation);
|
|
271
|
+
window.removeEventListener("popstate", syncControlledLocation);
|
|
217
272
|
};
|
|
218
|
-
|
|
219
|
-
window.addEventListener("hashchange", syncControlledHash);
|
|
220
|
-
return () => window.removeEventListener("hashchange", syncControlledHash);
|
|
221
|
-
}, [isControlled, onValueChange, tabs, value]);
|
|
273
|
+
}, [defaultTab, isControlled, onValueChange, tabs, value]);
|
|
222
274
|
useEffect(() => {
|
|
223
275
|
if (!enableSearch || autoFocusedSearchRef.current)
|
|
224
276
|
return;
|
|
@@ -306,24 +358,24 @@ export function SettingsTabsPage({ general, account, team, whatsNew, extraTabs =
|
|
|
306
358
|
setQuery("");
|
|
307
359
|
if (typeof window === "undefined")
|
|
308
360
|
return;
|
|
309
|
-
const
|
|
310
|
-
if (
|
|
311
|
-
|
|
312
|
-
window.history.pushState(null, "", `${pathname}${search}#${hash}`);
|
|
361
|
+
const section = entry.hash?.replace(/^#/, "");
|
|
362
|
+
if (section) {
|
|
363
|
+
updateRouteForTab(entry.tabId, section);
|
|
313
364
|
// Let the inner panels open + scroll to their section.
|
|
365
|
+
window.dispatchEvent(new Event("popstate"));
|
|
314
366
|
window.dispatchEvent(new Event("hashchange"));
|
|
315
367
|
window.requestAnimationFrame(() => {
|
|
316
368
|
document
|
|
317
|
-
.getElementById(
|
|
369
|
+
.getElementById(section)
|
|
318
370
|
?.scrollIntoView({ block: "start", behavior: "smooth" });
|
|
319
371
|
});
|
|
320
372
|
}
|
|
321
373
|
else if (!isControlled) {
|
|
322
|
-
|
|
374
|
+
updateRouteForTab(entry.tabId);
|
|
323
375
|
}
|
|
324
376
|
};
|
|
325
377
|
const searching = enableSearch && trimmedQuery.length > 0;
|
|
326
|
-
return (_jsxs("div", { ref: rootRef, className: cn("flex h-full min-h-0 w-full flex-col overflow-hidden bg-background sm:flex-row", className), children: [_jsxs("div", { className: cn("flex shrink-0 flex-col gap-2 bg-background p-2 sm:min-h-0 sm:w-60 sm:overflow-y-auto sm:p-4", navClassName), children: [
|
|
378
|
+
return (_jsxs("div", { ref: rootRef, className: cn("flex h-full min-h-0 w-full flex-col overflow-hidden bg-background sm:flex-row", className), children: [_jsxs("div", { className: cn("flex shrink-0 flex-col gap-2 bg-background p-2 sm:min-h-0 sm:w-60 sm:overflow-y-auto sm:p-4", navClassName), children: [enableSearch ? (_jsxs("div", { className: "relative sm:mb-2", children: [_jsx(IconSearch, { className: "pointer-events-none absolute start-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground" }), _jsx("input", { ref: searchInputRef, type: "search", value: query, onChange: (event) => setQuery(event.target.value), onKeyDown: (event) => {
|
|
327
379
|
if (event.key === "Escape")
|
|
328
380
|
setQuery("");
|
|
329
381
|
if (event.key === "Enter" && results[0]) {
|
|
@@ -333,11 +385,12 @@ export function SettingsTabsPage({ general, account, team, whatsNew, extraTabs =
|
|
|
333
385
|
}, placeholder: searchPlaceholder, "aria-label": searchPlaceholder, className: "h-8 w-full rounded-md border border-border bg-background ps-8 pe-7 text-[13px] text-foreground outline-none transition-colors placeholder:text-muted-foreground focus:border-foreground/30 focus:ring-2 focus:ring-accent/40" }), query ? (_jsx("button", { type: "button", onClick: () => setQuery(""), "aria-label": "Clear search", className: "absolute end-1.5 top-1/2 flex size-5 -translate-y-1/2 items-center justify-center rounded text-muted-foreground hover:bg-accent/60 hover:text-foreground", children: _jsx(IconX, { className: "size-3.5" }) })) : null] })) : null, searching ? (_jsx("div", { role: "listbox", "aria-label": "Settings search results", className: "flex flex-col gap-0.5", children: results.length === 0 ? (_jsx("p", { className: "px-2 py-6 text-center text-[12px] text-muted-foreground", children: "No matching settings" })) : (results.map((entry) => {
|
|
334
386
|
const Icon = entry.icon;
|
|
335
387
|
const tab = tabs.find((candidate) => candidate.id === entry.tabId);
|
|
388
|
+
const entryHash = entry.hash?.replace(/^#/, "");
|
|
336
389
|
const resultHref = tab?.href
|
|
337
|
-
?
|
|
338
|
-
?
|
|
390
|
+
? entryHash
|
|
391
|
+
? buildSettingsEntryRoute(entry.tabId, entryHash)
|
|
339
392
|
: tab.href
|
|
340
|
-
:
|
|
393
|
+
: buildSettingsEntryRoute(entry.tabId, entryHash);
|
|
341
394
|
const result = (_jsxs(_Fragment, { children: [Icon ? (_jsx(Icon, { className: "mt-0.5 size-4 shrink-0 text-muted-foreground" })) : null, _jsxs("span", { className: "flex min-w-0 flex-col", children: [_jsx("span", { className: "truncate font-medium", children: entry.label }), _jsx("span", { className: "truncate text-[11px] text-muted-foreground", children: entry.description ?? entry.tabLabel })] })] }));
|
|
342
395
|
return resultHref ? (_jsx(Link, { to: resultHref, role: "option", "aria-selected": false, className: "flex items-start gap-2 rounded-md px-2.5 py-2 text-start text-sm text-foreground transition-colors hover:bg-accent/60", children: result }, entry.id)) : (_jsx("button", { type: "button", role: "option", "aria-selected": false, onClick: () => selectEntry(entry), className: "flex items-start gap-2 rounded-md px-2.5 py-2 text-start text-sm text-foreground transition-colors hover:bg-accent/60", children: result }, entry.id));
|
|
343
396
|
})) })) : hasCustomTabs ? (_jsx(Tabs, { items: tabs.map((tab) => ({
|
|
@@ -351,7 +404,7 @@ export function SettingsTabsPage({ general, account, team, whatsNew, extraTabs =
|
|
|
351
404
|
const nextTab = String(tabId);
|
|
352
405
|
changeTab(nextTab);
|
|
353
406
|
if (!isControlled)
|
|
354
|
-
|
|
407
|
+
updateRouteForTab(nextTab);
|
|
355
408
|
}, orientation: "vertical", "aria-label": ariaLabel, className: "flex gap-1 overflow-x-auto sm:flex-col sm:overflow-x-visible" })) : (_jsx("nav", { "aria-label": ariaLabel, role: "tablist", className: "flex gap-1 overflow-x-auto sm:flex-col sm:overflow-x-visible", children: tabGroups.map((group, groupIndex) => (_jsx("div", { "data-settings-tab-group": group.id, className: cn("contents sm:block", groupIndex > 0 && "sm:mt-3 sm:pt-1"), children: _jsxs("div", { className: "contents sm:flex sm:flex-col sm:gap-1", children: [_jsx("div", { className: "hidden px-3 pb-1 pt-1 text-[11px] font-medium text-muted-foreground sm:block", children: tabGroupLabels[group.id] ?? group.id }), group.tabs.map((tab) => {
|
|
356
409
|
const Icon = tab.icon;
|
|
357
410
|
const selected = tab.id === selectedTab?.id;
|
|
@@ -366,7 +419,7 @@ export function SettingsTabsPage({ general, account, team, whatsNew, extraTabs =
|
|
|
366
419
|
return (_jsx("button", { type: "button", role: "tab", "aria-selected": selected, "aria-controls": `settings-tabpanel-${tab.id}`, id: `settings-tab-${tab.id}`, onClick: () => {
|
|
367
420
|
changeTab(tab.id);
|
|
368
421
|
if (!isControlled)
|
|
369
|
-
|
|
422
|
+
updateRouteForTab(tab.id);
|
|
370
423
|
}, className: cn("flex min-h-9 shrink-0 items-center gap-2 rounded-md px-3 py-2 text-start text-sm font-medium transition-colors sm:w-full", selected
|
|
371
424
|
? "bg-accent text-foreground"
|
|
372
425
|
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground"), children: tabContent }, tab.id));
|
|
@@ -13,6 +13,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
13
13
|
import { Picker, Switch } from "@agent-native/toolkit/design-system";
|
|
14
14
|
import { IconAlertCircle, IconCheck, IconChevronDown, IconChevronRight, IconExternalLink, IconLoader2, IconLockOpen, } from "@tabler/icons-react";
|
|
15
15
|
import { useCallback, useEffect, useState } from "react";
|
|
16
|
+
import { buildSettingsRoute } from "../../navigation/index.js";
|
|
16
17
|
import { agentNativePath } from "../api-path.js";
|
|
17
18
|
import { SettingsRow } from "./SettingsRow.js";
|
|
18
19
|
import { openBuilderConnectPopup, useBuilderStatus, } from "./useBuilderStatus.js";
|
|
@@ -221,7 +222,8 @@ export function VoiceTranscriptionSection({ compact = false, } = {}) {
|
|
|
221
222
|
const focusKey = (key) => {
|
|
222
223
|
if (typeof window === "undefined")
|
|
223
224
|
return;
|
|
224
|
-
window.
|
|
225
|
+
window.history.pushState(null, "", buildSettingsRoute(`integrations:secrets:${key}`));
|
|
226
|
+
window.dispatchEvent(new Event("popstate"));
|
|
225
227
|
};
|
|
226
228
|
const chooseSource = (next) => {
|
|
227
229
|
if (next === transcriptionMode)
|
|
@@ -266,6 +268,9 @@ export function VoiceTranscriptionSection({ compact = false, } = {}) {
|
|
|
266
268
|
}
|
|
267
269
|
};
|
|
268
270
|
if (transcriptionMode === null) {
|
|
271
|
+
if (compact) {
|
|
272
|
+
return (_jsx(SettingsRow, { label: "Voice transcription", description: "Choose how voice input is transcribed.", control: _jsx("div", { className: "h-9 w-44 animate-pulse rounded-md border border-border bg-muted-foreground/10", "aria-label": "Loading voice transcription" }) }));
|
|
273
|
+
}
|
|
269
274
|
return (_jsxs("div", { className: "flex items-center gap-1.5 text-[10px] text-muted-foreground", children: [_jsx(IconLoader2, { size: 10, className: "animate-spin" }), "Loading\u2026"] }));
|
|
270
275
|
}
|
|
271
276
|
if (compact) {
|
|
@@ -34,13 +34,35 @@ function firstVisibleSection(sections) {
|
|
|
34
34
|
return "llm";
|
|
35
35
|
return sections[0] ?? "llm";
|
|
36
36
|
}
|
|
37
|
+
function settingsPathParts() {
|
|
38
|
+
if (typeof window === "undefined")
|
|
39
|
+
return [];
|
|
40
|
+
const pathParts = window.location.pathname.split("/").filter(Boolean);
|
|
41
|
+
const settingsIndex = pathParts.indexOf("settings");
|
|
42
|
+
return settingsIndex === -1 ? [] : pathParts.slice(settingsIndex + 1);
|
|
43
|
+
}
|
|
44
|
+
function secretKeyFromPath(pathParts) {
|
|
45
|
+
const secretsIndex = pathParts.findIndex((part) => part.toLowerCase() === "secrets");
|
|
46
|
+
if (secretsIndex === -1)
|
|
47
|
+
return undefined;
|
|
48
|
+
const key = pathParts.slice(secretsIndex + 1).join("/");
|
|
49
|
+
return key || undefined;
|
|
50
|
+
}
|
|
37
51
|
function initialOpenSection(sections) {
|
|
38
52
|
const hashSection = typeof window === "undefined"
|
|
39
53
|
? null
|
|
40
54
|
: normalizeSettingsSection(window.location.hash);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
55
|
+
if (hashSection && sections.includes(hashSection))
|
|
56
|
+
return hashSection;
|
|
57
|
+
if (typeof window !== "undefined") {
|
|
58
|
+
const routeParts = settingsPathParts();
|
|
59
|
+
for (let index = routeParts.length - 1; index >= 0; index -= 1) {
|
|
60
|
+
const pathSection = normalizeSettingsSection(routeParts[index]);
|
|
61
|
+
if (pathSection && sections.includes(pathSection))
|
|
62
|
+
return pathSection;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return firstVisibleSection(sections);
|
|
44
66
|
}
|
|
45
67
|
export function useSettingsPanelController({ sections = ALL_SETTINGS_SECTIONS, initialSection, sectionRequestKey, onScrollToSection, } = {}) {
|
|
46
68
|
const visibleSections = useMemo(() => new Set(sections), [sections]);
|
|
@@ -72,23 +94,40 @@ export function useSettingsPanelController({ sections = ALL_SETTINGS_SECTIONS, i
|
|
|
72
94
|
useEffect(() => {
|
|
73
95
|
if (typeof window === "undefined")
|
|
74
96
|
return;
|
|
75
|
-
const
|
|
97
|
+
const handleLocationChange = () => {
|
|
76
98
|
const hash = window.location.hash?.replace(/^#/, "") ?? "";
|
|
77
|
-
|
|
99
|
+
let section = normalizeSettingsSection(hash);
|
|
100
|
+
const pathParts = settingsPathParts();
|
|
101
|
+
if (!section) {
|
|
102
|
+
for (let index = pathParts.length - 1; index >= 0; index -= 1) {
|
|
103
|
+
const pathSection = normalizeSettingsSection(pathParts[index]);
|
|
104
|
+
if (pathSection) {
|
|
105
|
+
section = pathSection;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
78
110
|
if (!section || !isSectionVisible(section))
|
|
79
111
|
return;
|
|
80
112
|
if (hash.startsWith("secrets:") || hash === "secrets") {
|
|
81
113
|
const key = hash.slice("secrets:".length);
|
|
82
114
|
setFocusSecretKey(key || undefined);
|
|
83
115
|
}
|
|
116
|
+
else if (section === "secrets") {
|
|
117
|
+
setFocusSecretKey(secretKeyFromPath(pathParts));
|
|
118
|
+
}
|
|
84
119
|
else {
|
|
85
120
|
setFocusSecretKey(undefined);
|
|
86
121
|
}
|
|
87
122
|
openSettingsSection(section, { scroll: true });
|
|
88
123
|
};
|
|
89
|
-
|
|
90
|
-
window.addEventListener("hashchange",
|
|
91
|
-
|
|
124
|
+
handleLocationChange();
|
|
125
|
+
window.addEventListener("hashchange", handleLocationChange);
|
|
126
|
+
window.addEventListener("popstate", handleLocationChange);
|
|
127
|
+
return () => {
|
|
128
|
+
window.removeEventListener("hashchange", handleLocationChange);
|
|
129
|
+
window.removeEventListener("popstate", handleLocationChange);
|
|
130
|
+
};
|
|
92
131
|
}, [isSectionVisible, openSettingsSection]);
|
|
93
132
|
return {
|
|
94
133
|
sections,
|
|
@@ -17,11 +17,11 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
17
17
|
id?: undefined;
|
|
18
18
|
provider?: undefined;
|
|
19
19
|
} | {
|
|
20
|
-
error?: undefined;
|
|
21
20
|
configured?: undefined;
|
|
22
21
|
connectPath?: undefined;
|
|
23
22
|
url: string;
|
|
24
23
|
id: string;
|
|
25
24
|
provider: string;
|
|
25
|
+
error?: undefined;
|
|
26
26
|
}>;
|
|
27
27
|
export default _default;
|
|
@@ -15,6 +15,36 @@ export interface WebsiteDesignTokens {
|
|
|
15
15
|
spacing: string[];
|
|
16
16
|
radii: string[];
|
|
17
17
|
cssVariables: Record<string, string>;
|
|
18
|
+
/**
|
|
19
|
+
* Semantic roles are inferred from visible rendered elements, not from
|
|
20
|
+
* variable names. They are optional so static HTML callers can keep their
|
|
21
|
+
* smaller result without inventing values that were never observed.
|
|
22
|
+
*/
|
|
23
|
+
semanticColors?: Partial<Record<"primary" | "secondary" | "accent" | "background" | "surface" | "text" | "textMuted", string>>;
|
|
24
|
+
shadows?: string[];
|
|
25
|
+
backgrounds?: string[];
|
|
26
|
+
components?: Array<{
|
|
27
|
+
role: "heading" | "body" | "button" | "link" | "card" | "input" | "nav" | "hero";
|
|
28
|
+
fontFamily?: string;
|
|
29
|
+
fontSize?: string;
|
|
30
|
+
fontWeight?: string;
|
|
31
|
+
lineHeight?: string;
|
|
32
|
+
letterSpacing?: string;
|
|
33
|
+
color?: string;
|
|
34
|
+
backgroundColor?: string;
|
|
35
|
+
backgroundImage?: string;
|
|
36
|
+
border?: string;
|
|
37
|
+
borderRadius?: string;
|
|
38
|
+
boxShadow?: string;
|
|
39
|
+
padding?: string;
|
|
40
|
+
gap?: string;
|
|
41
|
+
textTransform?: string;
|
|
42
|
+
}>;
|
|
43
|
+
layout?: {
|
|
44
|
+
contentWidth?: string;
|
|
45
|
+
pagePadding?: string;
|
|
46
|
+
sectionGap?: string;
|
|
47
|
+
};
|
|
18
48
|
}
|
|
19
49
|
export interface WebsiteExtraction {
|
|
20
50
|
title: string;
|
|
@@ -904,6 +904,11 @@ declare const messages: {
|
|
|
904
904
|
addYourOwn: string;
|
|
905
905
|
noMatches: string;
|
|
906
906
|
connected: string;
|
|
907
|
+
connectionError: string;
|
|
908
|
+
connectionErrorReason: string;
|
|
909
|
+
reconnect: string;
|
|
910
|
+
reconnecting: string;
|
|
911
|
+
reconnectFailed: string;
|
|
907
912
|
configure: string;
|
|
908
913
|
connect: string;
|
|
909
914
|
connectWithOAuth: string;
|
|
@@ -909,6 +909,11 @@ const messages = {
|
|
|
909
909
|
addYourOwn: "Add your own",
|
|
910
910
|
noMatches: "No integrations match that search.",
|
|
911
911
|
connected: "Connected",
|
|
912
|
+
connectionError: "Connection error",
|
|
913
|
+
connectionErrorReason: "Reason: {{reason}}",
|
|
914
|
+
reconnect: "Reconnect",
|
|
915
|
+
reconnecting: "Reconnecting…",
|
|
916
|
+
reconnectFailed: "Reconnect failed: {{error}}",
|
|
912
917
|
configure: "Configure",
|
|
913
918
|
connect: "Connect",
|
|
914
919
|
connectWithOAuth: "Connect",
|
|
@@ -190,7 +190,7 @@ async function handleMcpOAuthCallback(event, options) {
|
|
|
190
190
|
}
|
|
191
191
|
await options.reconfigure();
|
|
192
192
|
const returnPath = flow.returnUrl ??
|
|
193
|
-
`/settings?connected=mcp-${encodeURIComponent(flow.name)}
|
|
193
|
+
`/settings/integrations?connected=mcp-${encodeURIComponent(flow.name)}`;
|
|
194
194
|
return redirectWithStagedCookies(event, getAppUrl(event, returnPath));
|
|
195
195
|
}
|
|
196
196
|
catch {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* POST /_agent-native/mcp/servers add a server
|
|
10
10
|
* DELETE /_agent-native/mcp/servers/:id remove a server (scope via ?scope=)
|
|
11
11
|
* POST /_agent-native/mcp/servers/:id/test dry-run connect (no persist)
|
|
12
|
+
* POST /_agent-native/mcp/servers/:id/reconnect retry connect + refresh
|
|
12
13
|
* POST /_agent-native/mcp/servers/test dry-run a URL before persisting
|
|
13
14
|
* GET /_agent-native/mcp/builtin list built-in capability toggles
|
|
14
15
|
* POST /_agent-native/mcp/builtin update built-in capability toggles
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* POST /_agent-native/mcp/servers add a server
|
|
10
10
|
* DELETE /_agent-native/mcp/servers/:id remove a server (scope via ?scope=)
|
|
11
11
|
* POST /_agent-native/mcp/servers/:id/test dry-run connect (no persist)
|
|
12
|
+
* POST /_agent-native/mcp/servers/:id/reconnect retry connect + refresh
|
|
12
13
|
* POST /_agent-native/mcp/servers/test dry-run a URL before persisting
|
|
13
14
|
* GET /_agent-native/mcp/builtin list built-in capability toggles
|
|
14
15
|
* POST /_agent-native/mcp/builtin update built-in capability toggles
|
|
@@ -63,6 +64,15 @@ function projectForClient(stored, scope, ownerId, status) {
|
|
|
63
64
|
status,
|
|
64
65
|
};
|
|
65
66
|
}
|
|
67
|
+
function reconnectStatusForClient(manager, mergedId) {
|
|
68
|
+
const status = statusFor(manager, mergedId);
|
|
69
|
+
if (status.state !== "error")
|
|
70
|
+
return status;
|
|
71
|
+
return {
|
|
72
|
+
state: "error",
|
|
73
|
+
error: formatMcpConnectError(status.error),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
66
76
|
function statusFor(manager, mergedId) {
|
|
67
77
|
const snap = manager.getStatus();
|
|
68
78
|
if (snap.connectedServers.includes(mergedId)) {
|
|
@@ -328,6 +338,11 @@ export function mountMcpServersRoutes(nitroApp, manager, options = {}) {
|
|
|
328
338
|
if (parts.length === 2 && parts[1] === "test" && method === "POST") {
|
|
329
339
|
return handleTestExisting(event, manager, id);
|
|
330
340
|
}
|
|
341
|
+
if (parts.length === 2 &&
|
|
342
|
+
parts[1] === "reconnect" &&
|
|
343
|
+
method === "POST") {
|
|
344
|
+
return handleReconnectExisting(event, manager, id);
|
|
345
|
+
}
|
|
331
346
|
if (parts.length === 1 && method === "DELETE") {
|
|
332
347
|
return handleDelete(event, manager, id);
|
|
333
348
|
}
|
|
@@ -803,6 +818,40 @@ async function handleTestExisting(event, _manager, id) {
|
|
|
803
818
|
}
|
|
804
819
|
return { ok: true, toolCount: result.toolCount, tools: result.tools };
|
|
805
820
|
}
|
|
821
|
+
async function handleReconnectExisting(event, manager, id) {
|
|
822
|
+
const scope = getQuery(event).scope;
|
|
823
|
+
const parsedScope = scope === "org" ? "org" : scope === "user" ? "user" : null;
|
|
824
|
+
if (!parsedScope) {
|
|
825
|
+
setResponseStatus(event, 400);
|
|
826
|
+
return { error: 'scope query param must be "user" or "org"' };
|
|
827
|
+
}
|
|
828
|
+
const { email, orgId } = await resolveContextForRequest(event);
|
|
829
|
+
let scopeId = null;
|
|
830
|
+
if (parsedScope === "user") {
|
|
831
|
+
scopeId = email;
|
|
832
|
+
}
|
|
833
|
+
else {
|
|
834
|
+
scopeId = orgId;
|
|
835
|
+
}
|
|
836
|
+
if (!scopeId) {
|
|
837
|
+
setResponseStatus(event, 401);
|
|
838
|
+
return { error: "Authentication required" };
|
|
839
|
+
}
|
|
840
|
+
const list = await listRemoteServers(parsedScope, scopeId);
|
|
841
|
+
const server = list.find((s) => s.id === id);
|
|
842
|
+
if (!server) {
|
|
843
|
+
setResponseStatus(event, 404);
|
|
844
|
+
return { error: "Server not found" };
|
|
845
|
+
}
|
|
846
|
+
await reconfigureManager(manager);
|
|
847
|
+
const mergedId = mergedConfigKey(parsedScope, server, scopeId);
|
|
848
|
+
const status = reconnectStatusForClient(manager, mergedId);
|
|
849
|
+
const projected = projectForClient(server, parsedScope, scopeId, status);
|
|
850
|
+
return {
|
|
851
|
+
ok: true,
|
|
852
|
+
server: projected,
|
|
853
|
+
};
|
|
854
|
+
}
|
|
806
855
|
async function tryConnect(url, headers) {
|
|
807
856
|
try {
|
|
808
857
|
const { Client, StreamableHTTPClientTransport } = await import("@modelcontextprotocol/client");
|
package/dist/navigation/index.js
CHANGED
|
@@ -22,12 +22,22 @@ function normalizeLeadingPath(path) {
|
|
|
22
22
|
return `/${trimmed.replace(/^\/+/, "").replace(/\/+$/, "")}`;
|
|
23
23
|
}
|
|
24
24
|
function normalizeTabId(tab) {
|
|
25
|
-
|
|
25
|
+
const normalized = tab
|
|
26
26
|
.trim()
|
|
27
27
|
.replace(/^#/, "")
|
|
28
28
|
.toLowerCase()
|
|
29
29
|
.replace(/['"]/g, "")
|
|
30
30
|
.replace(/[\s_]+/g, "-");
|
|
31
|
+
if (normalized === "connections")
|
|
32
|
+
return "integrations";
|
|
33
|
+
if (normalized === "team" || normalized === "org")
|
|
34
|
+
return "organization";
|
|
35
|
+
if (normalized === "changelog" ||
|
|
36
|
+
normalized === "what-s-new" ||
|
|
37
|
+
normalized === "updates") {
|
|
38
|
+
return "whats-new";
|
|
39
|
+
}
|
|
40
|
+
return normalized;
|
|
31
41
|
}
|
|
32
42
|
function pathSegment(value) {
|
|
33
43
|
return encodeURIComponent(value.trim().replace(/^\/+|\/+$/g, ""));
|
|
@@ -40,10 +50,11 @@ function resolveOpenPathRoute(route, params) {
|
|
|
40
50
|
export function buildSettingsRoute(tab, basePath = STANDARD_APP_ROUTES.settings) {
|
|
41
51
|
const path = normalizeLeadingPath(basePath);
|
|
42
52
|
const normalizedTab = tab ? normalizeTabId(tab) : null;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
const segments = (normalizedTab || STANDARD_SETTINGS_TABS.general)
|
|
54
|
+
.split(":")
|
|
55
|
+
.map((segment) => pathSegment(segment))
|
|
56
|
+
.filter(Boolean);
|
|
57
|
+
return `${path}/${segments.join("/")}`;
|
|
47
58
|
}
|
|
48
59
|
export function buildTeamRoute(options = {}) {
|
|
49
60
|
return options.teamInSettings
|
|
@@ -41,16 +41,16 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
41
41
|
thumbsUpRate: number;
|
|
42
42
|
avgEvalScore: number;
|
|
43
43
|
} | {
|
|
44
|
-
error?: undefined;
|
|
45
44
|
summary: import("./types.js").TraceSummary;
|
|
46
45
|
spans: import("./types.js").TraceSpan[];
|
|
47
46
|
id?: undefined;
|
|
47
|
+
error?: undefined;
|
|
48
48
|
ok?: undefined;
|
|
49
49
|
} | {
|
|
50
|
-
error?: undefined;
|
|
51
50
|
summary?: undefined;
|
|
52
51
|
spans?: undefined;
|
|
53
52
|
id: string;
|
|
53
|
+
error?: undefined;
|
|
54
54
|
ok?: undefined;
|
|
55
55
|
} | {
|
|
56
56
|
summary?: undefined;
|
|
@@ -59,9 +59,9 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
59
59
|
error: any;
|
|
60
60
|
ok?: undefined;
|
|
61
61
|
} | {
|
|
62
|
-
error?: undefined;
|
|
63
62
|
summary?: undefined;
|
|
64
63
|
spans?: undefined;
|
|
65
64
|
id?: undefined;
|
|
66
65
|
ok: boolean;
|
|
66
|
+
error?: undefined;
|
|
67
67
|
}>>;
|