@64mb/freelens-power 2.3.0 → 2.4.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 CHANGED
@@ -16,9 +16,9 @@ Power tools and personal dashboards for Freelens. Built for Freelens 1.x and tes
16
16
  - **Resource relationships:** a focused Service graph connects Ingress and installed Gateway API routes/listeners to selected Pods, published endpoints, owners and node references, with acceptance and cross-namespace reference evidence, resource links, explicit expansion of all available graph resources and saved upstream visibility
17
17
  - **Fast resource search:** double Shift searches all discoverable resource types, including Secrets, ConfigMaps and custom resources, through a persistent local metadata index with gentle background refresh, type and namespace filters, name-part and typo matching, resource links and explicit AI attachment; search and background indexing can be disabled together in Monitoring settings
18
18
  - **Local metric history:** opt-in SQLite storage, up to seven days within a 100 MiB budget, with aggregated ranges and explicit collection gaps
19
- - **AI assistant:** native Codex or Claude CLI, per-cluster conversations, read-only API discovery and resource summaries, model/effort/speed selection, editable prompts, quick-start commands, Markdown, cancellable replies, context preview with JSON highlighting, dismissible resource attachments retained when drawers close, optional terminal attachments, automatic visible Relationships/Consumers/Timeline snapshots when no attachment exists, resource links, resizable pinned chat, and a switch to disable all AI features
19
+ - **AI assistant:** native Codex or Claude CLI, per-cluster conversations, read-only API discovery and resource summaries, model/effort/speed selection, editable prompts, quick-start commands, Markdown with themed SQL highlighting, cancellable replies, context preview with JSON highlighting, dismissible resource attachments retained when drawers close, optional terminal attachments, automatic visible Relationships/Consumers/Timeline snapshots when no attachment exists, resource links, resizable pinned chat, and a switch to disable all AI features
20
20
  - **Read-only UI:** hides common mutation actions without changing Kubernetes permissions
21
- - **Master switch:** restores the native interface while preserving all settings
21
+ - **Interface:** hides the bottom Freelens status bar and reclaims its space; the master switch restores the native interface while preserving all settings
22
22
  - **Settings:** native switches, compact dashboard editors, and JSON backup and restore of cards and prompt shortcuts
23
23
 
24
24
  AI tool results exclude environment values and Secret payloads; automatic log summaries contain numeric issue counters. Power Logs lines and SQL results attach to a reviewable context block when the AI action is clicked. Drafted SQL is inserted into the editor without execution. Terminal output is sent only when explicitly attached; review its masked preview before sending. Websites run in isolated Electron views. Every dashboard card also opens in your browser.
@@ -1,7 +1,7 @@
1
1
  const require_power_logs = require("./common/power-logs.js");
2
2
  let node_sqlite = require("node:sqlite");
3
3
  //#region src/main/power-logs-query.ts
4
- var functions = new Set(`abs avg ceil ceiling char coalesce concat concat_ws count date datetime floor format glob group_concat hex if ifnull iif instr json json_array json_array_length json_error_position json_extract json_group_array json_group_object json_insert json_object json_patch json_pretty json_quote json_remove json_replace json_set json_type json_valid likelihood likely lower ltrim max min nullif octet_length pow power printf quote replace round rtrim sign strftime string_agg substr substring sum time timediff total trim typeof unicode unixepoch unlikely upper zeroblob length rank dense_rank row_number percent_rank cume_dist ntile lag lead first_value last_value nth_value`.split(" "));
4
+ var functions = new Set(`abs avg ceil ceiling char coalesce concat concat_ws count current_date current_time current_timestamp date datetime floor format glob group_concat hex if ifnull iif instr json json_array json_array_length json_error_position json_extract json_group_array json_group_object json_insert json_object json_patch json_pretty json_quote json_remove json_replace json_set json_type json_valid likelihood likely lower ltrim max min nullif octet_length pow power printf quote replace round rtrim sign strftime string_agg substr substring sum time timediff total trim typeof unicode unixepoch unlikely upper zeroblob length rank dense_rank row_number percent_rank cume_dist ntile lag lead first_value last_value nth_value`.split(" "));
5
5
  function singleStatement(sql) {
6
6
  let ended = false;
7
7
  let intent = "";
@@ -110,13 +110,14 @@ function runPowerLogsQuery(path, sql) {
110
110
  };
111
111
  } catch (error) {
112
112
  const message = error instanceof Error ? error.message : "";
113
- if (/not authorized|authorization denied|prohibited/i.test(message)) throw new Error("Use read-only SELECT or EXPLAIN statements over logs");
113
+ const missingFunction = /^no such function: ([a-z_][a-z0-9_]{0,63})$/i.exec(message)?.[1]?.toLowerCase();
114
+ const queryError = missingFunction ? missingFunction === "epoch_ms" ? "SQLite does not support epoch_ms(). For Unix milliseconds use unixepoch('now') * 1000." : `SQLite does not support the function [${missingFunction}]. Use supported SQLite functions.` : /not authorized|authorization denied|prohibited/i.test(message) ? "Use read-only SELECT or EXPLAIN over logs with supported SQLite functions. External files and extensions are disabled." : "SQLite could not run this query. Check SQL syntax, column names and supported functions.";
114
115
  return {
115
116
  columns: [],
116
117
  rows: [],
117
118
  truncated: false,
118
119
  elapsedMs: Date.now() - started,
119
- error: "SQLite could not run this query. Check SQL syntax, column names and supported functions."
120
+ error: queryError
120
121
  };
121
122
  } finally {
122
123
  database.close();
@@ -1 +1 @@
1
- {"version":3,"file":"power-logs-query.js","names":[],"sources":["../../src/main/power-logs-query.ts"],"sourcesContent":["import { constants, DatabaseSync } from \"node:sqlite\";\nimport { POWER_LOGS_LIMITS as L, type LogCell, type LogQueryResult } from \"../common/power-logs\";\n\nexport type PowerLogsQuerySnapshot = { database: string; captureId: string; expiresAt: number };\n\nconst functions = new Set(\n `abs avg ceil ceiling char coalesce concat concat_ws count date datetime floor format glob group_concat hex if ifnull iif instr json json_array json_array_length json_error_position json_extract json_group_array json_group_object json_insert json_object json_patch json_pretty json_quote json_remove json_replace json_set json_type json_valid likelihood likely lower ltrim max min nullif octet_length pow power printf quote replace round rtrim sign strftime string_agg substr substring sum time timediff total trim typeof unicode unixepoch unlikely upper zeroblob length rank dense_rank row_number percent_rank cume_dist ntile lag lead first_value last_value nth_value`.split(\n \" \",\n ),\n);\n\n// the scanner treats quoted text and comments as opaque before counting statements\nfunction singleStatement(sql: string): boolean {\n let ended = false;\n let intent = \"\";\n for (let i = 0; i < sql.length; ) {\n const c = sql[i];\n if (/\\s/.test(c)) {\n i++;\n continue;\n }\n if (sql.startsWith(\"--\", i)) {\n const end = sql.indexOf(\"\\n\", i + 2);\n i = end < 0 ? sql.length : end + 1;\n continue;\n }\n if (sql.startsWith(\"/*\", i)) {\n const end = sql.indexOf(\"*/\", i + 2);\n if (end < 0) return false;\n i = end + 2;\n continue;\n }\n if (ended) return false;\n if (!intent) {\n const word = /^[a-z]+/i.exec(sql.slice(i));\n if (!word || !/^(select|with|explain)$/i.test(word[0])) return false;\n intent = word[0];\n }\n if (c === \";\") {\n ended = true;\n i++;\n continue;\n }\n if (c === \"'\" || c === '\"' || c === \"`\" || c === \"[\") {\n const closing = c === \"[\" ? \"]\" : c;\n let closed = false;\n for (i++; i < sql.length; i++) {\n if (sql[i] !== closing) continue;\n if (closing !== \"]\" && sql[i + 1] === closing) {\n i++;\n continue;\n }\n i++;\n closed = true;\n break;\n }\n if (!closed) return false;\n continue;\n }\n i++;\n }\n return Boolean(intent);\n}\n\nfunction cell(value: unknown): LogCell {\n if (value == null) return null;\n if (typeof value === \"bigint\")\n return value >= BigInt(Number.MIN_SAFE_INTEGER) && value <= BigInt(Number.MAX_SAFE_INTEGER)\n ? Number(value)\n : value.toString();\n if (value instanceof Uint8Array) return Buffer.from(value).toString(\"hex\");\n if (typeof value === \"number\") return Number.isFinite(value) ? value : String(value);\n return typeof value === \"string\" ? value : String(value);\n}\n\nexport function runPowerLogsQuery(path: string, sql: string): LogQueryResult {\n if (!singleStatement(sql)) throw new Error(\"Use a single SELECT or EXPLAIN statement\");\n const started = Date.now();\n const database = new DatabaseSync(path, { readOnly: true, allowExtension: false });\n try {\n if (typeof database.setAuthorizer !== \"function\")\n return {\n columns: [],\n rows: [],\n truncated: false,\n elapsedMs: Date.now() - started,\n error: \"Update Freelens to use secure Power Logs SQL queries. This runtime does not support SQL authorization.\",\n };\n database.exec(\n \"PRAGMA hard_heap_limit=134217728; PRAGMA cache_size=-16384; PRAGMA temp_store=MEMORY; PRAGMA mmap_size=0\",\n );\n database.setAuthorizer((action, table, name, db) => {\n if (action === constants.SQLITE_SELECT || action === constants.SQLITE_RECURSIVE) return constants.SQLITE_OK;\n if (action === constants.SQLITE_READ && (db === \"main\" || db === null) && table === \"logs\")\n return constants.SQLITE_OK;\n if (\n action === constants.SQLITE_READ &&\n (db === \"main\" || db === null) &&\n table === \"json_each\" &&\n (name === \"key\" || name === \"value\" || name === \"type\")\n )\n return constants.SQLITE_OK;\n // SQLite uses an empty column and no database for constant projections from a CTE\n if (action === constants.SQLITE_READ && db === null && name === \"\" && table && !/^(sqlite_|pragma_)/i.test(table))\n return constants.SQLITE_OK;\n if (action === constants.SQLITE_FUNCTION && functions.has((name ?? \"\").toLowerCase())) return constants.SQLITE_OK;\n return constants.SQLITE_DENY;\n });\n const statement = database.prepare(sql);\n statement.setReadBigInts(true);\n statement.setReturnArrays(true);\n const columns = statement.columns().map((column) => column.name);\n let bytes = Buffer.byteLength(JSON.stringify(columns));\n if (columns.length > 100 || bytes > L.resultBytes) throw new Error(\"Query result exceeds limit\");\n const rows: LogCell[][] = [];\n let truncated = false;\n for (const row of statement.iterate()) {\n const converted = (row as unknown as unknown[]).map(cell);\n const size = Buffer.byteLength(JSON.stringify(converted));\n if (rows.length >= L.resultRows || bytes + size > L.resultBytes) {\n truncated = true;\n break;\n }\n rows.push(converted);\n bytes += size;\n }\n return { columns, rows, truncated, elapsedMs: Date.now() - started };\n } catch (error) {\n const message = error instanceof Error ? error.message : \"\";\n if (/not authorized|authorization denied|prohibited/i.test(message))\n throw new Error(\"Use read-only SELECT or EXPLAIN statements over logs\");\n return {\n columns: [],\n rows: [],\n truncated: false,\n elapsedMs: Date.now() - started,\n error: \"SQLite could not run this query. Check SQL syntax, column names and supported functions.\",\n };\n } finally {\n database.close();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"power-logs-query.js","names":[],"sources":["../../src/main/power-logs-query.ts"],"sourcesContent":["import { constants, DatabaseSync } from \"node:sqlite\";\nimport { POWER_LOGS_LIMITS as L, type LogCell, type LogQueryResult } from \"../common/power-logs\";\n\nexport type PowerLogsQuerySnapshot = { database: string; captureId: string; expiresAt: number };\n\nconst functions = new Set(\n `abs avg ceil ceiling char coalesce concat concat_ws count current_date current_time current_timestamp date datetime floor format glob group_concat hex if ifnull iif instr json json_array json_array_length json_error_position json_extract json_group_array json_group_object json_insert json_object json_patch json_pretty json_quote json_remove json_replace json_set json_type json_valid likelihood likely lower ltrim max min nullif octet_length pow power printf quote replace round rtrim sign strftime string_agg substr substring sum time timediff total trim typeof unicode unixepoch unlikely upper zeroblob length rank dense_rank row_number percent_rank cume_dist ntile lag lead first_value last_value nth_value`.split(\n \" \",\n ),\n);\n\n// the scanner treats quoted text and comments as opaque before counting statements\nfunction singleStatement(sql: string): boolean {\n let ended = false;\n let intent = \"\";\n for (let i = 0; i < sql.length; ) {\n const c = sql[i];\n if (/\\s/.test(c)) {\n i++;\n continue;\n }\n if (sql.startsWith(\"--\", i)) {\n const end = sql.indexOf(\"\\n\", i + 2);\n i = end < 0 ? sql.length : end + 1;\n continue;\n }\n if (sql.startsWith(\"/*\", i)) {\n const end = sql.indexOf(\"*/\", i + 2);\n if (end < 0) return false;\n i = end + 2;\n continue;\n }\n if (ended) return false;\n if (!intent) {\n const word = /^[a-z]+/i.exec(sql.slice(i));\n if (!word || !/^(select|with|explain)$/i.test(word[0])) return false;\n intent = word[0];\n }\n if (c === \";\") {\n ended = true;\n i++;\n continue;\n }\n if (c === \"'\" || c === '\"' || c === \"`\" || c === \"[\") {\n const closing = c === \"[\" ? \"]\" : c;\n let closed = false;\n for (i++; i < sql.length; i++) {\n if (sql[i] !== closing) continue;\n if (closing !== \"]\" && sql[i + 1] === closing) {\n i++;\n continue;\n }\n i++;\n closed = true;\n break;\n }\n if (!closed) return false;\n continue;\n }\n i++;\n }\n return Boolean(intent);\n}\n\nfunction cell(value: unknown): LogCell {\n if (value == null) return null;\n if (typeof value === \"bigint\")\n return value >= BigInt(Number.MIN_SAFE_INTEGER) && value <= BigInt(Number.MAX_SAFE_INTEGER)\n ? Number(value)\n : value.toString();\n if (value instanceof Uint8Array) return Buffer.from(value).toString(\"hex\");\n if (typeof value === \"number\") return Number.isFinite(value) ? value : String(value);\n return typeof value === \"string\" ? value : String(value);\n}\n\nexport function runPowerLogsQuery(path: string, sql: string): LogQueryResult {\n if (!singleStatement(sql)) throw new Error(\"Use a single SELECT or EXPLAIN statement\");\n const started = Date.now();\n const database = new DatabaseSync(path, { readOnly: true, allowExtension: false });\n try {\n if (typeof database.setAuthorizer !== \"function\")\n return {\n columns: [],\n rows: [],\n truncated: false,\n elapsedMs: Date.now() - started,\n error: \"Update Freelens to use secure Power Logs SQL queries. This runtime does not support SQL authorization.\",\n };\n database.exec(\n \"PRAGMA hard_heap_limit=134217728; PRAGMA cache_size=-16384; PRAGMA temp_store=MEMORY; PRAGMA mmap_size=0\",\n );\n database.setAuthorizer((action, table, name, db) => {\n if (action === constants.SQLITE_SELECT || action === constants.SQLITE_RECURSIVE) return constants.SQLITE_OK;\n if (action === constants.SQLITE_READ && (db === \"main\" || db === null) && table === \"logs\")\n return constants.SQLITE_OK;\n if (\n action === constants.SQLITE_READ &&\n (db === \"main\" || db === null) &&\n table === \"json_each\" &&\n (name === \"key\" || name === \"value\" || name === \"type\")\n )\n return constants.SQLITE_OK;\n // SQLite uses an empty column and no database for constant projections from a CTE\n if (action === constants.SQLITE_READ && db === null && name === \"\" && table && !/^(sqlite_|pragma_)/i.test(table))\n return constants.SQLITE_OK;\n if (action === constants.SQLITE_FUNCTION && functions.has((name ?? \"\").toLowerCase())) return constants.SQLITE_OK;\n return constants.SQLITE_DENY;\n });\n const statement = database.prepare(sql);\n statement.setReadBigInts(true);\n statement.setReturnArrays(true);\n const columns = statement.columns().map((column) => column.name);\n let bytes = Buffer.byteLength(JSON.stringify(columns));\n if (columns.length > 100 || bytes > L.resultBytes) throw new Error(\"Query result exceeds limit\");\n const rows: LogCell[][] = [];\n let truncated = false;\n for (const row of statement.iterate()) {\n const converted = (row as unknown as unknown[]).map(cell);\n const size = Buffer.byteLength(JSON.stringify(converted));\n if (rows.length >= L.resultRows || bytes + size > L.resultBytes) {\n truncated = true;\n break;\n }\n rows.push(converted);\n bytes += size;\n }\n return { columns, rows, truncated, elapsedMs: Date.now() - started };\n } catch (error) {\n const message = error instanceof Error ? error.message : \"\";\n const missingFunction = /^no such function: ([a-z_][a-z0-9_]{0,63})$/i.exec(message)?.[1]?.toLowerCase();\n const queryError = missingFunction\n ? missingFunction === \"epoch_ms\"\n ? \"SQLite does not support epoch_ms(). For Unix milliseconds use unixepoch('now') * 1000.\"\n : `SQLite does not support the function [${missingFunction}]. Use supported SQLite functions.`\n : /not authorized|authorization denied|prohibited/i.test(message)\n ? \"Use read-only SELECT or EXPLAIN over logs with supported SQLite functions. External files and extensions are disabled.\"\n : \"SQLite could not run this query. Check SQL syntax, column names and supported functions.\";\n return {\n columns: [],\n rows: [],\n truncated: false,\n elapsedMs: Date.now() - started,\n error: queryError,\n };\n } finally {\n database.close();\n }\n}\n"],"mappings":"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"}
@@ -3,6 +3,7 @@ const require__global_external_react = require("./_virtual/_global-external_reac
3
3
  var POWER_LOGS_SQL_DRAFT_PROMPT = `On the Power Logs workspace, help draft SQLite SELECT queries for captured logs.
4
4
  The table is logs(timestamp INTEGER, pod TEXT, podUid TEXT, container TEXT, level TEXT, message TEXT, fieldsJson TEXT, previous INTEGER).
5
5
  Timestamp is Unix epoch milliseconds and can be NULL. previous is 0 or 1. fieldsJson contains JSON text or NULL, usable with SQLite json_extract.
6
+ Use SQLite date/time functions, not DuckDB or PostgreSQL functions. For the last five minutes use timestamp >= unixepoch('now') * 1000 - 300000. epoch_ms() is not available. CURRENT_TIMESTAMP is a UTC text value, not milliseconds.
6
7
  Return proposed queries in fenced sql blocks. Draft queries only: never execute them, call a query tool, or claim they ran. The user can insert a draft into the SQL editor, review it, and explicitly run it.`;
7
8
  function isPowerLogsWorkspace() {
8
9
  return !!document.querySelector("[data-testid=\"power-logs-page\"]") || /\/power-logs\/?$/.test(window.location.pathname);
@@ -1 +1 @@
1
- {"version":3,"file":"ai-logs-sql.js","names":[],"sources":["../../src/renderer/ai-logs-sql.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport const POWER_LOGS_SQL_DRAFT_PROMPT = `On the Power Logs workspace, help draft SQLite SELECT queries for captured logs.\nThe table is logs(timestamp INTEGER, pod TEXT, podUid TEXT, container TEXT, level TEXT, message TEXT, fieldsJson TEXT, previous INTEGER).\nTimestamp is Unix epoch milliseconds and can be NULL. previous is 0 or 1. fieldsJson contains JSON text or NULL, usable with SQLite json_extract.\nReturn proposed queries in fenced sql blocks. Draft queries only: never execute them, call a query tool, or claim they ran. The user can insert a draft into the SQL editor, review it, and explicitly run it.`;\n\nexport function isPowerLogsWorkspace(): boolean {\n return (\n !!document.querySelector('[data-testid=\"power-logs-page\"]') || /\\/power-logs\\/?$/.test(window.location.pathname)\n );\n}\n\nexport function usePowerLogsWorkspace(): boolean {\n const [active, setActive] = useState(isPowerLogsWorkspace);\n useEffect(() => {\n const update = (event: Event) => {\n const value = (event as CustomEvent<{ active?: unknown }>).detail?.active;\n if (typeof value === \"boolean\") setActive(value);\n };\n window.addEventListener(\"power-logs-workspace-change\", update);\n return () => window.removeEventListener(\"power-logs-workspace-change\", update);\n }, []);\n return active;\n}\n"],"mappings":";;AAEA,IAAa,8BAA8B;;;;AAK3C,SAAgB,uBAAgC;CAC9C,OACE,CAAC,CAAC,SAAS,cAAc,mCAAiC,KAAK,mBAAmB,KAAK,OAAO,SAAS,QAAQ;AAEnH;AAEA,SAAgB,wBAAiC;CAC/C,MAAM,CAAC,QAAQ,aAAa,+BAAA,SAAS,oBAAoB;CACzD,+BAAA,gBAAgB;EACd,MAAM,UAAU,UAAiB;GAC/B,MAAM,QAAS,MAA4C,QAAQ;GACnE,IAAI,OAAO,UAAU,WAAW,UAAU,KAAK;EACjD;EACA,OAAO,iBAAiB,+BAA+B,MAAM;EAC7D,aAAa,OAAO,oBAAoB,+BAA+B,MAAM;CAC/E,GAAG,CAAC,CAAC;CACL,OAAO;AACT"}
1
+ {"version":3,"file":"ai-logs-sql.js","names":[],"sources":["../../src/renderer/ai-logs-sql.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport const POWER_LOGS_SQL_DRAFT_PROMPT = `On the Power Logs workspace, help draft SQLite SELECT queries for captured logs.\nThe table is logs(timestamp INTEGER, pod TEXT, podUid TEXT, container TEXT, level TEXT, message TEXT, fieldsJson TEXT, previous INTEGER).\nTimestamp is Unix epoch milliseconds and can be NULL. previous is 0 or 1. fieldsJson contains JSON text or NULL, usable with SQLite json_extract.\nUse SQLite date/time functions, not DuckDB or PostgreSQL functions. For the last five minutes use timestamp >= unixepoch('now') * 1000 - 300000. epoch_ms() is not available. CURRENT_TIMESTAMP is a UTC text value, not milliseconds.\nReturn proposed queries in fenced sql blocks. Draft queries only: never execute them, call a query tool, or claim they ran. The user can insert a draft into the SQL editor, review it, and explicitly run it.`;\n\nexport function isPowerLogsWorkspace(): boolean {\n return (\n !!document.querySelector('[data-testid=\"power-logs-page\"]') || /\\/power-logs\\/?$/.test(window.location.pathname)\n );\n}\n\nexport function usePowerLogsWorkspace(): boolean {\n const [active, setActive] = useState(isPowerLogsWorkspace);\n useEffect(() => {\n const update = (event: Event) => {\n const value = (event as CustomEvent<{ active?: unknown }>).detail?.active;\n if (typeof value === \"boolean\") setActive(value);\n };\n window.addEventListener(\"power-logs-workspace-change\", update);\n return () => window.removeEventListener(\"power-logs-workspace-change\", update);\n }, []);\n return active;\n}\n"],"mappings":";;AAEA,IAAa,8BAA8B;;;;;AAM3C,SAAgB,uBAAgC;CAC9C,OACE,CAAC,CAAC,SAAS,cAAc,mCAAiC,KAAK,mBAAmB,KAAK,OAAO,SAAS,QAAQ;AAEnH;AAEA,SAAgB,wBAAiC;CAC/C,MAAM,CAAC,QAAQ,aAAa,+BAAA,SAAS,oBAAoB;CACzD,+BAAA,gBAAgB;EACd,MAAM,UAAU,UAAiB;GAC/B,MAAM,QAAS,MAA4C,QAAQ;GACnE,IAAI,OAAO,UAAU,WAAW,UAAU,KAAK;EACjD;EACA,OAAO,iBAAiB,+BAA+B,MAAM;EAC7D,aAAa,OAAO,oBAAoB,+BAA+B,MAAM;CAC/E,GAAG,CAAC,CAAC;CACL,OAAO;AACT"}
@@ -6,6 +6,7 @@ const require_ai_icon = require("./ai-icon.js");
6
6
  const require_native_tooltip = require("./native-tooltip.js");
7
7
  const require_ai_logs_sql = require("./ai-logs-sql.js");
8
8
  const require_markdown_it = require("./node_modules/.pnpm/markdown-it@15.0.2/node_modules/markdown-it/dist/markdown-it.js");
9
+ const require_power_log_sql_editor = require("./power-log-sql-editor.js");
9
10
  let electron = require("electron");
10
11
  //#region src/renderer/ai-message.tsx
11
12
  var markdown = new require_markdown_it.default({
@@ -192,7 +193,9 @@ function CodeBlock({ text, language }) {
192
193
  ].includes(language.toLowerCase());
193
194
  const command = terminalInsertText(text);
194
195
  const logsWorkspace = require_ai_logs_sql.usePowerLogsWorkspace();
195
- const sqlDraft = ["sql", "sqlite"].includes(language.toLowerCase()) && logsWorkspace;
196
+ const sql = ["sql", "sqlite"].includes(language.toLowerCase());
197
+ const sqlTokens = require__global_external_react.useMemo(() => sql ? require_power_log_sql_editor.tokenizeSql(text) : void 0, [sql, text]);
198
+ const sqlDraft = sql && logsWorkspace;
196
199
  const insert = async () => {
197
200
  const activeTerminal = visibleTerminalId();
198
201
  if (!shell || !command || !activeTerminal || inserting) return;
@@ -266,7 +269,10 @@ function CodeBlock({ text, language }) {
266
269
  })
267
270
  ] })]
268
271
  }),
