@shuffleio/shuffle-mcps 0.0.57 → 0.0.58

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.js CHANGED
@@ -3638,6 +3638,7 @@ var deleteDatastoreItems = async (keys2, category) => {
3638
3638
  };
3639
3639
  var DATASTORE_CATEGORIES = {
3640
3640
  INCIDENTS: "shuffle-security_incidents",
3641
+ EVENTS: "shuffle-security_events",
3641
3642
  VULNERABILITIES: "shuffle-security_vulns",
3642
3643
  VULNS: "shuffle-security_vulns",
3643
3644
  ASSETS: "shuffle-security_assets",
@@ -4273,7 +4274,7 @@ var applyValidationStaleness = (data) => {
4273
4274
  });
4274
4275
  };
4275
4276
  var doFetch3 = async (crossOrgId) => {
4276
- if (!hasShuffleAuth()) return [];
4277
+ if (!hasShuffleAuth()) return { data: [], failed: false };
4277
4278
  const headers = {
4278
4279
  ...getAuthHeader(crossOrgId ?? void 0)
4279
4280
  };
@@ -4282,12 +4283,13 @@ var doFetch3 = async (crossOrgId) => {
4282
4283
  credentials: "include",
4283
4284
  headers
4284
4285
  });
4285
- if (!resp.ok) return [];
4286
+ if (!resp.ok) return { data: [], failed: true };
4286
4287
  const result = await resp.json();
4287
4288
  const data = result?.data || result;
4288
- return Array.isArray(data) ? applyValidationStaleness(data) : [];
4289
+ if (!Array.isArray(data)) return { data: [], failed: true };
4290
+ return { data: applyValidationStaleness(data), failed: false };
4289
4291
  } catch {
4290
- return [];
4292
+ return { data: [], failed: true };
4291
4293
  }
4292
4294
  };
