@shuffleio/shuffle-mcps 0.0.39 → 0.0.40

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/dist/index.mjs CHANGED
@@ -19,24 +19,25 @@ import {
19
19
  setHostBaseUrl,
20
20
  setRegionUrl,
21
21
  shuffleFetch
22
- } from "./chunk-DCHKGFML.mjs";
22
+ } from "./chunk-5LZ5IZ2O.mjs";
23
23
 
24
24
  // index.ts
25
- import "./shuffle-mcp-3U5AFQDK.css";
26
- import React7 from "react";
25
+ import "./shuffle-mcp-S6QOJJG4.css";
26
+ import React10 from "react";
27
27
 
28
28
  // ShuffleMcpThemeProvider.tsx
29
29
  import React from "react";
30
30
  import { ThemeProvider, createTheme, useTheme as useMuiTheme } from "@mui/material";
31
- import "./shuffle-mcp-3U5AFQDK.css";
31
+ import "./shuffle-mcp-S6QOJJG4.css";
32
32
  import { jsx, jsxs } from "react/jsx-runtime";
33
33
  var readHtmlDarkClass = () => {
34
34
  if (typeof document === "undefined") return false;
35
- return document.documentElement.classList.contains("dark");
35
+ return document.documentElement.classList.contains("dark") || Boolean(document.body) && document.body.classList.contains("dark");
36
36
  };
37
37
  var readAncestorDark = (anchor) => {
38
38
  if (!anchor || typeof document === "undefined") return null;
39
- const start = anchor.parentElement;
39
+ const ownRoot = anchor.closest("[data-shuffle-core-root], [data-shuffle-mcp-root]");
40
+ const start = ownRoot ? ownRoot.parentElement : anchor.parentElement;
40
41
  if (!start) return null;
41
42
  const scoped = start.closest('[data-shuffle-mode="dark"], [data-shuffle-mode="light"]');
42
43
  if (scoped) return scoped.getAttribute("data-shuffle-mode") === "dark";
@@ -55,12 +56,20 @@ var useAutoDarkClass = (enabled, anchorRef) => {
55
56
  recompute();
56
57
  const observer = new MutationObserver(recompute);
57
58
  observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] });
58
- let node = anchorRef.current?.parentElement ?? null;
59
+ if (document.body) {
60
+ observer.observe(document.body, { attributes: true, attributeFilter: ["class"] });
61
+ }
62
+ const ownRoot = anchorRef.current?.closest("[data-shuffle-core-root], [data-shuffle-mcp-root]");
63
+ let node = ownRoot ? ownRoot.parentElement : anchorRef.current?.parentElement ?? null;
59
64
  while (node) {
60
65
  observer.observe(node, { attributes: true, attributeFilter: ["class", "data-shuffle-mode"] });
61
66
  node = node.parentElement;
62
67
  }
63
- return () => observer.disconnect();
68
+ window.addEventListener("shuffle:theme-change", recompute);
69
+ return () => {
70
+ observer.disconnect();
71
+ window.removeEventListener("shuffle:theme-change", recompute);
72
+ };
64
73
  }, [enabled, anchorRef]);
65
74
  return isDark;
66
75
  };