269
- /* @__PURE__ */ require_jsx_runtime.jsx("pre", { children: /* @__PURE__ */ require_jsx_runtime.jsx("code", { children: text }) }),
272
+ /* @__PURE__ */ require_jsx_runtime.jsx("pre", { children: /* @__PURE__ */ require_jsx_runtime.jsx("code", { children: sqlTokens ? sqlTokens.map((token, index) => /* @__PURE__ */ require_jsx_runtime.jsx("span", {
273
+ "data-sql-token": token.kind,
274
+ children: token.text
275
+ }, index)) : text }) }),
270
276
  shell && !command && /* @__PURE__ */ require_jsx_runtime.jsx("div", {
271
277
  className: "power-ai-code-hint",
272
278
  children: "Terminal insertion requires a single line without control characters."
@@ -1 +1 @@
1
- {"version":3,"file":"ai-message.js","names":[],"sources":["../../src/renderer/ai-message.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { clipboard, shell } from \"electron\";\nimport MarkdownIt, { type Token } from \"markdown-it\";\nimport { autorun } from \"mobx\";\nimport { createElement, Fragment, type ReactNode, useEffect, useMemo, useState } from \"react\";\nimport { AiIcon } from \"./ai-icon\";\nimport { isPowerLogsWorkspace, usePowerLogsWorkspace } from \"./ai-logs-sql\";\nimport { NativeTooltip } from \"./native-tooltip\";\n\nconst markdown = new MarkdownIt({ html: false, linkify: true, breaks: true });\nconst markdownTags = new Set([\n \"p\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"ul\",\n \"ol\",\n \"li\",\n \"blockquote\",\n \"table\",\n \"thead\",\n \"tbody\",\n \"tr\",\n \"th\",\n \"td\",\n \"strong\",\n \"em\",\n \"s\",\n \"a\",\n]);\n\nfunction externalLink(value: string | number | null): string | undefined {\n if (typeof value !== \"string\" || !value) return;\n try {\n const url = new URL(value);\n if ([\"https:\", \"http:\", \"mailto:\"].includes(url.protocol) && !url.username && !url.password) return url.href;\n } catch {}\n return;\n}\n\nfunction renderTokens(tokens: Token[]): ReactNode[] {\n type Container = { token?: Token; key: number; children: ReactNode[] };\n const stack: Container[] = [{ key: 0, children: [] }];\n const append = (node: ReactNode) => stack[stack.length - 1].children.push(node);\n tokens.forEach((token, index) => {\n if (token.nesting === 1) {\n stack.push({ token, key: index, children: [] });\n return;\n }\n if (token.nesting === -1) {\n if (stack.length === 1) return;\n const container = stack.pop()!;\n const opening = container.token!;\n const props: Record<string, unknown> = { key: container.key };\n let tag = markdownTags.has(opening.tag) && !opening.hidden ? opening.tag : Fragment;\n if (tag === \"a\") {\n const href = externalLink(opening.attrGet(\"href\"));\n if (!href) tag = Fragment;\n else {\n props.href = href;\n props.rel = \"noopener noreferrer\";\n props.target = \"_blank\";\n const open = (event: React.MouseEvent<HTMLAnchorElement>) => {\n event.preventDefault();\n if (event.type === \"auxclick\" && event.button !== 1) return;\n void shell.openExternal(href).catch(() => {});\n };\n props.onClick = open;\n props.onAuxClick = open;\n }\n }\n if (tag === \"ol\") {\n const start = Number(opening.attrGet(\"start\"));\n if (Number.isSafeInteger(start) && start > 0) props.start = start;\n }\n if (tag === \"th\" || tag === \"td\") {\n const alignment = String(opening.attrGet(\"style\") ?? \"\").match(/^text-align:(left|right|center)$/)?.[1];\n if (alignment) props.style = { textAlign: alignment };\n }\n const element = createElement(tag, props, ...container.children);\n const title = tag === \"a\" ? opening.attrGet(\"title\") : undefined;\n append(\n title ? (\n <NativeTooltip key={container.key} title={title}>\n {element}\n </NativeTooltip>\n ) : (\n element\n ),\n );\n return;\n }\n switch (token.type) {\n case \"inline\":\n append(<Fragment key={index}>{renderTokens(token.children ?? [])}</Fragment>);\n break;\n case \"code_inline\":\n append(<code key={index}>{token.content}</code>);\n break;\n case \"fence\":\n case \"code_block\":\n append(<CodeBlock key={index} language={token.info.trim().split(/\\s+/)[0]} text={token.content} />);\n break;\n case \"hardbreak\":\n case \"softbreak\":\n append(<br key={index} />);\n break;\n case \"hr\":\n append(<hr key={index} />);\n break;\n default:\n append(<Fragment key={index}>{token.content}</Fragment>);\n }\n });\n return stack[0].children;\n}\n\nexport function terminalInsertText(text: string): string | undefined {\n const command = text.replace(/^[\\r\\n]+|[\\r\\n]+$/g, \"\");\n // surrounding line endings are formatting, embedded control characters must never reach the terminal\n if (!command.trim() || /[\\u0000-\\u001f\\u007f-\\u009f\\u2028\\u2029]/u.test(command)) return undefined;\n return command;\n}\n\nfunction visibleTerminalId(): string | undefined {\n const prefix = \"dock-tab-content-for-\";\n for (const element of document.querySelectorAll<HTMLElement>(`[data-testid^=\"${prefix}\"]`)) {\n let visible = true;\n for (let node: HTMLElement | null = element; node; node = node.parentElement) {\n const style = getComputedStyle(node);\n if (\n node.hidden ||\n node.getAttribute(\"aria-hidden\") === \"true\" ||\n style.display === \"none\" ||\n style.visibility === \"hidden\" ||\n style.visibility === \"collapse\"\n ) {\n visible = false;\n break;\n }\n }\n if (!visible) continue;\n const id = element.dataset.testid?.slice(prefix.length);\n if (!id || !Renderer.Component.terminalStore.isConnected(id)) continue;\n const api = Renderer.Component.terminalStore.getTerminalApi(id);\n if (api?.isReady && api.isConnected()) return id;\n }\n return;\n}\n\nfunction useActiveTerminalId(): string | undefined {\n const [terminalId, setTerminalId] = useState<string>();\n useEffect(() => {\n let stop: (() => void) | undefined;\n const update = () => {\n stop?.();\n stop = autorun(() => setTerminalId(visibleTerminalId()));\n };\n update();\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 observer.disconnect();\n stop?.();\n };\n }, []);\n return terminalId;\n}\n\nfunction CodeBlock({ text, language }: { text: string; language: string }) {\n const [feedback, setFeedback] = useState(\"\");\n const terminalId = useActiveTerminalId();\n const [inserting, setInserting] = useState(false);\n const shell = [\"\", \"bash\", \"sh\", \"shell\", \"zsh\", \"console\", \"terminal\"].includes(language.toLowerCase());\n const command = terminalInsertText(text);\n const logsWorkspace = usePowerLogsWorkspace();\n const sqlDraft = [\"sql\", \"sqlite\"].includes(language.toLowerCase()) && logsWorkspace;\n const insert = async () => {\n const activeTerminal = visibleTerminalId();\n if (!shell || !command || !activeTerminal || inserting) return;\n setInserting(true);\n try {\n await Renderer.Component.terminalStore.sendCommand(command, { enter: false, tabId: activeTerminal });\n setFeedback(\"Inserted into terminal. Review the command before running it.\");\n } catch {\n setFeedback(\"Unable to insert into terminal.\");\n } finally {\n setInserting(false);\n }\n };\n return (\n <div className=\"power-ai-code\">\n <div className=\"power-ai-code-toolbar\">\n <span>{language || \"code\"}</span>\n <div>\n <NativeTooltip title=\"Copy code to clipboard\">\n <button\n type=\"button\"\n aria-label=\"Copy code\"\n onClick={() => {\n try {\n clipboard.writeText(text);\n setFeedback(\"Copied\");\n } catch {\n setFeedback(\"Unable to copy code.\");\n }\n }}\n >\n <AiIcon material=\"content_copy\" size={14} /> Copy\n </button>\n </NativeTooltip>\n {sqlDraft && (\n <NativeTooltip title=\"Insert into the SQL editor without running\">\n <button\n type=\"button\"\n aria-label=\"Insert into SQL\"\n disabled={!text.trim() || text.length > 65536}\n onClick={() => {\n if (!isPowerLogsWorkspace() || !text.trim() || text.length > 65536) return;\n window.dispatchEvent(new CustomEvent(\"power-logs-sql-draft\", { detail: { sql: text } }));\n window.dispatchEvent(new Event(\"power-ai-close\"));\n }}\n >\n <AiIcon material=\"post_add\" size={14} /> Insert into SQL\n </button>\n </NativeTooltip>\n )}\n {shell && terminalId && (\n <NativeTooltip\n title={\n !command\n ? \"Only a single line without control characters can be inserted\"\n : !terminalId\n ? \"Focus an open terminal tab to insert\"\n : \"Insert without running\"\n }\n >\n <button\n type=\"button\"\n aria-label=\"Insert into terminal\"\n disabled={!command || !terminalId || inserting}\n onClick={() => void insert()}\n >\n <AiIcon material=\"terminal\" size={14} /> Insert\n </button>\n </NativeTooltip>\n )}\n </div>\n </div>\n <pre>\n <code>{text}</code>\n </pre>\n {shell && !command && (\n <div className=\"power-ai-code-hint\">Terminal insertion requires a single line without control characters.</div>\n )}\n <div role=\"status\" className=\"power-ai-code-feedback\">\n {feedback}\n </div>\n </div>\n );\n}\n\nexport function AiMessageContent({ text }: { text: string }) {\n const content = useMemo(() => renderTokens(markdown.parse(text, {})), [text]);\n return <div className=\"power-ai-markdown\">{content}</div>;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ai-message.js","names":[],"sources":["../../src/renderer/ai-message.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { clipboard, shell } from \"electron\";\nimport MarkdownIt, { type Token } from \"markdown-it\";\nimport { autorun } from \"mobx\";\nimport { createElement, Fragment, type ReactNode, useEffect, useMemo, useState } from \"react\";\nimport { AiIcon } from \"./ai-icon\";\nimport { isPowerLogsWorkspace, usePowerLogsWorkspace } from \"./ai-logs-sql\";\nimport { NativeTooltip } from \"./native-tooltip\";\nimport { tokenizeSql } from \"./power-log-sql-editor\";\n\nconst markdown = new MarkdownIt({ html: false, linkify: true, breaks: true });\nconst markdownTags = new Set([\n \"p\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"ul\",\n \"ol\",\n \"li\",\n \"blockquote\",\n \"table\",\n \"thead\",\n \"tbody\",\n \"tr\",\n \"th\",\n \"td\",\n \"strong\",\n \"em\",\n \"s\",\n \"a\",\n]);\n\nfunction externalLink(value: string | number | null): string | undefined {\n if (typeof value !== \"string\" || !value) return;\n try {\n const url = new URL(value);\n if ([\"https:\", \"http:\", \"mailto:\"].includes(url.protocol) && !url.username && !url.password) return url.href;\n } catch {}\n return;\n}\n\nfunction renderTokens(tokens: Token[]): ReactNode[] {\n type Container = { token?: Token; key: number; children: ReactNode[] };\n const stack: Container[] = [{ key: 0, children: [] }];\n const append = (node: ReactNode) => stack[stack.length - 1].children.push(node);\n tokens.forEach((token, index) => {\n if (token.nesting === 1) {\n stack.push({ token, key: index, children: [] });\n return;\n }\n if (token.nesting === -1) {\n if (stack.length === 1) return;\n const container = stack.pop()!;\n const opening = container.token!;\n const props: Record<string, unknown> = { key: container.key };\n let tag = markdownTags.has(opening.tag) && !opening.hidden ? opening.tag : Fragment;\n if (tag === \"a\") {\n const href = externalLink(opening.attrGet(\"href\"));\n if (!href) tag = Fragment;\n else {\n props.href = href;\n props.rel = \"noopener noreferrer\";\n props.target = \"_blank\";\n const open = (event: React.MouseEvent<HTMLAnchorElement>) => {\n event.preventDefault();\n if (event.type === \"auxclick\" && event.button !== 1) return;\n void shell.openExternal(href).catch(() => {});\n };\n props.onClick = open;\n props.onAuxClick = open;\n }\n }\n if (tag === \"ol\") {\n const start = Number(opening.attrGet(\"start\"));\n if (Number.isSafeInteger(start) && start > 0) props.start = start;\n }\n if (tag === \"th\" || tag === \"td\") {\n const alignment = String(opening.attrGet(\"style\") ?? \"\").match(/^text-align:(left|right|center)$/)?.[1];\n if (alignment) props.style = { textAlign: alignment };\n }\n const element = createElement(tag, props, ...container.children);\n const title = tag === \"a\" ? opening.attrGet(\"title\") : undefined;\n append(\n title ? (\n <NativeTooltip key={container.key} title={title}>\n {element}\n </NativeTooltip>\n ) : (\n element\n ),\n );\n return;\n }\n switch (token.type) {\n case \"inline\":\n append(<Fragment key={index}>{renderTokens(token.children ?? [])}</Fragment>);\n break;\n case \"code_inline\":\n append(<code key={index}>{token.content}</code>);\n break;\n case \"fence\":\n case \"code_block\":\n append(<CodeBlock key={index} language={token.info.trim().split(/\\s+/)[0]} text={token.content} />);\n break;\n case \"hardbreak\":\n case \"softbreak\":\n append(<br key={index} />);\n break;\n case \"hr\":\n append(<hr key={index} />);\n break;\n default:\n append(<Fragment key={index}>{token.content}</Fragment>);\n }\n });\n return stack[0].children;\n}\n\nexport function terminalInsertText(text: string): string | undefined {\n const command = text.replace(/^[\\r\\n]+|[\\r\\n]+$/g, \"\");\n // surrounding line endings are formatting, embedded control characters must never reach the terminal\n if (!command.trim() || /[\\u0000-\\u001f\\u007f-\\u009f\\u2028\\u2029]/u.test(command)) return undefined;\n return command;\n}\n\nfunction visibleTerminalId(): string | undefined {\n const prefix = \"dock-tab-content-for-\";\n for (const element of document.querySelectorAll<HTMLElement>(`[data-testid^=\"${prefix}\"]`)) {\n let visible = true;\n for (let node: HTMLElement | null = element; node; node = node.parentElement) {\n const style = getComputedStyle(node);\n if (\n node.hidden ||\n node.getAttribute(\"aria-hidden\") === \"true\" ||\n style.display === \"none\" ||\n style.visibility === \"hidden\" ||\n style.visibility === \"collapse\"\n ) {\n visible = false;\n break;\n }\n }\n if (!visible) continue;\n const id = element.dataset.testid?.slice(prefix.length);\n if (!id || !Renderer.Component.terminalStore.isConnected(id)) continue;\n const api = Renderer.Component.terminalStore.getTerminalApi(id);\n if (api?.isReady && api.isConnected()) return id;\n }\n return;\n}\n\nfunction useActiveTerminalId(): string | undefined {\n const [terminalId, setTerminalId] = useState<string>();\n useEffect(() => {\n let stop: (() => void) | undefined;\n const update = () => {\n stop?.();\n stop = autorun(() => setTerminalId(visibleTerminalId()));\n };\n update();\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 observer.disconnect();\n stop?.();\n };\n }, []);\n return terminalId;\n}\n\nfunction CodeBlock({ text, language }: { text: string; language: string }) {\n const [feedback, setFeedback] = useState(\"\");\n const terminalId = useActiveTerminalId();\n const [inserting, setInserting] = useState(false);\n const shell = [\"\", \"bash\", \"sh\", \"shell\", \"zsh\", \"console\", \"terminal\"].includes(language.toLowerCase());\n const command = terminalInsertText(text);\n const logsWorkspace = usePowerLogsWorkspace();\n const sql = [\"sql\", \"sqlite\"].includes(language.toLowerCase());\n const sqlTokens = useMemo(() => (sql ? tokenizeSql(text) : undefined), [sql, text]);\n const sqlDraft = sql && logsWorkspace;\n const insert = async () => {\n const activeTerminal = visibleTerminalId();\n if (!shell || !command || !activeTerminal || inserting) return;\n setInserting(true);\n try {\n await Renderer.Component.terminalStore.sendCommand(command, { enter: false, tabId: activeTerminal });\n setFeedback(\"Inserted into terminal. Review the command before running it.\");\n } catch {\n setFeedback(\"Unable to insert into terminal.\");\n } finally {\n setInserting(false);\n }\n };\n return (\n <div className=\"power-ai-code\">\n <div className=\"power-ai-code-toolbar\">\n <span>{language || \"code\"}</span>\n <div>\n <NativeTooltip title=\"Copy code to clipboard\">\n <button\n type=\"button\"\n aria-label=\"Copy code\"\n onClick={() => {\n try {\n clipboard.writeText(text);\n setFeedback(\"Copied\");\n } catch {\n setFeedback(\"Unable to copy code.\");\n }\n }}\n >\n <AiIcon material=\"content_copy\" size={14} /> Copy\n </button>\n </NativeTooltip>\n {sqlDraft && (\n <NativeTooltip title=\"Insert into the SQL editor without running\">\n <button\n type=\"button\"\n aria-label=\"Insert into SQL\"\n disabled={!text.trim() || text.length > 65536}\n onClick={() => {\n if (!isPowerLogsWorkspace() || !text.trim() || text.length > 65536) return;\n window.dispatchEvent(new CustomEvent(\"power-logs-sql-draft\", { detail: { sql: text } }));\n window.dispatchEvent(new Event(\"power-ai-close\"));\n }}\n >\n <AiIcon material=\"post_add\" size={14} /> Insert into SQL\n </button>\n </NativeTooltip>\n )}\n {shell && terminalId && (\n <NativeTooltip\n title={\n !command\n ? \"Only a single line without control characters can be inserted\"\n : !terminalId\n ? \"Focus an open terminal tab to insert\"\n : \"Insert without running\"\n }\n >\n <button\n type=\"button\"\n aria-label=\"Insert into terminal\"\n disabled={!command || !terminalId || inserting}\n onClick={() => void insert()}\n >\n <AiIcon material=\"terminal\" size={14} /> Insert\n </button>\n </NativeTooltip>\n )}\n </div>\n </div>\n <pre>\n <code>\n {sqlTokens\n ? sqlTokens.map((token, index) => (\n <span key={index} data-sql-token={token.kind}>\n {token.text}\n </span>\n ))\n : text}\n </code>\n </pre>\n {shell && !command && (\n <div className=\"power-ai-code-hint\">Terminal insertion requires a single line without control characters.</div>\n )}\n <div role=\"status\" className=\"power-ai-code-feedback\">\n {feedback}\n </div>\n </div>\n );\n}\n\nexport function AiMessageContent({ text }: { text: string }) {\n const content = useMemo(() => renderTokens(markdown.parse(text, {})), [text]);\n return <div className=\"power-ai-markdown\">{content}</div>;\n}\n"],"mappings":"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"}
@@ -188,12 +188,19 @@ body:has(.AddRemoveButtons .remove-button:not([data-freelens-power-read-only]))
188
188
  .power-ai-markdown a { color: var(--primary); text-decoration: underline; text-underline-offset: 2px; }
189
189
  .power-ai-markdown hr { margin: 20px 0; border: 0; border-top: 1px solid var(--borderFaintColor); }
190
190
  .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; }
191
- .power-ai-code { margin: 12px 0; border: 1px solid var(--borderFaintColor); border-radius: 8px; overflow: hidden; background: var(--mainBackground); }
191
+ .power-ai-code { --sql-string:#e6a28c; --sql-number:#98c78e; --sql-function:#81b9e6; --sql-identifier:var(--textColorPrimary); margin: 12px 0; border: 1px solid var(--borderFaintColor); border-radius: 8px; overflow: hidden; background: var(--mainBackground); }
192
192
  .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; }
193
193
  .power-ai-code-toolbar > div { display: flex; gap: 4px; }
194
194
  .power-ai-code-toolbar button { padding: 4px 6px; font-size: 11px; }
195
- .power-ai-code pre { margin: 0; padding: 12px; overflow-x: auto; white-space: pre; }
196
- .power-ai-code pre code { padding: 0; background: transparent; }
195
+ .power-ai-code pre { color:var(--textColorPrimary); margin: 0; padding: 12px; overflow-x: auto; white-space: pre; }
196
+ .power-ai-code pre code { padding: 0; background: transparent; color:inherit; }
197
+ .theme-light .power-ai-code { --sql-string:#9e2b1a; --sql-number:#17642d; --sql-function:#005a9e; --sql-identifier:#684c9b; }
198
+ .power-ai-code [data-sql-token=keyword] { color:var(--primary); }
199
+ .power-ai-code [data-sql-token=function] { color:var(--sql-function); }
200
+ .power-ai-code [data-sql-token=string] { color:var(--sql-string); }
201
+ .power-ai-code [data-sql-token=identifier] { color:var(--sql-identifier); }
202
+ .power-ai-code [data-sql-token=number] { color:var(--sql-number); }
203
+ .power-ai-code [data-sql-token=comment] { color:var(--textColorSecondary); }
197
204
  .power-ai-code-hint, .power-ai-code-feedback:not(:empty) { padding: 0 12px 10px; color: var(--textColorSecondary); font-size: 11px; }
198
205
  .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; }
199
206
  .power-ai-autocomplete button { display: flex; width: 100%; justify-content: space-between; gap: 12px; border: 0; text-align: left; }
@@ -1 +1 @@
1
- {"version":3,"file":"ai.js","names":[],"sources":["../../src/renderer/ai.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { ipcRenderer } from \"electron\";\nimport { autorun } from \"mobx\";\nimport { observer } from \"mobx-react\";\nimport { type CSSProperties, useEffect, useRef, useState } from \"react\";\nimport ReactDOM from \"react-dom\";\nimport { AI_CHAT_CHANNEL, AI_READ_ACTIVITY_CHANNEL, type AiReadActivity } from \"../common/ai\";\nimport { AI_CANCEL_CHANNEL, attachedAiContext, normalizeAiReferences } from \"../common/ai-extras\";\nimport { expandAiShortcut } from \"../common/ai-shortcuts\";\nimport { type AiMessage, AiPreferencesStore } from \"../common/store/ai-preferences-store\";\nimport { AiShortcutsStore } from \"../common/store/ai-shortcuts-store\";\nimport { hasAiContextMutations } from \"./ai-context-mutations\";\nimport { AiCopyAnswer } from \"./ai-copy-answer\";\nimport {\n AI_DIAGNOSTIC_EVENT,\n type DiagnosticFinding,\n diagnosticQuestion,\n sanitizeDiagnosticFinding,\n} from \"./ai-diagnostic-handoff\";\nimport { AiContextPreview, AiResourceReferences } from \"./ai-extras\";\nimport { AiIcon, AiPinIcon } from \"./ai-icon\";\nimport { isPowerLogsWorkspace, POWER_LOGS_SQL_DRAFT_PROMPT } from \"./ai-logs-sql\";\nimport { AiMessageContent } from \"./ai-message\";\nimport { AiProviderIcon } from \"./ai-provider-icon\";\nimport { AiResizeHandle, clampAiPanelWidth, DEFAULT_AI_PANEL_WIDTH } from \"./ai-resize\";\nimport { AiStarterPrompts } from \"./ai-shortcuts\";\nimport {\n type AiTerminalAttachment,\n AiTerminalContext,\n activeAiTerminal,\n captureAiTerminal,\n} from \"./ai-terminal-context\";\nimport { NativeTooltip } from \"./native-tooltip\";\n\nexport interface AiScreenContext {\n clusterId?: string;\n screen?: string;\n resource?: { kind?: string; namespace?: string; name?: string };\n}\n\nexport function readAiContext(): AiScreenContext {\n const clusterId = Renderer.Catalog.activeCluster.get()?.metadata.uid;\n const screen = window.location.pathname;\n const details = new URLSearchParams(window.location.search).get(\"kube-details\");\n const match =\n details?.match(/^\\/api(?:\\/v\\d+)?\\/namespaces\\/([^/]+)\\/([^/]+)\\/([^/]+)$/) ??\n details?.match(/^\\/apis\\/[^/]+\\/[^/]+\\/namespaces\\/([^/]+)\\/([^/]+)\\/([^/]+)$/);\n const clusterResource =\n details?.match(/^\\/api\\/[^/]+\\/([^/]+)\\/([^/]+)$/) ?? details?.match(/^\\/apis\\/[^/]+\\/[^/]+\\/([^/]+)\\/([^/]+)$/);\n const resource = match\n ? { namespace: match[1], kind: match[2], name: match[3] }\n : clusterResource\n ? { kind: clusterResource[1], name: clusterResource[2] }\n : undefined;\n return { clusterId, screen, ...(resource ? { resource } : {}) };\n}\n\nexport function isAiClusterDocument(): boolean {\n return window.top !== window && Boolean(Renderer.Catalog.activeCluster.get());\n}\n\nexport function aiLauncherBottom(): number {\n const dock = document.querySelector<HTMLElement>(\".Dock\");\n if (!dock) return 16;\n const rect = dock.getBoundingClientRect();\n const style = window.getComputedStyle(dock);\n if (\n dock.hidden ||\n style.display === \"none\" ||\n style.visibility === \"hidden\" ||\n rect.width <= 0 ||\n rect.height <= 0 ||\n rect.top <= 0 ||\n rect.top >= window.innerHeight\n )\n return 16;\n return Math.max(16, window.innerHeight - rect.top + 16);\n}\n\nexport function aiLauncherLeft(): number {\n const sidebar = document.querySelector<HTMLElement>('[data-testid=\"cluster-sidebar\"], .Sidebar');\n const dock = document.querySelector<HTMLElement>(\".Dock\");\n let contentLeft = 0;\n for (const [element, edge] of [\n [sidebar, \"right\"],\n [dock, \"left\"],\n ] as const) {\n if (!element || element.hidden) continue;\n const style = window.getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n if (style.display === \"none\" || style.visibility === \"hidden\" || rect.width <= 0) continue;\n const value = rect[edge];\n if (Number.isFinite(value) && value >= 0 && value < window.innerWidth - 80)\n contentLeft = Math.max(contentLeft, value);\n }\n return contentLeft + 16;\n}\n\nexport function hasAiResourceDetails(): boolean {\n if (new URLSearchParams(window.location.search).get(\"kube-details\")) return true;\n return Array.from(\n document.querySelectorAll<HTMLElement>(\".Drawer.KubeObjectDetails, .Drawer.ReleaseDetails, .DetailsDrawer\"),\n ).some((element) => {\n const style = window.getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n return (\n !element.hidden && style.display !== \"none\" && style.visibility !== \"hidden\" && rect.width > 0 && rect.height > 0\n );\n });\n}\n\nexport function hasAiOverlay(): boolean {\n return Array.from(document.querySelectorAll<HTMLElement>('[role=\"dialog\"], dialog[open], .Dialog')).some(\n (element) => {\n const style = window.getComputedStyle(element);\n return !element.hidden && style.display !== \"none\" && style.visibility !== \"hidden\";\n },\n );\n}\n\nconst styles = `\n@keyframes power-ai-spin { to { transform: rotate(360deg); } }\n@keyframes power-ai-dot { 0%, 80%, 100% { opacity: .25; } 40% { opacity: 1; } }\nbody:has(.AddRemoveButtons .remove-button:not([data-freelens-power-read-only])) .power-ai-launcher { display: none; }\n.power-ai-read-activity > span { display: inline-flex; align-items: center; gap: 4px; }\n.power-ai-read-activity [data-status=\"reading\"] .Icon { animation: power-ai-spin 1.2s linear infinite; }\n.power-ai-thinking { margin: 12px 16px 18px; line-height: 1.5; color: var(--textColorSecondary); }\n.power-ai-dots > span { animation: power-ai-dot 1.3s ease-in-out infinite; }\n.power-ai-dots > span:nth-child(2) { animation-delay: .15s; }\n.power-ai-dots > span:nth-child(3) { animation-delay: .3s; }\n@media (prefers-reduced-motion: reduce) { .power-ai-read-activity [data-status=\"reading\"] .Icon, .power-ai-dots > span { animation: none; } }\n@keyframes power-ai-enter { from { transform: translateX(100%); } to { transform: translateX(0); } }\n:root .power-ai-launcher { position: fixed; bottom: 16px; left: auto; right: 16px; z-index: 100; display: inline-flex; align-items: center; gap: 6px; min-width: 0; min-height: 0; height: 34px; border: 1px solid var(--primary, #5896ff); border-radius: 24px; padding: 0 13px; background: var(--contentColor, #242424); color: var(--textColorAccent); box-shadow: 0 3px 12px #0003; font: inherit; font-size: 12px; font-weight: 500; line-height: 1; cursor: pointer; transition: opacity 180ms ease, background-color 140ms ease, box-shadow 140ms ease, transform 180ms ease; }\n.power-ai-overview-actions { position: relative; z-index: 5; height: 0; min-height: 0; flex: 0 0 0; pointer-events: none; }\n.power-ai-overview-actions + [data-testid=\"cluster-overview-page\"] [data-monitoring-summaries] { --power-monitoring-summary-top: 56px; }\n.power-ai-overview-actions button { transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease, box-shadow 160ms ease; position: absolute; top: 12px; right: 12px; pointer-events: auto; box-shadow: 0 2px 8px #0002; display: inline-flex; flex: 0 0 auto; width: auto; align-items: center; gap: 6px; min-height: 32px; padding: 6px 12px; font: inherit; font-size: 12px; border: 1px solid var(--borderFaintColor); border-radius: 10px; color: var(--textColorPrimary); background: var(--contentColor); cursor: pointer; }\n.power-ai-overview-actions button:hover { border-color: var(--primary); color: var(--textColorAccent); background: var(--contentColor); }\n.power-ai-overview-actions button:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-launcher.power-ai-launcher-hidden { opacity: 0; transform: translateY(8px); pointer-events: none; }\n.power-ai-launcher .Icon { color: inherit; }\n.power-ai-launcher:hover { background: color-mix(in srgb, var(--primary, #5896ff) 12%, var(--contentColor, #242424)); box-shadow: 0 4px 12px #0003; transform: translateY(-1px); }\n.power-ai-launcher:active { transform: translateY(0); box-shadow: 0 2px 6px #0002; }\n@media (prefers-reduced-motion: reduce) { :root .power-ai-launcher { transition: none; } .power-ai-launcher:hover, .power-ai-launcher:active { transform: none; } }\n.power-ai-launcher:focus-visible { outline: 2px solid var(--primary, #5896ff); outline-offset: 3px; }\n.power-ai-panel { position: fixed; right: 0; top: 0; bottom: 0; width: min(560px, 100vw); z-index: 10001; display: flex; flex-direction: column; background: var(--contentColor, #242424); color: var(--textColorAccent, white); animation: power-ai-enter 160ms ease-out; border-left: 1px solid var(--borderFaintColor); box-shadow: -4px 0 24px #0004; }\n.power-ai-resize-handle { position: absolute; left: -4px; top: 0; bottom: 0; width: 8px; z-index: 2; cursor: col-resize; touch-action: none; }\n.power-ai-resize-handle:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }\n.power-ai-panel header { padding: 16px; display: flex; gap: 10px; flex-shrink: 0; }\n.power-ai-panel header { border-bottom: 1px solid var(--borderFaintColor); justify-content: space-between; align-items: center; }\n.power-ai-messages { overflow: auto; flex: 1; min-height: 0; padding: 24px 16px; font-size: var(--power-ai-font-size, 14px); line-height: 1.65; overscroll-behavior: contain; }\n.power-ai-message { overflow-wrap: anywhere; padding: 14px 16px; margin-bottom: 20px; color: var(--textColorAccent); border: 1px solid var(--borderFaintColor); border-radius: 8px; }\n.power-ai-panel button { padding: 7px 10px; border: 1px solid var(--borderFaintColor); border-radius: 8px; background: var(--contentColor); color: var(--textColorPrimary); cursor: pointer; }\n:root .power-ai-panel header button:is(.power-ai-close, .power-ai-pin) { width: 30px; height: 30px; padding: 0; display: inline-flex; align-items: center; justify-content: center; border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel header button:is(.power-ai-close, .power-ai-pin):not(:disabled):not(.disabled):hover { color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent); }\n:root .power-ai-panel header button:is(.power-ai-close, .power-ai-pin):focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n:root .power-ai-panel button.power-ai-copy-answer { width: 24px; height: 24px; padding: 0; margin-left: auto; flex-shrink: 0; justify-content: center; border: 0; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel button.power-ai-copy-answer:not(:disabled):not(.disabled):hover { color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent); }\n:root .power-ai-panel button.power-ai-copy-answer:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-cancellation { display: flex; align-items: center; gap: 6px; }\n:root .power-ai-panel button.power-ai-dismiss { width: 24px; height: 24px; padding: 0; justify-content: center; border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel button.power-ai-dismiss:hover { color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent); }\n:root .power-ai-panel button.power-ai-dismiss:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-panel button:disabled { opacity: 0.5; cursor: default; }\n .power-ai-panel textarea { display: block; width: 100%; box-sizing: border-box; min-width: 0; min-height: 64px; max-height: 180px; field-sizing: content; padding: 12px 16px 6px; border: 0; border-radius: 12px; background: transparent; color: var(--textColorAccent); font: inherit; font-size: var(--power-ai-font-size, 14px); line-height: 1.5; resize: none; }\n.power-ai-panel textarea::placeholder { color: var(--textColorSecondary); opacity: 1; }\n.power-ai-panel textarea:focus { outline: none; }\n.power-ai-composer-footer { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 4px 10px 10px 16px; }\n.power-ai-composer-footer > span { color: var(--textColorSecondary); font-size: 11px; line-height: 1.5; }\n:root .power-ai-panel form button[type=\"submit\"] { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 34px; width: 34px; height: 34px; padding: 0; border-radius: 10px; }\n:root .power-ai-panel form button[type=\"submit\"]:not(:disabled):not(.disabled) { background-color: var(--primary); border-color: var(--primary); color: white; }\n:root .power-ai-panel form button[type=\"submit\"]:not(:disabled):not(.disabled):hover { background-color: color-mix(in srgb, var(--primary) 88%, white 12%); border-color: color-mix(in srgb, var(--primary) 88%, white 12%); color: white; }\n:root .power-ai-panel form button[type=\"submit\"]:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }\n:root .power-ai-panel form button[type=\"submit\"]:disabled { background-color: var(--contentColor); border-color: var(--borderFaintColor); color: var(--textColorSecondary); }\n.power-ai-message-user { border-color: color-mix(in srgb, var(--primary) 28%, var(--borderFaintColor)); background: color-mix(in srgb, var(--primary) 7%, var(--mainBackground)); }\n.power-ai-context { padding: 10px 20px; line-height: 1.5; border-bottom: 1px solid var(--borderFaintColor); font-size: 12px; color: var(--textColorSecondary); overflow-wrap: anywhere; }\n.power-ai-attached-resource { display: flex; align-items: center; justify-content: space-between; gap: 8px; }\n.power-ai-title, .power-ai-panel button { display: inline-flex; align-items: center; gap: 6px; }\n.power-ai-title { margin-right: auto; white-space: nowrap; color: var(--textColorAccent); }\n.power-ai-brand { display: inline-flex; align-items: center; gap: 6px; color: var(--primary); }\n.power-ai-brand .Icon { color: inherit; }\n:root .power-ai-panel header button.power-ai-pin[aria-pressed=\"true\"] { color: var(--primary); }\n.power-ai-panel header > button { flex-shrink: 0; }\n.power-ai-panel form { position: relative; flex-shrink: 0; margin: 0 16px 16px; border: 1px solid var(--borderFaintColor); border-radius: 12px; background: var(--mainBackground); transition: border-color 160ms ease; }\n.power-ai-panel form > .power-ai-context-preview { padding: 8px 48px 4px 16px !important; min-height: 34px; margin: 0; box-sizing: border-box; }\n.power-ai-context-preview pre { white-space: pre-wrap; overflow-wrap: anywhere; overflow: auto; }\n.power-ai-finding-content pre { max-height: 140px; }\n.power-ai-context-content pre { max-height: 160px; }\n.power-ai-context-preview .power-log-json { --json-key:#9cdcfe; --json-string:#ce9178; --json-number:#b5cea8; --json-literal:#c586c0; }\n.theme-light .power-ai-context-preview .power-log-json { --json-key:#005a9e; --json-string:#9e2b1a; --json-number:#17642d; --json-literal:#7a288c; }\n.power-ai-context-preview .power-log-json [data-token=key] { color:var(--json-key); }\n.power-ai-context-preview .power-log-json [data-token=string] { color:var(--json-string); }\n.power-ai-context-preview .power-log-json [data-token=number] { color:var(--json-number); }\n.power-ai-context-preview .power-log-json [data-token=literal] { color:var(--json-literal); }\n.power-ai-context-finding { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 4px; min-width: 0; }\n.power-ai-context-finding > .Icon { flex-shrink: 0; margin-top: 7px; }\n.power-ai-context-finding > details { flex: 1; min-width: 0; }\n.power-ai-context-finding summary { padding: 6px 0; min-height: 28px; box-sizing: border-box; cursor: pointer; overflow-wrap: anywhere; }\n:root .power-ai-panel button.power-ai-remove-context { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; min-height: 28px; flex-shrink: 0; padding: 0; border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel button.power-ai-remove-context:hover { background: color-mix(in srgb, var(--primary) 10%, transparent); color: var(--primary); }\n:root .power-ai-panel button.power-ai-remove-context:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-panel form:focus-within { border-color: var(--primary); }\n.power-ai-message > strong { display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 500; color: var(--textColorSecondary); margin-bottom: 10px; }\n.power-ai-message-assistant { border-color: transparent; background: transparent; }\n.power-ai-markdown { line-height: 1.65; font-size: var(--power-ai-font-size, 14px); color: var(--textColorAccent); }\n.power-ai-markdown p { margin: 0 0 14px; white-space: pre-wrap; }\n.power-ai-markdown p:last-child { margin-bottom: 0; }\n.power-ai-markdown ul, .power-ai-markdown ol { padding-left: 24px; margin: 10px 0 16px; }\n.power-ai-markdown ul { list-style: disc; }\n.power-ai-markdown ol { list-style: decimal; }\n.power-ai-markdown li { margin: 5px 0; }\n.power-ai-markdown li > ul, .power-ai-markdown li > ol { margin: 6px 0; }\n.power-ai-markdown li > p { margin-bottom: 6px; }\n.power-ai-markdown :is(h1, h2, h3, h4, h5, h6) { color: var(--textColorAccent); font-weight: 600; line-height: 1.4; margin: 24px 0 12px; }\n.power-ai-markdown :is(h1, h2, h3, h4, h5, h6):first-child { margin-top: 0; }\n.power-ai-markdown h1 { font-size: 1.43em; }\n.power-ai-markdown h2 { font-size: 1.29em; }\n.power-ai-markdown h3 { font-size: 1.14em; }\n.power-ai-markdown :is(h4, h5, h6) { font-size: 1em; }\n.power-ai-markdown blockquote { margin: 16px 0; padding: 4px 14px; border-left: 3px solid var(--borderColor); color: var(--textColorSecondary); }\n.power-ai-markdown blockquote > p:last-child { margin-bottom: 0; }\n.power-ai-markdown table { display: block; max-width: 100%; overflow-x: auto; margin: 16px 0; border-collapse: collapse; font-size: max(10px, calc(var(--power-ai-font-size, 14px) - 1px)); }\n.power-ai-markdown th, .power-ai-markdown td { padding: 9px 12px; border: 1px solid var(--borderFaintColor); text-align: left; }\n.power-ai-markdown th { font-weight: 600; background: color-mix(in srgb, var(--textColorAccent) 5%, transparent); }\n.power-ai-markdown a { color: var(--primary); text-decoration: underline; text-underline-offset: 2px; }\n.power-ai-markdown hr { margin: 20px 0; border: 0; border-top: 1px solid var(--borderFaintColor); }\n.power-ai-markdown code { font-family: var(--font-monospace, monospace); font-size: max(10px, calc(var(--power-ai-font-size, 14px) - 1px)); background: color-mix(in srgb, var(--textColorAccent) 8%, transparent); padding: 1px 4px; border-radius: 4px; }\n.power-ai-code { margin: 12px 0; border: 1px solid var(--borderFaintColor); border-radius: 8px; overflow: hidden; background: var(--mainBackground); }\n.power-ai-code-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 8px; border-bottom: 1px solid var(--borderFaintColor); color: var(--textColorSecondary); font-size: 11px; }\n.power-ai-code-toolbar > div { display: flex; gap: 4px; }\n.power-ai-code-toolbar button { padding: 4px 6px; font-size: 11px; }\n.power-ai-code pre { margin: 0; padding: 12px; overflow-x: auto; white-space: pre; }\n.power-ai-code pre code { padding: 0; background: transparent; }\n.power-ai-code-hint, .power-ai-code-feedback:not(:empty) { padding: 0 12px 10px; color: var(--textColorSecondary); font-size: 11px; }\n.power-ai-autocomplete { position: absolute; bottom: calc(100% + 8px); left: 0; right: 0; max-height: 240px; overflow-y: auto; padding: 6px; border: 1px solid var(--borderColor); border-radius: 10px; background: var(--contentColor); box-shadow: 0 4px 16px #0003; }\n.power-ai-autocomplete button { display: flex; width: 100%; justify-content: space-between; gap: 12px; border: 0; text-align: left; }\n.power-ai-autocomplete button[aria-selected=\"true\"] { background: color-mix(in srgb, var(--primary) 14%, var(--contentColor)); color: var(--textColorAccent); }\n.power-ai-autocomplete button > span:last-child { color: var(--textColorSecondary); font-size: 12px; }\n@media (prefers-reduced-motion: reduce) { .power-ai-panel { animation: none; } }\n`;\n\nconst AiChat = observer(({ isClusterDocument }: { isClusterDocument: () => boolean }) => {\n const preferences = AiPreferencesStore.getInstanceOrCreate<AiPreferencesStore>();\n const [open, setOpen] = useState(false);\n const [pinned, setPinned] = useState(false);\n const [launcherBottom, setLauncherBottom] = useState(aiLauncherBottom);\n const [launcherLeft, setLauncherLeft] = useState(aiLauncherLeft);\n const [resourceDetailsOpen, setResourceDetailsOpen] = useState(hasAiResourceDetails);\n const [viewportWidth, setViewportWidth] = useState(window.innerWidth);\n const [launcherHidden, setLauncherHidden] = useState(false);\n const [draft, setDraft] = useState(\"\");\n const [finding, setFinding] = useState<DiagnosticFinding>();\n const [resourceAttachment, setResourceAttachment] = useState<AiScreenContext>();\n const dismissedResource = useRef<string>();\n const panelOpen = useRef(open);\n panelOpen.current = open;\n const captureScreenResource = (current = readAiContext()) => {\n if (\n current.clusterId &&\n current.resource &&\n dismissedResource.current !== JSON.stringify({ clusterId: current.clusterId, resource: current.resource })\n )\n setResourceAttachment(current);\n };\n const attachScreenResource = () => {\n dismissedResource.current = undefined;\n captureScreenResource();\n };\n const removeResource = () => {\n const current = resourceAttachment ?? readAiContext();\n dismissedResource.current = JSON.stringify({ clusterId: current.clusterId, resource: current.resource });\n setResourceAttachment(undefined);\n };\n const [terminalAttachment, setTerminalAttachment] = useState<AiTerminalAttachment>();\n const [suggestionIndex, setSuggestionIndex] = useState(0);\n const [dismissedDraft, setDismissedDraft] = useState<string>();\n const suggestions =\n /^\\/[^\\s]*$/.test(draft) && dismissedDraft !== draft\n ? AiShortcutsStore.getInstanceOrCreate<AiShortcutsStore>().shortcuts.filter((shortcut) =>\n `${shortcut.command} ${shortcut.label}`.toLowerCase().includes(draft.slice(1).toLowerCase()),\n )\n : [];\n const dismissSuggestions = useRef<() => boolean>(() => false);\n dismissSuggestions.current = () => {\n if (!suggestions.length) return false;\n setDismissedDraft(draft);\n return true;\n };\n const following = useRef(true);\n const composer = useRef<HTMLTextAreaElement>(null);\n const selectSuggestion = (index: number) => {\n const shortcut = suggestions[index];\n if (!shortcut) return;\n setDraft(`/${shortcut.command} `);\n setSuggestionIndex(0);\n composer.current?.focus();\n };\n const [context, setContext] = useState(readAiContext);\n useEffect(() => {\n if (open && !finding && !terminalAttachment) window.dispatchEvent(new Event(\"power-ai-request-screen-context\"));\n }, [open]);\n const [pending, setPending] = useState<string[]>([]);\n const [error, setError] = useState(\"\");\n const [stopped, setStopped] = useState<string[]>([]);\n const activeRequests = useRef(new Map<string, string>());\n const [activity, setActivity] = useState<{\n key: string;\n reads: { method: AiReadActivity[\"method\"]; status: \"reading\" | \"ok\" | \"unavailable\" }[];\n }>({ key: \"\", reads: [] });\n const clusterReview = useRef<() => void>(() => {});\n const messagesElement = useRef<HTMLDivElement>(null);\n const [coveredByOverlay, setCoveredByOverlay] = useState(hasAiOverlay);\n useEffect(() => {\n let observedElements: Element[] = [];\n const resizeObserver =\n typeof ResizeObserver === \"undefined\"\n ? undefined\n : new ResizeObserver(() => {\n setLauncherBottom(aiLauncherBottom());\n setLauncherLeft(aiLauncherLeft());\n });\n const updateDock = () => {\n setViewportWidth(window.innerWidth);\n setLauncherBottom(aiLauncherBottom());\n setLauncherLeft(aiLauncherLeft());\n const elements = [\n document.querySelector(\".Dock\"),\n document.querySelector('[data-testid=\"cluster-sidebar\"], .Sidebar'),\n ].filter((element): element is Element => !!element);\n if (\n elements.length !== observedElements.length ||\n elements.some((element, index) => element !== observedElements[index])\n ) {\n resizeObserver?.disconnect();\n observedElements = elements;\n for (const element of elements) resizeObserver?.observe(element);\n }\n };\n const update = () => {\n updateDock();\n const nextContext = readAiContext();\n setContext(nextContext);\n if (panelOpen.current) captureScreenResource(nextContext);\n setResourceAttachment((current) => (current?.clusterId === nextContext.clusterId ? current : undefined));\n setFinding((current) => (current && current.clusterId !== nextContext.clusterId ? undefined : current));\n setResourceDetailsOpen(hasAiResourceDetails());\n setCoveredByOverlay(hasAiOverlay());\n };\n const onActivity = (_event: unknown, value: unknown) => {\n if (!value || typeof value !== \"object\") return;\n const entry = value as { requestId?: string; method?: string; status?: string };\n const requestKey = activeRequests.current.get(entry.requestId ?? \"\");\n if (\n !requestKey ||\n requestKey !== readAiContext().clusterId ||\n ![\"pods\", \"nodes\", \"resources\", \"logs\"].includes(entry.method ?? \"\") ||\n ![\"reading\", \"ok\", \"unavailable\"].includes(entry.status ?? \"\")\n )\n return;\n const read = {\n method: entry.method as AiReadActivity[\"method\"],\n status: entry.status as \"reading\" | \"ok\" | \"unavailable\",\n };\n setActivity((previous) => ({\n key: requestKey,\n reads: [\n ...(previous.key === requestKey ? previous.reads.filter((item) => item.method !== read.method) : []),\n read,\n ],\n }));\n };\n ipcRenderer.on(AI_READ_ACTIVITY_CHANNEL, onActivity);\n window.addEventListener(\"resize\", updateDock);\n window.addEventListener(\"popstate\", update);\n update();\n const timer = window.setInterval(update, 500);\n const observer = new MutationObserver((mutations) => {\n if (hasAiContextMutations(mutations)) update();\n });\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"class\", \"style\", \"hidden\", \"open\"],\n });\n const onDiagnostic = (event: Event) => {\n const next = sanitizeDiagnosticFinding((event as CustomEvent).detail);\n if (!next || !preferences.enabled || !isClusterDocument() || next.clusterId !== readAiContext().clusterId) return;\n update();\n setFinding(next);\n setDraft(\n (previous) =>\n previous ||\n (next.source === \"relationships\" ||\n next.source === \"diagnostics\" ||\n preferences.conversations[next.clusterId]?.length\n ? \"\"\n : \"Explain this finding and suggest the next read-only checks.\"),\n );\n setOpen(true);\n requestAnimationFrame(() => composer.current?.focus());\n };\n window.addEventListener(AI_DIAGNOSTIC_EVENT, onDiagnostic);\n window.addEventListener(\"power-ai-open\", updateAndOpen);\n window.addEventListener(\"power-ai-open-only\", openOnly);\n const closePanel = () => setOpen(false);\n window.addEventListener(\"power-ai-close\", closePanel);\n function openOnly() {\n attachScreenResource();\n update();\n setOpen(true);\n }\n function updateAndOpen() {\n openOnly();\n clusterReview.current();\n }\n return () => {\n window.removeEventListener(\"resize\", updateDock);\n window.removeEventListener(\"popstate\", update);\n resizeObserver?.disconnect();\n ipcRenderer.removeListener(AI_READ_ACTIVITY_CHANNEL, onActivity);\n for (const requestId of activeRequests.current.keys()) {\n void ipcRenderer.invoke(AI_CANCEL_CHANNEL, requestId).catch(() => {});\n }\n activeRequests.current.clear();\n window.clearInterval(timer);\n observer.disconnect();\n window.removeEventListener(\"power-ai-open\", updateAndOpen);\n window.removeEventListener(\"power-ai-open-only\", openOnly);\n window.removeEventListener(\"power-ai-close\", closePanel);\n window.removeEventListener(AI_DIAGNOSTIC_EVENT, onDiagnostic);\n };\n }, []);\n useEffect(() => {\n setLauncherHidden(false);\n const onScroll = (event: Event) => {\n const target = event.target;\n if (!(target instanceof HTMLElement) || target.closest('.power-ai-panel, .Sidebar, [role=\"navigation\"], aside'))\n return;\n if (!target.closest('.ItemListLayout, .KubeObjectListLayout, main, [role=\"main\"]')) return;\n if (target.scrollHeight <= target.clientHeight || target.clientHeight <= 0) return;\n setLauncherHidden(target.scrollTop > 0 && target.scrollHeight - target.clientHeight - target.scrollTop <= 16);\n };\n document.addEventListener(\"scroll\", onScroll, true);\n return () => document.removeEventListener(\"scroll\", onScroll, true);\n }, [context.screen]);\n useEffect(() => {\n if (!open) return;\n const onEscape = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\" || hasAiOverlay()) return;\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n if (!dismissSuggestions.current()) setOpen(false);\n };\n window.addEventListener(\"keydown\", onEscape, true);\n return () => window.removeEventListener(\"keydown\", onEscape, true);\n }, [open]);\n useEffect(() => {\n if (!open || pinned) return;\n const onOutsideClick = (event: MouseEvent) => {\n const target = event.target;\n if (\n !(target instanceof Element) ||\n target.closest(\n \".power-ai-panel, .power-ai-launcher, .power-ai-overview-actions, [data-freelens-power-ai-overlay]\",\n )\n )\n return;\n setOpen(false);\n };\n document.addEventListener(\"click\", onOutsideClick, true);\n return () => document.removeEventListener(\"click\", onOutsideClick, true);\n }, [open, pinned]);\n const availablePanelWidth = Math.max(1, viewportWidth - Math.max(0, launcherLeft - 16));\n const panelWidth = clampAiPanelWidth(preferences.chatPanelWidth ?? DEFAULT_AI_PANEL_WIDTH, availablePanelWidth);\n const attachedResource =\n resourceAttachment && resourceAttachment.clusterId === context.clusterId ? resourceAttachment.resource : undefined;\n const previewContext = attachedAiContext({\n clusterId: context.clusterId,\n screen: context.screen,\n ...(finding && finding.clusterId === context.clusterId && finding.resource\n ? { resource: finding.resource }\n : attachedResource\n ? { resource: attachedResource }\n : {}),\n });\n const key = context.clusterId ?? \"global\";\n const messages = preferences.conversations[key] ?? [];\n const busy = pending.includes(key);\n const readActivity = activity.key === key ? activity.reads : [];\n useEffect(() => {\n const element = messagesElement.current;\n if (element && following.current) element.scrollTop = element.scrollHeight;\n }, [messages.length, busy, open, key]);\n useEffect(() => {\n following.current = true;\n const element = messagesElement.current;\n if (element && open) element.scrollTop = element.scrollHeight;\n }, [open, key]);\n useEffect(() => {\n if (!terminalAttachment) return;\n const update = () => {\n if (activeAiTerminal(terminalAttachment.clusterId) !== terminalAttachment.terminalId)\n setTerminalAttachment(undefined);\n };\n update();\n const timer = window.setInterval(update, 500);\n const observer = new MutationObserver(update);\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"class\", \"style\", \"hidden\", \"aria-hidden\", \"data-testid\"],\n });\n return () => {\n window.clearInterval(timer);\n observer.disconnect();\n };\n }, [terminalAttachment, context.clusterId]);\n if (!preferences.enabled || !isClusterDocument() || coveredByOverlay) return null;\n const send = async (starter?: string) => {\n const question = expandAiShortcut(\n (starter ?? draft).trim(),\n AiShortcutsStore.getInstanceOrCreate<AiShortcutsStore>().shortcuts,\n );\n if (!question || busy) return;\n if (question.length > 20_000) {\n setError(\"Message is too long. Please keep it under 20,000 characters.\");\n return;\n }\n const activeFinding = finding?.clusterId === readAiContext().clusterId ? finding : undefined;\n const payloadQuestion = diagnosticQuestion(question, activeFinding);\n if (payloadQuestion.length > 20_000) {\n setError(\"Message and attached finding are too long. Shorten the message or remove the finding.\");\n return;\n }\n const currentContext = readAiContext();\n const requestResource =\n activeFinding?.resource ??\n (resourceAttachment && resourceAttachment.clusterId === currentContext.clusterId\n ? resourceAttachment.resource\n : undefined);\n const requestContext = attachedAiContext({\n clusterId: currentContext.clusterId,\n screen: currentContext.screen,\n ...(requestResource ? { resource: requestResource } : {}),\n });\n if ((requestContext.clusterId ?? \"global\") !== key) {\n setContext(requestContext);\n return;\n }\n const terminalSnapshot =\n terminalAttachment?.clusterId === requestContext.clusterId\n ? captureAiTerminal(requestContext.clusterId, terminalAttachment?.terminalId)\n : undefined;\n if (terminalAttachment && !terminalSnapshot) {\n setTerminalAttachment(undefined);\n setError(\"The attached terminal changed or is unavailable. Attach it again before sending.\");\n return;\n }\n setTerminalAttachment(undefined);\n setFinding(undefined);\n following.current = true;\n const next: AiMessage[] = [...messages, { role: \"user\", text: question }];\n preferences.setMessages(key, next);\n setDraft(\"\");\n setError(\"\");\n setStopped((keys) => keys.filter((entry) => entry !== key));\n setActivity({ key, reads: [] });\n setPending((keys) => [...keys, key]);\n const provider = preferences.provider;\n const requestId = crypto.randomUUID();\n activeRequests.current.set(requestId, key);\n try {\n const response = await ipcRenderer.invoke(AI_CHAT_CHANNEL, {\n requestId,\n messages: [...next.slice(0, -1), { role: \"user\" as const, text: payloadQuestion }]\n .slice(-80)\n .reduceRight<AiMessage[]>((tail, message) => {\n if (tail.reduce((length, item) => length + item.text.length, 0) + message.text.length < 100_000)\n tail.unshift({ role: message.role, text: message.text });\n return tail;\n }, []),\n context: requestContext,\n ...(terminalSnapshot ? { terminalSnapshot } : {}),\n systemPrompt: [\n preferences.systemPrompt,\n requestContext.clusterId ? preferences.clusterPrompt : \"\",\n isPowerLogsWorkspace() ? POWER_LOGS_SQL_DRAFT_PROMPT : \"\",\n ]\n .filter(Boolean)\n .join(\"\\n\\n\"),\n model: preferences.model,\n speed: preferences.speed,\n reasoningEffort: preferences.reasoningEffort,\n });\n if (activeRequests.current.get(requestId) !== key) return;\n if (!response || typeof response.text !== \"string\") throw new Error(\"Invalid response\");\n setActivity({\n key,\n reads: Array.isArray(response.reads)\n ? response.reads\n .filter(\n (read: AiReadActivity) =>\n [\"pods\", \"nodes\", \"resources\", \"logs\"].includes(read?.method) &&\n [\"ok\", \"unavailable\"].includes(read?.status),\n )\n .slice(0, 6)\n : [],\n });\n preferences.setMessages(key, [\n ...next,\n {\n role: \"assistant\",\n text: response.text,\n provider: response.provider === \"claude\" ? \"claude\" : provider,\n references: normalizeAiReferences(response.references),\n },\n ]);\n } catch (failure) {\n if (activeRequests.current.get(requestId) !== key) return;\n const code = String(failure).match(/FREELENS_AI_([A-Z_]+)/)?.[1];\n const messages: Record<string, string> = {\n READ_LIMIT: \"The assistant reached the read limit. Try a more specific question.\",\n TIMEOUT: \"The request timed out. Please try again.\",\n INVALID_REPLY: \"The assistant returned an incomplete reply. Please try again.\",\n CLI_FAILURE: \"The selected CLI request failed. Check your model access or try again.\",\n CANCELLED: \"The request was canceled.\",\n UNSAFE_POLICY:\n \"Claude managed policy cannot be safely isolated. Use Codex or ask your administrator to disable managed hooks and command helpers.\",\n INPUT_LIMIT: \"The request is too large. Start a new chat or shorten the message.\",\n };\n setError(\n (code && messages[code]) ||\n \"Unable to complete the request. Check that the selected CLI is installed and signed in, then try again.\",\n );\n } finally {\n activeRequests.current.delete(requestId);\n setPending((keys) => keys.filter((entry) => entry !== key));\n }\n };\n const stopResponse = () => {\n const requestId = [...activeRequests.current].find(([, requestKey]) => requestKey === key)?.[0];\n if (!requestId) return;\n activeRequests.current.delete(requestId);\n setStopped((keys) => [...keys.filter((entry) => entry !== key), key]);\n setActivity({ key, reads: [] });\n setError(\"\");\n void ipcRenderer.invoke(AI_CANCEL_CHANNEL, requestId).catch(() => {});\n };\n clusterReview.current = () => {\n const currentKey = readAiContext().clusterId;\n if (!currentKey || currentKey !== key || preferences.conversations[currentKey]?.length) return;\n void send(\n preferences.clusterPrompt.trim() ||\n \"Review this cluster using read-only queries and summarize its health and useful next steps.\",\n );\n };\n return (\n <>\n <style>{styles}</style>\n {!open && (\n <NativeTooltip title=\"Open AI assistant\">\n <button\n type=\"button\"\n className={`power-ai-launcher${launcherHidden ? \" power-ai-launcher-hidden\" : \"\"}`}\n aria-hidden={launcherHidden || undefined}\n tabIndex={launcherHidden ? -1 : 0}\n style={{\n bottom: launcherBottom,\n left: resourceDetailsOpen ? launcherLeft : \"auto\",\n right: resourceDetailsOpen ? \"auto\" : 16,\n }}\n onPointerDown={attachScreenResource}\n onMouseDown={attachScreenResource}\n onClick={() => {\n attachScreenResource();\n setOpen(true);\n }}\n aria-label=\"Open AI assistant\"\n >\n <span aria-hidden=\"true\">\n <AiIcon material=\"chat_bubble_outline\" size={16} />\n </span>{\" \"}\n AI\n </button>\n </NativeTooltip>\n )}\n {open && (\n <aside\n className=\"power-ai-panel\"\n aria-label=\"AI assistant\"\n onPointerDownCapture={() => captureScreenResource()}\n onMouseDownCapture={() => captureScreenResource()}\n onFocusCapture={() => captureScreenResource()}\n style={{ \"--power-ai-font-size\": `${preferences.chatFontSize ?? 14}px`, width: panelWidth } as CSSProperties}\n >\n <AiResizeHandle\n width={panelWidth}\n available={availablePanelWidth}\n onChange={(width) => preferences.setChatPanelWidth(width)}\n />\n <header>\n <strong className=\"power-ai-title\">\n <NativeTooltip title=\"AI assistant\">\n <span className=\"power-ai-brand\">\n <AiIcon material=\"auto_awesome\" size={18} /> AI\n </span>\n </NativeTooltip>{\" \"}\n Assistant\n </strong>\n <NativeTooltip title=\"Clear this conversation and start a new chat\">\n <button\n type=\"button\"\n disabled={busy}\n aria-label=\"New chat\"\n onClick={() => {\n setTerminalAttachment(undefined);\n setFinding(undefined);\n removeResource();\n preferences.setMessages(key, []);\n setStopped((keys) => keys.filter((entry) => entry !== key));\n setActivity({ key, reads: [] });\n setError(\"\");\n }}\n >\n <AiIcon material=\"add_comment\" size={16} /> New chat\n </button>\n </NativeTooltip>\n <NativeTooltip title={pinned ? \"Unpin to close when clicking outside\" : \"Pin to keep the assistant open\"}>\n <button\n type=\"button\"\n className=\"power-ai-pin\"\n aria-label=\"Pin AI assistant\"\n aria-pressed={pinned}\n onClick={() => setPinned((value) => !value)}\n >\n <AiPinIcon pinned={pinned} size={18} />\n </button>\n </NativeTooltip>\n <NativeTooltip title=\"Close AI assistant\">\n <button\n type=\"button\"\n onPointerDown={(event) => event.stopPropagation()}\n onMouseDown={(event) => event.stopPropagation()}\n onClick={(event) => {\n event.stopPropagation();\n setOpen(false);\n }}\n className=\"power-ai-close\"\n aria-label=\"Close AI assistant\"\n >\n <span aria-hidden=\"true\">\n <AiIcon material=\"close\" size={18} />\n </span>\n </button>\n </NativeTooltip>\n </header>\n <div className=\"power-ai-context\">\n {context.clusterId ? \"Cluster conversation\" : \"General conversation\"} · {context.screen}\n {attachedResource && !(finding?.clusterId === context.clusterId && finding?.resource) && (\n <div className=\"power-ai-attached-resource\" aria-label=\"Attached resource\">\n <span>\n {attachedResource.kind}/{attachedResource.name}\n {attachedResource.namespace ? ` · ${attachedResource.namespace}` : \"\"}\n </span>\n <NativeTooltip title=\"Remove resource from attached context\">\n <button\n type=\"button\"\n className=\"power-ai-remove-context\"\n aria-label=\"Remove attached resource\"\n onClick={removeResource}\n >\n <AiIcon material=\"close\" size={14} />\n </button>\n </NativeTooltip>\n </div>\n )}\n <br />\n Only screen and resource metadata are attached automatically.\n </div>\n <div\n className=\"power-ai-messages\"\n onScroll={(event) => {\n const element = event.currentTarget;\n following.current = element.scrollHeight - element.scrollTop - element.clientHeight < 48;\n }}\n aria-live=\"polite\"\n ref={messagesElement}\n >\n {messages.length === 0 && (\n <div className=\"power-ai-starters\">\n <p style={{ marginBottom: 12 }}>Ask about this screen or your cluster:</p>\n <AiStarterPrompts\n disabled={busy}\n onSelect={(prompt) => {\n void send(prompt);\n }}\n />\n </div>\n )}\n {messages.map((message, index) => (\n <div className={`power-ai-message power-ai-message-${message.role}`} key={index}>\n <strong>\n {message.role === \"user\" ? (\n <NativeTooltip title=\"You\">\n <span>\n <AiIcon material=\"person_outline\" size={16} />\n </span>\n </NativeTooltip>\n ) : (\n <AiProviderIcon provider={message.provider === \"claude\" ? \"claude\" : \"codex\"} />\n )}\n {message.role === \"user\" ? \"You\" : message.provider === \"claude\" ? \"Claude\" : \"Codex\"}\n {message.role === \"assistant\" && <AiCopyAnswer text={message.text} />}\n </strong>\n <AiMessageContent text={message.text} />\n {message.role === \"assistant\" && context.clusterId && (\n <AiResourceReferences\n clusterId={context.clusterId}\n references={message.references}\n text={message.text}\n onOpened={() => setOpen(false)}\n />\n )}\n </div>\n ))}\n {readActivity.length > 0 && (\n <div\n className=\"power-ai-read-activity\"\n style={{ fontSize: 11, color: \"var(--textColorSecondary)\", margin: \"8px 16px\" }}\n >\n {readActivity.map((read, index) => (\n <NativeTooltip\n key={index}\n title={`${read.method} · ${read.status === \"reading\" ? \"reading\" : read.status === \"ok\" ? \"read\" : \"unavailable\"}`}\n >\n <span data-method={read.method} data-status={read.status} style={{ marginRight: 10 }}>\n <AiIcon\n material={\n read.status === \"reading\"\n ? \"sync\"\n : read.status === \"ok\"\n ? \"check_circle_outline\"\n : \"info_outline\"\n }\n size={13}\n />{\" \"}\n {read.method} ·{\" \"}\n {read.status === \"reading\" ? \"reading\" : read.status === \"ok\" ? \"read\" : \"unavailable\"}\n </span>\n </NativeTooltip>\n ))}\n </div>\n )}\n {busy && (\n <p className=\"power-ai-thinking\" role=\"status\">\n {stopped.includes(key) ? \"Stopping response\" : \"Thinking\"}\n <span className=\"power-ai-dots\" aria-hidden=\"true\">\n <span>.</span>\n <span>.</span>\n <span>.</span>\n </span>\n </p>\n )}\n {!busy && stopped.includes(key) && (\n <p className=\"power-ai-cancellation\" role=\"status\">\n Response stopped{\" \"}\n <NativeTooltip title=\"Dismiss\">\n <button\n type=\"button\"\n aria-label=\"Dismiss cancellation\"\n className=\"power-ai-dismiss\"\n onClick={() => setStopped((keys) => keys.filter((entry) => entry !== key))}\n >\n <AiIcon material=\"close\" size={14} />\n </button>\n </NativeTooltip>\n </p>\n )}\n {error && <p role=\"alert\">{error}</p>}\n </div>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n void send();\n }}\n >\n {suggestions.length > 0 && (\n <div\n className=\"power-ai-autocomplete\"\n role=\"listbox\"\n id=\"power-ai-commands\"\n aria-label=\"Prompt shortcuts\"\n >\n {suggestions.map((shortcut, index) => (\n <NativeTooltip key={shortcut.id} title={`Insert /${shortcut.command}: ${shortcut.label}`}>\n <button\n type=\"button\"\n role=\"option\"\n id={`power-ai-command-${index}`}\n aria-selected={index === suggestionIndex % suggestions.length}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => selectSuggestion(index)}\n >\n <span>/{shortcut.command}</span>\n <span>{shortcut.label}</span>\n </button>\n </NativeTooltip>\n ))}\n </div>\n )}\n <AiContextPreview\n finding={finding?.clusterId === context.clusterId ? finding : undefined}\n onRemoveFinding={() => setFinding(undefined)}\n context={previewContext}\n />\n <AiTerminalContext\n clusterId={context.clusterId}\n attachment={terminalAttachment}\n onChange={setTerminalAttachment}\n disabled={busy}\n />\n <textarea\n ref={composer}\n aria-controls={suggestions.length ? \"power-ai-commands\" : undefined}\n aria-expanded={suggestions.length > 0}\n aria-activedescendant={\n suggestions.length ? `power-ai-command-${suggestionIndex % suggestions.length}` : undefined\n }\n autoFocus\n aria-label=\"Message\"\n placeholder=\"Ask about this cluster…\"\n onKeyDown={(event) => {\n if (event.nativeEvent.isComposing || event.keyCode === 229) return;\n if (suggestions.length && !event.shiftKey) {\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n setSuggestionIndex(\n (index) =>\n (index + (event.key === \"ArrowDown\" ? 1 : suggestions.length - 1)) % suggestions.length,\n );\n return;\n }\n if (event.key === \"Enter\" || event.key === \"Tab\") {\n event.preventDefault();\n selectSuggestion(suggestionIndex % suggestions.length);\n return;\n }\n }\n if (\n event.key === \"Enter\" &&\n !event.shiftKey &&\n !event.nativeEvent.isComposing &&\n event.keyCode !== 229\n ) {\n event.preventDefault();\n if (!busy) void send();\n }\n }}\n value={draft}\n onChange={(event) => {\n setDraft(event.target.value);\n setSuggestionIndex(0);\n setDismissedDraft(undefined);\n }}\n disabled={busy}\n />\n <div className=\"power-ai-composer-footer\">\n <span>Enter to send · Shift+Enter for newline</span>\n {busy ? (\n <button\n type=\"button\"\n aria-label=\"Stop response\"\n disabled={stopped.includes(key)}\n onClick={stopResponse}\n >\n <AiIcon material=\"stop\" size={16} /> Stop\n </button>\n ) : (\n <button type=\"submit\" disabled={!draft.trim()} aria-label=\"Send\">\n <AiIcon material=\"send\" size={16} />\n </button>\n )}\n </div>\n </form>\n </aside>\n )}\n </>\n );\n});\n\nexport function startAiChat(isClusterDocument: () => boolean = isAiClusterDocument): () => void {\n const container = document.createElement(\"div\");\n container.dataset.freelensPowerAi = \"\";\n document.body.append(container);\n let mounted = false;\n let overviewActions: HTMLDivElement | undefined;\n let overviewIcon: HTMLSpanElement | undefined;\n let overviewLabel: HTMLSpanElement | undefined;\n let overviewResize: ResizeObserver | undefined;\n const updateOverviewLabel = () => {\n const overview = overviewActions?.nextElementSibling;\n const compact = Boolean(overview?.querySelector(\"[data-freelens-power-monitoring]\") && overview.clientWidth > 960);\n const label = compact ? \"Ask AI\" : \"Ask about cluster\";\n if (overviewLabel && overviewLabel.textContent !== label) overviewLabel.textContent = label;\n overviewActions?.querySelector(\"button\")?.setAttribute(\"aria-label\", compact ? \"Ask AI about cluster\" : label);\n };\n const removeOverview = () => {\n overviewResize?.disconnect();\n overviewResize = undefined;\n if (overviewIcon) ReactDOM.unmountComponentAtNode(overviewIcon);\n overviewIcon = undefined;\n overviewLabel = undefined;\n overviewActions?.remove();\n overviewActions = undefined;\n };\n const preferences = AiPreferencesStore.getInstanceOrCreate<AiPreferencesStore>();\n const reconcile = () => {\n const overview =\n preferences.enabled &&\n isClusterDocument() &&\n Renderer.Catalog.activeCluster.get() &&\n document.querySelector('[data-testid=\"cluster-overview-page\"]');\n if (!overview) {\n removeOverview();\n return;\n }\n if (overviewActions?.isConnected && overviewActions.nextElementSibling === overview) {\n updateOverviewLabel();\n return;\n }\n removeOverview();\n overviewActions = document.createElement(\"div\");\n overviewActions.className = \"power-ai-overview-actions\";\n const overviewButton = document.createElement(\"button\");\n overviewButton.type = \"button\";\n overviewButton.setAttribute(\"aria-label\", \"Ask about cluster\");\n overviewButton.id = \"power-ai-overview-button\";\n overviewIcon = document.createElement(\"span\");\n overviewIcon.setAttribute(\"aria-hidden\", \"true\");\n overviewLabel = document.createElement(\"span\");\n overviewButton.append(overviewIcon, overviewLabel);\n overviewButton.onclick = () => window.dispatchEvent(new Event(\"power-ai-open\"));\n overviewActions.append(overviewButton);\n overview.before(overviewActions);\n updateOverviewLabel();\n if (typeof ResizeObserver !== \"undefined\") {\n overviewResize = new ResizeObserver(updateOverviewLabel);\n overviewResize.observe(overview);\n }\n ReactDOM.render(\n <>\n <AiIcon material=\"auto_awesome\" size={16} />\n <Renderer.Component.Tooltip targetId=\"power-ai-overview-button\">\n Open the AI assistant to ask about this cluster\n </Renderer.Component.Tooltip>\n </>,\n overviewIcon,\n );\n };\n const observer = new MutationObserver(reconcile);\n const stop = autorun(() => {\n if (preferences.enabled && !mounted) {\n observer.observe(document.body, { childList: true, subtree: true });\n mounted = true;\n ReactDOM.render(<AiChat isClusterDocument={isClusterDocument} />, container);\n } else if (!preferences.enabled && mounted) {\n observer.disconnect();\n ReactDOM.unmountComponentAtNode(container);\n mounted = false;\n }\n reconcile();\n });\n return () => {\n stop();\n observer.disconnect();\n removeOverview();\n ReactDOM.unmountComponentAtNode(container);\n container.remove();\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,SAAgB,gBAAiC;CAC/C,MAAM,YAAY,mBAAA,SAAS,QAAQ,cAAc,IAAI,CAAC,EAAE,SAAS;CACjE,MAAM,SAAS,OAAO,SAAS;CAC/B,MAAM,UAAU,IAAI,gBAAgB,OAAO,SAAS,MAAM,CAAC,CAAC,IAAI,cAAc;CAC9E,MAAM,QACJ,SAAS,MAAM,2DAA2D,KAC1E,SAAS,MAAM,+DAA+D;CAChF,MAAM,kBACJ,SAAS,MAAM,kCAAkC,KAAK,SAAS,MAAM,0CAA0C;CACjH,MAAM,WAAW,QACb;EAAE,WAAW,MAAM;EAAI,MAAM,MAAM;EAAI,MAAM,MAAM;CAAG,IACtD,kBACE;EAAE,MAAM,gBAAgB;EAAI,MAAM,gBAAgB;CAAG,IACrD,KAAA;CACN,OAAO;EAAE;EAAW;EAAQ,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;CAAG;AAChE;AAEA,SAAgB,sBAA+B;CAC7C,OAAO,OAAO,QAAQ,UAAU,QAAQ,mBAAA,SAAS,QAAQ,cAAc,IAAI,CAAC;AAC9E;AAEA,SAAgB,mBAA2B;CACzC,MAAM,OAAO,SAAS,cAA2B,OAAO;CACxD,IAAI,CAAC,MAAM,OAAO;CAClB,MAAM,OAAO,KAAK,sBAAsB;CACxC,MAAM,QAAQ,OAAO,iBAAiB,IAAI;CAC1C,IACE,KAAK,UACL,MAAM,YAAY,UAClB,MAAM,eAAe,YACrB,KAAK,SAAS,KACd,KAAK,UAAU,KACf,KAAK,OAAO,KACZ,KAAK,OAAO,OAAO,aAEnB,OAAO;CACT,OAAO,KAAK,IAAI,IAAI,OAAO,cAAc,KAAK,MAAM,EAAE;AACxD;AAEA,SAAgB,iBAAyB;CACvC,MAAM,UAAU,SAAS,cAA2B,6CAA2C;CAC/F,MAAM,OAAO,SAAS,cAA2B,OAAO;CACxD,IAAI,cAAc;CAClB,KAAK,MAAM,CAAC,SAAS,SAAS,CAC5B,CAAC,SAAS,OAAO,GACjB,CAAC,MAAM,MAAM,CACf,GAAY;EACV,IAAI,CAAC,WAAW,QAAQ,QAAQ;EAChC,MAAM,QAAQ,OAAO,iBAAiB,OAAO;EAC7C,MAAM,OAAO,QAAQ,sBAAsB;EAC3C,IAAI,MAAM,YAAY,UAAU,MAAM,eAAe,YAAY,KAAK,SAAS,GAAG;EAClF,MAAM,QAAQ,KAAK;EACnB,IAAI,OAAO,SAAS,KAAK,KAAK,SAAS,KAAK,QAAQ,OAAO,aAAa,IACtE,cAAc,KAAK,IAAI,aAAa,KAAK;CAC7C;CACA,OAAO,cAAc;AACvB;AAEA,SAAgB,uBAAgC;CAC9C,IAAI,IAAI,gBAAgB,OAAO,SAAS,MAAM,CAAC,CAAC,IAAI,cAAc,GAAG,OAAO;CAC5E,OAAO,MAAM,KACX,SAAS,iBAA8B,mEAAmE,CAC5G,CAAC,CAAC,MAAM,YAAY;EAClB,MAAM,QAAQ,OAAO,iBAAiB,OAAO;EAC7C,MAAM,OAAO,QAAQ,sBAAsB;EAC3C,OACE,CAAC,QAAQ,UAAU,MAAM,YAAY,UAAU,MAAM,eAAe,YAAY,KAAK,QAAQ,KAAK,KAAK,SAAS;CAEpH,CAAC;AACH;AAEA,SAAgB,eAAwB;CACtC,OAAO,MAAM,KAAK,SAAS,iBAA8B,0CAAwC,CAAC,CAAC,CAAC,MACjG,YAAY;EACX,MAAM,QAAQ,OAAO,iBAAiB,OAAO;EAC7C,OAAO,CAAC,QAAQ,UAAU,MAAM,YAAY,UAAU,MAAM,eAAe;CAC7E,CACF;AACF;AAEA,IAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwHf,IAAM,SAAS,oCAAA,UAAU,EAAE,wBAA8D;CACvF,MAAM,cAAc,6BAAA,mBAAmB,oBAAwC;CAC/E,MAAM,CAAC,MAAM,WAAW,+BAAA,SAAS,KAAK;CACtC,MAAM,CAAC,QAAQ,aAAa,+BAAA,SAAS,KAAK;CAC1C,MAAM,CAAC,gBAAgB,qBAAqB,+BAAA,SAAS,gBAAgB;CACrE,MAAM,CAAC,cAAc,mBAAmB,+BAAA,SAAS,cAAc;CAC/D,MAAM,CAAC,qBAAqB,0BAA0B,+BAAA,SAAS,oBAAoB;CACnF,MAAM,CAAC,eAAe,oBAAoB,+BAAA,SAAS,OAAO,UAAU;CACpE,MAAM,CAAC,gBAAgB,qBAAqB,+BAAA,SAAS,KAAK;CAC1D,MAAM,CAAC,OAAO,YAAY,+BAAA,SAAS,EAAE;CACrC,MAAM,CAAC,SAAS,cAAc,+BAAA,SAA4B;CAC1D,MAAM,CAAC,oBAAoB,yBAAyB,+BAAA,SAA0B;CAC9E,MAAM,oBAAoB,+BAAA,OAAe;CACzC,MAAM,YAAY,+BAAA,OAAO,IAAI;CAC7B,UAAU,UAAU;CACpB,MAAM,yBAAyB,UAAU,cAAc,MAAM;EAC3D,IACE,QAAQ,aACR,QAAQ,YACR,kBAAkB,YAAY,KAAK,UAAU;GAAE,WAAW,QAAQ;GAAW,UAAU,QAAQ;EAAS,CAAC,GAEzG,sBAAsB,OAAO;CACjC;CACA,MAAM,6BAA6B;EACjC,kBAAkB,UAAU,KAAA;EAC5B,sBAAsB;CACxB;CACA,MAAM,uBAAuB;EAC3B,MAAM,UAAU,sBAAsB,cAAc;EACpD,kBAAkB,UAAU,KAAK,UAAU;GAAE,WAAW,QAAQ;GAAW,UAAU,QAAQ;EAAS,CAAC;EACvG,sBAAsB,KAAA,CAAS;CACjC;CACA,MAAM,CAAC,oBAAoB,yBAAyB,+BAAA,SAA+B;CACnF,MAAM,CAAC,iBAAiB,sBAAsB,+BAAA,SAAS,CAAC;CACxD,MAAM,CAAC,gBAAgB,qBAAqB,+BAAA,SAAiB;CAC7D,MAAM,cACJ,aAAa,KAAK,KAAK,KAAK,mBAAmB,QAC3C,2BAAA,iBAAiB,oBAAsC,CAAC,CAAC,UAAU,QAAQ,aACzE,GAAG,SAAS,QAAQ,GAAG,SAAS,QAAQ,YAAY,CAAC,CAAC,SAAS,MAAM,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAC7F,IACA,CAAC;CACP,MAAM,qBAAqB,+BAAA,aAA4B,KAAK;CAC5D,mBAAmB,gBAAgB;EACjC,IAAI,CAAC,YAAY,QAAQ,OAAO;EAChC,kBAAkB,KAAK;EACvB,OAAO;CACT;CACA,MAAM,YAAY,+BAAA,OAAO,IAAI;CAC7B,MAAM,WAAW,+BAAA,OAA4B,IAAI;CACjD,MAAM,oBAAoB,UAAkB;EAC1C,MAAM,WAAW,YAAY;EAC7B,IAAI,CAAC,UAAU;EACf,SAAS,IAAI,SAAS,QAAQ,EAAE;EAChC,mBAAmB,CAAC;EACpB,SAAS,SAAS,MAAM;CAC1B;CACA,MAAM,CAAC,SAAS,cAAc,+BAAA,SAAS,aAAa;CACpD,+BAAA,gBAAgB;EACd,IAAI,QAAQ,CAAC,WAAW,CAAC,oBAAoB,OAAO,cAAc,IAAI,MAAM,iCAAiC,CAAC;CAChH,GAAG,CAAC,IAAI,CAAC;CACT,MAAM,CAAC,SAAS,cAAc,+BAAA,SAAmB,CAAC,CAAC;CACnD,MAAM,CAAC,OAAO,YAAY,+BAAA,SAAS,EAAE;CACrC,MAAM,CAAC,SAAS,cAAc,+BAAA,SAAmB,CAAC,CAAC;CACnD,MAAM,iBAAiB,+BAAA,uBAAO,IAAI,IAAoB,CAAC;CACvD,MAAM,CAAC,UAAU,eAAe,+BAAA,SAG7B;EAAE,KAAK;EAAI,OAAO,CAAC;CAAE,CAAC;CACzB,MAAM,gBAAgB,+BAAA,aAAyB,CAAC,CAAC;CACjD,MAAM,kBAAkB,+BAAA,OAAuB,IAAI;CACnD,MAAM,CAAC,kBAAkB,uBAAuB,+BAAA,SAAS,YAAY;CACrE,+BAAA,gBAAgB;EACd,IAAI,mBAA8B,CAAC;EACnC,MAAM,iBACJ,OAAO,mBAAmB,cACtB,KAAA,IACA,IAAI,qBAAqB;GACvB,kBAAkB,iBAAiB,CAAC;GACpC,gBAAgB,eAAe,CAAC;EAClC,CAAC;EACP,MAAM,mBAAmB;GACvB,iBAAiB,OAAO,UAAU;GAClC,kBAAkB,iBAAiB,CAAC;GACpC,gBAAgB,eAAe,CAAC;GAChC,MAAM,WAAW,CACf,SAAS,cAAc,OAAO,GAC9B,SAAS,cAAc,6CAA2C,CACpE,CAAC,CAAC,QAAQ,YAAgC,CAAC,CAAC,OAAO;GACnD,IACE,SAAS,WAAW,iBAAiB,UACrC,SAAS,MAAM,SAAS,UAAU,YAAY,iBAAiB,MAAM,GACrE;IACA,gBAAgB,WAAW;IAC3B,mBAAmB;IACnB,KAAK,MAAM,WAAW,UAAU,gBAAgB,QAAQ,OAAO;GACjE;EACF;EACA,MAAM,eAAe;GACnB,WAAW;GACX,MAAM,cAAc,cAAc;GAClC,WAAW,WAAW;GACtB,IAAI,UAAU,SAAS,sBAAsB,WAAW;GACxD,uBAAuB,YAAa,SAAS,cAAc,YAAY,YAAY,UAAU,KAAA,CAAU;GACvG,YAAY,YAAa,WAAW,QAAQ,cAAc,YAAY,YAAY,KAAA,IAAY,OAAQ;GACtG,uBAAuB,qBAAqB,CAAC;GAC7C,oBAAoB,aAAa,CAAC;EACpC;EACA,MAAM,cAAc,QAAiB,UAAmB;GACtD,IAAI,CAAC,SAAS,OAAO,UAAU,UAAU;GACzC,MAAM,QAAQ;GACd,MAAM,aAAa,eAAe,QAAQ,IAAI,MAAM,aAAa,EAAE;GACnE,IACE,CAAC,cACD,eAAe,cAAc,CAAC,CAAC,aAC/B,CAAC;IAAC;IAAQ;IAAS;IAAa;GAAM,CAAC,CAAC,SAAS,MAAM,UAAU,EAAE,KACnE,CAAC;IAAC;IAAW;IAAM;GAAa,CAAC,CAAC,SAAS,MAAM,UAAU,EAAE,GAE7D;GACF,MAAM,OAAO;IACX,QAAQ,MAAM;IACd,QAAQ,MAAM;GAChB;GACA,aAAa,cAAc;IACzB,KAAK;IACL,OAAO,CACL,GAAI,SAAS,QAAQ,aAAa,SAAS,MAAM,QAAQ,SAAS,KAAK,WAAW,KAAK,MAAM,IAAI,CAAC,GAClG,IACF;GACF,EAAE;EACJ;EACA,SAAA,YAAY,GAAG,WAAA,0BAA0B,UAAU;EACnD,OAAO,iBAAiB,UAAU,UAAU;EAC5C,OAAO,iBAAiB,YAAY,MAAM;EAC1C,OAAO;EACP,MAAM,QAAQ,OAAO,YAAY,QAAQ,GAAG;EAC5C,MAAM,WAAW,IAAI,kBAAkB,cAAc;GACnD,IAAI,6BAAA,sBAAsB,SAAS,GAAG,OAAO;EAC/C,CAAC;EACD,SAAS,QAAQ,SAAS,MAAM;GAC9B,WAAW;GACX,SAAS;GACT,YAAY;GACZ,iBAAiB;IAAC;IAAS;IAAS;IAAU;GAAM;EACtD,CAAC;EACD,MAAM,gBAAgB,UAAiB;GACrC,MAAM,OAAO,8BAAA,0BAA2B,MAAsB,MAAM;GACpE,IAAI,CAAC,QAAQ,CAAC,YAAY,WAAW,CAAC,kBAAkB,KAAK,KAAK,cAAc,cAAc,CAAC,CAAC,WAAW;GAC3G,OAAO;GACP,WAAW,IAAI;GACf,UACG,aACC,aACC,KAAK,WAAW,mBACjB,KAAK,WAAW,iBAChB,YAAY,cAAc,KAAK,UAAU,EAAE,SACvC,KACA,8DACR;GACA,QAAQ,IAAI;GACZ,4BAA4B,SAAS,SAAS,MAAM,CAAC;EACvD;EACA,OAAO,iBAAiB,8BAAA,qBAAqB,YAAY;EACzD,OAAO,iBAAiB,iBAAiB,aAAa;EACtD,OAAO,iBAAiB,sBAAsB,QAAQ;EACtD,MAAM,mBAAmB,QAAQ,KAAK;EACtC,OAAO,iBAAiB,kBAAkB,UAAU;EACpD,SAAS,WAAW;GAClB,qBAAqB;GACrB,OAAO;GACP,QAAQ,IAAI;EACd;EACA,SAAS,gBAAgB;GACvB,SAAS;GACT,cAAc,QAAQ;EACxB;EACA,aAAa;GACX,OAAO,oBAAoB,UAAU,UAAU;GAC/C,OAAO,oBAAoB,YAAY,MAAM;GAC7C,gBAAgB,WAAW;GAC3B,SAAA,YAAY,eAAe,WAAA,0BAA0B,UAAU;GAC/D,KAAK,MAAM,aAAa,eAAe,QAAQ,KAAK,GAClD,SAAK,YAAY,OAAO,kBAAA,mBAAmB,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC;GAEtE,eAAe,QAAQ,MAAM;GAC7B,OAAO,cAAc,KAAK;GAC1B,SAAS,WAAW;GACpB,OAAO,oBAAoB,iBAAiB,aAAa;GACzD,OAAO,oBAAoB,sBAAsB,QAAQ;GACzD,OAAO,oBAAoB,kBAAkB,UAAU;GACvD,OAAO,oBAAoB,8BAAA,qBAAqB,YAAY;EAC9D;CACF,GAAG,CAAC,CAAC;CACL,+BAAA,gBAAgB;EACd,kBAAkB,KAAK;EACvB,MAAM,YAAY,UAAiB;GACjC,MAAM,SAAS,MAAM;GACrB,IAAI,EAAE,kBAAkB,gBAAgB,OAAO,QAAQ,yDAAuD,GAC5G;GACF,IAAI,CAAC,OAAO,QAAQ,+DAA6D,GAAG;GACpF,IAAI,OAAO,gBAAgB,OAAO,gBAAgB,OAAO,gBAAgB,GAAG;GAC5E,kBAAkB,OAAO,YAAY,KAAK,OAAO,eAAe,OAAO,eAAe,OAAO,aAAa,EAAE;EAC9G;EACA,SAAS,iBAAiB,UAAU,UAAU,IAAI;EAClD,aAAa,SAAS,oBAAoB,UAAU,UAAU,IAAI;CACpE,GAAG,CAAC,QAAQ,MAAM,CAAC;CACnB,+BAAA,gBAAgB;EACd,IAAI,CAAC,MAAM;EACX,MAAM,YAAY,UAAyB;GACzC,IAAI,MAAM,QAAQ,YAAY,aAAa,GAAG;GAC9C,MAAM,eAAe;GACrB,MAAM,gBAAgB;GACtB,MAAM,yBAAyB;GAC/B,IAAI,CAAC,mBAAmB,QAAQ,GAAG,QAAQ,KAAK;EAClD;EACA,OAAO,iBAAiB,WAAW,UAAU,IAAI;EACjD,aAAa,OAAO,oBAAoB,WAAW,UAAU,IAAI;CACnE,GAAG,CAAC,IAAI,CAAC;CACT,+BAAA,gBAAgB;EACd,IAAI,CAAC,QAAQ,QAAQ;EACrB,MAAM,kBAAkB,UAAsB;GAC5C,MAAM,SAAS,MAAM;GACrB,IACE,EAAE,kBAAkB,YACpB,OAAO,QACL,mGACF,GAEA;GACF,QAAQ,KAAK;EACf;EACA,SAAS,iBAAiB,SAAS,gBAAgB,IAAI;EACvD,aAAa,SAAS,oBAAoB,SAAS,gBAAgB,IAAI;CACzE,GAAG,CAAC,MAAM,MAAM,CAAC;CACjB,MAAM,sBAAsB,KAAK,IAAI,GAAG,gBAAgB,KAAK,IAAI,GAAG,eAAe,EAAE,CAAC;CACtF,MAAM,aAAa,kBAAA,kBAAkB,YAAY,kBAAA,KAA0C,mBAAmB;CAC9G,MAAM,mBACJ,sBAAsB,mBAAmB,cAAc,QAAQ,YAAY,mBAAmB,WAAW,KAAA;CAC3G,MAAM,iBAAiB,kBAAA,kBAAkB;EACvC,WAAW,QAAQ;EACnB,QAAQ,QAAQ;EAChB,GAAI,WAAW,QAAQ,cAAc,QAAQ,aAAa,QAAQ,WAC9D,EAAE,UAAU,QAAQ,SAAS,IAC7B,mBACE,EAAE,UAAU,iBAAiB,IAC7B,CAAC;CACT,CAAC;CACD,MAAM,MAAM,QAAQ,aAAa;CACjC,MAAM,WAAW,YAAY,cAAc,QAAQ,CAAC;CACpD,MAAM,OAAO,QAAQ,SAAS,GAAG;CACjC,MAAM,eAAe,SAAS,QAAQ,MAAM,SAAS,QAAQ,CAAC;CAC9D,+BAAA,gBAAgB;EACd,MAAM,UAAU,gBAAgB;EAChC,IAAI,WAAW,UAAU,SAAS,QAAQ,YAAY,QAAQ;CAChE,GAAG;EAAC,SAAS;EAAQ;EAAM;EAAM;CAAG,CAAC;CACrC,+BAAA,gBAAgB;EACd,UAAU,UAAU;EACpB,MAAM,UAAU,gBAAgB;EAChC,IAAI,WAAW,MAAM,QAAQ,YAAY,QAAQ;CACnD,GAAG,CAAC,MAAM,GAAG,CAAC;CACd,+BAAA,gBAAgB;EACd,IAAI,CAAC,oBAAoB;EACzB,MAAM,eAAe;GACnB,IAAI,4BAAA,iBAAiB,mBAAmB,SAAS,MAAM,mBAAmB,YACxE,sBAAsB,KAAA,CAAS;EACnC;EACA,OAAO;EACP,MAAM,QAAQ,OAAO,YAAY,QAAQ,GAAG;EAC5C,MAAM,WAAW,IAAI,iBAAiB,MAAM;EAC5C,SAAS,QAAQ,SAAS,MAAM;GAC9B,WAAW;GACX,SAAS;GACT,YAAY;GACZ,iBAAiB;IAAC;IAAS;IAAS;IAAU;IAAe;GAAa;EAC5E,CAAC;EACD,aAAa;GACX,OAAO,cAAc,KAAK;GAC1B,SAAS,WAAW;EACtB;CACF,GAAG,CAAC,oBAAoB,QAAQ,SAAS,CAAC;CAC1C,IAAI,CAAC,YAAY,WAAW,CAAC,kBAAkB,KAAK,kBAAkB,OAAO;CAC7E,MAAM,OAAO,OAAO,YAAqB;EACvC,MAAM,WAAW,qBAAA,kBACd,WAAW,MAAA,CAAO,KAAK,GACxB,2BAAA,iBAAiB,oBAAsC,CAAC,CAAC,SAC3D;EACA,IAAI,CAAC,YAAY,MAAM;EACvB,IAAI,SAAS,SAAS,KAAQ;GAC5B,SAAS,8DAA8D;GACvE;EACF;EACA,MAAM,gBAAgB,SAAS,cAAc,cAAc,CAAC,CAAC,YAAY,UAAU,KAAA;EACnF,MAAM,kBAAkB,8BAAA,mBAAmB,UAAU,aAAa;EAClE,IAAI,gBAAgB,SAAS,KAAQ;GACnC,SAAS,uFAAuF;GAChG;EACF;EACA,MAAM,iBAAiB,cAAc;EACrC,MAAM,kBACJ,eAAe,aACd,sBAAsB,mBAAmB,cAAc,eAAe,YACnE,mBAAmB,WACnB,KAAA;EACN,MAAM,iBAAiB,kBAAA,kBAAkB;GACvC,WAAW,eAAe;GAC1B,QAAQ,eAAe;GACvB,GAAI,kBAAkB,EAAE,UAAU,gBAAgB,IAAI,CAAC;EACzD,CAAC;EACD,KAAK,eAAe,aAAa,cAAc,KAAK;GAClD,WAAW,cAAc;GACzB;EACF;EACA,MAAM,mBACJ,oBAAoB,cAAc,eAAe,YAC7C,4BAAA,kBAAkB,eAAe,WAAW,oBAAoB,UAAU,IAC1E,KAAA;EACN,IAAI,sBAAsB,CAAC,kBAAkB;GAC3C,sBAAsB,KAAA,CAAS;GAC/B,SAAS,kFAAkF;GAC3F;EACF;EACA,sBAAsB,KAAA,CAAS;EAC/B,WAAW,KAAA,CAAS;EACpB,UAAU,UAAU;EACpB,MAAM,OAAoB,CAAC,GAAG,UAAU;GAAE,MAAM;GAAQ,MAAM;EAAS,CAAC;EACxE,YAAY,YAAY,KAAK,IAAI;EACjC,SAAS,EAAE;EACX,SAAS,EAAE;EACX,YAAY,SAAS,KAAK,QAAQ,UAAU,UAAU,GAAG,CAAC;EAC1D,YAAY;GAAE;GAAK,OAAO,CAAC;EAAE,CAAC;EAC9B,YAAY,SAAS,CAAC,GAAG,MAAM,GAAG,CAAC;EACnC,MAAM,WAAW,YAAY;EAC7B,MAAM,YAAY,OAAO,WAAW;EACpC,eAAe,QAAQ,IAAI,WAAW,GAAG;EACzC,IAAI;GACF,MAAM,WAAW,MAAM,SAAA,YAAY,OAAO,WAAA,iBAAiB;IACzD;IACA,UAAU,CAAC,GAAG,KAAK,MAAM,GAAG,EAAE,GAAG;KAAE,MAAM;KAAiB,MAAM;IAAgB,CAAC,CAAC,CAC/E,MAAM,GAAG,CAAC,CACV,aAA0B,MAAM,YAAY;KAC3C,IAAI,KAAK,QAAQ,QAAQ,SAAS,SAAS,KAAK,KAAK,QAAQ,CAAC,IAAI,QAAQ,KAAK,SAAS,KACtF,KAAK,QAAQ;MAAE,MAAM,QAAQ;MAAM,MAAM,QAAQ;KAAK,CAAC;KACzD,OAAO;IACT,GAAG,CAAC,CAAC;IACP,SAAS;IACT,GAAI,mBAAmB,EAAE,iBAAiB,IAAI,CAAC;IAC/C,cAAc;KACZ,YAAY;KACZ,eAAe,YAAY,YAAY,gBAAgB;KACvD,oBAAA,qBAAqB,IAAI,oBAAA,8BAA8B;IACzD,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,MAAM;IACd,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,iBAAiB,YAAY;GAC/B,CAAC;GACD,IAAI,eAAe,QAAQ,IAAI,SAAS,MAAM,KAAK;GACnD,IAAI,CAAC,YAAY,OAAO,SAAS,SAAS,UAAU,MAAM,IAAI,MAAM,kBAAkB;GACtF,YAAY;IACV;IACA,OAAO,MAAM,QAAQ,SAAS,KAAK,IAC/B,SAAS,MACN,QACE,SACC;KAAC;KAAQ;KAAS;KAAa;IAAM,CAAC,CAAC,SAAS,MAAM,MAAM,KAC5D,CAAC,MAAM,aAAa,CAAC,CAAC,SAAS,MAAM,MAAM,CAC/C,CAAC,CACA,MAAM,GAAG,CAAC,IACb,CAAC;GACP,CAAC;GACD,YAAY,YAAY,KAAK,CAC3B,GAAG,MACH;IACE,MAAM;IACN,MAAM,SAAS;IACf,UAAU,SAAS,aAAa,WAAW,WAAW;IACtD,YAAY,kBAAA,sBAAsB,SAAS,UAAU;GACvD,CACF,CAAC;EACH,SAAS,SAAS;GAChB,IAAI,eAAe,QAAQ,IAAI,SAAS,MAAM,KAAK;GACnD,MAAM,OAAO,OAAO,OAAO,CAAC,CAAC,MAAM,uBAAuB,CAAC,GAAG;GAW9D,SACG,QAAQ;IAVT,YAAY;IACZ,SAAS;IACT,eAAe;IACf,aAAa;IACb,WAAW;IACX,eACE;IACF,aAAa;GAGJ,EAAS,SAChB,yGACJ;EACF,UAAU;GACR,eAAe,QAAQ,OAAO,SAAS;GACvC,YAAY,SAAS,KAAK,QAAQ,UAAU,UAAU,GAAG,CAAC;EAC5D;CACF;CACA,MAAM,qBAAqB;EACzB,MAAM,YAAY,CAAC,GAAG,eAAe,OAAO,CAAC,CAAC,MAAM,GAAG,gBAAgB,eAAe,GAAG,CAAC,GAAG;EAC7F,IAAI,CAAC,WAAW;EAChB,eAAe,QAAQ,OAAO,SAAS;EACvC,YAAY,SAAS,CAAC,GAAG,KAAK,QAAQ,UAAU,UAAU,GAAG,GAAG,GAAG,CAAC;EACpE,YAAY;GAAE;GAAK,OAAO,CAAC;EAAE,CAAC;EAC9B,SAAS,EAAE;EACX,SAAK,YAAY,OAAO,kBAAA,mBAAmB,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC;CACtE;CACA,cAAc,gBAAgB;EAC5B,MAAM,aAAa,cAAc,CAAC,CAAC;EACnC,IAAI,CAAC,cAAc,eAAe,OAAO,YAAY,cAAc,WAAW,EAAE,QAAQ;EACxF,KACE,YAAY,cAAc,KAAK,KAC7B,6FACJ;CACF;CACA,OACE,oCAAA,KAAA,oBAAA,UAAA,EAAA,UAAA;EACE,oCAAA,IAAC,SAAD,EAAA,UAAQ,OAAc,CAAA;EACrB,CAAC,QACA,oCAAA,IAAC,uBAAA,eAAD;GAAe,OAAM;aACnB,oCAAA,KAAC,UAAD;IACE,MAAK;IACL,WAAW,oBAAoB,iBAAiB,8BAA8B;IAC9E,eAAa,kBAAkB,KAAA;IAC/B,UAAU,iBAAiB,KAAK;IAChC,OAAO;KACL,QAAQ;KACR,MAAM,sBAAsB,eAAe;KAC3C,OAAO,sBAAsB,SAAS;IACxC;IACA,eAAe;IACf,aAAa;IACb,eAAe;KACb,qBAAqB;KACrB,QAAQ,IAAI;IACd;IACA,cAAW;cAhBb;KAkBE,oCAAA,IAAC,QAAD;MAAM,eAAY;gBAChB,oCAAA,IAAC,gBAAA,QAAD;OAAQ,UAAS;OAAsB,MAAM;MAAK,CAAA;KAC9C,CAAA;KAAE;KAAI;IAEN;;EACK,CAAA;EAEhB,QACC,oCAAA,KAAC,SAAD;GACE,WAAU;GACV,cAAW;GACX,4BAA4B,sBAAsB;GAClD,0BAA0B,sBAAsB;GAChD,sBAAsB,sBAAsB;GAC5C,OAAO;IAAE,wBAAwB,GAAG,YAAY,gBAAgB,GAAG;IAAK,OAAO;GAAW;aAN5F;IAQE,oCAAA,IAAC,kBAAA,gBAAD;KACE,OAAO;KACP,WAAW;KACX,WAAW,UAAU,YAAY,kBAAkB,KAAK;IACzD,CAAA;IACD,oCAAA,KAAC,UAAD,EAAA,UAAA;KACE,oCAAA,KAAC,UAAD;MAAQ,WAAU;gBAAlB;OACE,oCAAA,IAAC,uBAAA,eAAD;QAAe,OAAM;kBACnB,oCAAA,KAAC,QAAD;SAAM,WAAU;mBAAhB,CACE,oCAAA,IAAC,gBAAA,QAAD;UAAQ,UAAS;UAAe,MAAM;SAAK,CAAA,GAAC,KACxC;;OACO,CAAA;OAAE;OAAI;MAEf;;KACR,oCAAA,IAAC,uBAAA,eAAD;MAAe,OAAM;gBACnB,oCAAA,KAAC,UAAD;OACE,MAAK;OACL,UAAU;OACV,cAAW;OACX,eAAe;QACb,sBAAsB,KAAA,CAAS;QAC/B,WAAW,KAAA,CAAS;QACpB,eAAe;QACf,YAAY,YAAY,KAAK,CAAC,CAAC;QAC/B,YAAY,SAAS,KAAK,QAAQ,UAAU,UAAU,GAAG,CAAC;QAC1D,YAAY;SAAE;SAAK,OAAO,CAAC;QAAE,CAAC;QAC9B,SAAS,EAAE;OACb;iBAZF,CAcE,oCAAA,IAAC,gBAAA,QAAD;QAAQ,UAAS;QAAc,MAAM;OAAK,CAAA,GAAC,WACrC;;KACK,CAAA;KACf,oCAAA,IAAC,uBAAA,eAAD;MAAe,OAAO,SAAS,yCAAyC;gBACtE,oCAAA,IAAC,UAAD;OACE,MAAK;OACL,WAAU;OACV,cAAW;OACX,gBAAc;OACd,eAAe,WAAW,UAAU,CAAC,KAAK;iBAE1C,oCAAA,IAAC,gBAAA,WAAD;QAAmB;QAAQ,MAAM;OAAK,CAAA;MAChC,CAAA;KACK,CAAA;KACf,oCAAA,IAAC,uBAAA,eAAD;MAAe,OAAM;gBACnB,oCAAA,IAAC,UAAD;OACE,MAAK;OACL,gBAAgB,UAAU,MAAM,gBAAgB;OAChD,cAAc,UAAU,MAAM,gBAAgB;OAC9C,UAAU,UAAU;QAClB,MAAM,gBAAgB;QACtB,QAAQ,KAAK;OACf;OACA,WAAU;OACV,cAAW;iBAEX,oCAAA,IAAC,QAAD;QAAM,eAAY;kBAChB,oCAAA,IAAC,gBAAA,QAAD;SAAQ,UAAS;SAAQ,MAAM;QAAK,CAAA;OAChC,CAAA;MACA,CAAA;KACK,CAAA;IACT,EAAA,CAAA;IACR,oCAAA,KAAC,OAAD;KAAK,WAAU;eAAf;MACG,QAAQ,YAAY,yBAAyB;MAAuB;MAAI,QAAQ;MAChF,oBAAoB,EAAE,SAAS,cAAc,QAAQ,aAAa,SAAS,aAC1E,oCAAA,KAAC,OAAD;OAAK,WAAU;OAA6B,cAAW;iBAAvD,CACE,oCAAA,KAAC,QAAD,EAAA,UAAA;QACG,iBAAiB;QAAK;QAAE,iBAAiB;QACzC,iBAAiB,YAAY,MAAM,iBAAiB,cAAc;OAC/D,EAAA,CAAA,GACN,oCAAA,IAAC,uBAAA,eAAD;QAAe,OAAM;kBACnB,oCAAA,IAAC,UAAD;SACE,MAAK;SACL,WAAU;SACV,cAAW;SACX,SAAS;mBAET,oCAAA,IAAC,gBAAA,QAAD;UAAQ,UAAS;UAAQ,MAAM;SAAK,CAAA;QAC9B,CAAA;OACK,CAAA,CACZ;;MAEP,oCAAA,IAAC,MAAD,CAAK,CAAA;MAAC;KAEH;;IACL,oCAAA,KAAC,OAAD;KACE,WAAU;KACV,WAAW,UAAU;MACnB,MAAM,UAAU,MAAM;MACtB,UAAU,UAAU,QAAQ,eAAe,QAAQ,YAAY,QAAQ,eAAe;KACxF;KACA,aAAU;KACV,KAAK;eAPP;MASG,SAAS,WAAW,KACnB,oCAAA,KAAC,OAAD;OAAK,WAAU;iBAAf,CACE,oCAAA,IAAC,KAAD;QAAG,OAAO,EAAE,cAAc,GAAG;kBAAG;OAAyC,CAAA,GACzE,oCAAA,IAAC,uBAAA,kBAAD;QACE,UAAU;QACV,WAAW,WAAW;SACpB,KAAU,MAAM;QAClB;OACD,CAAA,CACE;;MAEN,SAAS,KAAK,SAAS,UACtB,oCAAA,KAAC,OAAD;OAAK,WAAW,qCAAqC,QAAQ;iBAA7D;QACE,oCAAA,KAAC,UAAD,EAAA,UAAA;SACG,QAAQ,SAAS,SAChB,oCAAA,IAAC,uBAAA,eAAD;UAAe,OAAM;oBACnB,oCAAA,IAAC,QAAD,EAAA,UACE,oCAAA,IAAC,gBAAA,QAAD;WAAQ,UAAS;WAAiB,MAAM;UAAK,CAAA,EACzC,CAAA;SACO,CAAA,IAEf,oCAAA,IAAC,yBAAA,gBAAD,EAAgB,UAAU,QAAQ,aAAa,WAAW,WAAW,QAAU,CAAA;SAEhF,QAAQ,SAAS,SAAS,QAAQ,QAAQ,aAAa,WAAW,WAAW;SAC7E,QAAQ,SAAS,eAAe,oCAAA,IAAC,uBAAA,cAAD,EAAc,MAAM,QAAQ,KAAO,CAAA;QAC9D,EAAA,CAAA;QACR,oCAAA,IAAC,mBAAA,kBAAD,EAAkB,MAAM,QAAQ,KAAO,CAAA;QACtC,QAAQ,SAAS,eAAe,QAAQ,aACvC,oCAAA,IAAC,oBAAA,sBAAD;SACE,WAAW,QAAQ;SACnB,YAAY,QAAQ;SACpB,MAAM,QAAQ;SACd,gBAAgB,QAAQ,KAAK;QAC9B,CAAA;OAEA;SAvBqE,KAuBrE,CACN;MACA,aAAa,SAAS,KACrB,oCAAA,IAAC,OAAD;OACE,WAAU;OACV,OAAO;QAAE,UAAU;QAAI,OAAO;QAA6B,QAAQ;OAAW;iBAE7E,aAAa,KAAK,MAAM,UACvB,oCAAA,IAAC,uBAAA,eAAD;QAEE,OAAO,GAAG,KAAK,OAAO,KAAK,KAAK,WAAW,YAAY,YAAY,KAAK,WAAW,OAAO,SAAS;kBAEnG,oCAAA,KAAC,QAAD;SAAM,eAAa,KAAK;SAAQ,eAAa,KAAK;SAAQ,OAAO,EAAE,aAAa,GAAG;mBAAnF;UACE,oCAAA,IAAC,gBAAA,QAAD;WACE,UACE,KAAK,WAAW,YACZ,SACA,KAAK,WAAW,OACd,yBACA;WAER,MAAM;UACP,CAAA;UAAE;UACF,KAAK;UAAO;UAAG;UACf,KAAK,WAAW,YAAY,YAAY,KAAK,WAAW,OAAO,SAAS;SACrE;;OACO,GAjBR,KAiBQ,CAChB;MACE,CAAA;MAEN,QACC,oCAAA,KAAC,KAAD;OAAG,WAAU;OAAoB,MAAK;iBAAtC,CACG,QAAQ,SAAS,GAAG,IAAI,sBAAsB,YAC/C,oCAAA,KAAC,QAAD;QAAM,WAAU;QAAgB,eAAY;kBAA5C;SACE,oCAAA,IAAC,QAAD,EAAA,UAAM,IAAO,CAAA;SACb,oCAAA,IAAC,QAAD,EAAA,UAAM,IAAO,CAAA;SACb,oCAAA,IAAC,QAAD,EAAA,UAAM,IAAO,CAAA;QACT;SACL;;MAEJ,CAAC,QAAQ,QAAQ,SAAS,GAAG,KAC5B,oCAAA,KAAC,KAAD;OAAG,WAAU;OAAwB,MAAK;iBAA1C;QAAmD;QAChC;QACjB,oCAAA,IAAC,uBAAA,eAAD;SAAe,OAAM;mBACnB,oCAAA,IAAC,UAAD;UACE,MAAK;UACL,cAAW;UACX,WAAU;UACV,eAAe,YAAY,SAAS,KAAK,QAAQ,UAAU,UAAU,GAAG,CAAC;oBAEzE,oCAAA,IAAC,gBAAA,QAAD;WAAQ,UAAS;WAAQ,MAAM;UAAK,CAAA;SAC9B,CAAA;QACK,CAAA;OACd;;MAEJ,SAAS,oCAAA,IAAC,KAAD;OAAG,MAAK;iBAAS;MAAS,CAAA;KACjC;;IACL,oCAAA,KAAC,QAAD;KACE,WAAW,UAAU;MACnB,MAAM,eAAe;MACrB,KAAU;KACZ;eAJF;MAMG,YAAY,SAAS,KACpB,oCAAA,IAAC,OAAD;OACE,WAAU;OACV,MAAK;OACL,IAAG;OACH,cAAW;iBAEV,YAAY,KAAK,UAAU,UAC1B,oCAAA,IAAC,uBAAA,eAAD;QAAiC,OAAO,WAAW,SAAS,QAAQ,IAAI,SAAS;kBAC/E,oCAAA,KAAC,UAAD;SACE,MAAK;SACL,MAAK;SACL,IAAI,oBAAoB;SACxB,iBAAe,UAAU,kBAAkB,YAAY;SACvD,cAAc,UAAU,MAAM,eAAe;SAC7C,eAAe,iBAAiB,KAAK;mBANvC,CAQE,oCAAA,KAAC,QAAD,EAAA,UAAA,CAAM,KAAE,SAAS,OAAc,EAAA,CAAA,GAC/B,oCAAA,IAAC,QAAD,EAAA,UAAO,SAAS,MAAY,CAAA,CACtB;;OACK,GAZK,SAAS,EAYd,CAChB;MACE,CAAA;MAEP,oCAAA,IAAC,oBAAA,kBAAD;OACE,SAAS,SAAS,cAAc,QAAQ,YAAY,UAAU,KAAA;OAC9D,uBAAuB,WAAW,KAAA,CAAS;OAC3C,SAAS;MACV,CAAA;MACD,oCAAA,IAAC,4BAAA,mBAAD;OACE,WAAW,QAAQ;OACnB,YAAY;OACZ,UAAU;OACV,UAAU;MACX,CAAA;MACD,oCAAA,IAAC,YAAD;OACE,KAAK;OACL,iBAAe,YAAY,SAAS,sBAAsB,KAAA;OAC1D,iBAAe,YAAY,SAAS;OACpC,yBACE,YAAY,SAAS,oBAAoB,kBAAkB,YAAY,WAAW,KAAA;OAEpF,WAAA;OACA,cAAW;OACX,aAAY;OACZ,YAAY,UAAU;QACpB,IAAI,MAAM,YAAY,eAAe,MAAM,YAAY,KAAK;QAC5D,IAAI,YAAY,UAAU,CAAC,MAAM,UAAU;SACzC,IAAI,MAAM,QAAQ,eAAe,MAAM,QAAQ,WAAW;UACxD,MAAM,eAAe;UACrB,oBACG,WACE,SAAS,MAAM,QAAQ,cAAc,IAAI,YAAY,SAAS,MAAM,YAAY,MACrF;UACA;SACF;SACA,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,OAAO;UAChD,MAAM,eAAe;UACrB,iBAAiB,kBAAkB,YAAY,MAAM;UACrD;SACF;QACF;QACA,IACE,MAAM,QAAQ,WACd,CAAC,MAAM,YACP,CAAC,MAAM,YAAY,eACnB,MAAM,YAAY,KAClB;SACA,MAAM,eAAe;SACrB,IAAI,CAAC,MAAM,KAAU;QACvB;OACF;OACA,OAAO;OACP,WAAW,UAAU;QACnB,SAAS,MAAM,OAAO,KAAK;QAC3B,mBAAmB,CAAC;QACpB,kBAAkB,KAAA,CAAS;OAC7B;OACA,UAAU;MACX,CAAA;MACD,oCAAA,KAAC,OAAD;OAAK,WAAU;iBAAf,CACE,oCAAA,IAAC,QAAD,EAAA,UAAM,0CAA6C,CAAA,GAClD,OACC,oCAAA,KAAC,UAAD;QACE,MAAK;QACL,cAAW;QACX,UAAU,QAAQ,SAAS,GAAG;QAC9B,SAAS;kBAJX,CAME,oCAAA,IAAC,gBAAA,QAAD;SAAQ,UAAS;SAAO,MAAM;QAAK,CAAA,GAAC,OAC9B;YAER,oCAAA,IAAC,UAAD;QAAQ,MAAK;QAAS,UAAU,CAAC,MAAM,KAAK;QAAG,cAAW;kBACxD,oCAAA,IAAC,gBAAA,QAAD;SAAQ,UAAS;SAAO,MAAM;QAAK,CAAA;OAC7B,CAAA,CAEP;;KACD;;GACD;;CAET,EAAA,CAAA;AAEN,CAAC;AAED,SAAgB,YAAY,oBAAmC,qBAAiC;CAC9F,MAAM,YAAY,SAAS,cAAc,KAAK;CAC9C,UAAU,QAAQ,kBAAkB;CACpC,SAAS,KAAK,OAAO,SAAS;CAC9B,IAAI,UAAU;CACd,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,MAAM,4BAA4B;EAChC,MAAM,WAAW,iBAAiB;EAClC,MAAM,UAAU,QAAQ,UAAU,cAAc,kCAAkC,KAAK,SAAS,cAAc,GAAG;EACjH,MAAM,QAAQ,UAAU,WAAW;EACnC,IAAI,iBAAiB,cAAc,gBAAgB,OAAO,cAAc,cAAc;EACtF,iBAAiB,cAAc,QAAQ,CAAC,EAAE,aAAa,cAAc,UAAU,yBAAyB,KAAK;CAC/G;CACA,MAAM,uBAAuB;EAC3B,gBAAgB,WAAW;EAC3B,iBAAiB,KAAA;EACjB,IAAI,cAAc,mCAAA,QAAS,uBAAuB,YAAY;EAC9D,eAAe,KAAA;EACf,gBAAgB,KAAA;EAChB,iBAAiB,OAAO;EACxB,kBAAkB,KAAA;CACpB;CACA,MAAM,cAAc,6BAAA,mBAAmB,oBAAwC;CAC/E,MAAM,kBAAkB;EACtB,MAAM,WACJ,YAAY,WACZ,kBAAkB,KAClB,mBAAA,SAAS,QAAQ,cAAc,IAAI,KACnC,SAAS,cAAc,yCAAuC;EAChE,IAAI,CAAC,UAAU;GACb,eAAe;GACf;EACF;EACA,IAAI,iBAAiB,eAAe,gBAAgB,uBAAuB,UAAU;GACnF,oBAAoB;GACpB;EACF;EACA,eAAe;EACf,kBAAkB,SAAS,cAAc,KAAK;EAC9C,gBAAgB,YAAY;EAC5B,MAAM,iBAAiB,SAAS,cAAc,QAAQ;EACtD,eAAe,OAAO;EACtB,eAAe,aAAa,cAAc,mBAAmB;EAC7D,eAAe,KAAK;EACpB,eAAe,SAAS,cAAc,MAAM;EAC5C,aAAa,aAAa,eAAe,MAAM;EAC/C,gBAAgB,SAAS,cAAc,MAAM;EAC7C,eAAe,OAAO,cAAc,aAAa;EACjD,eAAe,gBAAgB,OAAO,cAAc,IAAI,MAAM,eAAe,CAAC;EAC9E,gBAAgB,OAAO,cAAc;EACrC,SAAS,OAAO,eAAe;EAC/B,oBAAoB;EACpB,IAAI,OAAO,mBAAmB,aAAa;GACzC,iBAAiB,IAAI,eAAe,mBAAmB;GACvD,eAAe,QAAQ,QAAQ;EACjC;EACA,mCAAA,QAAS,OACP,oCAAA,KAAA,oBAAA,UAAA,EAAA,UAAA,CACE,oCAAA,IAAC,gBAAA,QAAD;GAAQ,UAAS;GAAe,MAAM;EAAK,CAAA,GAC3C,oCAAA,IAAC,mBAAA,SAAS,UAAU,SAApB;GAA4B,UAAS;aAA2B;EAEpC,CAAA,CAC5B,EAAA,CAAA,GACF,YACF;CACF;CACA,MAAM,WAAW,IAAI,iBAAiB,SAAS;CAC/C,MAAM,OAAO,8BAAA,cAAc;EACzB,IAAI,YAAY,WAAW,CAAC,SAAS;GACnC,SAAS,QAAQ,SAAS,MAAM;IAAE,WAAW;IAAM,SAAS;GAAK,CAAC;GAClE,UAAU;GACV,mCAAA,QAAS,OAAO,oCAAA,IAAC,QAAD,EAA2B,kBAAoB,CAAA,GAAG,SAAS;EAC7E,OAAO,IAAI,CAAC,YAAY,WAAW,SAAS;GAC1C,SAAS,WAAW;GACpB,mCAAA,QAAS,uBAAuB,SAAS;GACzC,UAAU;EACZ;EACA,UAAU;CACZ,CAAC;CACD,aAAa;EACX,KAAK;EACL,SAAS,WAAW;EACpB,eAAe;EACf,mCAAA,QAAS,uBAAuB,SAAS;EACzC,UAAU,OAAO;CACnB;AACF"}
1
+ {"version":3,"file":"ai.js","names":[],"sources":["../../src/renderer/ai.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { ipcRenderer } from \"electron\";\nimport { autorun } from \"mobx\";\nimport { observer } from \"mobx-react\";\nimport { type CSSProperties, useEffect, useRef, useState } from \"react\";\nimport ReactDOM from \"react-dom\";\nimport { AI_CHAT_CHANNEL, AI_READ_ACTIVITY_CHANNEL, type AiReadActivity } from \"../common/ai\";\nimport { AI_CANCEL_CHANNEL, attachedAiContext, normalizeAiReferences } from \"../common/ai-extras\";\nimport { expandAiShortcut } from \"../common/ai-shortcuts\";\nimport { type AiMessage, AiPreferencesStore } from \"../common/store/ai-preferences-store\";\nimport { AiShortcutsStore } from \"../common/store/ai-shortcuts-store\";\nimport { hasAiContextMutations } from \"./ai-context-mutations\";\nimport { AiCopyAnswer } from \"./ai-copy-answer\";\nimport {\n AI_DIAGNOSTIC_EVENT,\n type DiagnosticFinding,\n diagnosticQuestion,\n sanitizeDiagnosticFinding,\n} from \"./ai-diagnostic-handoff\";\nimport { AiContextPreview, AiResourceReferences } from \"./ai-extras\";\nimport { AiIcon, AiPinIcon } from \"./ai-icon\";\nimport { isPowerLogsWorkspace, POWER_LOGS_SQL_DRAFT_PROMPT } from \"./ai-logs-sql\";\nimport { AiMessageContent } from \"./ai-message\";\nimport { AiProviderIcon } from \"./ai-provider-icon\";\nimport { AiResizeHandle, clampAiPanelWidth, DEFAULT_AI_PANEL_WIDTH } from \"./ai-resize\";\nimport { AiStarterPrompts } from \"./ai-shortcuts\";\nimport {\n type AiTerminalAttachment,\n AiTerminalContext,\n activeAiTerminal,\n captureAiTerminal,\n} from \"./ai-terminal-context\";\nimport { NativeTooltip } from \"./native-tooltip\";\n\nexport interface AiScreenContext {\n clusterId?: string;\n screen?: string;\n resource?: { kind?: string; namespace?: string; name?: string };\n}\n\nexport function readAiContext(): AiScreenContext {\n const clusterId = Renderer.Catalog.activeCluster.get()?.metadata.uid;\n const screen = window.location.pathname;\n const details = new URLSearchParams(window.location.search).get(\"kube-details\");\n const match =\n details?.match(/^\\/api(?:\\/v\\d+)?\\/namespaces\\/([^/]+)\\/([^/]+)\\/([^/]+)$/) ??\n details?.match(/^\\/apis\\/[^/]+\\/[^/]+\\/namespaces\\/([^/]+)\\/([^/]+)\\/([^/]+)$/);\n const clusterResource =\n details?.match(/^\\/api\\/[^/]+\\/([^/]+)\\/([^/]+)$/) ?? details?.match(/^\\/apis\\/[^/]+\\/[^/]+\\/([^/]+)\\/([^/]+)$/);\n const resource = match\n ? { namespace: match[1], kind: match[2], name: match[3] }\n : clusterResource\n ? { kind: clusterResource[1], name: clusterResource[2] }\n : undefined;\n return { clusterId, screen, ...(resource ? { resource } : {}) };\n}\n\nexport function isAiClusterDocument(): boolean {\n return window.top !== window && Boolean(Renderer.Catalog.activeCluster.get());\n}\n\nexport function aiLauncherBottom(): number {\n const dock = document.querySelector<HTMLElement>(\".Dock\");\n if (!dock) return 16;\n const rect = dock.getBoundingClientRect();\n const style = window.getComputedStyle(dock);\n if (\n dock.hidden ||\n style.display === \"none\" ||\n style.visibility === \"hidden\" ||\n rect.width <= 0 ||\n rect.height <= 0 ||\n rect.top <= 0 ||\n rect.top >= window.innerHeight\n )\n return 16;\n return Math.max(16, window.innerHeight - rect.top + 16);\n}\n\nexport function aiLauncherLeft(): number {\n const sidebar = document.querySelector<HTMLElement>('[data-testid=\"cluster-sidebar\"], .Sidebar');\n const dock = document.querySelector<HTMLElement>(\".Dock\");\n let contentLeft = 0;\n for (const [element, edge] of [\n [sidebar, \"right\"],\n [dock, \"left\"],\n ] as const) {\n if (!element || element.hidden) continue;\n const style = window.getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n if (style.display === \"none\" || style.visibility === \"hidden\" || rect.width <= 0) continue;\n const value = rect[edge];\n if (Number.isFinite(value) && value >= 0 && value < window.innerWidth - 80)\n contentLeft = Math.max(contentLeft, value);\n }\n return contentLeft + 16;\n}\n\nexport function hasAiResourceDetails(): boolean {\n if (new URLSearchParams(window.location.search).get(\"kube-details\")) return true;\n return Array.from(\n document.querySelectorAll<HTMLElement>(\".Drawer.KubeObjectDetails, .Drawer.ReleaseDetails, .DetailsDrawer\"),\n ).some((element) => {\n const style = window.getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n return (\n !element.hidden && style.display !== \"none\" && style.visibility !== \"hidden\" && rect.width > 0 && rect.height > 0\n );\n });\n}\n\nexport function hasAiOverlay(): boolean {\n return Array.from(document.querySelectorAll<HTMLElement>('[role=\"dialog\"], dialog[open], .Dialog')).some(\n (element) => {\n const style = window.getComputedStyle(element);\n return !element.hidden && style.display !== \"none\" && style.visibility !== \"hidden\";\n },\n );\n}\n\nconst styles = `\n@keyframes power-ai-spin { to { transform: rotate(360deg); } }\n@keyframes power-ai-dot { 0%, 80%, 100% { opacity: .25; } 40% { opacity: 1; } }\nbody:has(.AddRemoveButtons .remove-button:not([data-freelens-power-read-only])) .power-ai-launcher { display: none; }\n.power-ai-read-activity > span { display: inline-flex; align-items: center; gap: 4px; }\n.power-ai-read-activity [data-status=\"reading\"] .Icon { animation: power-ai-spin 1.2s linear infinite; }\n.power-ai-thinking { margin: 12px 16px 18px; line-height: 1.5; color: var(--textColorSecondary); }\n.power-ai-dots > span { animation: power-ai-dot 1.3s ease-in-out infinite; }\n.power-ai-dots > span:nth-child(2) { animation-delay: .15s; }\n.power-ai-dots > span:nth-child(3) { animation-delay: .3s; }\n@media (prefers-reduced-motion: reduce) { .power-ai-read-activity [data-status=\"reading\"] .Icon, .power-ai-dots > span { animation: none; } }\n@keyframes power-ai-enter { from { transform: translateX(100%); } to { transform: translateX(0); } }\n:root .power-ai-launcher { position: fixed; bottom: 16px; left: auto; right: 16px; z-index: 100; display: inline-flex; align-items: center; gap: 6px; min-width: 0; min-height: 0; height: 34px; border: 1px solid var(--primary, #5896ff); border-radius: 24px; padding: 0 13px; background: var(--contentColor, #242424); color: var(--textColorAccent); box-shadow: 0 3px 12px #0003; font: inherit; font-size: 12px; font-weight: 500; line-height: 1; cursor: pointer; transition: opacity 180ms ease, background-color 140ms ease, box-shadow 140ms ease, transform 180ms ease; }\n.power-ai-overview-actions { position: relative; z-index: 5; height: 0; min-height: 0; flex: 0 0 0; pointer-events: none; }\n.power-ai-overview-actions + [data-testid=\"cluster-overview-page\"] [data-monitoring-summaries] { --power-monitoring-summary-top: 56px; }\n.power-ai-overview-actions button { transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease, box-shadow 160ms ease; position: absolute; top: 12px; right: 12px; pointer-events: auto; box-shadow: 0 2px 8px #0002; display: inline-flex; flex: 0 0 auto; width: auto; align-items: center; gap: 6px; min-height: 32px; padding: 6px 12px; font: inherit; font-size: 12px; border: 1px solid var(--borderFaintColor); border-radius: 10px; color: var(--textColorPrimary); background: var(--contentColor); cursor: pointer; }\n.power-ai-overview-actions button:hover { border-color: var(--primary); color: var(--textColorAccent); background: var(--contentColor); }\n.power-ai-overview-actions button:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-launcher.power-ai-launcher-hidden { opacity: 0; transform: translateY(8px); pointer-events: none; }\n.power-ai-launcher .Icon { color: inherit; }\n.power-ai-launcher:hover { background: color-mix(in srgb, var(--primary, #5896ff) 12%, var(--contentColor, #242424)); box-shadow: 0 4px 12px #0003; transform: translateY(-1px); }\n.power-ai-launcher:active { transform: translateY(0); box-shadow: 0 2px 6px #0002; }\n@media (prefers-reduced-motion: reduce) { :root .power-ai-launcher { transition: none; } .power-ai-launcher:hover, .power-ai-launcher:active { transform: none; } }\n.power-ai-launcher:focus-visible { outline: 2px solid var(--primary, #5896ff); outline-offset: 3px; }\n.power-ai-panel { position: fixed; right: 0; top: 0; bottom: 0; width: min(560px, 100vw); z-index: 10001; display: flex; flex-direction: column; background: var(--contentColor, #242424); color: var(--textColorAccent, white); animation: power-ai-enter 160ms ease-out; border-left: 1px solid var(--borderFaintColor); box-shadow: -4px 0 24px #0004; }\n.power-ai-resize-handle { position: absolute; left: -4px; top: 0; bottom: 0; width: 8px; z-index: 2; cursor: col-resize; touch-action: none; }\n.power-ai-resize-handle:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }\n.power-ai-panel header { padding: 16px; display: flex; gap: 10px; flex-shrink: 0; }\n.power-ai-panel header { border-bottom: 1px solid var(--borderFaintColor); justify-content: space-between; align-items: center; }\n.power-ai-messages { overflow: auto; flex: 1; min-height: 0; padding: 24px 16px; font-size: var(--power-ai-font-size, 14px); line-height: 1.65; overscroll-behavior: contain; }\n.power-ai-message { overflow-wrap: anywhere; padding: 14px 16px; margin-bottom: 20px; color: var(--textColorAccent); border: 1px solid var(--borderFaintColor); border-radius: 8px; }\n.power-ai-panel button { padding: 7px 10px; border: 1px solid var(--borderFaintColor); border-radius: 8px; background: var(--contentColor); color: var(--textColorPrimary); cursor: pointer; }\n:root .power-ai-panel header button:is(.power-ai-close, .power-ai-pin) { width: 30px; height: 30px; padding: 0; display: inline-flex; align-items: center; justify-content: center; border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel header button:is(.power-ai-close, .power-ai-pin):not(:disabled):not(.disabled):hover { color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent); }\n:root .power-ai-panel header button:is(.power-ai-close, .power-ai-pin):focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n:root .power-ai-panel button.power-ai-copy-answer { width: 24px; height: 24px; padding: 0; margin-left: auto; flex-shrink: 0; justify-content: center; border: 0; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel button.power-ai-copy-answer:not(:disabled):not(.disabled):hover { color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent); }\n:root .power-ai-panel button.power-ai-copy-answer:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-cancellation { display: flex; align-items: center; gap: 6px; }\n:root .power-ai-panel button.power-ai-dismiss { width: 24px; height: 24px; padding: 0; justify-content: center; border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel button.power-ai-dismiss:hover { color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent); }\n:root .power-ai-panel button.power-ai-dismiss:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-panel button:disabled { opacity: 0.5; cursor: default; }\n .power-ai-panel textarea { display: block; width: 100%; box-sizing: border-box; min-width: 0; min-height: 64px; max-height: 180px; field-sizing: content; padding: 12px 16px 6px; border: 0; border-radius: 12px; background: transparent; color: var(--textColorAccent); font: inherit; font-size: var(--power-ai-font-size, 14px); line-height: 1.5; resize: none; }\n.power-ai-panel textarea::placeholder { color: var(--textColorSecondary); opacity: 1; }\n.power-ai-panel textarea:focus { outline: none; }\n.power-ai-composer-footer { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 4px 10px 10px 16px; }\n.power-ai-composer-footer > span { color: var(--textColorSecondary); font-size: 11px; line-height: 1.5; }\n:root .power-ai-panel form button[type=\"submit\"] { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 34px; width: 34px; height: 34px; padding: 0; border-radius: 10px; }\n:root .power-ai-panel form button[type=\"submit\"]:not(:disabled):not(.disabled) { background-color: var(--primary); border-color: var(--primary); color: white; }\n:root .power-ai-panel form button[type=\"submit\"]:not(:disabled):not(.disabled):hover { background-color: color-mix(in srgb, var(--primary) 88%, white 12%); border-color: color-mix(in srgb, var(--primary) 88%, white 12%); color: white; }\n:root .power-ai-panel form button[type=\"submit\"]:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }\n:root .power-ai-panel form button[type=\"submit\"]:disabled { background-color: var(--contentColor); border-color: var(--borderFaintColor); color: var(--textColorSecondary); }\n.power-ai-message-user { border-color: color-mix(in srgb, var(--primary) 28%, var(--borderFaintColor)); background: color-mix(in srgb, var(--primary) 7%, var(--mainBackground)); }\n.power-ai-context { padding: 10px 20px; line-height: 1.5; border-bottom: 1px solid var(--borderFaintColor); font-size: 12px; color: var(--textColorSecondary); overflow-wrap: anywhere; }\n.power-ai-attached-resource { display: flex; align-items: center; justify-content: space-between; gap: 8px; }\n.power-ai-title, .power-ai-panel button { display: inline-flex; align-items: center; gap: 6px; }\n.power-ai-title { margin-right: auto; white-space: nowrap; color: var(--textColorAccent); }\n.power-ai-brand { display: inline-flex; align-items: center; gap: 6px; color: var(--primary); }\n.power-ai-brand .Icon { color: inherit; }\n:root .power-ai-panel header button.power-ai-pin[aria-pressed=\"true\"] { color: var(--primary); }\n.power-ai-panel header > button { flex-shrink: 0; }\n.power-ai-panel form { position: relative; flex-shrink: 0; margin: 0 16px 16px; border: 1px solid var(--borderFaintColor); border-radius: 12px; background: var(--mainBackground); transition: border-color 160ms ease; }\n.power-ai-panel form > .power-ai-context-preview { padding: 8px 48px 4px 16px !important; min-height: 34px; margin: 0; box-sizing: border-box; }\n.power-ai-context-preview pre { white-space: pre-wrap; overflow-wrap: anywhere; overflow: auto; }\n.power-ai-finding-content pre { max-height: 140px; }\n.power-ai-context-content pre { max-height: 160px; }\n.power-ai-context-preview .power-log-json { --json-key:#9cdcfe; --json-string:#ce9178; --json-number:#b5cea8; --json-literal:#c586c0; }\n.theme-light .power-ai-context-preview .power-log-json { --json-key:#005a9e; --json-string:#9e2b1a; --json-number:#17642d; --json-literal:#7a288c; }\n.power-ai-context-preview .power-log-json [data-token=key] { color:var(--json-key); }\n.power-ai-context-preview .power-log-json [data-token=string] { color:var(--json-string); }\n.power-ai-context-preview .power-log-json [data-token=number] { color:var(--json-number); }\n.power-ai-context-preview .power-log-json [data-token=literal] { color:var(--json-literal); }\n.power-ai-context-finding { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 4px; min-width: 0; }\n.power-ai-context-finding > .Icon { flex-shrink: 0; margin-top: 7px; }\n.power-ai-context-finding > details { flex: 1; min-width: 0; }\n.power-ai-context-finding summary { padding: 6px 0; min-height: 28px; box-sizing: border-box; cursor: pointer; overflow-wrap: anywhere; }\n:root .power-ai-panel button.power-ai-remove-context { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; min-height: 28px; flex-shrink: 0; padding: 0; border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); }\n:root .power-ai-panel button.power-ai-remove-context:hover { background: color-mix(in srgb, var(--primary) 10%, transparent); color: var(--primary); }\n:root .power-ai-panel button.power-ai-remove-context:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n.power-ai-panel form:focus-within { border-color: var(--primary); }\n.power-ai-message > strong { display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 500; color: var(--textColorSecondary); margin-bottom: 10px; }\n.power-ai-message-assistant { border-color: transparent; background: transparent; }\n.power-ai-markdown { line-height: 1.65; font-size: var(--power-ai-font-size, 14px); color: var(--textColorAccent); }\n.power-ai-markdown p { margin: 0 0 14px; white-space: pre-wrap; }\n.power-ai-markdown p:last-child { margin-bottom: 0; }\n.power-ai-markdown ul, .power-ai-markdown ol { padding-left: 24px; margin: 10px 0 16px; }\n.power-ai-markdown ul { list-style: disc; }\n.power-ai-markdown ol { list-style: decimal; }\n.power-ai-markdown li { margin: 5px 0; }\n.power-ai-markdown li > ul, .power-ai-markdown li > ol { margin: 6px 0; }\n.power-ai-markdown li > p { margin-bottom: 6px; }\n.power-ai-markdown :is(h1, h2, h3, h4, h5, h6) { color: var(--textColorAccent); font-weight: 600; line-height: 1.4; margin: 24px 0 12px; }\n.power-ai-markdown :is(h1, h2, h3, h4, h5, h6):first-child { margin-top: 0; }\n.power-ai-markdown h1 { font-size: 1.43em; }\n.power-ai-markdown h2 { font-size: 1.29em; }\n.power-ai-markdown h3 { font-size: 1.14em; }\n.power-ai-markdown :is(h4, h5, h6) { font-size: 1em; }\n.power-ai-markdown blockquote { margin: 16px 0; padding: 4px 14px; border-left: 3px solid var(--borderColor); color: var(--textColorSecondary); }\n.power-ai-markdown blockquote > p:last-child { margin-bottom: 0; }\n.power-ai-markdown table { display: block; max-width: 100%; overflow-x: auto; margin: 16px 0; border-collapse: collapse; font-size: max(10px, calc(var(--power-ai-font-size, 14px) - 1px)); }\n.power-ai-markdown th, .power-ai-markdown td { padding: 9px 12px; border: 1px solid var(--borderFaintColor); text-align: left; }\n.power-ai-markdown th { font-weight: 600; background: color-mix(in srgb, var(--textColorAccent) 5%, transparent); }\n.power-ai-markdown a { color: var(--primary); text-decoration: underline; text-underline-offset: 2px; }\n.power-ai-markdown hr { margin: 20px 0; border: 0; border-top: 1px solid var(--borderFaintColor); }\n.power-ai-markdown code { font-family: var(--font-monospace, monospace); font-size: max(10px, calc(var(--power-ai-font-size, 14px) - 1px)); background: color-mix(in srgb, var(--textColorAccent) 8%, transparent); padding: 1px 4px; border-radius: 4px; }\n.power-ai-code { --sql-string:#e6a28c; --sql-number:#98c78e; --sql-function:#81b9e6; --sql-identifier:var(--textColorPrimary); 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 { color:var(--textColorPrimary); margin: 0; padding: 12px; overflow-x: auto; white-space: pre; }\n.power-ai-code pre code { padding: 0; background: transparent; color:inherit; }\n.theme-light .power-ai-code { --sql-string:#9e2b1a; --sql-number:#17642d; --sql-function:#005a9e; --sql-identifier:#684c9b; }\n.power-ai-code [data-sql-token=keyword] { color:var(--primary); }\n.power-ai-code [data-sql-token=function] { color:var(--sql-function); }\n.power-ai-code [data-sql-token=string] { color:var(--sql-string); }\n.power-ai-code [data-sql-token=identifier] { color:var(--sql-identifier); }\n.power-ai-code [data-sql-token=number] { color:var(--sql-number); }\n.power-ai-code [data-sql-token=comment] { color:var(--textColorSecondary); }\n.power-ai-code-hint, .power-ai-code-feedback:not(:empty) { padding: 0 12px 10px; color: var(--textColorSecondary); font-size: 11px; }\n.power-ai-autocomplete { position: absolute; bottom: calc(100% + 8px); left: 0; right: 0; max-height: 240px; overflow-y: auto; padding: 6px; border: 1px solid var(--borderColor); border-radius: 10px; background: var(--contentColor); box-shadow: 0 4px 16px #0003; }\n.power-ai-autocomplete button { display: flex; width: 100%; justify-content: space-between; gap: 12px; border: 0; text-align: left; }\n.power-ai-autocomplete button[aria-selected=\"true\"] { background: color-mix(in srgb, var(--primary) 14%, var(--contentColor)); color: var(--textColorAccent); }\n.power-ai-autocomplete button > span:last-child { color: var(--textColorSecondary); font-size: 12px; }\n@media (prefers-reduced-motion: reduce) { .power-ai-panel { animation: none; } }\n`;\n\nconst AiChat = observer(({ isClusterDocument }: { isClusterDocument: () => boolean }) => {\n const preferences = AiPreferencesStore.getInstanceOrCreate<AiPreferencesStore>();\n const [open, setOpen] = useState(false);\n const [pinned, setPinned] = useState(false);\n const [launcherBottom, setLauncherBottom] = useState(aiLauncherBottom);\n const [launcherLeft, setLauncherLeft] = useState(aiLauncherLeft);\n const [resourceDetailsOpen, setResourceDetailsOpen] = useState(hasAiResourceDetails);\n const [viewportWidth, setViewportWidth] = useState(window.innerWidth);\n const [launcherHidden, setLauncherHidden] = useState(false);\n const [draft, setDraft] = useState(\"\");\n const [finding, setFinding] = useState<DiagnosticFinding>();\n const [resourceAttachment, setResourceAttachment] = useState<AiScreenContext>();\n const dismissedResource = useRef<string>();\n const panelOpen = useRef(open);\n panelOpen.current = open;\n const captureScreenResource = (current = readAiContext()) => {\n if (\n current.clusterId &&\n current.resource &&\n dismissedResource.current !== JSON.stringify({ clusterId: current.clusterId, resource: current.resource })\n )\n setResourceAttachment(current);\n };\n const attachScreenResource = () => {\n dismissedResource.current = undefined;\n captureScreenResource();\n };\n const removeResource = () => {\n const current = resourceAttachment ?? readAiContext();\n dismissedResource.current = JSON.stringify({ clusterId: current.clusterId, resource: current.resource });\n setResourceAttachment(undefined);\n };\n const [terminalAttachment, setTerminalAttachment] = useState<AiTerminalAttachment>();\n const [suggestionIndex, setSuggestionIndex] = useState(0);\n const [dismissedDraft, setDismissedDraft] = useState<string>();\n const suggestions =\n /^\\/[^\\s]*$/.test(draft) && dismissedDraft !== draft\n ? AiShortcutsStore.getInstanceOrCreate<AiShortcutsStore>().shortcuts.filter((shortcut) =>\n `${shortcut.command} ${shortcut.label}`.toLowerCase().includes(draft.slice(1).toLowerCase()),\n )\n : [];\n const dismissSuggestions = useRef<() => boolean>(() => false);\n dismissSuggestions.current = () => {\n if (!suggestions.length) return false;\n setDismissedDraft(draft);\n return true;\n };\n const following = useRef(true);\n const composer = useRef<HTMLTextAreaElement>(null);\n const selectSuggestion = (index: number) => {\n const shortcut = suggestions[index];\n if (!shortcut) return;\n setDraft(`/${shortcut.command} `);\n setSuggestionIndex(0);\n composer.current?.focus();\n };\n const [context, setContext] = useState(readAiContext);\n useEffect(() => {\n if (open && !finding && !terminalAttachment) window.dispatchEvent(new Event(\"power-ai-request-screen-context\"));\n }, [open]);\n const [pending, setPending] = useState<string[]>([]);\n const [error, setError] = useState(\"\");\n const [stopped, setStopped] = useState<string[]>([]);\n const activeRequests = useRef(new Map<string, string>());\n const [activity, setActivity] = useState<{\n key: string;\n reads: { method: AiReadActivity[\"method\"]; status: \"reading\" | \"ok\" | \"unavailable\" }[];\n }>({ key: \"\", reads: [] });\n const clusterReview = useRef<() => void>(() => {});\n const messagesElement = useRef<HTMLDivElement>(null);\n const [coveredByOverlay, setCoveredByOverlay] = useState(hasAiOverlay);\n useEffect(() => {\n let observedElements: Element[] = [];\n const resizeObserver =\n typeof ResizeObserver === \"undefined\"\n ? undefined\n : new ResizeObserver(() => {\n setLauncherBottom(aiLauncherBottom());\n setLauncherLeft(aiLauncherLeft());\n });\n const updateDock = () => {\n setViewportWidth(window.innerWidth);\n setLauncherBottom(aiLauncherBottom());\n setLauncherLeft(aiLauncherLeft());\n const elements = [\n document.querySelector(\".Dock\"),\n document.querySelector('[data-testid=\"cluster-sidebar\"], .Sidebar'),\n ].filter((element): element is Element => !!element);\n if (\n elements.length !== observedElements.length ||\n elements.some((element, index) => element !== observedElements[index])\n ) {\n resizeObserver?.disconnect();\n observedElements = elements;\n for (const element of elements) resizeObserver?.observe(element);\n }\n };\n const update = () => {\n updateDock();\n const nextContext = readAiContext();\n setContext(nextContext);\n if (panelOpen.current) captureScreenResource(nextContext);\n setResourceAttachment((current) => (current?.clusterId === nextContext.clusterId ? current : undefined));\n setFinding((current) => (current && current.clusterId !== nextContext.clusterId ? undefined : current));\n setResourceDetailsOpen(hasAiResourceDetails());\n setCoveredByOverlay(hasAiOverlay());\n };\n const onActivity = (_event: unknown, value: unknown) => {\n if (!value || typeof value !== \"object\") return;\n const entry = value as { requestId?: string; method?: string; status?: string };\n const requestKey = activeRequests.current.get(entry.requestId ?? \"\");\n if (\n !requestKey ||\n requestKey !== readAiContext().clusterId ||\n ![\"pods\", \"nodes\", \"resources\", \"logs\"].includes(entry.method ?? \"\") ||\n ![\"reading\", \"ok\", \"unavailable\"].includes(entry.status ?? \"\")\n )\n return;\n const read = {\n method: entry.method as AiReadActivity[\"method\"],\n status: entry.status as \"reading\" | \"ok\" | \"unavailable\",\n };\n setActivity((previous) => ({\n key: requestKey,\n reads: [\n ...(previous.key === requestKey ? previous.reads.filter((item) => item.method !== read.method) : []),\n read,\n ],\n }));\n };\n ipcRenderer.on(AI_READ_ACTIVITY_CHANNEL, onActivity);\n window.addEventListener(\"resize\", updateDock);\n window.addEventListener(\"popstate\", update);\n update();\n const timer = window.setInterval(update, 500);\n const observer = new MutationObserver((mutations) => {\n if (hasAiContextMutations(mutations)) update();\n });\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"class\", \"style\", \"hidden\", \"open\"],\n });\n const onDiagnostic = (event: Event) => {\n const next = sanitizeDiagnosticFinding((event as CustomEvent).detail);\n if (!next || !preferences.enabled || !isClusterDocument() || next.clusterId !== readAiContext().clusterId) return;\n update();\n setFinding(next);\n setDraft(\n (previous) =>\n previous ||\n (next.source === \"relationships\" ||\n next.source === \"diagnostics\" ||\n preferences.conversations[next.clusterId]?.length\n ? \"\"\n : \"Explain this finding and suggest the next read-only checks.\"),\n );\n setOpen(true);\n requestAnimationFrame(() => composer.current?.focus());\n };\n window.addEventListener(AI_DIAGNOSTIC_EVENT, onDiagnostic);\n window.addEventListener(\"power-ai-open\", updateAndOpen);\n window.addEventListener(\"power-ai-open-only\", openOnly);\n const closePanel = () => setOpen(false);\n window.addEventListener(\"power-ai-close\", closePanel);\n function openOnly() {\n attachScreenResource();\n update();\n setOpen(true);\n }\n function updateAndOpen() {\n openOnly();\n clusterReview.current();\n }\n return () => {\n window.removeEventListener(\"resize\", updateDock);\n window.removeEventListener(\"popstate\", update);\n resizeObserver?.disconnect();\n ipcRenderer.removeListener(AI_READ_ACTIVITY_CHANNEL, onActivity);\n for (const requestId of activeRequests.current.keys()) {\n void ipcRenderer.invoke(AI_CANCEL_CHANNEL, requestId).catch(() => {});\n }\n activeRequests.current.clear();\n window.clearInterval(timer);\n observer.disconnect();\n window.removeEventListener(\"power-ai-open\", updateAndOpen);\n window.removeEventListener(\"power-ai-open-only\", openOnly);\n window.removeEventListener(\"power-ai-close\", closePanel);\n window.removeEventListener(AI_DIAGNOSTIC_EVENT, onDiagnostic);\n };\n }, []);\n useEffect(() => {\n setLauncherHidden(false);\n const onScroll = (event: Event) => {\n const target = event.target;\n if (!(target instanceof HTMLElement) || target.closest('.power-ai-panel, .Sidebar, [role=\"navigation\"], aside'))\n return;\n if (!target.closest('.ItemListLayout, .KubeObjectListLayout, main, [role=\"main\"]')) return;\n if (target.scrollHeight <= target.clientHeight || target.clientHeight <= 0) return;\n setLauncherHidden(target.scrollTop > 0 && target.scrollHeight - target.clientHeight - target.scrollTop <= 16);\n };\n document.addEventListener(\"scroll\", onScroll, true);\n return () => document.removeEventListener(\"scroll\", onScroll, true);\n }, [context.screen]);\n useEffect(() => {\n if (!open) return;\n const onEscape = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\" || hasAiOverlay()) return;\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n if (!dismissSuggestions.current()) setOpen(false);\n };\n window.addEventListener(\"keydown\", onEscape, true);\n return () => window.removeEventListener(\"keydown\", onEscape, true);\n }, [open]);\n useEffect(() => {\n if (!open || pinned) return;\n const onOutsideClick = (event: MouseEvent) => {\n const target = event.target;\n if (\n !(target instanceof Element) ||\n target.closest(\n \".power-ai-panel, .power-ai-launcher, .power-ai-overview-actions, [data-freelens-power-ai-overlay]\",\n )\n )\n return;\n setOpen(false);\n };\n document.addEventListener(\"click\", onOutsideClick, true);\n return () => document.removeEventListener(\"click\", onOutsideClick, true);\n }, [open, pinned]);\n const availablePanelWidth = Math.max(1, viewportWidth - Math.max(0, launcherLeft - 16));\n const panelWidth = clampAiPanelWidth(preferences.chatPanelWidth ?? DEFAULT_AI_PANEL_WIDTH, availablePanelWidth);\n const attachedResource =\n resourceAttachment && resourceAttachment.clusterId === context.clusterId ? resourceAttachment.resource : undefined;\n const previewContext = attachedAiContext({\n clusterId: context.clusterId,\n screen: context.screen,\n ...(finding && finding.clusterId === context.clusterId && finding.resource\n ? { resource: finding.resource }\n : attachedResource\n ? { resource: attachedResource }\n : {}),\n });\n const key = context.clusterId ?? \"global\";\n const messages = preferences.conversations[key] ?? [];\n const busy = pending.includes(key);\n const readActivity = activity.key === key ? activity.reads : [];\n useEffect(() => {\n const element = messagesElement.current;\n if (element && following.current) element.scrollTop = element.scrollHeight;\n }, [messages.length, busy, open, key]);\n useEffect(() => {\n following.current = true;\n const element = messagesElement.current;\n if (element && open) element.scrollTop = element.scrollHeight;\n }, [open, key]);\n useEffect(() => {\n if (!terminalAttachment) return;\n const update = () => {\n if (activeAiTerminal(terminalAttachment.clusterId) !== terminalAttachment.terminalId)\n setTerminalAttachment(undefined);\n };\n update();\n const timer = window.setInterval(update, 500);\n const observer = new MutationObserver(update);\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"class\", \"style\", \"hidden\", \"aria-hidden\", \"data-testid\"],\n });\n return () => {\n window.clearInterval(timer);\n observer.disconnect();\n };\n }, [terminalAttachment, context.clusterId]);\n if (!preferences.enabled || !isClusterDocument() || coveredByOverlay) return null;\n const send = async (starter?: string) => {\n const question = expandAiShortcut(\n (starter ?? draft).trim(),\n AiShortcutsStore.getInstanceOrCreate<AiShortcutsStore>().shortcuts,\n );\n if (!question || busy) return;\n if (question.length > 20_000) {\n setError(\"Message is too long. Please keep it under 20,000 characters.\");\n return;\n }\n const activeFinding = finding?.clusterId === readAiContext().clusterId ? finding : undefined;\n const payloadQuestion = diagnosticQuestion(question, activeFinding);\n if (payloadQuestion.length > 20_000) {\n setError(\"Message and attached finding are too long. Shorten the message or remove the finding.\");\n return;\n }\n const currentContext = readAiContext();\n const requestResource =\n activeFinding?.resource ??\n (resourceAttachment && resourceAttachment.clusterId === currentContext.clusterId\n ? resourceAttachment.resource\n : undefined);\n const requestContext = attachedAiContext({\n clusterId: currentContext.clusterId,\n screen: currentContext.screen,\n ...(requestResource ? { resource: requestResource } : {}),\n });\n if ((requestContext.clusterId ?? \"global\") !== key) {\n setContext(requestContext);\n return;\n }\n const terminalSnapshot =\n terminalAttachment?.clusterId === requestContext.clusterId\n ? captureAiTerminal(requestContext.clusterId, terminalAttachment?.terminalId)\n : undefined;\n if (terminalAttachment && !terminalSnapshot) {\n setTerminalAttachment(undefined);\n setError(\"The attached terminal changed or is unavailable. Attach it again before sending.\");\n return;\n }\n setTerminalAttachment(undefined);\n setFinding(undefined);\n following.current = true;\n const next: AiMessage[] = [...messages, { role: \"user\", text: question }];\n preferences.setMessages(key, next);\n setDraft(\"\");\n setError(\"\");\n setStopped((keys) => keys.filter((entry) => entry !== key));\n setActivity({ key, reads: [] });\n setPending((keys) => [...keys, key]);\n const provider = preferences.provider;\n const requestId = crypto.randomUUID();\n activeRequests.current.set(requestId, key);\n try {\n const response = await ipcRenderer.invoke(AI_CHAT_CHANNEL, {\n requestId,\n messages: [...next.slice(0, -1), { role: \"user\" as const, text: payloadQuestion }]\n .slice(-80)\n .reduceRight<AiMessage[]>((tail, message) => {\n if (tail.reduce((length, item) => length + item.text.length, 0) + message.text.length < 100_000)\n tail.unshift({ role: message.role, text: message.text });\n return tail;\n }, []),\n context: requestContext,\n ...(terminalSnapshot ? { terminalSnapshot } : {}),\n systemPrompt: [\n preferences.systemPrompt,\n requestContext.clusterId ? preferences.clusterPrompt : \"\",\n isPowerLogsWorkspace() ? POWER_LOGS_SQL_DRAFT_PROMPT : \"\",\n ]\n .filter(Boolean)\n .join(\"\\n\\n\"),\n model: preferences.model,\n speed: preferences.speed,\n reasoningEffort: preferences.reasoningEffort,\n });\n if (activeRequests.current.get(requestId) !== key) return;\n if (!response || typeof response.text !== \"string\") throw new Error(\"Invalid response\");\n setActivity({\n key,\n reads: Array.isArray(response.reads)\n ? response.reads\n .filter(\n (read: AiReadActivity) =>\n [\"pods\", \"nodes\", \"resources\", \"logs\"].includes(read?.method) &&\n [\"ok\", \"unavailable\"].includes(read?.status),\n )\n .slice(0, 6)\n : [],\n });\n preferences.setMessages(key, [\n ...next,\n {\n role: \"assistant\",\n text: response.text,\n provider: response.provider === \"claude\" ? \"claude\" : provider,\n references: normalizeAiReferences(response.references),\n },\n ]);\n } catch (failure) {\n if (activeRequests.current.get(requestId) !== key) return;\n const code = String(failure).match(/FREELENS_AI_([A-Z_]+)/)?.[1];\n const messages: Record<string, string> = {\n READ_LIMIT: \"The assistant reached the read limit. Try a more specific question.\",\n TIMEOUT: \"The request timed out. Please try again.\",\n INVALID_REPLY: \"The assistant returned an incomplete reply. Please try again.\",\n CLI_FAILURE: \"The selected CLI request failed. Check your model access or try again.\",\n CANCELLED: \"The request was canceled.\",\n UNSAFE_POLICY:\n \"Claude managed policy cannot be safely isolated. Use Codex or ask your administrator to disable managed hooks and command helpers.\",\n INPUT_LIMIT: \"The request is too large. Start a new chat or shorten the message.\",\n };\n setError(\n (code && messages[code]) ||\n \"Unable to complete the request. Check that the selected CLI is installed and signed in, then try again.\",\n );\n } finally {\n activeRequests.current.delete(requestId);\n setPending((keys) => keys.filter((entry) => entry !== key));\n }\n };\n const stopResponse = () => {\n const requestId = [...activeRequests.current].find(([, requestKey]) => requestKey === key)?.[0];\n if (!requestId) return;\n activeRequests.current.delete(requestId);\n setStopped((keys) => [...keys.filter((entry) => entry !== key), key]);\n setActivity({ key, reads: [] });\n setError(\"\");\n void ipcRenderer.invoke(AI_CANCEL_CHANNEL, requestId).catch(() => {});\n };\n clusterReview.current = () => {\n const currentKey = readAiContext().clusterId;\n if (!currentKey || currentKey !== key || preferences.conversations[currentKey]?.length) return;\n void send(\n preferences.clusterPrompt.trim() ||\n \"Review this cluster using read-only queries and summarize its health and useful next steps.\",\n );\n };\n return (\n <>\n <style>{styles}</style>\n {!open && (\n <NativeTooltip title=\"Open AI assistant\">\n <button\n type=\"button\"\n className={`power-ai-launcher${launcherHidden ? \" power-ai-launcher-hidden\" : \"\"}`}\n aria-hidden={launcherHidden || undefined}\n tabIndex={launcherHidden ? -1 : 0}\n style={{\n bottom: launcherBottom,\n left: resourceDetailsOpen ? launcherLeft : \"auto\",\n right: resourceDetailsOpen ? \"auto\" : 16,\n }}\n onPointerDown={attachScreenResource}\n onMouseDown={attachScreenResource}\n onClick={() => {\n attachScreenResource();\n setOpen(true);\n }}\n aria-label=\"Open AI assistant\"\n >\n <span aria-hidden=\"true\">\n <AiIcon material=\"chat_bubble_outline\" size={16} />\n </span>{\" \"}\n AI\n </button>\n </NativeTooltip>\n )}\n {open && (\n <aside\n className=\"power-ai-panel\"\n aria-label=\"AI assistant\"\n onPointerDownCapture={() => captureScreenResource()}\n onMouseDownCapture={() => captureScreenResource()}\n onFocusCapture={() => captureScreenResource()}\n style={{ \"--power-ai-font-size\": `${preferences.chatFontSize ?? 14}px`, width: panelWidth } as CSSProperties}\n >\n <AiResizeHandle\n width={panelWidth}\n available={availablePanelWidth}\n onChange={(width) => preferences.setChatPanelWidth(width)}\n />\n <header>\n <strong className=\"power-ai-title\">\n <NativeTooltip title=\"AI assistant\">\n <span className=\"power-ai-brand\">\n <AiIcon material=\"auto_awesome\" size={18} /> AI\n </span>\n </NativeTooltip>{\" \"}\n Assistant\n </strong>\n <NativeTooltip title=\"Clear this conversation and start a new chat\">\n <button\n type=\"button\"\n disabled={busy}\n aria-label=\"New chat\"\n onClick={() => {\n setTerminalAttachment(undefined);\n setFinding(undefined);\n removeResource();\n preferences.setMessages(key, []);\n setStopped((keys) => keys.filter((entry) => entry !== key));\n setActivity({ key, reads: [] });\n setError(\"\");\n }}\n >\n <AiIcon material=\"add_comment\" size={16} /> New chat\n </button>\n </NativeTooltip>\n <NativeTooltip title={pinned ? \"Unpin to close when clicking outside\" : \"Pin to keep the assistant open\"}>\n <button\n type=\"button\"\n className=\"power-ai-pin\"\n aria-label=\"Pin AI assistant\"\n aria-pressed={pinned}\n onClick={() => setPinned((value) => !value)}\n >\n <AiPinIcon pinned={pinned} size={18} />\n </button>\n </NativeTooltip>\n <NativeTooltip title=\"Close AI assistant\">\n <button\n type=\"button\"\n onPointerDown={(event) => event.stopPropagation()}\n onMouseDown={(event) => event.stopPropagation()}\n onClick={(event) => {\n event.stopPropagation();\n setOpen(false);\n }}\n className=\"power-ai-close\"\n aria-label=\"Close AI assistant\"\n >\n <span aria-hidden=\"true\">\n <AiIcon material=\"close\" size={18} />\n </span>\n </button>\n </NativeTooltip>\n </header>\n <div className=\"power-ai-context\">\n {context.clusterId ? \"Cluster conversation\" : \"General conversation\"} · {context.screen}\n {attachedResource && !(finding?.clusterId === context.clusterId && finding?.resource) && (\n <div className=\"power-ai-attached-resource\" aria-label=\"Attached resource\">\n <span>\n {attachedResource.kind}/{attachedResource.name}\n {attachedResource.namespace ? ` · ${attachedResource.namespace}` : \"\"}\n </span>\n <NativeTooltip title=\"Remove resource from attached context\">\n <button\n type=\"button\"\n className=\"power-ai-remove-context\"\n aria-label=\"Remove attached resource\"\n onClick={removeResource}\n >\n <AiIcon material=\"close\" size={14} />\n </button>\n </NativeTooltip>\n </div>\n )}\n <br />\n Only screen and resource metadata are attached automatically.\n </div>\n <div\n className=\"power-ai-messages\"\n onScroll={(event) => {\n const element = event.currentTarget;\n following.current = element.scrollHeight - element.scrollTop - element.clientHeight < 48;\n }}\n aria-live=\"polite\"\n ref={messagesElement}\n >\n {messages.length === 0 && (\n <div className=\"power-ai-starters\">\n <p style={{ marginBottom: 12 }}>Ask about this screen or your cluster:</p>\n <AiStarterPrompts\n disabled={busy}\n onSelect={(prompt) => {\n void send(prompt);\n }}\n />\n </div>\n )}\n {messages.map((message, index) => (\n <div className={`power-ai-message power-ai-message-${message.role}`} key={index}>\n <strong>\n {message.role === \"user\" ? (\n <NativeTooltip title=\"You\">\n <span>\n <AiIcon material=\"person_outline\" size={16} />\n </span>\n </NativeTooltip>\n ) : (\n <AiProviderIcon provider={message.provider === \"claude\" ? \"claude\" : \"codex\"} />\n )}\n {message.role === \"user\" ? \"You\" : message.provider === \"claude\" ? \"Claude\" : \"Codex\"}\n {message.role === \"assistant\" && <AiCopyAnswer text={message.text} />}\n </strong>\n <AiMessageContent text={message.text} />\n {message.role === \"assistant\" && context.clusterId && (\n <AiResourceReferences\n clusterId={context.clusterId}\n references={message.references}\n text={message.text}\n onOpened={() => setOpen(false)}\n />\n )}\n </div>\n ))}\n {readActivity.length > 0 && (\n <div\n className=\"power-ai-read-activity\"\n style={{ fontSize: 11, color: \"var(--textColorSecondary)\", margin: \"8px 16px\" }}\n >\n {readActivity.map((read, index) => (\n <NativeTooltip\n key={index}\n title={`${read.method} · ${read.status === \"reading\" ? \"reading\" : read.status === \"ok\" ? \"read\" : \"unavailable\"}`}\n >\n <span data-method={read.method} data-status={read.status} style={{ marginRight: 10 }}>\n <AiIcon\n material={\n read.status === \"reading\"\n ? \"sync\"\n : read.status === \"ok\"\n ? \"check_circle_outline\"\n : \"info_outline\"\n }\n size={13}\n />{\" \"}\n {read.method} ·{\" \"}\n {read.status === \"reading\" ? \"reading\" : read.status === \"ok\" ? \"read\" : \"unavailable\"}\n </span>\n </NativeTooltip>\n ))}\n </div>\n )}\n {busy && (\n <p className=\"power-ai-thinking\" role=\"status\">\n {stopped.includes(key) ? \"Stopping response\" : \"Thinking\"}\n <span className=\"power-ai-dots\" aria-hidden=\"true\">\n <span>.</span>\n <span>.</span>\n <span>.</span>\n </span>\n </p>\n )}\n {!busy && stopped.includes(key) && (\n <p className=\"power-ai-cancellation\" role=\"status\">\n Response stopped{\" \"}\n <NativeTooltip title=\"Dismiss\">\n <button\n type=\"button\"\n aria-label=\"Dismiss cancellation\"\n className=\"power-ai-dismiss\"\n onClick={() => setStopped((keys) => keys.filter((entry) => entry !== key))}\n >\n <AiIcon material=\"close\" size={14} />\n </button>\n </NativeTooltip>\n </p>\n )}\n {error && <p role=\"alert\">{error}</p>}\n </div>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n void send();\n }}\n >\n {suggestions.length > 0 && (\n <div\n className=\"power-ai-autocomplete\"\n role=\"listbox\"\n id=\"power-ai-commands\"\n aria-label=\"Prompt shortcuts\"\n >\n {suggestions.map((shortcut, index) => (\n <NativeTooltip key={shortcut.id} title={`Insert /${shortcut.command}: ${shortcut.label}`}>\n <button\n type=\"button\"\n role=\"option\"\n id={`power-ai-command-${index}`}\n aria-selected={index === suggestionIndex % suggestions.length}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => selectSuggestion(index)}\n >\n <span>/{shortcut.command}</span>\n <span>{shortcut.label}</span>\n </button>\n </NativeTooltip>\n ))}\n </div>\n )}\n <AiContextPreview\n finding={finding?.clusterId === context.clusterId ? finding : undefined}\n onRemoveFinding={() => setFinding(undefined)}\n context={previewContext}\n />\n <AiTerminalContext\n clusterId={context.clusterId}\n attachment={terminalAttachment}\n onChange={setTerminalAttachment}\n disabled={busy}\n />\n <textarea\n ref={composer}\n aria-controls={suggestions.length ? \"power-ai-commands\" : undefined}\n aria-expanded={suggestions.length > 0}\n aria-activedescendant={\n suggestions.length ? `power-ai-command-${suggestionIndex % suggestions.length}` : undefined\n }\n autoFocus\n aria-label=\"Message\"\n placeholder=\"Ask about this cluster…\"\n onKeyDown={(event) => {\n if (event.nativeEvent.isComposing || event.keyCode === 229) return;\n if (suggestions.length && !event.shiftKey) {\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n setSuggestionIndex(\n (index) =>\n (index + (event.key === \"ArrowDown\" ? 1 : suggestions.length - 1)) % suggestions.length,\n );\n return;\n }\n if (event.key === \"Enter\" || event.key === \"Tab\") {\n event.preventDefault();\n selectSuggestion(suggestionIndex % suggestions.length);\n return;\n }\n }\n if (\n event.key === \"Enter\" &&\n !event.shiftKey &&\n !event.nativeEvent.isComposing &&\n event.keyCode !== 229\n ) {\n event.preventDefault();\n if (!busy) void send();\n }\n }}\n value={draft}\n onChange={(event) => {\n setDraft(event.target.value);\n setSuggestionIndex(0);\n setDismissedDraft(undefined);\n }}\n disabled={busy}\n />\n <div className=\"power-ai-composer-footer\">\n <span>Enter to send · Shift+Enter for newline</span>\n {busy ? (\n <button\n type=\"button\"\n aria-label=\"Stop response\"\n disabled={stopped.includes(key)}\n onClick={stopResponse}\n >\n <AiIcon material=\"stop\" size={16} /> Stop\n </button>\n ) : (\n <button type=\"submit\" disabled={!draft.trim()} aria-label=\"Send\">\n <AiIcon material=\"send\" size={16} />\n </button>\n )}\n </div>\n </form>\n </aside>\n )}\n </>\n );\n});\n\nexport function startAiChat(isClusterDocument: () => boolean = isAiClusterDocument): () => void {\n const container = document.createElement(\"div\");\n container.dataset.freelensPowerAi = \"\";\n document.body.append(container);\n let mounted = false;\n let overviewActions: HTMLDivElement | undefined;\n let overviewIcon: HTMLSpanElement | undefined;\n let overviewLabel: HTMLSpanElement | undefined;\n let overviewResize: ResizeObserver | undefined;\n const updateOverviewLabel = () => {\n const overview = overviewActions?.nextElementSibling;\n const compact = Boolean(overview?.querySelector(\"[data-freelens-power-monitoring]\") && overview.clientWidth > 960);\n const label = compact ? \"Ask AI\" : \"Ask about cluster\";\n if (overviewLabel && overviewLabel.textContent !== label) overviewLabel.textContent = label;\n overviewActions?.querySelector(\"button\")?.setAttribute(\"aria-label\", compact ? \"Ask AI about cluster\" : label);\n };\n const removeOverview = () => {\n overviewResize?.disconnect();\n overviewResize = undefined;\n if (overviewIcon) ReactDOM.unmountComponentAtNode(overviewIcon);\n overviewIcon = undefined;\n overviewLabel = undefined;\n overviewActions?.remove();\n overviewActions = undefined;\n };\n const preferences = AiPreferencesStore.getInstanceOrCreate<AiPreferencesStore>();\n const reconcile = () => {\n const overview =\n preferences.enabled &&\n isClusterDocument() &&\n Renderer.Catalog.activeCluster.get() &&\n document.querySelector('[data-testid=\"cluster-overview-page\"]');\n if (!overview) {\n removeOverview();\n return;\n }\n if (overviewActions?.isConnected && overviewActions.nextElementSibling === overview) {\n updateOverviewLabel();\n return;\n }\n removeOverview();\n overviewActions = document.createElement(\"div\");\n overviewActions.className = \"power-ai-overview-actions\";\n const overviewButton = document.createElement(\"button\");\n overviewButton.type = \"button\";\n overviewButton.setAttribute(\"aria-label\", \"Ask about cluster\");\n overviewButton.id = \"power-ai-overview-button\";\n overviewIcon = document.createElement(\"span\");\n overviewIcon.setAttribute(\"aria-hidden\", \"true\");\n overviewLabel = document.createElement(\"span\");\n overviewButton.append(overviewIcon, overviewLabel);\n overviewButton.onclick = () => window.dispatchEvent(new Event(\"power-ai-open\"));\n overviewActions.append(overviewButton);\n overview.before(overviewActions);\n updateOverviewLabel();\n if (typeof ResizeObserver !== \"undefined\") {\n overviewResize = new ResizeObserver(updateOverviewLabel);\n overviewResize.observe(overview);\n }\n ReactDOM.render(\n <>\n <AiIcon material=\"auto_awesome\" size={16} />\n <Renderer.Component.Tooltip targetId=\"power-ai-overview-button\">\n Open the AI assistant to ask about this cluster\n </Renderer.Component.Tooltip>\n </>,\n overviewIcon,\n );\n };\n const observer = new MutationObserver(reconcile);\n const stop = autorun(() => {\n if (preferences.enabled && !mounted) {\n observer.observe(document.body, { childList: true, subtree: true });\n mounted = true;\n ReactDOM.render(<AiChat isClusterDocument={isClusterDocument} />, container);\n } else if (!preferences.enabled && mounted) {\n observer.disconnect();\n ReactDOM.unmountComponentAtNode(container);\n mounted = false;\n }\n reconcile();\n });\n return () => {\n stop();\n observer.disconnect();\n removeOverview();\n ReactDOM.unmountComponentAtNode(container);\n container.remove();\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ //#region src/renderer/host-layout.ts
2
+ function startHostLayoutStyles() {
3
+ const style = document.createElement("style");
4
+ style.dataset.freelensPower = "host-layout";
5
+ style.textContent = `
6
+ :root .ClusterManager { --status-bar-height: 0px; }
7
+ :root .ClusterManager > [data-testid="status-bar"] { display: none; }
8
+ `;
9
+ document.head.append(style);
10
+ return () => style.remove();
11
+ }
12
+ //#endregion
13
+ exports.startHostLayoutStyles = startHostLayoutStyles;
14
+
15
+ //# sourceMappingURL=host-layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-layout.js","names":[],"sources":["../../src/renderer/host-layout.ts"],"sourcesContent":["export function startHostLayoutStyles(): () => void {\n const style = document.createElement(\"style\");\n style.dataset.freelensPower = \"host-layout\";\n style.textContent = `\n :root .ClusterManager { --status-bar-height: 0px; }\n :root .ClusterManager > [data-testid=\"status-bar\"] { display: none; }\n `;\n document.head.append(style);\n return () => style.remove();\n}\n"],"mappings":";AAAA,SAAgB,wBAAoC;CAClD,MAAM,QAAQ,SAAS,cAAc,OAAO;CAC5C,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,cAAc;;;;CAIpB,SAAS,KAAK,OAAO,KAAK;CAC1B,aAAa,MAAM,OAAO;AAC5B"}
@@ -29,6 +29,7 @@ const require_secret_certificate_details = require("./details/secret-certificate
29
29
  const require_service_diagnostics_details = require("./details/service-diagnostics-details.js");
30
30
  const require_diagnostics_state = require("./diagnostics-state.js");
31
31
  const require_diagnostics = require("./diagnostics.js");
32
+ const require_host_layout = require("./host-layout.js");
32
33
  const require_secure_node_shell_menu = require("./menus/secure-node-shell-menu.js");
33
34
  const require_monitoring = require("./monitoring.js");
34
35
  const require_monitoring_history_collection = require("./monitoring-history-collection.js");
@@ -85,6 +86,7 @@ var FreelensPowerRenderer = class extends require_extensions.Renderer.LensExtens
85
86
  require_pod_monitoring.startPodMonitoring,
86
87
  require_pod_details_enhancements.startPodDetailsEnhancements,
87
88
  require_button_styles.startPowerButtonStyles,
89
+ require_host_layout.startHostLayoutStyles,
88
90
  require_appearance.startAppearanceOverride,
89
91
  require_welcome.startWelcomeOverride,
90
92
  require_ai.startAiChat,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/renderer/index.tsx"],"sourcesContent":["/**\n * Copyright (c) Freelens Authors. All rights reserved.\n * Licensed under MIT License. See THIRD_PARTY_LICENSES for more information.\n */\n\nimport { Common, Renderer } from \"@freelensapp/extensions\";\nimport { computed, reaction } from \"mobx\";\nimport { observer } from \"mobx-react\";\nimport { EXTENSION_DISPLAY_NAME, EXTENSION_ID } from \"../common/extension-info\";\nimport { AiPreferencesStore } from \"../common/store/ai-preferences-store\";\nimport { AiShortcutsStore } from \"../common/store/ai-shortcuts-store\";\nimport { AppearancePreferencesStore } from \"../common/store/appearance-preferences-store\";\nimport { DashboardPreferencesStore } from \"../common/store/dashboard-preferences-store\";\nimport { LogsPreferencesStore } from \"../common/store/logs-preferences-store\";\nimport { MonitoringPreferencesStore } from \"../common/store/monitoring-preferences-store\";\nimport { NodeShellPreferencesStore } from \"../common/store/node-shell-preferences-store\";\nimport { PowerPreferencesStore } from \"../common/store/power-preferences-store\";\nimport { ReadOnlyPreferencesStore } from \"../common/store/read-only-preferences-store\";\nimport { startAiChat } from \"./ai\";\nimport { startAppearanceOverride } from \"./appearance\";\nimport { startPowerButtonStyles } from \"./button-styles\";\nimport { ClusterIconsPage } from \"./cluster-icons\";\nimport { DashboardPage } from \"./dashboard\";\nimport { HpaDiagnosticsDetails } from \"./details/hpa-diagnostics-details\";\nimport { NamespaceHealthDetails } from \"./details/namespace-health-details\";\nimport { ResourceHealthDetails } from \"./details/resource-health-details\";\nimport { SecretCertificateDetails } from \"./details/secret-certificate-details\";\nimport { ServiceDiagnosticsDetails } from \"./details/service-diagnostics-details\";\nimport { DiagnosticsPage } from \"./diagnostics\";\nimport { type DiagnosticsResourceScope, focusDiagnosticsNamespace } from \"./diagnostics-state\";\nimport { SecureNodeShellMenu } from \"./menus/secure-node-shell-menu\";\nimport { startMonitoring } from \"./monitoring\";\nimport { startMonitoringCollector } from \"./monitoring-collector\";\nimport { startMonitoringHistoryCollection } from \"./monitoring-history-collection\";\nimport { NodeMonitoringDetails } from \"./node-monitoring\";\nimport { startPodDetailsEnhancements } from \"./pod-details-enhancements\";\nimport { startPodMonitoring } from \"./pod-monitoring\";\nimport { PowerLogsPage } from \"./power-logs\";\nimport { PowerLogsMenu, startPowerLogsEntrypoints } from \"./power-logs-entrypoints\";\nimport { PowerPreferences } from \"./preferences/preferences\";\nimport { openPreferencesSection } from \"./preferences/section-navigation\";\nimport { startReadOnlyMode } from \"./read-only\";\nimport { ResourceRelationshipsPage } from \"./resource-relationships\";\nimport { startResourceSearch } from \"./resource-search\";\nimport { startWelcomeOverride } from \"./welcome\";\n\nimport type { ReactNode } from \"react\";\n\nconst PowerEnabled = observer(({ children }: { children: ReactNode }) =>\n PowerPreferencesStore.getInstanceOrCreate<PowerPreferencesStore>().enabled ? <>{children}</> : null,\n);\n\nconst RelationshipsPage = observer(() => (\n <PowerEnabled>\n <ResourceRelationshipsPage\n enabled={MonitoringPreferencesStore.getInstanceOrCreate<MonitoringPreferencesStore>().relationshipsVisible}\n />\n </PowerEnabled>\n));\n\nexport default class FreelensPowerRenderer extends Renderer.LensExtension {\n get name() {\n return EXTENSION_DISPLAY_NAME;\n }\n get sanitizedExtensionId() {\n return EXTENSION_ID;\n }\n get storeName() {\n return this.manifest.storeName || EXTENSION_ID;\n }\n\n private stopFeatures?: () => void;\n\n onActivate() {\n const power = PowerPreferencesStore.getInstanceOrCreate<PowerPreferencesStore>();\n power.loadExtension(this);\n LogsPreferencesStore.getInstanceOrCreate().loadExtension(this);\n AiPreferencesStore.getInstanceOrCreate().loadExtension(this);\n AiShortcutsStore.getInstanceOrCreate().loadExtension(this);\n ReadOnlyPreferencesStore.getInstanceOrCreate().loadExtension(this);\n NodeShellPreferencesStore.getInstanceOrCreate().loadExtension(this);\n MonitoringPreferencesStore.getInstanceOrCreate().loadExtension(this);\n AppearancePreferencesStore.getInstanceOrCreate().loadExtension(this);\n DashboardPreferencesStore.getInstanceOrCreate().loadExtension(this);\n this.stopFeatures?.();\n let disposers: (() => void)[] = [];\n const stop = reaction(\n () => power.enabled,\n (enabled) => {\n for (const dispose of disposers) dispose();\n disposers = [];\n if (enabled) {\n for (const start of [\n startReadOnlyMode,\n startMonitoringCollector,\n startMonitoringHistoryCollection,\n startMonitoring,\n startPodMonitoring,\n startPodDetailsEnhancements,\n startPowerButtonStyles,\n startAppearanceOverride,\n startWelcomeOverride,\n startAiChat,\n startResourceSearch,\n startPowerLogsEntrypoints,\n ]) {\n try {\n disposers.push(start());\n } catch {\n Common.logger.warn(\"[Freelens Power] feature could not start\", { feature: start.name });\n }\n }\n }\n },\n { fireImmediately: true },\n );\n this.stopFeatures = () => {\n stop();\n for (const dispose of disposers) dispose();\n disposers = [];\n };\n }\n\n onDeactivate() {\n this.stopFeatures?.();\n this.stopFeatures = undefined;\n }\n\n appPreferences = [\n {\n id: \"freelens-power-settings\",\n title: \"\",\n components: { Input: PowerPreferences, Hint: () => null },\n },\n ];\n\n globalPages = [\n {\n id: \"cluster-icons\",\n components: {\n Page: () => (\n <PowerEnabled>\n <ClusterIconsPage />\n </PowerEnabled>\n ),\n },\n },\n {\n id: \"dashboard\",\n components: {\n Page: () => (\n <PowerEnabled>\n <DashboardPage\n onOpenPreferences={() => openPreferencesSection(\"dashboard\", () => this.navigateToPreferences())}\n />\n </PowerEnabled>\n ),\n },\n },\n ];\n\n clusterPages = [\n {\n id: \"power-logs\",\n components: {\n Page: () => (\n <PowerEnabled>\n <PowerLogsPage />\n </PowerEnabled>\n ),\n },\n },\n { id: \"relationships\", components: { Page: () => <RelationshipsPage /> } },\n {\n id: \"diagnostics\",\n components: {\n Page: () => (\n <PowerEnabled>\n <DiagnosticsPage />\n </PowerEnabled>\n ),\n },\n },\n ];\n\n clusterPageMenus = [\n {\n visible: computed(\n () =>\n PowerPreferencesStore.getInstanceOrCreate<PowerPreferencesStore>().enabled &&\n MonitoringPreferencesStore.getInstanceOrCreate<MonitoringPreferencesStore>().diagnosticsVisible,\n ),\n target: { pageId: \"diagnostics\" },\n title: \"Diagnostics\",\n orderNumber: 5,\n components: { Icon: () => <Renderer.Component.Icon material=\"insights\" tooltip=\"Resource diagnostics\" /> },\n },\n {\n visible: computed(\n () =>\n PowerPreferencesStore.getInstanceOrCreate<PowerPreferencesStore>().enabled &&\n MonitoringPreferencesStore.getInstanceOrCreate<MonitoringPreferencesStore>().relationshipsVisible,\n ),\n id: \"relationships\",\n target: { pageId: \"relationships\" },\n title: \"Relationships\",\n orderNumber: 6,\n components: {\n Icon: () => <Renderer.Component.Icon material=\"account_tree\" tooltip=\"Resource relationships\" />,\n },\n },\n {\n id: \"power-logs\",\n visible: computed(\n () =>\n PowerPreferencesStore.getInstanceOrCreate<PowerPreferencesStore>().enabled &&\n LogsPreferencesStore.getInstanceOrCreate<LogsPreferencesStore>().enabled,\n ),\n target: { pageId: \"power-logs\" },\n title: \"Power Logs\",\n orderNumber: 7,\n components: {\n Icon: () => <Renderer.Component.Icon material=\"subject\" tooltip=\"Workload logs and SQL captures\" />,\n },\n },\n ];\n\n topBarItems = [\n {\n components: {\n Item: () => (\n <PowerEnabled>\n <Renderer.Component.Icon\n material=\"battery_charging_full\"\n className=\"freelens-power-settings-icon\"\n tooltip=\"Freelens Power settings\"\n onClick={() => this.navigateToPreferences()}\n />\n </PowerEnabled>\n ),\n },\n },\n ];\n\n private openDiagnostics = (namespace?: string, resourceScope?: DiagnosticsResourceScope) => {\n const clusterId = Renderer.Catalog.activeCluster.get()?.metadata.uid;\n if (clusterId && (namespace || resourceScope)) focusDiagnosticsNamespace(clusterId, namespace, resourceScope);\n void this.navigate(\"diagnostics\");\n };\n\n kubeObjectDetailItems: Renderer.LensExtension[\"kubeObjectDetailItems\"] = [\n ...[\"Pod\", \"Deployment\", \"StatefulSet\", \"DaemonSet\", \"Node\"].map((kind) => ({\n kind,\n apiVersions: kind === \"Pod\" || kind === \"Node\" ? [\"v1\"] : [\"apps/v1\"],\n priority: 320,\n components: {\n Details: (props: Renderer.Component.KubeObjectDetailsProps) => (\n <PowerEnabled>\n <ResourceHealthDetails {...props} onOpenDiagnostics={this.openDiagnostics} />\n </PowerEnabled>\n ),\n },\n })),\n {\n kind: \"Namespace\",\n apiVersions: [\"v1\"],\n priority: 320,\n components: {\n Details: (props) => (\n <PowerEnabled>\n <NamespaceHealthDetails {...props} onOpenDiagnostics={this.openDiagnostics} />\n </PowerEnabled>\n ),\n },\n },\n {\n kind: \"Service\",\n apiVersions: [\"v1\"],\n priority: 320,\n components: {\n Details: (props) => (\n <PowerEnabled>\n <ServiceDiagnosticsDetails {...props} object={props.object as Renderer.K8sApi.Service} />\n </PowerEnabled>\n ),\n },\n },\n {\n kind: \"HorizontalPodAutoscaler\",\n apiVersions: [\"autoscaling/v1\", \"autoscaling/v2\"],\n priority: 320,\n components: {\n Details: (props) => (\n <PowerEnabled>\n <HpaDiagnosticsDetails {...props} object={props.object as Renderer.K8sApi.HorizontalPodAutoscaler} />\n </PowerEnabled>\n ),\n },\n },\n {\n kind: \"Node\",\n apiVersions: [\"v1\"],\n // host order is [300 - priority], before native metrics at [-1]\n priority: 310,\n components: {\n Details: (props) => (\n <PowerEnabled>\n <NodeMonitoringDetails {...props} object={props.object as Renderer.K8sApi.Node} />\n </PowerEnabled>\n ),\n },\n },\n {\n kind: \"Secret\",\n apiVersions: [\"v1\"],\n priority: 10,\n components: {\n Details: (props) => (\n <PowerEnabled>\n <SecretCertificateDetails {...props} object={props.object as Renderer.K8sApi.Secret} />\n </PowerEnabled>\n ),\n },\n },\n ];\n\n kubeObjectMenuItems = [\n ...([\"Pod\", \"Deployment\", \"DaemonSet\", \"StatefulSet\", \"ReplicaSet\", \"Job\", \"CronJob\"] as const).map((kind) => ({\n kind,\n apiVersions: kind === \"Pod\" ? [\"v1\"] : kind === \"Job\" || kind === \"CronJob\" ? [\"batch/v1\"] : [\"apps/v1\"],\n components: {\n MenuItem: (props: Renderer.Component.KubeObjectMenuProps<Renderer.K8sApi.KubeObject>) => (\n <PowerEnabled>\n <PowerLogsMenu {...props} />\n </PowerEnabled>\n ),\n },\n })),\n {\n kind: \"Node\",\n apiVersions: [\"v1\"],\n components: {\n MenuItem: (props: Renderer.Component.KubeObjectMenuProps<Renderer.K8sApi.Node>) => (\n <PowerEnabled>\n <SecureNodeShellMenu {...props} />\n </PowerEnabled>\n ),\n },\n },\n ];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,IAAM,eAAe,oCAAA,UAAU,EAAE,eAC/B,gCAAA,sBAAsB,oBAA2C,CAAC,CAAC,UAAU,oCAAA,IAAA,oBAAA,UAAA,EAAG,SAAW,CAAA,IAAI,IACjG;AAEA,IAAM,oBAAoB,oCAAA,eACxB,oCAAA,IAAC,cAAD,EAAA,UACE,oCAAA,IAAC,+BAAA,2BAAD,EACE,SAAS,qCAAA,2BAA2B,oBAAgD,CAAC,CAAC,qBACvF,CAAA,EACW,CAAA,CACf;AAED,IAAqB,wBAArB,cAAmD,mBAAA,SAAS,cAAc;CACxE,IAAI,OAAO;EACT,OAAO,uBAAA;CACT;CACA,IAAI,uBAAuB;EACzB,OAAO,uBAAA;CACT;CACA,IAAI,YAAY;EACd,OAAO,KAAK,SAAS,aAAA;CACvB;CAEA;CAEA,aAAa;EACX,MAAM,QAAQ,gCAAA,sBAAsB,oBAA2C;EAC/E,MAAM,cAAc,IAAI;EACxB,+BAAA,qBAAqB,oBAAoB,CAAC,CAAC,cAAc,IAAI;EAC7D,6BAAA,mBAAmB,oBAAoB,CAAC,CAAC,cAAc,IAAI;EAC3D,2BAAA,iBAAiB,oBAAoB,CAAC,CAAC,cAAc,IAAI;EACzD,oCAAA,yBAAyB,oBAAoB,CAAC,CAAC,cAAc,IAAI;EACjE,qCAAA,0BAA0B,oBAAoB,CAAC,CAAC,cAAc,IAAI;EAClE,qCAAA,2BAA2B,oBAAoB,CAAC,CAAC,cAAc,IAAI;EACnE,qCAAA,2BAA2B,oBAAoB,CAAC,CAAC,cAAc,IAAI;EACnE,oCAAA,0BAA0B,oBAAoB,CAAC,CAAC,cAAc,IAAI;EAClE,KAAK,eAAe;EACpB,IAAI,YAA4B,CAAC;EACjC,MAAM,OAAO,8BAAA,eACL,MAAM,UACX,YAAY;GACX,KAAK,MAAM,WAAW,WAAW,QAAQ;GACzC,YAAY,CAAC;GACb,IAAI,SACF,KAAK,MAAM,SAAS;IAClB,kBAAA;IACA,6BAAA;IACA,sCAAA;IACA,mBAAA;IACA,uBAAA;IACA,iCAAA;IACA,sBAAA;IACA,mBAAA;IACA,gBAAA;IACA,WAAA;IACA,wBAAA;IACA,+BAAA;GACF,GACE,IAAI;IACF,UAAU,KAAK,MAAM,CAAC;GACxB,QAAQ;IACN,mBAAA,OAAO,OAAO,KAAK,4CAA4C,EAAE,SAAS,MAAM,KAAK,CAAC;GACxF;EAGN,GACA,EAAE,iBAAiB,KAAK,CAC1B;EACA,KAAK,qBAAqB;GACxB,KAAK;GACL,KAAK,MAAM,WAAW,WAAW,QAAQ;GACzC,YAAY,CAAC;EACf;CACF;CAEA,eAAe;EACb,KAAK,eAAe;EACpB,KAAK,eAAe,KAAA;CACtB;CAEA,iBAAiB,CACf;EACE,IAAI;EACJ,OAAO;EACP,YAAY;GAAE,OAAO,oBAAA;GAAkB,YAAY;EAAK;CAC1D,CACF;CAEA,cAAc,CACZ;EACE,IAAI;EACJ,YAAY,EACV,YACE,oCAAA,IAAC,cAAD,EAAA,UACE,oCAAA,IAAC,sBAAA,kBAAD,CAAmB,CAAA,EACP,CAAA,EAElB;CACF,GACA;EACE,IAAI;EACJ,YAAY,EACV,YACE,oCAAA,IAAC,cAAD,EAAA,UACE,oCAAA,IAAC,kBAAA,eAAD,EACE,yBAAyB,2BAAA,uBAAuB,mBAAmB,KAAK,sBAAsB,CAAC,EAChG,CAAA,EACW,CAAA,EAElB;CACF,CACF;CAEA,eAAe;EACb;GACE,IAAI;GACJ,YAAY,EACV,YACE,oCAAA,IAAC,cAAD,EAAA,UACE,oCAAA,IAAC,mBAAA,eAAD,CAAgB,CAAA,EACJ,CAAA,EAElB;EACF;EACA;GAAE,IAAI;GAAiB,YAAY,EAAE,YAAY,oCAAA,IAAC,mBAAD,CAAoB,CAAA,EAAE;EAAE;EACzE;GACE,IAAI;GACJ,YAAY,EACV,YACE,oCAAA,IAAC,cAAD,EAAA,UACE,oCAAA,IAAC,oBAAA,iBAAD,CAAkB,CAAA,EACN,CAAA,EAElB;EACF;CACF;CAEA,mBAAmB;EACjB;GACE,SAAS,8BAAA,eAEL,gCAAA,sBAAsB,oBAA2C,CAAC,CAAC,WACnE,qCAAA,2BAA2B,oBAAgD,CAAC,CAAC,kBACjF;GACA,QAAQ,EAAE,QAAQ,cAAc;GAChC,OAAO;GACP,aAAa;GACb,YAAY,EAAE,YAAY,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;IAAyB,UAAS;IAAW,SAAQ;GAAwB,CAAA,EAAE;EAC3G;EACA;GACE,SAAS,8BAAA,eAEL,gCAAA,sBAAsB,oBAA2C,CAAC,CAAC,WACnE,qCAAA,2BAA2B,oBAAgD,CAAC,CAAC,oBACjF;GACA,IAAI;GACJ,QAAQ,EAAE,QAAQ,gBAAgB;GAClC,OAAO;GACP,aAAa;GACb,YAAY,EACV,YAAY,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;IAAyB,UAAS;IAAe,SAAQ;GAA0B,CAAA,EACjG;EACF;EACA;GACE,IAAI;GACJ,SAAS,8BAAA,eAEL,gCAAA,sBAAsB,oBAA2C,CAAC,CAAC,WACnE,+BAAA,qBAAqB,oBAA0C,CAAC,CAAC,OACrE;GACA,QAAQ,EAAE,QAAQ,aAAa;GAC/B,OAAO;GACP,aAAa;GACb,YAAY,EACV,YAAY,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;IAAyB,UAAS;IAAU,SAAQ;GAAkC,CAAA,EACpG;EACF;CACF;CAEA,cAAc,CACZ,EACE,YAAY,EACV,YACE,oCAAA,IAAC,cAAD,EAAA,UACE,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;EACE,UAAS;EACT,WAAU;EACV,SAAQ;EACR,eAAe,KAAK,sBAAsB;CAC3C,CAAA,EACW,CAAA,EAElB,EACF,CACF;CAEA,mBAA2B,WAAoB,kBAA6C;EAC1F,MAAM,YAAY,mBAAA,SAAS,QAAQ,cAAc,IAAI,CAAC,EAAE,SAAS;EACjE,IAAI,cAAc,aAAa,gBAAgB,0BAAA,0BAA0B,WAAW,WAAW,aAAa;EAC5G,KAAU,SAAS,aAAa;CAClC;CAEA,wBAAyE;EACvE,GAAG;GAAC;GAAO;GAAc;GAAe;GAAa;EAAM,CAAC,CAAC,KAAK,UAAU;GAC1E;GACA,aAAa,SAAS,SAAS,SAAS,SAAS,CAAC,IAAI,IAAI,CAAC,SAAS;GACpE,UAAU;GACV,YAAY,EACV,UAAU,UACR,oCAAA,IAAC,cAAD,EAAA,UACE,oCAAA,IAAC,gCAAA,uBAAD;IAAuB,GAAI;IAAO,mBAAmB,KAAK;GAAkB,CAAA,EAChE,CAAA,EAElB;EACF,EAAE;EACF;GACE,MAAM;GACN,aAAa,CAAC,IAAI;GAClB,UAAU;GACV,YAAY,EACV,UAAU,UACR,oCAAA,IAAC,cAAD,EAAA,UACE,oCAAA,IAAC,iCAAA,wBAAD;IAAwB,GAAI;IAAO,mBAAmB,KAAK;GAAkB,CAAA,EACjE,CAAA,EAElB;EACF;EACA;GACE,MAAM;GACN,aAAa,CAAC,IAAI;GAClB,UAAU;GACV,YAAY,EACV,UAAU,UACR,oCAAA,IAAC,cAAD,EAAA,UACE,oCAAA,IAAC,oCAAA,2BAAD;IAA2B,GAAI;IAAO,QAAQ,MAAM;GAAoC,CAAA,EAC5E,CAAA,EAElB;EACF;EACA;GACE,MAAM;GACN,aAAa,CAAC,kBAAkB,gBAAgB;GAChD,UAAU;GACV,YAAY,EACV,UAAU,UACR,oCAAA,IAAC,cAAD,EAAA,UACE,oCAAA,IAAC,gCAAA,uBAAD;IAAuB,GAAI;IAAO,QAAQ,MAAM;GAAoD,CAAA,EACxF,CAAA,EAElB;EACF;EACA;GACE,MAAM;GACN,aAAa,CAAC,IAAI;GAElB,UAAU;GACV,YAAY,EACV,UAAU,UACR,oCAAA,IAAC,cAAD,EAAA,UACE,oCAAA,IAAC,wBAAA,uBAAD;IAAuB,GAAI;IAAO,QAAQ,MAAM;GAAiC,CAAA,EACrE,CAAA,EAElB;EACF;EACA;GACE,MAAM;GACN,aAAa,CAAC,IAAI;GAClB,UAAU;GACV,YAAY,EACV,UAAU,UACR,oCAAA,IAAC,cAAD,EAAA,UACE,oCAAA,IAAC,mCAAA,0BAAD;IAA0B,GAAI;IAAO,QAAQ,MAAM;GAAmC,CAAA,EAC1E,CAAA,EAElB;EACF;CACF;CAEA,sBAAsB,CACpB,GAAI;EAAC;EAAO;EAAc;EAAa;EAAe;EAAc;EAAO;CAAS,CAAC,CAAW,KAAK,UAAU;EAC7G;EACA,aAAa,SAAS,QAAQ,CAAC,IAAI,IAAI,SAAS,SAAS,SAAS,YAAY,CAAC,UAAU,IAAI,CAAC,SAAS;EACvG,YAAY,EACV,WAAW,UACT,oCAAA,IAAC,cAAD,EAAA,UACE,oCAAA,IAAC,+BAAA,eAAD,EAAe,GAAI,MAAQ,CAAA,EACf,CAAA,EAElB;CACF,EAAE,GACF;EACE,MAAM;EACN,aAAa,CAAC,IAAI;EAClB,YAAY,EACV,WAAW,UACT,oCAAA,IAAC,cAAD,EAAA,UACE,oCAAA,IAAC,+BAAA,qBAAD,EAAqB,GAAI,MAAQ,CAAA,EACrB,CAAA,EAElB;CACF,CACF;AACF"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/renderer/index.tsx"],"sourcesContent":["/**\n * Copyright (c) Freelens Authors. All rights reserved.\n * Licensed under MIT License. See THIRD_PARTY_LICENSES for more information.\n */\n\nimport { Common, Renderer } from \"@freelensapp/extensions\";\nimport { computed, reaction } from \"mobx\";\nimport { observer } from \"mobx-react\";\nimport { EXTENSION_DISPLAY_NAME, EXTENSION_ID } from \"../common/extension-info\";\nimport { AiPreferencesStore } from \"../common/store/ai-preferences-store\";\nimport { AiShortcutsStore } from \"../common/store/ai-shortcuts-store\";\nimport { AppearancePreferencesStore } from \"../common/store/appearance-preferences-store\";\nimport { DashboardPreferencesStore } from \"../common/store/dashboard-preferences-store\";\nimport { LogsPreferencesStore } from \"../common/store/logs-preferences-store\";\nimport { MonitoringPreferencesStore } from \"../common/store/monitoring-preferences-store\";\nimport { NodeShellPreferencesStore } from \"../common/store/node-shell-preferences-store\";\nimport { PowerPreferencesStore } from \"../common/store/power-preferences-store\";\nimport { ReadOnlyPreferencesStore } from \"../common/store/read-only-preferences-store\";\nimport { startAiChat } from \"./ai\";\nimport { startAppearanceOverride } from \"./appearance\";\nimport { startPowerButtonStyles } from \"./button-styles\";\nimport { ClusterIconsPage } from \"./cluster-icons\";\nimport { DashboardPage } from \"./dashboard\";\nimport { HpaDiagnosticsDetails } from \"./details/hpa-diagnostics-details\";\nimport { NamespaceHealthDetails } from \"./details/namespace-health-details\";\nimport { ResourceHealthDetails } from \"./details/resource-health-details\";\nimport { SecretCertificateDetails } from \"./details/secret-certificate-details\";\nimport { ServiceDiagnosticsDetails } from \"./details/service-diagnostics-details\";\nimport { DiagnosticsPage } from \"./diagnostics\";\nimport { type DiagnosticsResourceScope, focusDiagnosticsNamespace } from \"./diagnostics-state\";\nimport { startHostLayoutStyles } from \"./host-layout\";\nimport { SecureNodeShellMenu } from \"./menus/secure-node-shell-menu\";\nimport { startMonitoring } from \"./monitoring\";\nimport { startMonitoringCollector } from \"./monitoring-collector\";\nimport { startMonitoringHistoryCollection } from \"./monitoring-history-collection\";\nimport { NodeMonitoringDetails } from \"./node-monitoring\";\nimport { startPodDetailsEnhancements } from \"./pod-details-enhancements\";\nimport { startPodMonitoring } from \"./pod-monitoring\";\nimport { PowerLogsPage } from \"./power-logs\";\nimport { PowerLogsMenu, startPowerLogsEntrypoints } from \"./power-logs-entrypoints\";\nimport { PowerPreferences } from \"./preferences/preferences\";\nimport { openPreferencesSection } from \"./preferences/section-navigation\";\nimport { startReadOnlyMode } from \"./read-only\";\nimport { ResourceRelationshipsPage } from \"./resource-relationships\";\nimport { startResourceSearch } from \"./resource-search\";\nimport { startWelcomeOverride } from \"./welcome\";\n\nimport type { ReactNode } from \"react\";\n\nconst PowerEnabled = observer(({ children }: { children: ReactNode }) =>\n PowerPreferencesStore.getInstanceOrCreate<PowerPreferencesStore>().enabled ? <>{children}</> : null,\n);\n\nconst RelationshipsPage = observer(() => (\n <PowerEnabled>\n <ResourceRelationshipsPage\n enabled={MonitoringPreferencesStore.getInstanceOrCreate<MonitoringPreferencesStore>().relationshipsVisible}\n />\n </PowerEnabled>\n));\n\nexport default class FreelensPowerRenderer extends Renderer.LensExtension {\n get name() {\n return EXTENSION_DISPLAY_NAME;\n }\n get sanitizedExtensionId() {\n return EXTENSION_ID;\n }\n get storeName() {\n return this.manifest.storeName || EXTENSION_ID;\n }\n\n private stopFeatures?: () => void;\n\n onActivate() {\n const power = PowerPreferencesStore.getInstanceOrCreate<PowerPreferencesStore>();\n power.loadExtension(this);\n LogsPreferencesStore.getInstanceOrCreate().loadExtension(this);\n AiPreferencesStore.getInstanceOrCreate().loadExtension(this);\n AiShortcutsStore.getInstanceOrCreate().loadExtension(this);\n ReadOnlyPreferencesStore.getInstanceOrCreate().loadExtension(this);\n NodeShellPreferencesStore.getInstanceOrCreate().loadExtension(this);\n MonitoringPreferencesStore.getInstanceOrCreate().loadExtension(this);\n AppearancePreferencesStore.getInstanceOrCreate().loadExtension(this);\n DashboardPreferencesStore.getInstanceOrCreate().loadExtension(this);\n this.stopFeatures?.();\n let disposers: (() => void)[] = [];\n const stop = reaction(\n () => power.enabled,\n (enabled) => {\n for (const dispose of disposers) dispose();\n disposers = [];\n if (enabled) {\n for (const start of [\n startReadOnlyMode,\n startMonitoringCollector,\n startMonitoringHistoryCollection,\n startMonitoring,\n startPodMonitoring,\n startPodDetailsEnhancements,\n startPowerButtonStyles,\n startHostLayoutStyles,\n startAppearanceOverride,\n startWelcomeOverride,\n startAiChat,\n startResourceSearch,\n startPowerLogsEntrypoints,\n ]) {\n try {\n disposers.push(start());\n } catch {\n Common.logger.warn(\"[Freelens Power] feature could not start\", { feature: start.name });\n }\n }\n }\n },\n { fireImmediately: true },\n );\n this.stopFeatures = () => {\n stop();\n for (const dispose of disposers) dispose();\n disposers = [];\n };\n }\n\n onDeactivate() {\n this.stopFeatures?.();\n this.stopFeatures = undefined;\n }\n\n appPreferences = [\n {\n id: \"freelens-power-settings\",\n title: \"\",\n components: { Input: PowerPreferences, Hint: () => null },\n },\n ];\n\n globalPages = [\n {\n id: \"cluster-icons\",\n components: {\n Page: () => (\n <PowerEnabled>\n <ClusterIconsPage />\n </PowerEnabled>\n ),\n },\n },\n {\n id: \"dashboard\",\n components: {\n Page: () => (\n <PowerEnabled>\n <DashboardPage\n onOpenPreferences={() => openPreferencesSection(\"dashboard\", () => this.navigateToPreferences())}\n />\n </PowerEnabled>\n ),\n },\n },\n ];\n\n clusterPages = [\n {\n id: \"power-logs\",\n components: {\n Page: () => (\n <PowerEnabled>\n <PowerLogsPage />\n </PowerEnabled>\n ),\n },\n },\n { id: \"relationships\", components: { Page: () => <RelationshipsPage /> } },\n {\n id: \"diagnostics\",\n components: {\n Page: () => (\n <PowerEnabled>\n <DiagnosticsPage />\n </PowerEnabled>\n ),\n },\n },\n ];\n\n clusterPageMenus = [\n {\n visible: computed(\n () =>\n PowerPreferencesStore.getInstanceOrCreate<PowerPreferencesStore>().enabled &&\n MonitoringPreferencesStore.getInstanceOrCreate<MonitoringPreferencesStore>().diagnosticsVisible,\n ),\n target: { pageId: \"diagnostics\" },\n title: \"Diagnostics\",\n orderNumber: 5,\n components: { Icon: () => <Renderer.Component.Icon material=\"insights\" tooltip=\"Resource diagnostics\" /> },\n },\n {\n visible: computed(\n () =>\n PowerPreferencesStore.getInstanceOrCreate<PowerPreferencesStore>().enabled &&\n MonitoringPreferencesStore.getInstanceOrCreate<MonitoringPreferencesStore>().relationshipsVisible,\n ),\n id: \"relationships\",\n target: { pageId: \"relationships\" },\n title: \"Relationships\",\n orderNumber: 6,\n components: {\n Icon: () => <Renderer.Component.Icon material=\"account_tree\" tooltip=\"Resource relationships\" />,\n },\n },\n {\n id: \"power-logs\",\n visible: computed(\n () =>\n PowerPreferencesStore.getInstanceOrCreate<PowerPreferencesStore>().enabled &&\n LogsPreferencesStore.getInstanceOrCreate<LogsPreferencesStore>().enabled,\n ),\n target: { pageId: \"power-logs\" },\n title: \"Power Logs\",\n orderNumber: 7,\n components: {\n Icon: () => <Renderer.Component.Icon material=\"subject\" tooltip=\"Workload logs and SQL captures\" />,\n },\n },\n ];\n\n topBarItems = [\n {\n components: {\n Item: () => (\n <PowerEnabled>\n <Renderer.Component.Icon\n material=\"battery_charging_full\"\n className=\"freelens-power-settings-icon\"\n tooltip=\"Freelens Power settings\"\n onClick={() => this.navigateToPreferences()}\n />\n </PowerEnabled>\n ),\n },\n },\n ];\n\n private openDiagnostics = (namespace?: string, resourceScope?: DiagnosticsResourceScope) => {\n const clusterId = Renderer.Catalog.activeCluster.get()?.metadata.uid;\n if (clusterId && (namespace || resourceScope)) focusDiagnosticsNamespace(clusterId, namespace, resourceScope);\n void this.navigate(\"diagnostics\");\n };\n\n kubeObjectDetailItems: Renderer.LensExtension[\"kubeObjectDetailItems\"] = [\n ...[\"Pod\", \"Deployment\", \"StatefulSet\", \"DaemonSet\", \"Node\"].map((kind) => ({\n kind,\n apiVersions: kind === \"Pod\" || kind === \"Node\" ? [\"v1\"] : [\"apps/v1\"],\n priority: 320,\n components: {\n Details: (props: Renderer.Component.KubeObjectDetailsProps) => (\n <PowerEnabled>\n <ResourceHealthDetails {...props} onOpenDiagnostics={this.openDiagnostics} />\n </PowerEnabled>\n ),\n },\n })),\n {\n kind: \"Namespace\",\n apiVersions: [\"v1\"],\n priority: 320,\n components: {\n Details: (props) => (\n <PowerEnabled>\n <NamespaceHealthDetails {...props} onOpenDiagnostics={this.openDiagnostics} />\n </PowerEnabled>\n ),\n },\n },\n {\n kind: \"Service\",\n apiVersions: [\"v1\"],\n priority: 320,\n components: {\n Details: (props) => (\n <PowerEnabled>\n <ServiceDiagnosticsDetails {...props} object={props.object as Renderer.K8sApi.Service} />\n </PowerEnabled>\n ),\n },\n },\n {\n kind: \"HorizontalPodAutoscaler\",\n apiVersions: [\"autoscaling/v1\", \"autoscaling/v2\"],\n priority: 320,\n components: {\n Details: (props) => (\n <PowerEnabled>\n <HpaDiagnosticsDetails {...props} object={props.object as Renderer.K8sApi.HorizontalPodAutoscaler} />\n </PowerEnabled>\n ),\n },\n },\n {\n kind: \"Node\",\n apiVersions: [\"v1\"],\n // host order is [300 - priority], before native metrics at [-1]\n priority: 310,\n components: {\n Details: (props) => (\n <PowerEnabled>\n <NodeMonitoringDetails {...props} object={props.object as Renderer.K8sApi.Node} />\n </PowerEnabled>\n ),\n },\n },\n {\n kind: \"Secret\",\n apiVersions: [\"v1\"],\n priority: 10,\n components: {\n Details: (props) => (\n <PowerEnabled>\n <SecretCertificateDetails {...props} object={props.object as Renderer.K8sApi.Secret} />\n </PowerEnabled>\n ),\n },\n },\n ];\n\n kubeObjectMenuItems = [\n ...([\"Pod\", \"Deployment\", \"DaemonSet\", \"StatefulSet\", \"ReplicaSet\", \"Job\", \"CronJob\"] as const).map((kind) => ({\n kind,\n apiVersions: kind === \"Pod\" ? [\"v1\"] : kind === \"Job\" || kind === \"CronJob\" ? [\"batch/v1\"] : [\"apps/v1\"],\n components: {\n MenuItem: (props: Renderer.Component.KubeObjectMenuProps<Renderer.K8sApi.KubeObject>) => (\n <PowerEnabled>\n <PowerLogsMenu {...props} />\n </PowerEnabled>\n ),\n },\n })),\n {\n kind: \"Node\",\n apiVersions: [\"v1\"],\n components: {\n MenuItem: (props: Renderer.Component.KubeObjectMenuProps<Renderer.K8sApi.Node>) => (\n <PowerEnabled>\n <SecureNodeShellMenu {...props} />\n </PowerEnabled>\n ),\n },\n },\n ];\n}\n"],"mappings":"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"}
@@ -10,6 +10,7 @@ const require_ai_diagnostic_handoff = require("./ai-diagnostic-handoff.js");
10
10
  const require_power_log_field_filters = require("./src/common/power-log-field-filters.js");
11
11
  const require_power_log_json_fields = require("./power-log-json-fields.js");
12
12
  const require_power_log_json = require("./power-log-json.js");
13
+ const require_power_log_sql_editor = require("./power-log-sql-editor.js");
13
14
  const require_date_time = require("./src/common/date-time.js");
14
15
  const require_diagnostic_explain_button = require("./diagnostic-explain-button.js");
15
16
  const require_power_log_json_filter_sql = require("./src/common/power-log-json-filter-sql.js");
@@ -18,7 +19,6 @@ const require_power_log_sql_level = require("./src/common/power-log-sql-level.js
18
19
  const require_power_logs_ai = require("./src/common/power-logs-ai.js");
19
20
  const require_power_log_message = require("./power-log-message.js");
20
21
  const require_power_log_json_cell = require("./power-log-json-cell.js");
21
- const require_power_log_sql_editor = require("./power-log-sql-editor.js");
22
22
  const require_power_logs_css = require("./power-logs.css.js");
23
23
  const require_power_logs_client = require("./power-logs-client.js");
24
24
  const require_power_logs_collector = require("./power-logs-collector.js");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@64mb/freelens-power",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "Power tools for Freelens Kubernetes IDE",
5
5
  "main": "out/main/index.js",
6
6
  "renderer": "out/renderer/index.js",