@64mb/freelens-power 1.5.0 → 1.6.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.
Files changed (71) hide show
  1. package/README.md +4 -1
  2. package/out/main/ai-ipc.js +34 -3
  3. package/out/main/ai-ipc.js.map +1 -1
  4. package/out/main/common/power-logs-limits.js +227 -0
  5. package/out/main/common/power-logs-limits.js.map +1 -0
  6. package/out/main/common/power-logs.js +32 -0
  7. package/out/main/common/power-logs.js.map +1 -0
  8. package/out/main/common/store/logs-preferences-store.js +45 -0
  9. package/out/main/common/store/logs-preferences-store.js.map +1 -0
  10. package/out/main/dashboard-icon-cache.js +1 -1
  11. package/out/main/index.js +4 -0
  12. package/out/main/index.js.map +1 -1
  13. package/out/main/power-logs-budget.js +126 -0
  14. package/out/main/power-logs-budget.js.map +1 -0
  15. package/out/main/power-logs-child.js +86 -0
  16. package/out/main/power-logs-child.js.map +1 -0
  17. package/out/main/power-logs-database.js +179 -0
  18. package/out/main/power-logs-database.js.map +1 -0
  19. package/out/main/power-logs-ipc.js +275 -0
  20. package/out/main/power-logs-ipc.js.map +1 -0
  21. package/out/main/power-logs-query-child.js +23 -0
  22. package/out/main/power-logs-query-child.js.map +1 -0
  23. package/out/main/power-logs-query.js +127 -0
  24. package/out/main/power-logs-query.js.map +1 -0
  25. package/out/main/power-logs-worker.js +215 -0
  26. package/out/main/power-logs-worker.js.map +1 -0
  27. package/out/main/resource-search.js +1 -1
  28. package/out/renderer/ai-logs-sql.js +27 -0
  29. package/out/renderer/ai-logs-sql.js.map +1 -0
  30. package/out/renderer/ai-message.js +48 -27
  31. package/out/renderer/ai-message.js.map +1 -1
  32. package/out/renderer/ai-terminal-context.js +50 -40
  33. package/out/renderer/ai-terminal-context.js.map +1 -1
  34. package/out/renderer/ai.js +15 -2
  35. package/out/renderer/ai.js.map +1 -1
  36. package/out/renderer/appearance.js +1 -0
  37. package/out/renderer/appearance.js.map +1 -1
  38. package/out/renderer/index.js +67 -29
  39. package/out/renderer/index.js.map +1 -1
  40. package/out/renderer/power-log-json.js +29 -0
  41. package/out/renderer/power-log-json.js.map +1 -0
  42. package/out/renderer/power-logs-client.js +35 -0
  43. package/out/renderer/power-logs-client.js.map +1 -0
  44. package/out/renderer/power-logs-collector.js +316 -0
  45. package/out/renderer/power-logs-collector.js.map +1 -0
  46. package/out/renderer/power-logs-entrypoints.js +201 -0
  47. package/out/renderer/power-logs-entrypoints.js.map +1 -0
  48. package/out/renderer/power-logs-sql-row.js +52 -0
  49. package/out/renderer/power-logs-sql-row.js.map +1 -0
  50. package/out/renderer/power-logs-transport.js +122 -0
  51. package/out/renderer/power-logs-transport.js.map +1 -0
  52. package/out/renderer/power-logs.css.js +116 -0
  53. package/out/renderer/power-logs.css.js.map +1 -0
  54. package/out/renderer/power-logs.js +1352 -0
  55. package/out/renderer/power-logs.js.map +1 -0
  56. package/out/renderer/preferences/logs-preferences.js +93 -0
  57. package/out/renderer/preferences/logs-preferences.js.map +1 -0
  58. package/out/renderer/preferences/preferences.js +23 -9
  59. package/out/renderer/preferences/preferences.js.map +1 -1
  60. package/out/renderer/resource-relationships.js +1 -1
  61. package/out/renderer/src/common/power-log-parser.js +114 -0
  62. package/out/renderer/src/common/power-log-parser.js.map +1 -0
  63. package/out/renderer/src/common/power-logs-ai.js +56 -0
  64. package/out/renderer/src/common/power-logs-ai.js.map +1 -0
  65. package/out/renderer/src/common/power-logs-limits.js +227 -0
  66. package/out/renderer/src/common/power-logs-limits.js.map +1 -0
  67. package/out/renderer/src/common/power-logs.js +32 -0
  68. package/out/renderer/src/common/power-logs.js.map +1 -0
  69. package/out/renderer/src/common/store/logs-preferences-store.js +45 -0
  70. package/out/renderer/src/common/store/logs-preferences-store.js.map +1 -0
  71. package/package.json +4 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"power-logs.js","names":[],"sources":["../../src/renderer/power-logs.tsx"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { Renderer } from \"@freelensapp/extensions\";\nimport { observer } from \"mobx-react\";\nimport {\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { formatDateTime } from \"../common/date-time\";\nimport {\n POWER_LOGS_LIMITS as L,\n type LogCapture,\n type LogLevel,\n type LogQueryResult,\n type LogRecord,\n type LogSource,\n type LogTarget,\n} from \"../common/power-logs\";\nimport { powerLogLineEvidence, powerLogQueryEvidence } from \"../common/power-logs-ai\";\nimport { applyPowerLogsLimits, normalizePowerLogsLimits } from \"../common/power-logs-limits\";\nimport { LogsPreferencesStore } from \"../common/store/logs-preferences-store\";\nimport { explainDiagnosticFinding } from \"./ai-diagnostic-handoff\";\nimport { DiagnosticExplainButton } from \"./diagnostic-explain-button\";\nimport { LogJson } from \"./power-log-json\";\nimport { powerLogsStyles } from \"./power-logs.css\";\nimport { createPowerLogsClient } from \"./power-logs-client\";\nimport { collectHistoricalLogs, type LiveLogCoverage, resolveLogSources, startLiveLogs } from \"./power-logs-collector\";\nimport { openPowerLogs, parsePowerLogsTarget } from \"./power-logs-entrypoints\";\nimport { sqlRowDetails } from \"./power-logs-sql-row\";\nimport { createPowerLogsTransport } from \"./power-logs-transport\";\nimport { searchContextId } from \"./resource-search-client\";\n\nconst Icon = (props: { material: string; size?: number }) => (\n <span aria-hidden=\"true\" style={{ display: \"inline-flex\" }}>\n <Renderer.Component.Icon {...props} />\n </span>\n);\nconst sourceKey = (r: Pick<LogRecord, \"pod\" | \"container\" | \"previous\">) =>\n `${r.pod} / ${r.container}${r.previous ? \" (previous)\" : \"\"}`;\nconst levels: LogLevel[] = [\"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\", \"unknown\"];\nconst examples = [\n [\"Recent\", \"SELECT message, level, container, pod, timestamp FROM logs ORDER BY timestamp DESC NULLS LAST LIMIT 200\"],\n [\n \"Errors\",\n \"SELECT pod, container, count(*) AS errors FROM logs WHERE level IN ('error','fatal') GROUP BY pod, container ORDER BY errors DESC\",\n ],\n [\n \"Timeline\",\n \"SELECT strftime('%Y-%m-%d %H:%M', timestamp / 1000, 'unixepoch') AS minute, level, count(*) AS lines FROM logs GROUP BY minute, level ORDER BY minute\",\n ],\n [\n \"JSON\",\n \"SELECT pod, json_extract(fieldsJson, '$.message') AS message FROM logs WHERE fieldsJson IS NOT NULL LIMIT 100\",\n ],\n] as const;\nconst sqlColumnWidth = (column: string) =>\n column === \"message\" || column === \"fieldsJson\" ? 360 : column === \"level\" ? 90 : 200;\ntype ViewRecord = LogRecord & { key: number; bytes: number };\n\nfunction initialTarget(): LogTarget | undefined {\n try {\n return parsePowerLogsTarget(JSON.parse(new URLSearchParams(window.location.search).get(\"target\") ?? \"null\"));\n } catch {\n return;\n }\n}\nfunction initialSource(container: unknown = new URLSearchParams(window.location.search).get(\"container\")): string {\n return typeof container === \"string\" && /^[a-z0-9](?:[-a-z0-9]*[a-z0-9])?$/.test(container) && container.length <= 63\n ? `container:${container}`\n : \"\";\n}\n\nfunction LogSelect({\n label,\n value,\n options,\n onChange,\n disabled = false,\n renderOption,\n onKeyDown,\n}: {\n label: string;\n value: string;\n options: { value: string; label: string }[];\n onChange(value: string): void;\n disabled?: boolean;\n onKeyDown?: (event: ReactKeyboardEvent) => void;\n renderOption?: (option: { value: string; label: string }, context: \"menu\" | \"value\") => ReactNode;\n}) {\n return (\n <span className=\"power-logs-select\" data-source-select={label === \"Container source\" || undefined}>\n <Renderer.Component.Select\n aria-label={label}\n value={value}\n options={options}\n formatOptionLabel={(option, meta) =>\n renderOption ? (\n renderOption(option, meta.context)\n ) : label === \"Log level\" && option.value ? (\n <span className=\"power-logs-level-label\" data-level={option.value}>\n {option.label}\n </span>\n ) : (\n option.label\n )\n }\n isDisabled={disabled}\n onKeyDown={onKeyDown}\n tabSelectsValue={false}\n isClearable={false}\n menuPosition=\"fixed\"\n menuPortalTarget={document.body}\n styles={{\n menu: (base) => (label === \"Container source\" ? { ...base, width: \"100%\", maxWidth: \"100%\" } : base),\n menuList: (base) => (label === \"Container source\" ? { ...base, width: \"100%\", maxWidth: \"100%\" } : base),\n option: (base) => (label === \"Container source\" ? { ...base, whiteSpace: \"normal\" } : base),\n menuPortal: (base) => {\n if (label !== \"Container source\" && label !== \"Capture snapshot\") return { ...base, zIndex: 10000 };\n const width = Math.min(label === \"Capture snapshot\" ? 620 : 560, window.innerWidth - 32);\n return {\n ...base,\n zIndex: 10000,\n width,\n left: Math.max(\n 16,\n Math.min(typeof base.left === \"number\" ? base.left : 16, window.innerWidth - width - 16),\n ),\n };\n },\n }}\n onChange={(option) => {\n if (option) onChange(option.value);\n }}\n />\n </span>\n );\n}\n\nconst SourcePicker = observer(() => {\n const stores = [\n Renderer.K8sApi.podsStore,\n Renderer.K8sApi.deploymentStore,\n Renderer.K8sApi.daemonSetStore,\n Renderer.K8sApi.statefulSetStore,\n Renderer.K8sApi.replicaSetStore,\n Renderer.K8sApi.jobStore,\n Renderer.K8sApi.cronJobStore,\n ];\n const targets = stores.flatMap((store) =>\n store.getItems().flatMap((object) => {\n const target = parsePowerLogsTarget({ kind: object.kind, ...object.metadata });\n return target ? [target] : [];\n }),\n );\n const [value, setValue] = useState(\"\");\n const sorted = [...targets].sort((a, b) =>\n `${a.namespace}/${a.kind}/${a.name}`.localeCompare(`${b.namespace}/${b.kind}/${b.name}`),\n );\n return (\n <div className=\"power-logs-source\">\n <span>Resource</span>\n <LogSelect\n label=\"Resource\"\n value={value}\n onChange={setValue}\n options={[\n { value: \"\", label: \"Choose a loaded pod or workload\" },\n ...sorted.map((target) => ({\n value: target.uid,\n label: `${target.namespace} / ${target.kind} / ${target.name}`,\n })),\n ]}\n />\n <button\n type=\"button\"\n disabled={!targets.some((target) => target.uid === value)}\n onClick={() => {\n const target = targets.find((t) => t.uid === value);\n if (target) openPowerLogs(target);\n }}\n >\n <Icon material=\"subject\" size={16} /> Open logs\n </button>\n </div>\n );\n});\n\nfunction LogRows({\n records,\n selected,\n onSelect,\n follow,\n setFollow,\n compact,\n}: {\n records: ViewRecord[];\n selected?: number;\n onSelect(record: ViewRecord): void;\n follow: boolean;\n setFollow(value: boolean): void;\n compact: boolean;\n}) {\n const viewport = useRef<HTMLDivElement>(null);\n const [top, setTop] = useState(0);\n const [height, setHeight] = useState(400);\n useEffect(() => {\n const element = viewport.current;\n if (!element) return;\n const resize = new ResizeObserver(() => setHeight(element.clientHeight));\n resize.observe(element);\n return () => resize.disconnect();\n }, []);\n useLayoutEffect(() => {\n if (follow && viewport.current) {\n viewport.current.scrollTop = viewport.current.scrollHeight;\n setTop(viewport.current.scrollTop);\n }\n }, [records, follow, compact]);\n const rowHeight = compact ? 24 : 34;\n const start = Math.max(0, Math.floor(top / rowHeight) - 5);\n const visible = records.slice(start, start + Math.ceil(height / rowHeight) + 10);\n return (\n <div className=\"power-logs-viewer\">\n <div\n className=\"power-logs-stream\"\n ref={viewport}\n aria-label=\"Log lines\"\n onScroll={(event) => {\n const el = event.currentTarget;\n setTop(el.scrollTop);\n if (el.scrollHeight - el.scrollTop - el.clientHeight > 60) setFollow(false);\n }}\n >\n {records.length === 0 ? (\n <div className=\"power-logs-empty\">No matching log lines</div>\n ) : (\n <div style={{ height: records.length * rowHeight, position: \"relative\" }}>\n {visible.map((record, i) => (\n <button\n type=\"button\"\n className=\"power-log-row\"\n data-level={record.level}\n aria-pressed={selected === record.key}\n style={{ top: (start + i) * rowHeight, height: rowHeight }}\n key={record.key}\n onClick={() => onSelect(record)}\n >\n <span title={record.timestamp !== null ? formatDateTime(record.timestamp) : \"Timestamp unavailable\"}>\n {record.timestamp !== null ? formatDateTime(record.timestamp).slice(-8) : \"—\"}\n </span>\n <span className=\"power-log-level\">{record.level}</span>\n <span className=\"power-log-origin\" title={sourceKey(record)}>\n {record.container}\n {record.previous ? \" (previous)\" : \"\"} · {record.pod}\n </span>\n <span>{record.message}</span>\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction LogDetails({ record, jsonColumn, onClose }: { record: LogRecord; jsonColumn?: string; onClose: () => void }) {\n const structuredFields = useMemo(() => {\n if (!record?.fieldsJson) return \"\";\n try {\n return JSON.stringify(JSON.parse(record.fieldsJson), null, 2);\n } catch {\n return record.fieldsJson;\n }\n }, [record?.fieldsJson]);\n return (\n <aside className=\"power-logs-detail\" aria-label=\"Log line details\">\n <header>\n <strong>Line details</strong>\n <button\n className=\"power-logs-detail-close\"\n aria-label=\"Close line details\"\n title=\"Close line details\"\n onClick={onClose}\n >\n <Icon material=\"close\" size={16} />\n </button>\n </header>\n <p className=\"power-logs-muted\">{[record.pod && sourceKey(record), record.level].filter(Boolean).join(\" · \")}</p>\n {record.message && <pre>{record.message}</pre>}\n {record.fieldsJson && (\n <>\n <strong>{jsonColumn ? `Structured fields · ${jsonColumn}` : \"Structured fields\"}</strong>\n <LogJson text={structuredFields} />\n </>\n )}\n </aside>\n );\n}\n\nfunction Workspace({ clusterId, contextId }: { clusterId: string; contextId: string }) {\n const client = useMemo(() => createPowerLogsClient({ clusterId, contextId }), [clusterId, contextId]);\n const [target, setTarget] = useState(initialTarget);\n const [records, setRecords] = useState<ViewRecord[]>([]);\n const [sources, setSources] = useState<LogSource[]>([]);\n const [notes, setNotes] = useState<string[]>([]);\n const [status, setStatus] = useState(\"Choose a resource to read its logs\");\n const [error, setError] = useState(\"\");\n const [tab, setTab] = useState<\"live\" | \"captures\">(\"live\");\n const [text, setText] = useState(\"\");\n const [level, setLevel] = useState(\"\");\n const [source, setSource] = useState(initialSource);\n const preferences = LogsPreferencesStore.getInstanceOrCreate<LogsPreferencesStore>();\n const limits = normalizePowerLogsLimits(preferences.limits);\n useEffect(() => {\n applyPowerLogsLimits(preferences.limits);\n }, [preferences.limits]);\n const [compact, setCompact] = useState(preferences.compactRows === true);\n const [selected, setSelected] = useState<ViewRecord>();\n const [selectedSqlRow, setSelectedSqlRow] = useState<\n ReturnType<typeof sqlRowDetails> & { row: LogQueryResult[\"rows\"][number] }\n >();\n const [liveCoverage, setLiveCoverage] = useState<LiveLogCoverage>();\n const [live, setLive] = useState(false);\n const [follow, setFollow] = useState(true);\n const [busy, setBusy] = useState(false);\n const [captures, setCaptures] = useState<LogCapture[]>([]);\n const [captureId, setCaptureId] = useState(\"\");\n const captureSelection = useRef(captureId);\n captureSelection.current = captureId;\n const deleting = useRef(new Set<string>());\n const [deletingCount, setDeletingCount] = useState(0);\n const [capturing, setCapturing] = useState<LogCapture>();\n const [capturePending, setCapturePending] = useState(false);\n const [captureMinutes, setCaptureMinutes] = useState(15);\n const [previous, setPrevious] = useState(false);\n const [sql, setSql] = useState<string>(examples[0][1]);\n const [result, setResult] = useState<LogQueryResult>();\n const [resultEvidence, setResultEvidence] = useState<{ capture: LogCapture; sql: string }>();\n const [resultPage, setResultPage] = useState(0);\n const [queryId, setQueryId] = useState(\"\");\n const captureOptions = useRef<HTMLDetailsElement>(null);\n useEffect(() => {\n const outside = (event: PointerEvent) => {\n if (\n !captureOptions.current?.contains(event.target as Node) &&\n !(event.target as Element)?.closest?.(\".Select__menu\")\n ) {\n if (captureOptions.current) captureOptions.current.open = false;\n }\n };\n const escape = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\" || event.defaultPrevented || (event.target as Element)?.closest?.(\".Select\")) return;\n if (captureOptions.current?.open) captureOptions.current.open = false;\n else {\n setSelected(undefined);\n setSelectedSqlRow(undefined);\n }\n };\n window.addEventListener(\"pointerdown\", outside);\n window.addEventListener(\"keydown\", escape);\n return () => {\n window.removeEventListener(\"pointerdown\", outside);\n window.removeEventListener(\"keydown\", escape);\n };\n }, []);\n const historyController = useRef<AbortController>();\n const liveController = useRef<AbortController>();\n const captureController = useRef<AbortController>();\n const queryRef = useRef(\"\");\n const epoch = useRef(0);\n const alive = useRef(true);\n const sequence = useRef(0);\n const recordsRef = useRef(records);\n recordsRef.current = records;\n const pending = useRef<LogRecord[]>([]);\n const flushTimer = useRef<ReturnType<typeof setTimeout>>();\n const refreshCaptures = () =>\n client\n .list()\n .then((value) => {\n if (alive.current) setCaptures(value);\n })\n .catch(() => {\n if (alive.current) setError(\"Temporary captures are unavailable\");\n });\n const stopLive = () => {\n liveController.current?.abort();\n liveController.current = undefined;\n setLive(false);\n };\n const flush = () => {\n clearTimeout(flushTimer.current);\n flushTimer.current = undefined;\n const batch = pending.current;\n pending.current = [];\n if (!batch.length || !alive.current) return;\n const next = batch.map((record) => ({\n ...record,\n key: ++sequence.current,\n bytes: Buffer.byteLength(JSON.stringify(record)),\n }));\n setRecords((current) => {\n const combined = [...current, ...next];\n let bytes = combined.reduce((sum, r) => sum + r.bytes, 0);\n let start = 0;\n while (combined.length - start > L.liveRows || bytes > L.liveBytes) bytes -= combined[start++].bytes;\n return combined.slice(start).sort((a, b) => (a.timestamp ?? 0) - (b.timestamp ?? 0) || a.key - b.key);\n });\n };\n const appendView = (batch: LogRecord[]) => {\n if (!alive.current) return;\n pending.current.push(...batch);\n if (pending.current.length > 1000) flush();\n else flushTimer.current ??= setTimeout(flush, 80);\n };\n useEffect(() => {\n alive.current = true;\n const onTarget = (event: Event) => {\n const next = parsePowerLogsTarget((event as CustomEvent).detail);\n if (next) {\n if (queryRef.current) {\n void client.cancel(queryRef.current).catch(() => {});\n queryRef.current = \"\";\n setQueryId(\"\");\n }\n setSource(initialSource((event as CustomEvent).detail.container));\n setTarget(next);\n }\n };\n window.addEventListener(\"power-logs-target\", onTarget);\n void refreshCaptures();\n const timer = setInterval(() => void refreshCaptures(), 30000);\n return () => {\n alive.current = false;\n epoch.current++;\n clearInterval(timer);\n clearTimeout(flushTimer.current);\n historyController.current?.abort();\n liveController.current?.abort();\n captureController.current?.abort();\n if (queryRef.current) void client.cancel(queryRef.current).catch(() => {});\n window.removeEventListener(\"power-logs-target\", onTarget);\n };\n }, [client]);\n const readHistory = async () => {\n if (!target) return;\n const currentEpoch = ++epoch.current;\n historyController.current?.abort();\n stopLive();\n const controller = new AbortController();\n historyController.current = controller;\n clearTimeout(flushTimer.current);\n flushTimer.current = undefined;\n pending.current = [];\n setBusy(true);\n setRecords([]);\n setSelected(undefined);\n setError(\"\");\n setNotes([]);\n setStatus(\"Discovering owned containers…\");\n try {\n const transport = createPowerLogsTransport(clusterId);\n const discovery = await resolveLogSources(target, transport, controller.signal);\n if (controller.signal.aborted || currentEpoch !== epoch.current) return;\n setSources(discovery.sources);\n setNotes(discovery.notes);\n setStatus(`Reading ${discovery.sources.length} container sources…`);\n const history = await collectHistoricalLogs(discovery.sources, transport, {\n signal: controller.signal,\n tailLines: L.historyLines,\n limitBytes: L.historyBytes,\n onRecords: (batch) => {\n if (currentEpoch === epoch.current) appendView(batch);\n },\n });\n if (controller.signal.aborted || currentEpoch !== epoch.current) return;\n flush();\n setNotes([...new Set([...discovery.notes, ...history.notes])]);\n setStatus(\n `${discovery.sources.length} sources · last ${limits.historyLines.toLocaleString()} lines per container, up to ${limits.historyBytes / 1048576} MiB each`,\n );\n } catch {\n if (alive.current && currentEpoch === epoch.current)\n setError(\n controller.signal.aborted\n ? \"Log loading stopped\"\n : \"Could not read this resource's logs. Check permissions and whether it still exists.\",\n );\n } finally {\n if (alive.current && currentEpoch === epoch.current) setBusy(false);\n }\n };\n useEffect(() => {\n setText(\"\");\n setSources([]);\n setTab(\"live\");\n void readHistory();\n }, [target?.uid]);\n const toggleLive = () => {\n if (live) {\n stopLive();\n return;\n }\n setLive(true);\n };\n const sourceIdentity = sources.map((item) => `${item.podUid}/${item.container}`).join(\";\");\n useEffect(() => {\n if (!live || !sources.length) return;\n const controller = new AbortController();\n liveController.current = controller;\n const collector = startLiveLogs(sources, createPowerLogsTransport(clusterId), {\n signal: controller.signal,\n tailLines: L.historyLines,\n initialRecords: recordsRef.current,\n onRecords: appendView,\n onCoverage: (coverage) => {\n if (alive.current && liveController.current === controller)\n setLiveCoverage({ ...coverage, notes: [...coverage.notes] });\n },\n });\n setLiveCoverage({ ...collector.coverage });\n void collector.done.finally(() => {\n if (alive.current && !controller.signal.aborted && liveController.current === controller) {\n liveController.current = undefined;\n setLive(false);\n }\n });\n return () => {\n controller.abort();\n if (liveController.current === controller) liveController.current = undefined;\n };\n }, [live, sourceIdentity]);\n useEffect(() => {\n if (!live || !target) return;\n const controller = new AbortController();\n const startingEpoch = epoch.current;\n let refreshing = false;\n const timer = setInterval(() => {\n if (refreshing) return;\n refreshing = true;\n void resolveLogSources(target, createPowerLogsTransport(clusterId), controller.signal)\n .then((discovery) => {\n if (controller.signal.aborted || epoch.current !== startingEpoch) return;\n setSources(discovery.sources);\n setNotes(discovery.notes);\n setStatus(`${discovery.sources.length} sources · ownership inventory refreshed`);\n })\n .catch(() => {\n if (!controller.signal.aborted && alive.current && epoch.current === startingEpoch) {\n stopLive();\n setNotes((current) => [\n ...new Set([\n ...current,\n \"Workload inventory changed or became unavailable. Refresh before following logs again.\",\n ]),\n ]);\n }\n })\n .finally(() => {\n refreshing = false;\n });\n }, 30000);\n return () => {\n clearInterval(timer);\n controller.abort();\n };\n }, [live, target?.uid]);\n const capture = async () => {\n if (!target || captureController.current || queryRef.current) return;\n setCapturePending(true);\n const controller = new AbortController();\n captureController.current = controller;\n let current: LogCapture | undefined;\n let partial = false;\n let captureNotes: string[] = [];\n setError(\"\");\n stopLive();\n try {\n current = await client.create(target);\n setCapturing(current);\n const transport = createPowerLogsTransport(clusterId);\n const discovery = await resolveLogSources(target, transport, controller.signal);\n captureNotes = discovery.notes;\n partial = discovery.partial;\n const captureSources = previous\n ? [...discovery.sources, ...discovery.sources.map((item) => ({ ...item, previous: true }))]\n : discovery.sources;\n const boundary = current.createdAt;\n const history = await collectHistoricalLogs(captureSources, transport, {\n signal: controller.signal,\n tailLines: L.captureSourceLines,\n sinceTime: new Date(boundary - captureMinutes * 60000).toISOString(),\n limitBytes: L.captureSourceBytes,\n onRecords: async (batch) => {\n if (batch.some((record) => record.timestamp === null)) {\n partial = true;\n captureNotes.push(\"Some records have no timestamp and their capture window cannot be verified\");\n }\n batch = batch.filter(\n (record) =>\n record.timestamp === null ||\n (record.timestamp <= boundary && record.timestamp >= boundary - captureMinutes * 60000),\n );\n for (let offset = 0; offset < batch.length; ) {\n const chunk: LogRecord[] = [];\n let bytes = 2;\n while (offset < batch.length && chunk.length < L.batchRows) {\n const record = batch[offset];\n const size = Buffer.byteLength(JSON.stringify(record)) + 1;\n if (chunk.length && bytes + size > L.batchBytes) break;\n chunk.push(record);\n bytes += size;\n offset++;\n }\n if (controller.signal.aborted) throw new Error(\"Capture stopped\");\n try {\n current = await client.append(current!.id, chunk);\n if (alive.current) setCapturing(current);\n } catch {\n controller.abort();\n throw new Error(\"Capture reached its storage limit or became unavailable\");\n }\n }\n },\n });\n partial ||= history.partial;\n captureNotes.push(...history.notes);\n } catch {\n partial = true;\n captureNotes.push(\"Collection stopped or a source was unavailable; this snapshot may be incomplete\");\n } finally {\n if (current) {\n try {\n const saved = await client.finish(\n current.id,\n partial || controller.signal.aborted,\n [...new Set(captureNotes)].slice(0, 20),\n );\n if (alive.current) {\n setCaptureId(saved.id);\n setCaptures((items) => [saved, ...items.filter((item) => item.id !== saved.id)]);\n setTab(\"captures\");\n setSql(examples[0][1]);\n void runQuery(saved, examples[0][1]);\n }\n } catch {\n if (alive.current) setError(\"The temporary capture could not be finalized\");\n }\n } else if (alive.current)\n setError(\"Could not create a capture. Delete an old snapshot or check the log service.\");\n if (alive.current) {\n setCapturing(undefined);\n setCapturePending(false);\n void refreshCaptures();\n }\n captureController.current = undefined;\n }\n };\n const runQuery = async (selectedCapture?: LogCapture, query = sql) => {\n if (queryRef.current || (!selectedCapture && captureController.current)) return;\n const captured = selectedCapture ?? captures.find((item) => item.id === captureId);\n if (!captured || captured.state === \"collecting\" || deleting.current.has(captured.id)) return;\n const id = randomUUID();\n queryRef.current = id;\n setQueryId(id);\n setError(\"\");\n setResult(undefined);\n setSelectedSqlRow(undefined);\n setResultEvidence({ capture: captured, sql: query });\n setResultPage(0);\n try {\n const value = await client.query(captured.id, id, query);\n if (alive.current && queryRef.current === id) {\n if (value.error) setError(value.error);\n else setResult(value);\n }\n } catch {\n if (alive.current && queryRef.current === id)\n setError(\n \"Query stopped or failed. Use one read-only SELECT or EXPLAIN; external files, networking and extensions are disabled.\",\n );\n } finally {\n if (queryRef.current === id) {\n if (alive.current) setQueryId(\"\");\n queryRef.current = \"\";\n }\n }\n };\n const filtered = useMemo(\n () =>\n records.filter(\n (record) =>\n (!text || record.message.toLocaleLowerCase().includes(text.toLocaleLowerCase())) &&\n (!level || record.level === level) &&\n (!source ||\n (source.startsWith(\"container:\") ? record.container === source.slice(10) : sourceKey(record) === source)),\n ),\n [records, text, level, source],\n );\n const chosenCapture = captures.find((item) => item.id === captureId);\n const collectionNotes = tab === \"live\" ? [...new Set([...notes, ...(live ? (liveCoverage?.notes ?? []) : [])])] : [];\n useEffect(() => {\n window.dispatchEvent(new CustomEvent(\"power-logs-workspace-change\", { detail: { active: true } }));\n return () => {\n window.dispatchEvent(new CustomEvent(\"power-logs-workspace-change\", { detail: { active: false } }));\n };\n }, []);\n useEffect(() => {\n const insert = (event: Event) => {\n const sql = (event as CustomEvent<{ sql?: unknown }>).detail?.sql;\n if (typeof sql !== \"string\" || !sql.trim() || sql.length > 65536) return;\n setTab(\"captures\");\n setSql(sql);\n setSelectedSqlRow(undefined);\n if (!captureId) {\n const latest = captures.find((item) => item.state !== \"collecting\" && item.target.uid === target?.uid);\n if (latest) setCaptureId(latest.id);\n }\n requestAnimationFrame(() => document.getElementById(\"power-logs-sql\")?.focus());\n };\n window.addEventListener(\"power-logs-sql-draft\", insert);\n return () => window.removeEventListener(\"power-logs-sql-draft\", insert);\n }, [captureId, captures, target?.uid]);\n const attachAi = () => {\n const resource =\n tab === \"captures\"\n ? result && resultEvidence\n ? resultEvidence.capture.target\n : (chosenCapture?.target ?? target)\n : target;\n const summary =\n tab === \"captures\" && result && resultEvidence\n ? powerLogQueryEvidence(\n resultEvidence.capture,\n resultEvidence.sql,\n selectedSqlRow ? { ...result, rows: [selectedSqlRow.row], truncated: false } : result,\n )\n : tab === \"live\" && selected\n ? powerLogLineEvidence(resource, selected)\n : JSON.stringify({\n target: resource,\n ...(tab === \"captures\"\n ? { sql, rows: [], state: \"Draft query, not executed\" }\n : { status, sources: sources.length }),\n });\n if (\n !explainDiagnosticFinding({\n clusterId,\n title: tab === \"captures\" ? (selectedSqlRow ? \"SQL row\" : \"SQL query\") : selected ? \"Log line\" : \"Power Logs\",\n summary: summary.slice(0, 6000),\n ...(resource ? { resource: { kind: resource.kind, name: resource.name, namespace: resource.namespace } } : {}),\n })\n )\n window.dispatchEvent(new Event(\"power-ai-open-only\"));\n };\n const deleteCapture = async (id: string) => {\n if (deleting.current.has(id) || queryRef.current || captureController.current) return;\n deleting.current.add(id);\n setDeletingCount(deleting.current.size);\n try {\n await client.delete(id);\n if (id === captureSelection.current) {\n setCaptureId(\"\");\n setResult(undefined);\n setResultEvidence(undefined);\n setSelectedSqlRow(undefined);\n }\n await refreshCaptures();\n } catch {\n setError(\"Could not delete capture\");\n } finally {\n deleting.current.delete(id);\n if (alive.current) setDeletingCount(deleting.current.size);\n }\n };\n const native = () => {\n const first = sources[0];\n const pod = Renderer.K8sApi.podsStore\n .getItems()\n .find((item) =>\n target?.kind === \"Pod\" ? item.metadata.uid === target.uid : item.metadata.uid === first?.podUid,\n );\n const requested = source.startsWith(\"container:\")\n ? source.slice(10)\n : sources.find((item) => sourceKey(item) === source)?.container;\n const defaultContainer = pod?.metadata.annotations?.[\"kubectl.kubernetes.io/default-container\"];\n const container =\n pod?.getAllContainers().find((item) => item.name === (requested ?? defaultContainer)) ??\n pod?.getAllContainers()[0];\n if (pod && container)\n Renderer.Component.logTabStore.createPodTab({ selectedPod: pod, selectedContainer: container });\n else setError(\"Open the Pod in the native resource view to use its Logs action\");\n };\n return (\n <div className=\"power-logs\" data-testid=\"power-logs-page\" data-compact={compact || undefined}>\n <style>{powerLogsStyles}</style>\n <header>\n <h1 className=\"power-logs-page-title\">Power Logs</h1>\n <div\n className=\"power-logs-tabs\"\n role=\"tablist\"\n aria-label=\"Log workspace\"\n onKeyDown={(event) => {\n if (![\"ArrowLeft\", \"ArrowRight\", \"Home\", \"End\"].includes(event.key)) return;\n const tabs = [...event.currentTarget.querySelectorAll<HTMLButtonElement>(\"[role=tab]\")];\n const index = tabs.indexOf(document.activeElement as HTMLButtonElement);\n if (index < 0) return;\n event.preventDefault();\n const next =\n event.key === \"Home\"\n ? 0\n : event.key === \"End\"\n ? tabs.length - 1\n : (index + (event.key === \"ArrowRight\" ? 1 : -1) + tabs.length) % tabs.length;\n tabs[next]?.focus();\n tabs[next]?.click();\n }}\n >\n <button role=\"tab\" aria-selected={tab === \"live\"} onClick={() => setTab(\"live\")}>\n <Icon material=\"subject\" size={16} /> Live view\n </button>\n <button\n role=\"tab\"\n aria-selected={tab === \"captures\"}\n onClick={() => {\n setTab(\"captures\");\n const latest = captures.find(\n (item) => item.state !== \"collecting\" && (!target || item.target.uid === target.uid),\n );\n if (!captureId && latest && !capturePending) {\n setCaptureId(latest.id);\n setSql(examples[0][1]);\n void runQuery(latest, examples[0][1]);\n }\n void refreshCaptures();\n }}\n >\n <Icon material=\"code\" size={16} /> SQL\n </button>\n </div>\n\n <div className=\"power-logs-actions\">\n <div className=\"power-logs-toolbar power-logs-capture\">\n <details ref={captureOptions} className=\"power-logs-options\">\n <summary title={`Capture window: ${captureMinutes} minutes`}>\n <Icon material=\"tune\" size={16} /> Options\n </summary>\n <div>\n {\" \"}\n <label>\n Capture window\n <LogSelect\n label=\"Capture window\"\n value={String(captureMinutes)}\n onChange={(value) => setCaptureMinutes(Number(value))}\n options={[\n { value: \"5\", label: \"5 minutes\" },\n { value: \"15\", label: \"15 minutes\" },\n { value: \"60\", label: \"1 hour\" },\n ]}\n />\n </label>\n <Renderer.Component.Switch checked={previous} onChange={setPrevious}>\n Include previous containers\n </Renderer.Component.Switch>\n <Renderer.Component.Switch\n checked={compact}\n onChange={(value) => {\n setCompact(value);\n preferences.compactRows = value;\n }}\n >\n Compact density\n </Renderer.Component.Switch>\n </div>\n </details>\n {tab === \"captures\" && (\n <button\n type=\"button\"\n disabled={!target || capturePending || busy || !!queryId || deletingCount > 0}\n onClick={() => void capture()}\n >\n <Icon material=\"save_alt\" size={16} /> Capture logs\n </button>\n )}\n {capturePending && (\n <>\n <span role=\"status\" className=\"power-logs-muted\">\n {capturing\n ? `${capturing.rows.toLocaleString()} lines · ${(capturing.bytes / 1048576).toFixed(1)} MiB`\n : \"Preparing capture…\"}\n </span>\n <button type=\"button\" onClick={() => captureController.current?.abort()}>\n <Icon material=\"stop\" size={16} /> Stop & keep partial\n </button>\n </>\n )}\n </div>\n\n <DiagnosticExplainButton aria-label=\"Open AI assistant\" title=\"Open AI assistant\" onClick={attachAi}>\n <Icon material=\"chat_bubble_outline\" size={16} /> AI\n </DiagnosticExplainButton>\n {tab === \"live\" && (\n <button type=\"button\" disabled={!target || busy} onClick={() => void readHistory()}>\n <Icon material=\"refresh\" size={16} /> Refresh\n </button>\n )}\n {target?.kind === \"Pod\" && (\n <button type=\"button\" aria-label=\"Native logs\" title=\"Native logs\" onClick={native}>\n <Renderer.Component.Icon material=\"open_in_new\" size={16} tooltip=\"Native logs\" tooltipOverrideDisabled />\n </button>\n )}\n </div>\n </header>\n {target ? (\n <div\n className=\"power-logs-target power-logs-muted\"\n title={`${target.kind} / ${target.name} · ${target.namespace} · UID ${target.uid}`}\n >\n <strong>\n {target.kind} / {target.name}\n </strong>{\" \"}\n · {target.namespace}\n </div>\n ) : (\n <SourcePicker />\n )}\n {error && (\n <div role=\"alert\" className=\"power-logs-notice power-logs-error\">\n {error}\n </div>\n )}\n {tab === \"live\" ? (\n <>\n <div className=\"power-logs-filters\">\n <input\n aria-label=\"Search log messages\"\n placeholder=\"Search messages…\"\n value={text}\n maxLength={300}\n onChange={(event) => setText(event.target.value)}\n />\n <LogSelect\n label=\"Log level\"\n value={level}\n onChange={setLevel}\n options={[\n { value: \"\", label: \"All levels\" },\n ...levels.map((value) => ({ value, label: value.toUpperCase() })),\n ]}\n />\n <LogSelect\n label=\"Container source\"\n renderOption={(option, context) => {\n if (context !== \"menu\") return <span title={option.label}>{option.label}</span>;\n const item = sources.find((item) => sourceKey(item) === option.value);\n return (\n <span className=\"power-logs-source-option\" title={option.label}>\n <Icon material={item ? \"view_in_ar\" : \"layers\"} size={16} />\n <span className=\"power-logs-option-text\">\n <strong>{item ? item.pod : option.value ? \"All pods\" : option.label}</strong>\n <small>\n {option.value\n ? `Container · ${item?.container ?? option.value.slice(10)}`\n : \"Every pod and container\"}\n {item?.previous ? \" · Previous\" : \"\"}\n </small>\n </span>\n <span className=\"power-logs-source-check\" aria-hidden=\"true\">\n {source === option.value && <Icon material=\"check\" size={16} />}\n </span>\n </span>\n );\n }}\n value={source}\n onChange={setSource}\n options={[\n { value: \"\", label: `All sources (${sources.length})` },\n ...[...new Set(sources.map((item) => item.container))].map((container) => ({\n value: `container:${container}`,\n label: `All pods / ${container}`,\n })),\n ...[...new Set(sources.map(sourceKey))].map((value) => ({ value, label: value })),\n ]}\n />\n <button\n type=\"button\"\n disabled={!sources.length || busy || capturePending}\n aria-pressed={live}\n onClick={toggleLive}\n >\n <Icon material={live ? \"pause\" : \"play_arrow\"} size={16} /> {live ? \"Pause\" : \"Live\"}\n </button>\n <button type=\"button\" aria-pressed={follow} onClick={() => setFollow(!follow)}>\n <Icon material=\"vertical_align_bottom\" size={16} /> Follow tail\n </button>\n {busy && (\n <button onClick={() => historyController.current?.abort()} type=\"button\">\n <Icon material=\"stop\" size={16} /> Stop loading\n </button>\n )}\n </div>\n <div\n className=\"power-logs-muted power-logs-status\"\n role=\"status\"\n title={`${status} · Viewer retains up to ${limits.liveRows.toLocaleString()} lines / ${limits.liveBytes / 1048576} MiB`}\n >\n <span>{filtered.length.toLocaleString()} matching lines</span> · {status}\n {liveCoverage && live ? ` · ${liveCoverage.active}/${liveCoverage.total} active sources` : \"\"} · Viewer\n retains up to {limits.liveRows.toLocaleString()} lines / {limits.liveBytes / 1048576} MiB\n </div>\n <div className=\"power-logs-workspace\">\n <LogRows\n records={filtered}\n selected={selected?.key}\n onSelect={setSelected}\n follow={follow}\n setFollow={setFollow}\n compact={compact}\n />\n {selected && <LogDetails record={selected} onClose={() => setSelected(undefined)} />}\n </div>\n </>\n ) : (\n <>\n <div className=\"power-logs-toolbar power-logs-snapshot-bar\">\n <LogSelect\n label=\"Capture snapshot\"\n onKeyDown={(event) => {\n if (\n event.key !== \"Delete\" ||\n !event.altKey ||\n ((event.target as HTMLInputElement).value ?? \"\").length > 0\n )\n return;\n const button = document.querySelector<HTMLButtonElement>(\n \".Select__menu .Select__option--is-focused [data-capture-delete]\",\n );\n if (button && !button.disabled) {\n event.preventDefault();\n event.stopPropagation();\n void deleteCapture(button.dataset.captureDelete!);\n }\n }}\n renderOption={(option, context) => {\n const item = captures.find((item) => item.id === option.value);\n if (context !== \"menu\" || !item) return option.label;\n return (\n <span className=\"power-logs-snapshot-option\" title={option.label}>\n <span className=\"power-logs-option-text\">\n <strong>{item.target.name}</strong>\n <small>\n {formatDateTime(item.createdAt)} · {item.rows.toLocaleString()} lines ·{\" \"}\n {item.state[0].toUpperCase()}\n {item.state.slice(1)}\n </small>\n </span>\n <button\n type=\"button\"\n aria-label={`Delete snapshot ${item.target.name}`}\n title=\"Delete snapshot (Alt+Delete)\"\n data-capture-delete={item.id}\n onKeyDown={(event) => event.stopPropagation()}\n disabled={!!queryId || capturePending || deletingCount > 0 || item.state === \"collecting\"}\n onMouseDown={(event) => {\n event.preventDefault();\n event.stopPropagation();\n }}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void deleteCapture(item.id);\n }}\n >\n <Renderer.Component.Icon\n material=\"delete_outline\"\n size={16}\n tooltip=\"Delete snapshot\"\n tooltipOverrideDisabled\n />\n </button>\n </span>\n );\n }}\n value={captureId}\n disabled={!!queryId || capturePending || deletingCount > 0}\n onChange={(value) => {\n setCaptureId(value);\n setResult(undefined);\n setResultEvidence(undefined);\n setSelectedSqlRow(undefined);\n const snapshot = captures.find((item) => item.id === value);\n if (snapshot) {\n setSql(examples[0][1]);\n void runQuery(snapshot, examples[0][1]);\n }\n }}\n options={[\n { value: \"\", label: \"Choose a snapshot\" },\n ...captures.map((item) => ({\n value: item.id,\n label: `${item.target.name} · ${formatDateTime(item.createdAt)} · ${item.rows.toLocaleString()} lines · ${item.state[0].toUpperCase()}${item.state.slice(1)}`,\n })),\n ]}\n />\n <button\n type=\"button\"\n disabled={!captureId || !!queryId || deleting.current.has(captureId)}\n title=\"Export JSON Lines (NDJSON)\"\n onClick={() => {\n void client.export(captureId).catch(() => setError(\"Could not export capture\"));\n }}\n >\n <Icon material=\"download\" size={16} /> Export JSON\n </button>\n </div>\n {!!chosenCapture?.notes.length && (\n <details className=\"power-logs-snapshot-notes power-logs-muted\">\n <summary>Snapshot notes ({chosenCapture.notes.length})</summary>\n {chosenCapture.notes.map((note) => (\n <div key={note}>{note}</div>\n ))}\n </details>\n )}\n <div className=\"power-logs-toolbar power-logs-sql-tools\">\n <label\n htmlFor=\"power-logs-sql\"\n title={`Read-only SELECT · ${limits.queryMs / 1000} s · ${limits.resultRows.toLocaleString()} rows · Schema: logs(timestamp INTEGER in milliseconds, pod, podUid, container, level, message, fieldsJson, previous INTEGER 0 or 1)`}\n >\n SQL query\n </label>\n <button\n type=\"button\"\n disabled={\n !chosenCapture ||\n !!queryId ||\n capturePending ||\n deleting.current.has(captureId) ||\n chosenCapture.state === \"collecting\"\n }\n onClick={() => void runQuery()}\n >\n <Icon material=\"play_arrow\" size={16} /> Run query\n </button>\n {queryId && (\n <button\n type=\"button\"\n onClick={() => {\n void client.cancel(queryId).catch(() => setError(\"Could not cancel query\"));\n }}\n >\n <Icon material=\"stop\" size={16} /> Cancel\n </button>\n )}\n {examples.map(([title, query]) => (\n <button type=\"button\" key={title} onClick={() => setSql(query)}>\n <Icon\n material={\n title === \"Recent\"\n ? \"history\"\n : title === \"Errors\"\n ? \"error_outline\"\n : title === \"Timeline\"\n ? \"timeline\"\n : \"data_object\"\n }\n size={16}\n />{\" \"}\n SQL: {title}\n </button>\n ))}\n </div>\n <textarea\n rows={2}\n id=\"power-logs-sql\"\n value={sql}\n maxLength={65536}\n onChange={(event) => setSql(event.target.value)}\n spellCheck={false}\n />\n {result ? (\n <>\n <div className=\"power-logs-toolbar power-logs-results-bar\">\n <span role=\"status\" className=\"power-logs-muted\">\n {result.rows.length} rows · {result.elapsedMs} ms{result.truncated ? \" · Result truncated\" : \"\"}\n </span>\n </div>\n <div className=\"power-logs-workspace\">\n <div className=\"power-logs-results\">\n <table\n style={{\n minWidth:\n result.columns.length > 3\n ? result.columns.reduce((width, column) => width + sqlColumnWidth(column), 0)\n : undefined,\n }}\n >\n <colgroup>\n {result.columns.map((column, i) => (\n <col\n key={i}\n style={{\n width: result.columns.length > 3 ? sqlColumnWidth(column) : undefined,\n }}\n />\n ))}\n </colgroup>\n <thead>\n <tr>\n {result.columns.map((column, i) => (\n <th key={i} data-column={column}>\n {column}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {result.rows.slice(resultPage * 50, (resultPage + 1) * 50).map((row, i) => (\n <tr\n key={i}\n tabIndex={0}\n aria-label={`Open SQL row ${resultPage * 50 + i + 1}`}\n onClick={() => setSelectedSqlRow({ ...sqlRowDetails(result.columns, row), row })}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n setSelectedSqlRow({ ...sqlRowDetails(result.columns, row), row });\n }\n }}\n >\n {row.map((cell, j) => (\n <td\n key={j}\n data-column={result.columns[j]}\n data-level={result.columns[j] === \"level\" ? String(cell) : undefined}\n >\n <span className=\"power-logs-cell\" title={cell === null ? \"NULL\" : String(cell)}>\n {cell === null ? \"NULL\" : String(cell)}\n </span>\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n {result.rows.length === 0 && (\n <div className=\"power-logs-empty\">\n {chosenCapture?.rows === 0\n ? \"This snapshot contains no log lines. Try a longer capture window.\"\n : \"This query returned no rows. Adjust the query or choose SQL: Recent.\"}\n </div>\n )}\n </div>\n {selectedSqlRow && (\n <LogDetails\n record={selectedSqlRow.record}\n jsonColumn={selectedSqlRow.jsonColumn}\n onClose={() => setSelectedSqlRow(undefined)}\n />\n )}\n </div>\n {result.rows.length > 50 && (\n <nav className=\"power-logs-toolbar power-logs-pagination\" aria-label=\"SQL result pages\">\n <button\n type=\"button\"\n aria-label=\"Previous page\"\n title=\"Previous page\"\n disabled={resultPage === 0}\n onClick={() => {\n setResultPage(resultPage - 1);\n setSelectedSqlRow(undefined);\n }}\n >\n <Icon material=\"chevron_left\" size={16} />\n </button>\n <span className=\"power-logs-muted\">\n Page {resultPage + 1} / {Math.max(1, Math.ceil(result.rows.length / 50))}\n </span>\n <button\n type=\"button\"\n aria-label=\"Next page\"\n title=\"Next page\"\n disabled={(resultPage + 1) * 50 >= result.rows.length}\n onClick={() => {\n setResultPage(resultPage + 1);\n setSelectedSqlRow(undefined);\n }}\n >\n <Icon material=\"chevron_right\" size={16} />\n </button>\n </nav>\n )}\n </>\n ) : (\n <div className=\"power-logs-results power-logs-empty\">\n {queryId\n ? \"Running query…\"\n : captures.length === 0\n ? \"Capture logs to create a temporary snapshot for SQL.\"\n : \"Choose a snapshot to preview its logs.\"}\n </div>\n )}\n </>\n )}\n <div className=\"power-logs-muted power-logs-footer\">\n <span\n className=\"power-logs-caption\"\n title={`Gentle collection: ${limits.requestsPerSecond} requests/s, ${limits.bytesPerSecond / 1048576} MiB/s. Captures: ${limits.captureSourceLines.toLocaleString()} lines / ${limits.captureSourceBytes / 1048576} MiB per source, ${limits.captureBytes / 1048576} MiB total. Up to ${limits.captures} snapshots retained for ${limits.ttlMs / 60000} minutes.`}\n >\n Gentle collection · {limits.requestsPerSecond} requests/s · {limits.bytesPerSecond / 1048576} MiB/s · Captures\n limited to {limits.captureSourceLines.toLocaleString()} lines / {limits.captureSourceBytes / 1048576} MiB per\n source and {limits.captureBytes / 1048576} MiB total · Up to {limits.captures} temporary snapshots, retained\n for {limits.ttlMs / 60000} min\n </span>\n {collectionNotes.length > 0 && (\n <span role=\"note\" className=\"power-logs-notice power-logs-collection-note\" title={collectionNotes.join(\"\\n\")}>\n <Icon material=\"warning_amber\" size={14} />\n <span>{collectionNotes.join(\" · \")}</span>\n </span>\n )}\n </div>\n </div>\n );\n}\n\nconst ObservedWorkspace = observer(Workspace);\n\nexport const PowerLogsPage = observer(() => {\n const enabled = LogsPreferencesStore.getInstanceOrCreate<LogsPreferencesStore>().enabled;\n const clusterId = Renderer.Catalog.activeCluster.get()?.metadata.uid;\n if (!enabled || !clusterId)\n return (\n <div className=\"power-logs\">\n <style>{powerLogsStyles}</style>\n <h1>Power Logs</h1>\n <p>Enable Power Logs in Power settings and open a cluster to view logs.</p>\n </div>\n );\n const contextId = searchContextId();\n return <ObservedWorkspace key={`${clusterId}:${contextId}`} clusterId={clusterId} contextId={contextId} />;\n});\n"],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ const require_extensions = require("../_virtual/_global-external_@freelensapp/extensions.js");