@@ -115,11 +124,26 @@ var buildComponentOverrides = (scopeClassName) => ({
115
124
  },
116
125
  // ---- Portaled surfaces: stamp scopeClassName so HSL tokens resolve ----
117
126
  MuiDrawer: {
118
- defaultProps: { slotProps: { paper: { className: scopeClassName } } }
127
+ defaultProps: { slotProps: { paper: { className: scopeClassName } } },
128
+ styleOverrides: {
129
+ paper: {
130
+ backgroundColor: "hsl(var(--sidebar-background, var(--card)))",
131
+ color: "hsl(var(--sidebar-foreground, var(--foreground)))",
132
+ borderRight: "1px solid hsl(var(--sidebar-border, var(--border)))"
133
+ }
134
+ }
119
135
  },
120
136
  MuiDialog: {
121
137
  defaultProps: { slotProps: { paper: { className: scopeClassName } } },
122
- styleOverrides: { root: { zIndex: 10010 } }
138
+ styleOverrides: {
139
+ root: { zIndex: 10010 },
140
+ paper: {
141
+ backgroundColor: "hsl(var(--card))",
142
+ color: "hsl(var(--card-foreground))",
143
+ border: "1px solid hsl(var(--border))",
144
+ boxShadow: "0 12px 32px rgba(0, 0, 0, 0.2)"
145
+ }
146
+ }
123
147
  },
124
148
  MuiMenu: {
125
149
  defaultProps: { slotProps: { paper: { className: scopeClassName } } },
@@ -128,7 +152,8 @@ var buildComponentOverrides = (scopeClassName) => ({
128
152
  paper: {
129
153
  backgroundColor: "hsl(var(--popover))",
130
154
  color: "hsl(var(--popover-foreground))",
131
- border: "1px solid hsl(var(--border))"
155
+ border: "1px solid hsl(var(--border))",
156
+ boxShadow: "0 4px 14px rgba(0, 0, 0, 0.12)"
132
157
  }
133
158
  }
134
159
  },
@@ -139,7 +164,8 @@ var buildComponentOverrides = (scopeClassName) => ({
139
164
  paper: {
140
165
  backgroundColor: "hsl(var(--popover))",
141
166
  color: "hsl(var(--popover-foreground))",
142
- border: "1px solid hsl(var(--border))"
167
+ border: "1px solid hsl(var(--border))",
168
+ boxShadow: "0 4px 14px rgba(0, 0, 0, 0.12)"
143
169
  }
144
170
  }
145
171
  },
@@ -150,6 +176,23 @@ var buildComponentOverrides = (scopeClassName) => ({
150
176
  // Render above app drawers, dialogs, menus, and popovers.
151
177
  popper: { sx: { zIndex: 10030 } }
152
178
  }
179
+ },
180
+ styleOverrides: {
181
+ tooltip: {
182
+ backgroundColor: "hsl(var(--popover))",
183
+ color: "hsl(var(--popover-foreground))",
184
+ border: "1px solid hsl(var(--border))",
185
+ boxShadow: "0 4px 14px rgba(0, 0, 0, 0.12)",
186
+ fontSize: "0.75rem",
187
+ borderRadius: 8
188
+ },
189
+ arrow: {
190
+ color: "hsl(var(--popover))",
191
+ "&::before": {
192
+ border: "1px solid hsl(var(--border))",
193
+ boxSizing: "border-box"
194
+ }
195
+ }
153
196
  }
154
197
  },
155
198
  MuiDivider: {
@@ -166,7 +209,7 @@ var ShuffleMcpThemeProvider = ({
166
209
  const autoIsDark = useAutoDarkClass(mode === "auto", anchorRef);
167
210
  const effectiveDark = mode === "auto" ? autoIsDark : mode === "dark";
168
211
  const sameAsParent = parentCtx !== null && parentCtx.isDark === effectiveDark;
169
- const scopeClassName = effectiveDark ? "shuffle-mcp-scope dark" : "shuffle-mcp-scope";
212
+ const scopeClassName = effectiveDark ? "shuffle-mcp-scope dark" : "shuffle-mcp-scope light";
170
213
  const resolvedModeAttr = effectiveDark ? "dark" : "light";
171
214
  const merged = React.useMemo(
172
215
  () => createTheme({
@@ -575,7 +618,7 @@ var keyFor = (input, init) => {
575
618
  return null;
576
619
  }
577
620
  };
578
- var withStoredApiKey = (input, init) => {
621
+ var withStoredAuth = (input, init) => {
579
622
  if (typeof window === "undefined") return init;
580
623
  let urlStr;
581
624
  if (typeof input === "string") urlStr = input;
@@ -584,17 +627,35 @@ var withStoredApiKey = (input, init) => {
584
627
  else return init;
585
628
  try {
586
629
  const url = new URL(urlStr, window.location.href);
587
- const isKnownShuffleOrigin = allowedOrigins.has(url.origin) || url.origin === window.location.origin || url.hostname === "shuffler.io" || url.hostname.endsWith(".shuffler.io") || url.hostname === "tunnel.schemaless.org";
630
+ const isKnownShuffleOrigin = allowedOrigins.has(url.origin) || url.origin === window.location.origin || url.hostname === "shuffler.io" || url.hostname.endsWith(".shuffler.io") || url.hostname === "tunnel.schemaless.org" || url.hostname === "shuffle.security" || url.hostname.endsWith(".shuffle.security");
588
631
  if (!url.pathname.startsWith("/api/") || !isKnownShuffleOrigin) return init;
589
- const apiKey = window.localStorage.getItem("shuffle_api_key");
590
- if (!apiKey) return init;
632
+ if (url.pathname === "/api/v1/login" || url.pathname === "/api/v1/users/register") return init;
633
+ const sessionToken = window.localStorage.getItem("session_token");
634
+ const token = sessionToken && sessionToken.trim().length > 0 ? sessionToken.trim() : null;
591
635
  const requestHeaders = typeof Request !== "undefined" && input instanceof Request ? input.headers : void 0;
592
636
  const headers = new Headers(requestHeaders);
593
637
  if (init?.headers) {
594
638
  new Headers(init.headers).forEach((value, name) => headers.set(name, value));
595
639
  }
596
- if (!headers.has("Authorization")) headers.set("Authorization", `Bearer ${apiKey}`);
597
- return { ...init, headers };
640
+ if (token && !headers.has("Authorization")) {
641
+ headers.set("Authorization", `Bearer ${token}`);
642
+ }
643
+ if (!headers.has("Org-Id")) {
644
+ try {
645
+ const raw = window.localStorage.getItem("shuffle_user_info");
646
+ if (raw) {
647
+ const parsed = JSON.parse(raw);
648
+ const orgId = parsed?.active_org?.id;
649
+ if (orgId) headers.set("Org-Id", orgId);
650
+ }
651
+ } catch {
652
+ }
653
+ }
654
+ return {
655
+ ...init,
656
+ credentials: init?.credentials || "include",
657
+ headers
658
+ };
598
659
  } catch {
599
660
  return init;
600
661
  }
@@ -633,7 +694,7 @@ var installFetchBreaker2 = () => {
633
694
  installed = true;
634
695
  const original = window.fetch.bind(window);
635
696
  window.fetch = (async (input, init) => {
636
- const authenticatedInit = withStoredApiKey(input, init);
697
+ const authenticatedInit = withStoredAuth(input, init);
637
698
  const key = keyFor(input, authenticatedInit);
638
699
  if (!key) return original(input, authenticatedInit);
639
700
  const entry = getEntry(key);
@@ -1875,7 +1936,7 @@ async function backfillAppImages(dedupedApps) {
1875
1936
  let missing = dedupedApps.filter((d) => !d.bestImage && !d.app.large_image);
1876
1937
  if (missing.length === 0) return dedupedApps;
1877
1938
  try {
1878
- const { fetchAppsViaApiConfig: fetchAppsViaApiConfig2 } = await import("./appsCache-32FX7WJE.mjs");
1939
+ const { fetchAppsViaApiConfig: fetchAppsViaApiConfig2 } = await import("./appsCache-EFH5WV4I.mjs");
1879
1940
  const apps = await fetchAppsViaApiConfig2().catch(() => []);
1880
1941
  if (Array.isArray(apps) && apps.length > 0) {
1881
1942
  const byName = /* @__PURE__ */ new Map();
@@ -1935,10 +1996,10 @@ async function backfillAppImages(dedupedApps) {
1935
1996
  }
1936
1997
 
1937
1998
  // ingestionDetection.ts
1938
- var EMAIL_APP_PATTERNS = ["gmail", "outlook", "email", "microsoft_graph", "office365", "exchange", "imap", "smtp"];
1999
+ var EMAIL_APP_PATTERNS = ["gmail", "outlook", "email", "microsoft_graph", "office365", "exchange", "imap", "smtp", "proofpoint", "mimecast", "phishing"];
1939
2000
  var CASES_PATTERNS = ["jira", "servicenow", "zendesk", "freshdesk", "pagerduty", "opsgenie", "ticket", "itsm", "salesforce", "thehive", "cortex"];
1940
- var EDR_PATTERNS = ["crowdstrike", "sentinelone", "carbon black", "defender", "cylance", "sophos", "trellix", "vmware", "tanium", "falcon", "edr"];
1941
- var SIEM_PATTERNS = ["splunk", "elastic", "qradar", "sentinel", "chronicle", "logrhythm", "sumo logic", "graylog", "wazuh", "siem", "arcsight"];
2001
+ var EDR_PATTERNS = ["crowdstrike", "sentinelone", "carbon black", "cybereason", "microsoft defender", "defender for endpoint", "defender", "cylance", "sophos", "trellix", "tanium", "crowdstrike falcon", "falcon", "vmware", "edr", "xdr"];
2002
+ var SIEM_PATTERNS = ["splunk", "elastic", "qradar", "microsoft sentinel", "azure sentinel", "sentinel", "chronicle", "logrhythm", "sumo logic", "graylog", "wazuh", "siem", "arcsight"];
1942
2003
  var THREAT_INTEL_PATTERNS = ["virustotal", "shodan", "alienvault", "otx", "threatcrowd", "urlscan", "hybrid-analysis", "abuseipdb", "greynoise", "urlhaus", "malwarebazaar", "threatfox", "misp", "opencti", "recorded future", "mandiant", "crowdstrike intel", "intel471", "flashpoint", "domaintools"];
1943
2004
  var COMMUNICATION_PATTERNS_NAMES = ["slack", "teams", "discord", "mattermost", "telegram", "webhook"];
1944
2005
  var VULN_SCANNER_PATTERNS = ["qualys", "tenable", "nessus", "rapid7", "nexpose", "snyk", "sonarqube", "trivy", "grype", "anchore", "dependabot", "aws_inspector", "azure_defender", "gcp_scc", "scout", "prowler", "checkov", "wiz", "orca", "lacework", "prisma"];
@@ -2132,6 +2193,65 @@ var fetchAppConfig = (appId) => {
2132
2193
  return promise;
2133
2194
  };
2134
2195
 
2196
+ // ../Shuffle-Core/views/appsFetchCache.ts
2197
+ var JSON_CACHE_TTL_MS = 12e4;
2198
+ var WORKFLOWS_TTL_MS = 5 * 60 * 1e3;
2199
+ var _jsonCache = /* @__PURE__ */ new Map();
2200
+ var _inFlightPromises = /* @__PURE__ */ new Map();
2201
+ function normalizeEndpointKey(url, init) {
2202
+ let pathname = url;
2203
+ let search = "";
2204
+ try {
2205
+ const parsed = new URL(url, "https://shuffle.internal");
2206
+ pathname = parsed.pathname;
2207
+ search = parsed.search;
2208
+ } catch {
2209
+ }
2210
+ let orgId = "";
2211
+ if (init?.headers) {
2212
+ if (init.headers instanceof Headers) {
2213
+ orgId = init.headers.get("Org-Id") || "";
2214
+ } else if (Array.isArray(init.headers)) {
2215
+ const match = init.headers.find(([k]) => k.toLowerCase() === "org-id");
2216
+ if (match) orgId = match[1];
2217
+ } else if (typeof init.headers === "object") {
2218
+ orgId = init.headers["Org-Id"] || init.headers["org-id"] || "";
2219
+ }
2220
+ }
2221
+ return `${pathname}${search}${orgId ? `::org:${orgId}` : ""}`;
2222
+ }
2223
+ async function fetchJsonCached(url, init, ttlMs = JSON_CACHE_TTL_MS, force = false) {
2224
+ const cacheKey2 = normalizeEndpointKey(url, init);
2225
+ const now = Date.now();
2226
+ if (!force) {
2227
+ const cached = _jsonCache.get(cacheKey2);
2228
+ if (cached && now - cached.ts < ttlMs) {
2229
+ return cached.data;
2230
+ }
2231
+ const inFlight = _inFlightPromises.get(cacheKey2);
2232
+ if (inFlight) {
2233
+ return inFlight;
2234
+ }
2235
+ }
2236
+ const p = (async () => {
2237
+ try {
2238
+ const res = await fetch(url, init);
2239
+ if (!res.ok) {
2240
+ const prev = _jsonCache.get(cacheKey2);
2241
+ if (prev) return prev.data;
2242
+ throw new Error(`HTTP ${res.status}`);
2243
+ }
2244
+ const data = await res.json();
2245
+ _jsonCache.set(cacheKey2, { ts: Date.now(), data });
2246
+ return data;
2247
+ } finally {
2248
+ _inFlightPromises.delete(cacheKey2);
2249
+ }
2250
+ })();
2251
+ _inFlightPromises.set(cacheKey2, p);
2252
+ return p;
2253
+ }
2254
+
2135
2255
  // authenticatedApps.ts
2136
2256
  var TTL_MS = 3e4;
2137
2257
  var cache2 = /* @__PURE__ */ new Map();
@@ -2155,14 +2275,16 @@ var doFetch2 = async (crossOrgId) => {
2155
2275
  const headers = {
2156
2276
  ...getAuthHeader(crossOrgId ?? void 0)
2157
2277
  };
2158
- const response = await fetch(getApiUrl("/api/v1/apps/authentication"), {
2159
- credentials: "include",
2160
- headers
2161
- });
2162
- if (!response.ok) return [];
2163
- const result = await response.json();
2164
- const data = result?.data || result;
2165
- return Array.isArray(data) ? applyValidationStaleness(data) : [];
2278
+ try {
2279
+ const result = await fetchJsonCached(getApiUrl("/api/v1/apps/authentication"), {
2280
+ credentials: "include",
2281
+ headers
2282
+ });
2283
+ const data = result?.data || result;
2284
+ return Array.isArray(data) ? applyValidationStaleness(data) : [];
2285
+ } catch {
2286
+ return [];
2287
+ }
2166
2288
  };
2167
2289
  var fetchAuthenticatedApps = (crossOrgId) => {
2168
2290
  const key = cacheKey(crossOrgId);
@@ -4163,6 +4285,14 @@ var NO_AUTH_APPS = /* @__PURE__ */ new Set([
4163
4285
  "shuffle_files",
4164
4286
  "shuffles_app_management",
4165
4287
  "shuffle_tools",
4288
+ "shuffle_assets",
4289
+ "shuffle_software",
4290
+ "shuffle_packages",
4291
+ "shuffle_vulnerabilities",
4292
+ "assets",
4293
+ "software",
4294
+ "packages",
4295
+ "vulnerabilities",
4166
4296
  "tools",
4167
4297
  "http",
4168
4298
  "singul",
@@ -7108,7 +7238,7 @@ function AppDetailDrawer({
7108
7238
  }
7109
7239
 
7110
7240
  // views/ShuffleMCP.tsx
7111
- import "./shuffle-mcp-3U5AFQDK.css";
7241
+ import "./shuffle-mcp-S6QOJJG4.css";
7112
7242
 
7113
7243
  // components/SegmentedControl.tsx
7114
7244
  import * as React3 from "react";
@@ -8146,10 +8276,89 @@ import {
8146
8276
  } from "@mui/material";
8147
8277
  import { Plus, CheckCircle2, AlertTriangle } from "lucide-react";
8148
8278
 
8279
+ // ../Shuffle-Core/lib/shuffleUrls.ts
8280
+ var readEnv = (key) => {
8281
+ try {
8282
+ const meta = new Function("try { return import.meta } catch { return undefined }")();
8283
+ const val = meta?.env?.[key];
8284
+ if (val && typeof val === "string" && val.trim().length > 0) {
8285
+ return val.trim();
8286
+ }
8287
+ } catch {
8288
+ }
8289
+ if (typeof window !== "undefined") {
8290
+ const win = window;
8291
+ const runtimeConfig = win.__SHUFFLE_CONFIG__ || win._env_ || win.__ENV__;
8292
+ if (runtimeConfig && typeof runtimeConfig === "object") {
8293
+ const val = runtimeConfig[key] || runtimeConfig[key.replace(/^VITE_/, "")];
8294
+ if (val && typeof val === "string" && val.trim().length > 0) {
8295
+ return val.trim();
8296
+ }
8297
+ }
8298
+ }
8299
+ try {
8300
+ if (typeof process !== "undefined" && process.env) {
8301
+ const val = process.env[key] || process.env[key.replace(/^VITE_/, "")];
8302
+ if (val && typeof val === "string" && val.trim().length > 0) {
8303
+ return val.trim();
8304
+ }
8305
+ }
8306
+ } catch {
8307
+ }
8308
+ return void 0;
8309
+ };
8310
+ var isManagedDomain = () => {
8311
+ if (typeof window === "undefined") return false;
8312
+ const hostname = window.location.hostname.toLowerCase();
8313
+ return hostname.includes("lovable") || hostname.includes("shuffler.io") || hostname.includes("shutdown.no") || hostname.includes("shuffle.security");
8314
+ };
8315
+ var getShuffleCoreBaseUrl = () => {
8316
+ const envUrl = readEnv("VITE_SHUFFLE_CORE_URL") || readEnv("SHUFFLE_CORE_URL") || readEnv("VITE_SHUFFLE_AUTOMATION_URL") || readEnv("VITE_SHUFFLE_URL");
8317
+ if (envUrl) {
8318
+ return envUrl.replace(/\/+$/, "");
8319
+ }
8320
+ if (typeof window !== "undefined") {
8321
+ try {
8322
+ const savedCore = localStorage.getItem("shuffle_core_url");
8323
+ if (savedCore && savedCore.trim().length > 0) {
8324
+ return savedCore.trim().replace(/\/+$/, "");
8325
+ }
8326
+ const customHost = localStorage.getItem("shuffle_custom_host_url");
8327
+ if (customHost && customHost.trim().length > 0) {
8328
+ const cleaned = customHost.trim().replace(/\/+$/, "");
8329
+ if (cleaned.includes(":5001")) {
8330
+ return cleaned.replace(":5001", ":3001");
8331
+ }
8332
+ return cleaned;
8333
+ }
8334
+ } catch {
8335
+ }
8336
+ }
8337
+ if (typeof window !== "undefined") {
8338
+ const hostname = window.location.hostname;
8339
+ const isManaged = isManagedDomain();
8340
+ if (isManaged) {
8341
+ return "https://shuffler.io";
8342
+ }
8343
+ if (window.location.port === "3001") {
8344
+ return window.location.origin;
8345
+ }
8346
+ return `${window.location.protocol}//${hostname}:3001`;
8347
+ }
8348
+ return "https://shuffler.io";
8349
+ };
8350
+ var getShuffleCoreUrl = (path) => {
8351
+ const base3 = getShuffleCoreBaseUrl();
8352
+ if (!path) return base3;
8353
+ const cleanPath = path.startsWith("/") ? path : `/${path}`;
8354
+ return `${base3}${cleanPath}`;
8355
+ };
8356
+
8149
8357
  // ../Shuffle-Core/api.ts
8150
8358
  installFetchBreaker2();
8151
8359
  var DEV_BACKEND = "https://tunnel.schemaless.org";
8152
- var PROD_BACKEND = "https://shuffler.io";
8360
+ var PROD_BACKEND = "https://uk.shuffler.io";
8361
+ var SHUFFLE_AUTOMATION_URL = getShuffleCoreUrl("/new-dashboard");
8153
8362
  var CLOUD_DOMAINS = ["shuffle.security", "www.shuffle.security", "security.shuffler.io", "shutdown.no", "www.shutdown.no"];
8154
8363
  var getEnvVar = (key) => {
8155
8364
  try {
@@ -8185,7 +8394,11 @@ var _cachedRegion = (() => {
8185
8394
  const raw = localStorage.getItem(REGION_STORAGE_KEY);
8186
8395
  if (!raw) return { url: null, orgId: null };
8187
8396
  const parsed = JSON.parse(raw);
8188
- return { url: parsed?.url || null, orgId: parsed?.orgId || null };
8397
+ const url = parsed?.url ? parsed.url.replace(/\/+$/, "") : null;
8398
+ if (url === "https://shuffler.io" || url === PROD_BACKEND) {
8399
+ return { url: null, orgId: parsed?.orgId || null };
8400
+ }
8401
+ return { url, orgId: parsed?.orgId || null };
8189
8402
  } catch {
8190
8403
  return { url: null, orgId: null };
8191
8404
  }
@@ -8193,8 +8406,20 @@ var _cachedRegion = (() => {
8193
8406
  var _readCachedCustomHost = () => {
8194
8407
  if (typeof window === "undefined") return null;
8195
8408
  try {
8409
+ const mode = localStorage.getItem("shuffle_selected_server_mode");
8410
+ if (mode && mode !== "self-hosted") return null;
8196
8411
  const raw = localStorage.getItem("shuffle_custom_host_url");
8197
- return raw ? raw.trim().replace(/\/+$/, "") : null;
8412
+ const cleaned = raw ? raw.trim().replace(/\/+$/, "") : null;
8413
+ if (!cleaned) return null;
8414
+ if (cleaned === DEV_BACKEND && !isDevEnvironment2() && mode !== "self-hosted") {
8415
+ try {
8416
+ localStorage.removeItem("shuffle_custom_host_url");
8417
+ localStorage.removeItem("shuffle_selected_server_mode");
8418
+ } catch {
8419
+ }
8420
+ return null;
8421
+ }
8422
+ return cleaned;
8198
8423
  } catch {
8199
8424
  return null;
8200
8425
  }
@@ -8247,6 +8472,38 @@ if (typeof window !== "undefined") {
8247
8472
  } catch {
8248
8473
  }
8249
8474
  }
8475
+ var LEGACY_API_KEY_STORAGE_KEY = "shuffle_api_key";
8476
+ var clearAuthTokens = () => {
8477
+ try {
8478
+ localStorage.removeItem("session_token");
8479
+ localStorage.removeItem(LEGACY_API_KEY_STORAGE_KEY);
8480
+ } catch {
8481
+ }
8482
+ };
8483
+ var getSessionToken = () => {
8484
+ try {
8485
+ if (typeof localStorage === "undefined") return null;
8486
+ if (localStorage.getItem(LEGACY_API_KEY_STORAGE_KEY) !== null) {
8487
+ localStorage.removeItem(LEGACY_API_KEY_STORAGE_KEY);
8488
+ }
8489
+ const stored = localStorage.getItem("session_token");
8490
+ if (stored && stored.trim().length > 0 && stored !== "null" && stored !== "undefined") {
8491
+ return stored.trim();
8492
+ }
8493
+ return null;
8494
+ } catch {
8495
+ return null;
8496
+ }
8497
+ };
8498
+ var setSessionToken = (token) => {
8499
+ clearAuthTokens();
8500
+ if (token && token.trim().length > 0) {
8501
+ try {
8502
+ localStorage.setItem("session_token", token.trim());
8503
+ } catch {
8504
+ }
8505
+ }
8506
+ };
8250
8507
  var API_CONFIG5 = {
8251
8508
  get baseUrl() {
8252
8509
  const url = _hostBaseUrl || (isDevEnvironment2() || getEnvVar("VITE_SHUFFLE_API_URL") ? getDefaultBaseUrl() : _regionUrl || getDefaultBaseUrl());
@@ -8257,28 +8514,36 @@ var API_CONFIG5 = {
8257
8514
  return url;
8258
8515
  },
8259
8516
  version: "v1",
8517
+ /** DEPRECATED alias for the single session token. */
8260
8518
  get apiKey() {
8261
- try {
8262
- return typeof localStorage !== "undefined" ? localStorage.getItem("shuffle_api_key") : null;
8263
- } catch {
8264
- return null;
8265
- }
8519
+ return getSessionToken();
8266
8520
  },
8521
+ /** DEPRECATED: writes/clears the single session token. */
8267
8522
  setApiKey(key) {
8268
- try {
8269
- if (key) localStorage.setItem("shuffle_api_key", key);
8270
- else localStorage.removeItem("shuffle_api_key");
8271
- } catch {
8272
- }
8523
+ setSessionToken(key);
8273
8524
  }
8274
8525
  };
8275
8526
  var getApiUrl2 = (endpoint) => `${API_CONFIG5.baseUrl}${endpoint}`;
8276
8527
  var getAuthHeader2 = (overrideOrgId) => {
8277
8528
  const headers = {};
8278
- const apiKey = API_CONFIG5.apiKey;
8279
- if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
8280
- const orgId = overrideOrgId ?? _trackedOrgId;
8281
- if (orgId) headers["Org-Id"] = orgId;
8529
+ const token = getSessionToken();
8530
+ if (token) {
8531
+ headers["Authorization"] = `Bearer ${token}`;
8532
+ }
8533
+ let orgId = overrideOrgId ?? _trackedOrgId;
8534
+ if (!orgId && typeof localStorage !== "undefined") {
8535
+ try {
8536
+ const raw = localStorage.getItem("shuffle_user_info");
8537
+ if (raw) {
8538
+ const parsed = JSON.parse(raw);
8539
+ orgId = parsed?.active_org?.id || parsed?.org_id || null;
8540
+ }
8541
+ } catch {
8542
+ }
8543
+ }
8544
+ if (orgId) {
8545
+ headers["Org-Id"] = orgId;
8546
+ }
8282
8547
  return headers;
8283
8548
  };
8284
8549
 
@@ -10312,7 +10577,7 @@ var safeHandler_default = safeHandler;
10312
10577
 
10313
10578
  // components/AgentPresets.tsx
10314
10579
  import { useEffect as useEffect12, useMemo as useMemo7, useState as useState13 } from "react";
10315
- import { Box as Box16, Button as Button9, ClickAwayListener, Paper, Popper, TextField as TextField6, Tooltip as Tooltip9, Typography as Typography14 } from "@mui/material";
10580
+ import { Box as Box16, ButtonBase, ClickAwayListener, Paper, Popper, TextField as TextField6, Tooltip as Tooltip9, Typography as Typography14 } from "@mui/material";
10316
10581
  import { Workflow, ShieldAlert, LifeBuoy, Bug, Radar, Monitor, Plus as Plus2, X as CloseIcon6, BellRing } from "lucide-react";
10317
10582
  import { Fragment as Fragment9, jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
10318
10583
  var normalizeToolName = (name) => (name || "").toLowerCase().trim().replace(/[\s-]+/g, "_");
@@ -10325,8 +10590,8 @@ var prettyAppName = (name) => name.replace(/[_-]+/g, " ").trim().split(/\s+/).ma
10325
10590
  var AGENT_PRESETS = [
10326
10591
  {
10327
10592
  id: "build-workflows",
10328
- label: "Build Workflows",
10329
- description: "Designs and edits Shuffle workflows for you \u2014 pick apps, wire actions, and iterate on automations from a description.",
10593
+ label: "Build Workflow",
10594
+ description: "Designs and builds Shuffle workflows for you \u2014 pick apps, wire actions, and iterate on automations from a description.",
10330
10595
  defaultPrompt: "Build a Shuffle workflow that ",
10331
10596
  icon: /* @__PURE__ */ jsx23(Workflow, { size: 16 }),
10332
10597
  enabled: true,
@@ -10335,8 +10600,8 @@ var AGENT_PRESETS = [
10335
10600
  },
10336
10601
  {
10337
10602
  id: "incident-response",
10338
- label: "Incident Response Agent",
10339
- description: "Triages incidents: enriches observables, correlates related cases, and proposes next actions with rationale.",
10603
+ label: "Incident Handler",
10604
+ description: "Supports your incident investigation \u2014 extracts observables, correlates related alerts, analyzes attack scope, and proposes tiered containment options with human confirmation.",
10340
10605
  defaultPrompt: "Investigate this incident and recommend next steps: ",
10341
10606
  icon: /* @__PURE__ */ jsx23(ShieldAlert, { size: 16 }),
10342
10607
  enabled: true,
@@ -10357,28 +10622,41 @@ var AGENT_PRESETS = [
10357
10622
  label: "Support Agent",
10358
10623
  description: 'Uses the platform on your behalf \u2014 navigates settings, runs diagnostics, and answers "how do I\u2026" questions.',
10359
10624
  defaultPrompt: "Help me with the following on the Shuffle platform: ",
10360
- icon: /* @__PURE__ */ jsx23(LifeBuoy, { size: 16 })
10625
+ icon: /* @__PURE__ */ jsx23(LifeBuoy, { size: 16 }),
10626
+ enabled: true,
10627
+ defaultApps: [{ name: "shuffle_tools" }]
10361
10628
  },
10362
10629
  {
10363
10630
  id: "vulnerability",
10364
- label: "Vulnerability Agent",
10365
- description: "Reviews vulnerabilities, ranks by exploitability and asset criticality, and drafts remediation plans.",
10366
- defaultPrompt: "Review my current vulnerabilities and prioritize them by ",
10367
- icon: /* @__PURE__ */ jsx23(Bug, { size: 16 })
10631
+ label: "Vulnerability Management",
10632
+ description: "Helps you solve vulnerabilities \u2014 demystifies CVEs in plain language, analyzes realistic exploitability (EPSS/KEV), and guides you through exact remediation steps and fixes.",
10633
+ defaultPrompt: "Help me review and solve this vulnerability: ",
10634
+ icon: /* @__PURE__ */ jsx23(Bug, { size: 16 }),
10635
+ enabled: true,
10636
+ defaultApps: [
10637
+ { name: "shuffle_vulnerabilities" },
10638
+ { name: "shuffle_assets" },
10639
+ { name: "shuffle_software" },
10640
+ { name: "shuffle_packages" }
10641
+ ]
10368
10642
  },
10369
10643
  {
10370
10644
  id: "detection",
10371
10645
  label: "Detection Agent",
10372
10646
  description: "Creates and tunes detection rules (Sigma, pipelines) \u2014 adjusts logic, filters false positives, and validates coverage.",
10373
10647
  defaultPrompt: "Modify my detections to ",
10374
- icon: /* @__PURE__ */ jsx23(Radar, { size: 16 })
10648
+ icon: /* @__PURE__ */ jsx23(Radar, { size: 16 }),
10649
+ enabled: true,
10650
+ defaultApps: [{ name: "shuffle_detection" }]
10375
10651
  },
10376
10652
  {
10377
10653
  id: "handle-notifications",
10378
10654
  label: "Handle Notifications",
10379
10655
  description: "Automatically handles incoming incidents for you \u2014 triages, enriches, and resolves or escalates based on your rules.",
10380
10656
  defaultPrompt: "Automatically handle incoming incidents by ",
10381
- icon: /* @__PURE__ */ jsx23(BellRing, { size: 16 })
10657
+ icon: /* @__PURE__ */ jsx23(BellRing, { size: 16 }),
10658
+ enabled: true,
10659
+ defaultApps: [{ name: "shuffle_incidents" }]
10382
10660
  }
10383
10661
  ];
10384
10662
  var isSupportUser = () => {
@@ -10401,7 +10679,7 @@ var filterAgentPresets = (list, support) => {
10401
10679
  if (support === true || support === void 0 && isSupportUser()) return list;
10402
10680
  return list.map((p) => SUPPORT_ONLY_PRESET_IDS.includes(p.id) ? { ...p, enabled: false } : p);
10403
10681
  };
10404
- var AgentPresets = ({ variant = "default", onSelectPreset, selectedPreset, onRemoveSelected, presets, chipRef, isSupport }) => {
10682
+ var AgentPresets = ({ variant = "default", onSelectPreset, selectedPreset, onRemoveSelected, presets, chipRef, isSupport, sx, placement }) => {
10405
10683
  const [anchorEl, setAnchorEl] = useState13(null);
10406
10684
  const open = Boolean(anchorEl);
10407
10685
  const [supportTick, setSupportTick] = useState13(0);
@@ -10416,47 +10694,106 @@ var AgentPresets = ({ variant = "default", onSelectPreset, selectedPreset, onRem
10416
10694
  [presets, supportTick, open, isSupport]
10417
10695
  );
10418
10696
  const MAX_LABEL_CHARS = 18;
10419
- const displayLabel = selectedPreset ? selectedPreset.label.length > MAX_LABEL_CHARS ? `${selectedPreset.label.slice(0, MAX_LABEL_CHARS - 1).trimEnd()}\u2026` : selectedPreset.label : "Skills";
10420
- const trigger = /* @__PURE__ */ jsx23(
10421
- Button9,
10697
+ const cleanLabel = selectedPreset?.label?.replace(/\s+Agent$/i, "") || "";
10698
+ const displayLabel = selectedPreset ? cleanLabel.length > MAX_LABEL_CHARS ? `${cleanLabel.slice(0, MAX_LABEL_CHARS - 1).trimEnd()}\u2026` : cleanLabel : "Skills";
10699
+ const trigger = /* @__PURE__ */ jsxs17(
10700
+ ButtonBase,
10422
10701
  {
10423
10702
  ref: chipRef,
10424
- size: "small",
10425
10703
  onClick: (e) => setAnchorEl(e.currentTarget),
10426
- startIcon: selectedPreset ? selectedPreset.icon ?? void 0 : /* @__PURE__ */ jsx23(Plus2, { size: variant === "floating" ? 12 : 14 }),
10427
- endIcon: selectedPreset ? /* @__PURE__ */ jsx23(
10428
- Box16,
10704
+ "aria-label": selectedPreset ? `Skill: ${selectedPreset.label}` : "Select skill",
10705
+ sx: [
10429
10706
  {
10430
- component: "span",
10431
- onClick: (e) => {
10432
- e.stopPropagation();
10433
- onRemoveSelected?.();
10434
- },
10435
- sx: { display: "inline-flex", alignItems: "center", justifyContent: "center", ml: 0.25 },
10436
- children: /* @__PURE__ */ jsx23(CloseIcon6, { size: variant === "floating" ? 12 : 14 })
10437
- }
10438
- ) : void 0,
10439
- sx: {
10440
- textTransform: "none",
10441
- fontSize: variant === "floating" ? "0.72rem" : "0.78rem",
10442
- fontWeight: 500,
10443
- height: variant === "floating" ? 30 : variant === "inline" ? 38 : 36,
10444
- px: variant === "floating" ? 1.25 : 1.625,
10445
- py: 0.375,
10446
- borderRadius: 999,
10447
- border: "1px solid hsl(var(--border))",
10448
- color: selectedPreset ? "hsl(var(--foreground))" : "hsl(var(--muted-foreground))",
10449
- bgcolor: selectedPreset ? "hsl(var(--muted) / 0.6)" : "transparent",
10450
- flexShrink: 0,
10451
- transition: "background-color 120ms ease, border-color 120ms ease, box-shadow 120ms ease",
10452
- "&:hover": {
10453
- bgcolor: selectedPreset ? "hsl(var(--muted) / 0.85)" : "hsl(var(--muted))",
10454
- color: "hsl(var(--foreground))",
10455
- borderColor: selectedPreset ? "hsl(var(--muted-foreground) / 0.35)" : "hsl(var(--border))",
10456
- boxShadow: selectedPreset ? "0 1px 4px hsl(var(--background) / 0.35)" : "none"
10457
- }
10458
- },
10459
- children: displayLabel
10707
+ display: "inline-flex",
10708
+ alignItems: "center",
10709
+ gap: "5px",
10710
+ height: variant === "floating" ? 30 : variant === "inline" ? 38 : 32,
10711
+ px: variant === "floating" ? "9px" : "12px",
10712
+ py: 0,
10713
+ borderRadius: 999,
10714
+ border: "1px solid hsl(var(--border))",
10715
+ color: selectedPreset ? "hsl(var(--foreground))" : "hsl(var(--muted-foreground))",
10716
+ bgcolor: selectedPreset ? "hsl(var(--muted) / 0.7)" : "transparent",
10717
+ fontSize: variant === "floating" ? "0.75rem" : "0.78rem",
10718
+ fontWeight: 500,
10719
+ flexShrink: 0,
10720
+ boxSizing: "border-box",
10721
+ cursor: "pointer",
10722
+ transition: "background-color 120ms ease, border-color 120ms ease, box-shadow 120ms ease",
10723
+ "&:hover": {
10724
+ bgcolor: selectedPreset ? "hsl(var(--muted) / 0.9)" : "hsl(var(--muted) / 0.5)",
10725
+ borderColor: selectedPreset ? "hsl(var(--muted-foreground) / 0.35)" : "hsl(var(--border))",
10726
+ boxShadow: selectedPreset ? "0 1px 4px hsl(var(--background) / 0.35)" : "none"
10727
+ }
10728
+ },
10729
+ ...Array.isArray(sx) ? sx : sx ? [sx] : []
10730
+ ],
10731
+ children: [
10732
+ /* @__PURE__ */ jsx23(
10733
+ Box16,
10734
+ {
10735
+ component: "span",
10736
+ sx: {
10737
+ display: "inline-flex",
10738
+ alignItems: "center",
10739
+ justifyContent: "center",
10740
+ flexShrink: 0,
10741
+ color: selectedPreset ? "hsl(var(--primary))" : "inherit",
10742
+ "& svg": {
10743
+ width: variant === "floating" ? 14 : 16,
10744
+ height: variant === "floating" ? 14 : 16
10745
+ }
10746
+ },
10747
+ children: selectedPreset ? selectedPreset.icon ?? void 0 : /* @__PURE__ */ jsx23(Plus2, { size: variant === "floating" ? 12 : 14 })
10748
+ }
10749
+ ),
10750
+ /* @__PURE__ */ jsx23(
10751
+ Typography14,
10752
+ {
10753
+ component: "span",
10754
+ sx: {
10755
+ fontSize: "inherit",
10756
+ fontWeight: "inherit",
10757
+ color: "inherit",
10758
+ lineHeight: 1,
10759
+ whiteSpace: "nowrap",
10760
+ overflow: "hidden",
10761
+ textOverflow: "ellipsis",
10762
+ maxWidth: 150
10763
+ },
10764
+ children: displayLabel
10765
+ }
10766
+ ),
10767
+ selectedPreset && /* @__PURE__ */ jsx23(
10768
+ Box16,
10769
+ {
10770
+ component: "span",
10771
+ role: "button",
10772
+ "aria-label": "Remove skill",
10773
+ onClick: (e) => {
10774
+ e.stopPropagation();
10775
+ onRemoveSelected?.();
10776
+ },
10777
+ sx: {
10778
+ display: "inline-flex",
10779
+ alignItems: "center",
10780
+ justifyContent: "center",
10781
+ ml: "1px",
10782
+ p: "2px",
10783
+ borderRadius: "50%",
10784
+ cursor: "pointer",
10785
+ flexShrink: 0,
10786
+ color: "hsl(var(--muted-foreground))",
10787
+ transition: "background-color 120ms ease, color 120ms ease",
10788
+ "&:hover": {
10789
+ bgcolor: "hsl(var(--foreground) / 0.12)",
10790
+ color: "hsl(var(--foreground))"
10791
+ }
10792
+ },
10793
+ children: /* @__PURE__ */ jsx23(CloseIcon6, { size: variant === "floating" ? 11 : 12 })
10794
+ }
10795
+ )
10796
+ ]
10460
10797
  }
10461
10798
  );
10462
10799
  const [query, setQuery] = useState13("");
@@ -10472,9 +10809,12 @@ var AgentPresets = ({ variant = "default", onSelectPreset, selectedPreset, onRem
10472
10809
  {
10473
10810
  open,
10474
10811
  anchorEl,
10475
- placement: "bottom-end",
10812
+ placement: placement || "bottom-start",
10476
10813
  style: { zIndex: 1400 },
10477
- modifiers: [{ name: "offset", options: { offset: [0, 6] } }],
10814
+ modifiers: [
10815
+ { name: "offset", options: { offset: [0, 6] } },
10816
+ { name: "preventOverflow", options: { padding: 8 } }
10817
+ ],
10478
10818
  children: /* @__PURE__ */ jsx23(ClickAwayListener, { onClickAway: () => {
10479
10819
  setAnchorEl(null);
10480
10820
  setQuery("");
@@ -10712,13 +11052,7 @@ var AgentPresets = ({ variant = "default", onSelectPreset, selectedPreset, onRem
10712
11052
  ) })
10713
11053
  }
10714
11054
  ) : null;
10715
- if (variant === "inline") {
10716
- return /* @__PURE__ */ jsxs17(Fragment9, { children: [
10717
- trigger,
10718
- menu
10719
- ] });
10720
- }
10721
- return /* @__PURE__ */ jsxs17(Box16, { sx: { width: "100%", display: "flex", justifyContent: "flex-end" }, children: [
11055
+ return /* @__PURE__ */ jsxs17(Fragment9, { children: [
10722
11056
  trigger,
10723
11057
  menu
10724
11058
  ] });
@@ -11392,12 +11726,15 @@ var runAgent = async (request) => {
11392
11726
  params.tool_ids = request.toolIds;
11393
11727
  }
11394
11728
  const PRESET_PATHS = {
11395
- "build-workflows": "workflow-edit",
11729
+ "build-workflows": "edit-workflow",
11730
+ "edit-workflow": "edit-workflow",
11396
11731
  "handle-notifications": "handle-notifications",
11397
- "incident-response": "incident-response",
11732
+ "incident-response": "incident-handler",
11733
+ "incident-handler": "incident-handler",
11398
11734
  "host-monitor-control": "computer-use",
11399
11735
  support: "support",
11400
11736
  vulnerability: "vulnerability",
11737
+ "vulnerability-management": "vulnerability",
11401
11738
  detection: "detection"
11402
11739
  };
11403
11740
  const presetSlug = request.presetId ? PRESET_PATHS[request.presetId] : void 0;
@@ -11494,7 +11831,7 @@ var resolveAgentContinuationTargets = async (executionId, authorization) => {
11494
11831
  const resp = await fetch(getApiUrl("/api/v1/streams/results"), {
11495
11832
  method: "POST",
11496
11833
  credentials: "include",
11497
- headers: { "Content-Type": "application/json" },
11834
+ headers: { "Content-Type": "application/json", ...getAuthHeader() },
11498
11835
  body: JSON.stringify({ execution_id: executionId, authorization })
11499
11836
  });
11500
11837
  if (!resp.ok) return empty;
@@ -12811,62 +13148,785 @@ var collectLlmImageAttachments = (root, maxDepth = 10) => {
12811
13148
  return deduped;
12812
13149
  };
12813
13150
 
12814
- // components/AgentUI.tsx
12815
- import { Fragment as Fragment12, jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
12816
- var normalizeMarkdown = (raw) => {
12817
- if (raw == null) return "";
12818
- let s = typeof raw === "string" ? raw : (() => {
12819
- try {
12820
- return JSON.stringify(raw, null, 2);
12821
- } catch {
12822
- return String(raw);
12823
- }
12824
- })();
12825
- if (s.length > 1 && s.startsWith('"') && s.endsWith('"')) {
12826
- try {
12827
- s = JSON.parse(s);
12828
- } catch {
12829
- }
12830
- }
12831
- s = s.replace(/\\r\\n/g, "\n").replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\"/g, '"');
12832
- return s.trim();
12833
- };
12834
- var LAST_PRESET_STORAGE_KEY = "agent_last_preset_id";
12835
- var PRESET_APPS_STORAGE_KEY = "agent_preset_apps_overrides";
12836
- var NO_PRESET_KEY = "__none__";
12837
- var PRESET_TEMPLATE_SLUGS = {
12838
- "build-workflows": "workflow-edit",
12839
- "handle-notifications": "handle-notifications",
12840
- "incident-response": "incident-response",
12841
- "host-monitor-control": "computer-use",
12842
- support: "support",
12843
- vulnerability: "vulnerability",
12844
- detection: "detection"
12845
- };
12846
- var readPresetAppsOverride = (presetId) => {
13151
+ // connectedSourcesService.ts
13152
+ var CACHE_PREFIX = "shuffle:connected_tools:";
13153
+ function getCachedConnectedTools(category) {
13154
+ if (!category) return [];
12847
13155
  try {
12848
- const raw = localStorage.getItem(PRESET_APPS_STORAGE_KEY);
12849
- if (!raw) return null;
13156
+ if (typeof localStorage === "undefined") return [];
13157
+ const raw = localStorage.getItem(`${CACHE_PREFIX}${category}`);
13158
+ if (!raw) return [];
12850
13159
  const parsed = JSON.parse(raw);
12851
- const list = parsed?.[presetId];
12852
- if (!Array.isArray(list)) return null;
12853
- return list.filter((a) => a && typeof a.name === "string");
13160
+ return Array.isArray(parsed) ? parsed : [];
12854
13161
  } catch {
12855
- return null;
13162
+ return [];
12856
13163
  }
12857
- };
12858
- var writePresetAppsOverride = (presetId, apps) => {
13164
+ }
13165
+ function setCachedConnectedTools(category, tools) {
13166
+ if (!category) return;
12859
13167
  try {
12860
- const raw = localStorage.getItem(PRESET_APPS_STORAGE_KEY);
12861
- const parsed = raw ? JSON.parse(raw) : {};
12862
- parsed[presetId] = apps.map((a) => ({ name: a.name, id: a.id, icon: a.icon }));
12863
- localStorage.setItem(PRESET_APPS_STORAGE_KEY, JSON.stringify(parsed));
13168
+ if (typeof localStorage === "undefined") return;
13169
+ localStorage.setItem(`${CACHE_PREFIX}${category}`, JSON.stringify(tools));
12864
13170
  } catch {
12865
13171
  }
12866
- };
12867
- var deepParseJsonStrings3 = (obj, depth = 0) => {
12868
- if (depth > 5) return obj;
12869
- if (typeof obj === "string") {
13172
+ }
13173
+ function mergeConnectedTools(baseApps, connectedTools) {
13174
+ if (!connectedTools || connectedTools.length === 0) return baseApps;
13175
+ const seen = /* @__PURE__ */ new Set();
13176
+ const merged = [];
13177
+ for (const app2 of baseApps) {
13178
+ if (!app2?.name) continue;
13179
+ const norm4 = normalizeAppName(app2.name);
13180
+ if (!seen.has(norm4)) {
13181
+ seen.add(norm4);
13182
+ merged.push(app2);
13183
+ }
13184
+ }
13185
+ for (const app2 of connectedTools) {
13186
+ if (!app2?.name) continue;
13187
+ const norm4 = normalizeAppName(app2.name);
13188
+ if (!seen.has(norm4) && !isIgnoredWorkflowAppName(norm4)) {
13189
+ seen.add(norm4);
13190
+ merged.push(app2);
13191
+ }
13192
+ }
13193
+ return merged;
13194
+ }
13195
+ function resolveConnectedTools(category, authApiResponse = [], workflowsResponse = []) {
13196
+ const tools = [];
13197
+ const seen = /* @__PURE__ */ new Set();
13198
+ const authList = Array.isArray(authApiResponse) ? authApiResponse : authApiResponse?.data || [];
13199
+ const workflows = Array.isArray(workflowsResponse) ? workflowsResponse : workflowsResponse?.workflows || [];
13200
+ const addTool = (name, id, icon) => {
13201
+ if (!name || typeof name !== "string") return;
13202
+ const trimmed = name.trim();
13203
+ if (!trimmed) return;
13204
+ const norm4 = normalizeAppName(trimmed);
13205
+ if (!norm4 || seen.has(norm4) || isIgnoredWorkflowAppName(norm4)) return;
13206
+ seen.add(norm4);
13207
+ tools.push({ name: trimmed, id: id || void 0, icon: icon || void 0 });
13208
+ };
13209
+ const authByName = /* @__PURE__ */ new Map();
13210
+ for (const entry of authList) {
13211
+ const app2 = entry?.app || entry;
13212
+ const rawName = app2?.name;
13213
+ if (!rawName) continue;
13214
+ const norm4 = normalizeAppName(rawName);
13215
+ const isValid = entry?.active === true || entry?.validation?.valid === true || entry?.hasValidAuth === true || app2?.is_valid === true || app2?.tested === true;
13216
+ const img = app2?.large_image || app2?.image_url || app2?.image || entry?.bestImage || "";
13217
+ if (!authByName.has(norm4) || isValid) {
13218
+ authByName.set(norm4, {
13219
+ name: rawName,
13220
+ id: app2?.id || entry?.id,
13221
+ icon: img,
13222
+ active: Boolean(entry?.active),
13223
+ valid: isValid
13224
+ });
13225
+ }
13226
+ }
13227
+ if (category === "incidents") {
13228
+ const ingestWf = findIngestTicketsWorkflow(workflows);
13229
+ const ingestAppNames = ingestWf ? extractWorkflowAppNames(ingestWf) : /* @__PURE__ */ new Set();
13230
+ const forwardWf = findForwardTicketsWorkflow(workflows);
13231
+ const forwardAppNames = forwardWf ? extractWorkflowAppNames(forwardWf) : /* @__PURE__ */ new Set();
13232
+ ingestAppNames.forEach((norm4) => {
13233
+ const auth = authByName.get(norm4);
13234
+ if (auth) {
13235
+ addTool(auth.name, auth.id, auth.icon);
13236
+ } else {
13237
+ const formatted = norm4.split("_").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
13238
+ addTool(formatted);
13239
+ }
13240
+ });
13241
+ forwardAppNames.forEach((norm4) => {
13242
+ const auth = authByName.get(norm4);
13243
+ if (auth) {
13244
+ addTool(auth.name, auth.id, auth.icon);
13245
+ } else {
13246
+ const formatted = norm4.split("_").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
13247
+ addTool(formatted);
13248
+ }
13249
+ });
13250
+ for (const [norm4, auth] of authByName.entries()) {
13251
+ if (!auth.valid && !auth.active) continue;
13252
+ const isSiem = SIEM_PATTERNS.some((p) => norm4.includes(p));
13253
+ const isEdr = EDR_PATTERNS.some((p) => norm4.includes(p));
13254
+ const isEmail = EMAIL_APP_PATTERNS.some((p) => norm4.includes(p));
13255
+ const isCases = CASES_PATTERNS.some((p) => norm4.includes(p));
13256
+ const isComms = COMMUNICATION_PATTERNS_NAMES.some((p) => norm4.includes(p));
13257
+ if (isSiem || isEdr || isEmail || isCases || isComms) {
13258
+ addTool(auth.name, auth.id, auth.icon);
13259
+ }
13260
+ }
13261
+ } else if (category === "vulnerabilities") {
13262
+ const ingestVulnWf = workflows.find(
13263
+ (w) => typeof w?.name === "string" && (w.name === "Ingest Vulnerabilities" || w.name.toLowerCase().includes("ingest vulnerabilit"))
13264
+ );
13265
+ const vulnAppNames = ingestVulnWf ? extractWorkflowAppNames(ingestVulnWf) : /* @__PURE__ */ new Set();
13266
+ vulnAppNames.forEach((norm4) => {
13267
+ const auth = authByName.get(norm4);
13268
+ if (auth) {
13269
+ addTool(auth.name, auth.id, auth.icon);
13270
+ } else {
13271
+ const formatted = norm4.split("_").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
13272
+ addTool(formatted);
13273
+ }
13274
+ });
13275
+ for (const [norm4, auth] of authByName.entries()) {
13276
+ if (!auth.valid && !auth.active) continue;
13277
+ const isScanner = isVulnScannerApp(auth.name) || VULN_SCANNER_PATTERNS.some((p) => norm4.includes(p));
13278
+ if (isScanner) {
13279
+ addTool(auth.name, auth.id, auth.icon);
13280
+ }
13281
+ }
13282
+ }
13283
+ return tools;
13284
+ }
13285
+
13286
+ // agentContextRegistry.ts
13287
+ var STORAGE_PREFIX = "shuffle_agent_context_choice_";
13288
+ var matchRoutePattern = (pattern, pathname) => {
13289
+ const normPattern = pattern.replace(/\/+$/, "") || "/";
13290
+ const normPath = pathname.replace(/\/+$/, "") || "/";
13291
+ if (normPattern === normPath) return {};
13292
+ const patternSegments = normPattern.split("/");
13293
+ const pathSegments = normPath.split("/");
13294
+ if (patternSegments.length !== pathSegments.length) {
13295
+ if (patternSegments[patternSegments.length - 1] === "*" && pathSegments.length >= patternSegments.length - 1) {
13296
+ const params2 = {};
13297
+ for (let i = 0; i < patternSegments.length - 1; i++) {
13298
+ if (patternSegments[i].startsWith(":")) {
13299
+ params2[patternSegments[i].slice(1)] = decodeURIComponent(pathSegments[i]);
13300
+ } else if (patternSegments[i] !== pathSegments[i]) {
13301
+ return null;
13302
+ }
13303
+ }
13304
+ params2["*"] = pathSegments.slice(patternSegments.length - 1).join("/");
13305
+ return params2;
13306
+ }
13307
+ return null;
13308
+ }
13309
+ const params = {};
13310
+ for (let i = 0; i < patternSegments.length; i++) {
13311
+ const pSeg = patternSegments[i];
13312
+ const uSeg = pathSegments[i];
13313
+ if (pSeg.startsWith(":")) {
13314
+ params[pSeg.slice(1)] = decodeURIComponent(uSeg);
13315
+ } else if (pSeg !== uSeg) {
13316
+ return null;
13317
+ }
13318
+ }
13319
+ return params;
13320
+ };
13321
+ var isAgentRoute = (pathname) => {
13322
+ const norm4 = pathname.toLowerCase().replace(/\/+$/, "") || "/";
13323
+ return norm4 === "/agents" || norm4 === "/agent" || norm4.startsWith("/agents/") || norm4.startsWith("/agent/");
13324
+ };
13325
+ var getActivePageEntityName = () => {
13326
+ if (typeof document === "undefined") return void 0;
13327
+ try {
13328
+ const titleInput = document.querySelector(
13329
+ '[data-incident-field="title"] input, [data-case-field="title"] input, [data-ticket-field="title"] input, [data-alert-field="title"] input, [data-host-field="name"] input, [data-monitor-field="name"] input, [data-asset-field="name"] input, [data-software-field="name"] input, [data-package-field="name"] input'
13330
+ );
13331
+ if (titleInput?.value && titleInput.value.trim().length > 0) {
13332
+ return titleInput.value.trim();
13333
+ }
13334
+ const heading = document.querySelector("h1, h2, [data-entity-title]");
13335
+ if (heading?.textContent && heading.textContent.trim().length > 0 && heading.textContent.trim().length < 90) {
13336
+ return heading.textContent.trim();
13337
+ }
13338
+ } catch {
13339
+ }
13340
+ return void 0;
13341
+ };
13342
+ var DEFAULT_AGENT_CONTEXT_RULES = [
13343
+ // ==========================================
13344
+ // 1. Incidents, Cases, Tickets, Alerts (Grouped)
13345
+ // ==========================================
13346
+ // Specific Incident Detail
13347
+ {
13348
+ id: "incident-detail",
13349
+ match: "/incidents/:id",
13350
+ defaultApps: [{ name: "shuffle_incidents" }],
13351
+ defaultPresetId: "incident-response",
13352
+ sourceCategory: "incidents",
13353
+ title: (params) => {
13354
+ const entity = getActivePageEntityName();
13355
+ return entity ? `How can we help handle incident "${entity}"?` : `How can we help handle incident #${params.id}?`;
13356
+ },
13357
+ subtitle: () => "Shuffle Incidents MCP",
13358
+ defaultPrompt: (params) => `Investigate incident ${params.id} and recommend next steps: `,
13359
+ placeholder: "Ask about this incident, triage observables, or correlate...",
13360
+ getStorageKey: (params) => `incident_${params.id}`,
13361
+ description: "Focused on the currently viewed incident with Shuffle Incidents MCP"
13362
+ },
13363
+ // Simplified Incident Detail
13364
+ {
13365
+ id: "incident-simple-detail",
13366
+ match: "/incidents-simple/:id",
13367
+ defaultApps: [{ name: "shuffle_incidents" }],
13368
+ defaultPresetId: "incident-response",
13369
+ sourceCategory: "incidents",
13370
+ title: (params) => {
13371
+ const entity = getActivePageEntityName();
13372
+ return entity ? `How can we help handle incident "${entity}"?` : `How can we help handle incident #${params.id}?`;
13373
+ },
13374
+ subtitle: () => "Shuffle Incidents MCP",
13375
+ defaultPrompt: (params) => `Investigate incident ${params.id} and recommend next steps: `,
13376
+ placeholder: "Ask about this incident, triage observables, or correlate...",
13377
+ getStorageKey: (params) => `incident_${params.id}`,
13378
+ description: "Focused on the currently viewed incident with Shuffle Incidents MCP"
13379
+ },
13380
+ // Specific Case Detail
13381
+ {
13382
+ id: "case-detail",
13383
+ match: "/cases/:id",
13384
+ defaultApps: [{ name: "shuffle_incidents" }],
13385
+ defaultPresetId: "incident-response",
13386
+ sourceCategory: "incidents",
13387
+ title: (params) => {
13388
+ const entity = getActivePageEntityName();
13389
+ return entity ? `How can we help handle case "${entity}"?` : `How can we help handle case #${params.id}?`;
13390
+ },
13391
+ subtitle: () => "Shuffle Incidents MCP",
13392
+ defaultPrompt: (params) => `Investigate case ${params.id} and recommend next steps: `,
13393
+ placeholder: "Review case evidence, correlate events, or recommend response actions...",
13394
+ getStorageKey: (params) => `case_${params.id}`,
13395
+ description: "Focused on the currently viewed case with Shuffle Incidents MCP"
13396
+ },
13397
+ // Specific Ticket Detail
13398
+ {
13399
+ id: "ticket-detail",
13400
+ match: "/tickets/:id",
13401
+ defaultApps: [{ name: "shuffle_incidents" }],
13402
+ defaultPresetId: "incident-response",
13403
+ sourceCategory: "incidents",
13404
+ title: (params) => {
13405
+ const entity = getActivePageEntityName();
13406
+ return entity ? `How can we help handle ticket "${entity}"?` : `How can we help handle ticket #${params.id}?`;
13407
+ },
13408
+ subtitle: () => "Shuffle Incidents MCP",
13409
+ defaultPrompt: (params) => `Investigate ticket ${params.id} and recommend next steps: `,
13410
+ placeholder: "Investigate ticket, draft reply, or correlate related incidents...",
13411
+ getStorageKey: (params) => `ticket_${params.id}`,
13412
+ description: "Focused on the currently viewed ticket with Shuffle Incidents MCP"
13413
+ },
13414
+ // Specific Alert Detail
13415
+ {
13416
+ id: "alert-detail",
13417
+ match: "/alerts/:id",
13418
+ defaultApps: [{ name: "shuffle_incidents" }],
13419
+ defaultPresetId: "incident-response",
13420
+ sourceCategory: "incidents",
13421
+ title: (params) => {
13422
+ const entity = getActivePageEntityName();
13423
+ return entity ? `How can we help handle alert "${entity}"?` : `How can we help handle alert #${params.id}?`;
13424
+ },
13425
+ subtitle: () => "Shuffle Incidents MCP",
13426
+ defaultPrompt: (params) => `Investigate alert ${params.id} and recommend next steps: `,
13427
+ placeholder: "Analyze alert telemetry, assess false positive probability, or escalate...",
13428
+ getStorageKey: (params) => `alert_${params.id}`,
13429
+ description: "Focused on the currently viewed alert with Shuffle Incidents MCP"
13430
+ },
13431
+ // Incidents Overview & Subpages (/incidents/*)
13432
+ {
13433
+ id: "incidents-group",
13434
+ match: (pathname) => pathname.startsWith("/incidents") || pathname.startsWith("/incidents-simple"),
13435
+ defaultApps: [{ name: "shuffle_incidents" }],
13436
+ defaultPresetId: "incident-response",
13437
+ sourceCategory: "incidents",
13438
+ title: "How can we help handle incidents?",
13439
+ subtitle: "Shuffle Incidents MCP",
13440
+ defaultPrompt: "Investigate this incident and recommend next steps: ",
13441
+ placeholder: "Triage incidents, correlate alerts, or search threat intelligence...",
13442
+ getStorageKey: () => "incidents_list",
13443
+ description: "Incidents overview with Shuffle Incidents MCP"
13444
+ },
13445
+ // Cases Overview & Subpages (/cases/*)
13446
+ {
13447
+ id: "cases-group",
13448
+ match: (pathname) => pathname.startsWith("/cases"),
13449
+ defaultApps: [{ name: "shuffle_incidents" }],
13450
+ defaultPresetId: "incident-response",
13451
+ sourceCategory: "incidents",
13452
+ title: "How can we help handle cases?",
13453
+ subtitle: "Shuffle Incidents MCP",
13454
+ defaultPrompt: "Investigate this case and recommend next steps: ",
13455
+ placeholder: "Review active cases, correlate investigations, or log evidence...",
13456
+ getStorageKey: () => "cases_list",
13457
+ description: "Cases overview with Shuffle Incidents MCP"
13458
+ },
13459
+ // Tickets Overview & Subpages (/tickets/*)
13460
+ {
13461
+ id: "tickets-group",
13462
+ match: (pathname) => pathname.startsWith("/tickets"),
13463
+ defaultApps: [{ name: "shuffle_incidents" }],
13464
+ defaultPresetId: "incident-response",
13465
+ sourceCategory: "incidents",
13466
+ title: "How can we help handle tickets?",
13467
+ subtitle: "Shuffle Incidents MCP",
13468
+ defaultPrompt: "Investigate this ticket and recommend next steps: ",
13469
+ placeholder: "Triage incoming tickets, automate assignments, or resolve issues...",
13470
+ getStorageKey: () => "tickets_list",
13471
+ description: "Tickets overview with Shuffle Incidents MCP"
13472
+ },
13473
+ // Alerts Overview & Subpages (/alerts/*, /notifications/*)
13474
+ {
13475
+ id: "alerts-group",
13476
+ match: (pathname) => pathname.startsWith("/alerts") || pathname.startsWith("/notifications"),
13477
+ defaultApps: [{ name: "shuffle_incidents" }],
13478
+ defaultPresetId: "incident-response",
13479
+ sourceCategory: "incidents",
13480
+ title: "How can we help handle alerts?",
13481
+ subtitle: "Shuffle Incidents MCP",
13482
+ defaultPrompt: "Investigate this alert and recommend next steps: ",
13483
+ placeholder: "Triage incoming security alerts, filter noise, or escalate to incident...",
13484
+ getStorageKey: () => "alerts_list",
13485
+ description: "Alert and notification triage with Shuffle Incidents MCP"
13486
+ },
13487
+ // ==========================================
13488
+ // 2. Vulnerabilities (shuffle_vulnerabilities, shuffle_assets, shuffle_software, shuffle_packages)
13489
+ // ==========================================
13490
+ // Specific Vulnerability Detail
13491
+ {
13492
+ id: "vulnerability-detail",
13493
+ match: "/vulnerabilities/:id",
13494
+ defaultApps: [
13495
+ { name: "shuffle_vulnerabilities" },
13496
+ { name: "shuffle_assets" },
13497
+ { name: "shuffle_software" },
13498
+ { name: "shuffle_packages" }
13499
+ ],
13500
+ defaultPresetId: "vulnerability",
13501
+ sourceCategory: "vulnerabilities",
13502
+ title: (params) => {
13503
+ const entity = getActivePageEntityName();
13504
+ return entity ? `How can we help with ${entity}?` : `How can we help with vulnerability ${params.id}?`;
13505
+ },
13506
+ subtitle: () => "Shuffle Vulnerabilities, Assets, Software & Packages",
13507
+ defaultPrompt: (params) => `Review vulnerability ${params.id} and draft remediation plan: `,
13508
+ placeholder: "Analyze this CVE, check affected hosts, and draft remediation...",
13509
+ getStorageKey: (params) => `vulnerability_${params.id}`,
13510
+ description: "Focused on the selected vulnerability with Shuffle Vulnerabilities, Assets, Software & Packages"
13511
+ },
13512
+ // Vulnerabilities List & Subpages
13513
+ {
13514
+ id: "vulnerabilities-list",
13515
+ match: (pathname) => pathname.startsWith("/vulnerabilities"),
13516
+ defaultApps: [
13517
+ { name: "shuffle_vulnerabilities" },
13518
+ { name: "shuffle_assets" },
13519
+ { name: "shuffle_software" },
13520
+ { name: "shuffle_packages" }
13521
+ ],
13522
+ defaultPresetId: "vulnerability",
13523
+ sourceCategory: "vulnerabilities",
13524
+ title: "How can we help review vulnerabilities?",
13525
+ subtitle: () => "Shuffle Vulnerabilities, Assets, Software & Packages",
13526
+ defaultPrompt: "Review my current vulnerabilities and prioritize them by ",
13527
+ placeholder: "Review CVEs, prioritize by exploitability, or draft patch workflows...",
13528
+ getStorageKey: () => "vulnerabilities_list",
13529
+ description: "Vulnerabilities overview with Shuffle Vulnerabilities, Assets, Software & Packages"
13530
+ },
13531
+ // ==========================================
13532
+ // 3. Monitors & Computer Use (shuffle_host_monitors for all)
13533
+ // ==========================================
13534
+ // Specific Host Terminal (/monitors/:id/terminal)
13535
+ {
13536
+ id: "monitor-terminal-detail",
13537
+ match: "/monitors/:id/terminal",
13538
+ defaultApps: [{ name: "shuffle_host_monitors" }],
13539
+ defaultPresetId: "host-monitor-control",
13540
+ title: (params) => {
13541
+ const entity = getActivePageEntityName();
13542
+ return entity ? `How can we help in terminal for "${entity}"?` : `How can we help in terminal on host #${params.id}?`;
13543
+ },
13544
+ subtitle: () => "Shuffle Host Monitors MCP",
13545
+ defaultPrompt: (params) => `Run commands on host ${params.id} to `,
13546
+ placeholder: "Ask the agent to execute shell commands, inspect logs, or debug...",
13547
+ getStorageKey: (params) => `monitor_terminal_${params.id}`,
13548
+ description: "Interactive terminal control with Shuffle Host Monitors MCP"
13549
+ },
13550
+ // General Host Terminal (/monitors/terminal)
13551
+ {
13552
+ id: "monitor-terminal",
13553
+ match: "/monitors/terminal",
13554
+ defaultApps: [{ name: "shuffle_host_monitors" }],
13555
+ defaultPresetId: "host-monitor-control",
13556
+ title: "How can we help in the host terminal?",
13557
+ subtitle: "Shuffle Host Monitors MCP",
13558
+ defaultPrompt: "Run terminal commands on this host to ",
13559
+ placeholder: "Ask the agent to execute shell commands, inspect files, or debug...",
13560
+ getStorageKey: () => "monitors_terminal",
13561
+ description: "Interactive terminal control with Shuffle Host Monitors MCP"
13562
+ },
13563
+ // Host Response Actions (/monitors/response)
13564
+ {
13565
+ id: "monitor-response",
13566
+ match: "/monitors/response",
13567
+ defaultApps: [{ name: "shuffle_host_monitors" }],
13568
+ defaultPresetId: "host-monitor-control",
13569
+ title: "How can we help with host response?",
13570
+ subtitle: "Shuffle Host Monitors MCP",
13571
+ defaultPrompt: "Take response actions on this host to ",
13572
+ placeholder: "Isolate host, terminate suspicious processes, or run remediation...",
13573
+ getStorageKey: () => "monitors_response",
13574
+ description: "Host response actions with Shuffle Host Monitors MCP"
13575
+ },
13576
+ // Specific Host Overview (/monitors/:id)
13577
+ {
13578
+ id: "monitor-detail",
13579
+ match: "/monitors/:id",
13580
+ defaultApps: [{ name: "shuffle_host_monitors" }],
13581
+ defaultPresetId: "host-monitor-control",
13582
+ title: (params) => {
13583
+ const entity = getActivePageEntityName();
13584
+ return entity ? `How can we help with host "${entity}"?` : `How can we help with host #${params.id}?`;
13585
+ },
13586
+ subtitle: () => "Shuffle Host Monitors MCP",
13587
+ defaultPrompt: (params) => `Take control of host ${params.id} and help me with: `,
13588
+ placeholder: "Inspect host telemetry, running processes, network connections, or remediate...",
13589
+ getStorageKey: (params) => `monitor_${params.id}`,
13590
+ description: "Host detail view with Shuffle Host Monitors MCP"
13591
+ },
13592
+ // Monitors Fleet Overview & Subpages (/monitors, /monitors/*)
13593
+ {
13594
+ id: "host-monitors-group",
13595
+ match: (pathname) => pathname.startsWith("/monitors"),
13596
+ defaultApps: [{ name: "shuffle_host_monitors" }],
13597
+ defaultPresetId: "host-monitor-control",
13598
+ title: "How can we help with host monitors?",
13599
+ subtitle: "Shuffle Host Monitors MCP",
13600
+ defaultPrompt: "Take control of this host and help me with: ",
13601
+ placeholder: "Ask the agent to run terminal commands, inspect files, or remediate...",
13602
+ getStorageKey: () => "host_monitors",
13603
+ description: "Computer use and host monitors control with Shuffle Host Monitors MCP"
13604
+ },
13605
+ // ==========================================
13606
+ // 4. Workflows & Automations
13607
+ // ==========================================
13608
+ // Specific Workflow Detail (/workflows/:id)
13609
+ {
13610
+ id: "workflow-detail",
13611
+ match: "/workflows/:id",
13612
+ defaultApps: [{ name: "shuffle_workflows_builder" }, { name: "shuffle_apps" }],
13613
+ defaultPresetId: "build-workflows",
13614
+ title: (params) => {
13615
+ const entity = getActivePageEntityName();
13616
+ return entity ? `How can we help edit "${entity}"?` : `How can we help edit workflow #${params.id}?`;
13617
+ },
13618
+ subtitle: () => "Shuffle Workflows Builder & Shuffle Apps",
13619
+ defaultPrompt: (params) => `Edit workflow ${params.id} to `,
13620
+ placeholder: "Describe the changes, new actions, or logic to add...",
13621
+ getStorageKey: (params) => `workflow_${params.id}`,
13622
+ description: "Focused on editing the selected workflow with Shuffle Workflows Builder and Shuffle Apps"
13623
+ },
13624
+ // Workflows Overview & Subpages (/workflows, /workflows/*)
13625
+ {
13626
+ id: "workflows-group",
13627
+ match: (pathname) => pathname === "/workflows" || pathname.startsWith("/workflows") || pathname.startsWith("/infrastructure/flows"),
13628
+ defaultApps: [{ name: "shuffle_workflows_builder" }, { name: "shuffle_apps" }],
13629
+ defaultPresetId: "build-workflows",
13630
+ title: "How can we help edit workflows?",
13631
+ subtitle: "Shuffle Workflows Builder & Shuffle Apps",
13632
+ defaultPrompt: "Edit this Shuffle workflow to ",
13633
+ placeholder: "Describe the workflow you want to build or edit...",
13634
+ getStorageKey: () => "workflows_builder",
13635
+ description: "Workflow builder with Shuffle Workflows Builder and Shuffle Apps"
13636
+ },
13637
+ // ==========================================
13638
+ // 5. Assets, Software & Packages
13639
+ // ==========================================
13640
+ // Specific Asset Tab (/assets/:tab)
13641
+ {
13642
+ id: "assets-tab",
13643
+ match: "/assets/:tab",
13644
+ defaultApps: [{ name: "shuffle_assets" }, { name: "shuffle_vulnerabilities" }],
13645
+ defaultPresetId: "vulnerability",
13646
+ sourceCategory: "vulnerabilities",
13647
+ title: (params) => {
13648
+ const entity = getActivePageEntityName();
13649
+ if (entity) return `How can we help with "${entity}"?`;
13650
+ const tabName = (params.tab || "assets").replace(/[-_]+/g, " ");
13651
+ return `How can we help with ${tabName}?`;
13652
+ },
13653
+ subtitle: () => "Shuffle Assets & Shuffle Vulnerabilities",
13654
+ defaultPrompt: (params) => `Inspect ${params.tab || "assets"} and review vulnerabilities: `,
13655
+ placeholder: "Search assets, inspect hosts, or check security posture...",
13656
+ getStorageKey: (params) => `assets_tab_${params.tab}`,
13657
+ description: "Assets tab view with Shuffle Assets and Shuffle Vulnerabilities MCPs"
13658
+ },
13659
+ // Assets Overview (/assets, /assets/*)
13660
+ {
13661
+ id: "assets-overview",
13662
+ match: (pathname) => pathname === "/assets" || pathname.startsWith("/assets"),
13663
+ defaultApps: [{ name: "shuffle_assets" }, { name: "shuffle_vulnerabilities" }],
13664
+ defaultPresetId: "vulnerability",
13665
+ sourceCategory: "vulnerabilities",
13666
+ title: "How can we help with assets?",
13667
+ subtitle: "Shuffle Assets & Shuffle Vulnerabilities",
13668
+ defaultPrompt: "Audit assets and review vulnerabilities for ",
13669
+ placeholder: "Search assets, inspect hosts, or check security posture...",
13670
+ getStorageKey: () => "assets_overview",
13671
+ description: "Assets overview with Shuffle Assets and Shuffle Vulnerabilities MCPs"
13672
+ },
13673
+ // Software Inventory (/software, /software/*)
13674
+ {
13675
+ id: "software-inventory",
13676
+ match: (pathname) => pathname === "/software" || pathname.startsWith("/software"),
13677
+ defaultApps: [{ name: "shuffle_software" }, { name: "shuffle_vulnerabilities" }],
13678
+ defaultPresetId: "vulnerability",
13679
+ sourceCategory: "vulnerabilities",
13680
+ title: (params) => {
13681
+ const entity = getActivePageEntityName();
13682
+ return entity ? `How can we help with "${entity}"?` : "How can we help with software inventory?";
13683
+ },
13684
+ subtitle: () => "Shuffle Software & Shuffle Vulnerabilities",
13685
+ defaultPrompt: "Inspect software inventory and check for vulnerabilities in ",
13686
+ placeholder: "Search installed software, verify versions, or scan for CVEs...",
13687
+ getStorageKey: () => "software_inventory",
13688
+ description: "Software inventory with Shuffle Software and Shuffle Vulnerabilities MCPs"
13689
+ },
13690
+ // Packages Inventory (/packages, /packages/*)
13691
+ {
13692
+ id: "packages-inventory",
13693
+ match: (pathname) => pathname === "/packages" || pathname.startsWith("/packages"),
13694
+ defaultApps: [{ name: "shuffle_packages" }, { name: "shuffle_vulnerabilities" }],
13695
+ defaultPresetId: "vulnerability",
13696
+ sourceCategory: "vulnerabilities",
13697
+ title: (params) => {
13698
+ const entity = getActivePageEntityName();
13699
+ return entity ? `How can we help with "${entity}"?` : "How can we help with packages?";
13700
+ },
13701
+ subtitle: () => "Shuffle Packages & Shuffle Vulnerabilities",
13702
+ defaultPrompt: "Analyze package dependencies and known vulnerabilities for ",
13703
+ placeholder: "Search package dependencies, verify licenses, or check CVEs...",
13704
+ getStorageKey: () => "packages_inventory",
13705
+ description: "Package dependencies with Shuffle Packages and Shuffle Vulnerabilities MCPs"
13706
+ },
13707
+ // ==========================================
13708
+ // 6. Detection & Sigma
13709
+ // ==========================================
13710
+ {
13711
+ id: "detection",
13712
+ match: (pathname) => pathname.startsWith("/detection"),
13713
+ defaultApps: [{ name: "shuffle_detection" }],
13714
+ defaultPresetId: "detection",
13715
+ title: "How can we help tune detections?",
13716
+ subtitle: "Shuffle Detection MCP",
13717
+ defaultPrompt: "Modify my detections to ",
13718
+ placeholder: "Create Sigma rules, tune detection pipelines, or filter false positives...",
13719
+ getStorageKey: () => "detection",
13720
+ description: "Detection engineering with Shuffle Detection MCP"
13721
+ },
13722
+ // ==========================================
13723
+ // 7. Documentation (/docs, /docs/*)
13724
+ // ==========================================
13725
+ {
13726
+ id: "docs",
13727
+ match: (pathname) => pathname === "/docs" || pathname.startsWith("/docs/"),
13728
+ defaultApps: [{ name: "shuffle_tools" }],
13729
+ defaultPresetId: "support",
13730
+ title: "How can we help with documentation?",
13731
+ subtitle: "Documentation & Knowledge Assistant",
13732
+ defaultPrompt: "Help me understand or find information about ",
13733
+ placeholder: "Ask questions about Shuffle features, guides, or API...",
13734
+ getStorageKey: (params, pathname) => `docs_${pathname.replace(/[^a-zA-Z0-9_-]/g, "_")}`,
13735
+ description: "Documentation assistant for Shuffle guides, features, and API references",
13736
+ sideshift: true
13737
+ },
13738
+ // ==========================================
13739
+ // 8. Default Fallback (Support)
13740
+ // ==========================================
13741
+ {
13742
+ id: "default",
13743
+ match: () => true,
13744
+ defaultApps: [{ name: "shuffle_tools" }],
13745
+ defaultPresetId: "support",
13746
+ title: "How can we help on this page?",
13747
+ subtitle: "General Platform Assistant",
13748
+ defaultPrompt: "Help me with the following on this page: ",
13749
+ placeholder: "Ask anything about Shuffle, integrations, or workflows...",
13750
+ getStorageKey: (params, pathname) => `page_${pathname.replace(/[^a-zA-Z0-9_-]/g, "_")}`,
13751
+ description: "General support agent for the platform",
13752
+ missingConfig: true
13753
+ }
13754
+ ];
13755
+ var customRuleRegistry = [];
13756
+ var registerAgentContextRule = (rule, prepend = true) => {
13757
+ if (prepend) {
13758
+ customRuleRegistry.unshift(rule);
13759
+ } else {
13760
+ customRuleRegistry.push(rule);
13761
+ }
13762
+ return () => {
13763
+ const idx = customRuleRegistry.indexOf(rule);
13764
+ if (idx !== -1) customRuleRegistry.splice(idx, 1);
13765
+ };
13766
+ };
13767
+ var getAgentContextRules = (customRules) => {
13768
+ return [...customRules ?? [], ...customRuleRegistry, ...DEFAULT_AGENT_CONTEXT_RULES];
13769
+ };
13770
+ var getPageContextChoice = (storageKey) => {
13771
+ try {
13772
+ const raw = localStorage.getItem(`${STORAGE_PREFIX}${storageKey}`);
13773
+ if (!raw) return null;
13774
+ return JSON.parse(raw);
13775
+ } catch {
13776
+ return null;
13777
+ }
13778
+ };
13779
+ var setPageContextChoice = (storageKey, choice) => {
13780
+ try {
13781
+ const existing = getPageContextChoice(storageKey) || { updatedAt: Date.now() };
13782
+ const payload = {
13783
+ ...existing,
13784
+ ...choice,
13785
+ updatedAt: Date.now()
13786
+ };
13787
+ localStorage.setItem(`${STORAGE_PREFIX}${storageKey}`, JSON.stringify(payload));
13788
+ } catch {
13789
+ }
13790
+ };
13791
+ var clearPageContextChoice = (storageKey) => {
13792
+ try {
13793
+ localStorage.removeItem(`${STORAGE_PREFIX}${storageKey}`);
13794
+ } catch {
13795
+ }
13796
+ };
13797
+ var resolveAgentContext = (pathname, search = "", customRules) => {
13798
+ const normPath = pathname.replace(/\/+$/, "") || "/";
13799
+ const searchParams = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
13800
+ const rules = getAgentContextRules(customRules);
13801
+ let matchedRule = null;
13802
+ let matchedParams = {};
13803
+ for (const rule of rules) {
13804
+ if (typeof rule.match === "string") {
13805
+ const params = matchRoutePattern(rule.match, normPath);
13806
+ if (params !== null) {
13807
+ matchedRule = rule;
13808
+ matchedParams = params;
13809
+ break;
13810
+ }
13811
+ } else if (rule.match instanceof RegExp) {
13812
+ if (rule.match.test(normPath)) {
13813
+ matchedRule = rule;
13814
+ break;
13815
+ }
13816
+ } else if (typeof rule.match === "function") {
13817
+ const res = rule.match(normPath, searchParams);
13818
+ if (res) {
13819
+ matchedRule = rule;
13820
+ if (typeof res === "object") {
13821
+ matchedParams = res;
13822
+ }
13823
+ break;
13824
+ }
13825
+ }
13826
+ }
13827
+ if (!matchedRule) {
13828
+ matchedRule = DEFAULT_AGENT_CONTEXT_RULES[DEFAULT_AGENT_CONTEXT_RULES.length - 1];
13829
+ }
13830
+ const storageKey = matchedRule.getStorageKey ? matchedRule.getStorageKey(matchedParams, normPath) : matchedRule.id;
13831
+ const savedChoice = getPageContextChoice(storageKey);
13832
+ const isOverridden = !!savedChoice && (savedChoice.apps !== void 0 || savedChoice.presetId !== void 0);
13833
+ const cachedConnected = matchedRule.sourceCategory ? getCachedConnectedTools(matchedRule.sourceCategory) : [];
13834
+ const baseDefaultApps = mergeConnectedTools(matchedRule.defaultApps, cachedConnected);
13835
+ const effectiveApps = savedChoice?.apps ?? baseDefaultApps;
13836
+ const effectivePresetId = savedChoice?.presetId !== void 0 ? savedChoice.presetId ?? void 0 : matchedRule.defaultPresetId;
13837
+ const title = typeof matchedRule.title === "function" ? matchedRule.title(matchedParams, normPath) : matchedRule.title ?? "Agent";
13838
+ const subtitle = typeof matchedRule.subtitle === "function" ? matchedRule.subtitle(matchedParams, normPath) : matchedRule.subtitle ?? "Context aware assistant";
13839
+ const defaultPrompt = typeof matchedRule.defaultPrompt === "function" ? matchedRule.defaultPrompt(matchedParams, normPath) : matchedRule.defaultPrompt ?? "";
13840
+ const missingConfig = Boolean(matchedRule.missingConfig ?? matchedRule.id === "default");
13841
+ return {
13842
+ ruleId: matchedRule.id,
13843
+ apps: effectiveApps,
13844
+ presetId: effectivePresetId,
13845
+ title,
13846
+ subtitle,
13847
+ defaultPrompt,
13848
+ placeholder: matchedRule.placeholder,
13849
+ storageKey,
13850
+ params: matchedParams,
13851
+ pathname: normPath,
13852
+ sourceCategory: matchedRule.sourceCategory,
13853
+ isOverridden,
13854
+ originalDefaultApps: baseDefaultApps,
13855
+ originalDefaultPresetId: matchedRule.defaultPresetId,
13856
+ missingConfig,
13857
+ sideshift: matchedRule.sideshift
13858
+ };
13859
+ };
13860
+
13861
+ // components/AgentUI.tsx
13862
+ import { Fragment as Fragment12, jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
13863
+ var normalizeMarkdown = (raw) => {
13864
+ if (raw == null) return "";
13865
+ let s = typeof raw === "string" ? raw : (() => {
13866
+ try {
13867
+ return JSON.stringify(raw, null, 2);
13868
+ } catch {
13869
+ return String(raw);
13870
+ }
13871
+ })();
13872
+ if (s.length > 1 && s.startsWith('"') && s.endsWith('"')) {
13873
+ try {
13874
+ s = JSON.parse(s);
13875
+ } catch {
13876
+ }
13877
+ }
13878
+ s = s.replace(/\\r\\n/g, "\n").replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\"/g, '"');
13879
+ return s.trim();
13880
+ };
13881
+ var LAST_PRESET_STORAGE_KEY = "agent_last_preset_id";
13882
+ var PRESET_APPS_STORAGE_KEY = "agent_preset_apps_overrides";
13883
+ var NO_PRESET_KEY = "__none__";
13884
+ var PRESET_TEMPLATE_SLUGS = {
13885
+ "build-workflows": "edit-workflow",
13886
+ "handle-notifications": "handle-notifications",
13887
+ "incident-response": "incident-handler",
13888
+ "host-monitor-control": "computer-use",
13889
+ support: "support",
13890
+ vulnerability: "vulnerability",
13891
+ detection: "detection"
13892
+ };
13893
+ var TEMPLATE_SLUG_TO_PRESET_ID = {
13894
+ "workflow-edit": "build-workflows",
13895
+ "edit-workflow": "build-workflows",
13896
+ "build-workflows": "build-workflows",
13897
+ "incident-response": "incident-response",
13898
+ "incident-handler": "incident-response",
13899
+ "vulnerability": "vulnerability",
13900
+ "vulnerability-management": "vulnerability",
13901
+ "computer-use": "host-monitor-control",
13902
+ support: "support",
13903
+ "handle-notifications": "handle-notifications",
13904
+ detection: "detection"
13905
+ };
13906
+ var readPresetAppsOverride = (presetId) => {
13907
+ try {
13908
+ const raw = localStorage.getItem(PRESET_APPS_STORAGE_KEY);
13909
+ if (!raw) return null;
13910
+ const parsed = JSON.parse(raw);
13911
+ const list = parsed?.[presetId];
13912
+ if (!Array.isArray(list)) return null;
13913
+ return list.filter((a) => a && typeof a.name === "string");
13914
+ } catch {
13915
+ return null;
13916
+ }
13917
+ };
13918
+ var writePresetAppsOverride = (presetId, apps) => {
13919
+ try {
13920
+ const raw = localStorage.getItem(PRESET_APPS_STORAGE_KEY);
13921
+ const parsed = raw ? JSON.parse(raw) : {};
13922
+ parsed[presetId] = apps.map((a) => ({ name: a.name, id: a.id, icon: a.icon }));
13923
+ localStorage.setItem(PRESET_APPS_STORAGE_KEY, JSON.stringify(parsed));
13924
+ } catch {
13925
+ }
13926
+ };
13927
+ var deepParseJsonStrings3 = (obj, depth = 0) => {
13928
+ if (depth > 5) return obj;
13929
+ if (typeof obj === "string") {
12870
13930
  const trimmed = obj.trim();
12871
13931
  if (trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]")) {
12872
13932
  try {
@@ -13974,6 +15034,7 @@ var AgentUI = ({
13974
15034
  heroIconSize = 84,
13975
15035
  maxWidth = 850,
13976
15036
  compact = false,
15037
+ mobileView,
13977
15038
  hideAppPicker = false,
13978
15039
  hideAttach = false,
13979
15040
  disableStartTab = false,
@@ -14008,10 +15069,14 @@ var AgentUI = ({
14008
15069
  userId,
14009
15070
  hidePresets = false,
14010
15071
  presets,
15072
+ initialPresetId,
14011
15073
  onSelectPreset,
15074
+ contextCategory,
15075
+ contextStorageKey,
14012
15076
  isSupport,
14013
15077
  presetCtas
14014
15078
  }) => {
15079
+ const isEffectiveSupport = isSupport !== void 0 ? isSupport : isSupportUser();
14015
15080
  const resolveUrl2 = useCallback10(
14016
15081
  (path) => apiBaseUrl ? `${apiBaseUrl.replace(/\/+$/, "")}${path}` : getApiUrl(path),
14017
15082
  [apiBaseUrl]
@@ -14022,7 +15087,8 @@ var AgentUI = ({
14022
15087
  return h;
14023
15088
  }, [apiKey, orgId]);
14024
15089
  const hasApiKey = !!apiKey || !!API_CONFIG.apiKey;
14025
- const isPhone = useMediaQuery("(max-width:600px)", { noSsr: true });
15090
+ const isPhoneScreen = useMediaQuery("(max-width:600px)", { noSsr: true });
15091
+ const isPhone = mobileView !== void 0 ? mobileView : isPhoneScreen;
14026
15092
  const navigate = useNavigate();
14027
15093
  const [actionInput, setActionInput] = useState18(defaultInput);
14028
15094
  const { prompt: savedPromptPrefix } = useAgentPromptPrefix({ userId, persist: !disableStartTab });
@@ -14058,27 +15124,32 @@ var AgentUI = ({
14058
15124
  const inputRef = useRef11(null);
14059
15125
  const seededPresetIdRef = useRef11(null);
14060
15126
  useEffect17(() => {
14061
- if (defaultInput && defaultInput.trim().length > 0) {
15127
+ if (!initialPresetId && defaultInput && defaultInput.trim().length > 0) {
14062
15128
  setSelectedPreset(null);
14063
15129
  return;
14064
15130
  }
14065
15131
  try {
14066
- const lastId = localStorage.getItem(LAST_PRESET_STORAGE_KEY);
14067
- if (!lastId) return;
14068
- const list = filterAgentPresets(presets && presets.length > 0 ? presets : AGENT_PRESETS, isSupport);
15132
+ const lastId = initialPresetId !== void 0 ? initialPresetId : localStorage.getItem(LAST_PRESET_STORAGE_KEY);
15133
+ if (!lastId) {
15134
+ if (initialPresetId === null) setSelectedPreset(null);
15135
+ return;
15136
+ }
15137
+ const list = filterAgentPresets(presets && presets.length > 0 ? presets : AGENT_PRESETS, isEffectiveSupport);
14069
15138
  const match = list.find((p) => p.id === lastId);
14070
15139
  if (!match || match.enabled === false) return;
14071
15140
  setSelectedPreset(match);
14072
- const override = readPresetAppsOverride(match.id);
14073
- if (override) {
14074
- setChosenApps(override);
14075
- } else if (match.defaultApps && match.defaultApps.length > 0) {
14076
- setChosenApps(match.defaultApps.map((app2) => ({ name: app2.name, id: app2.id, icon: app2.icon })));
15141
+ if (!defaultApps && !apps) {
15142
+ const override = readPresetAppsOverride(match.id);
15143
+ if (override) {
15144
+ setChosenApps(override);
15145
+ } else if (match.defaultApps && match.defaultApps.length > 0) {
15146
+ setChosenApps(match.defaultApps.map((app2) => ({ name: app2.name, id: app2.id, icon: app2.icon })));
15147
+ }
14077
15148
  }
14078
15149
  seededPresetIdRef.current = match.id;
14079
15150
  } catch {
14080
15151
  }
14081
- }, [presets, defaultInput, isSupport]);
15152
+ }, [presets, defaultInput, isEffectiveSupport, initialPresetId, defaultApps, apps]);
14082
15153
  useLayoutEffect(() => {
14083
15154
  if (hidePresets) {
14084
15155
  setPresetsChipWidth(0);
@@ -14303,6 +15374,40 @@ var AgentUI = ({
14303
15374
  [agentData]
14304
15375
  );
14305
15376
  const [showStarter, setShowStarter] = useState18(true);
15377
+ const handleRemovePreset = useCallback10(() => {
15378
+ try {
15379
+ localStorage.removeItem(LAST_PRESET_STORAGE_KEY);
15380
+ } catch {
15381
+ }
15382
+ setSelectedPreset(null);
15383
+ }, []);
15384
+ const handleSelectPresetInternal = useCallback10((preset) => {
15385
+ try {
15386
+ localStorage.setItem(LAST_PRESET_STORAGE_KEY, preset.id);
15387
+ } catch {
15388
+ }
15389
+ const override = readPresetAppsOverride(preset.id);
15390
+ if (override && override.length > 0) {
15391
+ setChosenApps(override);
15392
+ } else if (preset.defaultApps && preset.defaultApps.length > 0) {
15393
+ setChosenApps(preset.defaultApps.map((app2) => ({ name: app2.name, id: app2.id, icon: app2.icon })));
15394
+ } else {
15395
+ setChosenApps([]);
15396
+ }
15397
+ seededPresetIdRef.current = preset.id;
15398
+ if (onSelectPreset) {
15399
+ onSelectPreset(preset);
15400
+ return;
15401
+ }
15402
+ setSelectedPreset(preset);
15403
+ setTimeout(() => {
15404
+ const el = inputRef.current;
15405
+ try {
15406
+ el?.focus();
15407
+ } catch {
15408
+ }
15409
+ }, 0);
15410
+ }, [onSelectPreset]);
14306
15411
  const [scheduleAnchor, setScheduleAnchor] = useState18(null);
14307
15412
  const [mobilePlusAnchor, setMobilePlusAnchor] = useState18(null);
14308
15413
  const [scheduleCron, setScheduleCron] = useState18("0 * * * *");
@@ -14360,7 +15465,7 @@ var AgentUI = ({
14360
15465
  }, [viewMode]);
14361
15466
  const [attachedImages, setAttachedImages] = useState18([]);
14362
15467
  const [previewImage, setPreviewImage] = useState18(null);
14363
- const promptMultiline = promptMultilineBase || attachedImages.length > 0;
15468
+ const promptMultiline = promptMultilineBase || attachedImages.length > 0 || isPhone && Boolean(selectedPreset);
14364
15469
  const promptSingleLineLocked = !promptMultiline;
14365
15470
  const [nowTick, setNowTick] = useState18(() => Math.floor(Date.now() / 1e3));
14366
15471
  const [localRunStart, setLocalRunStart] = useState18(null);
@@ -14614,11 +15719,18 @@ var AgentUI = ({
14614
15719
  const loadAuthenticatedApps = useCallback10(async (signal) => {
14615
15720
  setAuthAppsLoading(true);
14616
15721
  try {
14617
- const resp = await fetch(resolveUrl2("/api/v1/apps/authentication"), {
14618
- credentials: "include",
14619
- headers: { ...resolveHeaders2() }
14620
- });
14621
- if (!resp.ok) {
15722
+ const [authRes, wfRes] = await Promise.allSettled([
15723
+ fetch(resolveUrl2("/api/v1/apps/authentication"), {
15724
+ credentials: "include",
15725
+ headers: { ...resolveHeaders2() }
15726
+ }),
15727
+ fetch(resolveUrl2("/api/v1/workflows"), {
15728
+ credentials: "include",
15729
+ headers: { ...resolveHeaders2() }
15730
+ })
15731
+ ]);
15732
+ const resp = authRes.status === "fulfilled" ? authRes.value : null;
15733
+ if (!resp || !resp.ok) {
14622
15734
  if (!signal?.cancelled) setAvailableApps([]);
14623
15735
  return;
14624
15736
  }
@@ -14643,18 +15755,59 @@ var AgentUI = ({
14643
15755
  }
14644
15756
  if (signal?.cancelled) return;
14645
15757
  setAvailableApps(loaded);
14646
- setDetectedLLM(resolveActiveLLMProvider(list));
14647
- } catch {
14648
- } finally {
14649
- if (!signal?.cancelled) setAuthAppsLoading(false);
14650
- }
14651
- }, [resolveUrl2, resolveHeaders2]);
14652
- useEffect17(() => {
14653
- if (!autoLoadApps) return;
14654
- if (!hasApiKey) return;
14655
- const signal = { cancelled: false };
14656
- loadAuthenticatedApps(signal);
14657
- return () => {
15758
+ const wfResp = wfRes.status === "fulfilled" ? wfRes.value : null;
15759
+ const wfResult = wfResp && wfResp.ok ? await wfResp.json() : [];
15760
+ const effectiveCategory = contextCategory || ((defaultApps || chosenApps).some((a) => normalizeAgentAppName(a.name || "").includes("incident")) ? "incidents" : (defaultApps || chosenApps).some((a) => normalizeAgentAppName(a.name || "").includes("vulnerabilit")) ? "vulnerabilities" : void 0);
15761
+ let connectedTools = [];
15762
+ if (effectiveCategory) {
15763
+ connectedTools = resolveConnectedTools(effectiveCategory, list, wfResult);
15764
+ if (connectedTools.length > 0) {
15765
+ setCachedConnectedTools(effectiveCategory, connectedTools);
15766
+ }
15767
+ }
15768
+ setChosenApps((prev) => {
15769
+ let changed = false;
15770
+ const savedChoice = contextStorageKey ? getPageContextChoice(contextStorageKey) : null;
15771
+ let baseList = prev;
15772
+ if (!savedChoice?.apps && connectedTools.length > 0) {
15773
+ const merged = mergeConnectedTools(prev, connectedTools);
15774
+ if (merged.length !== prev.length || merged.some((m, idx) => prev[idx]?.name !== m.name)) {
15775
+ baseList = merged;
15776
+ changed = true;
15777
+ }
15778
+ }
15779
+ const updated = baseList.map((app2) => {
15780
+ if (app2.icon && app2.id) return app2;
15781
+ const slug = normalizeAgentAppName(app2.name || "");
15782
+ const match = loaded.find((a) => normalizeAgentAppName(a.name || "") === slug);
15783
+ if (!match) return app2;
15784
+ if (!app2.icon && match.icon || !app2.id && match.id) {
15785
+ changed = true;
15786
+ return {
15787
+ ...app2,
15788
+ id: app2.id || match.id,
15789
+ icon: app2.icon || match.icon
15790
+ };
15791
+ }
15792
+ return app2;
15793
+ });
15794
+ if (changed && onAppsChange) {
15795
+ onAppsChange(updated);
15796
+ }
15797
+ return changed ? updated : prev;
15798
+ });
15799
+ setDetectedLLM(resolveActiveLLMProvider(list));
15800
+ } catch {
15801
+ } finally {
15802
+ if (!signal?.cancelled) setAuthAppsLoading(false);
15803
+ }
15804
+ }, [resolveUrl2, resolveHeaders2, contextCategory, contextStorageKey, defaultApps, onAppsChange]);
15805
+ useEffect17(() => {
15806
+ if (!autoLoadApps) return;
15807
+ if (!hasApiKey) return;
15808
+ const signal = { cancelled: false };
15809
+ loadAuthenticatedApps(signal);
15810
+ return () => {
14658
15811
  signal.cancelled = true;
14659
15812
  };
14660
15813
  }, [autoLoadApps, hasApiKey, loadAuthenticatedApps]);
@@ -15253,7 +16406,9 @@ var AgentUI = ({
15253
16406
  if (!raw) return null;
15254
16407
  const slug = String(raw).trim().toLowerCase();
15255
16408
  const list = presets && presets.length > 0 ? presets : AGENT_PRESETS;
15256
- return list.find((p) => p.id === slug || PRESET_TEMPLATE_SLUGS[p.id] === slug) ?? null;
16409
+ return list.find(
16410
+ (p) => p.id === slug || PRESET_TEMPLATE_SLUGS[p.id] === slug || TEMPLATE_SLUG_TO_PRESET_ID[slug] === p.id
16411
+ ) ?? null;
15257
16412
  }, [agentData, agentActionResult, execution, presets]);
15258
16413
  const rerunAgent = useCallback10(() => {
15259
16414
  const resolved = resolveRunInput();
@@ -16000,14 +17155,13 @@ var AgentUI = ({
16000
17155
  gap: 1,
16001
17156
  width: isPhone ? "100%" : "fit-content",
16002
17157
  alignSelf: "center",
16003
- position: isPhone ? "fixed" : "sticky",
17158
+ position: "sticky",
16004
17159
  top: isPhone ? 0 : 8,
16005
- left: isPhone ? 0 : "auto",
16006
- right: isPhone ? 0 : "auto",
16007
- zIndex: isPhone ? 1300 : 5,
17160
+ left: "auto",
17161
+ right: "auto",
17162
+ zIndex: isPhone ? 20 : 5,
16008
17163
  bgcolor: isPhone ? "hsl(var(--background))" : "hsl(var(--card))",
16009
17164
  borderRadius: isPhone ? 0 : 9999,
16010
- borderBottom: isPhone ? "1px solid hsl(var(--border))" : "none",
16011
17165
  boxShadow: isPhone ? "0 4px 16px rgba(0,0,0,0.12)" : "none",
16012
17166
  px: isPhone ? 1 : 0,
16013
17167
  py: isPhone ? 1 : 0
@@ -16460,7 +17614,7 @@ var AgentUI = ({
16460
17614
  ]
16461
17615
  }
16462
17616
  );
16463
- const postRunDiscovery = Boolean(postRunScheduleHint) && !scheduleDisabledReason || postRunAppReqs.length > 0 || postRunUnauthedApps.length > 0 ? /* @__PURE__ */ jsxs22(
17617
+ const postRunDiscovery = isEffectiveSupport && (Boolean(postRunScheduleHint) && !scheduleDisabledReason || postRunAppReqs.length > 0 || postRunUnauthedApps.length > 0) ? /* @__PURE__ */ jsxs22(
16464
17618
  Box20,
16465
17619
  {
16466
17620
  sx: {
@@ -16474,7 +17628,47 @@ var AgentUI = ({
16474
17628
  bgcolor: "hsl(var(--muted) / 0.35)"
16475
17629
  },
16476
17630
  children: [
16477
- /* @__PURE__ */ jsx28(Typography17, { sx: { fontSize: "0.78rem", color: "hsl(var(--muted-foreground))", mr: 0.5 }, children: "Set this up to run on its own" }),
17631
+ /* @__PURE__ */ jsx28(
17632
+ Tooltip13,
17633
+ {
17634
+ title: "Visible to support users only \u2014 this helps guide us towards things working better over time.",
17635
+ arrow: true,
17636
+ children: /* @__PURE__ */ jsxs22(
17637
+ Box20,
17638
+ {
17639
+ sx: {
17640
+ display: "inline-flex",
17641
+ alignItems: "center",
17642
+ gap: 0.75,
17643
+ mr: 0.5,
17644
+ cursor: "help"
17645
+ },
17646
+ children: [
17647
+ /* @__PURE__ */ jsx28(Typography17, { sx: { fontSize: "0.78rem", color: "hsl(var(--muted-foreground))" }, children: "Set this up to run on its own" }),
17648
+ /* @__PURE__ */ jsx28(
17649
+ Box20,
17650
+ {
17651
+ component: "span",
17652
+ sx: {
17653
+ fontSize: "0.64rem",
17654
+ fontWeight: 600,
17655
+ textTransform: "uppercase",
17656
+ letterSpacing: "0.04em",
17657
+ px: 0.75,
17658
+ py: 0.15,
17659
+ borderRadius: "4px",
17660
+ bgcolor: "hsl(var(--muted))",
17661
+ color: "hsl(var(--muted-foreground))",
17662
+ border: "1px solid hsl(var(--border))"
17663
+ },
17664
+ children: "Support only"
17665
+ }
17666
+ )
17667
+ ]
17668
+ }
17669
+ )
17670
+ }
17671
+ ),
16478
17672
  postRunScheduleHint && !scheduleDisabledReason && /* @__PURE__ */ jsx28(Tooltip13, { title: `Detected schedule: ${postRunScheduleHint.label}. Click to review and save.`, arrow: true, children: /* @__PURE__ */ jsxs22(
16479
17673
  Box20,
16480
17674
  {
@@ -16569,22 +17763,46 @@ var AgentUI = ({
16569
17763
  ) : null;
16570
17764
  const mobilePlusCanSchedule = (hasExecution || showStarter) && !scheduleDisabledReason && !disableSchedule && (actionInput || "").trim().length >= 1;
16571
17765
  const mobilePlusButton = isPhone ? /* @__PURE__ */ jsx28(
16572
- IconButton10,
17766
+ Tooltip13,
16573
17767
  {
16574
- type: "button",
16575
- "aria-label": "Skills, schedule and attachments",
16576
- onClick: (e) => setMobilePlusAnchor(e.currentTarget),
17768
+ title: selectedPreset ? `Skill: ${selectedPreset.label} (click to change)` : "Add skill, schedule, or attachments",
17769
+ arrow: true,
17770
+ children: /* @__PURE__ */ jsx28(
17771
+ IconButton10,
17772
+ {
17773
+ type: "button",
17774
+ "aria-label": "Skills, schedule and attachments",
17775
+ onClick: (e) => setMobilePlusAnchor(e.currentTarget),
17776
+ sx: {
17777
+ width: 32,
17778
+ height: 32,
17779
+ flexShrink: 0,
17780
+ alignSelf: "center",
17781
+ border: "1px solid hsl(var(--border))",
17782
+ color: selectedPreset ? "hsl(var(--foreground))" : "hsl(var(--muted-foreground))",
17783
+ bgcolor: selectedPreset ? "hsl(var(--muted))" : "transparent",
17784
+ "&:hover": { bgcolor: "hsl(var(--muted))", color: "hsl(var(--foreground))" }
17785
+ },
17786
+ children: /* @__PURE__ */ jsx28(PlusIcon2, { size: 16 })
17787
+ }
17788
+ )
17789
+ }
17790
+ ) : null;
17791
+ const mobileSkillChip = isPhone && selectedPreset && !hidePresets ? /* @__PURE__ */ jsx28(
17792
+ AgentPresets_default,
17793
+ {
17794
+ variant: "floating",
17795
+ chipRef: presetsChipRef,
17796
+ presets,
17797
+ isSupport: isEffectiveSupport,
17798
+ selectedPreset,
17799
+ onRemoveSelected: handleRemovePreset,
17800
+ onSelectPreset: handleSelectPresetInternal,
17801
+ placement: "bottom-start",
16577
17802
  sx: {
16578
- width: 32,
16579
17803
  height: 32,
16580
- flexShrink: 0,
16581
- alignSelf: "flex-start",
16582
- border: "1px solid hsl(var(--border))",
16583
- color: selectedPreset ? "hsl(var(--foreground))" : "hsl(var(--muted-foreground))",
16584
- bgcolor: selectedPreset ? "hsl(var(--muted))" : "transparent",
16585
- "&:hover": { bgcolor: "hsl(var(--muted))", color: "hsl(var(--foreground))" }
16586
- },
16587
- children: selectedPreset?.icon ?? /* @__PURE__ */ jsx28(PlusIcon2, { size: 16 })
17804
+ alignSelf: "center"
17805
+ }
16588
17806
  }
16589
17807
  ) : null;
16590
17808
  const mobilePlusMenu = isPhone ? /* @__PURE__ */ jsx28(
@@ -16644,7 +17862,7 @@ var AgentUI = ({
16644
17862
  ]
16645
17863
  }
16646
17864
  ),
16647
- /* @__PURE__ */ jsxs22(
17865
+ !disableSchedule && /* @__PURE__ */ jsxs22(
16648
17866
  MenuItem2,
16649
17867
  {
16650
17868
  disabled: !mobilePlusCanSchedule || agentRequestLoading,
@@ -16707,8 +17925,7 @@ var AgentUI = ({
16707
17925
  ...Array.isArray(contentSx) ? contentSx : contentSx ? [contentSx] : []
16708
17926
  ],
16709
17927
  children: [
16710
- (showRunSwitcher || isPhone) && tabBar,
16711
- isPhone && /* @__PURE__ */ jsx28(Box20, { sx: { height: 52, flexShrink: 0, flexGrow: 0 } }),
17928
+ showRunSwitcher && tabBar,
16712
17929
  schedulePopover,
16713
17930
  mobilePlusMenu,
16714
17931
  showStarter ? /* @__PURE__ */ jsxs22(
@@ -16726,7 +17943,7 @@ var AgentUI = ({
16726
17943
  gap: isPhone ? 1.5 : compact ? 2 : 3,
16727
17944
  py: isPhone ? 1 : compact ? 2 : 4,
16728
17945
  width: "100%",
16729
- ...isPhone ? { flex: 1, justifyContent: "center" } : {}
17946
+ ...isPhone ? { flex: 1, justifyContent: "center", marginTop: compact ? "-16px" : "-50px" } : {}
16730
17947
  },
16731
17948
  children: [
16732
17949
  !hideHeroIcon && !compact && !isPhone && /* @__PURE__ */ jsx28(Box20, { sx: {
@@ -16740,13 +17957,13 @@ var AgentUI = ({
16740
17957
  justifyContent: "center",
16741
17958
  boxShadow: "0 8px 24px rgba(0,0,0,0.25)"
16742
17959
  }, children: heroIcon ?? /* @__PURE__ */ jsx28(AgentIcon_default, { size: Math.round(heroIconSize * 0.67) }) }),
16743
- /* @__PURE__ */ jsx28(Typography17, { component: "h1", sx: {
16744
- fontSize: compact ? { xs: "1.1rem", md: "1.5rem" } : { xs: "1.35rem", md: "2.25rem" },
17960
+ title ? /* @__PURE__ */ jsx28(Typography17, { component: "h1", sx: {
17961
+ fontSize: isPhone ? "1.35rem" : compact ? { xs: "1.1rem", md: "1.5rem" } : { xs: "1.35rem", md: "2.25rem" },
16745
17962
  fontWeight: 600,
16746
17963
  color: "hsl(var(--foreground))",
16747
17964
  textAlign: "center",
16748
17965
  letterSpacing: "-0.01em"
16749
- }, children: title }),
17966
+ }, children: title }) : null,
16750
17967
  subtitle && /* @__PURE__ */ jsx28(Typography17, { sx: {
16751
17968
  fontSize: { xs: "0.8rem", sm: "0.95rem" },
16752
17969
  color: "hsl(var(--muted-foreground))",
@@ -16761,11 +17978,11 @@ var AgentUI = ({
16761
17978
  gap: 0.5,
16762
17979
  // Keep the same radius in both states so growing to multiple
16763
17980
  // lines does not visually snap from a pill to a boxy card.
16764
- borderRadius: "28px",
17981
+ borderRadius: isPhone ? promptMultiline ? "20px" : "28px" : "28px",
16765
17982
  border: "1.5px solid hsl(var(--border))",
16766
17983
  bgcolor: "hsl(var(--card))",
16767
- px: isPhone ? 1 : 2.25,
16768
- py: 1,
17984
+ px: isPhone ? 1.5 : 2.25,
17985
+ py: isPhone ? promptMultiline ? 1.25 : 1 : 1,
16769
17986
  boxSizing: "border-box",
16770
17987
  // A one-line prompt is a fixed-size control. Lock all three
16771
17988
  // dimensions so TextareaAutosize cannot retain a stale
@@ -16798,7 +18015,10 @@ var AgentUI = ({
16798
18015
  maxHeight: "33px"
16799
18016
  } : {}
16800
18017
  }, children: [
16801
- isPhone && !promptMultiline && mobilePlusButton,
18018
+ isPhone && !promptMultiline && /* @__PURE__ */ jsxs22(Box20, { sx: { display: "inline-flex", alignItems: "center", gap: 0.5, flexShrink: 0 }, children: [
18019
+ mobilePlusButton,
18020
+ mobileSkillChip
18021
+ ] }),
16802
18022
  /* @__PURE__ */ jsx28(
16803
18023
  InputBase2,
16804
18024
  {
@@ -16908,9 +18128,8 @@ var AgentUI = ({
16908
18128
  ref: chipOverlayRef,
16909
18129
  "data-static": promptMultiline ? "1" : "0",
16910
18130
  sx: isPhone ? {
16911
- // Mobile: the skill chip lives inside the "+" menu. The
16912
- // trigger stays mounted (invisible) so the menu can still
16913
- // be opened programmatically and anchored correctly.
18131
+ // Mobile: when no preset is selected, keep an invisible trigger mounted
18132
+ // so the "+" menu can programmatically open the skills picker.
16914
18133
  position: "absolute",
16915
18134
  left: 0,
16916
18135
  bottom: 0,
@@ -16962,48 +18181,16 @@ var AgentUI = ({
16962
18181
  to: { transform: "translateY(0)", opacity: 1 }
16963
18182
  }
16964
18183
  },
16965
- children: /* @__PURE__ */ jsx28(
18184
+ children: (!isPhone || !selectedPreset) && /* @__PURE__ */ jsx28(
16966
18185
  AgentPresets_default,
16967
18186
  {
16968
18187
  variant: "floating",
16969
- chipRef: presetsChipRef,
18188
+ chipRef: !isPhone || !selectedPreset ? presetsChipRef : void 0,
16970
18189
  presets,
16971
- isSupport,
18190
+ isSupport: isEffectiveSupport,
16972
18191
  selectedPreset,
16973
- onRemoveSelected: () => {
16974
- try {
16975
- localStorage.removeItem(LAST_PRESET_STORAGE_KEY);
16976
- } catch {
16977
- }
16978
- setSelectedPreset(null);
16979
- },
16980
- onSelectPreset: (preset) => {
16981
- try {
16982
- localStorage.setItem(LAST_PRESET_STORAGE_KEY, preset.id);
16983
- } catch {
16984
- }
16985
- const override = readPresetAppsOverride(preset.id);
16986
- if (override && override.length > 0) {
16987
- setChosenApps(override);
16988
- } else if (preset.defaultApps && preset.defaultApps.length > 0) {
16989
- setChosenApps(preset.defaultApps.map((app2) => ({ name: app2.name, id: app2.id, icon: app2.icon })));
16990
- } else {
16991
- setChosenApps([]);
16992
- }
16993
- seededPresetIdRef.current = preset.id;
16994
- if (onSelectPreset) {
16995
- onSelectPreset(preset);
16996
- return;
16997
- }
16998
- setSelectedPreset(preset);
16999
- setTimeout(() => {
17000
- const el = inputRef.current;
17001
- try {
17002
- el?.focus();
17003
- } catch {
17004
- }
17005
- }, 0);
17006
- }
18192
+ onRemoveSelected: handleRemovePreset,
18193
+ onSelectPreset: handleSelectPresetInternal
17007
18194
  }
17008
18195
  )
17009
18196
  }
@@ -17041,7 +18228,10 @@ var AgentUI = ({
17041
18228
  /* @__PURE__ */ jsx28(Typography17, { sx: { fontSize: "0.7rem", color: "hsl(var(--foreground))", maxWidth: 140, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: img.name }),
17042
18229
  /* @__PURE__ */ jsx28(IconButton10, { size: "small", onClick: () => setAttachedImages((prev) => prev.filter((_, i) => i !== idx)), sx: { p: 0.125, color: "hsl(var(--muted-foreground))", "&:hover": { color: "hsl(var(--destructive))" } }, "aria-label": "Remove attached image", children: /* @__PURE__ */ jsx28(CloseIcon7, { size: 11 }) })
17043
18230
  ] }, `${img.name}-${idx}`)) }),
17044
- isPhone && promptMultiline && mobilePlusButton,
18231
+ isPhone && promptMultiline && /* @__PURE__ */ jsxs22(Box20, { sx: { display: "inline-flex", alignItems: "center", gap: 0.5, flexShrink: 0, minWidth: 0, maxWidth: "calc(100% - 60px)" }, children: [
18232
+ mobilePlusButton,
18233
+ mobileSkillChip
18234
+ ] }),
17045
18235
  /* @__PURE__ */ jsxs22(Box20, { sx: {
17046
18236
  display: "flex",
17047
18237
  alignItems: "center",
@@ -17429,7 +18619,7 @@ var AgentUI = ({
17429
18619
  ]
17430
18620
  }
17431
18621
  ) }),
17432
- /* @__PURE__ */ jsx28(
18622
+ !hideChooseLLM && /* @__PURE__ */ jsx28(
17433
18623
  Box20,
17434
18624
  {
17435
18625
  component: "span",
@@ -17506,15 +18696,18 @@ var AgentUI = ({
17506
18696
  "&:hover": !agentRequestLoading ? { bgcolor: needsAuth ? "hsl(var(--severity-medium) / 0.18)" : "hsl(var(--muted) / 0.9)" } : {}
17507
18697
  },
17508
18698
  children: [
17509
- /* @__PURE__ */ jsx28(
17510
- Avatar7,
17511
- {
17512
- src: app2.icon || void 0,
17513
- alt: app2.name,
17514
- variant: "rounded",
17515
- sx: { width: 18, height: 18, bgcolor: "transparent" }
17516
- }
17517
- ),
18699
+ (() => {
18700
+ const appIcon = app2.icon || availableApps.find((a) => normalizeAgentAppName(a.name || "") === slug)?.icon || resolvedToolApps[slug]?.icon;
18701
+ return /* @__PURE__ */ jsx28(Box20, { sx: { display: "inline-flex", alignItems: "center", justifyContent: "center", width: 18, height: 18, flexShrink: 0 }, children: /* @__PURE__ */ jsx28(
18702
+ AppFallbackIcon,
18703
+ {
18704
+ name: app2.name,
18705
+ imageUrl: appIcon,
18706
+ size: 18,
18707
+ style: { borderRadius: 3, objectFit: "contain" }
18708
+ }
18709
+ ) });
18710
+ })(),
17518
18711
  !isPhone && /* @__PURE__ */ jsx28(Typography17, { sx: { fontSize: "0.8rem", mx: 0.25, textTransform: "capitalize" }, children: app2.name.replace(/_/g, " ") }),
17519
18712
  needsAuth && /* @__PURE__ */ jsx28(WarningIcon, { size: 14, color: "hsl(var(--severity-medium))", style: { marginRight: 2 } }),
17520
18713
  isRequired ? /* @__PURE__ */ jsx28(
@@ -17679,21 +18872,38 @@ var AgentUI = ({
17679
18872
  const hasAllowed = Array.isArray(agentData?.allowed_actions) && agentData.allowed_actions.length > 0;
17680
18873
  const list = hasAllowed ? executionApps : chosenApps;
17681
18874
  return list;
17682
- })().map((app2, i) => /* @__PURE__ */ jsx28(Tooltip13, { title: (app2.name || "").replace(/_/g, " "), children: /* @__PURE__ */ jsx28(
17683
- Avatar7,
17684
- {
17685
- src: app2.icon || void 0,
17686
- alt: app2.name,
17687
- variant: "rounded",
17688
- onClick: () => setAuthDrawerApp({ name: app2.name, id: app2.id || null }),
17689
- sx: {
17690
- bgcolor: "hsl(var(--muted))",
17691
- cursor: "pointer",
17692
- transition: "transform 0.15s ease, border-color 0.15s ease",
17693
- "&:hover": { transform: "scale(1.08)", borderColor: "hsl(var(--primary)) !important" }
18875
+ })().map((app2, i) => {
18876
+ const slug = normalizeAgentAppName(app2.name || "");
18877
+ const appIcon = app2.icon || availableApps.find((a) => normalizeAgentAppName(a.name || "") === slug)?.icon || resolvedToolApps[slug]?.icon;
18878
+ return /* @__PURE__ */ jsx28(Tooltip13, { title: (app2.name || "").replace(/_/g, " "), children: /* @__PURE__ */ jsx28(
18879
+ Box20,
18880
+ {
18881
+ onClick: () => setAuthDrawerApp({ name: app2.name, id: app2.id || null }),
18882
+ sx: {
18883
+ display: "inline-flex",
18884
+ alignItems: "center",
18885
+ justifyContent: "center",
18886
+ width: 24,
18887
+ height: 24,
18888
+ borderRadius: "6px",
18889
+ overflow: "hidden",
18890
+ bgcolor: "hsl(var(--muted))",
18891
+ cursor: "pointer",
18892
+ transition: "transform 0.15s ease, border-color 0.15s ease",
18893
+ "&:hover": { transform: "scale(1.08)", borderColor: "hsl(var(--primary)) !important" }
18894
+ },
18895
+ children: /* @__PURE__ */ jsx28(
18896
+ AppFallbackIcon,
18897
+ {
18898
+ name: app2.name,
18899
+ imageUrl: appIcon,
18900
+ size: 24,
18901
+ style: { borderRadius: 6, objectFit: "contain" }
18902
+ }
18903
+ )
17694
18904
  }
17695
- }
17696
- ) }, i)) }),
18905
+ ) }, i);
18906
+ }) }),
17697
18907
  /* @__PURE__ */ jsxs22(Box20, { sx: { flex: 1, minWidth: 0 }, children: [
17698
18908
  /* @__PURE__ */ jsx28(Typography17, { sx: { fontSize: "0.85rem", color: "hsl(var(--foreground))", fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: agentData?.original_input || actionInput || "Agent run" }),
17699
18909
  /* @__PURE__ */ jsxs22(Typography17, { sx: { fontSize: "0.7rem", color: "hsl(var(--muted-foreground))" }, children: [
@@ -20995,6 +22205,7 @@ var AgentExecutionDrawer = ({
20995
22205
  bodySx,
20996
22206
  topBanner,
20997
22207
  onSchedule,
22208
+ isSupport,
20998
22209
  theme,
20999
22210
  colorMode
21000
22211
  }) => {
@@ -21171,6 +22382,7 @@ var AgentExecutionDrawer = ({
21171
22382
  apiBaseUrl,
21172
22383
  orgId,
21173
22384
  onSchedule,
22385
+ isSupport,
21174
22386
  theme,
21175
22387
  colorMode
21176
22388
  },
@@ -21453,6 +22665,7 @@ var AgentsView = ({
21453
22665
  onSchedule: effectiveSchedule,
21454
22666
  apiKey,
21455
22667
  orgId,
22668
+ isSupport: userdata?.support === true || userdata?.support === "true",
21456
22669
  theme: resolvedTheme,
21457
22670
  colorMode
21458
22671
  }
@@ -21855,22 +23068,942 @@ var AddAppModal = ({ open, onClose, initialQuery, categoryLabel }) => {
21855
23068
  };
21856
23069
  var AddAppModal_default = AddAppModal;
21857
23070
 
23071
+ // components/AskAiButton.tsx
23072
+ import { Box as Box28, ButtonBase as ButtonBase2, Tooltip as Tooltip19, Typography as Typography25 } from "@mui/material";
23073
+ import { jsx as jsx36, jsxs as jsxs30 } from "react/jsx-runtime";
23074
+ var AskAiButton = ({
23075
+ onClick,
23076
+ isOpen = false,
23077
+ isSupport,
23078
+ requireSupport = true,
23079
+ pathname,
23080
+ label = "Ask AI",
23081
+ tagLabel = "Support only",
23082
+ contextHint,
23083
+ tooltipTitle,
23084
+ sx,
23085
+ hideWhenOpen = true
23086
+ }) => {
23087
+ const themeScope = useShuffleMcpTheme();
23088
+ const currentPath = pathname !== void 0 ? pathname : typeof window !== "undefined" ? window.location.pathname : "";
23089
+ if (isAgentRoute(currentPath)) {
23090
+ return null;
23091
+ }
23092
+ const isEffectiveSupport = isSupport !== void 0 ? isSupport : isSupportUser();
23093
+ if (requireSupport && !isEffectiveSupport) {
23094
+ return null;
23095
+ }
23096
+ if (hideWhenOpen && isOpen) {
23097
+ return null;
23098
+ }
23099
+ const effectiveTooltip = tooltipTitle !== void 0 ? tooltipTitle : contextHint ? `Ask AI (${contextHint})` : "Ask AI \u2022 Context-aware assistant";
23100
+ return /* @__PURE__ */ jsx36(
23101
+ Box28,
23102
+ {
23103
+ className: themeScope?.scopeClassName,
23104
+ sx: {
23105
+ position: "fixed",
23106
+ bottom: "calc(24px + env(safe-area-inset-bottom, 0px))",
23107
+ right: "calc(24px + env(safe-area-inset-right, 0px))",
23108
+ zIndex: 1250
23109
+ },
23110
+ children: /* @__PURE__ */ jsx36(Tooltip19, { title: effectiveTooltip, arrow: true, placement: "top-end", children: /* @__PURE__ */ jsxs30(
23111
+ ButtonBase2,
23112
+ {
23113
+ onClick,
23114
+ focusRipple: true,
23115
+ "aria-label": `${label}${tagLabel ? ` (${tagLabel})` : ""}`,
23116
+ sx: [
23117
+ {
23118
+ display: "inline-flex",
23119
+ alignItems: "center",
23120
+ gap: 1.25,
23121
+ px: 2.25,
23122
+ py: 1.25,
23123
+ borderRadius: "9999px",
23124
+ bgcolor: "hsl(var(--card))",
23125
+ color: "hsl(var(--foreground))",
23126
+ border: "1px solid hsl(var(--border))",
23127
+ boxShadow: "0 4px 20px -2px rgba(0, 0, 0, 0.35), 0 2px 6px -1px rgba(0, 0, 0, 0.16)",
23128
+ backdropFilter: "blur(10px)",
23129
+ cursor: "pointer",
23130
+ userSelect: "none",
23131
+ transition: "transform 160ms cubic-bezier(0.16, 1, 0.3, 1), box-shadow 160ms ease, border-color 160ms ease, background-color 160ms ease",
23132
+ "&:hover": {
23133
+ transform: "translateY(-2px)",
23134
+ bgcolor: "hsl(var(--card) / 0.95)",
23135
+ borderColor: "hsla(var(--primary) / 0.45)",
23136
+ boxShadow: "0 8px 26px -4px hsla(var(--primary) / 0.25), 0 4px 10px -2px rgba(0, 0, 0, 0.2)"
23137
+ },
23138
+ "&:active": {
23139
+ transform: "translateY(0)",
23140
+ boxShadow: "0 2px 10px -2px rgba(0, 0, 0, 0.25)"
23141
+ }
23142
+ },
23143
+ ...Array.isArray(sx) ? sx : sx ? [sx] : []
23144
+ ],
23145
+ children: [
23146
+ /* @__PURE__ */ jsx36(
23147
+ Box28,
23148
+ {
23149
+ sx: {
23150
+ display: "flex",
23151
+ alignItems: "center",
23152
+ justifyContent: "center",
23153
+ width: 24,
23154
+ height: 24,
23155
+ borderRadius: "50%",
23156
+ bgcolor: "hsla(var(--primary) / 0.14)",
23157
+ color: "hsl(var(--primary))",
23158
+ flexShrink: 0
23159
+ },
23160
+ children: /* @__PURE__ */ jsx36(AgentIcon_default, { size: 16 })
23161
+ }
23162
+ ),
23163
+ /* @__PURE__ */ jsx36(
23164
+ Typography25,
23165
+ {
23166
+ sx: {
23167
+ fontSize: "0.86rem",
23168
+ fontWeight: 600,
23169
+ letterSpacing: "-0.01em",
23170
+ lineHeight: 1,
23171
+ color: "inherit"
23172
+ },
23173
+ children: label
23174
+ }
23175
+ ),
23176
+ tagLabel && /* @__PURE__ */ jsx36(
23177
+ Box28,
23178
+ {
23179
+ component: "span",
23180
+ sx: {
23181
+ fontSize: "0.64rem",
23182
+ fontWeight: 700,
23183
+ textTransform: "uppercase",
23184
+ letterSpacing: "0.04em",
23185
+ color: "hsl(var(--primary))",
23186
+ bgcolor: "hsla(var(--primary) / 0.12)",
23187
+ border: "1px solid hsla(var(--primary) / 0.26)",
23188
+ px: 0.9,
23189
+ py: 0.25,
23190
+ borderRadius: "9999px",
23191
+ lineHeight: 1.1,
23192
+ flexShrink: 0
23193
+ },
23194
+ children: tagLabel
23195
+ }
23196
+ )
23197
+ ]
23198
+ }
23199
+ ) })
23200
+ }
23201
+ );
23202
+ };
23203
+ var AskAiButton_default = AskAiButton;
23204
+
23205
+ // components/AskAiDrawer.tsx
23206
+ import { useCallback as useCallback14, useEffect as useEffect24, useMemo as useMemo13, useState as useState26 } from "react";
23207
+ import { Box as Box29, ButtonBase as ButtonBase3, Typography as Typography26 } from "@mui/material";
23208
+ import { jsx as jsx37, jsxs as jsxs31 } from "react/jsx-runtime";
23209
+ var AskAiDrawer = ({
23210
+ open,
23211
+ onClose,
23212
+ title,
23213
+ subtitle,
23214
+ pathname: propPathname,
23215
+ search: propSearch,
23216
+ rules,
23217
+ onContextResolved,
23218
+ hideResetAction = true,
23219
+ agentUIProps,
23220
+ ...drawerProps
23221
+ }) => {
23222
+ const [internalPathname, setInternalPathname] = useState26(
23223
+ () => typeof window !== "undefined" ? window.location.pathname : "/"
23224
+ );
23225
+ const [internalSearch, setInternalSearch] = useState26(
23226
+ () => typeof window !== "undefined" ? window.location.search : ""
23227
+ );
23228
+ useEffect24(() => {
23229
+ if (propPathname !== void 0) return;
23230
+ const updateLoc = () => {
23231
+ setInternalPathname(window.location.pathname);
23232
+ setInternalSearch(window.location.search);
23233
+ };
23234
+ window.addEventListener("popstate", updateLoc);
23235
+ return () => window.removeEventListener("popstate", updateLoc);
23236
+ }, [propPathname]);
23237
+ const activePathname = propPathname !== void 0 ? propPathname : internalPathname;
23238
+ const activeSearch = propSearch !== void 0 ? propSearch : internalSearch;
23239
+ const [resetKey, setResetKey] = useState26(0);
23240
+ const resolvedContext = useMemo13(
23241
+ () => resolveAgentContext(activePathname, activeSearch, rules),
23242
+ // eslint-disable-next-line react-hooks/exhaustive-deps
23243
+ [activePathname, activeSearch, rules, resetKey]
23244
+ );
23245
+ useEffect24(() => {
23246
+ onContextResolved?.(resolvedContext);
23247
+ }, [resolvedContext, onContextResolved]);
23248
+ const [isOverridden, setIsOverridden] = useState26(resolvedContext.isOverridden);
23249
+ useEffect24(() => {
23250
+ setIsOverridden(resolvedContext.isOverridden);
23251
+ }, [resolvedContext.isOverridden, resolvedContext.storageKey]);
23252
+ const handleAppsChange = useCallback14(
23253
+ (apps) => {
23254
+ setPageContextChoice(resolvedContext.storageKey, {
23255
+ apps: apps.map((a) => ({ name: a.name, id: a.id, icon: a.icon }))
23256
+ });
23257
+ setIsOverridden(true);
23258
+ },
23259
+ [resolvedContext.storageKey]
23260
+ );
23261
+ const handleSelectPreset = useCallback14(
23262
+ (preset) => {
23263
+ setPageContextChoice(resolvedContext.storageKey, {
23264
+ presetId: preset.id
23265
+ });
23266
+ setIsOverridden(true);
23267
+ },
23268
+ [resolvedContext.storageKey]
23269
+ );
23270
+ const handleResetToDefaults = useCallback14(() => {
23271
+ clearPageContextChoice(resolvedContext.storageKey);
23272
+ setIsOverridden(false);
23273
+ setResetKey((k) => k + 1);
23274
+ }, [resolvedContext.storageKey]);
23275
+ const effectiveTitle = title !== void 0 ? title : resolvedContext.title;
23276
+ const effectiveSubtitle = subtitle !== void 0 ? subtitle : /* @__PURE__ */ jsxs31(Box29, { sx: { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap", mt: 0.25 }, children: [
23277
+ /* @__PURE__ */ jsx37(Typography26, { component: "span", sx: { fontSize: "0.78rem", color: "hsl(var(--muted-foreground))" }, children: resolvedContext.subtitle }),
23278
+ isOverridden && !hideResetAction && /* @__PURE__ */ jsx37(
23279
+ ButtonBase3,
23280
+ {
23281
+ onClick: handleResetToDefaults,
23282
+ sx: {
23283
+ fontSize: "0.68rem",
23284
+ fontWeight: 600,
23285
+ color: "hsl(var(--primary))",
23286
+ textDecoration: "underline",
23287
+ cursor: "pointer",
23288
+ py: 0.1,
23289
+ px: 0.4,
23290
+ borderRadius: 0.5,
23291
+ transition: "opacity 120ms ease",
23292
+ "&:hover": { opacity: 0.75 }
23293
+ },
23294
+ children: "Reset to defaults"
23295
+ }
23296
+ )
23297
+ ] });
23298
+ return /* @__PURE__ */ jsx37(
23299
+ AgentRunDrawer_default,
23300
+ {
23301
+ ...drawerProps,
23302
+ open,
23303
+ onClose,
23304
+ title: effectiveTitle,
23305
+ subtitle: effectiveSubtitle,
23306
+ agentUIProps: {
23307
+ ...agentUIProps,
23308
+ key: `ask_ai_${resolvedContext.storageKey}_${resetKey}`,
23309
+ defaultApps: resolvedContext.apps,
23310
+ initialPresetId: resolvedContext.presetId,
23311
+ defaultInput: agentUIProps?.defaultInput ?? resolvedContext.defaultPrompt,
23312
+ placeholder: agentUIProps?.placeholder ?? resolvedContext.placeholder,
23313
+ contextCategory: resolvedContext.sourceCategory,
23314
+ contextStorageKey: resolvedContext.storageKey,
23315
+ onAppsChange: (apps) => {
23316
+ handleAppsChange(apps);
23317
+ agentUIProps?.onAppsChange?.(apps);
23318
+ },
23319
+ onSelectPreset: (preset) => {
23320
+ handleSelectPreset(preset);
23321
+ agentUIProps?.onSelectPreset?.(preset);
23322
+ }
23323
+ }
23324
+ }
23325
+ );
23326
+ };
23327
+ var AskAiDrawer_default = AskAiDrawer;
23328
+
23329
+ // components/AskAiSidePanel.tsx
23330
+ import React8, { useCallback as useCallback15, useEffect as useEffect25, useRef as useRef15, useState as useState27 } from "react";
23331
+ import {
23332
+ Box as Box30,
23333
+ ButtonBase as ButtonBase4,
23334
+ IconButton as IconButton15,
23335
+ Typography as Typography27
23336
+ } from "@mui/material";
23337
+ import {
23338
+ AlertTriangle as AlertTriangle4,
23339
+ ArrowLeft,
23340
+ Server as Server3,
23341
+ ShieldCheck as ShieldCheck2,
23342
+ X as CloseIcon11
23343
+ } from "lucide-react";
23344
+ import { Fragment as Fragment16, jsx as jsx38, jsxs as jsxs32 } from "react/jsx-runtime";
23345
+ var AGENT_DRAWER_OPEN_EVENT = "agent-drawer-open";
23346
+ var AskAiSidePanel = ({
23347
+ open,
23348
+ onClose,
23349
+ initialTab = "run",
23350
+ activeTab: propActiveTab,
23351
+ onTabChange,
23352
+ permissionsSlot,
23353
+ localLLMSlot,
23354
+ localLLMTabBadge,
23355
+ permissionsDisabled = false,
23356
+ permissionsDisabledTooltip,
23357
+ pathname,
23358
+ search,
23359
+ rules,
23360
+ isSupport,
23361
+ width = 380,
23362
+ theme,
23363
+ globalUrl,
23364
+ agentUIProps,
23365
+ onContextResolved,
23366
+ sideshift,
23367
+ userdata,
23368
+ isLoaded,
23369
+ isLoggedIn,
23370
+ serverside,
23371
+ colorMode,
23372
+ sx
23373
+ }) => {
23374
+ const themeScope = useShuffleMcpTheme();
23375
+ const effectiveTheme = theme || (themeScope?.isDark ? "dark" : "light");
23376
+ const [currentPathname, setCurrentPathname] = useState27(() => {
23377
+ if (pathname !== void 0) return pathname;
23378
+ if (typeof window !== "undefined") return window.location.pathname;
23379
+ return "/";
23380
+ });
23381
+ const [currentSearch, setCurrentSearch] = useState27(() => {
23382
+ if (search !== void 0) return search;
23383
+ if (typeof window !== "undefined") return window.location.search;
23384
+ return "";
23385
+ });
23386
+ useEffect25(() => {
23387
+ if (pathname !== void 0) {
23388
+ setCurrentPathname(pathname);
23389
+ return;
23390
+ }
23391
+ if (typeof window !== "undefined") {
23392
+ const handleLocationChange = () => {
23393
+ setCurrentPathname(window.location.pathname);
23394
+ setCurrentSearch(window.location.search);
23395
+ };
23396
+ window.addEventListener("popstate", handleLocationChange);
23397
+ return () => window.removeEventListener("popstate", handleLocationChange);
23398
+ }
23399
+ return;
23400
+ }, [pathname]);
23401
+ useEffect25(() => {
23402
+ if (search !== void 0) {
23403
+ setCurrentSearch(search);
23404
+ }
23405
+ }, [search]);
23406
+ const isAgentDisabled = isAgentRoute(currentPathname);
23407
+ useEffect25(() => {
23408
+ if (isAgentDisabled && open) {
23409
+ onClose();
23410
+ }
23411
+ }, [isAgentDisabled, open, onClose]);
23412
+ const context = React8.useMemo(
23413
+ () => resolveAgentContext(currentPathname, currentSearch, rules),
23414
+ [currentPathname, currentSearch, rules]
23415
+ );
23416
+ useEffect25(() => {
23417
+ onContextResolved?.(context);
23418
+ }, [context, onContextResolved]);
23419
+ useSyncHostBaseUrl(globalUrl);
23420
+ const [internalTab, setInternalTab] = useState27(initialTab);
23421
+ const currentTab = propActiveTab !== void 0 ? propActiveTab : internalTab;
23422
+ const handleTabChange = useCallback15(
23423
+ (nextTab) => {
23424
+ setInternalTab(nextTab);
23425
+ onTabChange?.(nextTab);
23426
+ },
23427
+ [onTabChange]
23428
+ );
23429
+ useEffect25(() => {
23430
+ if (initialTab) {
23431
+ setInternalTab(initialTab);
23432
+ }
23433
+ }, [initialTab]);
23434
+ const prevOpenRef = useRef15(open);
23435
+ useEffect25(() => {
23436
+ if (open && !prevOpenRef.current && initialTab) {
23437
+ setInternalTab(initialTab);
23438
+ onTabChange?.(initialTab);
23439
+ }
23440
+ prevOpenRef.current = open;
23441
+ }, [open, initialTab, onTabChange]);
23442
+ useEffect25(() => {
23443
+ if (typeof window === "undefined") return;
23444
+ window.__shuffleAgentDrawerMounted = (window.__shuffleAgentDrawerMounted || 0) + 1;
23445
+ return () => {
23446
+ window.__shuffleAgentDrawerMounted = Math.max(
23447
+ 0,
23448
+ (window.__shuffleAgentDrawerMounted || 1) - 1
23449
+ );
23450
+ };
23451
+ }, []);
23452
+ useEffect25(() => {
23453
+ if (typeof window === "undefined") return;
23454
+ const onOpen = (event) => {
23455
+ const tab = event.detail?.tab;
23456
+ if (tab) {
23457
+ handleTabChange(tab);
23458
+ }
23459
+ };
23460
+ window.addEventListener(AGENT_DRAWER_OPEN_EVENT, onOpen);
23461
+ return () => {
23462
+ window.removeEventListener(AGENT_DRAWER_OPEN_EVENT, onOpen);
23463
+ };
23464
+ }, [handleTabChange]);
23465
+ const effectiveLocalLLMSlot = localLLMSlot ?? /* @__PURE__ */ jsx38(
23466
+ LocalLLMConfig_default,
23467
+ {
23468
+ open,
23469
+ globalUrl,
23470
+ userdata,
23471
+ isLoaded,
23472
+ isLoggedIn,
23473
+ serverside,
23474
+ theme: effectiveTheme,
23475
+ colorMode
23476
+ }
23477
+ );
23478
+ const TAB_ORDER2 = ["run", "localLLM"];
23479
+ const visibleTabs = TAB_ORDER2.filter((t) => {
23480
+ if (t === "run") return true;
23481
+ if (t === "localLLM") return !!effectiveLocalLLMSlot;
23482
+ return false;
23483
+ });
23484
+ const safeActiveTab = visibleTabs.includes(currentTab) ? currentTab : "run";
23485
+ const effectiveWidth = safeActiveTab === "localLLM" ? Math.max(width, 520) : width;
23486
+ const effectiveSideshift = sideshift !== void 0 ? sideshift : context.sideshift ?? true;
23487
+ useEffect25(() => {
23488
+ if (typeof document === "undefined") return;
23489
+ if (open && !isAgentDisabled && effectiveSideshift) {
23490
+ document.documentElement.style.setProperty(
23491
+ "--ask-ai-panel-width",
23492
+ `${effectiveWidth}px`
23493
+ );
23494
+ } else {
23495
+ document.documentElement.style.setProperty("--ask-ai-panel-width", "0px");
23496
+ }
23497
+ return () => {
23498
+ document.documentElement.style.setProperty("--ask-ai-panel-width", "0px");
23499
+ };
23500
+ }, [open, isAgentDisabled, effectiveWidth, effectiveSideshift]);
23501
+ const handleAppsChange = useCallback15(
23502
+ (nextApps) => {
23503
+ setPageContextChoice(context.storageKey, {
23504
+ apps: nextApps.map((a) => ({ name: a.name, id: a.id, icon: a.icon }))
23505
+ });
23506
+ agentUIProps?.onAppsChange?.(nextApps);
23507
+ },
23508
+ [context.storageKey, agentUIProps]
23509
+ );
23510
+ const handleSelectPreset = useCallback15(
23511
+ (preset) => {
23512
+ setPageContextChoice(context.storageKey, {
23513
+ presetId: preset?.id ?? null
23514
+ });
23515
+ },
23516
+ [context.storageKey]
23517
+ );
23518
+ if (isAgentDisabled) {
23519
+ return null;
23520
+ }
23521
+ const isVisible = open && !isAgentDisabled;
23522
+ return /* @__PURE__ */ jsxs32(Fragment16, { children: [
23523
+ /* @__PURE__ */ jsx38(
23524
+ Box30,
23525
+ {
23526
+ onClick: onClose,
23527
+ "aria-hidden": "true",
23528
+ sx: {
23529
+ position: "fixed",
23530
+ inset: 0,
23531
+ bgcolor: "rgba(0, 0, 0, 0.45)",
23532
+ zIndex: 1199,
23533
+ display: { xs: isVisible ? "block" : "none", sm: "none" },
23534
+ backdropFilter: "blur(2px)",
23535
+ transition: "opacity 0.2s ease"
23536
+ }
23537
+ }
23538
+ ),
23539
+ /* @__PURE__ */ jsxs32(
23540
+ Box30,
23541
+ {
23542
+ component: "aside",
23543
+ "aria-label": "Ask AI",
23544
+ "aria-hidden": !isVisible,
23545
+ className: themeScope?.scopeClassName,
23546
+ sx: [
23547
+ {
23548
+ position: "fixed",
23549
+ top: 0,
23550
+ right: 0,
23551
+ bottom: 0,
23552
+ width: { xs: "100%", sm: effectiveWidth },
23553
+ maxWidth: "100vw",
23554
+ height: "100dvh",
23555
+ bgcolor: "hsl(var(--card))",
23556
+ borderLeft: "1px solid hsl(var(--border))",
23557
+ boxShadow: isVisible ? "-6px 0 24px rgba(0, 0, 0, 0.16)" : "none",
23558
+ zIndex: 1200,
23559
+ display: "flex",
23560
+ flexDirection: "column",
23561
+ transform: isVisible ? "translateX(0)" : "translateX(100%)",
23562
+ transition: "transform 0.22s cubic-bezier(0.16, 1, 0.3, 1), width 0.2s ease",
23563
+ pointerEvents: isVisible ? "auto" : "none",
23564
+ visibility: isVisible ? "visible" : "hidden",
23565
+ boxSizing: "border-box",
23566
+ overflow: "hidden"
23567
+ },
23568
+ ...Array.isArray(sx) ? sx : [sx]
23569
+ ],
23570
+ children: [
23571
+ /* @__PURE__ */ jsxs32(
23572
+ Box30,
23573
+ {
23574
+ sx: {
23575
+ display: "flex",
23576
+ alignItems: "center",
23577
+ justifyContent: "space-between",
23578
+ px: 2,
23579
+ pt: 1.5,
23580
+ pb: 1,
23581
+ borderBottom: "1px solid hsl(var(--border) / 0.6)",
23582
+ flexShrink: 0
23583
+ },
23584
+ children: [
23585
+ /* @__PURE__ */ jsxs32(Box30, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
23586
+ /* @__PURE__ */ jsx38(
23587
+ Box30,
23588
+ {
23589
+ sx: {
23590
+ width: 24,
23591
+ height: 24,
23592
+ borderRadius: "6px",
23593
+ bgcolor: "hsl(var(--primary) / 0.12)",
23594
+ border: "1px solid hsl(var(--primary) / 0.3)",
23595
+ display: "flex",
23596
+ alignItems: "center",
23597
+ justifyContent: "center",
23598
+ color: "hsl(var(--primary))",
23599
+ flexShrink: 0
23600
+ },
23601
+ children: safeActiveTab === "permissions" ? /* @__PURE__ */ jsx38(ShieldCheck2, { size: 14 }) : safeActiveTab === "localLLM" ? /* @__PURE__ */ jsx38(Server3, { size: 14 }) : /* @__PURE__ */ jsx38(AgentIcon_default, { size: 14 })
23602
+ }
23603
+ ),
23604
+ /* @__PURE__ */ jsx38(
23605
+ Typography27,
23606
+ {
23607
+ sx: {
23608
+ fontWeight: 700,
23609
+ fontSize: "0.86rem",
23610
+ color: "hsl(var(--foreground))",
23611
+ letterSpacing: "-0.01em"
23612
+ },
23613
+ children: safeActiveTab === "permissions" ? "Agent Permissions" : safeActiveTab === "localLLM" ? "Local LLM Settings" : "Ask AI"
23614
+ }
23615
+ ),
23616
+ /* @__PURE__ */ jsx38(
23617
+ Box30,
23618
+ {
23619
+ sx: {
23620
+ fontSize: "0.66rem",
23621
+ fontWeight: 600,
23622
+ textTransform: "uppercase",
23623
+ letterSpacing: "0.04em",
23624
+ px: 0.75,
23625
+ py: 0.2,
23626
+ borderRadius: "4px",
23627
+ bgcolor: "hsl(var(--muted))",
23628
+ color: "hsl(var(--muted-foreground))",
23629
+ border: "1px solid hsl(var(--border))"
23630
+ },
23631
+ children: "Support only"
23632
+ }
23633
+ )
23634
+ ] }),
23635
+ /* @__PURE__ */ jsx38(Box30, { sx: { display: "flex", alignItems: "center", gap: 0.5 }, children: /* @__PURE__ */ jsx38(
23636
+ IconButton15,
23637
+ {
23638
+ onClick: onClose,
23639
+ size: "small",
23640
+ "aria-label": "Close Ask AI panel",
23641
+ sx: {
23642
+ color: "hsl(var(--muted-foreground))",
23643
+ p: 0.75,
23644
+ borderRadius: "8px",
23645
+ "&:hover": {
23646
+ color: "hsl(var(--foreground))",
23647
+ bgcolor: "hsl(var(--muted))"
23648
+ }
23649
+ },
23650
+ children: /* @__PURE__ */ jsx38(CloseIcon11, { size: 16 })
23651
+ }
23652
+ ) })
23653
+ ]
23654
+ }
23655
+ ),
23656
+ safeActiveTab === "localLLM" && effectiveLocalLLMSlot && /* @__PURE__ */ jsxs32(
23657
+ Box30,
23658
+ {
23659
+ sx: {
23660
+ flex: 1,
23661
+ display: "flex",
23662
+ flexDirection: "column",
23663
+ minHeight: 0,
23664
+ overflow: "hidden"
23665
+ },
23666
+ children: [
23667
+ /* @__PURE__ */ jsxs32(
23668
+ Box30,
23669
+ {
23670
+ sx: {
23671
+ display: "flex",
23672
+ alignItems: "center",
23673
+ justifyContent: "space-between",
23674
+ px: 2,
23675
+ py: 1.25,
23676
+ borderBottom: "1px solid hsl(var(--border) / 0.6)",
23677
+ bgcolor: "hsl(var(--card))",
23678
+ flexShrink: 0
23679
+ },
23680
+ children: [
23681
+ /* @__PURE__ */ jsxs32(
23682
+ ButtonBase4,
23683
+ {
23684
+ onClick: () => handleTabChange("run"),
23685
+ sx: {
23686
+ display: "inline-flex",
23687
+ alignItems: "center",
23688
+ gap: 0.75,
23689
+ fontSize: "0.82rem",
23690
+ fontWeight: 600,
23691
+ color: "hsl(var(--primary))",
23692
+ py: 0.5,
23693
+ px: 1,
23694
+ borderRadius: 1,
23695
+ transition: "background-color 120ms ease",
23696
+ "&:hover": {
23697
+ bgcolor: "hsl(var(--muted))"
23698
+ }
23699
+ },
23700
+ children: [
23701
+ /* @__PURE__ */ jsx38(ArrowLeft, { size: 14 }),
23702
+ "Back to chat"
23703
+ ]
23704
+ }
23705
+ ),
23706
+ /* @__PURE__ */ jsxs32(
23707
+ Box30,
23708
+ {
23709
+ sx: {
23710
+ display: "flex",
23711
+ alignItems: "center",
23712
+ gap: 0.5,
23713
+ fontSize: "0.78rem",
23714
+ color: "hsl(var(--muted-foreground))",
23715
+ fontWeight: 500
23716
+ },
23717
+ children: [
23718
+ /* @__PURE__ */ jsx38(Server3, { size: 13 }),
23719
+ "Local LLM",
23720
+ localLLMTabBadge
23721
+ ]
23722
+ }
23723
+ )
23724
+ ]
23725
+ }
23726
+ ),
23727
+ /* @__PURE__ */ jsx38(
23728
+ Box30,
23729
+ {
23730
+ sx: {
23731
+ flex: 1,
23732
+ overflowY: "auto",
23733
+ overflowX: "hidden",
23734
+ p: 2,
23735
+ minHeight: 0
23736
+ },
23737
+ children: effectiveLocalLLMSlot
23738
+ }
23739
+ )
23740
+ ]
23741
+ }
23742
+ ),
23743
+ safeActiveTab === "run" && /* @__PURE__ */ jsxs32(Fragment16, { children: [
23744
+ context.missingConfig && /* @__PURE__ */ jsxs32(
23745
+ Box30,
23746
+ {
23747
+ sx: {
23748
+ mx: 2,
23749
+ mt: 1.5,
23750
+ mb: 0.5,
23751
+ p: 1.25,
23752
+ borderRadius: 1.5,
23753
+ bgcolor: "hsl(var(--warning) / 0.1)",
23754
+ border: "1px solid hsl(var(--warning) / 0.3)",
23755
+ color: "hsl(var(--warning))",
23756
+ display: "flex",
23757
+ flexDirection: "column",
23758
+ gap: 0.5,
23759
+ flexShrink: 0
23760
+ },
23761
+ children: [
23762
+ /* @__PURE__ */ jsxs32(
23763
+ Box30,
23764
+ {
23765
+ sx: {
23766
+ display: "flex",
23767
+ alignItems: "center",
23768
+ gap: 0.75,
23769
+ fontWeight: 600,
23770
+ fontSize: "0.78rem"
23771
+ },
23772
+ children: [
23773
+ /* @__PURE__ */ jsx38(AlertTriangle4, { size: 14 }),
23774
+ "Missing page configuration"
23775
+ ]
23776
+ }
23777
+ ),
23778
+ /* @__PURE__ */ jsxs32(
23779
+ Typography27,
23780
+ {
23781
+ sx: {
23782
+ fontSize: "0.72rem",
23783
+ color: "hsl(var(--muted-foreground))",
23784
+ lineHeight: 1.35
23785
+ },
23786
+ children: [
23787
+ "No specific MCP apps or skills mapped for",
23788
+ " ",
23789
+ /* @__PURE__ */ jsx38("code", { children: currentPathname }),
23790
+ ". Using default platform tools. Support users: add a route mapping in",
23791
+ " ",
23792
+ /* @__PURE__ */ jsx38("code", { children: "agentContextRegistry.ts" }),
23793
+ " or manually choose tools below."
23794
+ ]
23795
+ }
23796
+ )
23797
+ ]
23798
+ }
23799
+ ),
23800
+ /* @__PURE__ */ jsx38(
23801
+ Box30,
23802
+ {
23803
+ sx: {
23804
+ flex: 1,
23805
+ overflowY: "auto",
23806
+ overflowX: "hidden",
23807
+ px: 1.5,
23808
+ pb: 2,
23809
+ minHeight: 0,
23810
+ display: "flex",
23811
+ flexDirection: "column"
23812
+ },
23813
+ children: /* @__PURE__ */ jsx38(
23814
+ AgentUI_default,
23815
+ {
23816
+ compact: true,
23817
+ mobileView: true,
23818
+ hideHeroIcon: true,
23819
+ title: context.title || "How can we help on this page?",
23820
+ subtitle: null,
23821
+ hideChooseLLM: false,
23822
+ disableSchedule: true,
23823
+ hideAttach: false,
23824
+ maxWidth: effectiveWidth - 32,
23825
+ defaultApps: context.apps,
23826
+ initialPresetId: context.presetId,
23827
+ placeholder: context.placeholder,
23828
+ contextCategory: context.sourceCategory,
23829
+ contextStorageKey: context.storageKey,
23830
+ onAppsChange: handleAppsChange,
23831
+ onSelectPreset: handleSelectPreset,
23832
+ onChooseLLM: () => handleTabChange("localLLM"),
23833
+ apiBaseUrl: globalUrl || agentUIProps?.apiBaseUrl,
23834
+ theme: effectiveTheme,
23835
+ ...agentUIProps,
23836
+ sx: {
23837
+ flex: 1,
23838
+ minHeight: "100%",
23839
+ display: "flex",
23840
+ flexDirection: "column",
23841
+ justifyContent: "center",
23842
+ pt: 0,
23843
+ pb: 2,
23844
+ ...agentUIProps?.sx ? Array.isArray(agentUIProps.sx) ? {} : agentUIProps.sx : {}
23845
+ }
23846
+ },
23847
+ context.storageKey
23848
+ )
23849
+ }
23850
+ )
23851
+ ] })
23852
+ ]
23853
+ }
23854
+ )
23855
+ ] });
23856
+ };
23857
+ var AskAiSidePanel_default = AskAiSidePanel;
23858
+
23859
+ // components/AskAiWidget.tsx
23860
+ import { useCallback as useCallback16, useEffect as useEffect26, useState as useState28 } from "react";
23861
+ import { Fragment as Fragment17, jsx as jsx39, jsxs as jsxs33 } from "react/jsx-runtime";
23862
+ var AGENT_DRAWER_OPEN_EVENT2 = "agent-drawer-open";
23863
+ var AskAiWidget = ({
23864
+ open: controlledOpen,
23865
+ onOpenChange,
23866
+ mode = "panel",
23867
+ isSupport,
23868
+ requireSupport = true,
23869
+ buttonProps,
23870
+ hideButton = false,
23871
+ pathname,
23872
+ search,
23873
+ rules,
23874
+ initialTab: propInitialTab = "run",
23875
+ onContextResolved,
23876
+ permissionsSlot,
23877
+ localLLMSlot,
23878
+ ...panelProps
23879
+ }) => {
23880
+ const [internalOpen, setInternalOpen] = useState28(false);
23881
+ const [activeTab, setActiveTab] = useState28(propInitialTab);
23882
+ const isDrawerOpen = controlledOpen !== void 0 ? controlledOpen : internalOpen;
23883
+ const currentPath = pathname !== void 0 ? pathname : typeof window !== "undefined" ? window.location.pathname : "";
23884
+ const isAgentDisabled = isAgentRoute(currentPath);
23885
+ const setDrawerOpen = useCallback16(
23886
+ (nextOpen) => {
23887
+ if (isAgentDisabled && nextOpen) return;
23888
+ if (controlledOpen === void 0) {
23889
+ setInternalOpen(nextOpen);
23890
+ }
23891
+ onOpenChange?.(nextOpen);
23892
+ },
23893
+ [controlledOpen, isAgentDisabled, onOpenChange]
23894
+ );
23895
+ useEffect26(() => {
23896
+ if (isAgentDisabled && isDrawerOpen) {
23897
+ setDrawerOpen(false);
23898
+ }
23899
+ }, [isAgentDisabled, isDrawerOpen, setDrawerOpen]);
23900
+ const [currentContext, setCurrentContext] = useState28(null);
23901
+ const handleContextResolved = useCallback16(
23902
+ (ctx) => {
23903
+ setCurrentContext(ctx);
23904
+ onContextResolved?.(ctx);
23905
+ },
23906
+ [onContextResolved]
23907
+ );
23908
+ useEffect26(() => {
23909
+ const handleDrawerOpenEvent = (e) => {
23910
+ if (isAgentDisabled) return;
23911
+ const detail = e.detail;
23912
+ if (detail?.tab) {
23913
+ setActiveTab(detail.tab);
23914
+ }
23915
+ setDrawerOpen(true);
23916
+ };
23917
+ window.addEventListener(AGENT_DRAWER_OPEN_EVENT2, handleDrawerOpenEvent);
23918
+ return () => window.removeEventListener(AGENT_DRAWER_OPEN_EVENT2, handleDrawerOpenEvent);
23919
+ }, [isAgentDisabled, setDrawerOpen]);
23920
+ useEffect26(() => {
23921
+ if (propInitialTab) {
23922
+ setActiveTab(propInitialTab);
23923
+ }
23924
+ }, [propInitialTab]);
23925
+ const contextHint = currentContext?.apps && currentContext.apps.length > 0 ? currentContext.apps.map((a) => a.name.replace(/^shuffle_/, "").replace(/_/g, " ")).join(", ") : void 0;
23926
+ if (isAgentDisabled) {
23927
+ return null;
23928
+ }
23929
+ return /* @__PURE__ */ jsxs33(Fragment17, { children: [
23930
+ !hideButton && /* @__PURE__ */ jsx39(
23931
+ AskAiButton,
23932
+ {
23933
+ onClick: () => setDrawerOpen(!isDrawerOpen),
23934
+ isOpen: isDrawerOpen,
23935
+ isSupport,
23936
+ requireSupport,
23937
+ pathname,
23938
+ contextHint,
23939
+ ...buttonProps
23940
+ }
23941
+ ),
23942
+ mode === "drawer" ? /* @__PURE__ */ jsx39(
23943
+ AskAiDrawer,
23944
+ {
23945
+ open: isDrawerOpen,
23946
+ onClose: () => setDrawerOpen(false),
23947
+ initialTab: activeTab,
23948
+ pathname,
23949
+ search,
23950
+ rules,
23951
+ permissionsSlot,
23952
+ localLLMSlot,
23953
+ onContextResolved: handleContextResolved,
23954
+ ...panelProps
23955
+ }
23956
+ ) : /* @__PURE__ */ jsx39(
23957
+ AskAiSidePanel,
23958
+ {
23959
+ open: isDrawerOpen,
23960
+ onClose: () => setDrawerOpen(false),
23961
+ initialTab: activeTab,
23962
+ activeTab,
23963
+ onTabChange: setActiveTab,
23964
+ permissionsSlot,
23965
+ localLLMSlot,
23966
+ pathname,
23967
+ search,
23968
+ rules,
23969
+ isSupport,
23970
+ onContextResolved: handleContextResolved,
23971
+ ...panelProps
23972
+ }
23973
+ )
23974
+ ] });
23975
+ };
23976
+ var useContextAwareAgent = (pathname, search) => {
23977
+ const [activeContext, setActiveContext] = useState28(() => {
23978
+ const p = pathname ?? (typeof window !== "undefined" ? window.location.pathname : "/");
23979
+ const s = search ?? (typeof window !== "undefined" ? window.location.search : "");
23980
+ return resolveAgentContext(p, s);
23981
+ });
23982
+ useEffect26(() => {
23983
+ const p = pathname ?? (typeof window !== "undefined" ? window.location.pathname : "/");
23984
+ const s = search ?? (typeof window !== "undefined" ? window.location.search : "");
23985
+ setActiveContext(resolveAgentContext(p, s));
23986
+ }, [pathname, search]);
23987
+ return activeContext;
23988
+ };
23989
+ var AskAiWidget_default = AskAiWidget;
23990
+
21858
23991
  // components/AgentPromptPrefixChip.tsx
21859
- import { useEffect as useEffect24, useState as useState26 } from "react";
23992
+ import { useEffect as useEffect27, useState as useState29 } from "react";
21860
23993
  import {
21861
- Box as Box28,
23994
+ Box as Box31,
21862
23995
  Button as Button14,
21863
23996
  Dialog as Dialog7,
21864
23997
  DialogActions as DialogActions4,
21865
23998
  DialogContent as DialogContent6,
21866
23999
  DialogTitle as DialogTitle6,
21867
- IconButton as IconButton15,
24000
+ IconButton as IconButton16,
21868
24001
  TextField as TextField10,
21869
- Tooltip as Tooltip19,
21870
- Typography as Typography25
24002
+ Tooltip as Tooltip21,
24003
+ Typography as Typography28
21871
24004
  } from "@mui/material";
21872
- import { X as CloseIcon11 } from "lucide-react";
21873
- import { Fragment as Fragment16, jsx as jsx36, jsxs as jsxs30 } from "react/jsx-runtime";
24005
+ import { X as CloseIcon12 } from "lucide-react";
24006
+ import { Fragment as Fragment18, jsx as jsx40, jsxs as jsxs34 } from "react/jsx-runtime";
21874
24007
  var AgentPromptPrefixChip = ({
21875
24008
  label = "Shuffle Tools MCP",
21876
24009
  userId,
@@ -21885,9 +24018,9 @@ var AgentPromptPrefixChip = ({
21885
24018
  const managed = useAgentPromptPrefix({ userId, defaultPrompt, persist: !controlled });
21886
24019
  const prompt = controlled ? value : managed.prompt;
21887
24020
  const isSaving = controlled ? false : managed.isSaving;
21888
- const [open, setOpen] = useState26(false);
21889
- const [draft, setDraft] = useState26(prompt);
21890
- useEffect24(() => {
24021
+ const [open, setOpen] = useState29(false);
24022
+ const [draft, setDraft] = useState29(prompt);
24023
+ useEffect27(() => {
21891
24024
  if (!open) setDraft(prompt);
21892
24025
  }, [prompt, open]);
21893
24026
  const handleOpen = () => {
@@ -21905,9 +24038,9 @@ var AgentPromptPrefixChip = ({
21905
24038
  };
21906
24039
  const MAX_LABEL_CHARS = 15;
21907
24040
  const displayLabel = label.length > MAX_LABEL_CHARS ? `${label.slice(0, MAX_LABEL_CHARS - 1).trimEnd()}\u2026` : label;
21908
- return /* @__PURE__ */ jsxs30(Fragment16, { children: [
21909
- /* @__PURE__ */ jsx36(Tooltip19, { title: readOnly ? `${label} \u2014 preset handled by the backend` : "Click to edit the default prompt sent with your message", placement: "top", arrow: true, children: /* @__PURE__ */ jsxs30(
21910
- Box28,
24041
+ return /* @__PURE__ */ jsxs34(Fragment18, { children: [
24042
+ /* @__PURE__ */ jsx40(Tooltip21, { title: readOnly ? `${label} \u2014 preset handled by the backend` : "Click to edit the default prompt sent with your message", placement: "top", arrow: true, children: /* @__PURE__ */ jsxs34(
24043
+ Box31,
21911
24044
  {
21912
24045
  sx: {
21913
24046
  display: "inline-flex",
@@ -21922,8 +24055,8 @@ var AgentPromptPrefixChip = ({
21922
24055
  "&:hover": readOnly ? void 0 : { bgcolor: "hsl(var(--muted))" }
21923
24056
  },
21924
24057
  children: [
21925
- /* @__PURE__ */ jsx36(
21926
- Box28,
24058
+ /* @__PURE__ */ jsx40(
24059
+ Box31,
21927
24060
  {
21928
24061
  onClick: handleOpen,
21929
24062
  role: readOnly ? void 0 : "button",
@@ -21940,8 +24073,8 @@ var AgentPromptPrefixChip = ({
21940
24073
  cursor: readOnly ? "default" : "pointer"
21941
24074
  },
21942
24075
  "aria-label": readOnly ? `${label} preset selected` : `Edit default prompt for ${label}`,
21943
- children: /* @__PURE__ */ jsx36(
21944
- Typography25,
24076
+ children: /* @__PURE__ */ jsx40(
24077
+ Typography28,
21945
24078
  {
21946
24079
  component: "span",
21947
24080
  sx: {
@@ -21956,8 +24089,8 @@ var AgentPromptPrefixChip = ({
21956
24089
  )
21957
24090
  }
21958
24091
  ),
21959
- onRemove && /* @__PURE__ */ jsx36(
21960
- IconButton15,
24092
+ onRemove && /* @__PURE__ */ jsx40(
24093
+ IconButton16,
21961
24094
  {
21962
24095
  size: "small",
21963
24096
  onClick: (e) => {
@@ -21972,13 +24105,13 @@ var AgentPromptPrefixChip = ({
21972
24105
  "&:hover": { color: "hsl(var(--destructive))", bgcolor: "transparent" }
21973
24106
  },
21974
24107
  "aria-label": `Remove ${label} preset`,
21975
- children: /* @__PURE__ */ jsx36(CloseIcon11, { size: 12 })
24108
+ children: /* @__PURE__ */ jsx40(CloseIcon12, { size: 12 })
21976
24109
  }
21977
24110
  )
21978
24111
  ]
21979
24112
  }
21980
24113
  ) }),
21981
- /* @__PURE__ */ jsxs30(
24114
+ /* @__PURE__ */ jsxs34(
21982
24115
  Dialog7,
21983
24116
  {
21984
24117
  open,
@@ -21995,14 +24128,14 @@ var AgentPromptPrefixChip = ({
21995
24128
  }
21996
24129
  },
21997
24130
  children: [
21998
- /* @__PURE__ */ jsxs30(DialogTitle6, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between", pr: 1.5, borderBottom: "1px solid hsl(var(--border))" }, children: [
21999
- /* @__PURE__ */ jsxs30(Box28, { children: [
22000
- /* @__PURE__ */ jsx36(Typography25, { sx: { fontSize: "1rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: dialogTitle || `Edit default prompt \u2014 ${label}` }),
22001
- /* @__PURE__ */ jsx36(Typography25, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))", mt: 0.25 }, children: isSaving ? "Saving\u2026" : "This text is prepended to every message you send from this prompt box. Saved to your user preferences." })
24131
+ /* @__PURE__ */ jsxs34(DialogTitle6, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between", pr: 1.5, borderBottom: "1px solid hsl(var(--border))" }, children: [
24132
+ /* @__PURE__ */ jsxs34(Box31, { children: [
24133
+ /* @__PURE__ */ jsx40(Typography28, { sx: { fontSize: "1rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: dialogTitle || `Edit default prompt \u2014 ${label}` }),
24134
+ /* @__PURE__ */ jsx40(Typography28, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))", mt: 0.25 }, children: isSaving ? "Saving\u2026" : "This text is prepended to every message you send from this prompt box. Saved to your user preferences." })
22002
24135
  ] }),
22003
- /* @__PURE__ */ jsx36(IconButton15, { size: "small", onClick: () => setOpen(false), sx: { color: "hsl(var(--muted-foreground))" }, "aria-label": "Close", children: /* @__PURE__ */ jsx36(CloseIcon11, { size: 16 }) })
24136
+ /* @__PURE__ */ jsx40(IconButton16, { size: "small", onClick: () => setOpen(false), sx: { color: "hsl(var(--muted-foreground))" }, "aria-label": "Close", children: /* @__PURE__ */ jsx40(CloseIcon12, { size: 16 }) })
22004
24137
  ] }),
22005
- /* @__PURE__ */ jsx36(DialogContent6, { sx: { pt: 2 }, children: /* @__PURE__ */ jsx36(
24138
+ /* @__PURE__ */ jsx40(DialogContent6, { sx: { pt: 2 }, children: /* @__PURE__ */ jsx40(
22006
24139
  TextField10,
22007
24140
  {
22008
24141
  autoFocus: true,
@@ -22024,9 +24157,9 @@ var AgentPromptPrefixChip = ({
22024
24157
  }
22025
24158
  }
22026
24159
  ) }),
22027
- /* @__PURE__ */ jsxs30(DialogActions4, { sx: { px: 3, py: 2, borderTop: "1px solid hsl(var(--border))" }, children: [
22028
- /* @__PURE__ */ jsx36(Button14, { onClick: () => setOpen(false), sx: { textTransform: "none", color: "hsl(var(--muted-foreground))" }, children: "Cancel" }),
22029
- /* @__PURE__ */ jsx36(
24160
+ /* @__PURE__ */ jsxs34(DialogActions4, { sx: { px: 3, py: 2, borderTop: "1px solid hsl(var(--border))" }, children: [
24161
+ /* @__PURE__ */ jsx40(Button14, { onClick: () => setOpen(false), sx: { textTransform: "none", color: "hsl(var(--muted-foreground))" }, children: "Cancel" }),
24162
+ /* @__PURE__ */ jsx40(
22030
24163
  Button14,
22031
24164
  {
22032
24165
  onClick: handleSave,
@@ -22049,12 +24182,12 @@ var AgentPromptPrefixChip = ({
22049
24182
  };
22050
24183
 
22051
24184
  // useAppLookup.ts
22052
- import { useEffect as useEffect25, useMemo as useMemo13, useState as useState27 } from "react";
24185
+ import { useEffect as useEffect28, useMemo as useMemo15, useState as useState30 } from "react";
22053
24186
  var norm3 = (s) => s.toLowerCase().replace(/[\s_\-]+/g, "_");
22054
24187
  function useAppLookup(appName) {
22055
- const [loading, setLoading] = useState27(false);
22056
- const [info, setInfo] = useState27(null);
22057
- const [algoliaId, setAlgoliaId] = useState27(null);
24188
+ const [loading, setLoading] = useState30(false);
24189
+ const [info, setInfo] = useState30(null);
24190
+ const [algoliaId, setAlgoliaId] = useState30(null);
22058
24191
  const {
22059
24192
  authStates,
22060
24193
  authenticatedApps,
@@ -22063,7 +24196,7 @@ function useAppLookup(appName) {
22063
24196
  handleSaveAuth,
22064
24197
  refreshAuth
22065
24198
  } = useAppAuth();
22066
- useEffect25(() => {
24199
+ useEffect28(() => {
22067
24200
  if (!appName) {
22068
24201
  setInfo(null);
22069
24202
  setAlgoliaId(null);
@@ -22134,13 +24267,13 @@ function useAppLookup(appName) {
22134
24267
  setLoading(false);
22135
24268
  })();
22136
24269
  }, [appName]);
22137
- const matchingEntries = useMemo13(() => {
24270
+ const matchingEntries = useMemo15(() => {
22138
24271
  if (!appName) return [];
22139
24272
  return authenticatedApps.filter(
22140
24273
  (auth) => auth.app?.name && norm3(auth.app.name) === norm3(appName)
22141
24274
  );
22142
24275
  }, [appName, authenticatedApps]);
22143
- const image = useMemo13(() => {
24276
+ const image = useMemo15(() => {
22144
24277
  if (info?.image) return info.image;
22145
24278
  for (const entry of matchingEntries) {
22146
24279
  const img = entry.app?.large_image || entry.large_image;
@@ -22148,7 +24281,7 @@ function useAppLookup(appName) {
22148
24281
  }
22149
24282
  return "";
22150
24283
  }, [info, matchingEntries]);
22151
- const algoliaApp = useMemo13(() => {
24284
+ const algoliaApp = useMemo15(() => {
22152
24285
  if (!appName) return null;
22153
24286
  return {
22154
24287
  objectID: algoliaId || appName,
@@ -22184,23 +24317,23 @@ var resolveMode = (theme, colorMode) => {
22184
24317
  if (theme === "light" || theme === "dark") return theme;
22185
24318
  if (theme === "system") return "auto";
22186
24319
  if (colorMode) return colorMode;
22187
- return "dark";
24320
+ return "auto";
22188
24321
  };
22189
24322
  var withMcpTheme = (Inner, displayName2) => {
22190
- const Wrapped = ({ theme, colorMode, ...rest }) => React7.createElement(
24323
+ const Wrapped = ({ theme, colorMode, ...rest }) => React10.createElement(
22191
24324
  ShuffleMcpThemeProvider,
22192
24325
  { mode: resolveMode(theme, colorMode) },
22193
- React7.createElement(Inner, { ...rest, theme, colorMode })
24326
+ React10.createElement(Inner, { ...rest, theme, colorMode })
22194
24327
  );
22195
24328
  Wrapped.displayName = `ShuffleMCPs(${displayName2})`;
22196
24329
  return Wrapped;
22197
24330
  };
22198
24331
  var withMcpThemeRef = (Inner, displayName2) => {
22199
- const Wrapped = React7.forwardRef(
22200
- ({ theme, colorMode, ...rest }, ref) => React7.createElement(
24332
+ const Wrapped = React10.forwardRef(
24333
+ ({ theme, colorMode, ...rest }, ref) => React10.createElement(
22201
24334
  ShuffleMcpThemeProvider,
22202
24335
  { mode: resolveMode(theme, colorMode) },
22203
- React7.createElement(Inner, { ...rest, theme, colorMode, ref })
24336
+ React10.createElement(Inner, { ...rest, theme, colorMode, ref })
22204
24337
  )
22205
24338
  );
22206
24339
  Wrapped.displayName = `ShuffleMCPs(${displayName2})`;
@@ -22218,6 +24351,10 @@ var TryMcpSection2 = withMcpTheme(TryMcpSection, "TryMcpSection");
22218
24351
  var SingulActionsPreview2 = withMcpTheme(SingulActionsPreview_default, "SingulActionsPreview");
22219
24352
  var AgentUI2 = withMcpTheme(AgentUI_default, "AgentUI");
22220
24353
  var AgentRunDrawer2 = withMcpTheme(AgentRunDrawer_default, "AgentRunDrawer");
24354
+ var AskAiButton2 = withMcpTheme(AskAiButton_default, "AskAiButton");
24355
+ var AskAiDrawer2 = withMcpTheme(AskAiDrawer_default, "AskAiDrawer");
24356
+ var AskAiSidePanel2 = withMcpTheme(AskAiSidePanel_default, "AskAiSidePanel");
24357
+ var AskAiWidget2 = withMcpTheme(AskAiWidget_default, "AskAiWidget");
22221
24358
  var AgentActivityList2 = withMcpTheme(AgentActivityList_default, "AgentActivityList");
22222
24359
  var AgentExecutionDrawer2 = withMcpTheme(AgentExecutionDrawer_default, "AgentExecutionDrawer");
22223
24360
  var AgentsView2 = withMcpTheme(AgentsView_default, "AgentsView");
@@ -22246,9 +24383,14 @@ export {
22246
24383
  AppDetailProvider,
22247
24384
  AppSearchDrawer2 as AppSearchDrawer,
22248
24385
  AppTitleHeader2 as AppTitleHeader,
24386
+ AskAiButton2 as AskAiButton,
24387
+ AskAiDrawer2 as AskAiDrawer,
24388
+ AskAiSidePanel2 as AskAiSidePanel,
24389
+ AskAiWidget2 as AskAiWidget,
22249
24390
  CASES_PATTERNS,
22250
24391
  COMMUNICATION_PATTERNS_NAMES,
22251
24392
  DATASTORE_CATEGORIES,
24393
+ DEFAULT_AGENT_CONTEXT_RULES,
22252
24394
  DEFAULT_AGENT_PROMPT_PREFIX,
22253
24395
  EDR_PATTERNS,
22254
24396
  EMAIL_APP_PATTERNS,
@@ -22270,6 +24412,7 @@ export {
22270
24412
  VULN_SCANNER_PATTERNS,
22271
24413
  VideoEmbed,
22272
24414
  applyRegionFromPayload,
24415
+ clearPageContextChoice,
22273
24416
  index_default as default,
22274
24417
  deleteDatastoreItem,
22275
24418
  deleteDatastoreItems,
@@ -22282,6 +24425,8 @@ export {
22282
24425
  fetchAppsViaApiConfig,
22283
24426
  findForwardTicketsWorkflow,
22284
24427
  findIngestTicketsWorkflow,
24428
+ getActivePageEntityName,
24429
+ getAgentContextRules,
22285
24430
  getApiUrl,
22286
24431
  getAuthHeader,
22287
24432
  getDatastoreByCategory,
@@ -22291,10 +24436,12 @@ export {
22291
24436
  getFailureInfo,
22292
24437
  getHostBaseUrl,
22293
24438
  getIngestionCategory,
24439
+ getPageContextChoice,
22294
24440
  hasOutputWarning,
22295
24441
  installFetchBreaker,
22296
24442
  invalidateAppsCache,
22297
24443
  invalidateResolvedApps,
24444
+ isAgentRoute,
22298
24445
  isCloud,
22299
24446
  isCloudDomain,
22300
24447
  isEmailApp,
@@ -22303,11 +24450,14 @@ export {
22303
24450
  isThreatIntelApp,
22304
24451
  isVulnScannerApp,
22305
24452
  isWorkflowScheduleStopped,
24453
+ matchRoutePattern,
22306
24454
  normalizeAppName,
22307
24455
  parseRunResult,
22308
24456
  refreshAllIntegrationStatus,
24457
+ registerAgentContextRule,
22309
24458
  registerProtectedOrigin,
22310
24459
  resetRegionUrl,
24460
+ resolveAgentContext,
22311
24461
  resolveApp,
22312
24462
  resolveApps,
22313
24463
  resolveVideoUrl,
@@ -22317,6 +24467,7 @@ export {
22317
24467
  setDatastoreItem,
22318
24468
  setDatastoreItems,
22319
24469
  setHostBaseUrl,
24470
+ setPageContextChoice,
22320
24471
  setRegionUrl,
22321
24472
  setRuntimeOrgId,
22322
24473
  setToastImpl,
@@ -22328,5 +24479,6 @@ export {
22328
24479
  useAppDetail,
22329
24480
  useAppDetailOptional,
22330
24481
  useAppLookup,
24482
+ useContextAwareAgent,
22331
24483
  useSyncHostBaseUrl
22332
24484
  };