@64mb/freelens-power 1.2.2 → 1.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 +3 -1
- package/out/main/common/store/monitoring-preferences-store.js +5 -0
- package/out/main/common/store/monitoring-preferences-store.js.map +1 -1
- package/out/renderer/ai-diagnostic-handoff.js +52 -0
- package/out/renderer/ai-diagnostic-handoff.js.map +1 -0
- package/out/renderer/ai-extras.js +40 -4
- package/out/renderer/ai-extras.js.map +1 -1
- package/out/renderer/ai.js +48 -56
- package/out/renderer/ai.js.map +1 -1
- package/out/renderer/details/hpa-diagnostics-details.js +46 -0
- package/out/renderer/details/hpa-diagnostics-details.js.map +1 -0
- package/out/renderer/details/namespace-health-details.js +91 -0
- package/out/renderer/details/namespace-health-details.js.map +1 -0
- package/out/renderer/details/resource-health-details.js +131 -0
- package/out/renderer/details/resource-health-details.js.map +1 -0
- package/out/renderer/details/service-diagnostics-details.js +163 -0
- package/out/renderer/details/service-diagnostics-details.js.map +1 -0
- package/out/renderer/diagnostic-explain-button.js +16 -0
- package/out/renderer/diagnostic-explain-button.js.map +1 -0
- package/out/renderer/diagnostics-state.js +51 -0
- package/out/renderer/diagnostics-state.js.map +1 -0
- package/out/renderer/diagnostics.css.js +9 -0
- package/out/renderer/diagnostics.css.js.map +1 -1
- package/out/renderer/diagnostics.js +369 -73
- package/out/renderer/diagnostics.js.map +1 -1
- package/out/renderer/incident-copy-button.js +50 -0
- package/out/renderer/incident-copy-button.js.map +1 -0
- package/out/renderer/index.js +91 -19
- package/out/renderer/index.js.map +1 -1
- package/out/renderer/monitoring-history-collection.js +1 -1
- package/out/renderer/preferences/monitoring-preferences.js +10 -0
- package/out/renderer/preferences/monitoring-preferences.js.map +1 -1
- package/out/renderer/preferences/preferences.js +88 -0
- package/out/renderer/preferences/preferences.js.map +1 -1
- package/out/renderer/resource-relationships.css.js +7 -0
- package/out/renderer/resource-relationships.css.js.map +1 -0
- package/out/renderer/resource-relationships.js +556 -0
- package/out/renderer/resource-relationships.js.map +1 -0
- package/out/renderer/resource-search-distance.js +24 -0
- package/out/renderer/resource-search-distance.js.map +1 -0
- package/out/renderer/resource-search-fields.js +55 -0
- package/out/renderer/resource-search-fields.js.map +1 -0
- package/out/renderer/resource-search-model.js +193 -0
- package/out/renderer/resource-search-model.js.map +1 -0
- package/out/renderer/resource-search.js +365 -0
- package/out/renderer/resource-search.js.map +1 -0
- package/out/renderer/src/common/hpa-diagnostics.js +24 -0
- package/out/renderer/src/common/hpa-diagnostics.js.map +1 -0
- package/out/renderer/src/common/incident-summary.js +73 -0
- package/out/renderer/src/common/incident-summary.js.map +1 -0
- package/out/renderer/src/common/resource-health.js +92 -0
- package/out/renderer/src/common/resource-health.js.map +1 -0
- package/out/renderer/src/common/resource-relationships.js +155 -0
- package/out/renderer/src/common/resource-relationships.js.map +1 -0
- package/out/renderer/src/common/service-diagnostics.js +50 -0
- package/out/renderer/src/common/service-diagnostics.js.map +1 -0
- package/out/renderer/src/common/store/monitoring-preferences-store.js +5 -0
- package/out/renderer/src/common/store/monitoring-preferences-store.js.map +1 -1
- package/out/renderer/src/common/timeline-groups.js +36 -0
- package/out/renderer/src/common/timeline-groups.js.map +1 -0
- package/package.json +1 -1
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 { AiCopyAnswer } from \"./ai-copy-answer\";\nimport { AiContextPreview, AiResourceReferences } from \"./ai-extras\";\nimport { AiIcon } from \"./ai-icon\";\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\";\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-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 [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 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 setContext(readAiContext());\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(update);\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"class\", \"style\", \"hidden\", \"open\"],\n });\n window.addEventListener(\"power-ai-open\", updateAndOpen);\n function updateAndOpen() {\n update();\n setOpen(true);\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 };\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 useEffect(() => {\n const heldKeys = new Set<string>();\n let shiftDownAt: number | undefined;\n let lastTapAt: number | undefined;\n const reset = () => {\n shiftDownAt = undefined;\n lastTapAt = undefined;\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== \"Shift\") heldKeys.add(event.code || event.key);\n if (\n event.key !== \"Shift\" ||\n event.repeat ||\n event.isComposing ||\n event.keyCode === 229 ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey ||\n heldKeys.size > 0 ||\n shiftDownAt !== undefined\n ) {\n reset();\n return;\n }\n shiftDownAt = performance.now();\n };\n const onKeyUp = (event: KeyboardEvent) => {\n if (event.key === \"Meta\") {\n // macOS can omit keyup events for keys released while [Meta] is held\n heldKeys.clear();\n reset();\n return;\n }\n heldKeys.delete(event.code || event.key);\n const now = performance.now();\n if (\n event.key !== \"Shift\" ||\n shiftDownAt === undefined ||\n now - shiftDownAt > 400 ||\n event.isComposing ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey ||\n !preferences.enabled ||\n !isClusterDocument() ||\n hasAiOverlay()\n ) {\n reset();\n return;\n }\n shiftDownAt = undefined;\n if (lastTapAt === undefined || now - lastTapAt > 400) {\n lastTapAt = now;\n return;\n }\n reset();\n setContext(readAiContext());\n setOpen((value) => !value);\n };\n window.addEventListener(\"keydown\", onKeyDown, true);\n window.addEventListener(\"keyup\", onKeyUp, true);\n const onBlur = () => {\n heldKeys.clear();\n reset();\n };\n window.addEventListener(\"blur\", onBlur);\n return () => {\n window.removeEventListener(\"keydown\", onKeyDown, true);\n window.removeEventListener(\"keyup\", onKeyUp, true);\n window.removeEventListener(\"blur\", onBlur);\n };\n }, [preferences, isClusterDocument]);\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 shortcutLabel = \"Shift, Shift\";\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 requestContext = attachedAiContext(readAiContext());\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 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(-80).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: [preferences.systemPrompt, requestContext.clusterId ? preferences.clusterPrompt : \"\"]\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 <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 title={`Open AI assistant (${shortcutLabel})`}\n >\n <span aria-hidden=\"true\">\n <AiIcon material=\"chat_bubble_outline\" size={16} />\n </span>{\" \"}\n AI\n </button>\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 <span className=\"power-ai-brand\" title=\"AI assistant\">\n <AiIcon material=\"auto_awesome\" size={18} /> AI\n </span>{\" \"}\n Assistant\n </strong>\n <button\n type=\"button\"\n disabled={busy}\n aria-label=\"New chat\"\n title=\"Clear this conversation and start a new chat\"\n onClick={() => {\n setTerminalAttachment(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 <button\n type=\"button\"\n className=\"power-ai-pin\"\n aria-label=\"Pin AI assistant\"\n aria-pressed={pinned}\n title={pinned ? \"Unpin to close when clicking outside\" : \"Pin to keep the assistant open\"}\n onClick={() => setPinned((value) => !value)}\n >\n <AiIcon material=\"push_pin\" size={18} />\n </button>\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 title=\"Close AI assistant\"\n >\n <span aria-hidden=\"true\">\n <AiIcon material=\"close\" size={18} />\n </span>\n </button>\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 <span title=\"You\">\n <AiIcon material=\"person_outline\" size={16} />\n </span>\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 <span\n key={index}\n title={`${read.method} · ${read.status === \"reading\" ? \"reading\" : read.status === \"ok\" ? \"read\" : \"unavailable\"}`}\n data-method={read.method}\n data-status={read.status}\n style={{ marginRight: 10 }}\n >\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 ))}\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 <button\n type=\"button\"\n aria-label=\"Dismiss cancellation\"\n className=\"power-ai-dismiss\"\n title=\"Dismiss\"\n onClick={() => setStopped((keys) => keys.filter((entry) => entry !== key))}\n >\n <AiIcon material=\"close\" size={14} />\n </button>\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 <button\n type=\"button\"\n role=\"option\"\n id={`power-ai-command-${index}`}\n aria-selected={index === suggestionIndex % suggestions.length}\n key={shortcut.id}\n title={`Insert /${shortcut.command}: ${shortcut.label}`}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => selectSuggestion(index)}\n >\n <span>/{shortcut.command}</span>\n <span>{shortcut.label}</span>\n </button>\n ))}\n </div>\n )}\n <AiContextPreview context={attachedAiContext(context)} />\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.title = \"Open the AI assistant to ask about this cluster\";\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(<AiIcon material=\"auto_awesome\" size={16} />, overviewIcon);\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 { 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 { 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\";\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 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(update);\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((previous) =>\n previous.trim() ? previous : \"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 function updateAndOpen() {\n update();\n setOpen(true);\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(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: [preferences.systemPrompt, requestContext.clusterId ? preferences.clusterPrompt : \"\"]\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 <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 title=\"Open AI assistant\"\n >\n <span aria-hidden=\"true\">\n <AiIcon material=\"chat_bubble_outline\" size={16} />\n </span>{\" \"}\n AI\n </button>\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 <span className=\"power-ai-brand\" title=\"AI assistant\">\n <AiIcon material=\"auto_awesome\" size={18} /> AI\n </span>{\" \"}\n Assistant\n </strong>\n <button\n type=\"button\"\n disabled={busy}\n aria-label=\"New chat\"\n title=\"Clear this conversation and start a 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 <button\n type=\"button\"\n className=\"power-ai-pin\"\n aria-label=\"Pin AI assistant\"\n aria-pressed={pinned}\n title={pinned ? \"Unpin to close when clicking outside\" : \"Pin to keep the assistant open\"}\n onClick={() => setPinned((value) => !value)}\n >\n <AiIcon material=\"push_pin\" size={18} />\n </button>\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 title=\"Close AI assistant\"\n >\n <span aria-hidden=\"true\">\n <AiIcon material=\"close\" size={18} />\n </span>\n </button>\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 <span title=\"You\">\n <AiIcon material=\"person_outline\" size={16} />\n </span>\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 <span\n key={index}\n title={`${read.method} · ${read.status === \"reading\" ? \"reading\" : read.status === \"ok\" ? \"read\" : \"unavailable\"}`}\n data-method={read.method}\n data-status={read.status}\n style={{ marginRight: 10 }}\n >\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 ))}\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 <button\n type=\"button\"\n aria-label=\"Dismiss cancellation\"\n className=\"power-ai-dismiss\"\n title=\"Dismiss\"\n onClick={() => setStopped((keys) => keys.filter((entry) => entry !== key))}\n >\n <AiIcon material=\"close\" size={14} />\n </button>\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 <button\n type=\"button\"\n role=\"option\"\n id={`power-ai-command-${index}`}\n aria-selected={index === suggestionIndex % suggestions.length}\n key={shortcut.id}\n title={`Insert /${shortcut.command}: ${shortcut.label}`}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => selectSuggestion(index)}\n >\n <span>/{shortcut.command}</span>\n <span>{shortcut.label}</span>\n </button>\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.title = \"Open the AI assistant to ask about this cluster\";\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(<AiIcon material=\"auto_awesome\" size={16} />, overviewIcon);\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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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const require_extensions = require("../_virtual/_global-external_@freelensapp/extensions.js");
|
|
2
|
+
const require__global_external_mobx_react = require("../_virtual/_global-external_mobx-react.js");
|
|
3
|
+
const require_jsx_runtime = require("../_virtual/_global-external_react/jsx-runtime.js");
|
|
4
|
+
const require_hpa_diagnostics = require("../src/common/hpa-diagnostics.js");
|
|
5
|
+
//#region src/renderer/details/hpa-diagnostics-details.tsx
|
|
6
|
+
var { DrawerTitle, DrawerItem, Icon } = require_extensions.Renderer.Component;
|
|
7
|
+
var HpaDiagnosticsDetails = require__global_external_mobx_react.observer(({ object }) => {
|
|
8
|
+
const result = require_hpa_diagnostics.diagnoseHpa(object);
|
|
9
|
+
const healthy = result.state !== "warning" && result.min !== result.max && object.status?.conditions?.some((condition) => condition.type === "ScalingActive" && condition.status === "True") && object.status?.conditions?.some((condition) => condition.type === "AbleToScale" && condition.status === "True") && !object.status?.conditions?.some((condition) => condition.type === "ScalingLimited" && condition.status === "True");
|
|
10
|
+
return /* @__PURE__ */ require_jsx_runtime.jsxs(require_jsx_runtime.Fragment, { children: [
|
|
11
|
+
/* @__PURE__ */ require_jsx_runtime.jsx(DrawerTitle, { children: "Autoscaling diagnostics" }),
|
|
12
|
+
/* @__PURE__ */ require_jsx_runtime.jsx(DrawerItem, {
|
|
13
|
+
name: "Summary",
|
|
14
|
+
children: /* @__PURE__ */ require_jsx_runtime.jsxs("span", {
|
|
15
|
+
style: { color: result.state === "warning" ? "var(--colorWarning)" : healthy ? "var(--colorOk)" : "var(--textColorSecondary)" },
|
|
16
|
+
children: [
|
|
17
|
+
/* @__PURE__ */ require_jsx_runtime.jsx(Icon, { material: result.state === "warning" ? "warning" : healthy ? "check_circle" : "info" }),
|
|
18
|
+
" ",
|
|
19
|
+
result.summary
|
|
20
|
+
]
|
|
21
|
+
})
|
|
22
|
+
}),
|
|
23
|
+
/* @__PURE__ */ require_jsx_runtime.jsxs(DrawerItem, {
|
|
24
|
+
name: "Replicas",
|
|
25
|
+
children: [
|
|
26
|
+
"Current ",
|
|
27
|
+
result.current ?? "unknown",
|
|
28
|
+
" · desired ",
|
|
29
|
+
result.desired ?? "unknown",
|
|
30
|
+
" · min ",
|
|
31
|
+
result.min,
|
|
32
|
+
" · max",
|
|
33
|
+
" ",
|
|
34
|
+
result.max ?? "unknown"
|
|
35
|
+
]
|
|
36
|
+
}),
|
|
37
|
+
result.evidence.map((item) => /* @__PURE__ */ require_jsx_runtime.jsx(DrawerItem, {
|
|
38
|
+
name: "Evidence",
|
|
39
|
+
children: item
|
|
40
|
+
}, item))
|
|
41
|
+
] });
|
|
42
|
+
});
|
|
43
|
+
//#endregion
|
|
44
|
+
exports.HpaDiagnosticsDetails = HpaDiagnosticsDetails;
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=hpa-diagnostics-details.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hpa-diagnostics-details.js","names":[],"sources":["../../../src/renderer/details/hpa-diagnostics-details.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { observer } from \"mobx-react\";\nimport { diagnoseHpa } from \"../../common/hpa-diagnostics\";\n\nconst { DrawerTitle, DrawerItem, Icon } = Renderer.Component;\nexport const HpaDiagnosticsDetails = observer(\n ({ object }: Renderer.Component.KubeObjectDetailsProps<Renderer.K8sApi.HorizontalPodAutoscaler>) => {\n const result = diagnoseHpa(object);\n const healthy =\n result.state !== \"warning\" &&\n result.min !== result.max &&\n object.status?.conditions?.some(\n (condition) => condition.type === \"ScalingActive\" && condition.status === \"True\",\n ) &&\n object.status?.conditions?.some((condition) => condition.type === \"AbleToScale\" && condition.status === \"True\") &&\n !object.status?.conditions?.some(\n (condition) => condition.type === \"ScalingLimited\" && condition.status === \"True\",\n );\n return (\n <>\n <DrawerTitle>Autoscaling diagnostics</DrawerTitle>\n <DrawerItem name=\"Summary\">\n <span\n style={{\n color:\n result.state === \"warning\"\n ? \"var(--colorWarning)\"\n : healthy\n ? \"var(--colorOk)\"\n : \"var(--textColorSecondary)\",\n }}\n >\n <Icon material={result.state === \"warning\" ? \"warning\" : healthy ? \"check_circle\" : \"info\"} />{\" \"}\n {result.summary}\n </span>\n </DrawerItem>\n <DrawerItem name=\"Replicas\">\n Current {result.current ?? \"unknown\"} · desired {result.desired ?? \"unknown\"} · min {result.min} · max{\" \"}\n {result.max ?? \"unknown\"}\n </DrawerItem>\n {result.evidence.map((item) => (\n <DrawerItem key={item} name=\"Evidence\">\n {item}\n </DrawerItem>\n ))}\n </>\n );\n },\n);\n"],"mappings":";;;;;AAIA,IAAM,EAAE,aAAa,YAAY,SAAS,mBAAA,SAAS;AACnD,IAAa,wBAAwB,oCAAA,UAClC,EAAE,aAAiG;CAClG,MAAM,SAAS,wBAAA,YAAY,MAAM;CACjC,MAAM,UACJ,OAAO,UAAU,aACjB,OAAO,QAAQ,OAAO,OACtB,OAAO,QAAQ,YAAY,MACxB,cAAc,UAAU,SAAS,mBAAmB,UAAU,WAAW,MAC5E,KACA,OAAO,QAAQ,YAAY,MAAM,cAAc,UAAU,SAAS,iBAAiB,UAAU,WAAW,MAAM,KAC9G,CAAC,OAAO,QAAQ,YAAY,MACzB,cAAc,UAAU,SAAS,oBAAoB,UAAU,WAAW,MAC7E;CACF,OACE,oCAAA,KAAA,oBAAA,UAAA,EAAA,UAAA;EACE,oCAAA,IAAC,aAAD,EAAA,UAAa,0BAAoC,CAAA;EACjD,oCAAA,IAAC,YAAD;GAAY,MAAK;aACf,oCAAA,KAAC,QAAD;IACE,OAAO,EACL,OACE,OAAO,UAAU,YACb,wBACA,UACE,mBACA,4BACV;cARF;KAUE,oCAAA,IAAC,MAAD,EAAM,UAAU,OAAO,UAAU,YAAY,YAAY,UAAU,iBAAiB,OAAS,CAAA;KAAE;KAC9F,OAAO;IACJ;;EACI,CAAA;EACZ,oCAAA,KAAC,YAAD;GAAY,MAAK;aAAjB;IAA4B;IACjB,OAAO,WAAW;IAAU;IAAY,OAAO,WAAW;IAAU;IAAQ,OAAO;IAAI;IAAO;IACtG,OAAO,OAAO;GACL;;EACX,OAAO,SAAS,KAAK,SACpB,oCAAA,IAAC,YAAD;GAAuB,MAAK;aACzB;EACS,GAFK,IAEL,CACb;CACD,EAAA,CAAA;AAEN,CACF"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
const require_extensions = require("../_virtual/_global-external_@freelensapp/extensions.js");
|
|
2
|
+
const require__global_external_react = require("../_virtual/_global-external_react.js");
|
|
3
|
+
const require_jsx_runtime = require("../_virtual/_global-external_react/jsx-runtime.js");
|
|
4
|
+
const require_date_time = require("../src/common/date-time.js");
|
|
5
|
+
const require_monitoring_math = require("../src/common/monitoring-math.js");
|
|
6
|
+
const require_monitoring_collector = require("../monitoring-collector.js");
|
|
7
|
+
const require_resource_health_details = require("./resource-health-details.js");
|
|
8
|
+
//#region src/renderer/details/namespace-health-details.tsx
|
|
9
|
+
var { DrawerItem } = require_extensions.Renderer.Component;
|
|
10
|
+
function NamespaceHealthDetails(props) {
|
|
11
|
+
const namespace = props.object.getName();
|
|
12
|
+
const clusterId = require_extensions.Renderer.Catalog.activeCluster.get()?.metadata.uid;
|
|
13
|
+
const [result, setResult] = require__global_external_react.useState();
|
|
14
|
+
require__global_external_react.useEffect(() => {
|
|
15
|
+
let active = true;
|
|
16
|
+
const release = require_monitoring_collector.retainMonitoringCollector();
|
|
17
|
+
const refresh = () => {
|
|
18
|
+
require_monitoring_collector.getMonitoringSnapshot().then((snapshot) => {
|
|
19
|
+
if (active) setResult({
|
|
20
|
+
namespace,
|
|
21
|
+
clusterId: snapshot.clusterId,
|
|
22
|
+
snapshot
|
|
23
|
+
});
|
|
24
|
+
}, () => {
|
|
25
|
+
if (active && clusterId) setResult({
|
|
26
|
+
namespace,
|
|
27
|
+
clusterId,
|
|
28
|
+
failed: true
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
refresh();
|
|
33
|
+
const timer = setInterval(refresh, 3e4);
|
|
34
|
+
return () => {
|
|
35
|
+
active = false;
|
|
36
|
+
clearInterval(timer);
|
|
37
|
+
release();
|
|
38
|
+
};
|
|
39
|
+
}, [namespace, clusterId]);
|
|
40
|
+
const snapshot = result?.namespace === namespace && result?.clusterId === clusterId ? result.snapshot : void 0;
|
|
41
|
+
const pods = snapshot?.pods?.filter((pod) => pod.getNs() === namespace);
|
|
42
|
+
const activePods = pods?.filter((pod) => pod.status?.phase !== "Succeeded" && pod.status?.phase !== "Failed");
|
|
43
|
+
let requests;
|
|
44
|
+
if (activePods) try {
|
|
45
|
+
const cpu = activePods.reduce((sum, pod) => sum + require_monitoring_math.effectivePodResource(pod, "cpu", "requests"), 0);
|
|
46
|
+
const memory = activePods.reduce((sum, pod) => sum + require_monitoring_math.effectivePodResource(pod, "memory", "requests"), 0);
|
|
47
|
+
requests = `${cpu.toFixed(2)} CPU cores · ${(memory / 1024 ** 2).toFixed(0)} MiB memory`;
|
|
48
|
+
} catch {
|
|
49
|
+
requests = "Unavailable: incomplete resource specifications";
|
|
50
|
+
}
|
|
51
|
+
const failed = result?.namespace === namespace && result?.clusterId === clusterId && result.failed;
|
|
52
|
+
return /* @__PURE__ */ require_jsx_runtime.jsxs(require_jsx_runtime.Fragment, { children: [
|
|
53
|
+
/* @__PURE__ */ require_jsx_runtime.jsx(require_resource_health_details.ResourceHealthDetails, {
|
|
54
|
+
...props,
|
|
55
|
+
onOpenDiagnostics: props.onOpenDiagnostics ? () => props.onOpenDiagnostics?.(namespace) : void 0
|
|
56
|
+
}),
|
|
57
|
+
/* @__PURE__ */ require_jsx_runtime.jsxs(DrawerItem, {
|
|
58
|
+
name: "Inventory scope",
|
|
59
|
+
children: [
|
|
60
|
+
"Namespace ",
|
|
61
|
+
namespace,
|
|
62
|
+
", from the API-visible pod inventory"
|
|
63
|
+
]
|
|
64
|
+
}),
|
|
65
|
+
/* @__PURE__ */ require_jsx_runtime.jsx(DrawerItem, {
|
|
66
|
+
name: "Pod coverage",
|
|
67
|
+
children: pods ? `${pods.length} visible pods · ${activePods?.length} non-terminal` : failed || snapshot ? "Unavailable or access denied" : "Loading"
|
|
68
|
+
}),
|
|
69
|
+
activePods && /* @__PURE__ */ require_jsx_runtime.jsxs(DrawerItem, {
|
|
70
|
+
name: "Pod readiness",
|
|
71
|
+
children: [
|
|
72
|
+
activePods.filter((pod) => pod.status?.conditions?.some((condition) => condition.type === "Ready" && condition.status === "True")).length,
|
|
73
|
+
"/",
|
|
74
|
+
activePods.length,
|
|
75
|
+
" non-terminal pods ready"
|
|
76
|
+
]
|
|
77
|
+
}),
|
|
78
|
+
requests && /* @__PURE__ */ require_jsx_runtime.jsx(DrawerItem, {
|
|
79
|
+
name: "Pod requests",
|
|
80
|
+
children: requests
|
|
81
|
+
}),
|
|
82
|
+
/* @__PURE__ */ require_jsx_runtime.jsxs(DrawerItem, {
|
|
83
|
+
name: "Coverage",
|
|
84
|
+
children: ["Filtered to this namespace · visibility may be limited by access permissions", snapshot ? ` · sampled ${require_date_time.formatDateTime(snapshot.time)}` : ""]
|
|
85
|
+
})
|
|
86
|
+
] });
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
exports.NamespaceHealthDetails = NamespaceHealthDetails;
|
|
90
|
+
|
|
91
|
+
//# sourceMappingURL=namespace-health-details.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namespace-health-details.js","names":[],"sources":["../../../src/renderer/details/namespace-health-details.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { useEffect, useState } from \"react\";\nimport { formatDateTime } from \"../../common/date-time\";\nimport { effectivePodResource } from \"../../common/monitoring-math\";\nimport { getMonitoringSnapshot, type MonitoringSnapshot, retainMonitoringCollector } from \"../monitoring-collector\";\nimport { ResourceHealthDetails, type ResourceHealthDetailsProps } from \"./resource-health-details\";\n\nconst { DrawerItem } = Renderer.Component;\n\nexport function NamespaceHealthDetails(props: ResourceHealthDetailsProps) {\n const namespace = props.object.getName();\n const clusterId = Renderer.Catalog.activeCluster.get()?.metadata.uid;\n const [result, setResult] = useState<{\n namespace: string;\n clusterId: string;\n snapshot?: MonitoringSnapshot;\n failed?: boolean;\n }>();\n useEffect(() => {\n let active = true;\n const release = retainMonitoringCollector();\n const refresh = () => {\n void getMonitoringSnapshot().then(\n (snapshot) => {\n if (active) setResult({ namespace, clusterId: snapshot.clusterId, snapshot });\n },\n () => {\n if (active && clusterId) setResult({ namespace, clusterId, failed: true });\n },\n );\n };\n refresh();\n const timer = setInterval(refresh, 30_000);\n return () => {\n active = false;\n clearInterval(timer);\n release();\n };\n }, [namespace, clusterId]);\n const snapshot = result?.namespace === namespace && result?.clusterId === clusterId ? result.snapshot : undefined;\n const pods = snapshot?.pods?.filter((pod) => pod.getNs() === namespace);\n const activePods = pods?.filter((pod) => pod.status?.phase !== \"Succeeded\" && pod.status?.phase !== \"Failed\");\n let requests: string | undefined;\n if (activePods) {\n try {\n const cpu = activePods.reduce((sum, pod) => sum + effectivePodResource(pod, \"cpu\", \"requests\"), 0);\n const memory = activePods.reduce((sum, pod) => sum + effectivePodResource(pod, \"memory\", \"requests\"), 0);\n requests = `${cpu.toFixed(2)} CPU cores · ${(memory / 1024 ** 2).toFixed(0)} MiB memory`;\n } catch {\n requests = \"Unavailable: incomplete resource specifications\";\n }\n }\n const failed = result?.namespace === namespace && result?.clusterId === clusterId && result.failed;\n return (\n <>\n <ResourceHealthDetails\n {...props}\n onOpenDiagnostics={props.onOpenDiagnostics ? () => props.onOpenDiagnostics?.(namespace) : undefined}\n />\n <DrawerItem name=\"Inventory scope\">Namespace {namespace}, from the API-visible pod inventory</DrawerItem>\n <DrawerItem name=\"Pod coverage\">\n {pods\n ? `${pods.length} visible pods · ${activePods?.length} non-terminal`\n : failed || snapshot\n ? \"Unavailable or access denied\"\n : \"Loading\"}\n </DrawerItem>\n {activePods && (\n <DrawerItem name=\"Pod readiness\">\n {\n activePods.filter((pod) =>\n pod.status?.conditions?.some((condition) => condition.type === \"Ready\" && condition.status === \"True\"),\n ).length\n }\n /{activePods.length} non-terminal pods ready\n </DrawerItem>\n )}\n {requests && <DrawerItem name=\"Pod requests\">{requests}</DrawerItem>}\n <DrawerItem name=\"Coverage\">\n Filtered to this namespace · visibility may be limited by access permissions\n {snapshot ? ` · sampled ${formatDateTime(snapshot.time)}` : \"\"}\n </DrawerItem>\n </>\n );\n}\n"],"mappings":";;;;;;;;AAOA,IAAM,EAAE,eAAe,mBAAA,SAAS;AAEhC,SAAgB,uBAAuB,OAAmC;CACxE,MAAM,YAAY,MAAM,OAAO,QAAQ;CACvC,MAAM,YAAY,mBAAA,SAAS,QAAQ,cAAc,IAAI,CAAC,EAAE,SAAS;CACjE,MAAM,CAAC,QAAQ,aAAa,+BAAA,SAKzB;CACH,+BAAA,gBAAgB;EACd,IAAI,SAAS;EACb,MAAM,UAAU,6BAAA,0BAA0B;EAC1C,MAAM,gBAAgB;GACpB,6BAAK,sBAAsB,CAAC,CAAC,MAC1B,aAAa;IACZ,IAAI,QAAQ,UAAU;KAAE;KAAW,WAAW,SAAS;KAAW;IAAS,CAAC;GAC9E,SACM;IACJ,IAAI,UAAU,WAAW,UAAU;KAAE;KAAW;KAAW,QAAQ;IAAK,CAAC;GAC3E,CACF;EACF;EACA,QAAQ;EACR,MAAM,QAAQ,YAAY,SAAS,GAAM;EACzC,aAAa;GACX,SAAS;GACT,cAAc,KAAK;GACnB,QAAQ;EACV;CACF,GAAG,CAAC,WAAW,SAAS,CAAC;CACzB,MAAM,WAAW,QAAQ,cAAc,aAAa,QAAQ,cAAc,YAAY,OAAO,WAAW,KAAA;CACxG,MAAM,OAAO,UAAU,MAAM,QAAQ,QAAQ,IAAI,MAAM,MAAM,SAAS;CACtE,MAAM,aAAa,MAAM,QAAQ,QAAQ,IAAI,QAAQ,UAAU,eAAe,IAAI,QAAQ,UAAU,QAAQ;CAC5G,IAAI;CACJ,IAAI,YACF,IAAI;EACF,MAAM,MAAM,WAAW,QAAQ,KAAK,QAAQ,MAAM,wBAAA,qBAAqB,KAAK,OAAO,UAAU,GAAG,CAAC;EACjG,MAAM,SAAS,WAAW,QAAQ,KAAK,QAAQ,MAAM,wBAAA,qBAAqB,KAAK,UAAU,UAAU,GAAG,CAAC;EACvG,WAAW,GAAG,IAAI,QAAQ,CAAC,EAAE,gBAAgB,SAAS,QAAQ,EAAA,CAAG,QAAQ,CAAC,EAAE;CAC9E,QAAQ;EACN,WAAW;CACb;CAEF,MAAM,SAAS,QAAQ,cAAc,aAAa,QAAQ,cAAc,aAAa,OAAO;CAC5F,OACE,oCAAA,KAAA,oBAAA,UAAA,EAAA,UAAA;EACE,oCAAA,IAAC,gCAAA,uBAAD;GACE,GAAI;GACJ,mBAAmB,MAAM,0BAA0B,MAAM,oBAAoB,SAAS,IAAI,KAAA;EAC3F,CAAA;EACD,oCAAA,KAAC,YAAD;GAAY,MAAK;aAAjB;IAAmC;IAAW;IAAU;GAAgD;;EACxG,oCAAA,IAAC,YAAD;GAAY,MAAK;aACd,OACG,GAAG,KAAK,OAAO,kBAAkB,YAAY,OAAO,iBACpD,UAAU,WACR,iCACA;EACI,CAAA;EACX,cACC,oCAAA,KAAC,YAAD;GAAY,MAAK;aAAjB;IAEI,WAAW,QAAQ,QACjB,IAAI,QAAQ,YAAY,MAAM,cAAc,UAAU,SAAS,WAAW,UAAU,WAAW,MAAM,CACvG,CAAC,CAAC;IACH;IACC,WAAW;IAAO;GACV;;EAEb,YAAY,oCAAA,IAAC,YAAD;GAAY,MAAK;aAAgB;EAAqB,CAAA;EACnE,oCAAA,KAAC,YAAD;GAAY,MAAK;aAAjB,CAA4B,gFAEzB,WAAW,cAAc,kBAAA,eAAe,SAAS,IAAI,MAAM,EAClD;;CACZ,EAAA,CAAA;AAEN"}
|