2
+ const require__global_external_mobx_react = require("../_virtual/_global-external_mobx-react.js");
3
+ const require_power_logs = require("../src/common/power-logs.js");
4
+ const require_power_logs_limits = require("../src/common/power-logs-limits.js");
5
+ const require_logs_preferences_store = require("../src/common/store/logs-preferences-store.js");
6
+ const require__global_external_react = require("../_virtual/_global-external_react.js");
7
+ const require_jsx_runtime = require("../_virtual/_global-external_react/jsx-runtime.js");
8
+ //#region src/renderer/preferences/logs-preferences.tsx
9
+ var LogLimitInput = require__global_external_mobx_react.observer(function LogLimitInput({ field, preferences }) {
10
+ const scale = field.scale ?? 1;
11
+ const value = preferences.limits[field.key];
12
+ const [draft, setDraft] = require__global_external_react.useState(String(value / scale));
13
+ require__global_external_react.useEffect(() => setDraft(String(value / scale)), [value, scale]);
14
+ const commit = () => {
15
+ const next = draft.trim() === "" ? value : Number(draft) * scale;
16
+ preferences.limits = require_power_logs_limits.normalizePowerLogsLimits({
17
+ ...preferences.limits,
18
+ [field.key]: Number.isFinite(next) ? next : value
19
+ });
20
+ require_power_logs_limits.applyPowerLogsLimits(preferences.limits);
21
+ setDraft(String(preferences.limits[field.key] / scale));
22
+ };
23
+ return /* @__PURE__ */ require_jsx_runtime.jsxs("label", {
24
+ className: "power-log-limit",
25
+ children: [/* @__PURE__ */ require_jsx_runtime.jsx("span", { children: field.label }), /* @__PURE__ */ require_jsx_runtime.jsxs("span", {
26
+ className: "power-log-limit-value",
27
+ children: [/* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Input, {
28
+ "aria-label": `${field.group}: ${field.label}`,
29
+ type: "number",
30
+ value: draft,
31
+ min: field.min / scale,
32
+ max: field.max / scale,
33
+ step: "any",
34
+ onChange: setDraft,
35
+ onBlur: commit,
36
+ onSubmit: commit
37
+ }), /* @__PURE__ */ require_jsx_runtime.jsx("span", { children: field.unit })]
38
+ })]
39
+ });
40
+ });
41
+ var LogsPreferences = require__global_external_mobx_react.observer(() => {
42
+ const preferences = require_logs_preferences_store.LogsPreferencesStore.getInstanceOrCreate();
43
+ return /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
44
+ style: {
45
+ display: "grid",
46
+ gap: 20
47
+ },
48
+ children: [
49
+ /* @__PURE__ */ require_jsx_runtime.jsxs("div", { children: [/* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Switch, {
50
+ checked: preferences.enabled,
51
+ onChange: (value) => {
52
+ preferences.enabled = value;
53
+ },
54
+ children: "Use Power Logs"
55
+ }), /* @__PURE__ */ require_jsx_runtime.jsx("div", {
56
+ className: "power-settings-hint",
57
+ children: "Colored workload logs and temporary SQLite captures for SQL analysis. Native logs return when disabled. Temporary captures follow the retention settings below and are deleted when Power Logs stops."
58
+ })] }),
59
+ /* @__PURE__ */ require_jsx_runtime.jsx("style", { children: `.power-log-limit-groups{display:grid;gap:20px}.power-log-limit-groups fieldset{min-width:0;border:1px solid var(--borderFaintColor);border-radius:6px;padding:16px;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px 20px}.power-log-limit-groups legend{padding:0 6px;color:var(--textColorAccent)}.power-log-limit{display:flex;flex-direction:column;gap:6px;min-width:0}.power-log-limit-value{display:flex;align-items:center;gap:8px;color:var(--textColorSecondary);font-size:12px}.power-log-limit-value .Input{min-width:0;flex:1}.power-log-limit-value input{width:100%;min-width:0}@container power-preferences(max-width:480px){.power-log-limit-groups fieldset{grid-template-columns:1fr}}` }),
60
+ /* @__PURE__ */ require_jsx_runtime.jsx("div", {
61
+ className: "power-settings-hint",
62
+ children: "Changes apply to new requests, captures and SQL queries. Existing captures retain their capacity and expiry."
63
+ }),
64
+ /* @__PURE__ */ require_jsx_runtime.jsx("div", {
65
+ className: "power-log-limit-groups",
66
+ children: [...new Set(require_power_logs_limits.LOG_LIMIT_FIELDS.map((field) => field.group))].map((group) => /* @__PURE__ */ require_jsx_runtime.jsxs("fieldset", { children: [/* @__PURE__ */ require_jsx_runtime.jsx("legend", { children: group }), require_power_logs_limits.LOG_LIMIT_FIELDS.filter((field) => field.group === group).map((field) => /* @__PURE__ */ require_jsx_runtime.jsx(LogLimitInput, {
67
+ field,
68
+ preferences
69
+ }, field.key))] }, group))
70
+ }),
71
+ /* @__PURE__ */ require_jsx_runtime.jsx("div", {
72
+ style: {
73
+ display: "flex",
74
+ justifyContent: "flex-end"
75
+ },
76
+ children: /* @__PURE__ */ require_jsx_runtime.jsxs(require_extensions.Renderer.Component.Button, {
77
+ onClick: () => {
78
+ preferences.limits = { ...require_power_logs.POWER_LOGS_DEFAULT_LIMITS };
79
+ require_power_logs_limits.applyPowerLogsLimits(preferences.limits);
80
+ },
81
+ children: [/* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Icon, {
82
+ material: "restore",
83
+ size: 16
84
+ }), " Reset log limits"]
85
+ })
86
+ })
87
+ ]
88
+ });
89
+ });
90
+ //#endregion
91
+ exports.LogsPreferences = LogsPreferences;
92
+
93
+ //# sourceMappingURL=logs-preferences.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs-preferences.js","names":[],"sources":["../../../src/renderer/preferences/logs-preferences.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { observer } from \"mobx-react\";\nimport { useEffect, useState } from \"react\";\nimport { POWER_LOGS_DEFAULT_LIMITS } from \"../../common/power-logs\";\nimport {\n applyPowerLogsLimits,\n LOG_LIMIT_FIELDS,\n type LogLimitField,\n normalizePowerLogsLimits,\n} from \"../../common/power-logs-limits\";\nimport { LogsPreferencesStore } from \"../../common/store/logs-preferences-store\";\n\nconst LogLimitInput = observer(function LogLimitInput({\n field,\n preferences,\n}: {\n field: LogLimitField;\n preferences: LogsPreferencesStore;\n}) {\n const scale = field.scale ?? 1;\n const value = preferences.limits[field.key];\n const [draft, setDraft] = useState(String(value / scale));\n useEffect(() => setDraft(String(value / scale)), [value, scale]);\n const commit = () => {\n const next = draft.trim() === \"\" ? value : Number(draft) * scale;\n preferences.limits = normalizePowerLogsLimits({\n ...preferences.limits,\n [field.key]: Number.isFinite(next) ? next : value,\n });\n applyPowerLogsLimits(preferences.limits);\n setDraft(String(preferences.limits[field.key] / scale));\n };\n return (\n <label className=\"power-log-limit\">\n <span>{field.label}</span>\n <span className=\"power-log-limit-value\">\n <Renderer.Component.Input\n aria-label={`${field.group}: ${field.label}`}\n type=\"number\"\n value={draft}\n min={field.min / scale}\n max={field.max / scale}\n step=\"any\"\n onChange={setDraft}\n onBlur={commit}\n onSubmit={commit}\n />\n <span>{field.unit}</span>\n </span>\n </label>\n );\n});\n\nexport const LogsPreferences = observer(() => {\n const preferences = LogsPreferencesStore.getInstanceOrCreate<LogsPreferencesStore>();\n return (\n <div style={{ display: \"grid\", gap: 20 }}>\n <div>\n <Renderer.Component.Switch\n checked={preferences.enabled}\n onChange={(value) => {\n preferences.enabled = value;\n }}\n >\n Use Power Logs\n </Renderer.Component.Switch>\n <div className=\"power-settings-hint\">\n Colored workload logs and temporary SQLite captures for SQL analysis. Native logs return when disabled.\n Temporary captures follow the retention settings below and are deleted when Power Logs stops.\n </div>\n </div>\n <style>{`.power-log-limit-groups{display:grid;gap:20px}.power-log-limit-groups fieldset{min-width:0;border:1px solid var(--borderFaintColor);border-radius:6px;padding:16px;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px 20px}.power-log-limit-groups legend{padding:0 6px;color:var(--textColorAccent)}.power-log-limit{display:flex;flex-direction:column;gap:6px;min-width:0}.power-log-limit-value{display:flex;align-items:center;gap:8px;color:var(--textColorSecondary);font-size:12px}.power-log-limit-value .Input{min-width:0;flex:1}.power-log-limit-value input{width:100%;min-width:0}@container power-preferences(max-width:480px){.power-log-limit-groups fieldset{grid-template-columns:1fr}}`}</style>\n <div className=\"power-settings-hint\">\n Changes apply to new requests, captures and SQL queries. Existing captures retain their capacity and expiry.\n </div>\n <div className=\"power-log-limit-groups\">\n {[...new Set(LOG_LIMIT_FIELDS.map((field) => field.group))].map((group) => (\n <fieldset key={group}>\n <legend>{group}</legend>\n {LOG_LIMIT_FIELDS.filter((field) => field.group === group).map((field) => (\n <LogLimitInput key={field.key} field={field} preferences={preferences} />\n ))}\n </fieldset>\n ))}\n </div>\n <div style={{ display: \"flex\", justifyContent: \"flex-end\" }}>\n <Renderer.Component.Button\n onClick={() => {\n preferences.limits = { ...POWER_LOGS_DEFAULT_LIMITS };\n applyPowerLogsLimits(preferences.limits);\n }}\n >\n <Renderer.Component.Icon material=\"restore\" size={16} /> Reset log limits\n </Renderer.Component.Button>\n </div>\n </div>\n );\n});\n"],"mappings":";;;;;;;;AAYA,IAAM,gBAAgB,oCAAA,SAAS,SAAS,cAAc,EACpD,OACA,eAIC;CACD,MAAM,QAAQ,MAAM,SAAS;CAC7B,MAAM,QAAQ,YAAY,OAAO,MAAM;CACvC,MAAM,CAAC,OAAO,YAAY,+BAAA,SAAS,OAAO,QAAQ,KAAK,CAAC;CACxD,+BAAA,gBAAgB,SAAS,OAAO,QAAQ,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,CAAC;CAC/D,MAAM,eAAe;EACnB,MAAM,OAAO,MAAM,KAAK,MAAM,KAAK,QAAQ,OAAO,KAAK,IAAI;EAC3D,YAAY,SAAS,0BAAA,yBAAyB;GAC5C,GAAG,YAAY;IACd,MAAM,MAAM,OAAO,SAAS,IAAI,IAAI,OAAO;EAC9C,CAAC;EACD,0BAAA,qBAAqB,YAAY,MAAM;EACvC,SAAS,OAAO,YAAY,OAAO,MAAM,OAAO,KAAK,CAAC;CACxD;CACA,OACE,oCAAA,KAAC,SAAD;EAAO,WAAU;YAAjB,CACE,oCAAA,IAAC,QAAD,EAAA,UAAO,MAAM,MAAY,CAAA,GACzB,oCAAA,KAAC,QAAD;GAAM,WAAU;aAAhB,CACE,oCAAA,IAAC,mBAAA,SAAS,UAAU,OAApB;IACE,cAAY,GAAG,MAAM,MAAM,IAAI,MAAM;IACrC,MAAK;IACL,OAAO;IACP,KAAK,MAAM,MAAM;IACjB,KAAK,MAAM,MAAM;IACjB,MAAK;IACL,UAAU;IACV,QAAQ;IACR,UAAU;GACX,CAAA,GACD,oCAAA,IAAC,QAAD,EAAA,UAAO,MAAM,KAAW,CAAA,CACpB;IACD;;AAEX,CAAC;AAED,IAAa,kBAAkB,oCAAA,eAAe;CAC5C,MAAM,cAAc,+BAAA,qBAAqB,oBAA0C;CACnF,OACE,oCAAA,KAAC,OAAD;EAAK,OAAO;GAAE,SAAS;GAAQ,KAAK;EAAG;YAAvC;GACE,oCAAA,KAAC,OAAD,EAAA,UAAA,CACE,oCAAA,IAAC,mBAAA,SAAS,UAAU,QAApB;IACE,SAAS,YAAY;IACrB,WAAW,UAAU;KACnB,YAAY,UAAU;IACxB;cACD;GAE0B,CAAA,GAC3B,oCAAA,IAAC,OAAD;IAAK,WAAU;cAAsB;GAGhC,CAAA,CACF,EAAA,CAAA;GACL,oCAAA,IAAC,SAAD,EAAA,UAAQ,8rBAAqsB,CAAA;GAC7sB,oCAAA,IAAC,OAAD;IAAK,WAAU;cAAsB;GAEhC,CAAA;GACL,oCAAA,IAAC,OAAD;IAAK,WAAU;cACZ,CAAC,GAAG,IAAI,IAAI,0BAAA,iBAAiB,KAAK,UAAU,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,UAC/D,oCAAA,KAAC,YAAD,EAAA,UAAA,CACE,oCAAA,IAAC,UAAD,EAAA,UAAS,MAAc,CAAA,GACtB,0BAAA,iBAAiB,QAAQ,UAAU,MAAM,UAAU,KAAK,CAAC,CAAC,KAAK,UAC9D,oCAAA,IAAC,eAAD;KAAsC;KAAoB;IAAc,GAApD,MAAM,GAA8C,CACzE,CACO,EAAA,GALK,KAKL,CACX;GACE,CAAA;GACL,oCAAA,IAAC,OAAD;IAAK,OAAO;KAAE,SAAS;KAAQ,gBAAgB;IAAW;cACxD,oCAAA,KAAC,mBAAA,SAAS,UAAU,QAApB;KACE,eAAe;MACb,YAAY,SAAS,EAAE,GAAG,mBAAA,0BAA0B;MACpD,0BAAA,qBAAqB,YAAY,MAAM;KACzC;eAJF,CAME,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;MAAyB,UAAS;MAAU,MAAM;KAAK,CAAA,GAAC,mBAC/B;;GACxB,CAAA;EACF;;AAET,CAAC"}
@@ -4,6 +4,7 @@ const require_jsx_runtime = require("../_virtual/_global-external_react/jsx-runt
4
4
  const require_ai_preferences = require("./ai-preferences.js");
5
5
  const require_appearance_preferences = require("./appearance-preferences.js");
6
6
  const require_dashboard_preferences = require("./dashboard-preferences.js");
7
+ const require_logs_preferences = require("./logs-preferences.js");
7
8
  const require_monitoring_preferences = require("./monitoring-preferences.js");
8
9
  const require_node_shell_preferences = require("./node-shell-preferences.js");
9
10
  const require_power_preferences = require("./power-preferences.js");
@@ -18,11 +19,11 @@ var styles = `
18
19
  #freelens-power-settings + hr { display: none; }
19
20
  .freelens-power-preferences { display: grid; gap: 24px; max-width: 760px; container: power-preferences / inline-size; }
20
21
  .freelens-power-preferences .power-preferences-section-links {
21
- display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); width: 100%; gap: 8px;
22
+ display:flex; align-items:center; width:100%; gap:8px; overflow-x:auto;
22
23
  }
23
24
  :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link {
24
25
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
25
- width: 100%; min-width: 0; min-height: 32px; padding: 4px 2px;
26
+ flex:1 0 auto; width:auto; min-width:max-content; min-height:32px; padding:4px 2px;
26
27
  border: 0; border-radius: 4px; background: transparent; box-shadow: none;
27
28
  color: var(--textColorSecondary); text-transform: none; white-space: nowrap; cursor: pointer;
28
29
  }
@@ -36,12 +37,7 @@ var styles = `
36
37
  color: var(--primary); background: transparent; box-shadow: none;
37
38
  outline: 2px solid var(--primary); outline-offset: 2px;
38
39
  }
39
- @container power-preferences (max-width: 660px) {
40
- .freelens-power-preferences .power-preferences-section-links { grid-template-columns: repeat(3, minmax(0, 1fr)); }
41
- }
42
- @container power-preferences (max-width: 360px) {
43
- .freelens-power-preferences .power-preferences-section-links { grid-template-columns: repeat(2, minmax(0, 1fr)); }
44
- }
40
+ @container power-preferences (max-width:660px) { .power-preferences-section-links { font-size:12px; } }
45
41
  .freelens-power-preferences section[id] { scroll-margin-top: 16px; }
46
42
  .freelens-power-preferences section {
47
43
  padding: 24px; border: 1px solid var(--borderFaintColor);
@@ -93,9 +89,14 @@ var sectionLinks = [
93
89
  title: "Monitoring",
94
90
  icon: "show_chart"
95
91
  },
92
+ {
93
+ id: "logs",
94
+ title: "Logs",
95
+ icon: "subject"
96
+ },
96
97
  {
97
98
  id: "shell",
98
- title: "Node shell",
99
+ title: "Shell",
99
100
  icon: "vpn_key"
100
101
  },
101
102
  {
@@ -123,6 +124,7 @@ var PowerPreferences = () => /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
123
124
  "aria-label": "Settings sections",
124
125
  children: sectionLinks.map(({ id, title, icon }) => /* @__PURE__ */ require_jsx_runtime.jsxs(require_extensions.Renderer.Component.Button, {
125
126
  className: "power-settings-section-link",
127
+ "aria-label": title,
126
128
  title: `Jump to ${title} settings`,
127
129
  onClick: (event) => {
128
130
  event.preventDefault();
@@ -205,6 +207,18 @@ var PowerPreferences = () => /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
205
207
  }), " Monitoring"]
206
208
  }), /* @__PURE__ */ require_jsx_runtime.jsx(require_monitoring_preferences.MonitoringPreferences, {})]
207
209
  }),
210
+ /* @__PURE__ */ require_jsx_runtime.jsxs("section", {
211
+ id: "freelens-power-logs-section",
212
+ tabIndex: -1,
213
+ "aria-labelledby": "freelens-power-logs-title",
214
+ children: [/* @__PURE__ */ require_jsx_runtime.jsxs("h3", {
215
+ id: "freelens-power-logs-title",
216
+ children: [/* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Icon, {
217
+ material: "subject",
218
+ size: 20
219
+ }), " Power Logs"]
220
+ }), /* @__PURE__ */ require_jsx_runtime.jsx(require_logs_preferences.LogsPreferences, {})]
221
+ }),
208
222
  /* @__PURE__ */ require_jsx_runtime.jsxs("section", {
209
223
  id: "freelens-power-shell-section",
210
224
  tabIndex: -1,
@@ -1 +1 @@
1
- {"version":3,"file":"preferences.js","names":[],"sources":["../../../src/renderer/preferences/preferences.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { EXTENSION_ID } from \"../../common/extension-info\";\nimport { AiPreferences } from \"./ai-preferences\";\nimport { AppearancePreferences } from \"./appearance-preferences\";\nimport { DashboardPreferences } from \"./dashboard-preferences\";\nimport { MonitoringPreferences } from \"./monitoring-preferences\";\nimport { NodeShellPreferences } from \"./node-shell-preferences\";\nimport { PowerPreferencesToggle } from \"./power-preferences\";\nimport { ReadOnlyPreferences } from \"./read-only-preferences\";\nimport { SettingsExport } from \"./settings-export\";\n\nconst styles = `\n .power-preferences-heading { display: flex; align-items: center; justify-content: space-between; gap: 16px; }\n .power-preferences-header-actions { display: inline-flex; margin-left: auto; flex-shrink: 0; }\n #freelens-power-settings > .SubTitle,\n #freelens-power-settings > .hint,\n #freelens-power-settings + hr { display: none; }\n .freelens-power-preferences { display: grid; gap: 24px; max-width: 760px; container: power-preferences / inline-size; }\n .freelens-power-preferences .power-preferences-section-links {\n display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); width: 100%; gap: 8px;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link {\n display: inline-flex; align-items: center; justify-content: center; gap: 6px;\n width: 100%; min-width: 0; min-height: 32px; padding: 4px 2px;\n border: 0; border-radius: 4px; background: transparent; box-shadow: none;\n color: var(--textColorSecondary); text-transform: none; white-space: nowrap; cursor: pointer;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link:hover {\n color: var(--primary); background: transparent; box-shadow: none;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link::before {\n content: none;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link:focus-visible {\n color: var(--primary); background: transparent; box-shadow: none;\n outline: 2px solid var(--primary); outline-offset: 2px;\n }\n @container power-preferences (max-width: 660px) {\n .freelens-power-preferences .power-preferences-section-links { grid-template-columns: repeat(3, minmax(0, 1fr)); }\n }\n @container power-preferences (max-width: 360px) {\n .freelens-power-preferences .power-preferences-section-links { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n }\n .freelens-power-preferences section[id] { scroll-margin-top: 16px; }\n .freelens-power-preferences section {\n padding: 24px; border: 1px solid var(--borderFaintColor);\n border-radius: 12px; background: var(--contentColor);\n }\n .freelens-power-preferences button, .freelens-power-preferences .Button { transition: color 160ms ease, background-color 160ms ease, border-color 160ms ease; }\n :root .freelens-power-preferences button.power-settings-icon-action,\n :root .power-preferences-header-actions button.power-settings-icon-action {\n display: inline-flex; align-items: center; justify-content: center;\n width: 32px; height: 32px; min-width: 32px; padding: 0; flex-shrink: 0;\n border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); cursor: pointer;\n transition: color 160ms ease, background-color 160ms ease;\n }\n :root .freelens-power-preferences button.power-settings-icon-action:not(:disabled):hover,\n :root .power-preferences-header-actions button.power-settings-icon-action:not(:disabled):hover {\n color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent);\n }\n :root .freelens-power-preferences button.power-settings-icon-action:focus-visible,\n :root .power-preferences-header-actions button.power-settings-icon-action:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n :root .freelens-power-preferences button.power-settings-icon-action:disabled,\n :root .power-preferences-header-actions button.power-settings-icon-action:disabled { opacity: 0.4; cursor: default; }\n .freelens-power-preferences h3 {\n display: flex; align-items: center; gap: 10px; margin: 0 0 24px; font-size: 16px; font-weight: 600; color: var(--textColorAccent);\n }\n .freelens-power-preferences label[data-testid=\"switch\"] {\n display: flex; width: 100%; align-items: center; justify-content: space-between;\n }\n .freelens-power-preferences .power-settings-hint {\n margin-top: 6px; font-size: 12px; line-height: 1.5; color: var(--textColorSecondary);\n }\n @media (max-width: 760px) {\n .freelens-power-preferences section { padding: 18px; }\n .freelens-power-preferences .power-settings-row { flex-wrap: wrap; }\n }\n`;\n\nconst sectionLinks = [\n { id: \"safety\", title: \"Safety\", icon: \"lock_outline\" },\n { id: \"appearance\", title: \"Appearance\", icon: \"palette\" },\n { id: \"monitoring\", title: \"Monitoring\", icon: \"show_chart\" },\n { id: \"shell\", title: \"Node shell\", icon: \"vpn_key\" },\n { id: \"ai\", title: \"AI\", icon: \"chat_bubble_outline\" },\n { id: \"dashboard\", title: \"Dashboard\", icon: \"dashboard\" },\n];\n\nexport const PowerPreferences = () => (\n <div className=\"freelens-power-preferences\">\n <style>{styles}</style>\n <SettingsExport />\n <section aria-label=\"Freelens Power\">\n <PowerPreferencesToggle />\n </section>\n <nav className=\"power-preferences-section-links\" aria-label=\"Settings sections\">\n {sectionLinks.map(({ id, title, icon }) => (\n <Renderer.Component.Button\n key={id}\n className=\"power-settings-section-link\"\n title={`Jump to ${title} settings`}\n onClick={(event) => {\n event.preventDefault();\n const section = document.getElementById(`freelens-power-${id}-section`);\n requestAnimationFrame(() => {\n if (!section?.isConnected) return;\n section.focus({ preventScroll: true });\n section.scrollIntoView({ block: \"start\", behavior: \"instant\" });\n });\n }}\n >\n <Renderer.Component.Icon material={icon} size={16} /> {title}\n </Renderer.Component.Button>\n ))}\n </nav>\n <section id=\"freelens-power-safety-section\" tabIndex={-1} aria-labelledby=\"freelens-power-safety-title\">\n <h3 id=\"freelens-power-safety-title\">\n <Renderer.Component.Icon material=\"lock_outline\" size={20} /> Read-only mode\n </h3>\n <ReadOnlyPreferences />\n </section>\n <section id=\"freelens-power-appearance-section\" tabIndex={-1} aria-labelledby=\"freelens-power-appearance-title\">\n <h3 id=\"freelens-power-appearance-title\">\n <Renderer.Component.Icon material=\"palette\" size={20} /> Appearance\n </h3>\n <AppearancePreferences />\n <div style={{ display: \"flex\", justifyContent: \"flex-end\", marginTop: 20 }}>\n <Renderer.Component.Button\n style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}\n onClick={() => Renderer.Navigation.navigate(`/extension/${EXTENSION_ID}/cluster-icons`)}\n title=\"Create matching icons for your saved clusters\"\n >\n <Renderer.Component.Icon material=\"palette\" size={16} /> Cluster icons\n </Renderer.Component.Button>\n </div>\n </section>\n <section id=\"freelens-power-monitoring-section\" tabIndex={-1} aria-labelledby=\"freelens-power-monitoring-title\">\n <h3 id=\"freelens-power-monitoring-title\">\n <Renderer.Component.Icon material=\"show_chart\" size={20} /> Monitoring\n </h3>\n <MonitoringPreferences />\n </section>\n <section id=\"freelens-power-shell-section\" tabIndex={-1} aria-labelledby=\"freelens-power-shell-title\">\n <h3 id=\"freelens-power-shell-title\">\n <Renderer.Component.Icon material=\"vpn_key\" size={20} /> Secure Node Shell\n </h3>\n <NodeShellPreferences />\n </section>\n <section id=\"freelens-power-ai-section\" tabIndex={-1} aria-labelledby=\"freelens-power-ai-title\">\n <h3 id=\"freelens-power-ai-title\">\n <Renderer.Component.Icon material=\"chat_bubble_outline\" size={20} /> AI assistant\n </h3>\n <AiPreferences />\n </section>\n <section id=\"freelens-power-dashboard-section\" tabIndex={-1} aria-labelledby=\"freelens-power-dashboard-title\">\n <h3 id=\"freelens-power-dashboard-title\">\n <Renderer.Component.Icon material=\"dashboard\" size={20} /> Dashboard\n </h3>\n <DashboardPreferences />\n </section>\n </div>\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"preferences.js","names":[],"sources":["../../../src/renderer/preferences/preferences.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { EXTENSION_ID } from \"../../common/extension-info\";\nimport { AiPreferences } from \"./ai-preferences\";\nimport { AppearancePreferences } from \"./appearance-preferences\";\nimport { DashboardPreferences } from \"./dashboard-preferences\";\nimport { LogsPreferences } from \"./logs-preferences\";\nimport { MonitoringPreferences } from \"./monitoring-preferences\";\nimport { NodeShellPreferences } from \"./node-shell-preferences\";\nimport { PowerPreferencesToggle } from \"./power-preferences\";\nimport { ReadOnlyPreferences } from \"./read-only-preferences\";\nimport { SettingsExport } from \"./settings-export\";\n\nconst styles = `\n .power-preferences-heading { display: flex; align-items: center; justify-content: space-between; gap: 16px; }\n .power-preferences-header-actions { display: inline-flex; margin-left: auto; flex-shrink: 0; }\n #freelens-power-settings > .SubTitle,\n #freelens-power-settings > .hint,\n #freelens-power-settings + hr { display: none; }\n .freelens-power-preferences { display: grid; gap: 24px; max-width: 760px; container: power-preferences / inline-size; }\n .freelens-power-preferences .power-preferences-section-links {\n display:flex; align-items:center; width:100%; gap:8px; overflow-x:auto;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link {\n display: inline-flex; align-items: center; justify-content: center; gap: 6px;\n flex:1 0 auto; width:auto; min-width:max-content; min-height:32px; padding:4px 2px;\n border: 0; border-radius: 4px; background: transparent; box-shadow: none;\n color: var(--textColorSecondary); text-transform: none; white-space: nowrap; cursor: pointer;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link:hover {\n color: var(--primary); background: transparent; box-shadow: none;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link::before {\n content: none;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link:focus-visible {\n color: var(--primary); background: transparent; box-shadow: none;\n outline: 2px solid var(--primary); outline-offset: 2px;\n }\n @container power-preferences (max-width:660px) { .power-preferences-section-links { font-size:12px; } }\n .freelens-power-preferences section[id] { scroll-margin-top: 16px; }\n .freelens-power-preferences section {\n padding: 24px; border: 1px solid var(--borderFaintColor);\n border-radius: 12px; background: var(--contentColor);\n }\n .freelens-power-preferences button, .freelens-power-preferences .Button { transition: color 160ms ease, background-color 160ms ease, border-color 160ms ease; }\n :root .freelens-power-preferences button.power-settings-icon-action,\n :root .power-preferences-header-actions button.power-settings-icon-action {\n display: inline-flex; align-items: center; justify-content: center;\n width: 32px; height: 32px; min-width: 32px; padding: 0; flex-shrink: 0;\n border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); cursor: pointer;\n transition: color 160ms ease, background-color 160ms ease;\n }\n :root .freelens-power-preferences button.power-settings-icon-action:not(:disabled):hover,\n :root .power-preferences-header-actions button.power-settings-icon-action:not(:disabled):hover {\n color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent);\n }\n :root .freelens-power-preferences button.power-settings-icon-action:focus-visible,\n :root .power-preferences-header-actions button.power-settings-icon-action:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n :root .freelens-power-preferences button.power-settings-icon-action:disabled,\n :root .power-preferences-header-actions button.power-settings-icon-action:disabled { opacity: 0.4; cursor: default; }\n .freelens-power-preferences h3 {\n display: flex; align-items: center; gap: 10px; margin: 0 0 24px; font-size: 16px; font-weight: 600; color: var(--textColorAccent);\n }\n .freelens-power-preferences label[data-testid=\"switch\"] {\n display: flex; width: 100%; align-items: center; justify-content: space-between;\n }\n .freelens-power-preferences .power-settings-hint {\n margin-top: 6px; font-size: 12px; line-height: 1.5; color: var(--textColorSecondary);\n }\n @media (max-width: 760px) {\n .freelens-power-preferences section { padding: 18px; }\n .freelens-power-preferences .power-settings-row { flex-wrap: wrap; }\n }\n`;\n\nconst sectionLinks = [\n { id: \"safety\", title: \"Safety\", icon: \"lock_outline\" },\n { id: \"appearance\", title: \"Appearance\", icon: \"palette\" },\n { id: \"monitoring\", title: \"Monitoring\", icon: \"show_chart\" },\n { id: \"logs\", title: \"Logs\", icon: \"subject\" },\n { id: \"shell\", title: \"Shell\", icon: \"vpn_key\" },\n { id: \"ai\", title: \"AI\", icon: \"chat_bubble_outline\" },\n { id: \"dashboard\", title: \"Dashboard\", icon: \"dashboard\" },\n];\n\nexport const PowerPreferences = () => (\n <div className=\"freelens-power-preferences\">\n <style>{styles}</style>\n <SettingsExport />\n <section aria-label=\"Freelens Power\">\n <PowerPreferencesToggle />\n </section>\n <nav className=\"power-preferences-section-links\" aria-label=\"Settings sections\">\n {sectionLinks.map(({ id, title, icon }) => (\n <Renderer.Component.Button\n key={id}\n className=\"power-settings-section-link\"\n aria-label={title}\n title={`Jump to ${title} settings`}\n onClick={(event) => {\n event.preventDefault();\n const section = document.getElementById(`freelens-power-${id}-section`);\n requestAnimationFrame(() => {\n if (!section?.isConnected) return;\n section.focus({ preventScroll: true });\n section.scrollIntoView({ block: \"start\", behavior: \"instant\" });\n });\n }}\n >\n <Renderer.Component.Icon material={icon} size={16} /> {title}\n </Renderer.Component.Button>\n ))}\n </nav>\n <section id=\"freelens-power-safety-section\" tabIndex={-1} aria-labelledby=\"freelens-power-safety-title\">\n <h3 id=\"freelens-power-safety-title\">\n <Renderer.Component.Icon material=\"lock_outline\" size={20} /> Read-only mode\n </h3>\n <ReadOnlyPreferences />\n </section>\n <section id=\"freelens-power-appearance-section\" tabIndex={-1} aria-labelledby=\"freelens-power-appearance-title\">\n <h3 id=\"freelens-power-appearance-title\">\n <Renderer.Component.Icon material=\"palette\" size={20} /> Appearance\n </h3>\n <AppearancePreferences />\n <div style={{ display: \"flex\", justifyContent: \"flex-end\", marginTop: 20 }}>\n <Renderer.Component.Button\n style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}\n onClick={() => Renderer.Navigation.navigate(`/extension/${EXTENSION_ID}/cluster-icons`)}\n title=\"Create matching icons for your saved clusters\"\n >\n <Renderer.Component.Icon material=\"palette\" size={16} /> Cluster icons\n </Renderer.Component.Button>\n </div>\n </section>\n <section id=\"freelens-power-monitoring-section\" tabIndex={-1} aria-labelledby=\"freelens-power-monitoring-title\">\n <h3 id=\"freelens-power-monitoring-title\">\n <Renderer.Component.Icon material=\"show_chart\" size={20} /> Monitoring\n </h3>\n <MonitoringPreferences />\n </section>\n <section id=\"freelens-power-logs-section\" tabIndex={-1} aria-labelledby=\"freelens-power-logs-title\">\n <h3 id=\"freelens-power-logs-title\">\n <Renderer.Component.Icon material=\"subject\" size={20} /> Power Logs\n </h3>\n <LogsPreferences />\n </section>\n <section id=\"freelens-power-shell-section\" tabIndex={-1} aria-labelledby=\"freelens-power-shell-title\">\n <h3 id=\"freelens-power-shell-title\">\n <Renderer.Component.Icon material=\"vpn_key\" size={20} /> Secure Node Shell\n </h3>\n <NodeShellPreferences />\n </section>\n <section id=\"freelens-power-ai-section\" tabIndex={-1} aria-labelledby=\"freelens-power-ai-title\">\n <h3 id=\"freelens-power-ai-title\">\n <Renderer.Component.Icon material=\"chat_bubble_outline\" size={20} /> AI assistant\n </h3>\n <AiPreferences />\n </section>\n <section id=\"freelens-power-dashboard-section\" tabIndex={-1} aria-labelledby=\"freelens-power-dashboard-title\">\n <h3 id=\"freelens-power-dashboard-title\">\n <Renderer.Component.Icon material=\"dashboard\" size={20} /> Dashboard\n </h3>\n <DashboardPreferences />\n </section>\n </div>\n);\n"],"mappings":"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"}
@@ -3,10 +3,10 @@ const require__global_external_mobx_react = require("./_virtual/_global-external
3
3
  const require_monitoring_preferences_store = require("./src/common/store/monitoring-preferences-store.js");
4
4
  const require__global_external_react = require("./_virtual/_global-external_react.js");
5
5
  const require_jsx_runtime = require("./_virtual/_global-external_react/jsx-runtime.js");
6
+ const require_resource_search_client = require("./resource-search-client.js");
6
7
  const require_resource_relationships = require("./src/common/resource-relationships.js");
7
8
  const require_gateway_relationships_client = require("./gateway-relationships-client.js");
8
9
  const require_resource_relationships_css = require("./resource-relationships.css.js");
9
- const require_resource_search_client = require("./resource-search-client.js");
10
10
  const require_resource_search_routing = require("./resource-search-routing.js");
11
11
  //#region src/renderer/resource-relationships.tsx
12
12
  var { Icon, Select } = require_extensions.Renderer.Component;
@@ -0,0 +1,114 @@
1
+ const require_power_logs = require("./power-logs.js");
2
+ //#region src/common/power-log-parser.ts
3
+ var ansi = /\x1b(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1b\\))/g;
4
+ var levels = {
5
+ trace: "trace",
6
+ debug: "debug",
7
+ info: "info",
8
+ information: "info",
9
+ warn: "warn",
10
+ warning: "warn",
11
+ error: "error",
12
+ fatal: "fatal",
13
+ critical: "fatal",
14
+ panic: "fatal"
15
+ };
16
+ var pinoLevels = /* @__PURE__ */ new Map([
17
+ [10, "trace"],
18
+ [20, "debug"],
19
+ [30, "info"],
20
+ [40, "warn"],
21
+ [50, "error"],
22
+ [60, "fatal"]
23
+ ]);
24
+ function parseLogLine(line, source) {
25
+ let message = line.replace(ansi, "").replace(/\r$/, "").replace(/\x00/g, "");
26
+ let timestamp = null;
27
+ const prefix = /^(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(?:\.\d{1,9})?(?:Z|[+-]\d\d:\d\d))\s/.exec(message);
28
+ if (prefix) {
29
+ const value = Date.parse(prefix[1]);
30
+ if (Number.isFinite(value)) timestamp = value;
31
+ message = message.slice(prefix[0].length);
32
+ }
33
+ let fieldsJson = null;
34
+ let level = "unknown";
35
+ try {
36
+ const fields = JSON.parse(message);
37
+ if (fields && typeof fields === "object" && !Array.isArray(fields)) {
38
+ const object = fields;
39
+ const rawLevel = object.level ?? object.severity ?? object.loglevel ?? object.log_level;
40
+ if (typeof rawLevel === "string") level = levels[rawLevel.toLowerCase()] ?? "unknown";
41
+ else if (typeof rawLevel === "number") level = pinoLevels.get(rawLevel) ?? "unknown";
42
+ const rawMessage = object.message ?? object.msg ?? object.text;
43
+ if (typeof rawMessage === "string") message = rawMessage.replace(ansi, "").replace(/\x00/g, "");
44
+ const serialized = JSON.stringify(fields);
45
+ if (Buffer.byteLength(serialized) <= require_power_logs.POWER_LOGS_LIMITS.recordBytes / 2) fieldsJson = serialized;
46
+ }
47
+ } catch {}
48
+ if (level === "unknown") {
49
+ const match = /(?:^|[\s\[])\b(trace|debug|info|warn(?:ing)?|error|fatal|critical|panic)\b[\s\]:-]?/i.exec(message);
50
+ if (match) level = levels[match[1].toLowerCase()] ?? "unknown";
51
+ }
52
+ const record = {
53
+ timestamp,
54
+ pod: source.pod,
55
+ podUid: source.podUid,
56
+ container: source.container,
57
+ level,
58
+ message,
59
+ fieldsJson,
60
+ previous: source.previous === true
61
+ };
62
+ const serializedBytes = () => Buffer.byteLength(JSON.stringify(record));
63
+ if (serializedBytes() > require_power_logs.POWER_LOGS_LIMITS.recordBytes && record.fieldsJson !== null) {
64
+ record.fieldsJson = null;
65
+ record.message += " [structured fields omitted]";
66
+ }
67
+ if (serializedBytes() > require_power_logs.POWER_LOGS_LIMITS.recordBytes) {
68
+ const characters = Array.from(record.message);
69
+ let low = 0;
70
+ let high = characters.length;
71
+ while (low < high) {
72
+ const middle = Math.ceil((low + high) / 2);
73
+ record.message = `${characters.slice(0, middle).join("")} [truncated]`;
74
+ if (serializedBytes() <= require_power_logs.POWER_LOGS_LIMITS.recordBytes) low = middle;
75
+ else high = middle - 1;
76
+ }
77
+ record.message = `${characters.slice(0, low).join("")} [truncated]`;
78
+ }
79
+ return record;
80
+ }
81
+ var LogLineDecoder = class {
82
+ decoder = new TextDecoder();
83
+ pending = "";
84
+ dropping = false;
85
+ truncated = false;
86
+ push(chunk, final = false) {
87
+ const text = typeof chunk === "string" ? chunk : this.decoder.decode(chunk, { stream: !final });
88
+ const lines = [];
89
+ for (const part of text.split(/(?<=\n)/)) {
90
+ const ended = part.endsWith("\n");
91
+ if (!this.dropping) this.pending += part;
92
+ if (Buffer.byteLength(this.pending) > require_power_logs.POWER_LOGS_LIMITS.recordBytes) {
93
+ this.pending = "";
94
+ this.dropping = true;
95
+ this.truncated = true;
96
+ }
97
+ if (ended) {
98
+ if (!this.dropping) lines.push(this.pending.replace(/\r?\n$/, ""));
99
+ this.pending = "";
100
+ this.dropping = false;
101
+ }
102
+ }
103
+ if (final && this.pending && !this.dropping) {
104
+ lines.push(this.pending);
105
+ this.pending = "";
106
+ }
107
+ return lines;
108
+ }
109
+ };
110
+ //#endregion
111
+ exports.LogLineDecoder = LogLineDecoder;
112
+ exports.parseLogLine = parseLogLine;
113
+
114
+ //# sourceMappingURL=power-log-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"power-log-parser.js","names":[],"sources":["../../../../src/common/power-log-parser.ts"],"sourcesContent":["import { type LogLevel, type LogRecord, type LogSource, POWER_LOGS_LIMITS } from \"./power-logs\";\n\nconst ansi = /\\x1b(?:\\[[0-?]*[ -/]*[@-~]|\\][^\\x07]*(?:\\x07|\\x1b\\\\))/g;\nconst levels: Record<string, LogLevel> = {\n trace: \"trace\",\n debug: \"debug\",\n info: \"info\",\n information: \"info\",\n warn: \"warn\",\n warning: \"warn\",\n error: \"error\",\n fatal: \"fatal\",\n critical: \"fatal\",\n panic: \"fatal\",\n};\nconst pinoLevels = new Map<number, LogLevel>([\n [10, \"trace\"],\n [20, \"debug\"],\n [30, \"info\"],\n [40, \"warn\"],\n [50, \"error\"],\n [60, \"fatal\"],\n]);\nexport function parseLogLine(line: string, source: LogSource): LogRecord {\n let message = line.replace(ansi, \"\").replace(/\\r$/, \"\").replace(/\\x00/g, \"\");\n let timestamp: number | null = null;\n const prefix = /^(\\d{4}-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d(?:\\.\\d{1,9})?(?:Z|[+-]\\d\\d:\\d\\d))\\s/.exec(message);\n if (prefix) {\n const value = Date.parse(prefix[1]);\n if (Number.isFinite(value)) timestamp = value;\n message = message.slice(prefix[0].length);\n }\n let fieldsJson: string | null = null;\n let level: LogLevel = \"unknown\";\n try {\n const fields: unknown = JSON.parse(message);\n if (fields && typeof fields === \"object\" && !Array.isArray(fields)) {\n const object = fields as Record<string, unknown>;\n const rawLevel = object.level ?? object.severity ?? object.loglevel ?? object.log_level;\n if (typeof rawLevel === \"string\") level = levels[rawLevel.toLowerCase()] ?? \"unknown\";\n else if (typeof rawLevel === \"number\") level = pinoLevels.get(rawLevel) ?? \"unknown\";\n const rawMessage = object.message ?? object.msg ?? object.text;\n if (typeof rawMessage === \"string\") message = rawMessage.replace(ansi, \"\").replace(/\\x00/g, \"\");\n const serialized = JSON.stringify(fields);\n if (Buffer.byteLength(serialized) <= POWER_LOGS_LIMITS.recordBytes / 2) fieldsJson = serialized;\n }\n } catch {\n /* malformed structured lines remain plain text */\n }\n if (level === \"unknown\") {\n const match = /(?:^|[\\s\\[])\\b(trace|debug|info|warn(?:ing)?|error|fatal|critical|panic)\\b[\\s\\]:-]?/i.exec(message);\n if (match) level = levels[match[1].toLowerCase()] ?? \"unknown\";\n }\n const record: LogRecord = {\n timestamp,\n pod: source.pod,\n podUid: source.podUid,\n container: source.container,\n level,\n message,\n fieldsJson,\n previous: source.previous === true,\n };\n const serializedBytes = () => Buffer.byteLength(JSON.stringify(record));\n if (serializedBytes() > POWER_LOGS_LIMITS.recordBytes && record.fieldsJson !== null) {\n record.fieldsJson = null;\n record.message += \" [structured fields omitted]\";\n }\n if (serializedBytes() > POWER_LOGS_LIMITS.recordBytes) {\n const characters = Array.from(record.message);\n let low = 0;\n let high = characters.length;\n while (low < high) {\n const middle = Math.ceil((low + high) / 2);\n record.message = `${characters.slice(0, middle).join(\"\")} [truncated]`;\n if (serializedBytes() <= POWER_LOGS_LIMITS.recordBytes) low = middle;\n else high = middle - 1;\n }\n record.message = `${characters.slice(0, low).join(\"\")} [truncated]`;\n }\n return record;\n}\n\nexport class LogLineDecoder {\n private decoder = new TextDecoder();\n private pending = \"\";\n private dropping = false;\n truncated = false;\n push(chunk: Uint8Array | string, final = false): string[] {\n const text = typeof chunk === \"string\" ? chunk : this.decoder.decode(chunk, { stream: !final });\n const lines: string[] = [];\n for (const part of text.split(/(?<=\\n)/)) {\n const ended = part.endsWith(\"\\n\");\n if (!this.dropping) this.pending += part;\n if (Buffer.byteLength(this.pending) > POWER_LOGS_LIMITS.recordBytes) {\n this.pending = \"\";\n this.dropping = true;\n this.truncated = true;\n }\n if (ended) {\n if (!this.dropping) lines.push(this.pending.replace(/\\r?\\n$/, \"\"));\n this.pending = \"\";\n this.dropping = false;\n }\n }\n if (final && this.pending && !this.dropping) {\n lines.push(this.pending);\n this.pending = \"\";\n }\n return lines;\n }\n}\n"],"mappings":"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"}