@64mb/freelens-power 2.2.1 → 2.3.0
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/README.md +1 -1
- package/THIRD_PARTY_LICENSES +26 -0
- package/out/main/ai-models.js +2 -1
- package/out/main/ai-models.js.map +1 -1
- package/out/main/ai.js +13 -5
- package/out/main/ai.js.map +1 -1
- package/out/renderer/ai-extras.js +21 -16
- package/out/renderer/ai-extras.js.map +1 -1
- package/out/renderer/ai-icon.js +23 -0
- package/out/renderer/ai-icon.js.map +1 -1
- package/out/renderer/ai.js +81 -10
- package/out/renderer/ai.js.map +1 -1
- package/out/renderer/appearance.js +20 -2
- package/out/renderer/appearance.js.map +1 -1
- package/out/renderer/details/resource-health-details.js +2 -2
- package/out/renderer/details/resource-health-details.js.map +1 -1
- package/out/renderer/power-log-json-cell.js +2 -2
- package/out/renderer/power-logs.css.js +11 -2
- package/out/renderer/power-logs.css.js.map +1 -1
- package/out/renderer/power-logs.js +75 -32
- package/out/renderer/power-logs.js.map +1 -1
- package/out/renderer/preferences/ai-preferences.js +6 -3
- package/out/renderer/preferences/ai-preferences.js.map +1 -1
- package/out/renderer/preferences/monitoring-preferences.js +14 -6
- package/out/renderer/preferences/monitoring-preferences.js.map +1 -1
- package/package.json +1 -1
package/out/renderer/ai.js
CHANGED
|
@@ -137,6 +137,7 @@ body:has(.AddRemoveButtons .remove-button:not([data-freelens-power-read-only]))
|
|
|
137
137
|
:root .power-ai-panel form button[type="submit"]:disabled { background-color: var(--contentColor); border-color: var(--borderFaintColor); color: var(--textColorSecondary); }
|
|
138
138
|
.power-ai-message-user { border-color: color-mix(in srgb, var(--primary) 28%, var(--borderFaintColor)); background: color-mix(in srgb, var(--primary) 7%, var(--mainBackground)); }
|
|
139
139
|
.power-ai-context { padding: 10px 20px; line-height: 1.5; border-bottom: 1px solid var(--borderFaintColor); font-size: 12px; color: var(--textColorSecondary); overflow-wrap: anywhere; }
|
|
140
|
+
.power-ai-attached-resource { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
|
140
141
|
.power-ai-title, .power-ai-panel button { display: inline-flex; align-items: center; gap: 6px; }
|
|
141
142
|
.power-ai-title { margin-right: auto; white-space: nowrap; color: var(--textColorAccent); }
|
|
142
143
|
.power-ai-brand { display: inline-flex; align-items: center; gap: 6px; color: var(--primary); }
|
|
@@ -145,6 +146,15 @@ body:has(.AddRemoveButtons .remove-button:not([data-freelens-power-read-only]))
|
|
|
145
146
|
.power-ai-panel header > button { flex-shrink: 0; }
|
|
146
147
|
.power-ai-panel form { position: relative; flex-shrink: 0; margin: 0 16px 16px; border: 1px solid var(--borderFaintColor); border-radius: 12px; background: var(--mainBackground); transition: border-color 160ms ease; }
|
|
147
148
|
.power-ai-panel form > .power-ai-context-preview { padding: 8px 48px 4px 16px !important; min-height: 34px; margin: 0; box-sizing: border-box; }
|
|
149
|
+
.power-ai-context-preview pre { white-space: pre-wrap; overflow-wrap: anywhere; overflow: auto; }
|
|
150
|
+
.power-ai-finding-content pre { max-height: 140px; }
|
|
151
|
+
.power-ai-context-content pre { max-height: 160px; }
|
|
152
|
+
.power-ai-context-preview .power-log-json { --json-key:#9cdcfe; --json-string:#ce9178; --json-number:#b5cea8; --json-literal:#c586c0; }
|
|
153
|
+
.theme-light .power-ai-context-preview .power-log-json { --json-key:#005a9e; --json-string:#9e2b1a; --json-number:#17642d; --json-literal:#7a288c; }
|
|
154
|
+
.power-ai-context-preview .power-log-json [data-token=key] { color:var(--json-key); }
|
|
155
|
+
.power-ai-context-preview .power-log-json [data-token=string] { color:var(--json-string); }
|
|
156
|
+
.power-ai-context-preview .power-log-json [data-token=number] { color:var(--json-number); }
|
|
157
|
+
.power-ai-context-preview .power-log-json [data-token=literal] { color:var(--json-literal); }
|
|
148
158
|
.power-ai-context-finding { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 4px; min-width: 0; }
|
|
149
159
|
.power-ai-context-finding > .Icon { flex-shrink: 0; margin-top: 7px; }
|
|
150
160
|
.power-ai-context-finding > details { flex: 1; min-width: 0; }
|
|
@@ -202,6 +212,28 @@ var AiChat = require__global_external_mobx_react.observer(({ isClusterDocument }
|
|
|
202
212
|
const [launcherHidden, setLauncherHidden] = require__global_external_react.useState(false);
|
|
203
213
|
const [draft, setDraft] = require__global_external_react.useState("");
|
|
204
214
|
const [finding, setFinding] = require__global_external_react.useState();
|
|
215
|
+
const [resourceAttachment, setResourceAttachment] = require__global_external_react.useState();
|
|
216
|
+
const dismissedResource = require__global_external_react.useRef();
|
|
217
|
+
const panelOpen = require__global_external_react.useRef(open);
|
|
218
|
+
panelOpen.current = open;
|
|
219
|
+
const captureScreenResource = (current = readAiContext()) => {
|
|
220
|
+
if (current.clusterId && current.resource && dismissedResource.current !== JSON.stringify({
|
|
221
|
+
clusterId: current.clusterId,
|
|
222
|
+
resource: current.resource
|
|
223
|
+
})) setResourceAttachment(current);
|
|
224
|
+
};
|
|
225
|
+
const attachScreenResource = () => {
|
|
226
|
+
dismissedResource.current = void 0;
|
|
227
|
+
captureScreenResource();
|
|
228
|
+
};
|
|
229
|
+
const removeResource = () => {
|
|
230
|
+
const current = resourceAttachment ?? readAiContext();
|
|
231
|
+
dismissedResource.current = JSON.stringify({
|
|
232
|
+
clusterId: current.clusterId,
|
|
233
|
+
resource: current.resource
|
|
234
|
+
});
|
|
235
|
+
setResourceAttachment(void 0);
|
|
236
|
+
};
|
|
205
237
|
const [terminalAttachment, setTerminalAttachment] = require__global_external_react.useState();
|
|
206
238
|
const [suggestionIndex, setSuggestionIndex] = require__global_external_react.useState(0);
|
|
207
239
|
const [dismissedDraft, setDismissedDraft] = require__global_external_react.useState();
|
|
@@ -257,6 +289,8 @@ var AiChat = require__global_external_mobx_react.observer(({ isClusterDocument }
|
|
|
257
289
|
updateDock();
|
|
258
290
|
const nextContext = readAiContext();
|
|
259
291
|
setContext(nextContext);
|
|
292
|
+
if (panelOpen.current) captureScreenResource(nextContext);
|
|
293
|
+
setResourceAttachment((current) => current?.clusterId === nextContext.clusterId ? current : void 0);
|
|
260
294
|
setFinding((current) => current && current.clusterId !== nextContext.clusterId ? void 0 : current);
|
|
261
295
|
setResourceDetailsOpen(hasAiResourceDetails());
|
|
262
296
|
setCoveredByOverlay(hasAiOverlay());
|
|
@@ -318,6 +352,7 @@ var AiChat = require__global_external_mobx_react.observer(({ isClusterDocument }
|
|
|
318
352
|
const closePanel = () => setOpen(false);
|
|
319
353
|
window.addEventListener("power-ai-close", closePanel);
|
|
320
354
|
function openOnly() {
|
|
355
|
+
attachScreenResource();
|
|
321
356
|
update();
|
|
322
357
|
setOpen(true);
|
|
323
358
|
}
|
|
@@ -376,6 +411,12 @@ var AiChat = require__global_external_mobx_react.observer(({ isClusterDocument }
|
|
|
376
411
|
}, [open, pinned]);
|
|
377
412
|
const availablePanelWidth = Math.max(1, viewportWidth - Math.max(0, launcherLeft - 16));
|
|
378
413
|
const panelWidth = require_ai_resize.clampAiPanelWidth(preferences.chatPanelWidth ?? 560, availablePanelWidth);
|
|
414
|
+
const attachedResource = resourceAttachment && resourceAttachment.clusterId === context.clusterId ? resourceAttachment.resource : void 0;
|
|
415
|
+
const previewContext = require_ai_extras.attachedAiContext({
|
|
416
|
+
clusterId: context.clusterId,
|
|
417
|
+
screen: context.screen,
|
|
418
|
+
...finding && finding.clusterId === context.clusterId && finding.resource ? { resource: finding.resource } : attachedResource ? { resource: attachedResource } : {}
|
|
419
|
+
});
|
|
379
420
|
const key = context.clusterId ?? "global";
|
|
380
421
|
const messages = preferences.conversations[key] ?? [];
|
|
381
422
|
const busy = pending.includes(key);
|
|
@@ -433,9 +474,12 @@ var AiChat = require__global_external_mobx_react.observer(({ isClusterDocument }
|
|
|
433
474
|
setError("Message and attached finding are too long. Shorten the message or remove the finding.");
|
|
434
475
|
return;
|
|
435
476
|
}
|
|
477
|
+
const currentContext = readAiContext();
|
|
478
|
+
const requestResource = activeFinding?.resource ?? (resourceAttachment && resourceAttachment.clusterId === currentContext.clusterId ? resourceAttachment.resource : void 0);
|
|
436
479
|
const requestContext = require_ai_extras.attachedAiContext({
|
|
437
|
-
|
|
438
|
-
|
|
480
|
+
clusterId: currentContext.clusterId,
|
|
481
|
+
screen: currentContext.screen,
|
|
482
|
+
...requestResource ? { resource: requestResource } : {}
|
|
439
483
|
});
|
|
440
484
|
if ((requestContext.clusterId ?? "global") !== key) {
|
|
441
485
|
setContext(requestContext);
|
|
@@ -555,7 +599,12 @@ var AiChat = require__global_external_mobx_react.observer(({ isClusterDocument }
|
|
|
555
599
|
left: resourceDetailsOpen ? launcherLeft : "auto",
|
|
556
600
|
right: resourceDetailsOpen ? "auto" : 16
|
|
557
601
|
},
|
|
558
|
-
|
|
602
|
+
onPointerDown: attachScreenResource,
|
|
603
|
+
onMouseDown: attachScreenResource,
|
|
604
|
+
onClick: () => {
|
|
605
|
+
attachScreenResource();
|
|
606
|
+
setOpen(true);
|
|
607
|
+
},
|
|
559
608
|
"aria-label": "Open AI assistant",
|
|
560
609
|
children: [
|
|
561
610
|
/* @__PURE__ */ require_jsx_runtime.jsx("span", {
|
|
@@ -573,6 +622,9 @@ var AiChat = require__global_external_mobx_react.observer(({ isClusterDocument }
|
|
|
573
622
|
open && /* @__PURE__ */ require_jsx_runtime.jsxs("aside", {
|
|
574
623
|
className: "power-ai-panel",
|
|
575
624
|
"aria-label": "AI assistant",
|
|
625
|
+
onPointerDownCapture: () => captureScreenResource(),
|
|
626
|
+
onMouseDownCapture: () => captureScreenResource(),
|
|
627
|
+
onFocusCapture: () => captureScreenResource(),
|
|
576
628
|
style: {
|
|
577
629
|
"--power-ai-font-size": `${preferences.chatFontSize ?? 14}px`,
|
|
578
630
|
width: panelWidth
|
|
@@ -610,6 +662,7 @@ var AiChat = require__global_external_mobx_react.observer(({ isClusterDocument }
|
|
|
610
662
|
onClick: () => {
|
|
611
663
|
setTerminalAttachment(void 0);
|
|
612
664
|
setFinding(void 0);
|
|
665
|
+
removeResource();
|
|
613
666
|
preferences.setMessages(key, []);
|
|
614
667
|
setStopped((keys) => keys.filter((entry) => entry !== key));
|
|
615
668
|
setActivity({
|
|
@@ -632,8 +685,8 @@ var AiChat = require__global_external_mobx_react.observer(({ isClusterDocument }
|
|
|
632
685
|
"aria-label": "Pin AI assistant",
|
|
633
686
|
"aria-pressed": pinned,
|
|
634
687
|
onClick: () => setPinned((value) => !value),
|
|
635
|
-
children: /* @__PURE__ */ require_jsx_runtime.jsx(require_ai_icon.
|
|
636
|
-
|
|
688
|
+
children: /* @__PURE__ */ require_jsx_runtime.jsx(require_ai_icon.AiPinIcon, {
|
|
689
|
+
pinned,
|
|
637
690
|
size: 18
|
|
638
691
|
})
|
|
639
692
|
})
|
|
@@ -666,7 +719,28 @@ var AiChat = require__global_external_mobx_react.observer(({ isClusterDocument }
|
|
|
666
719
|
context.clusterId ? "Cluster conversation" : "General conversation",
|
|
667
720
|
" · ",
|
|
668
721
|
context.screen,
|
|
669
|
-
context.resource &&
|
|
722
|
+
attachedResource && !(finding?.clusterId === context.clusterId && finding?.resource) && /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
|
|
723
|
+
className: "power-ai-attached-resource",
|
|
724
|
+
"aria-label": "Attached resource",
|
|
725
|
+
children: [/* @__PURE__ */ require_jsx_runtime.jsxs("span", { children: [
|
|
726
|
+
attachedResource.kind,
|
|
727
|
+
"/",
|
|
728
|
+
attachedResource.name,
|
|
729
|
+
attachedResource.namespace ? ` · ${attachedResource.namespace}` : ""
|
|
730
|
+
] }), /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
|
|
731
|
+
title: "Remove resource from attached context",
|
|
732
|
+
children: /* @__PURE__ */ require_jsx_runtime.jsx("button", {
|
|
733
|
+
type: "button",
|
|
734
|
+
className: "power-ai-remove-context",
|
|
735
|
+
"aria-label": "Remove attached resource",
|
|
736
|
+
onClick: removeResource,
|
|
737
|
+
children: /* @__PURE__ */ require_jsx_runtime.jsx(require_ai_icon.AiIcon, {
|
|
738
|
+
material: "close",
|
|
739
|
+
size: 14
|
|
740
|
+
})
|
|
741
|
+
})
|
|
742
|
+
})]
|
|
743
|
+
}),
|
|
670
744
|
/* @__PURE__ */ require_jsx_runtime.jsx("br", {}),
|
|
671
745
|
"Only screen and resource metadata are attached automatically."
|
|
672
746
|
]
|
|
@@ -809,10 +883,7 @@ var AiChat = require__global_external_mobx_react.observer(({ isClusterDocument }
|
|
|
809
883
|
/* @__PURE__ */ require_jsx_runtime.jsx(require_ai_extras$1.AiContextPreview, {
|
|
810
884
|
finding: finding?.clusterId === context.clusterId ? finding : void 0,
|
|
811
885
|
onRemoveFinding: () => setFinding(void 0),
|
|
812
|
-
context:
|
|
813
|
-
...context,
|
|
814
|
-
...finding && finding.clusterId === context.clusterId && finding.resource ? { resource: finding.resource } : {}
|
|
815
|
-
})
|
|
886
|
+
context: previewContext
|
|
816
887
|
}),
|
|
817
888
|
/* @__PURE__ */ require_jsx_runtime.jsx(require_ai_terminal_context.AiTerminalContext, {
|
|
818
889
|
clusterId: context.clusterId,
|
package/out/renderer/ai.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai.js","names":[],"sources":["../../src/renderer/ai.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { ipcRenderer } from \"electron\";\nimport { autorun } from \"mobx\";\nimport { observer } from \"mobx-react\";\nimport { type CSSProperties, useEffect, useRef, useState } from \"react\";\nimport ReactDOM from \"react-dom\";\nimport { AI_CHAT_CHANNEL, AI_READ_ACTIVITY_CHANNEL, type AiReadActivity } from \"../common/ai\";\nimport { AI_CANCEL_CHANNEL, attachedAiContext, normalizeAiReferences } from \"../common/ai-extras\";\nimport { expandAiShortcut } from \"../common/ai-shortcuts\";\nimport { type AiMessage, AiPreferencesStore } from \"../common/store/ai-preferences-store\";\nimport { AiShortcutsStore } from \"../common/store/ai-shortcuts-store\";\nimport { hasAiContextMutations } from \"./ai-context-mutations\";\nimport { AiCopyAnswer } from \"./ai-copy-answer\";\nimport {\n AI_DIAGNOSTIC_EVENT,\n type DiagnosticFinding,\n diagnosticQuestion,\n sanitizeDiagnosticFinding,\n} from \"./ai-diagnostic-handoff\";\nimport { AiContextPreview, AiResourceReferences } from \"./ai-extras\";\nimport { AiIcon } from \"./ai-icon\";\nimport { isPowerLogsWorkspace, POWER_LOGS_SQL_DRAFT_PROMPT } from \"./ai-logs-sql\";\nimport { AiMessageContent } from \"./ai-message\";\nimport { AiProviderIcon } from \"./ai-provider-icon\";\nimport { AiResizeHandle, clampAiPanelWidth, DEFAULT_AI_PANEL_WIDTH } from \"./ai-resize\";\nimport { AiStarterPrompts } from \"./ai-shortcuts\";\nimport {\n type AiTerminalAttachment,\n AiTerminalContext,\n activeAiTerminal,\n captureAiTerminal,\n} from \"./ai-terminal-context\";\nimport { NativeTooltip } from \"./native-tooltip\";\n\nexport interface AiScreenContext {\n clusterId?: string;\n screen?: string;\n resource?: { kind?: string; namespace?: string; name?: string };\n}\n\nexport function readAiContext(): AiScreenContext {\n const clusterId = Renderer.Catalog.activeCluster.get()?.metadata.uid;\n const screen = window.location.pathname;\n const details = new URLSearchParams(window.location.search).get(\"kube-details\");\n const match =\n details?.match(/^\\/api(?:\\/v\\d+)?\\/namespaces\\/([^/]+)\\/([^/]+)\\/([^/]+)$/) ??\n details?.match(/^\\/apis\\/[^/]+\\/[^/]+\\/namespaces\\/([^/]+)\\/([^/]+)\\/([^/]+)$/);\n const clusterResource =\n details?.match(/^\\/api\\/[^/]+\\/([^/]+)\\/([^/]+)$/) ?? details?.match(/^\\/apis\\/[^/]+\\/[^/]+\\/([^/]+)\\/([^/]+)$/);\n const resource = match\n ? { namespace: match[1], kind: match[2], name: match[3] }\n : clusterResource\n ? { kind: clusterResource[1], name: clusterResource[2] }\n : undefined;\n return { clusterId, screen, ...(resource ? { resource } : {}) };\n}\n\nexport function isAiClusterDocument(): boolean {\n return window.top !== window && Boolean(Renderer.Catalog.activeCluster.get());\n}\n\nexport function aiLauncherBottom(): number {\n const dock = document.querySelector<HTMLElement>(\".Dock\");\n if (!dock) return 16;\n const rect = dock.getBoundingClientRect();\n const style = window.getComputedStyle(dock);\n if (\n dock.hidden ||\n style.display === \"none\" ||\n style.visibility === \"hidden\" ||\n rect.width <= 0 ||\n rect.height <= 0 ||\n rect.top <= 0 ||\n rect.top >= window.innerHeight\n )\n return 16;\n return Math.max(16, window.innerHeight - rect.top + 16);\n}\n\nexport function aiLauncherLeft(): number {\n const sidebar = document.querySelector<HTMLElement>('[data-testid=\"cluster-sidebar\"], .Sidebar');\n const dock = document.querySelector<HTMLElement>(\".Dock\");\n let contentLeft = 0;\n for (const [element, edge] of [\n [sidebar, \"right\"],\n [dock, \"left\"],\n ] as const) {\n if (!element || element.hidden) continue;\n const style = window.getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n if (style.display === \"none\" || style.visibility === \"hidden\" || rect.width <= 0) continue;\n const value = rect[edge];\n if (Number.isFinite(value) && value >= 0 && value < window.innerWidth - 80)\n contentLeft = Math.max(contentLeft, value);\n }\n return contentLeft + 16;\n}\n\nexport function hasAiResourceDetails(): boolean {\n if (new URLSearchParams(window.location.search).get(\"kube-details\")) return true;\n return Array.from(\n document.querySelectorAll<HTMLElement>(\".Drawer.KubeObjectDetails, .Drawer.ReleaseDetails, .DetailsDrawer\"),\n ).some((element) => {\n const style = window.getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n return (\n !element.hidden && style.display !== \"none\" && style.visibility !== \"hidden\" && rect.width > 0 && rect.height > 0\n );\n });\n}\n\nexport function hasAiOverlay(): boolean {\n return Array.from(document.querySelectorAll<HTMLElement>('[role=\"dialog\"], dialog[open], .Dialog')).some(\n (element) => {\n const style = window.getComputedStyle(element);\n return !element.hidden && style.display !== \"none\" && style.visibility !== \"hidden\";\n },\n );\n}\n\nconst styles = `\n@keyframes power-ai-spin { to { transform: rotate(360deg); } }\n@keyframes power-ai-dot { 0%, 80%, 100% { opacity: .25; } 40% { opacity: 1; } }\nbody:has(.AddRemoveButtons .remove-button:not([data-freelens-power-read-only])) .power-ai-launcher { display: none; }\n.power-ai-read-activity > span { display: inline-flex; align-items: center; gap: 4px; }\n.power-ai-read-activity [data-status=\"reading\"] .Icon { animation: power-ai-spin 1.2s linear infinite; }\n.power-ai-thinking { margin: 12px 16px 18px; line-height: 1.5; color: var(--textColorSecondary); }\n.power-ai-dots > span { animation: power-ai-dot 1.3s ease-in-out infinite; }\n.power-ai-dots > span:nth-child(2) { animation-delay: .15s; }\n.power-ai-dots > span:nth-child(3) { animation-delay: .3s; }\n@media (prefers-reduced-motion: reduce) { .power-ai-read-activity [data-status=\"reading\"] .Icon, .power-ai-dots > span { animation: none; } }\n@keyframes power-ai-enter { from { transform: translateX(100%); } to { transform: translateX(0); } }\n:root .power-ai-launcher { position: fixed; bottom: 16px; left: auto; right: 16px; z-index: 100; display: inline-flex; align-items: center; gap: 6px; min-width: 0; min-height: 0; height: 34px; border: 1px solid var(--primary, #5896ff); border-radius: 24px; padding: 0 13px; background: var(--contentColor, #242424); color: var(--textColorAccent); box-shadow: 0 3px 12px #0003; font: inherit; font-size: 12px; font-weight: 500; line-height: 1; cursor: pointer; transition: opacity 180ms ease, background-color 140ms ease, box-shadow 140ms ease, transform 180ms ease; }\n.power-ai-overview-actions { position: relative; z-index: 5; height: 0; min-height: 0; flex: 0 0 0; pointer-events: none; }\n.power-ai-overview-actions + [data-testid=\"cluster-overview-page\"] [data-monitoring-summaries] { --power-monitoring-summary-top: 56px; }\n.power-ai-overview-actions button { transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease, box-shadow 160ms ease; position: absolute; top: 12px; right: 12px; pointer-events: auto; box-shadow: 0 2px 8px #0002; display: inline-flex; flex: 0 0 auto; width: auto; align-items: center; gap: 6px; min-height: 32px; padding: 6px 12px; font: inherit; font-size: 12px; border: 1px solid var(--borderFaintColor); border-radius: 10px; color: var(--textColorPrimary); background: var(--contentColor); cursor: pointer; }\n.power-ai-overview-actions button:hover { border-color: var(--primary); color: var(--textColorAccent); background: var(--contentColor); }\n.power-ai-overview-actions button:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-launcher.power-ai-launcher-hidden { opacity: 0; transform: translateY(8px); pointer-events: none; }\n.power-ai-launcher .Icon { color: inherit; }\n.power-ai-launcher:hover { background: color-mix(in srgb, var(--primary, #5896ff) 12%, var(--contentColor, #242424)); box-shadow: 0 4px 12px #0003; transform: translateY(-1px); }\n.power-ai-launcher:active { transform: translateY(0); box-shadow: 0 2px 6px #0002; }\n@media (prefers-reduced-motion: reduce) { :root .power-ai-launcher { transition: none; } .power-ai-launcher:hover, .power-ai-launcher:active { transform: none; } }\n.power-ai-launcher:focus-visible { outline: 2px solid var(--primary, #5896ff); outline-offset: 3px; }\n.power-ai-panel { position: fixed; right: 0; top: 0; bottom: 0; width: min(560px, 100vw); z-index: 10001; display: flex; flex-direction: column; background: var(--contentColor, #242424); color: var(--textColorAccent, white); animation: power-ai-enter 160ms ease-out; border-left: 1px solid var(--borderFaintColor); box-shadow: -4px 0 24px #0004; }\n.power-ai-resize-handle { position: absolute; left: -4px; top: 0; bottom: 0; width: 8px; z-index: 2; cursor: col-resize; touch-action: none; }\n.power-ai-resize-handle:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }\n.power-ai-panel header { padding: 16px; display: flex; gap: 10px; flex-shrink: 0; }\n.power-ai-panel header { border-bottom: 1px solid var(--borderFaintColor); justify-content: space-between; align-items: center; }\n.power-ai-messages { overflow: auto; flex: 1; min-height: 0; padding: 24px 16px; font-size: var(--power-ai-font-size, 14px); line-height: 1.65; overscroll-behavior: contain; }\n.power-ai-message { overflow-wrap: anywhere; padding: 14px 16px; margin-bottom: 20px; color: var(--textColorAccent); border: 1px solid var(--borderFaintColor); border-radius: 8px; }\n.power-ai-panel button { padding: 7px 10px; border: 1px solid var(--borderFaintColor); border-radius: 8px; background: var(--contentColor); color: var(--textColorPrimary); cursor: pointer; }\n:root .power-ai-panel header button:is(.power-ai-close, .power-ai-pin) { width: 30px; height: 30px; padding: 0; display: inline-flex; align-items: center; justify-content: center; border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel header button:is(.power-ai-close, .power-ai-pin):not(:disabled):not(.disabled):hover { color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent); }\n:root .power-ai-panel header button:is(.power-ai-close, .power-ai-pin):focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n:root .power-ai-panel button.power-ai-copy-answer { width: 24px; height: 24px; padding: 0; margin-left: auto; flex-shrink: 0; justify-content: center; border: 0; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel button.power-ai-copy-answer:not(:disabled):not(.disabled):hover { color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent); }\n:root .power-ai-panel button.power-ai-copy-answer:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-cancellation { display: flex; align-items: center; gap: 6px; }\n:root .power-ai-panel button.power-ai-dismiss { width: 24px; height: 24px; padding: 0; justify-content: center; border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel button.power-ai-dismiss:hover { color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent); }\n:root .power-ai-panel button.power-ai-dismiss:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-panel button:disabled { opacity: 0.5; cursor: default; }\n .power-ai-panel textarea { display: block; width: 100%; box-sizing: border-box; min-width: 0; min-height: 64px; max-height: 180px; field-sizing: content; padding: 12px 16px 6px; border: 0; border-radius: 12px; background: transparent; color: var(--textColorAccent); font: inherit; font-size: var(--power-ai-font-size, 14px); line-height: 1.5; resize: none; }\n.power-ai-panel textarea::placeholder { color: var(--textColorSecondary); opacity: 1; }\n.power-ai-panel textarea:focus { outline: none; }\n.power-ai-composer-footer { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 4px 10px 10px 16px; }\n.power-ai-composer-footer > span { color: var(--textColorSecondary); font-size: 11px; line-height: 1.5; }\n:root .power-ai-panel form button[type=\"submit\"] { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 34px; width: 34px; height: 34px; padding: 0; border-radius: 10px; }\n:root .power-ai-panel form button[type=\"submit\"]:not(:disabled):not(.disabled) { background-color: var(--primary); border-color: var(--primary); color: white; }\n:root .power-ai-panel form button[type=\"submit\"]:not(:disabled):not(.disabled):hover { background-color: color-mix(in srgb, var(--primary) 88%, white 12%); border-color: color-mix(in srgb, var(--primary) 88%, white 12%); color: white; }\n:root .power-ai-panel form button[type=\"submit\"]:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }\n:root .power-ai-panel form button[type=\"submit\"]:disabled { background-color: var(--contentColor); border-color: var(--borderFaintColor); color: var(--textColorSecondary); }\n.power-ai-message-user { border-color: color-mix(in srgb, var(--primary) 28%, var(--borderFaintColor)); background: color-mix(in srgb, var(--primary) 7%, var(--mainBackground)); }\n.power-ai-context { padding: 10px 20px; line-height: 1.5; border-bottom: 1px solid var(--borderFaintColor); font-size: 12px; color: var(--textColorSecondary); overflow-wrap: anywhere; }\n.power-ai-title, .power-ai-panel button { display: inline-flex; align-items: center; gap: 6px; }\n.power-ai-title { margin-right: auto; white-space: nowrap; color: var(--textColorAccent); }\n.power-ai-brand { display: inline-flex; align-items: center; gap: 6px; color: var(--primary); }\n.power-ai-brand .Icon { color: inherit; }\n:root .power-ai-panel header button.power-ai-pin[aria-pressed=\"true\"] { color: var(--primary); }\n.power-ai-panel header > button { flex-shrink: 0; }\n.power-ai-panel form { position: relative; flex-shrink: 0; margin: 0 16px 16px; border: 1px solid var(--borderFaintColor); border-radius: 12px; background: var(--mainBackground); transition: border-color 160ms ease; }\n.power-ai-panel form > .power-ai-context-preview { padding: 8px 48px 4px 16px !important; min-height: 34px; margin: 0; box-sizing: border-box; }\n.power-ai-context-finding { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 4px; min-width: 0; }\n.power-ai-context-finding > .Icon { flex-shrink: 0; margin-top: 7px; }\n.power-ai-context-finding > details { flex: 1; min-width: 0; }\n.power-ai-context-finding summary { padding: 6px 0; min-height: 28px; box-sizing: border-box; cursor: pointer; overflow-wrap: anywhere; }\n:root .power-ai-panel button.power-ai-remove-context { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; min-height: 28px; flex-shrink: 0; padding: 0; border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel button.power-ai-remove-context:hover { background: color-mix(in srgb, var(--primary) 10%, transparent); color: var(--primary); }\n:root .power-ai-panel button.power-ai-remove-context:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-panel form:focus-within { border-color: var(--primary); }\n.power-ai-message > strong { display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 500; color: var(--textColorSecondary); margin-bottom: 10px; }\n.power-ai-message-assistant { border-color: transparent; background: transparent; }\n.power-ai-markdown { line-height: 1.65; font-size: var(--power-ai-font-size, 14px); color: var(--textColorAccent); }\n.power-ai-markdown p { margin: 0 0 14px; white-space: pre-wrap; }\n.power-ai-markdown p:last-child { margin-bottom: 0; }\n.power-ai-markdown ul, .power-ai-markdown ol { padding-left: 24px; margin: 10px 0 16px; }\n.power-ai-markdown ul { list-style: disc; }\n.power-ai-markdown ol { list-style: decimal; }\n.power-ai-markdown li { margin: 5px 0; }\n.power-ai-markdown li > ul, .power-ai-markdown li > ol { margin: 6px 0; }\n.power-ai-markdown li > p { margin-bottom: 6px; }\n.power-ai-markdown :is(h1, h2, h3, h4, h5, h6) { color: var(--textColorAccent); font-weight: 600; line-height: 1.4; margin: 24px 0 12px; }\n.power-ai-markdown :is(h1, h2, h3, h4, h5, h6):first-child { margin-top: 0; }\n.power-ai-markdown h1 { font-size: 1.43em; }\n.power-ai-markdown h2 { font-size: 1.29em; }\n.power-ai-markdown h3 { font-size: 1.14em; }\n.power-ai-markdown :is(h4, h5, h6) { font-size: 1em; }\n.power-ai-markdown blockquote { margin: 16px 0; padding: 4px 14px; border-left: 3px solid var(--borderColor); color: var(--textColorSecondary); }\n.power-ai-markdown blockquote > p:last-child { margin-bottom: 0; }\n.power-ai-markdown table { display: block; max-width: 100%; overflow-x: auto; margin: 16px 0; border-collapse: collapse; font-size: max(10px, calc(var(--power-ai-font-size, 14px) - 1px)); }\n.power-ai-markdown th, .power-ai-markdown td { padding: 9px 12px; border: 1px solid var(--borderFaintColor); text-align: left; }\n.power-ai-markdown th { font-weight: 600; background: color-mix(in srgb, var(--textColorAccent) 5%, transparent); }\n.power-ai-markdown a { color: var(--primary); text-decoration: underline; text-underline-offset: 2px; }\n.power-ai-markdown hr { margin: 20px 0; border: 0; border-top: 1px solid var(--borderFaintColor); }\n.power-ai-markdown code { font-family: var(--font-monospace, monospace); font-size: max(10px, calc(var(--power-ai-font-size, 14px) - 1px)); background: color-mix(in srgb, var(--textColorAccent) 8%, transparent); padding: 1px 4px; border-radius: 4px; }\n.power-ai-code { margin: 12px 0; border: 1px solid var(--borderFaintColor); border-radius: 8px; overflow: hidden; background: var(--mainBackground); }\n.power-ai-code-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 8px; border-bottom: 1px solid var(--borderFaintColor); color: var(--textColorSecondary); font-size: 11px; }\n.power-ai-code-toolbar > div { display: flex; gap: 4px; }\n.power-ai-code-toolbar button { padding: 4px 6px; font-size: 11px; }\n.power-ai-code pre { margin: 0; padding: 12px; overflow-x: auto; white-space: pre; }\n.power-ai-code pre code { padding: 0; background: transparent; }\n.power-ai-code-hint, .power-ai-code-feedback:not(:empty) { padding: 0 12px 10px; color: var(--textColorSecondary); font-size: 11px; }\n.power-ai-autocomplete { position: absolute; bottom: calc(100% + 8px); left: 0; right: 0; max-height: 240px; overflow-y: auto; padding: 6px; border: 1px solid var(--borderColor); border-radius: 10px; background: var(--contentColor); box-shadow: 0 4px 16px #0003; }\n.power-ai-autocomplete button { display: flex; width: 100%; justify-content: space-between; gap: 12px; border: 0; text-align: left; }\n.power-ai-autocomplete button[aria-selected=\"true\"] { background: color-mix(in srgb, var(--primary) 14%, var(--contentColor)); color: var(--textColorAccent); }\n.power-ai-autocomplete button > span:last-child { color: var(--textColorSecondary); font-size: 12px; }\n@media (prefers-reduced-motion: reduce) { .power-ai-panel { animation: none; } }\n`;\n\nconst AiChat = observer(({ isClusterDocument }: { isClusterDocument: () => boolean }) => {\n const preferences = AiPreferencesStore.getInstanceOrCreate<AiPreferencesStore>();\n const [open, setOpen] = useState(false);\n const [pinned, setPinned] = useState(false);\n const [launcherBottom, setLauncherBottom] = useState(aiLauncherBottom);\n const [launcherLeft, setLauncherLeft] = useState(aiLauncherLeft);\n const [resourceDetailsOpen, setResourceDetailsOpen] = useState(hasAiResourceDetails);\n const [viewportWidth, setViewportWidth] = useState(window.innerWidth);\n const [launcherHidden, setLauncherHidden] = useState(false);\n const [draft, setDraft] = useState(\"\");\n const [finding, setFinding] = useState<DiagnosticFinding>();\n const [terminalAttachment, setTerminalAttachment] = useState<AiTerminalAttachment>();\n const [suggestionIndex, setSuggestionIndex] = useState(0);\n const [dismissedDraft, setDismissedDraft] = useState<string>();\n const suggestions =\n /^\\/[^\\s]*$/.test(draft) && dismissedDraft !== draft\n ? AiShortcutsStore.getInstanceOrCreate<AiShortcutsStore>().shortcuts.filter((shortcut) =>\n `${shortcut.command} ${shortcut.label}`.toLowerCase().includes(draft.slice(1).toLowerCase()),\n )\n : [];\n const dismissSuggestions = useRef<() => boolean>(() => false);\n dismissSuggestions.current = () => {\n if (!suggestions.length) return false;\n setDismissedDraft(draft);\n return true;\n };\n const following = useRef(true);\n const composer = useRef<HTMLTextAreaElement>(null);\n const selectSuggestion = (index: number) => {\n const shortcut = suggestions[index];\n if (!shortcut) return;\n setDraft(`/${shortcut.command} `);\n setSuggestionIndex(0);\n composer.current?.focus();\n };\n const [context, setContext] = useState(readAiContext);\n useEffect(() => {\n if (open && !finding && !terminalAttachment) window.dispatchEvent(new Event(\"power-ai-request-screen-context\"));\n }, [open]);\n const [pending, setPending] = useState<string[]>([]);\n const [error, setError] = useState(\"\");\n const [stopped, setStopped] = useState<string[]>([]);\n const activeRequests = useRef(new Map<string, string>());\n const [activity, setActivity] = useState<{\n key: string;\n reads: { method: AiReadActivity[\"method\"]; status: \"reading\" | \"ok\" | \"unavailable\" }[];\n }>({ key: \"\", reads: [] });\n const clusterReview = useRef<() => void>(() => {});\n const messagesElement = useRef<HTMLDivElement>(null);\n const [coveredByOverlay, setCoveredByOverlay] = useState(hasAiOverlay);\n useEffect(() => {\n let observedElements: Element[] = [];\n const resizeObserver =\n typeof ResizeObserver === \"undefined\"\n ? undefined\n : new ResizeObserver(() => {\n setLauncherBottom(aiLauncherBottom());\n setLauncherLeft(aiLauncherLeft());\n });\n const updateDock = () => {\n setViewportWidth(window.innerWidth);\n setLauncherBottom(aiLauncherBottom());\n setLauncherLeft(aiLauncherLeft());\n const elements = [\n document.querySelector(\".Dock\"),\n document.querySelector('[data-testid=\"cluster-sidebar\"], .Sidebar'),\n ].filter((element): element is Element => !!element);\n if (\n elements.length !== observedElements.length ||\n elements.some((element, index) => element !== observedElements[index])\n ) {\n resizeObserver?.disconnect();\n observedElements = elements;\n for (const element of elements) resizeObserver?.observe(element);\n }\n };\n const update = () => {\n updateDock();\n const nextContext = readAiContext();\n setContext(nextContext);\n setFinding((current) => (current && current.clusterId !== nextContext.clusterId ? undefined : current));\n setResourceDetailsOpen(hasAiResourceDetails());\n setCoveredByOverlay(hasAiOverlay());\n };\n const onActivity = (_event: unknown, value: unknown) => {\n if (!value || typeof value !== \"object\") return;\n const entry = value as { requestId?: string; method?: string; status?: string };\n const requestKey = activeRequests.current.get(entry.requestId ?? \"\");\n if (\n !requestKey ||\n requestKey !== readAiContext().clusterId ||\n ![\"pods\", \"nodes\", \"resources\", \"logs\"].includes(entry.method ?? \"\") ||\n ![\"reading\", \"ok\", \"unavailable\"].includes(entry.status ?? \"\")\n )\n return;\n const read = {\n method: entry.method as AiReadActivity[\"method\"],\n status: entry.status as \"reading\" | \"ok\" | \"unavailable\",\n };\n setActivity((previous) => ({\n key: requestKey,\n reads: [\n ...(previous.key === requestKey ? previous.reads.filter((item) => item.method !== read.method) : []),\n read,\n ],\n }));\n };\n ipcRenderer.on(AI_READ_ACTIVITY_CHANNEL, onActivity);\n window.addEventListener(\"resize\", updateDock);\n window.addEventListener(\"popstate\", update);\n update();\n const timer = window.setInterval(update, 500);\n const observer = new MutationObserver((mutations) => {\n if (hasAiContextMutations(mutations)) update();\n });\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"class\", \"style\", \"hidden\", \"open\"],\n });\n const onDiagnostic = (event: Event) => {\n const next = sanitizeDiagnosticFinding((event as CustomEvent).detail);\n if (!next || !preferences.enabled || !isClusterDocument() || next.clusterId !== readAiContext().clusterId) return;\n update();\n setFinding(next);\n setDraft(\n (previous) =>\n previous ||\n (next.source === \"relationships\" ||\n next.source === \"diagnostics\" ||\n preferences.conversations[next.clusterId]?.length\n ? \"\"\n : \"Explain this finding and suggest the next read-only checks.\"),\n );\n setOpen(true);\n requestAnimationFrame(() => composer.current?.focus());\n };\n window.addEventListener(AI_DIAGNOSTIC_EVENT, onDiagnostic);\n window.addEventListener(\"power-ai-open\", updateAndOpen);\n window.addEventListener(\"power-ai-open-only\", openOnly);\n const closePanel = () => setOpen(false);\n window.addEventListener(\"power-ai-close\", closePanel);\n function openOnly() {\n update();\n setOpen(true);\n }\n function updateAndOpen() {\n openOnly();\n clusterReview.current();\n }\n return () => {\n window.removeEventListener(\"resize\", updateDock);\n window.removeEventListener(\"popstate\", update);\n resizeObserver?.disconnect();\n ipcRenderer.removeListener(AI_READ_ACTIVITY_CHANNEL, onActivity);\n for (const requestId of activeRequests.current.keys()) {\n void ipcRenderer.invoke(AI_CANCEL_CHANNEL, requestId).catch(() => {});\n }\n activeRequests.current.clear();\n window.clearInterval(timer);\n observer.disconnect();\n window.removeEventListener(\"power-ai-open\", updateAndOpen);\n window.removeEventListener(\"power-ai-open-only\", openOnly);\n window.removeEventListener(\"power-ai-close\", closePanel);\n window.removeEventListener(AI_DIAGNOSTIC_EVENT, onDiagnostic);\n };\n }, []);\n useEffect(() => {\n setLauncherHidden(false);\n const onScroll = (event: Event) => {\n const target = event.target;\n if (!(target instanceof HTMLElement) || target.closest('.power-ai-panel, .Sidebar, [role=\"navigation\"], aside'))\n return;\n if (!target.closest('.ItemListLayout, .KubeObjectListLayout, main, [role=\"main\"]')) return;\n if (target.scrollHeight <= target.clientHeight || target.clientHeight <= 0) return;\n setLauncherHidden(target.scrollTop > 0 && target.scrollHeight - target.clientHeight - target.scrollTop <= 16);\n };\n document.addEventListener(\"scroll\", onScroll, true);\n return () => document.removeEventListener(\"scroll\", onScroll, true);\n }, [context.screen]);\n useEffect(() => {\n if (!open) return;\n const onEscape = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\" || hasAiOverlay()) return;\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n if (!dismissSuggestions.current()) setOpen(false);\n };\n window.addEventListener(\"keydown\", onEscape, true);\n return () => window.removeEventListener(\"keydown\", onEscape, true);\n }, [open]);\n useEffect(() => {\n if (!open || pinned) return;\n const onOutsideClick = (event: MouseEvent) => {\n const target = event.target;\n if (\n !(target instanceof Element) ||\n target.closest(\n \".power-ai-panel, .power-ai-launcher, .power-ai-overview-actions, [data-freelens-power-ai-overlay]\",\n )\n )\n return;\n setOpen(false);\n };\n document.addEventListener(\"click\", onOutsideClick, true);\n return () => document.removeEventListener(\"click\", onOutsideClick, true);\n }, [open, pinned]);\n const availablePanelWidth = Math.max(1, viewportWidth - Math.max(0, launcherLeft - 16));\n const panelWidth = clampAiPanelWidth(preferences.chatPanelWidth ?? DEFAULT_AI_PANEL_WIDTH, availablePanelWidth);\n const key = context.clusterId ?? \"global\";\n const messages = preferences.conversations[key] ?? [];\n const busy = pending.includes(key);\n const readActivity = activity.key === key ? activity.reads : [];\n useEffect(() => {\n const element = messagesElement.current;\n if (element && following.current) element.scrollTop = element.scrollHeight;\n }, [messages.length, busy, open, key]);\n useEffect(() => {\n following.current = true;\n const element = messagesElement.current;\n if (element && open) element.scrollTop = element.scrollHeight;\n }, [open, key]);\n useEffect(() => {\n if (!terminalAttachment) return;\n const update = () => {\n if (activeAiTerminal(terminalAttachment.clusterId) !== terminalAttachment.terminalId)\n setTerminalAttachment(undefined);\n };\n update();\n const timer = window.setInterval(update, 500);\n const observer = new MutationObserver(update);\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"class\", \"style\", \"hidden\", \"aria-hidden\", \"data-testid\"],\n });\n return () => {\n window.clearInterval(timer);\n observer.disconnect();\n };\n }, [terminalAttachment, context.clusterId]);\n if (!preferences.enabled || !isClusterDocument() || coveredByOverlay) return null;\n const send = async (starter?: string) => {\n const question = expandAiShortcut(\n (starter ?? draft).trim(),\n AiShortcutsStore.getInstanceOrCreate<AiShortcutsStore>().shortcuts,\n );\n if (!question || busy) return;\n if (question.length > 20_000) {\n setError(\"Message is too long. Please keep it under 20,000 characters.\");\n return;\n }\n const activeFinding = finding?.clusterId === readAiContext().clusterId ? finding : undefined;\n const payloadQuestion = diagnosticQuestion(question, activeFinding);\n if (payloadQuestion.length > 20_000) {\n setError(\"Message and attached finding are too long. Shorten the message or remove the finding.\");\n return;\n }\n const requestContext = attachedAiContext({\n ...readAiContext(),\n ...(activeFinding?.resource ? { resource: activeFinding.resource } : {}),\n });\n if ((requestContext.clusterId ?? \"global\") !== key) {\n setContext(requestContext);\n return;\n }\n const terminalSnapshot =\n terminalAttachment?.clusterId === requestContext.clusterId\n ? captureAiTerminal(requestContext.clusterId, terminalAttachment?.terminalId)\n : undefined;\n if (terminalAttachment && !terminalSnapshot) {\n setTerminalAttachment(undefined);\n setError(\"The attached terminal changed or is unavailable. Attach it again before sending.\");\n return;\n }\n setTerminalAttachment(undefined);\n setFinding(undefined);\n following.current = true;\n const next: AiMessage[] = [...messages, { role: \"user\", text: question }];\n preferences.setMessages(key, next);\n setDraft(\"\");\n setError(\"\");\n setStopped((keys) => keys.filter((entry) => entry !== key));\n setActivity({ key, reads: [] });\n setPending((keys) => [...keys, key]);\n const provider = preferences.provider;\n const requestId = crypto.randomUUID();\n activeRequests.current.set(requestId, key);\n try {\n const response = await ipcRenderer.invoke(AI_CHAT_CHANNEL, {\n requestId,\n messages: [...next.slice(0, -1), { role: \"user\" as const, text: payloadQuestion }]\n .slice(-80)\n .reduceRight<AiMessage[]>((tail, message) => {\n if (tail.reduce((length, item) => length + item.text.length, 0) + message.text.length < 100_000)\n tail.unshift({ role: message.role, text: message.text });\n return tail;\n }, []),\n context: requestContext,\n ...(terminalSnapshot ? { terminalSnapshot } : {}),\n systemPrompt: [\n preferences.systemPrompt,\n requestContext.clusterId ? preferences.clusterPrompt : \"\",\n isPowerLogsWorkspace() ? POWER_LOGS_SQL_DRAFT_PROMPT : \"\",\n ]\n .filter(Boolean)\n .join(\"\\n\\n\"),\n model: preferences.model,\n speed: preferences.speed,\n reasoningEffort: preferences.reasoningEffort,\n });\n if (activeRequests.current.get(requestId) !== key) return;\n if (!response || typeof response.text !== \"string\") throw new Error(\"Invalid response\");\n setActivity({\n key,\n reads: Array.isArray(response.reads)\n ? response.reads\n .filter(\n (read: AiReadActivity) =>\n [\"pods\", \"nodes\", \"resources\", \"logs\"].includes(read?.method) &&\n [\"ok\", \"unavailable\"].includes(read?.status),\n )\n .slice(0, 6)\n : [],\n });\n preferences.setMessages(key, [\n ...next,\n {\n role: \"assistant\",\n text: response.text,\n provider: response.provider === \"claude\" ? \"claude\" : provider,\n references: normalizeAiReferences(response.references),\n },\n ]);\n } catch (failure) {\n if (activeRequests.current.get(requestId) !== key) return;\n const code = String(failure).match(/FREELENS_AI_([A-Z_]+)/)?.[1];\n const messages: Record<string, string> = {\n READ_LIMIT: \"The assistant reached the read limit. Try a more specific question.\",\n TIMEOUT: \"The request timed out. Please try again.\",\n INVALID_REPLY: \"The assistant returned an incomplete reply. Please try again.\",\n CLI_FAILURE: \"The selected CLI request failed. Check your model access or try again.\",\n CANCELLED: \"The request was canceled.\",\n UNSAFE_POLICY:\n \"Claude managed policy cannot be safely isolated. Use Codex or ask your administrator to disable managed hooks and command helpers.\",\n INPUT_LIMIT: \"The request is too large. Start a new chat or shorten the message.\",\n };\n setError(\n (code && messages[code]) ||\n \"Unable to complete the request. Check that the selected CLI is installed and signed in, then try again.\",\n );\n } finally {\n activeRequests.current.delete(requestId);\n setPending((keys) => keys.filter((entry) => entry !== key));\n }\n };\n const stopResponse = () => {\n const requestId = [...activeRequests.current].find(([, requestKey]) => requestKey === key)?.[0];\n if (!requestId) return;\n activeRequests.current.delete(requestId);\n setStopped((keys) => [...keys.filter((entry) => entry !== key), key]);\n setActivity({ key, reads: [] });\n setError(\"\");\n void ipcRenderer.invoke(AI_CANCEL_CHANNEL, requestId).catch(() => {});\n };\n clusterReview.current = () => {\n const currentKey = readAiContext().clusterId;\n if (!currentKey || currentKey !== key || preferences.conversations[currentKey]?.length) return;\n void send(\n preferences.clusterPrompt.trim() ||\n \"Review this cluster using read-only queries and summarize its health and useful next steps.\",\n );\n };\n return (\n <>\n <style>{styles}</style>\n {!open && (\n <NativeTooltip title=\"Open AI assistant\">\n <button\n type=\"button\"\n className={`power-ai-launcher${launcherHidden ? \" power-ai-launcher-hidden\" : \"\"}`}\n aria-hidden={launcherHidden || undefined}\n tabIndex={launcherHidden ? -1 : 0}\n style={{\n bottom: launcherBottom,\n left: resourceDetailsOpen ? launcherLeft : \"auto\",\n right: resourceDetailsOpen ? \"auto\" : 16,\n }}\n onClick={() => setOpen(true)}\n aria-label=\"Open AI assistant\"\n >\n <span aria-hidden=\"true\">\n <AiIcon material=\"chat_bubble_outline\" size={16} />\n </span>{\" \"}\n AI\n </button>\n </NativeTooltip>\n )}\n {open && (\n <aside\n className=\"power-ai-panel\"\n aria-label=\"AI assistant\"\n style={{ \"--power-ai-font-size\": `${preferences.chatFontSize ?? 14}px`, width: panelWidth } as CSSProperties}\n >\n <AiResizeHandle\n width={panelWidth}\n available={availablePanelWidth}\n onChange={(width) => preferences.setChatPanelWidth(width)}\n />\n <header>\n <strong className=\"power-ai-title\">\n <NativeTooltip title=\"AI assistant\">\n <span className=\"power-ai-brand\">\n <AiIcon material=\"auto_awesome\" size={18} /> AI\n </span>\n </NativeTooltip>{\" \"}\n Assistant\n </strong>\n <NativeTooltip title=\"Clear this conversation and start a new chat\">\n <button\n type=\"button\"\n disabled={busy}\n aria-label=\"New chat\"\n onClick={() => {\n setTerminalAttachment(undefined);\n setFinding(undefined);\n preferences.setMessages(key, []);\n setStopped((keys) => keys.filter((entry) => entry !== key));\n setActivity({ key, reads: [] });\n setError(\"\");\n }}\n >\n <AiIcon material=\"add_comment\" size={16} /> New chat\n </button>\n </NativeTooltip>\n <NativeTooltip title={pinned ? \"Unpin to close when clicking outside\" : \"Pin to keep the assistant open\"}>\n <button\n type=\"button\"\n className=\"power-ai-pin\"\n aria-label=\"Pin AI assistant\"\n aria-pressed={pinned}\n onClick={() => setPinned((value) => !value)}\n >\n <AiIcon material=\"push_pin\" size={18} />\n </button>\n </NativeTooltip>\n <NativeTooltip title=\"Close AI assistant\">\n <button\n type=\"button\"\n onPointerDown={(event) => event.stopPropagation()}\n onMouseDown={(event) => event.stopPropagation()}\n onClick={(event) => {\n event.stopPropagation();\n setOpen(false);\n }}\n className=\"power-ai-close\"\n aria-label=\"Close AI assistant\"\n >\n <span aria-hidden=\"true\">\n <AiIcon material=\"close\" size={18} />\n </span>\n </button>\n </NativeTooltip>\n </header>\n <div className=\"power-ai-context\">\n {context.clusterId ? \"Cluster conversation\" : \"General conversation\"} · {context.screen}\n {context.resource && ` · ${context.resource.kind}/${context.resource.name}`}\n <br />\n Only screen and resource metadata are attached automatically.\n </div>\n <div\n className=\"power-ai-messages\"\n onScroll={(event) => {\n const element = event.currentTarget;\n following.current = element.scrollHeight - element.scrollTop - element.clientHeight < 48;\n }}\n aria-live=\"polite\"\n ref={messagesElement}\n >\n {messages.length === 0 && (\n <div className=\"power-ai-starters\">\n <p style={{ marginBottom: 12 }}>Ask about this screen or your cluster:</p>\n <AiStarterPrompts\n disabled={busy}\n onSelect={(prompt) => {\n void send(prompt);\n }}\n />\n </div>\n )}\n {messages.map((message, index) => (\n <div className={`power-ai-message power-ai-message-${message.role}`} key={index}>\n <strong>\n {message.role === \"user\" ? (\n <NativeTooltip title=\"You\">\n <span>\n <AiIcon material=\"person_outline\" size={16} />\n </span>\n </NativeTooltip>\n ) : (\n <AiProviderIcon provider={message.provider === \"claude\" ? \"claude\" : \"codex\"} />\n )}\n {message.role === \"user\" ? \"You\" : message.provider === \"claude\" ? \"Claude\" : \"Codex\"}\n {message.role === \"assistant\" && <AiCopyAnswer text={message.text} />}\n </strong>\n <AiMessageContent text={message.text} />\n {message.role === \"assistant\" && context.clusterId && (\n <AiResourceReferences\n clusterId={context.clusterId}\n references={message.references}\n text={message.text}\n onOpened={() => setOpen(false)}\n />\n )}\n </div>\n ))}\n {readActivity.length > 0 && (\n <div\n className=\"power-ai-read-activity\"\n style={{ fontSize: 11, color: \"var(--textColorSecondary)\", margin: \"8px 16px\" }}\n >\n {readActivity.map((read, index) => (\n <NativeTooltip\n key={index}\n title={`${read.method} · ${read.status === \"reading\" ? \"reading\" : read.status === \"ok\" ? \"read\" : \"unavailable\"}`}\n >\n <span data-method={read.method} data-status={read.status} style={{ marginRight: 10 }}>\n <AiIcon\n material={\n read.status === \"reading\"\n ? \"sync\"\n : read.status === \"ok\"\n ? \"check_circle_outline\"\n : \"info_outline\"\n }\n size={13}\n />{\" \"}\n {read.method} ·{\" \"}\n {read.status === \"reading\" ? \"reading\" : read.status === \"ok\" ? \"read\" : \"unavailable\"}\n </span>\n </NativeTooltip>\n ))}\n </div>\n )}\n {busy && (\n <p className=\"power-ai-thinking\" role=\"status\">\n {stopped.includes(key) ? \"Stopping response\" : \"Thinking\"}\n <span className=\"power-ai-dots\" aria-hidden=\"true\">\n <span>.</span>\n <span>.</span>\n <span>.</span>\n </span>\n </p>\n )}\n {!busy && stopped.includes(key) && (\n <p className=\"power-ai-cancellation\" role=\"status\">\n Response stopped{\" \"}\n <NativeTooltip title=\"Dismiss\">\n <button\n type=\"button\"\n aria-label=\"Dismiss cancellation\"\n className=\"power-ai-dismiss\"\n onClick={() => setStopped((keys) => keys.filter((entry) => entry !== key))}\n >\n <AiIcon material=\"close\" size={14} />\n </button>\n </NativeTooltip>\n </p>\n )}\n {error && <p role=\"alert\">{error}</p>}\n </div>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n void send();\n }}\n >\n {suggestions.length > 0 && (\n <div\n className=\"power-ai-autocomplete\"\n role=\"listbox\"\n id=\"power-ai-commands\"\n aria-label=\"Prompt shortcuts\"\n >\n {suggestions.map((shortcut, index) => (\n <NativeTooltip key={shortcut.id} title={`Insert /${shortcut.command}: ${shortcut.label}`}>\n <button\n type=\"button\"\n role=\"option\"\n id={`power-ai-command-${index}`}\n aria-selected={index === suggestionIndex % suggestions.length}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => selectSuggestion(index)}\n >\n <span>/{shortcut.command}</span>\n <span>{shortcut.label}</span>\n </button>\n </NativeTooltip>\n ))}\n </div>\n )}\n <AiContextPreview\n finding={finding?.clusterId === context.clusterId ? finding : undefined}\n onRemoveFinding={() => setFinding(undefined)}\n context={attachedAiContext({\n ...context,\n ...(finding && finding.clusterId === context.clusterId && finding.resource\n ? { resource: finding.resource }\n : {}),\n })}\n />\n <AiTerminalContext\n clusterId={context.clusterId}\n attachment={terminalAttachment}\n onChange={setTerminalAttachment}\n disabled={busy}\n />\n <textarea\n ref={composer}\n aria-controls={suggestions.length ? \"power-ai-commands\" : undefined}\n aria-expanded={suggestions.length > 0}\n aria-activedescendant={\n suggestions.length ? `power-ai-command-${suggestionIndex % suggestions.length}` : undefined\n }\n autoFocus\n aria-label=\"Message\"\n placeholder=\"Ask about this cluster…\"\n onKeyDown={(event) => {\n if (event.nativeEvent.isComposing || event.keyCode === 229) return;\n if (suggestions.length && !event.shiftKey) {\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n setSuggestionIndex(\n (index) =>\n (index + (event.key === \"ArrowDown\" ? 1 : suggestions.length - 1)) % suggestions.length,\n );\n return;\n }\n if (event.key === \"Enter\" || event.key === \"Tab\") {\n event.preventDefault();\n selectSuggestion(suggestionIndex % suggestions.length);\n return;\n }\n }\n if (\n event.key === \"Enter\" &&\n !event.shiftKey &&\n !event.nativeEvent.isComposing &&\n event.keyCode !== 229\n ) {\n event.preventDefault();\n if (!busy) void send();\n }\n }}\n value={draft}\n onChange={(event) => {\n setDraft(event.target.value);\n setSuggestionIndex(0);\n setDismissedDraft(undefined);\n }}\n disabled={busy}\n />\n <div className=\"power-ai-composer-footer\">\n <span>Enter to send · Shift+Enter for newline</span>\n {busy ? (\n <button\n type=\"button\"\n aria-label=\"Stop response\"\n disabled={stopped.includes(key)}\n onClick={stopResponse}\n >\n <AiIcon material=\"stop\" size={16} /> Stop\n </button>\n ) : (\n <button type=\"submit\" disabled={!draft.trim()} aria-label=\"Send\">\n <AiIcon material=\"send\" size={16} />\n </button>\n )}\n </div>\n </form>\n </aside>\n )}\n </>\n );\n});\n\nexport function startAiChat(isClusterDocument: () => boolean = isAiClusterDocument): () => void {\n const container = document.createElement(\"div\");\n container.dataset.freelensPowerAi = \"\";\n document.body.append(container);\n let mounted = false;\n let overviewActions: HTMLDivElement | undefined;\n let overviewIcon: HTMLSpanElement | undefined;\n let overviewLabel: HTMLSpanElement | undefined;\n let overviewResize: ResizeObserver | undefined;\n const updateOverviewLabel = () => {\n const overview = overviewActions?.nextElementSibling;\n const compact = Boolean(overview?.querySelector(\"[data-freelens-power-monitoring]\") && overview.clientWidth > 960);\n const label = compact ? \"Ask AI\" : \"Ask about cluster\";\n if (overviewLabel && overviewLabel.textContent !== label) overviewLabel.textContent = label;\n overviewActions?.querySelector(\"button\")?.setAttribute(\"aria-label\", compact ? \"Ask AI about cluster\" : label);\n };\n const removeOverview = () => {\n overviewResize?.disconnect();\n overviewResize = undefined;\n if (overviewIcon) ReactDOM.unmountComponentAtNode(overviewIcon);\n overviewIcon = undefined;\n overviewLabel = undefined;\n overviewActions?.remove();\n overviewActions = undefined;\n };\n const preferences = AiPreferencesStore.getInstanceOrCreate<AiPreferencesStore>();\n const reconcile = () => {\n const overview =\n preferences.enabled &&\n isClusterDocument() &&\n Renderer.Catalog.activeCluster.get() &&\n document.querySelector('[data-testid=\"cluster-overview-page\"]');\n if (!overview) {\n removeOverview();\n return;\n }\n if (overviewActions?.isConnected && overviewActions.nextElementSibling === overview) {\n updateOverviewLabel();\n return;\n }\n removeOverview();\n overviewActions = document.createElement(\"div\");\n overviewActions.className = \"power-ai-overview-actions\";\n const overviewButton = document.createElement(\"button\");\n overviewButton.type = \"button\";\n overviewButton.setAttribute(\"aria-label\", \"Ask about cluster\");\n overviewButton.id = \"power-ai-overview-button\";\n overviewIcon = document.createElement(\"span\");\n overviewIcon.setAttribute(\"aria-hidden\", \"true\");\n overviewLabel = document.createElement(\"span\");\n overviewButton.append(overviewIcon, overviewLabel);\n overviewButton.onclick = () => window.dispatchEvent(new Event(\"power-ai-open\"));\n overviewActions.append(overviewButton);\n overview.before(overviewActions);\n updateOverviewLabel();\n if (typeof ResizeObserver !== \"undefined\") {\n overviewResize = new ResizeObserver(updateOverviewLabel);\n overviewResize.observe(overview);\n }\n ReactDOM.render(\n <>\n <AiIcon material=\"auto_awesome\" size={16} />\n <Renderer.Component.Tooltip targetId=\"power-ai-overview-button\">\n Open the AI assistant to ask about this cluster\n </Renderer.Component.Tooltip>\n </>,\n overviewIcon,\n );\n };\n const observer = new MutationObserver(reconcile);\n const stop = autorun(() => {\n if (preferences.enabled && !mounted) {\n observer.observe(document.body, { childList: true, subtree: true });\n mounted = true;\n ReactDOM.render(<AiChat isClusterDocument={isClusterDocument} />, container);\n } else if (!preferences.enabled && mounted) {\n observer.disconnect();\n ReactDOM.unmountComponentAtNode(container);\n mounted = false;\n }\n reconcile();\n });\n return () => {\n stop();\n observer.disconnect();\n removeOverview();\n ReactDOM.unmountComponentAtNode(container);\n container.remove();\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ai.js","names":[],"sources":["../../src/renderer/ai.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { ipcRenderer } from \"electron\";\nimport { autorun } from \"mobx\";\nimport { observer } from \"mobx-react\";\nimport { type CSSProperties, useEffect, useRef, useState } from \"react\";\nimport ReactDOM from \"react-dom\";\nimport { AI_CHAT_CHANNEL, AI_READ_ACTIVITY_CHANNEL, type AiReadActivity } from \"../common/ai\";\nimport { AI_CANCEL_CHANNEL, attachedAiContext, normalizeAiReferences } from \"../common/ai-extras\";\nimport { expandAiShortcut } from \"../common/ai-shortcuts\";\nimport { type AiMessage, AiPreferencesStore } from \"../common/store/ai-preferences-store\";\nimport { AiShortcutsStore } from \"../common/store/ai-shortcuts-store\";\nimport { hasAiContextMutations } from \"./ai-context-mutations\";\nimport { AiCopyAnswer } from \"./ai-copy-answer\";\nimport {\n AI_DIAGNOSTIC_EVENT,\n type DiagnosticFinding,\n diagnosticQuestion,\n sanitizeDiagnosticFinding,\n} from \"./ai-diagnostic-handoff\";\nimport { AiContextPreview, AiResourceReferences } from \"./ai-extras\";\nimport { AiIcon, AiPinIcon } from \"./ai-icon\";\nimport { isPowerLogsWorkspace, POWER_LOGS_SQL_DRAFT_PROMPT } from \"./ai-logs-sql\";\nimport { AiMessageContent } from \"./ai-message\";\nimport { AiProviderIcon } from \"./ai-provider-icon\";\nimport { AiResizeHandle, clampAiPanelWidth, DEFAULT_AI_PANEL_WIDTH } from \"./ai-resize\";\nimport { AiStarterPrompts } from \"./ai-shortcuts\";\nimport {\n type AiTerminalAttachment,\n AiTerminalContext,\n activeAiTerminal,\n captureAiTerminal,\n} from \"./ai-terminal-context\";\nimport { NativeTooltip } from \"./native-tooltip\";\n\nexport interface AiScreenContext {\n clusterId?: string;\n screen?: string;\n resource?: { kind?: string; namespace?: string; name?: string };\n}\n\nexport function readAiContext(): AiScreenContext {\n const clusterId = Renderer.Catalog.activeCluster.get()?.metadata.uid;\n const screen = window.location.pathname;\n const details = new URLSearchParams(window.location.search).get(\"kube-details\");\n const match =\n details?.match(/^\\/api(?:\\/v\\d+)?\\/namespaces\\/([^/]+)\\/([^/]+)\\/([^/]+)$/) ??\n details?.match(/^\\/apis\\/[^/]+\\/[^/]+\\/namespaces\\/([^/]+)\\/([^/]+)\\/([^/]+)$/);\n const clusterResource =\n details?.match(/^\\/api\\/[^/]+\\/([^/]+)\\/([^/]+)$/) ?? details?.match(/^\\/apis\\/[^/]+\\/[^/]+\\/([^/]+)\\/([^/]+)$/);\n const resource = match\n ? { namespace: match[1], kind: match[2], name: match[3] }\n : clusterResource\n ? { kind: clusterResource[1], name: clusterResource[2] }\n : undefined;\n return { clusterId, screen, ...(resource ? { resource } : {}) };\n}\n\nexport function isAiClusterDocument(): boolean {\n return window.top !== window && Boolean(Renderer.Catalog.activeCluster.get());\n}\n\nexport function aiLauncherBottom(): number {\n const dock = document.querySelector<HTMLElement>(\".Dock\");\n if (!dock) return 16;\n const rect = dock.getBoundingClientRect();\n const style = window.getComputedStyle(dock);\n if (\n dock.hidden ||\n style.display === \"none\" ||\n style.visibility === \"hidden\" ||\n rect.width <= 0 ||\n rect.height <= 0 ||\n rect.top <= 0 ||\n rect.top >= window.innerHeight\n )\n return 16;\n return Math.max(16, window.innerHeight - rect.top + 16);\n}\n\nexport function aiLauncherLeft(): number {\n const sidebar = document.querySelector<HTMLElement>('[data-testid=\"cluster-sidebar\"], .Sidebar');\n const dock = document.querySelector<HTMLElement>(\".Dock\");\n let contentLeft = 0;\n for (const [element, edge] of [\n [sidebar, \"right\"],\n [dock, \"left\"],\n ] as const) {\n if (!element || element.hidden) continue;\n const style = window.getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n if (style.display === \"none\" || style.visibility === \"hidden\" || rect.width <= 0) continue;\n const value = rect[edge];\n if (Number.isFinite(value) && value >= 0 && value < window.innerWidth - 80)\n contentLeft = Math.max(contentLeft, value);\n }\n return contentLeft + 16;\n}\n\nexport function hasAiResourceDetails(): boolean {\n if (new URLSearchParams(window.location.search).get(\"kube-details\")) return true;\n return Array.from(\n document.querySelectorAll<HTMLElement>(\".Drawer.KubeObjectDetails, .Drawer.ReleaseDetails, .DetailsDrawer\"),\n ).some((element) => {\n const style = window.getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n return (\n !element.hidden && style.display !== \"none\" && style.visibility !== \"hidden\" && rect.width > 0 && rect.height > 0\n );\n });\n}\n\nexport function hasAiOverlay(): boolean {\n return Array.from(document.querySelectorAll<HTMLElement>('[role=\"dialog\"], dialog[open], .Dialog')).some(\n (element) => {\n const style = window.getComputedStyle(element);\n return !element.hidden && style.display !== \"none\" && style.visibility !== \"hidden\";\n },\n );\n}\n\nconst styles = `\n@keyframes power-ai-spin { to { transform: rotate(360deg); } }\n@keyframes power-ai-dot { 0%, 80%, 100% { opacity: .25; } 40% { opacity: 1; } }\nbody:has(.AddRemoveButtons .remove-button:not([data-freelens-power-read-only])) .power-ai-launcher { display: none; }\n.power-ai-read-activity > span { display: inline-flex; align-items: center; gap: 4px; }\n.power-ai-read-activity [data-status=\"reading\"] .Icon { animation: power-ai-spin 1.2s linear infinite; }\n.power-ai-thinking { margin: 12px 16px 18px; line-height: 1.5; color: var(--textColorSecondary); }\n.power-ai-dots > span { animation: power-ai-dot 1.3s ease-in-out infinite; }\n.power-ai-dots > span:nth-child(2) { animation-delay: .15s; }\n.power-ai-dots > span:nth-child(3) { animation-delay: .3s; }\n@media (prefers-reduced-motion: reduce) { .power-ai-read-activity [data-status=\"reading\"] .Icon, .power-ai-dots > span { animation: none; } }\n@keyframes power-ai-enter { from { transform: translateX(100%); } to { transform: translateX(0); } }\n:root .power-ai-launcher { position: fixed; bottom: 16px; left: auto; right: 16px; z-index: 100; display: inline-flex; align-items: center; gap: 6px; min-width: 0; min-height: 0; height: 34px; border: 1px solid var(--primary, #5896ff); border-radius: 24px; padding: 0 13px; background: var(--contentColor, #242424); color: var(--textColorAccent); box-shadow: 0 3px 12px #0003; font: inherit; font-size: 12px; font-weight: 500; line-height: 1; cursor: pointer; transition: opacity 180ms ease, background-color 140ms ease, box-shadow 140ms ease, transform 180ms ease; }\n.power-ai-overview-actions { position: relative; z-index: 5; height: 0; min-height: 0; flex: 0 0 0; pointer-events: none; }\n.power-ai-overview-actions + [data-testid=\"cluster-overview-page\"] [data-monitoring-summaries] { --power-monitoring-summary-top: 56px; }\n.power-ai-overview-actions button { transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease, box-shadow 160ms ease; position: absolute; top: 12px; right: 12px; pointer-events: auto; box-shadow: 0 2px 8px #0002; display: inline-flex; flex: 0 0 auto; width: auto; align-items: center; gap: 6px; min-height: 32px; padding: 6px 12px; font: inherit; font-size: 12px; border: 1px solid var(--borderFaintColor); border-radius: 10px; color: var(--textColorPrimary); background: var(--contentColor); cursor: pointer; }\n.power-ai-overview-actions button:hover { border-color: var(--primary); color: var(--textColorAccent); background: var(--contentColor); }\n.power-ai-overview-actions button:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-launcher.power-ai-launcher-hidden { opacity: 0; transform: translateY(8px); pointer-events: none; }\n.power-ai-launcher .Icon { color: inherit; }\n.power-ai-launcher:hover { background: color-mix(in srgb, var(--primary, #5896ff) 12%, var(--contentColor, #242424)); box-shadow: 0 4px 12px #0003; transform: translateY(-1px); }\n.power-ai-launcher:active { transform: translateY(0); box-shadow: 0 2px 6px #0002; }\n@media (prefers-reduced-motion: reduce) { :root .power-ai-launcher { transition: none; } .power-ai-launcher:hover, .power-ai-launcher:active { transform: none; } }\n.power-ai-launcher:focus-visible { outline: 2px solid var(--primary, #5896ff); outline-offset: 3px; }\n.power-ai-panel { position: fixed; right: 0; top: 0; bottom: 0; width: min(560px, 100vw); z-index: 10001; display: flex; flex-direction: column; background: var(--contentColor, #242424); color: var(--textColorAccent, white); animation: power-ai-enter 160ms ease-out; border-left: 1px solid var(--borderFaintColor); box-shadow: -4px 0 24px #0004; }\n.power-ai-resize-handle { position: absolute; left: -4px; top: 0; bottom: 0; width: 8px; z-index: 2; cursor: col-resize; touch-action: none; }\n.power-ai-resize-handle:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }\n.power-ai-panel header { padding: 16px; display: flex; gap: 10px; flex-shrink: 0; }\n.power-ai-panel header { border-bottom: 1px solid var(--borderFaintColor); justify-content: space-between; align-items: center; }\n.power-ai-messages { overflow: auto; flex: 1; min-height: 0; padding: 24px 16px; font-size: var(--power-ai-font-size, 14px); line-height: 1.65; overscroll-behavior: contain; }\n.power-ai-message { overflow-wrap: anywhere; padding: 14px 16px; margin-bottom: 20px; color: var(--textColorAccent); border: 1px solid var(--borderFaintColor); border-radius: 8px; }\n.power-ai-panel button { padding: 7px 10px; border: 1px solid var(--borderFaintColor); border-radius: 8px; background: var(--contentColor); color: var(--textColorPrimary); cursor: pointer; }\n:root .power-ai-panel header button:is(.power-ai-close, .power-ai-pin) { width: 30px; height: 30px; padding: 0; display: inline-flex; align-items: center; justify-content: center; border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel header button:is(.power-ai-close, .power-ai-pin):not(:disabled):not(.disabled):hover { color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent); }\n:root .power-ai-panel header button:is(.power-ai-close, .power-ai-pin):focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n:root .power-ai-panel button.power-ai-copy-answer { width: 24px; height: 24px; padding: 0; margin-left: auto; flex-shrink: 0; justify-content: center; border: 0; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel button.power-ai-copy-answer:not(:disabled):not(.disabled):hover { color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent); }\n:root .power-ai-panel button.power-ai-copy-answer:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-cancellation { display: flex; align-items: center; gap: 6px; }\n:root .power-ai-panel button.power-ai-dismiss { width: 24px; height: 24px; padding: 0; justify-content: center; border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel button.power-ai-dismiss:hover { color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent); }\n:root .power-ai-panel button.power-ai-dismiss:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-panel button:disabled { opacity: 0.5; cursor: default; }\n .power-ai-panel textarea { display: block; width: 100%; box-sizing: border-box; min-width: 0; min-height: 64px; max-height: 180px; field-sizing: content; padding: 12px 16px 6px; border: 0; border-radius: 12px; background: transparent; color: var(--textColorAccent); font: inherit; font-size: var(--power-ai-font-size, 14px); line-height: 1.5; resize: none; }\n.power-ai-panel textarea::placeholder { color: var(--textColorSecondary); opacity: 1; }\n.power-ai-panel textarea:focus { outline: none; }\n.power-ai-composer-footer { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 4px 10px 10px 16px; }\n.power-ai-composer-footer > span { color: var(--textColorSecondary); font-size: 11px; line-height: 1.5; }\n:root .power-ai-panel form button[type=\"submit\"] { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 34px; width: 34px; height: 34px; padding: 0; border-radius: 10px; }\n:root .power-ai-panel form button[type=\"submit\"]:not(:disabled):not(.disabled) { background-color: var(--primary); border-color: var(--primary); color: white; }\n:root .power-ai-panel form button[type=\"submit\"]:not(:disabled):not(.disabled):hover { background-color: color-mix(in srgb, var(--primary) 88%, white 12%); border-color: color-mix(in srgb, var(--primary) 88%, white 12%); color: white; }\n:root .power-ai-panel form button[type=\"submit\"]:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }\n:root .power-ai-panel form button[type=\"submit\"]:disabled { background-color: var(--contentColor); border-color: var(--borderFaintColor); color: var(--textColorSecondary); }\n.power-ai-message-user { border-color: color-mix(in srgb, var(--primary) 28%, var(--borderFaintColor)); background: color-mix(in srgb, var(--primary) 7%, var(--mainBackground)); }\n.power-ai-context { padding: 10px 20px; line-height: 1.5; border-bottom: 1px solid var(--borderFaintColor); font-size: 12px; color: var(--textColorSecondary); overflow-wrap: anywhere; }\n.power-ai-attached-resource { display: flex; align-items: center; justify-content: space-between; gap: 8px; }\n.power-ai-title, .power-ai-panel button { display: inline-flex; align-items: center; gap: 6px; }\n.power-ai-title { margin-right: auto; white-space: nowrap; color: var(--textColorAccent); }\n.power-ai-brand { display: inline-flex; align-items: center; gap: 6px; color: var(--primary); }\n.power-ai-brand .Icon { color: inherit; }\n:root .power-ai-panel header button.power-ai-pin[aria-pressed=\"true\"] { color: var(--primary); }\n.power-ai-panel header > button { flex-shrink: 0; }\n.power-ai-panel form { position: relative; flex-shrink: 0; margin: 0 16px 16px; border: 1px solid var(--borderFaintColor); border-radius: 12px; background: var(--mainBackground); transition: border-color 160ms ease; }\n.power-ai-panel form > .power-ai-context-preview { padding: 8px 48px 4px 16px !important; min-height: 34px; margin: 0; box-sizing: border-box; }\n.power-ai-context-preview pre { white-space: pre-wrap; overflow-wrap: anywhere; overflow: auto; }\n.power-ai-finding-content pre { max-height: 140px; }\n.power-ai-context-content pre { max-height: 160px; }\n.power-ai-context-preview .power-log-json { --json-key:#9cdcfe; --json-string:#ce9178; --json-number:#b5cea8; --json-literal:#c586c0; }\n.theme-light .power-ai-context-preview .power-log-json { --json-key:#005a9e; --json-string:#9e2b1a; --json-number:#17642d; --json-literal:#7a288c; }\n.power-ai-context-preview .power-log-json [data-token=key] { color:var(--json-key); }\n.power-ai-context-preview .power-log-json [data-token=string] { color:var(--json-string); }\n.power-ai-context-preview .power-log-json [data-token=number] { color:var(--json-number); }\n.power-ai-context-preview .power-log-json [data-token=literal] { color:var(--json-literal); }\n.power-ai-context-finding { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 4px; min-width: 0; }\n.power-ai-context-finding > .Icon { flex-shrink: 0; margin-top: 7px; }\n.power-ai-context-finding > details { flex: 1; min-width: 0; }\n.power-ai-context-finding summary { padding: 6px 0; min-height: 28px; box-sizing: border-box; cursor: pointer; overflow-wrap: anywhere; }\n:root .power-ai-panel button.power-ai-remove-context { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; min-height: 28px; flex-shrink: 0; padding: 0; border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel button.power-ai-remove-context:hover { background: color-mix(in srgb, var(--primary) 10%, transparent); color: var(--primary); }\n:root .power-ai-panel button.power-ai-remove-context:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-panel form:focus-within { border-color: var(--primary); }\n.power-ai-message > strong { display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 500; color: var(--textColorSecondary); margin-bottom: 10px; }\n.power-ai-message-assistant { border-color: transparent; background: transparent; }\n.power-ai-markdown { line-height: 1.65; font-size: var(--power-ai-font-size, 14px); color: var(--textColorAccent); }\n.power-ai-markdown p { margin: 0 0 14px; white-space: pre-wrap; }\n.power-ai-markdown p:last-child { margin-bottom: 0; }\n.power-ai-markdown ul, .power-ai-markdown ol { padding-left: 24px; margin: 10px 0 16px; }\n.power-ai-markdown ul { list-style: disc; }\n.power-ai-markdown ol { list-style: decimal; }\n.power-ai-markdown li { margin: 5px 0; }\n.power-ai-markdown li > ul, .power-ai-markdown li > ol { margin: 6px 0; }\n.power-ai-markdown li > p { margin-bottom: 6px; }\n.power-ai-markdown :is(h1, h2, h3, h4, h5, h6) { color: var(--textColorAccent); font-weight: 600; line-height: 1.4; margin: 24px 0 12px; }\n.power-ai-markdown :is(h1, h2, h3, h4, h5, h6):first-child { margin-top: 0; }\n.power-ai-markdown h1 { font-size: 1.43em; }\n.power-ai-markdown h2 { font-size: 1.29em; }\n.power-ai-markdown h3 { font-size: 1.14em; }\n.power-ai-markdown :is(h4, h5, h6) { font-size: 1em; }\n.power-ai-markdown blockquote { margin: 16px 0; padding: 4px 14px; border-left: 3px solid var(--borderColor); color: var(--textColorSecondary); }\n.power-ai-markdown blockquote > p:last-child { margin-bottom: 0; }\n.power-ai-markdown table { display: block; max-width: 100%; overflow-x: auto; margin: 16px 0; border-collapse: collapse; font-size: max(10px, calc(var(--power-ai-font-size, 14px) - 1px)); }\n.power-ai-markdown th, .power-ai-markdown td { padding: 9px 12px; border: 1px solid var(--borderFaintColor); text-align: left; }\n.power-ai-markdown th { font-weight: 600; background: color-mix(in srgb, var(--textColorAccent) 5%, transparent); }\n.power-ai-markdown a { color: var(--primary); text-decoration: underline; text-underline-offset: 2px; }\n.power-ai-markdown hr { margin: 20px 0; border: 0; border-top: 1px solid var(--borderFaintColor); }\n.power-ai-markdown code { font-family: var(--font-monospace, monospace); font-size: max(10px, calc(var(--power-ai-font-size, 14px) - 1px)); background: color-mix(in srgb, var(--textColorAccent) 8%, transparent); padding: 1px 4px; border-radius: 4px; }\n.power-ai-code { margin: 12px 0; border: 1px solid var(--borderFaintColor); border-radius: 8px; overflow: hidden; background: var(--mainBackground); }\n.power-ai-code-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 8px; border-bottom: 1px solid var(--borderFaintColor); color: var(--textColorSecondary); font-size: 11px; }\n.power-ai-code-toolbar > div { display: flex; gap: 4px; }\n.power-ai-code-toolbar button { padding: 4px 6px; font-size: 11px; }\n.power-ai-code pre { margin: 0; padding: 12px; overflow-x: auto; white-space: pre; }\n.power-ai-code pre code { padding: 0; background: transparent; }\n.power-ai-code-hint, .power-ai-code-feedback:not(:empty) { padding: 0 12px 10px; color: var(--textColorSecondary); font-size: 11px; }\n.power-ai-autocomplete { position: absolute; bottom: calc(100% + 8px); left: 0; right: 0; max-height: 240px; overflow-y: auto; padding: 6px; border: 1px solid var(--borderColor); border-radius: 10px; background: var(--contentColor); box-shadow: 0 4px 16px #0003; }\n.power-ai-autocomplete button { display: flex; width: 100%; justify-content: space-between; gap: 12px; border: 0; text-align: left; }\n.power-ai-autocomplete button[aria-selected=\"true\"] { background: color-mix(in srgb, var(--primary) 14%, var(--contentColor)); color: var(--textColorAccent); }\n.power-ai-autocomplete button > span:last-child { color: var(--textColorSecondary); font-size: 12px; }\n@media (prefers-reduced-motion: reduce) { .power-ai-panel { animation: none; } }\n`;\n\nconst AiChat = observer(({ isClusterDocument }: { isClusterDocument: () => boolean }) => {\n const preferences = AiPreferencesStore.getInstanceOrCreate<AiPreferencesStore>();\n const [open, setOpen] = useState(false);\n const [pinned, setPinned] = useState(false);\n const [launcherBottom, setLauncherBottom] = useState(aiLauncherBottom);\n const [launcherLeft, setLauncherLeft] = useState(aiLauncherLeft);\n const [resourceDetailsOpen, setResourceDetailsOpen] = useState(hasAiResourceDetails);\n const [viewportWidth, setViewportWidth] = useState(window.innerWidth);\n const [launcherHidden, setLauncherHidden] = useState(false);\n const [draft, setDraft] = useState(\"\");\n const [finding, setFinding] = useState<DiagnosticFinding>();\n const [resourceAttachment, setResourceAttachment] = useState<AiScreenContext>();\n const dismissedResource = useRef<string>();\n const panelOpen = useRef(open);\n panelOpen.current = open;\n const captureScreenResource = (current = readAiContext()) => {\n if (\n current.clusterId &&\n current.resource &&\n dismissedResource.current !== JSON.stringify({ clusterId: current.clusterId, resource: current.resource })\n )\n setResourceAttachment(current);\n };\n const attachScreenResource = () => {\n dismissedResource.current = undefined;\n captureScreenResource();\n };\n const removeResource = () => {\n const current = resourceAttachment ?? readAiContext();\n dismissedResource.current = JSON.stringify({ clusterId: current.clusterId, resource: current.resource });\n setResourceAttachment(undefined);\n };\n const [terminalAttachment, setTerminalAttachment] = useState<AiTerminalAttachment>();\n const [suggestionIndex, setSuggestionIndex] = useState(0);\n const [dismissedDraft, setDismissedDraft] = useState<string>();\n const suggestions =\n /^\\/[^\\s]*$/.test(draft) && dismissedDraft !== draft\n ? AiShortcutsStore.getInstanceOrCreate<AiShortcutsStore>().shortcuts.filter((shortcut) =>\n `${shortcut.command} ${shortcut.label}`.toLowerCase().includes(draft.slice(1).toLowerCase()),\n )\n : [];\n const dismissSuggestions = useRef<() => boolean>(() => false);\n dismissSuggestions.current = () => {\n if (!suggestions.length) return false;\n setDismissedDraft(draft);\n return true;\n };\n const following = useRef(true);\n const composer = useRef<HTMLTextAreaElement>(null);\n const selectSuggestion = (index: number) => {\n const shortcut = suggestions[index];\n if (!shortcut) return;\n setDraft(`/${shortcut.command} `);\n setSuggestionIndex(0);\n composer.current?.focus();\n };\n const [context, setContext] = useState(readAiContext);\n useEffect(() => {\n if (open && !finding && !terminalAttachment) window.dispatchEvent(new Event(\"power-ai-request-screen-context\"));\n }, [open]);\n const [pending, setPending] = useState<string[]>([]);\n const [error, setError] = useState(\"\");\n const [stopped, setStopped] = useState<string[]>([]);\n const activeRequests = useRef(new Map<string, string>());\n const [activity, setActivity] = useState<{\n key: string;\n reads: { method: AiReadActivity[\"method\"]; status: \"reading\" | \"ok\" | \"unavailable\" }[];\n }>({ key: \"\", reads: [] });\n const clusterReview = useRef<() => void>(() => {});\n const messagesElement = useRef<HTMLDivElement>(null);\n const [coveredByOverlay, setCoveredByOverlay] = useState(hasAiOverlay);\n useEffect(() => {\n let observedElements: Element[] = [];\n const resizeObserver =\n typeof ResizeObserver === \"undefined\"\n ? undefined\n : new ResizeObserver(() => {\n setLauncherBottom(aiLauncherBottom());\n setLauncherLeft(aiLauncherLeft());\n });\n const updateDock = () => {\n setViewportWidth(window.innerWidth);\n setLauncherBottom(aiLauncherBottom());\n setLauncherLeft(aiLauncherLeft());\n const elements = [\n document.querySelector(\".Dock\"),\n document.querySelector('[data-testid=\"cluster-sidebar\"], .Sidebar'),\n ].filter((element): element is Element => !!element);\n if (\n elements.length !== observedElements.length ||\n elements.some((element, index) => element !== observedElements[index])\n ) {\n resizeObserver?.disconnect();\n observedElements = elements;\n for (const element of elements) resizeObserver?.observe(element);\n }\n };\n const update = () => {\n updateDock();\n const nextContext = readAiContext();\n setContext(nextContext);\n if (panelOpen.current) captureScreenResource(nextContext);\n setResourceAttachment((current) => (current?.clusterId === nextContext.clusterId ? current : undefined));\n setFinding((current) => (current && current.clusterId !== nextContext.clusterId ? undefined : current));\n setResourceDetailsOpen(hasAiResourceDetails());\n setCoveredByOverlay(hasAiOverlay());\n };\n const onActivity = (_event: unknown, value: unknown) => {\n if (!value || typeof value !== \"object\") return;\n const entry = value as { requestId?: string; method?: string; status?: string };\n const requestKey = activeRequests.current.get(entry.requestId ?? \"\");\n if (\n !requestKey ||\n requestKey !== readAiContext().clusterId ||\n ![\"pods\", \"nodes\", \"resources\", \"logs\"].includes(entry.method ?? \"\") ||\n ![\"reading\", \"ok\", \"unavailable\"].includes(entry.status ?? \"\")\n )\n return;\n const read = {\n method: entry.method as AiReadActivity[\"method\"],\n status: entry.status as \"reading\" | \"ok\" | \"unavailable\",\n };\n setActivity((previous) => ({\n key: requestKey,\n reads: [\n ...(previous.key === requestKey ? previous.reads.filter((item) => item.method !== read.method) : []),\n read,\n ],\n }));\n };\n ipcRenderer.on(AI_READ_ACTIVITY_CHANNEL, onActivity);\n window.addEventListener(\"resize\", updateDock);\n window.addEventListener(\"popstate\", update);\n update();\n const timer = window.setInterval(update, 500);\n const observer = new MutationObserver((mutations) => {\n if (hasAiContextMutations(mutations)) update();\n });\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"class\", \"style\", \"hidden\", \"open\"],\n });\n const onDiagnostic = (event: Event) => {\n const next = sanitizeDiagnosticFinding((event as CustomEvent).detail);\n if (!next || !preferences.enabled || !isClusterDocument() || next.clusterId !== readAiContext().clusterId) return;\n update();\n setFinding(next);\n setDraft(\n (previous) =>\n previous ||\n (next.source === \"relationships\" ||\n next.source === \"diagnostics\" ||\n preferences.conversations[next.clusterId]?.length\n ? \"\"\n : \"Explain this finding and suggest the next read-only checks.\"),\n );\n setOpen(true);\n requestAnimationFrame(() => composer.current?.focus());\n };\n window.addEventListener(AI_DIAGNOSTIC_EVENT, onDiagnostic);\n window.addEventListener(\"power-ai-open\", updateAndOpen);\n window.addEventListener(\"power-ai-open-only\", openOnly);\n const closePanel = () => setOpen(false);\n window.addEventListener(\"power-ai-close\", closePanel);\n function openOnly() {\n attachScreenResource();\n update();\n setOpen(true);\n }\n function updateAndOpen() {\n openOnly();\n clusterReview.current();\n }\n return () => {\n window.removeEventListener(\"resize\", updateDock);\n window.removeEventListener(\"popstate\", update);\n resizeObserver?.disconnect();\n ipcRenderer.removeListener(AI_READ_ACTIVITY_CHANNEL, onActivity);\n for (const requestId of activeRequests.current.keys()) {\n void ipcRenderer.invoke(AI_CANCEL_CHANNEL, requestId).catch(() => {});\n }\n activeRequests.current.clear();\n window.clearInterval(timer);\n observer.disconnect();\n window.removeEventListener(\"power-ai-open\", updateAndOpen);\n window.removeEventListener(\"power-ai-open-only\", openOnly);\n window.removeEventListener(\"power-ai-close\", closePanel);\n window.removeEventListener(AI_DIAGNOSTIC_EVENT, onDiagnostic);\n };\n }, []);\n useEffect(() => {\n setLauncherHidden(false);\n const onScroll = (event: Event) => {\n const target = event.target;\n if (!(target instanceof HTMLElement) || target.closest('.power-ai-panel, .Sidebar, [role=\"navigation\"], aside'))\n return;\n if (!target.closest('.ItemListLayout, .KubeObjectListLayout, main, [role=\"main\"]')) return;\n if (target.scrollHeight <= target.clientHeight || target.clientHeight <= 0) return;\n setLauncherHidden(target.scrollTop > 0 && target.scrollHeight - target.clientHeight - target.scrollTop <= 16);\n };\n document.addEventListener(\"scroll\", onScroll, true);\n return () => document.removeEventListener(\"scroll\", onScroll, true);\n }, [context.screen]);\n useEffect(() => {\n if (!open) return;\n const onEscape = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\" || hasAiOverlay()) return;\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n if (!dismissSuggestions.current()) setOpen(false);\n };\n window.addEventListener(\"keydown\", onEscape, true);\n return () => window.removeEventListener(\"keydown\", onEscape, true);\n }, [open]);\n useEffect(() => {\n if (!open || pinned) return;\n const onOutsideClick = (event: MouseEvent) => {\n const target = event.target;\n if (\n !(target instanceof Element) ||\n target.closest(\n \".power-ai-panel, .power-ai-launcher, .power-ai-overview-actions, [data-freelens-power-ai-overlay]\",\n )\n )\n return;\n setOpen(false);\n };\n document.addEventListener(\"click\", onOutsideClick, true);\n return () => document.removeEventListener(\"click\", onOutsideClick, true);\n }, [open, pinned]);\n const availablePanelWidth = Math.max(1, viewportWidth - Math.max(0, launcherLeft - 16));\n const panelWidth = clampAiPanelWidth(preferences.chatPanelWidth ?? DEFAULT_AI_PANEL_WIDTH, availablePanelWidth);\n const attachedResource =\n resourceAttachment && resourceAttachment.clusterId === context.clusterId ? resourceAttachment.resource : undefined;\n const previewContext = attachedAiContext({\n clusterId: context.clusterId,\n screen: context.screen,\n ...(finding && finding.clusterId === context.clusterId && finding.resource\n ? { resource: finding.resource }\n : attachedResource\n ? { resource: attachedResource }\n : {}),\n });\n const key = context.clusterId ?? \"global\";\n const messages = preferences.conversations[key] ?? [];\n const busy = pending.includes(key);\n const readActivity = activity.key === key ? activity.reads : [];\n useEffect(() => {\n const element = messagesElement.current;\n if (element && following.current) element.scrollTop = element.scrollHeight;\n }, [messages.length, busy, open, key]);\n useEffect(() => {\n following.current = true;\n const element = messagesElement.current;\n if (element && open) element.scrollTop = element.scrollHeight;\n }, [open, key]);\n useEffect(() => {\n if (!terminalAttachment) return;\n const update = () => {\n if (activeAiTerminal(terminalAttachment.clusterId) !== terminalAttachment.terminalId)\n setTerminalAttachment(undefined);\n };\n update();\n const timer = window.setInterval(update, 500);\n const observer = new MutationObserver(update);\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"class\", \"style\", \"hidden\", \"aria-hidden\", \"data-testid\"],\n });\n return () => {\n window.clearInterval(timer);\n observer.disconnect();\n };\n }, [terminalAttachment, context.clusterId]);\n if (!preferences.enabled || !isClusterDocument() || coveredByOverlay) return null;\n const send = async (starter?: string) => {\n const question = expandAiShortcut(\n (starter ?? draft).trim(),\n AiShortcutsStore.getInstanceOrCreate<AiShortcutsStore>().shortcuts,\n );\n if (!question || busy) return;\n if (question.length > 20_000) {\n setError(\"Message is too long. Please keep it under 20,000 characters.\");\n return;\n }\n const activeFinding = finding?.clusterId === readAiContext().clusterId ? finding : undefined;\n const payloadQuestion = diagnosticQuestion(question, activeFinding);\n if (payloadQuestion.length > 20_000) {\n setError(\"Message and attached finding are too long. Shorten the message or remove the finding.\");\n return;\n }\n const currentContext = readAiContext();\n const requestResource =\n activeFinding?.resource ??\n (resourceAttachment && resourceAttachment.clusterId === currentContext.clusterId\n ? resourceAttachment.resource\n : undefined);\n const requestContext = attachedAiContext({\n clusterId: currentContext.clusterId,\n screen: currentContext.screen,\n ...(requestResource ? { resource: requestResource } : {}),\n });\n if ((requestContext.clusterId ?? \"global\") !== key) {\n setContext(requestContext);\n return;\n }\n const terminalSnapshot =\n terminalAttachment?.clusterId === requestContext.clusterId\n ? captureAiTerminal(requestContext.clusterId, terminalAttachment?.terminalId)\n : undefined;\n if (terminalAttachment && !terminalSnapshot) {\n setTerminalAttachment(undefined);\n setError(\"The attached terminal changed or is unavailable. Attach it again before sending.\");\n return;\n }\n setTerminalAttachment(undefined);\n setFinding(undefined);\n following.current = true;\n const next: AiMessage[] = [...messages, { role: \"user\", text: question }];\n preferences.setMessages(key, next);\n setDraft(\"\");\n setError(\"\");\n setStopped((keys) => keys.filter((entry) => entry !== key));\n setActivity({ key, reads: [] });\n setPending((keys) => [...keys, key]);\n const provider = preferences.provider;\n const requestId = crypto.randomUUID();\n activeRequests.current.set(requestId, key);\n try {\n const response = await ipcRenderer.invoke(AI_CHAT_CHANNEL, {\n requestId,\n messages: [...next.slice(0, -1), { role: \"user\" as const, text: payloadQuestion }]\n .slice(-80)\n .reduceRight<AiMessage[]>((tail, message) => {\n if (tail.reduce((length, item) => length + item.text.length, 0) + message.text.length < 100_000)\n tail.unshift({ role: message.role, text: message.text });\n return tail;\n }, []),\n context: requestContext,\n ...(terminalSnapshot ? { terminalSnapshot } : {}),\n systemPrompt: [\n preferences.systemPrompt,\n requestContext.clusterId ? preferences.clusterPrompt : \"\",\n isPowerLogsWorkspace() ? POWER_LOGS_SQL_DRAFT_PROMPT : \"\",\n ]\n .filter(Boolean)\n .join(\"\\n\\n\"),\n model: preferences.model,\n speed: preferences.speed,\n reasoningEffort: preferences.reasoningEffort,\n });\n if (activeRequests.current.get(requestId) !== key) return;\n if (!response || typeof response.text !== \"string\") throw new Error(\"Invalid response\");\n setActivity({\n key,\n reads: Array.isArray(response.reads)\n ? response.reads\n .filter(\n (read: AiReadActivity) =>\n [\"pods\", \"nodes\", \"resources\", \"logs\"].includes(read?.method) &&\n [\"ok\", \"unavailable\"].includes(read?.status),\n )\n .slice(0, 6)\n : [],\n });\n preferences.setMessages(key, [\n ...next,\n {\n role: \"assistant\",\n text: response.text,\n provider: response.provider === \"claude\" ? \"claude\" : provider,\n references: normalizeAiReferences(response.references),\n },\n ]);\n } catch (failure) {\n if (activeRequests.current.get(requestId) !== key) return;\n const code = String(failure).match(/FREELENS_AI_([A-Z_]+)/)?.[1];\n const messages: Record<string, string> = {\n READ_LIMIT: \"The assistant reached the read limit. Try a more specific question.\",\n TIMEOUT: \"The request timed out. Please try again.\",\n INVALID_REPLY: \"The assistant returned an incomplete reply. Please try again.\",\n CLI_FAILURE: \"The selected CLI request failed. Check your model access or try again.\",\n CANCELLED: \"The request was canceled.\",\n UNSAFE_POLICY:\n \"Claude managed policy cannot be safely isolated. Use Codex or ask your administrator to disable managed hooks and command helpers.\",\n INPUT_LIMIT: \"The request is too large. Start a new chat or shorten the message.\",\n };\n setError(\n (code && messages[code]) ||\n \"Unable to complete the request. Check that the selected CLI is installed and signed in, then try again.\",\n );\n } finally {\n activeRequests.current.delete(requestId);\n setPending((keys) => keys.filter((entry) => entry !== key));\n }\n };\n const stopResponse = () => {\n const requestId = [...activeRequests.current].find(([, requestKey]) => requestKey === key)?.[0];\n if (!requestId) return;\n activeRequests.current.delete(requestId);\n setStopped((keys) => [...keys.filter((entry) => entry !== key), key]);\n setActivity({ key, reads: [] });\n setError(\"\");\n void ipcRenderer.invoke(AI_CANCEL_CHANNEL, requestId).catch(() => {});\n };\n clusterReview.current = () => {\n const currentKey = readAiContext().clusterId;\n if (!currentKey || currentKey !== key || preferences.conversations[currentKey]?.length) return;\n void send(\n preferences.clusterPrompt.trim() ||\n \"Review this cluster using read-only queries and summarize its health and useful next steps.\",\n );\n };\n return (\n <>\n <style>{styles}</style>\n {!open && (\n <NativeTooltip title=\"Open AI assistant\">\n <button\n type=\"button\"\n className={`power-ai-launcher${launcherHidden ? \" power-ai-launcher-hidden\" : \"\"}`}\n aria-hidden={launcherHidden || undefined}\n tabIndex={launcherHidden ? -1 : 0}\n style={{\n bottom: launcherBottom,\n left: resourceDetailsOpen ? launcherLeft : \"auto\",\n right: resourceDetailsOpen ? \"auto\" : 16,\n }}\n onPointerDown={attachScreenResource}\n onMouseDown={attachScreenResource}\n onClick={() => {\n attachScreenResource();\n setOpen(true);\n }}\n aria-label=\"Open AI assistant\"\n >\n <span aria-hidden=\"true\">\n <AiIcon material=\"chat_bubble_outline\" size={16} />\n </span>{\" \"}\n AI\n </button>\n </NativeTooltip>\n )}\n {open && (\n <aside\n className=\"power-ai-panel\"\n aria-label=\"AI assistant\"\n onPointerDownCapture={() => captureScreenResource()}\n onMouseDownCapture={() => captureScreenResource()}\n onFocusCapture={() => captureScreenResource()}\n style={{ \"--power-ai-font-size\": `${preferences.chatFontSize ?? 14}px`, width: panelWidth } as CSSProperties}\n >\n <AiResizeHandle\n width={panelWidth}\n available={availablePanelWidth}\n onChange={(width) => preferences.setChatPanelWidth(width)}\n />\n <header>\n <strong className=\"power-ai-title\">\n <NativeTooltip title=\"AI assistant\">\n <span className=\"power-ai-brand\">\n <AiIcon material=\"auto_awesome\" size={18} /> AI\n </span>\n </NativeTooltip>{\" \"}\n Assistant\n </strong>\n <NativeTooltip title=\"Clear this conversation and start a new chat\">\n <button\n type=\"button\"\n disabled={busy}\n aria-label=\"New chat\"\n onClick={() => {\n setTerminalAttachment(undefined);\n setFinding(undefined);\n removeResource();\n preferences.setMessages(key, []);\n setStopped((keys) => keys.filter((entry) => entry !== key));\n setActivity({ key, reads: [] });\n setError(\"\");\n }}\n >\n <AiIcon material=\"add_comment\" size={16} /> New chat\n </button>\n </NativeTooltip>\n <NativeTooltip title={pinned ? \"Unpin to close when clicking outside\" : \"Pin to keep the assistant open\"}>\n <button\n type=\"button\"\n className=\"power-ai-pin\"\n aria-label=\"Pin AI assistant\"\n aria-pressed={pinned}\n onClick={() => setPinned((value) => !value)}\n >\n <AiPinIcon pinned={pinned} size={18} />\n </button>\n </NativeTooltip>\n <NativeTooltip title=\"Close AI assistant\">\n <button\n type=\"button\"\n onPointerDown={(event) => event.stopPropagation()}\n onMouseDown={(event) => event.stopPropagation()}\n onClick={(event) => {\n event.stopPropagation();\n setOpen(false);\n }}\n className=\"power-ai-close\"\n aria-label=\"Close AI assistant\"\n >\n <span aria-hidden=\"true\">\n <AiIcon material=\"close\" size={18} />\n </span>\n </button>\n </NativeTooltip>\n </header>\n <div className=\"power-ai-context\">\n {context.clusterId ? \"Cluster conversation\" : \"General conversation\"} · {context.screen}\n {attachedResource && !(finding?.clusterId === context.clusterId && finding?.resource) && (\n <div className=\"power-ai-attached-resource\" aria-label=\"Attached resource\">\n <span>\n {attachedResource.kind}/{attachedResource.name}\n {attachedResource.namespace ? ` · ${attachedResource.namespace}` : \"\"}\n </span>\n <NativeTooltip title=\"Remove resource from attached context\">\n <button\n type=\"button\"\n className=\"power-ai-remove-context\"\n aria-label=\"Remove attached resource\"\n onClick={removeResource}\n >\n <AiIcon material=\"close\" size={14} />\n </button>\n </NativeTooltip>\n </div>\n )}\n <br />\n Only screen and resource metadata are attached automatically.\n </div>\n <div\n className=\"power-ai-messages\"\n onScroll={(event) => {\n const element = event.currentTarget;\n following.current = element.scrollHeight - element.scrollTop - element.clientHeight < 48;\n }}\n aria-live=\"polite\"\n ref={messagesElement}\n >\n {messages.length === 0 && (\n <div className=\"power-ai-starters\">\n <p style={{ marginBottom: 12 }}>Ask about this screen or your cluster:</p>\n <AiStarterPrompts\n disabled={busy}\n onSelect={(prompt) => {\n void send(prompt);\n }}\n />\n </div>\n )}\n {messages.map((message, index) => (\n <div className={`power-ai-message power-ai-message-${message.role}`} key={index}>\n <strong>\n {message.role === \"user\" ? (\n <NativeTooltip title=\"You\">\n <span>\n <AiIcon material=\"person_outline\" size={16} />\n </span>\n </NativeTooltip>\n ) : (\n <AiProviderIcon provider={message.provider === \"claude\" ? \"claude\" : \"codex\"} />\n )}\n {message.role === \"user\" ? \"You\" : message.provider === \"claude\" ? \"Claude\" : \"Codex\"}\n {message.role === \"assistant\" && <AiCopyAnswer text={message.text} />}\n </strong>\n <AiMessageContent text={message.text} />\n {message.role === \"assistant\" && context.clusterId && (\n <AiResourceReferences\n clusterId={context.clusterId}\n references={message.references}\n text={message.text}\n onOpened={() => setOpen(false)}\n />\n )}\n </div>\n ))}\n {readActivity.length > 0 && (\n <div\n className=\"power-ai-read-activity\"\n style={{ fontSize: 11, color: \"var(--textColorSecondary)\", margin: \"8px 16px\" }}\n >\n {readActivity.map((read, index) => (\n <NativeTooltip\n key={index}\n title={`${read.method} · ${read.status === \"reading\" ? \"reading\" : read.status === \"ok\" ? \"read\" : \"unavailable\"}`}\n >\n <span data-method={read.method} data-status={read.status} style={{ marginRight: 10 }}>\n <AiIcon\n material={\n read.status === \"reading\"\n ? \"sync\"\n : read.status === \"ok\"\n ? \"check_circle_outline\"\n : \"info_outline\"\n }\n size={13}\n />{\" \"}\n {read.method} ·{\" \"}\n {read.status === \"reading\" ? \"reading\" : read.status === \"ok\" ? \"read\" : \"unavailable\"}\n </span>\n </NativeTooltip>\n ))}\n </div>\n )}\n {busy && (\n <p className=\"power-ai-thinking\" role=\"status\">\n {stopped.includes(key) ? \"Stopping response\" : \"Thinking\"}\n <span className=\"power-ai-dots\" aria-hidden=\"true\">\n <span>.</span>\n <span>.</span>\n <span>.</span>\n </span>\n </p>\n )}\n {!busy && stopped.includes(key) && (\n <p className=\"power-ai-cancellation\" role=\"status\">\n Response stopped{\" \"}\n <NativeTooltip title=\"Dismiss\">\n <button\n type=\"button\"\n aria-label=\"Dismiss cancellation\"\n className=\"power-ai-dismiss\"\n onClick={() => setStopped((keys) => keys.filter((entry) => entry !== key))}\n >\n <AiIcon material=\"close\" size={14} />\n </button>\n </NativeTooltip>\n </p>\n )}\n {error && <p role=\"alert\">{error}</p>}\n </div>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n void send();\n }}\n >\n {suggestions.length > 0 && (\n <div\n className=\"power-ai-autocomplete\"\n role=\"listbox\"\n id=\"power-ai-commands\"\n aria-label=\"Prompt shortcuts\"\n >\n {suggestions.map((shortcut, index) => (\n <NativeTooltip key={shortcut.id} title={`Insert /${shortcut.command}: ${shortcut.label}`}>\n <button\n type=\"button\"\n role=\"option\"\n id={`power-ai-command-${index}`}\n aria-selected={index === suggestionIndex % suggestions.length}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => selectSuggestion(index)}\n >\n <span>/{shortcut.command}</span>\n <span>{shortcut.label}</span>\n </button>\n </NativeTooltip>\n ))}\n </div>\n )}\n <AiContextPreview\n finding={finding?.clusterId === context.clusterId ? finding : undefined}\n onRemoveFinding={() => setFinding(undefined)}\n context={previewContext}\n />\n <AiTerminalContext\n clusterId={context.clusterId}\n attachment={terminalAttachment}\n onChange={setTerminalAttachment}\n disabled={busy}\n />\n <textarea\n ref={composer}\n aria-controls={suggestions.length ? \"power-ai-commands\" : undefined}\n aria-expanded={suggestions.length > 0}\n aria-activedescendant={\n suggestions.length ? `power-ai-command-${suggestionIndex % suggestions.length}` : undefined\n }\n autoFocus\n aria-label=\"Message\"\n placeholder=\"Ask about this cluster…\"\n onKeyDown={(event) => {\n if (event.nativeEvent.isComposing || event.keyCode === 229) return;\n if (suggestions.length && !event.shiftKey) {\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n setSuggestionIndex(\n (index) =>\n (index + (event.key === \"ArrowDown\" ? 1 : suggestions.length - 1)) % suggestions.length,\n );\n return;\n }\n if (event.key === \"Enter\" || event.key === \"Tab\") {\n event.preventDefault();\n selectSuggestion(suggestionIndex % suggestions.length);\n return;\n }\n }\n if (\n event.key === \"Enter\" &&\n !event.shiftKey &&\n !event.nativeEvent.isComposing &&\n event.keyCode !== 229\n ) {\n event.preventDefault();\n if (!busy) void send();\n }\n }}\n value={draft}\n onChange={(event) => {\n setDraft(event.target.value);\n setSuggestionIndex(0);\n setDismissedDraft(undefined);\n }}\n disabled={busy}\n />\n <div className=\"power-ai-composer-footer\">\n <span>Enter to send · Shift+Enter for newline</span>\n {busy ? (\n <button\n type=\"button\"\n aria-label=\"Stop response\"\n disabled={stopped.includes(key)}\n onClick={stopResponse}\n >\n <AiIcon material=\"stop\" size={16} /> Stop\n </button>\n ) : (\n <button type=\"submit\" disabled={!draft.trim()} aria-label=\"Send\">\n <AiIcon material=\"send\" size={16} />\n </button>\n )}\n </div>\n </form>\n </aside>\n )}\n </>\n );\n});\n\nexport function startAiChat(isClusterDocument: () => boolean = isAiClusterDocument): () => void {\n const container = document.createElement(\"div\");\n container.dataset.freelensPowerAi = \"\";\n document.body.append(container);\n let mounted = false;\n let overviewActions: HTMLDivElement | undefined;\n let overviewIcon: HTMLSpanElement | undefined;\n let overviewLabel: HTMLSpanElement | undefined;\n let overviewResize: ResizeObserver | undefined;\n const updateOverviewLabel = () => {\n const overview = overviewActions?.nextElementSibling;\n const compact = Boolean(overview?.querySelector(\"[data-freelens-power-monitoring]\") && overview.clientWidth > 960);\n const label = compact ? \"Ask AI\" : \"Ask about cluster\";\n if (overviewLabel && overviewLabel.textContent !== label) overviewLabel.textContent = label;\n overviewActions?.querySelector(\"button\")?.setAttribute(\"aria-label\", compact ? \"Ask AI about cluster\" : label);\n };\n const removeOverview = () => {\n overviewResize?.disconnect();\n overviewResize = undefined;\n if (overviewIcon) ReactDOM.unmountComponentAtNode(overviewIcon);\n overviewIcon = undefined;\n overviewLabel = undefined;\n overviewActions?.remove();\n overviewActions = undefined;\n };\n const preferences = AiPreferencesStore.getInstanceOrCreate<AiPreferencesStore>();\n const reconcile = () => {\n const overview =\n preferences.enabled &&\n isClusterDocument() &&\n Renderer.Catalog.activeCluster.get() &&\n document.querySelector('[data-testid=\"cluster-overview-page\"]');\n if (!overview) {\n removeOverview();\n return;\n }\n if (overviewActions?.isConnected && overviewActions.nextElementSibling === overview) {\n updateOverviewLabel();\n return;\n }\n removeOverview();\n overviewActions = document.createElement(\"div\");\n overviewActions.className = \"power-ai-overview-actions\";\n const overviewButton = document.createElement(\"button\");\n overviewButton.type = \"button\";\n overviewButton.setAttribute(\"aria-label\", \"Ask about cluster\");\n overviewButton.id = \"power-ai-overview-button\";\n overviewIcon = document.createElement(\"span\");\n overviewIcon.setAttribute(\"aria-hidden\", \"true\");\n overviewLabel = document.createElement(\"span\");\n overviewButton.append(overviewIcon, overviewLabel);\n overviewButton.onclick = () => window.dispatchEvent(new Event(\"power-ai-open\"));\n overviewActions.append(overviewButton);\n overview.before(overviewActions);\n updateOverviewLabel();\n if (typeof ResizeObserver !== \"undefined\") {\n overviewResize = new ResizeObserver(updateOverviewLabel);\n overviewResize.observe(overview);\n }\n ReactDOM.render(\n <>\n <AiIcon material=\"auto_awesome\" size={16} />\n <Renderer.Component.Tooltip targetId=\"power-ai-overview-button\">\n Open the AI assistant to ask about this cluster\n </Renderer.Component.Tooltip>\n </>,\n overviewIcon,\n );\n };\n const observer = new MutationObserver(reconcile);\n const stop = autorun(() => {\n if (preferences.enabled && !mounted) {\n observer.observe(document.body, { childList: true, subtree: true });\n mounted = true;\n ReactDOM.render(<AiChat isClusterDocument={isClusterDocument} />, container);\n } else if (!preferences.enabled && mounted) {\n observer.disconnect();\n ReactDOM.unmountComponentAtNode(container);\n mounted = false;\n }\n reconcile();\n });\n return () => {\n stop();\n observer.disconnect();\n removeOverview();\n ReactDOM.unmountComponentAtNode(container);\n container.remove();\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
const require__global_external_mobx = require("./_virtual/_global-external_mobx.js");
|
|
2
2
|
const require_appearance_preferences_store = require("./src/common/store/appearance-preferences-store.js");
|
|
3
3
|
//#region src/renderer/appearance.ts
|
|
4
|
+
function accentForeground(color) {
|
|
5
|
+
const channels = [
|
|
6
|
+
1,
|
|
7
|
+
3,
|
|
8
|
+
5
|
|
9
|
+
].map((offset) => {
|
|
10
|
+
const channel = Number.parseInt(color.slice(offset, offset + 2), 16) / 255;
|
|
11
|
+
return channel <= .04045 ? channel / 12.92 : ((channel + .055) / 1.055) ** 2.4;
|
|
12
|
+
});
|
|
13
|
+
const luminance = channels[0] * .2126 + channels[1] * .7152 + channels[2] * .0722;
|
|
14
|
+
return (luminance + .05) / .05 >= 1.05 / (luminance + .05) ? "#000000" : "#ffffff";
|
|
15
|
+
}
|
|
4
16
|
function startAppearanceOverride() {
|
|
5
17
|
const preferences = require_appearance_preferences_store.AppearancePreferencesStore.getInstanceOrCreate();
|
|
6
18
|
const style = document.createElement("style");
|
|
@@ -15,17 +27,22 @@ function startAppearanceOverride() {
|
|
|
15
27
|
return;
|
|
16
28
|
}
|
|
17
29
|
style.textContent = `${color === "default" ? "" : `
|
|
18
|
-
:root { --primary: ${color} !important; --buttonPrimaryBackground: ${color} !important; --menuSelectedOptionBgc: ${color} !important; --select-option-focused-bgc: color-mix(in srgb, ${color} 24%, var(--contentColor)) !important; --icon-focus-color: ${color} !important; }
|
|
30
|
+
:root { --freelens-power-accent-foreground: ${accentForeground(color)}; --select-option-focused-color: var(--textColorAccent) !important; --primary: ${color} !important; --buttonPrimaryBackground: ${color} !important; --menuSelectedOptionBgc: ${color} !important; --select-option-focused-bgc: color-mix(in srgb, ${color} 24%, var(--contentColor)) !important; --icon-focus-color: ${color} !important; }
|
|
19
31
|
:root .Checkbox, :root .Drawer .drawer-title, :root .DrawerParamToggler .param-link, :root .Drawer .ResizingAnchor { --blue: var(--primary); }
|
|
20
32
|
:root [role="treeitem"][class*="catalog-tree-module__selected--"] { --blue: var(--primary); }
|
|
21
33
|
:root [class*="main-layout-module__sidebar--"] > .ResizingAnchor { --blue: var(--primary); }
|
|
22
34
|
:root .MenuItem:is(.create-terminal-tab, .create-resource-tab) { --bgc-active: var(--primary); }
|
|
23
35
|
:root .Select:not(.Select--is-disabled) .Select__control--is-focused:not(.Select__control--is-disabled) { border-color: ${color} !important; box-shadow: 0 0 0 1px ${color} !important; }
|
|
24
|
-
:root .Select__option--is-selected { background: var(--primary) !important; color: var(--
|
|
36
|
+
:root .Select__option--is-selected { background: var(--primary) !important; color: var(--freelens-power-accent-foreground) !important; }
|
|
37
|
+
:root .Select__option--is-focused:not(.Select__option--is-selected) { color: var(--textColorAccent) !important; }
|
|
38
|
+
:root .Button.primary:not(.plain):not(.outlined):not(.light) { color: var(--freelens-power-accent-foreground); }
|
|
39
|
+
:root [data-testid="cluster-sidebar"] { --sidebarActiveColor: var(--freelens-power-accent-foreground); --sidebarSubmenuActiveColor: var(--primary); }
|
|
25
40
|
:root .NamespaceSelectMenu .Select__option { margin-block: 2px; }
|
|
26
41
|
:root .NamespaceSelectMenu .Select__option--is-selected { background: color-mix(in srgb, var(--primary) 10%, var(--contentColor)) !important; color: var(--textColorAccent) !important; }
|
|
27
42
|
:root .NamespaceSelectMenu .Select__option--is-selected.Select__option--is-focused { background: color-mix(in srgb, var(--primary) 24%, var(--contentColor)) !important; }
|
|
28
43
|
:root .NamespaceSelectMenu .Select__option--is-selected .Icon { color: var(--primary); }
|
|
44
|
+
:root .Select__option:not(.Select__option--is-disabled):active { background: var(--primary) !important; color: var(--freelens-power-accent-foreground) !important; }
|
|
45
|
+
:root .NamespaceSelectMenu .Select__option--is-selected:active .Icon { color: inherit; }
|
|
29
46
|
:root a.link { color: var(--primary); }
|
|
30
47
|
:root [data-testid="download-logs-dropdown"] { --accent-color: var(--primary); }
|
|
31
48
|
${recolorAppIcon ? ".Welcome [data-testid=\"no-welcome-banners-icon\"] svg path[fill=\"#23a49c\"] { fill: var(--primary); }" : ""}
|
|
@@ -38,6 +55,7 @@ function startAppearanceOverride() {
|
|
|
38
55
|
};
|
|
39
56
|
}
|
|
40
57
|
//#endregion
|
|
58
|
+
exports.accentForeground = accentForeground;
|
|
41
59
|
exports.startAppearanceOverride = startAppearanceOverride;
|
|
42
60
|
|
|
43
61
|
//# sourceMappingURL=appearance.js.map
|