4293
4295
  var fetchAuthenticatedApps = (crossOrgId) => {
@@ -4297,12 +4299,17 @@ var fetchAuthenticatedApps = (crossOrgId) => {
4297
4299
  return Promise.resolve(entry.data);
4298
4300
  }
4299
4301
  if (entry.promise) return entry.promise;
4300
- const promise = doFetch3(crossOrgId).then((data) => {
4301
- cache3.set(key, { data, fetchedAt: Date.now() });
4302
- return data;
4303
- }).catch((err) => {
4302
+ const promise = doFetch3(crossOrgId).then((outcome) => {
4303
+ if (outcome.failed) {
4304
+ const previous = cache3.get(key)?.data;
4305
+ cache3.delete(key);
4306
+ return previous || [];
4307
+ }
4308
+ cache3.set(key, { data: outcome.data, fetchedAt: Date.now() });
4309
+ return outcome.data;
4310
+ }).catch(() => {
4304
4311
  cache3.delete(key);
4305
- throw err;
4312
+ return [];
4306
4313
  });
4307
4314
  cache3.set(key, { ...entry, promise });
4308
4315
  return promise;
@@ -9656,30 +9663,235 @@ function AppDetailContent({
9656
9663
 
9657
9664
  // drawerLayer.ts
9658
9665
  var import_react14 = require("react");
9666
+ var STACK_KEY = "__shuffleOverlayStack";
9659
9667
  var COUNTER_KEY = "__shuffleDrawerLayerTop";
9660
- var DRAWER_LAYER_BASE = 10011;
9661
- var STEP = 10;
9662
- var getTop = (base3) => {
9663
- const store = globalThis;
9664
- const current = store[COUNTER_KEY];
9665
- return typeof current === "number" ? current : base3;
9666
- };
9667
- var useDrawerLayer = (open, base3 = DRAWER_LAYER_BASE) => {
9668
- const [zIndex, setZIndex] = (0, import_react14.useState)(base3);
9668
+ var AUTO_LAYER_KEY = "__shuffleOverlayAutoLayerInstalled";
9669
+ var OVERLAY_BASE = 10010;
9670
+ var DRAWER_LAYER_BASE = OVERLAY_BASE;
9671
+ var SURFACE_STEP = 20;
9672
+ var POPUP_OFFSET = 6;
9673
+ var TOOLTIP_OFFSET = 12;
9674
+ var getStore = () => globalThis;
9675
+ var getOverlayStack = () => {
9676
+ const store = getStore();
9677
+ if (!Array.isArray(store[STACK_KEY])) {
9678
+ store[STACK_KEY] = [];
9679
+ }
9680
+ return store[STACK_KEY];
9681
+ };
9682
+ var getTopSurfaceZIndex = (base3 = OVERLAY_BASE) => {
9683
+ const stack = getOverlayStack();
9684
+ const surfaces = stack.filter((r) => r.type === "surface");
9685
+ if (surfaces.length === 0) {
9686
+ const store = getStore();
9687
+ store[COUNTER_KEY] = base3;
9688
+ return base3;
9689
+ }
9690
+ let maxZ = base3;
9691
+ for (const s of surfaces) {
9692
+ if (s.zIndex > maxZ) {
9693
+ maxZ = s.zIndex;
9694
+ }
9695
+ }
9696
+ getStore()[COUNTER_KEY] = maxZ;
9697
+ return maxZ;
9698
+ };
9699
+ var syncGlobalCounter = (base3 = OVERLAY_BASE) => {
9700
+ getTopSurfaceZIndex(base3);
9701
+ };
9702
+ var allocateSurfaceLayer = (id, element2, base3 = OVERLAY_BASE) => {
9703
+ const stack = getOverlayStack();
9704
+ const existing = stack.find((r) => r.id === id || element2 && r.element === element2);
9705
+ if (existing) {
9706
+ return existing.zIndex;
9707
+ }
9708
+ const currentTop = getTopSurfaceZIndex(base3);
9709
+ const nextZ = currentTop + SURFACE_STEP;
9710
+ stack.push({ id, element: element2, zIndex: nextZ, type: "surface" });
9711
+ syncGlobalCounter(base3);
9712
+ return nextZ;
9713
+ };
9714
+ var releaseOverlayLayer = (idOrElement) => {
9715
+ const stack = getOverlayStack();
9716
+ const index = stack.findIndex(
9717
+ (r) => r.id === idOrElement || typeof idOrElement !== "string" && r.element === idOrElement
9718
+ );
9719
+ if (index !== -1) {
9720
+ stack.splice(index, 1);
9721
+ }
9722
+ syncGlobalCounter();
9723
+ };
9724
+ var bringSurfaceToFront = (idOrElement) => {
9725
+ const stack = getOverlayStack();
9726
+ const record = stack.find(
9727
+ (r) => r.id === idOrElement || typeof idOrElement !== "string" && r.element === idOrElement
9728
+ );
9729
+ if (!record || record.type !== "surface") {
9730
+ return typeof idOrElement === "string" ? allocateSurfaceLayer(idOrElement, null) : allocateSurfaceLayer("surface_" + Math.random().toString(36).substring(2, 9), idOrElement);
9731
+ }
9732
+ const currentTop = getTopSurfaceZIndex();
9733
+ if (record.zIndex >= currentTop) {
9734
+ return record.zIndex;
9735
+ }
9736
+ record.zIndex = currentTop + SURFACE_STEP;
9737
+ syncGlobalCounter();
9738
+ return record.zIndex;
9739
+ };
9740
+ var useOverlayLayer = (open, options) => {
9741
+ const base3 = options?.base ?? OVERLAY_BASE;
9742
+ const [zIndex, setZIndex] = (0, import_react14.useState)(() => open ? getTopSurfaceZIndex(base3) + SURFACE_STEP : base3);
9669
9743
  (0, import_react14.useEffect)(() => {
9670
9744
  if (!open) return;
9671
- const store = globalThis;
9672
- const next = Math.max(base3, getTop(base3) + STEP);
9673
- store[COUNTER_KEY] = next;
9674
- setZIndex(next);
9745
+ const id = "hook_" + Math.random().toString(36).substring(2, 9);
9746
+ const allocated = allocateSurfaceLayer(id, null, base3);
9747
+ setZIndex(allocated);
9675
9748
  return () => {
9676
- if (store[COUNTER_KEY] === next) {
9677
- store[COUNTER_KEY] = next - STEP;
9678
- }
9749
+ releaseOverlayLayer(id);
9679
9750
  };
9680
9751
  }, [open, base3]);
9681
9752
  return zIndex;
9682
9753
  };
9754
+ var useDrawerLayer = (open, base3 = DRAWER_LAYER_BASE) => useOverlayLayer(open, { base: base3 });
9755
+ var isSurfaceElement = (el) => {
9756
+ if (!(el instanceof HTMLElement)) return false;
9757
+ return el.classList.contains("MuiDialog-root") || el.classList.contains("MuiDrawer-root") || el.classList.contains("MuiModal-root") && !el.classList.contains("MuiPopover-root") && !el.classList.contains("MuiMenu-root") || el.getAttribute("role") === "dialog" || el.getAttribute("role") === "alertdialog" || Boolean(el.closest("[data-radix-portal]"));
9758
+ };
9759
+ var isChildPopupElement = (el) => {
9760
+ if (!(el instanceof HTMLElement)) return false;
9761
+ return el.classList.contains("MuiPopover-root") || el.classList.contains("MuiMenu-root") || el.classList.contains("MuiAutocomplete-popper") || Boolean(el.closest("[data-radix-popper-content-wrapper]")) || el.classList.contains("MuiPopper-root") && !el.classList.contains("MuiTooltip-popper");
9762
+ };
9763
+ var isTooltipElement = (el) => {
9764
+ if (!(el instanceof HTMLElement)) return false;
9765
+ return el.classList.contains("MuiTooltip-popper") || el.getAttribute("role") === "tooltip";
9766
+ };
9767
+ var isElementOpen = (el) => {
9768
+ if (el.getAttribute("aria-hidden") === "true") return false;
9769
+ if (el.getAttribute("data-state") === "closed") return false;
9770
+ if (el.classList.contains("MuiModal-hidden")) return false;
9771
+ const style = el.style;
9772
+ if (style.display === "none" || style.visibility === "hidden") return false;
9773
+ return true;
9774
+ };
9775
+ var observerInstance = null;
9776
+ var installGlobalOverlayAutoLayer = () => {
9777
+ if (typeof window === "undefined" || typeof document === "undefined") return;
9778
+ const store = getStore();
9779
+ if (store[AUTO_LAYER_KEY]) return;
9780
+ store[AUTO_LAYER_KEY] = true;
9781
+ const handleElementOpen = (el) => {
9782
+ if (isSurfaceElement(el)) {
9783
+ let layerId = el.dataset.shuffleLayerId;
9784
+ if (!layerId) {
9785
+ layerId = "dom_" + Math.random().toString(36).substring(2, 9);
9786
+ el.dataset.shuffleLayerId = layerId;
9787
+ }
9788
+ const targetZ = allocateSurfaceLayer(layerId, el);
9789
+ el.dataset.shuffleLayerZ = String(targetZ);
9790
+ el.style.setProperty("z-index", String(targetZ), "important");
9791
+ const dialogContent = el.querySelector('[role="dialog"], [role="alertdialog"]');
9792
+ if (dialogContent && dialogContent !== el) {
9793
+ dialogContent.style.setProperty("z-index", String(targetZ), "important");
9794
+ }
9795
+ return;
9796
+ }
9797
+ if (isChildPopupElement(el)) {
9798
+ const topZ = getTopSurfaceZIndex();
9799
+ const popupZ = topZ + POPUP_OFFSET;
9800
+ el.dataset.shuffleLayerZ = String(popupZ);
9801
+ el.style.setProperty("z-index", String(popupZ), "important");
9802
+ return;
9803
+ }
9804
+ if (isTooltipElement(el)) {
9805
+ const topZ = getTopSurfaceZIndex();
9806
+ const tooltipZ = topZ + TOOLTIP_OFFSET;
9807
+ el.dataset.shuffleLayerZ = String(tooltipZ);
9808
+ el.style.setProperty("z-index", String(tooltipZ), "important");
9809
+ return;
9810
+ }
9811
+ };
9812
+ const handleElementClose = (el) => {
9813
+ const layerId = el.dataset.shuffleLayerId;
9814
+ if (layerId) {
9815
+ releaseOverlayLayer(layerId);
9816
+ delete el.dataset.shuffleLayerId;
9817
+ delete el.dataset.shuffleLayerZ;
9818
+ } else {
9819
+ releaseOverlayLayer(el);
9820
+ }
9821
+ };
9822
+ const scanNode = (node) => {
9823
+ if (!(node instanceof HTMLElement)) return;
9824
+ if (isSurfaceElement(node) || isChildPopupElement(node) || isTooltipElement(node)) {
9825
+ if (isElementOpen(node)) {
9826
+ handleElementOpen(node);
9827
+ } else {
9828
+ handleElementClose(node);
9829
+ }
9830
+ }
9831
+ const children2 = node.children;
9832
+ for (let i = 0; i < children2.length; i++) {
9833
+ const child = children2[i];
9834
+ if (child instanceof HTMLElement) {
9835
+ if (isSurfaceElement(child) || isChildPopupElement(child) || isTooltipElement(child)) {
9836
+ if (isElementOpen(child)) {
9837
+ handleElementOpen(child);
9838
+ } else {
9839
+ handleElementClose(child);
9840
+ }
9841
+ }
9842
+ }
9843
+ }
9844
+ };
9845
+ observerInstance = new MutationObserver((mutations) => {
9846
+ for (const m of mutations) {
9847
+ if (m.type === "childList") {
9848
+ m.addedNodes.forEach(scanNode);
9849
+ m.removedNodes.forEach((node) => {
9850
+ if (node instanceof HTMLElement) {
9851
+ handleElementClose(node);
9852
+ }
9853
+ });
9854
+ } else if (m.type === "attributes") {
9855
+ const target = m.target;
9856
+ if (target instanceof HTMLElement) {
9857
+ scanNode(target);
9858
+ }
9859
+ }
9860
+ }
9861
+ });
9862
+ const body = document.body;
9863
+ if (body) {
9864
+ observerInstance.observe(body, {
9865
+ childList: true,
9866
+ subtree: true,
9867
+ attributes: true,
9868
+ attributeFilter: ["class", "style", "aria-hidden", "data-state"]
9869
+ });
9870
+ Array.from(body.children).forEach(scanNode);
9871
+ }
9872
+ document.addEventListener(
9873
+ "pointerdown",
9874
+ (e) => {
9875
+ const target = e.target;
9876
+ if (!target) return;
9877
+ const surface = target.closest(
9878
+ '.MuiDialog-root, .MuiDrawer-root, .MuiModal-root:not(.MuiPopover-root):not(.MuiMenu-root), [role="dialog"], [role="alertdialog"]'
9879
+ );
9880
+ if (!surface || !surface.dataset.shuffleLayerId) return;
9881
+ const currentZ = Number(surface.dataset.shuffleLayerZ || 0);
9882
+ const topZ = getTopSurfaceZIndex();
9883
+ if (currentZ > 0 && currentZ < topZ) {
9884
+ const newZ = bringSurfaceToFront(surface.dataset.shuffleLayerId);
9885
+ surface.dataset.shuffleLayerZ = String(newZ);
9886
+ surface.style.setProperty("z-index", String(newZ), "important");
9887
+ }
9888
+ },
9889
+ true
9890
+ );
9891
+ };
9892
+ if (typeof window !== "undefined") {
9893
+ installGlobalOverlayAutoLayer();
9894
+ }
9683
9895
 
9684
9896
  // views/AppDetailDrawer.tsx
9685
9897
  var import_jsx_runtime17 = require("react/jsx-runtime");
@@ -10141,6 +10353,11 @@ var ShuffleMCP = import_react15.default.forwardRef(({
10141
10353
  const [isOpen, setIsOpen] = (0, import_react15.useState)(false);
10142
10354
  const [selectedIndex, setSelectedIndex] = (0, import_react15.useState)(-1);
10143
10355
  const [internalSelectedApps, setInternalSelectedApps] = (0, import_react15.useState)(selectedApps);
10356
+ (0, import_react15.useEffect)(() => {
10357
+ if (selectedApps) {
10358
+ setInternalSelectedApps(selectedApps);
10359
+ }
10360
+ }, [selectedApps]);
10144
10361
  const [authenticatedApps, setAuthenticatedApps] = (0, import_react15.useState)(externalAuthenticatedApps || []);
10145
10362
  const [authenticatedAppsLoading, setAuthenticatedAppsLoading] = (0, import_react15.useState)(!externalAuthenticatedApps);
10146
10363
  const [drawerApp, setDrawerApp] = (0, import_react15.useState)(null);
@@ -11325,6 +11542,7 @@ var AddAppDialog = ({
11325
11542
  maxLength = 1024,
11326
11543
  initialInput = ""
11327
11544
  }) => {
11545
+ const dialogZIndex = useOverlayLayer(open);
11328
11546
  const [input, setInput] = (0, import_react16.useState)(initialInput);
11329
11547
  const [stage, setStage] = (0, import_react16.useState)("idle");
11330
11548
  const [spec, setSpec] = (0, import_react16.useState)(null);
@@ -11491,6 +11709,12 @@ var AddAppDialog = ({
11491
11709
  onClose: () => onOpenChange(false),
11492
11710
  fullWidth: true,
11493
11711
  maxWidth: "sm",
11712
+ sx: {
11713
+ zIndex: dialogZIndex,
11714
+ "& .MuiBackdrop-root": {
11715
+ zIndex: dialogZIndex
11716
+ }
11717
+ },
11494
11718
  PaperProps: {
11495
11719
  sx: {
11496
11720
  maxWidth: 640,
@@ -11499,7 +11723,8 @@ var AddAppDialog = ({
11499
11723
  color: "hsl(var(--foreground))",
11500
11724
  border: "1px solid hsl(var(--border))",
11501
11725
  borderRadius: 2,
11502
- boxSizing: "border-box"
11726
+ boxSizing: "border-box",
11727
+ zIndex: dialogZIndex
11503
11728
  }
11504
11729
  },
11505
11730
  children: [
@@ -12548,6 +12773,8 @@ var AiAgentPromptsEditor = ({
12548
12773
  prompts,
12549
12774
  apps,
12550
12775
  readOnly = false,
12776
+ skillLabel,
12777
+ isBuiltInApp,
12551
12778
  onChangePrompt,
12552
12779
  onRemovePrompt,
12553
12780
  onAddPrompt,
@@ -12635,16 +12862,44 @@ var AiAgentPromptsEditor = ({
12635
12862
  ] }),
12636
12863
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.Box, { sx: { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, children: [
12637
12864
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12638
- import_material18.Typography,
12865
+ import_material18.Tooltip,
12639
12866
  {
12640
- sx: {
12641
- fontSize: "0.65rem",
12642
- fontWeight: 600,
12643
- color: "hsl(var(--muted-foreground))",
12644
- textTransform: "uppercase",
12645
- letterSpacing: "0.05em"
12646
- },
12647
- children: "Allowed apps"
12867
+ title: skillLabel ? `Allowed apps are shared with ${skillLabel} permissions. Changes made here apply to all automations and agent runs.` : "Apps this AI Agent prompt is permitted to run.",
12868
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.Box, { sx: { display: "inline-flex", alignItems: "center", gap: 0.75 }, children: [
12869
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12870
+ import_material18.Typography,
12871
+ {
12872
+ sx: {
12873
+ fontSize: "0.65rem",
12874
+ fontWeight: 600,
12875
+ color: "hsl(var(--muted-foreground))",
12876
+ textTransform: "uppercase",
12877
+ letterSpacing: "0.05em"
12878
+ },
12879
+ children: "Allowed apps"
12880
+ }
12881
+ ),
12882
+ skillLabel && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
12883
+ import_material18.Typography,
12884
+ {
12885
+ component: "span",
12886
+ sx: {
12887
+ fontSize: "0.62rem",
12888
+ fontWeight: 600,
12889
+ color: "hsl(var(--primary))",
12890
+ bgcolor: "hsl(var(--primary) / 0.1)",
12891
+ px: 0.6,
12892
+ py: 0.1,
12893
+ borderRadius: 0.75,
12894
+ letterSpacing: "0.02em"
12895
+ },
12896
+ children: [
12897
+ skillLabel,
12898
+ " permissions"
12899
+ ]
12900
+ }
12901
+ )
12902
+ ] })
12648
12903
  }
12649
12904
  ),
12650
12905
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.Box, { sx: { display: "flex", alignItems: "center", gap: 0.5, flexWrap: "wrap", flex: 1 }, children: [
@@ -12653,8 +12908,9 @@ var AiAgentPromptsEditor = ({
12653
12908
  const meta = resolveAppMeta(appKey);
12654
12909
  const displayName2 = meta.name;
12655
12910
  const img = meta.image || `https://shuffler.io/images/apps/${displayName2}.png`;
12911
+ const isBuiltIn = isBuiltInApp ? isBuiltInApp(appKey) : false;
12656
12912
  const clickable = !readOnly && !!onRemoveApp;
12657
- const tip = clickable ? `Remove ${displayName2.replace(/_/g, " ")}` : displayName2.replace(/_/g, " ");
12913
+ const tip = isBuiltIn ? `${displayName2.replace(/_/g, " ")} (Default built-in app for ${skillLabel || "skill"})` : clickable ? `Remove ${displayName2.replace(/_/g, " ")} (Assigned permission)` : displayName2.replace(/_/g, " ");
12658
12914
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Tooltip, { title: tip, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12659
12915
  import_material18.IconButton,
12660
12916
  {
@@ -12664,12 +12920,12 @@ var AiAgentPromptsEditor = ({
12664
12920
  sx: {
12665
12921
  width: 26,
12666
12922
  height: 26,
12667
- border: "1px solid hsl(var(--severity-low) / 0.3)",
12668
- bgcolor: "hsl(var(--severity-low) / 0.1)",
12923
+ border: isBuiltIn ? "1px solid hsl(var(--primary) / 0.35)" : "1px solid hsl(var(--severity-low) / 0.3)",
12924
+ bgcolor: isBuiltIn ? "hsl(var(--primary) / 0.08)" : "hsl(var(--severity-low) / 0.1)",
12669
12925
  borderRadius: 1,
12670
12926
  "&.Mui-disabled": {
12671
12927
  opacity: 1,
12672
- bgcolor: "hsl(var(--severity-low) / 0.1)"
12928
+ bgcolor: isBuiltIn ? "hsl(var(--primary) / 0.08)" : "hsl(var(--severity-low) / 0.1)"
12673
12929
  },
12674
12930
  "&:hover": clickable ? {
12675
12931
  bgcolor: "hsl(var(--destructive) / 0.15)",
@@ -12688,7 +12944,7 @@ var AiAgentPromptsEditor = ({
12688
12944
  }
12689
12945
  ) }, appKey);
12690
12946
  }),
12691
- !readOnly && onAddAppRequested && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Tooltip, { title: "Add allowed app", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12947
+ !readOnly && onAddAppRequested && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Tooltip, { title: skillLabel ? `Assign tools to ${skillLabel}` : "Add allowed app", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
12692
12948
  import_material18.IconButton,
12693
12949
  {
12694
12950
  size: "small",
@@ -13397,7 +13653,7 @@ var AGENT_PRESETS = [
13397
13653
  icon: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react11.ShieldAlert, { size: 16 }),
13398
13654
  enabled: true,
13399
13655
  tag: "Beta",
13400
- defaultApps: [{ name: "shuffle_incidents" }, { name: "shuffle_datastore" }]
13656
+ defaultApps: [{ name: "shuffle_incidents" }]
13401
13657
  },
13402
13658
  {
13403
13659
  id: "host-monitor-control",
@@ -13858,6 +14114,150 @@ var AgentPresets = ({ variant = "default", onSelectPreset, selectedPreset, onRem
13858
14114
  };
13859
14115
  var AgentPresets_default = AgentPresets;
13860
14116
 
14117
+ // ../lib/agentTools.ts
14118
+ var STORAGE_KEY3 = "agent_tools_config";
14119
+ var AGENT_TOOLS_CHANGED_EVENT = "agent-tools-changed";
14120
+ var DEFAULT_AGENT = "default";
14121
+ var DEFAULT_ACTION_TYPE = "timeline_reply";
14122
+ var getActiveOrgId = () => {
14123
+ if (typeof window === "undefined") return null;
14124
+ try {
14125
+ const raw = localStorage.getItem("shuffle_user_info") || localStorage.getItem("userinfo") || localStorage.getItem("user_info");
14126
+ if (!raw) return null;
14127
+ const parsed = JSON.parse(raw);
14128
+ return parsed?.active_org?.id || parsed?.org_id || parsed?.active_org_id || Array.isArray(parsed?.orgs) && parsed.orgs[0]?.id || parsed?.id || null;
14129
+ } catch {
14130
+ return null;
14131
+ }
14132
+ };
14133
+ var getStorageKey = (orgId) => {
14134
+ const resolved = orgId || getActiveOrgId();
14135
+ return resolved ? `${STORAGE_KEY3}_${resolved}` : STORAGE_KEY3;
14136
+ };
14137
+ var coerceTool = (raw) => {
14138
+ if (typeof raw === "string") {
14139
+ const trimmed = raw.trim();
14140
+ if (!trimmed) return null;
14141
+ return { name: trimmed, id: trimmed };
14142
+ }
14143
+ if (raw && typeof raw === "object") {
14144
+ const obj = raw;
14145
+ const name = typeof obj.name === "string" ? obj.name.trim() : "";
14146
+ const id = typeof obj.id === "string" && obj.id.trim() ? obj.id.trim() : name;
14147
+ if (!name) return null;
14148
+ return { name, id };
14149
+ }
14150
+ return null;
14151
+ };
14152
+ var sanitize2 = (parsed) => {
14153
+ let target = parsed;
14154
+ if (target && typeof target === "object" && !Array.isArray(target)) {
14155
+ const obj = target;
14156
+ if (Array.isArray(obj.entries)) {
14157
+ target = obj.entries;
14158
+ }
14159
+ }
14160
+ if (!Array.isArray(target)) return [];
14161
+ return target.filter((e) => e && typeof e.agent === "string" && typeof e.actionType === "string" && Array.isArray(e.tools)).map((e) => ({
14162
+ agent: e.agent,
14163
+ actionType: e.actionType,
14164
+ tools: e.tools.map(coerceTool).filter((t) => !!t),
14165
+ updatedAt: typeof e.updatedAt === "number" ? e.updatedAt : void 0
14166
+ }));
14167
+ };
14168
+ var extractUpdatedAt = (parsed) => {
14169
+ if (parsed && typeof parsed === "object") {
14170
+ const obj = parsed;
14171
+ if (typeof obj.updatedAt === "number") return obj.updatedAt;
14172
+ }
14173
+ return 0;
14174
+ };
14175
+ var readCacheRecord = () => {
14176
+ if (typeof window === "undefined") return { entries: [], updatedAt: 0 };
14177
+ try {
14178
+ const key = getStorageKey();
14179
+ let raw = localStorage.getItem(key);
14180
+ let parsed = null;
14181
+ let entries = [];
14182
+ let updatedAt = 0;
14183
+ if (raw) {
14184
+ try {
14185
+ parsed = JSON.parse(raw);
14186
+ entries = sanitize2(parsed);
14187
+ updatedAt = extractUpdatedAt(parsed) || entries.reduce((max, e) => Math.max(max, e.updatedAt || 0), 0);
14188
+ } catch {
14189
+ }
14190
+ }
14191
+ if (entries.length === 0 || entries.every((e) => e.tools.length === 0)) {
14192
+ if (key !== STORAGE_KEY3) {
14193
+ const fallbackRaw = localStorage.getItem(STORAGE_KEY3);
14194
+ if (fallbackRaw) {
14195
+ try {
14196
+ const fallbackParsed = JSON.parse(fallbackRaw);
14197
+ const fallbackEntries = sanitize2(fallbackParsed);
14198
+ if (fallbackEntries.some((e) => e.tools.length > 0)) {
14199
+ entries = fallbackEntries;
14200
+ updatedAt = extractUpdatedAt(fallbackParsed) || fallbackEntries.reduce((max, e) => Math.max(max, e.updatedAt || 0), 0) || Date.now();
14201
+ writeCache(entries, updatedAt);
14202
+ }
14203
+ } catch {
14204
+ }
14205
+ }
14206
+ }
14207
+ }
14208
+ return { entries, updatedAt };
14209
+ } catch {
14210
+ return { entries: [], updatedAt: 0 };
14211
+ }
14212
+ };
14213
+ var readAll = () => readCacheRecord().entries;
14214
+ var writeCache = (entries, explicitUpdatedAt) => {
14215
+ if (typeof window === "undefined") return;
14216
+ try {
14217
+ const updatedAt = explicitUpdatedAt ?? Date.now();
14218
+ const payload = {
14219
+ version: 1,
14220
+ updatedAt,
14221
+ entries
14222
+ };
14223
+ const serialized = JSON.stringify(payload);
14224
+ const orgKey = getStorageKey();
14225
+ localStorage.setItem(orgKey, serialized);
14226
+ if (orgKey !== STORAGE_KEY3) {
14227
+ localStorage.setItem(STORAGE_KEY3, serialized);
14228
+ }
14229
+ window.dispatchEvent(
14230
+ new CustomEvent(AGENT_TOOLS_CHANGED_EVENT, { detail: { updatedAt, entries } })
14231
+ );
14232
+ } catch {
14233
+ }
14234
+ };
14235
+ var getAgentTools = (agent = DEFAULT_AGENT, actionType = DEFAULT_ACTION_TYPE) => {
14236
+ const all = readAll();
14237
+ const entry = all.find((e) => e.agent === agent && e.actionType === actionType);
14238
+ if (entry && entry.tools && entry.tools.length > 0) {
14239
+ return entry.tools;
14240
+ }
14241
+ if (agent === "incident-handler" || agent === "incident-response" || agent === DEFAULT_AGENT) {
14242
+ const found = all.find(
14243
+ (e) => (e.agent === "incident-handler" || e.agent === "incident-response" || e.agent === DEFAULT_AGENT) && e.actionType === actionType && e.tools && e.tools.length > 0
14244
+ );
14245
+ if (found?.tools && found.tools.length > 0) return found.tools;
14246
+ }
14247
+ return [];
14248
+ };
14249
+ var getToolsForSkill = (skillOrPresetId) => {
14250
+ const normalized = (skillOrPresetId || "").toLowerCase().trim();
14251
+ if (normalized === "incident-handler" || normalized === "incident-response" || normalized === "default") {
14252
+ const ih = getAgentTools("incident-handler");
14253
+ if (ih.length > 0) return ih;
14254
+ const ir = getAgentTools("incident-response");
14255
+ if (ir.length > 0) return ir;
14256
+ return getAgentTools(DEFAULT_AGENT);
14257
+ }
14258
+ return getAgentTools(normalized);
14259
+ };
14260
+
13861
14261
  // useAgentPromptPrefix.ts
13862
14262
  var import_react20 = require("react");
13863
14263
  var AGENT_PROMPT_PREFIX_CATEGORY = "agent-prompt-prefix";
@@ -14078,6 +14478,9 @@ var runAgent = async (request) => {
14078
14478
  if (request.incidentId) {
14079
14479
  input.incident_id = request.incidentId;
14080
14480
  }
14481
+ if (request.incidentContext) {
14482
+ input.incident_context = request.incidentContext;
14483
+ }
14081
14484
  if (request.vulnerabilityId) {
14082
14485
  input.vulnerability_id = request.vulnerabilityId;
14083
14486
  }
@@ -14356,16 +14759,143 @@ var getCachedGroupDocs = (groupId, folder) => {
14356
14759
  }));
14357
14760
  };
14358
14761
 
14762
+ // ../lib/incidentPromptContext.ts
14763
+ var GLOBAL_INCIDENT_KEY = "__shuffleActiveIncidentContext";
14764
+ var getGlobalScope = () => {
14765
+ if (typeof globalThis !== "undefined") return globalThis;
14766
+ if (typeof window !== "undefined") return window;
14767
+ if (typeof global !== "undefined") return global;
14768
+ return null;
14769
+ };
14770
+ var getActiveIncidentPromptContext = () => {
14771
+ const scope = getGlobalScope();
14772
+ if (!scope) return null;
14773
+ const info = scope[GLOBAL_INCIDENT_KEY];
14774
+ if (info && typeof info === "object") {
14775
+ return info;
14776
+ }
14777
+ return null;
14778
+ };
14779
+ var INCIDENT_PROMPT_DELIMITER_START = "=== INCIDENT CONTEXT ===";
14780
+ var INCIDENT_PROMPT_DELIMITER_END = "=== END INCIDENT CONTEXT ===";
14781
+ var formatObservableType = (type) => {
14782
+ if (!type) return "Indicator";
14783
+ const clean = type.toLowerCase().trim();
14784
+ switch (clean) {
14785
+ case "ip":
14786
+ case "ipv4":
14787
+ case "ip_address":
14788
+ return "IPv4";
14789
+ case "ipv6":
14790
+ return "IPv6";
14791
+ case "hash":
14792
+ case "sha256":
14793
+ case "file_hash":
14794
+ return "SHA256";
14795
+ case "md5":
14796
+ return "MD5";
14797
+ case "sha1":
14798
+ return "SHA1";
14799
+ case "hostname":
14800
+ case "host":
14801
+ case "endpoint":
14802
+ return "Hostname";
14803
+ case "domain":
14804
+ return "Domain";
14805
+ case "url":
14806
+ return "URL";
14807
+ case "user":
14808
+ case "username":
14809
+ case "account":
14810
+ return "User";
14811
+ case "email":
14812
+ return "Email";
14813
+ case "process":
14814
+ case "process_name":
14815
+ return "Process";
14816
+ case "file":
14817
+ case "filename":
14818
+ return "File";
14819
+ default:
14820
+ return type.charAt(0).toUpperCase() + type.slice(1);
14821
+ }
14822
+ };
14823
+ var isIncidentInjectedPrompt = (prompt) => {
14824
+ if (!prompt || typeof prompt !== "string") return false;
14825
+ return prompt.includes(INCIDENT_PROMPT_DELIMITER_START) || prompt.includes("OPERATIONAL DIRECTIVES:") || prompt.includes("INCIDENT OBSERVABLES / IOCs:");
14826
+ };
14827
+ var extractCleanIncidentPrompt = (prompt) => {
14828
+ if (!prompt || typeof prompt !== "string") return "";
14829
+ const trimmed = prompt.trim();
14830
+ const taskMatch = trimmed.match(/TASK TO EXECUTE:\s*\n\s*-\s*Task:\s*([^\n]+)/i);
14831
+ if (taskMatch && taskMatch[1]?.trim()) {
14832
+ return `Task: ${taskMatch[1].trim()}`;
14833
+ }
14834
+ const legacyMatch = trimmed.match(/\n\s*Task:\s*([^\n]+)/i);
14835
+ if (legacyMatch && legacyMatch[1]?.trim()) {
14836
+ return `Task: ${legacyMatch[1].trim()}`;
14837
+ }
14838
+ if (trimmed.includes(INCIDENT_PROMPT_DELIMITER_START)) {
14839
+ const before = trimmed.split(INCIDENT_PROMPT_DELIMITER_START)[0]?.trim();
14840
+ if (before) return before;
14841
+ }
14842
+ return trimmed;
14843
+ };
14844
+ var composeIncidentPromptInput = (rawInput, context) => {
14845
+ if (!rawInput || typeof rawInput !== "string") return "";
14846
+ const trimmed = rawInput.trim();
14847
+ if (isIncidentInjectedPrompt(trimmed)) {
14848
+ return trimmed;
14849
+ }
14850
+ const ctx = context || getActiveIncidentPromptContext();
14851
+ if (!ctx || !ctx.id) {
14852
+ return trimmed;
14853
+ }
14854
+ const incidentRef = ctx.id ? `#${ctx.id}` : "";
14855
+ const incidentTitle = ctx.title?.trim() || "Incident";
14856
+ const severity = ctx.severity || "Medium";
14857
+ const status = ctx.status || "In Progress";
14858
+ const description = ctx.description?.trim() || "No description provided.";
14859
+ const seenObservables = /* @__PURE__ */ new Set();
14860
+ const formattedObservables = [];
14861
+ if (Array.isArray(ctx.observables)) {
14862
+ for (const obs of ctx.observables) {
14863
+ if (!obs || obs.archived || !obs.value?.trim()) continue;
14864
+ const val = obs.value.trim();
14865
+ const typeLabel = formatObservableType(obs.type);
14866
+ const key = `${typeLabel.toLowerCase()}:${val.toLowerCase()}`;
14867
+ if (seenObservables.has(key)) continue;
14868
+ seenObservables.add(key);
14869
+ formattedObservables.push(`- ${typeLabel}: ${val}`);
14870
+ }
14871
+ }
14872
+ const observablesBlock = formattedObservables.length > 0 ? formattedObservables.slice(0, 50).join("\n") : "- None recorded yet";
14873
+ return `${trimmed}
14874
+
14875
+ ${INCIDENT_PROMPT_DELIMITER_START}
14876
+ INCIDENT CONTEXT:
14877
+ - Incident: ${incidentRef} ("${incidentTitle}")
14878
+ - Severity: ${severity} | Status: ${status}
14879
+ - Summary: ${description}
14880
+
14881
+ INCIDENT OBSERVABLES / IOCs:
14882
+ ${observablesBlock}
14883
+ ${INCIDENT_PROMPT_DELIMITER_END}
14884
+
14885
+ DIRECTIVES:
14886
+ - Relevant incident details and observables are provided above. Do not call "get_incident" unless raw external logs are required.`;
14887
+ };
14888
+
14359
14889
  // ../lib/docsPromptContext.ts
14360
14890
  var GLOBAL_DOC_KEY = "__shuffleActiveDocInfo";
14361
- var getGlobalScope = () => {
14891
+ var getGlobalScope2 = () => {
14362
14892
  if (typeof globalThis !== "undefined") return globalThis;
14363
14893
  if (typeof window !== "undefined") return window;
14364
14894
  if (typeof global !== "undefined") return global;
14365
14895
  return null;
14366
14896
  };
14367
14897
  var getActiveDocPromptContext = () => {
14368
- const scope = getGlobalScope();
14898
+ const scope = getGlobalScope2();
14369
14899
  if (!scope) return null;
14370
14900
  const info = scope[GLOBAL_DOC_KEY];
14371
14901
  if (info && typeof info === "object") {
@@ -14406,6 +14936,9 @@ var isDocInjectedPrompt = (prompt) => {
14406
14936
  var extractCleanDisplayPrompt = (prompt) => {
14407
14937
  if (!prompt || typeof prompt !== "string") return "";
14408
14938
  const trimmed = prompt.trim();
14939
+ if (isIncidentInjectedPrompt(trimmed)) {
14940
+ return extractCleanIncidentPrompt(trimmed);
14941
+ }
14409
14942
  if (!isDocInjectedPrompt(trimmed)) return trimmed;
14410
14943
  if (trimmed.includes(DOC_PROMPT_DELIMITER_END)) {
14411
14944
  const parts = trimmed.split(DOC_PROMPT_DELIMITER_END);
@@ -14445,7 +14978,7 @@ var composeDocPromptInput = (userQuestion, pathname, fallbackTitle, overrideDocI
14445
14978
  return trimmedQuestion;
14446
14979
  }
14447
14980
  const activeDoc = overrideDocInfo ?? getActiveDocPromptContext();
14448
- const rawTitle = (activeDoc?.title || fallbackTitle || getGlobalScope()?.__shuffleActiveEntityTitle || "Shuffle documentation").trim();
14981
+ const rawTitle = (activeDoc?.title || fallbackTitle || getGlobalScope2()?.__shuffleActiveEntityTitle || "Shuffle documentation").trim();
14449
14982
  const title = normalizeDocPromptTitle(rawTitle);
14450
14983
  const groupLabel = activeDoc?.groupLabel;
14451
14984
  const groupId = activeDoc?.groupId;
@@ -17102,6 +17635,7 @@ var DEFAULT_AGENT_CONTEXT_RULES = [
17102
17635
  const cleanId = formatEntityDisplayId(params.id);
17103
17636
  return `Investigate incident ${cleanId} and recommend next steps: `;
17104
17637
  },
17638
+ composeInput: (raw) => composeIncidentPromptInput(raw),
17105
17639
  placeholder: "Ask about this incident, triage observables, or correlate...",
17106
17640
  getStorageKey: (params) => `incident_${params.id}`,
17107
17641
  description: "Focused on the currently viewed incident with Shuffle Incidents MCP"
@@ -17126,6 +17660,7 @@ var DEFAULT_AGENT_CONTEXT_RULES = [
17126
17660
  const cleanId = formatEntityDisplayId(params.id);
17127
17661
  return `Investigate incident ${cleanId} and recommend next steps: `;
17128
17662
  },
17663
+ composeInput: (raw) => composeIncidentPromptInput(raw),
17129
17664
  placeholder: "Ask about this incident, triage observables, or correlate...",
17130
17665
  getStorageKey: (params) => `incident_${params.id}`,
17131
17666
  description: "Focused on the currently viewed incident with Shuffle Incidents MCP"
@@ -17148,6 +17683,7 @@ var DEFAULT_AGENT_CONTEXT_RULES = [
17148
17683
  const cleanId = formatEntityDisplayId(params.id);
17149
17684
  return `Investigate case ${cleanId} and recommend next steps: `;
17150
17685
  },
17686
+ composeInput: (raw) => composeIncidentPromptInput(raw),
17151
17687
  placeholder: "Review case evidence, correlate events, or recommend response actions...",
17152
17688
  getStorageKey: (params) => `case_${params.id}`,
17153
17689
  description: "Focused on the currently viewed case with Shuffle Incidents MCP"
@@ -17878,6 +18414,18 @@ var readPresetAppsOverride = (presetId) => {
17878
18414
  return null;
17879
18415
  }
17880
18416
  };
18417
+ var resolvePresetApps = (preset) => {
18418
+ const baseApps = (preset.defaultApps || []).map((app2) => ({ name: app2.name, id: app2.id, icon: app2.icon }));
18419
+ const assigned = getToolsForSkill(preset.id);
18420
+ const merged = [...baseApps];
18421
+ for (const t of assigned) {
18422
+ const key = (t.id || t.name).toLowerCase();
18423
+ if (!merged.some((m) => (m.id || m.name).toLowerCase() === key)) {
18424
+ merged.push({ name: t.name, id: t.id, icon: t.icon || void 0 });
18425
+ }
18426
+ }
18427
+ return merged;
18428
+ };
17881
18429
  var writePresetAppsOverride = (presetId, apps) => {
17882
18430
  try {
17883
18431
  const raw = localStorage.getItem(PRESET_APPS_STORAGE_KEY);
@@ -18256,8 +18804,12 @@ var extractAuthRequest = (decision) => {
18256
18804
  } else if (raw && typeof raw === "object") {
18257
18805
  parsed = raw;
18258
18806
  }
18259
- const needsAuth = parsed && (parsed.action === "app_authentication" || parsed.app_authentication === true);
18260
- if (!needsAuth) return null;
18807
+ const candidateObjects = [
18808
+ parsed,
18809
+ decision?.result,
18810
+ decision?.run_details,
18811
+ decision
18812
+ ].filter(Boolean);
18261
18813
  let toolAppName;
18262
18814
  let appId = null;
18263
18815
  if (typeof decision?.tool === "string") {
@@ -18270,8 +18822,36 @@ var extractAuthRequest = (decision) => {
18270
18822
  toolAppName = t;
18271
18823
  }
18272
18824
  }
18273
- let appName = parsed.app || parsed.app_name || parsed.appname;
18274
- if (!appName) appName = toolAppName;
18825
+ let needsAuth = false;
18826
+ let candidateAppName;
18827
+ for (const obj of candidateObjects) {
18828
+ if (obj.action === "app_authentication" || obj.app_authentication === true || obj.action === "authenticate" || obj.needs_auth === true || obj.auth_required === true) {
18829
+ needsAuth = true;
18830
+ }
18831
+ const candidate = obj.app || obj.app_name || obj.appname;
18832
+ if (typeof candidate === "string" && candidate.trim()) {
18833
+ candidateAppName = candidate.trim();
18834
+ }
18835
+ }
18836
+ const textSources = [
18837
+ decision?.error,
18838
+ decision?.reason,
18839
+ decision?.status_message,
18840
+ decision?.message,
18841
+ decision?.run_details?.error,
18842
+ typeof raw === "string" ? raw : ""
18843
+ ];
18844
+ const combinedText = textSources.filter(Boolean).join(" ").toLowerCase();
18845
+ if (combinedText.includes("app_authentication") || combinedText.includes("requires authentication") || combinedText.includes("missing authentication") || combinedText.includes("unauthorized") || combinedText.includes("not authenticated") || combinedText.includes("invalid credentials") || combinedText.includes("missing api key")) {
18846
+ needsAuth = true;
18847
+ }
18848
+ if (!needsAuth && (decision?.status === "WAITING" || decision?.status === "PENDING" || decision?.run_details?.status === "WAITING" || decision?.run_details?.status === "PENDING")) {
18849
+ if (toolAppName && appRequiresAuthentication(toolAppName)) {
18850
+ needsAuth = true;
18851
+ }
18852
+ }
18853
+ if (!needsAuth) return null;
18854
+ let appName = candidateAppName || toolAppName;
18275
18855
  if (!appName) {
18276
18856
  const f = (decision?.fields || []).find((x) => x?.key === "app" || x?.key === "app_name");
18277
18857
  if (f?.value) appName = f.value;
@@ -18286,12 +18866,17 @@ var STATUS_COLORS = {
18286
18866
  running: "hsl(var(--primary))"
18287
18867
  };
18288
18868
  var TERMINAL_RUN_STATUSES = ["FINISHED", "FAILURE", "ABORTED", "CANCELLED", "CANCELED"];
18289
- var resolveRunStatus = (executionStatus, agentStatus) => {
18290
- const exec = String(executionStatus || "").toUpperCase();
18291
- const agent = String(agentStatus || "").toUpperCase();
18292
- if (TERMINAL_RUN_STATUSES.includes(exec)) return exec;
18293
- if (TERMINAL_RUN_STATUSES.includes(agent)) return agent;
18294
- return exec || agent || "";
18869
+ var resolveRunStatus = (execStatus, agentStatus) => {
18870
+ const e = (execStatus || "").toUpperCase();
18871
+ const a = (agentStatus || "").toUpperCase();
18872
+ if (e === "FINISHED" || a === "FINISHED") return "FINISHED";
18873
+ if (e === "FAILURE" || a === "FAILURE") return "FAILURE";
18874
+ if (e === "ABORTED" || a === "ABORTED") return "ABORTED";
18875
+ if (e === "CANCELLED" || a === "CANCELLED" || e === "CANCELED" || a === "CANCELED") return "CANCELLED";
18876
+ if (e === "WAITING" || a === "WAITING") return "WAITING";
18877
+ if (e === "PENDING" || a === "PENDING") return "PENDING";
18878
+ if (e === "RUNNING" || a === "RUNNING" || e === "EXECUTING" || a === "EXECUTING") return "RUNNING";
18879
+ return e || a || "FINISHED";
18295
18880
  };
18296
18881
  var buildToolName = (apps) => {
18297
18882
  if (!apps.length) return "API";
@@ -18315,7 +18900,11 @@ var DurationCountdown = ({ resumeAtMs }) => {
18315
18900
  const remaining = resumeAtMs - nowMs;
18316
18901
  return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Tooltip, { title: `Scheduled to continue at ${new Date(resumeAtMs).toLocaleString()}`, arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Box, { component: "span", sx: { whiteSpace: "nowrap", cursor: "default" }, children: remaining > 0 ? `in ${formatTimeLeft(remaining)}` : "due now" }) });
18317
18902
  };
18318
- var StatusIcon = ({ status, resumeAtMs }) => {
18903
+ var StatusIcon = ({
18904
+ status,
18905
+ resumeAtMs,
18906
+ authBlockedApp
18907
+ }) => {
18319
18908
  const s = (status || "").toUpperCase();
18320
18909
  const isScheduledWait = s === "WAITING" && !!resumeAtMs;
18321
18910
  const [nowMs, setNowMs] = (0, import_react24.useState)(() => Date.now());
@@ -18326,7 +18915,10 @@ var StatusIcon = ({ status, resumeAtMs }) => {
18326
18915
  }, [isScheduledWait]);
18327
18916
  let node;
18328
18917
  let label;
18329
- if (s === "RUNNING" || s === "EXECUTING" || s === "") {
18918
+ if (authBlockedApp) {
18919
+ node = /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react15.Lock, { size: 20, color: "hsl(var(--destructive))" });
18920
+ label = `Authentication required for ${formatAppDisplayName(authBlockedApp)} \u2014 step cannot proceed until connected`;
18921
+ } else if (s === "RUNNING" || s === "EXECUTING" || s === "") {
18330
18922
  node = /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.CircularProgress, { size: 18, sx: { color: STATUS_COLORS.running } });
18331
18923
  label = "Running";
18332
18924
  } else if (s === "WAITING") {
@@ -18525,8 +19117,10 @@ var TimelineRow = ({
18525
19117
  const s = (effectiveStatus || "").toUpperCase();
18526
19118
  return s === "WAITING" || s === "RUNNING" || s === "EXECUTING" || s === "";
18527
19119
  })();
18528
- const barColor = isProcessing ? "hsl(var(--muted-foreground) / 0.45)" : isFailed ? STATUS_COLORS.error : "hsl(var(--muted-foreground) / 0.35)";
18529
- const hoverBarColor = isProcessing ? "hsl(var(--muted-foreground) / 0.45)" : effectiveStatus === "FINISHED" || effectiveStatus === "IGNORED" ? STATUS_COLORS.finished : isFailed ? STATUS_COLORS.error : STATUS_COLORS.running;
19120
+ const rowAuthReq = extractAuthRequest(details);
19121
+ const isRowAuthBlocked = !!rowAuthReq && !isAppAuthenticated?.(rowAuthReq.appName, rowAuthReq.appId) && (effectiveStatus === "WAITING" || effectiveStatus === "PENDING" || effectiveStatus === "FAILURE" || effectiveStatus === "ABORTED");
19122
+ const barColor = isProcessing ? "hsl(var(--muted-foreground) / 0.45)" : isFailed || isRowAuthBlocked ? STATUS_COLORS.error : "hsl(var(--muted-foreground) / 0.35)";
19123
+ const hoverBarColor = isProcessing ? "hsl(var(--muted-foreground) / 0.45)" : effectiveStatus === "FINISHED" || effectiveStatus === "IGNORED" ? STATUS_COLORS.finished : isFailed || isRowAuthBlocked ? STATUS_COLORS.error : STATUS_COLORS.running;
18530
19124
  const isRerunTarget = !!rerunningDecisionId && item.type === "decision" && details?.run_details?.id === rerunningDecisionId;
18531
19125
  return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
18532
19126
  import_material26.Box,
@@ -18535,9 +19129,25 @@ var TimelineRow = ({
18535
19129
  sx: {
18536
19130
  borderTop: index === 0 ? "none" : "1px solid hsl(var(--border))",
18537
19131
  bgcolor: highlight ? "hsla(var(--severity-medium) / 0.12)" : isRerunTarget ? "hsla(var(--primary) / 0.08)" : open ? "hsl(var(--muted) / 0.3)" : "transparent",
18538
- transition: "background 0.6s ease, box-shadow 0.6s ease, opacity 0.2s ease",
18539
- scrollMarginTop: 96,
19132
+ transition: "background-color 0.2s ease",
19133
+ "&:hover": {
19134
+ bgcolor: "hsl(var(--muted) / 0.4)"
19135
+ },
18540
19136
  position: "relative",
19137
+ "&::before": {
19138
+ content: '""',
19139
+ position: "absolute",
19140
+ left: 0,
19141
+ top: 0,
19142
+ bottom: 0,
19143
+ width: 3,
19144
+ bgcolor: barColor,
19145
+ transition: "background-color 0.15s ease"
19146
+ },
19147
+ "&:hover::before": {
19148
+ bgcolor: hoverBarColor
19149
+ },
19150
+ scrollMarginTop: 96,
18541
19151
  boxShadow: highlight ? "inset 0 0 0 2px hsla(var(--severity-medium) / 0.55)" : isRerunTarget ? "inset 0 0 0 1px hsla(var(--primary) / 0.5)" : "none",
18542
19152
  opacity: dimmedByRerun ? 0.35 : 1,
18543
19153
  pointerEvents: dimmedByRerun ? "none" : "auto"
@@ -18546,22 +19156,17 @@ var TimelineRow = ({
18546
19156
  /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
18547
19157
  import_material26.Box,
18548
19158
  {
18549
- onClick: isProcessing ? void 0 : onToggle,
19159
+ onClick: onToggle,
18550
19160
  sx: {
18551
19161
  display: "flex",
18552
19162
  alignItems: "center",
18553
19163
  gap: 1.5,
18554
- px: 2,
18555
- py: 1.25,
18556
- cursor: isProcessing ? "default" : "pointer",
18557
- "--timeline-bar-color": barColor,
18558
- "&:hover": isProcessing ? {} : {
18559
- bgcolor: "hsl(var(--muted) / 0.4)",
18560
- "--timeline-bar-color": hoverBarColor
18561
- }
19164
+ p: 1.5,
19165
+ cursor: "pointer",
19166
+ userSelect: "none"
18562
19167
  },
18563
19168
  children: [
18564
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Box, { sx: { width: 24, display: "flex", justifyContent: "center" }, children: isRerunTarget ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.CircularProgress, { size: 14, sx: { color: "hsl(var(--primary))" } }) : isProcessing ? isLikelyTimedOut ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Tooltip, { title: "No new activity for over a minute \u2014 this run has most likely timed out.", arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Box, { sx: { display: "flex" }, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react15.AlertTriangle, { size: 14, color: STATUS_COLORS.warning }) }) }) : isLiveProcessing ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.CircularProgress, { size: 12, sx: { color: "hsl(var(--muted-foreground))" } }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Box, { sx: { width: 6, height: 6, borderRadius: "50%", bgcolor: "hsl(var(--muted-foreground) / 0.5)" } }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(StatusIcon, { status: effectiveStatus, resumeAtMs: scheduledResumeMs }) }),
19169
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Box, { sx: { width: 24, display: "flex", justifyContent: "center" }, children: isRerunTarget ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.CircularProgress, { size: 14, sx: { color: "hsl(var(--primary))" } }) : isProcessing ? isLikelyTimedOut ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Tooltip, { title: "No new activity for over a minute \u2014 this run has most likely timed out.", arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Box, { sx: { display: "flex" }, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react15.AlertTriangle, { size: 14, color: STATUS_COLORS.warning }) }) }) : isLiveProcessing ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.CircularProgress, { size: 12, sx: { color: "hsl(var(--muted-foreground))" } }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Box, { sx: { width: 6, height: 6, borderRadius: "50%", bgcolor: "hsl(var(--muted-foreground) / 0.5)" } }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(StatusIcon, { status: effectiveStatus, resumeAtMs: scheduledResumeMs, authBlockedApp: isRowAuthBlocked ? rowAuthReq.appName : null }) }),
18565
19170
  /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Box, { sx: { width: 24, display: "flex", justifyContent: "center" }, children: isProcessing ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Box, { sx: { width: 22 } }) : toolApp?.icon ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Tooltip, { title: (toolApp.name || "").replace(/_/g, " "), arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Avatar, { src: toolApp.icon, sx: { width: 22, height: 22, bgcolor: "transparent" }, variant: "rounded" }) }) : item.category === "finalise" || details?.action === "finish" ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Tooltip, { title: "Final answer", arrow: true, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react15.Check, { size: 18 }) }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Box, { sx: { width: 22 } }) }),
18566
19171
  /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
18567
19172
  import_material26.Tooltip,
@@ -19080,6 +19685,7 @@ var AgentUI = ({
19080
19685
  composeSubmitInput: propComposeSubmitInput,
19081
19686
  contextParams,
19082
19687
  incidentId: propIncidentId,
19688
+ incidentContext: propIncidentContext,
19083
19689
  vulnerabilityId: propVulnerabilityId,
19084
19690
  workflowId: propWorkflowId
19085
19691
  }) => {
@@ -19094,6 +19700,10 @@ var AgentUI = ({
19094
19700
  return h;
19095
19701
  }, [apiKey, orgId]);
19096
19702
  const hasApiKey = !!apiKey || !!API_CONFIG.apiKey;
19703
+ const resolvedIncidentId = propIncidentId || (contextCategory === "incidents" ? contextParams?.id : void 0) || (typeof window !== "undefined" ? window.__shuffleActiveIncidentId : void 0);
19704
+ const resolvedIncidentContext = propIncidentContext || (typeof window !== "undefined" ? window.__shuffleActiveIncidentContext : void 0);
19705
+ const resolvedVulnerabilityId = propVulnerabilityId || (contextCategory === "vulnerabilities" ? contextParams?.id : void 0) || (typeof window !== "undefined" ? window.__shuffleActiveVulnerabilityId : void 0);
19706
+ const resolvedWorkflowId = propWorkflowId || (contextCategory === "workflows" ? contextParams?.id : void 0) || (typeof window !== "undefined" ? window.__shuffleActiveWorkflowId : void 0);
19097
19707
  const isPhoneScreen = (0, import_material26.useMediaQuery)("(max-width:600px)", { noSsr: true });
19098
19708
  const isPhone = mobileView !== void 0 ? mobileView : isPhoneScreen;
19099
19709
  const [actionInput, setActionInput] = (0, import_react24.useState)(() => {
@@ -19174,17 +19784,37 @@ var AgentUI = ({
19174
19784
  if (!match || match.enabled === false) return;
19175
19785
  setSelectedPreset(match);
19176
19786
  if (defaultApps === void 0 && !apps) {
19787
+ const resolved = resolvePresetApps(match);
19177
19788
  const override = readPresetAppsOverride(match.id);
19178
- if (override) {
19179
- setChosenApps(override);
19180
- } else if (match.defaultApps && match.defaultApps.length > 0) {
19181
- setChosenApps(match.defaultApps.map((app2) => ({ name: app2.name, id: app2.id, icon: app2.icon })));
19789
+ if (override && override.length > 0) {
19790
+ const merged = [...override];
19791
+ for (const app2 of resolved) {
19792
+ const key = (app2.id || app2.name).toLowerCase();
19793
+ if (!merged.some((m) => (m.id || m.name).toLowerCase() === key)) {
19794
+ merged.push(app2);
19795
+ }
19796
+ }
19797
+ setChosenApps(merged);
19798
+ } else {
19799
+ setChosenApps(resolved);
19182
19800
  }
19183
19801
  }
19184
19802
  seededPresetIdRef.current = match.id;
19185
19803
  } catch {
19186
19804
  }
19187
19805
  }, [presets, defaultInput, isEffectiveSupport, initialPresetId, defaultApps, apps]);
19806
+ (0, import_react24.useEffect)(() => {
19807
+ const handleToolsChanged = () => {
19808
+ const targetPreset = selectedPreset || AGENT_PRESETS.find((p) => p.id === "incident-response") || AGENT_PRESETS[0];
19809
+ if (targetPreset) {
19810
+ const next = resolvePresetApps(targetPreset);
19811
+ setChosenApps(next);
19812
+ writePresetAppsOverride(targetPreset.id, next);
19813
+ }
19814
+ };
19815
+ window.addEventListener(AGENT_TOOLS_CHANGED_EVENT, handleToolsChanged);
19816
+ return () => window.removeEventListener(AGENT_TOOLS_CHANGED_EVENT, handleToolsChanged);
19817
+ }, [selectedPreset]);
19188
19818
  (0, import_react24.useLayoutEffect)(() => {
19189
19819
  if (hidePresets) {
19190
19820
  setPresetsChipWidth(0);
@@ -19462,13 +20092,19 @@ var AgentUI = ({
19462
20092
  localStorage.setItem(LAST_PRESET_STORAGE_KEY, preset.id);
19463
20093
  } catch {
19464
20094
  }
20095
+ const resolved = resolvePresetApps(preset);
19465
20096
  const override = readPresetAppsOverride(preset.id);
19466
20097
  if (override && override.length > 0) {
19467
- setChosenApps(override);
19468
- } else if (preset.defaultApps && preset.defaultApps.length > 0) {
19469
- setChosenApps(preset.defaultApps.map((app2) => ({ name: app2.name, id: app2.id, icon: app2.icon })));
20098
+ const merged = [...override];
20099
+ for (const app2 of resolved) {
20100
+ const key = (app2.id || app2.name).toLowerCase();
20101
+ if (!merged.some((m) => (m.id || m.name).toLowerCase() === key)) {
20102
+ merged.push(app2);
20103
+ }
20104
+ }
20105
+ setChosenApps(merged);
19470
20106
  } else {
19471
- setChosenApps([]);
20107
+ setChosenApps(resolved);
19472
20108
  }
19473
20109
  seededPresetIdRef.current = preset.id;
19474
20110
  if (onSelectPreset) {
@@ -19686,9 +20322,9 @@ var AgentUI = ({
19686
20322
  }, [availableApps]);
19687
20323
  const pendingAuthApps = (0, import_react24.useMemo)(() => {
19688
20324
  if (authAppsLoading) return [];
19689
- const decisions = agentData?.decisions || [];
19690
20325
  const seen = /* @__PURE__ */ new Set();
19691
20326
  const out = [];
20327
+ const decisions = agentData?.decisions || [];
19692
20328
  for (const d of decisions) {
19693
20329
  const req = extractAuthRequest(d);
19694
20330
  if (!req) continue;
@@ -19700,8 +20336,21 @@ var AgentUI = ({
19700
20336
  const icon = appsById[req.appName]?.icon || appsById[slug]?.icon || (appId ? appsById[appId]?.icon : "") || "";
19701
20337
  out.push({ appName: req.appName, appId, icon });
19702
20338
  }
20339
+ const hasAllowed = Array.isArray(agentData?.allowed_actions) && agentData.allowed_actions.length > 0;
20340
+ const activeAppList = hasAllowed ? executionApps : chosenApps;
20341
+ for (const app2 of activeAppList) {
20342
+ if (!app2?.name) continue;
20343
+ const slug = normalizeAgentAppName(app2.name);
20344
+ if (seen.has(slug)) continue;
20345
+ if (appRequiresAuthentication(slug) && !isAppAuthenticated(app2.name, app2.id || null)) {
20346
+ seen.add(slug);
20347
+ const appId = app2.id || appsById[app2.name]?.id || appsById[slug]?.id || null;
20348
+ const icon = app2.icon || appsById[app2.name]?.icon || appsById[slug]?.icon || (appId ? appsById[appId]?.icon : "") || "";
20349
+ out.push({ appName: app2.name, appId, icon });
20350
+ }
20351
+ }
19703
20352
  return out;
19704
- }, [agentData, appsById, authAppsLoading, isAppAuthenticated]);
20353
+ }, [agentData, executionApps, chosenApps, appsById, authAppsLoading, isAppAuthenticated]);
19705
20354
  (0, import_react24.useEffect)(() => {
19706
20355
  if (apps) setChosenApps(apps);
19707
20356
  }, [apps]);
@@ -20316,9 +20965,6 @@ var AgentUI = ({
20316
20965
  return next;
20317
20966
  }, { replace: true });
20318
20967
  }
20319
- const resolvedIncidentId = propIncidentId || (contextCategory === "incidents" ? contextParams?.id : void 0) || (typeof window !== "undefined" ? window.__shuffleActiveIncidentId : void 0);
20320
- const resolvedVulnerabilityId = propVulnerabilityId || (contextCategory === "vulnerabilities" ? contextParams?.id : void 0) || (typeof window !== "undefined" ? window.__shuffleActiveVulnerabilityId : void 0);
20321
- const resolvedWorkflowId = propWorkflowId || (contextCategory === "workflows" ? contextParams?.id : void 0) || (typeof window !== "undefined" ? window.__shuffleActiveWorkflowId : void 0);
20322
20968
  const result = await runAgent({
20323
20969
  input: composed.trim(),
20324
20970
  skipPolling: true,
@@ -20327,6 +20973,7 @@ var AgentUI = ({
20327
20973
  ...apiBaseUrl ? { apiBaseUrl } : {},
20328
20974
  ...orgId ? { orgId } : {},
20329
20975
  ...resolvedIncidentId ? { incidentId: resolvedIncidentId } : {},
20976
+ ...resolvedIncidentContext ? { incidentContext: resolvedIncidentContext } : {},
20330
20977
  ...resolvedVulnerabilityId ? { vulnerabilityId: resolvedVulnerabilityId } : {},
20331
20978
  ...resolvedWorkflowId ? { workflowId: resolvedWorkflowId } : {},
20332
20979
  // Send a single comma-separated `tool_name` in the format
@@ -20397,6 +21044,13 @@ var AgentUI = ({
20397
21044
  const auth = raw?.authorization;
20398
21045
  if (eid && auth) {
20399
21046
  activeExecutionIdRef.current = eid;
21047
+ if (typeof window !== "undefined") {
21048
+ window.dispatchEvent(
21049
+ new CustomEvent("shuffle:agent_execution_status", {
21050
+ detail: { executionId: eid, status: "running", incidentId: resolvedIncidentId }
21051
+ })
21052
+ );
21053
+ }
20400
21054
  if (contextStorageKey) {
20401
21055
  setPageContextChoice(contextStorageKey, {
20402
21056
  draftPrompt: "",
@@ -20984,17 +21638,30 @@ var AgentUI = ({
20984
21638
  if (status === "FINISHED" || status === "SUCCESS") {
20985
21639
  window.dispatchEvent(
20986
21640
  new CustomEvent("shuffle:agent_execution_status", {
20987
- detail: { executionId: eid, status: "completed" }
21641
+ detail: { executionId: eid, status: "completed", incidentId: resolvedIncidentId }
20988
21642
  })
20989
21643
  );
21644
+ if (resolvedIncidentId) {
21645
+ window.dispatchEvent(
21646
+ new CustomEvent("incident:refresh", {
21647
+ detail: { id: resolvedIncidentId, incidentId: resolvedIncidentId, executionId: eid }
21648
+ })
21649
+ );
21650
+ }
20990
21651
  } else if (["FAILURE", "ABORTED", "CANCELLED", "CANCELED"].includes(status)) {
20991
21652
  window.dispatchEvent(
20992
21653
  new CustomEvent("shuffle:agent_execution_status", {
20993
- detail: { executionId: eid, status: "failed" }
21654
+ detail: { executionId: eid, status: "failed", incidentId: resolvedIncidentId }
21655
+ })
21656
+ );
21657
+ } else if (["RUNNING", "EXECUTING", "IN_PROGRESS", "WAITING"].includes(status)) {
21658
+ window.dispatchEvent(
21659
+ new CustomEvent("shuffle:agent_execution_status", {
21660
+ detail: { executionId: eid, status: "running", incidentId: resolvedIncidentId }
20994
21661
  })
20995
21662
  );
20996
21663
  }
20997
- }, [execution?.execution_id, execution?.status, agentData?.status]);
21664
+ }, [execution?.execution_id, execution?.status, agentData?.status, resolvedIncidentId]);
20998
21665
  (0, import_react24.useEffect)(() => {
20999
21666
  if (!finishDecisionId || agentRequestLoading) return;
21000
21667
  if (continuationFocusedForRef.current === finishDecisionId) return;
@@ -23192,7 +23859,47 @@ var AgentUI = ({
23192
23859
  children: formatAppDisplayName(app2.name || "")
23193
23860
  }
23194
23861
  ),
23195
- (needsAuth || isUnavailable) && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react15.AlertTriangle, { size: 14, color: "hsl(var(--severity-medium))", style: { marginRight: 2 } }),
23862
+ needsAuth ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
23863
+ import_material26.Box,
23864
+ {
23865
+ component: "span",
23866
+ sx: {
23867
+ fontSize: "0.65rem",
23868
+ fontWeight: 600,
23869
+ color: "hsl(var(--destructive))",
23870
+ bgcolor: "hsl(var(--destructive) / 0.12)",
23871
+ border: "1px solid hsl(var(--destructive) / 0.3)",
23872
+ borderRadius: 1,
23873
+ px: 0.6,
23874
+ py: 0.1,
23875
+ letterSpacing: "0.02em",
23876
+ textTransform: "uppercase",
23877
+ ml: 0.5,
23878
+ mr: 0.25
23879
+ },
23880
+ children: "Missing auth"
23881
+ }
23882
+ ) : isUnavailable ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
23883
+ import_material26.Box,
23884
+ {
23885
+ component: "span",
23886
+ sx: {
23887
+ fontSize: "0.65rem",
23888
+ fontWeight: 600,
23889
+ color: "hsl(var(--severity-medium))",
23890
+ bgcolor: "hsl(var(--severity-medium) / 0.12)",
23891
+ border: "1px solid hsl(var(--severity-medium) / 0.3)",
23892
+ borderRadius: 1,
23893
+ px: 0.6,
23894
+ py: 0.1,
23895
+ letterSpacing: "0.02em",
23896
+ textTransform: "uppercase",
23897
+ ml: 0.5,
23898
+ mr: 0.25
23899
+ },
23900
+ children: "Unavailable"
23901
+ }
23902
+ ) : null,
23196
23903
  isRequired ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
23197
23904
  import_lucide_react15.Lock,
23198
23905
  {
@@ -23394,43 +24101,83 @@ var AgentUI = ({
23394
24101
  return list;
23395
24102
  })().map((app2, i) => {
23396
24103
  const slug = normalizeAgentAppName(app2.name || "");
24104
+ const appNeedsAuth = !authAppsLoading && appRequiresAuthentication(slug) && !isAppAuthenticated(app2.name || "", app2.id || null);
23397
24105
  const appIcon = app2.icon || availableApps.find((a) => normalizeAgentAppName(a.name || "") === slug)?.icon || resolvedToolApps[slug]?.icon;
23398
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Tooltip, { title: formatAppDisplayName(app2.name || ""), children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
23399
- import_material26.Box,
24106
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
24107
+ import_material26.Tooltip,
23400
24108
  {
23401
- onClick: () => setAuthDrawerApp({ name: app2.name, id: app2.id || null }),
23402
- sx: {
23403
- display: "inline-flex",
23404
- alignItems: "center",
23405
- justifyContent: "center",
23406
- width: 24,
23407
- height: 24,
23408
- borderRadius: "6px",
23409
- overflow: "hidden",
23410
- bgcolor: "hsl(var(--muted))",
23411
- cursor: "pointer",
23412
- transition: "transform 0.15s ease, border-color 0.15s ease",
23413
- "&:hover": { transform: "scale(1.08)", borderColor: "hsl(var(--primary)) !important" }
23414
- },
24109
+ title: appNeedsAuth ? `${formatAppDisplayName(app2.name || "")} \u2014 Missing authentication (Click to connect)` : formatAppDisplayName(app2.name || ""),
23415
24110
  children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
23416
- AppFallbackIcon,
24111
+ import_material26.Box,
23417
24112
  {
23418
- name: app2.name,
23419
- imageUrl: appIcon,
23420
- size: 24,
23421
- style: { borderRadius: 6, objectFit: "contain" }
24113
+ onClick: () => setAuthDrawerApp({ name: app2.name, id: app2.id || null }),
24114
+ sx: {
24115
+ display: "inline-flex",
24116
+ alignItems: "center",
24117
+ justifyContent: "center",
24118
+ width: 24,
24119
+ height: 24,
24120
+ borderRadius: "6px",
24121
+ overflow: "hidden",
24122
+ bgcolor: "hsl(var(--muted))",
24123
+ cursor: "pointer",
24124
+ transition: "transform 0.15s ease, border-color 0.15s ease",
24125
+ border: appNeedsAuth ? "2px solid hsl(var(--destructive)) !important" : "none",
24126
+ boxShadow: appNeedsAuth ? "0 0 0 1px hsl(var(--destructive) / 0.4)" : "none",
24127
+ "&:hover": { transform: "scale(1.08)", borderColor: "hsl(var(--primary)) !important" }
24128
+ },
24129
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
24130
+ AppFallbackIcon,
24131
+ {
24132
+ name: app2.name,
24133
+ imageUrl: appIcon,
24134
+ size: 24,
24135
+ style: { borderRadius: 6, objectFit: "contain" }
24136
+ }
24137
+ )
23422
24138
  }
23423
24139
  )
23424
- }
23425
- ) }, i);
24140
+ },
24141
+ i
24142
+ );
23426
24143
  }) }),
23427
24144
  /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material26.Box, { sx: { flex: 1, minWidth: 0 }, children: [
23428
24145
  /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Typography, { sx: { fontSize: "0.85rem", color: "hsl(var(--foreground))", fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: extractCleanDisplayPrompt(agentData?.original_input) || actionInput || "Agent run" }),
23429
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material26.Typography, { sx: { fontSize: "0.7rem", color: "hsl(var(--muted-foreground))" }, children: [
23430
- "Status: ",
23431
- execution?.status || agentData?.status || "\u2014",
23432
- " \xB7 ",
23433
- execution?.execution_id?.slice(0, 8) || ""
24146
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material26.Typography, { sx: { fontSize: "0.7rem", color: "hsl(var(--muted-foreground))", display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap", mt: 0.25 }, children: [
24147
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("span", { children: [
24148
+ "Status: ",
24149
+ execution?.status || agentData?.status || "\u2014",
24150
+ " \xB7 ",
24151
+ execution?.execution_id?.slice(0, 8) || ""
24152
+ ] }),
24153
+ pendingAuthApps.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
24154
+ import_material26.Box,
24155
+ {
24156
+ component: "span",
24157
+ onClick: () => setAuthDrawerApp({ name: pendingAuthApps[0].appName, id: pendingAuthApps[0].appId }),
24158
+ sx: {
24159
+ display: "inline-flex",
24160
+ alignItems: "center",
24161
+ gap: 0.5,
24162
+ px: 0.75,
24163
+ py: 0.15,
24164
+ borderRadius: 1,
24165
+ bgcolor: "hsl(var(--destructive) / 0.12)",
24166
+ border: "1px solid hsl(var(--destructive) / 0.35)",
24167
+ color: "hsl(var(--destructive))",
24168
+ fontSize: "0.68rem",
24169
+ fontWeight: 600,
24170
+ cursor: "pointer",
24171
+ textTransform: "none",
24172
+ "&:hover": { bgcolor: "hsl(var(--destructive) / 0.2)" }
24173
+ },
24174
+ children: [
24175
+ "Missing Auth: ",
24176
+ pendingAuthApps.map((a) => formatAppDisplayName(a.appName)).join(", "),
24177
+ " \u2014 Connect"
24178
+ ]
24179
+ }
24180
+ )
23434
24181
  ] })
23435
24182
  ] }),
23436
24183
  /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(AgentAttachmentsButton_default, { attachments: llmImageAttachments }),
@@ -23610,6 +24357,57 @@ var AgentUI = ({
23610
24357
  }
23611
24358
  }
23612
24359
  ),
24360
+ pendingAuthApps.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
24361
+ import_material26.Box,
24362
+ {
24363
+ sx: {
24364
+ mb: 2,
24365
+ p: 2,
24366
+ borderRadius: 2,
24367
+ border: "1px solid hsla(var(--severity-medium) / 0.35)",
24368
+ bgcolor: "hsla(var(--severity-medium) / 0.08)",
24369
+ display: "flex",
24370
+ alignItems: "center",
24371
+ justifyContent: "space-between",
24372
+ gap: 2,
24373
+ flexWrap: "wrap"
24374
+ },
24375
+ children: [
24376
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material26.Box, { sx: { display: "flex", alignItems: "center", gap: 1.5, flex: 1, minWidth: 260 }, children: [
24377
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react15.Lock, { size: 22, color: "hsl(var(--severity-medium))" }),
24378
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material26.Box, { sx: { flex: 1, minWidth: 0 }, children: [
24379
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Typography, { sx: { fontSize: "0.875rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: pendingAuthApps.length === 1 ? `${formatAppDisplayName(pendingAuthApps[0].appName)} requires authentication` : `${pendingAuthApps.map((a) => formatAppDisplayName(a.appName)).join(", ")} require authentication` }),
24380
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Typography, { sx: { fontSize: "0.78rem", color: "hsl(var(--muted-foreground))" }, children: pendingAuthApps.length === 1 ? `The agent cannot complete steps using ${formatAppDisplayName(pendingAuthApps[0].appName)} and may remain pending until connected.` : `The agent cannot complete steps using these tools and may remain pending until connected.` })
24381
+ ] })
24382
+ ] }),
24383
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Box, { sx: { display: "flex", gap: 1, flexWrap: "wrap" }, children: pendingAuthApps.map(({ appName, appId }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
24384
+ import_material26.Button,
24385
+ {
24386
+ variant: "outlined",
24387
+ size: "small",
24388
+ onClick: () => setAuthDrawerApp({ name: appName, id: appId }),
24389
+ sx: {
24390
+ borderColor: "hsla(var(--severity-medium) / 0.6)",
24391
+ color: "hsl(var(--foreground))",
24392
+ textTransform: "none",
24393
+ fontSize: "0.75rem",
24394
+ fontWeight: 600,
24395
+ height: 32,
24396
+ "&:hover": {
24397
+ bgcolor: "hsla(var(--severity-medium) / 0.15)",
24398
+ borderColor: "hsl(var(--severity-medium))"
24399
+ }
24400
+ },
24401
+ children: [
24402
+ "Authenticate ",
24403
+ formatAppDisplayName(appName)
24404
+ ]
24405
+ },
24406
+ appName
24407
+ )) })
24408
+ ]
24409
+ }
24410
+ ),
23613
24411
  viewMode === "simple" && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material26.Box, { sx: {
23614
24412
  borderRadius: 2,
23615
24413
  border: "1px solid hsl(var(--border))",
@@ -23651,7 +24449,7 @@ var AgentUI = ({
23651
24449
  }
23652
24450
  const pendingAnswered = pendingQuestions.every((q) => questionAnswers[q.question]?.value);
23653
24451
  return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
23654
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
24452
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
23655
24453
  RunFinishedSummary,
23656
24454
  {
23657
24455
  status,
@@ -23664,77 +24462,7 @@ var AgentUI = ({
23664
24462
  durationSec,
23665
24463
  showMeta: true,
23666
24464
  bottomContent: aiAuthSuggestionNode,
23667
- children: [
23668
- pendingAuthApps.map(({ appName, appId, icon }) => {
23669
- const pretty = appName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
23670
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
23671
- import_material26.Box,
23672
- {
23673
- sx: {
23674
- display: "flex",
23675
- alignItems: "center",
23676
- gap: 1.5,
23677
- p: 1.5,
23678
- borderRadius: 1.5,
23679
- border: "1px solid hsla(var(--severity-medium) / 0.3)",
23680
- bgcolor: "hsla(var(--severity-medium) / 0.08)"
23681
- },
23682
- children: [
23683
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react15.Lock, { size: 22, color: "hsl(var(--severity-medium))" }),
23684
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material26.Box, { sx: { flex: 1, minWidth: 0 }, children: [
23685
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material26.Typography, { sx: { fontSize: "0.85rem", fontWeight: 600, color: "hsl(var(--foreground))" }, children: [
23686
- pretty,
23687
- " requires authentication"
23688
- ] }),
23689
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material26.Typography, { sx: { fontSize: "0.75rem", color: "hsl(var(--muted-foreground))" }, children: [
23690
- "Connect your ",
23691
- pretty,
23692
- " account so the agent can complete this step, then rerun."
23693
- ] })
23694
- ] }),
23695
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
23696
- import_material26.Button,
23697
- {
23698
- variant: "outlined",
23699
- size: "small",
23700
- startIcon: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
23701
- import_material26.Avatar,
23702
- {
23703
- src: icon || void 0,
23704
- alt: "",
23705
- variant: "rounded",
23706
- sx: {
23707
- width: 18,
23708
- height: 18,
23709
- borderRadius: 0.5,
23710
- bgcolor: "hsl(var(--background) / 0.4)",
23711
- color: "hsl(var(--background))",
23712
- fontSize: "0.7rem",
23713
- fontWeight: 700,
23714
- "& img": { objectFit: "contain" }
23715
- },
23716
- children: pretty.charAt(0)
23717
- }
23718
- ),
23719
- onClick: () => setAuthDrawerApp({ name: appName, id: appId }),
23720
- sx: {
23721
- height: 36,
23722
- textTransform: "none",
23723
- fontWeight: 600
23724
- },
23725
- children: [
23726
- "Authenticate ",
23727
- pretty
23728
- ]
23729
- }
23730
- )
23731
- ]
23732
- },
23733
- `auth-${appName}`
23734
- );
23735
- }),
23736
- !isRunning && postRunDiscovery
23737
- ]
24465
+ children: !isRunning && postRunDiscovery
23738
24466
  }
23739
24467
  ),
23740
24468
  !finishAnswer && pendingAsk && pendingQuestions.length > 0 ? (() => {
@@ -28014,6 +28742,8 @@ var AskAiSidePanel = ({
28014
28742
  defaultInput,
28015
28743
  serverside,
28016
28744
  colorMode,
28745
+ incidentId: propIncidentId,
28746
+ incidentContext: propIncidentContext,
28017
28747
  sx
28018
28748
  }) => {
28019
28749
  const themeScope = useShuffleMcpTheme();
@@ -28136,11 +28866,15 @@ var AskAiSidePanel = ({
28136
28866
  }, [open, initialTab, onTabChange]);
28137
28867
  const [activeTaskId, setActiveTaskId] = (0, import_react34.useState)(null);
28138
28868
  const [activeExecutionId, setActiveExecutionId] = (0, import_react34.useState)(null);
28869
+ const [activeIncidentId, setActiveIncidentId] = (0, import_react34.useState)(null);
28870
+ const [activeIncidentContext, setActiveIncidentContext] = (0, import_react34.useState)(null);
28139
28871
  const [runResetKey, setRunResetKey] = (0, import_react34.useState)(0);
28140
28872
  (0, import_react34.useEffect)(() => {
28141
28873
  if (!open) {
28142
28874
  setActiveTaskId(null);
28143
28875
  setActiveExecutionId(null);
28876
+ setActiveIncidentId(null);
28877
+ setActiveIncidentContext(null);
28144
28878
  }
28145
28879
  }, [open]);
28146
28880
  (0, import_react34.useEffect)(() => {
@@ -28172,6 +28906,12 @@ var AskAiSidePanel = ({
28172
28906
  } else if (!detail?.tab) {
28173
28907
  setActiveTaskId(null);
28174
28908
  }
28909
+ if (detail?.incidentId !== void 0) {
28910
+ setActiveIncidentId(detail.incidentId || null);
28911
+ }
28912
+ if (detail?.incidentContext !== void 0) {
28913
+ setActiveIncidentContext(detail.incidentContext || null);
28914
+ }
28175
28915
  if (detail?.resetExecution) {
28176
28916
  setActiveExecutionId(null);
28177
28917
  setRunResetKey((k) => k + 1);
@@ -28805,6 +29545,8 @@ var AskAiSidePanel = ({
28805
29545
  onAppsChange: handleAppsChange,
28806
29546
  onSelectPreset: handleSelectPreset,
28807
29547
  onChooseLLM: () => handleTabChange("localLLM"),
29548
+ incidentId: activeIncidentId || propIncidentId || agentUIProps?.incidentId,
29549
+ incidentContext: activeIncidentContext || propIncidentContext || agentUIProps?.incidentContext,
28808
29550
  apiBaseUrl: globalUrl || agentUIProps?.apiBaseUrl,
28809
29551
  theme: effectiveTheme,
28810
29552
  sx: {