@elizaos/app-core 2.0.0-alpha.54 → 2.0.0-alpha.55

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.
@@ -1 +1 @@
1
- {"version":3,"file":"AdvancedPageView.d.ts","sourceRoot":"","sources":["../../src/components/AdvancedPageView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAqOH,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,2CAwHvE"}
1
+ {"version":3,"file":"AdvancedPageView.d.ts","sourceRoot":"","sources":["../../src/components/AdvancedPageView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAqPH,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,2CA4HvE"}
@@ -18,9 +18,15 @@ import { useState } from "react";
18
18
  import { CustomActionsView } from "./CustomActionsView";
19
19
  import { FineTuningView } from "./FineTuningView";
20
20
  import { LifoSandboxView } from "./LifoSandboxView";
21
+ import { SecurityPageView } from "./SecurityPageView";
21
22
  import { TrajectoriesView } from "./TrajectoriesView";
22
23
  import { TrajectoryDetailView } from "./TrajectoryDetailView";
23
24
  const SUB_TABS = [
25
+ {
26
+ id: "actions",
27
+ label: "Actions",
28
+ description: "Custom agent commands and workflows",
29
+ },
24
30
  { id: "plugins", label: "Plugins", description: "Features and connectors" },
25
31
  { id: "skills", label: "Skills", description: "Custom agent skills" },
26
32
  // {
@@ -49,6 +55,11 @@ const SUB_TABS = [
49
55
  // description: "Browser-native shell sandbox and file explorer",
50
56
  // },
51
57
  { id: "logs", label: "Logs", description: "Runtime and service logs" },
58
+ {
59
+ id: "security",
60
+ label: "Security",
61
+ description: "Audit trail for privileged runtime activity",
62
+ },
52
63
  ];
53
64
  const MODAL_SUB_TABS = SUB_TABS.filter((t) => t.id !== "plugins" && t.id !== "skills");
54
65
  const SUBTAB_ICONS = {
@@ -63,6 +74,8 @@ const SUBTAB_ICONS = {
63
74
  };
64
75
  function mapTabToSubTab(tab) {
65
76
  switch (tab) {
77
+ case "actions":
78
+ return "actions";
66
79
  case "plugins":
67
80
  return "plugins";
68
81
  case "skills":
@@ -79,6 +92,8 @@ function mapTabToSubTab(tab) {
79
92
  return "lifo";
80
93
  case "logs":
81
94
  return "logs";
95
+ case "security":
96
+ return "security";
82
97
  default:
83
98
  return "plugins";
84
99
  }
@@ -94,6 +109,8 @@ export function AdvancedPageView({ inModal } = {}) {
94
109
  };
95
110
  const renderContent = () => {
96
111
  switch (currentSubTab) {
112
+ case "actions":
113
+ return _jsx(CustomActionsView, {});
97
114
  case "plugins":
98
115
  return _jsx(PluginsPageView, {});
99
116
  case "skills":
@@ -113,8 +130,10 @@ export function AdvancedPageView({ inModal } = {}) {
113
130
  return _jsx(LifoSandboxView, {});
114
131
  case "logs":
115
132
  return _jsx(LogsPageView, {});
133
+ case "security":
134
+ return _jsx(SecurityPageView, {});
116
135
  default:
117
- return inModal ? _jsx(CustomActionsView, {}) : _jsx(PluginsPageView, {});
136
+ return _jsx(PluginsPageView, {});
118
137
  }
119
138
  };
120
139
  return (_jsxs("div", { className: inModal ? "settings-modal-layout" : "flex flex-col h-full min-h-0", children: [inModal ? (_jsx("nav", { className: "settings-icon-sidebar", children: tabs.map((subTab) => (_jsxs("button", { type: "button", className: `advanced-subtab-btn settings-icon-btn ${currentSubTab === subTab.id ? "is-active" : ""}`, onClick: () => handleSubTabChange(subTab.id), title: subTab.description, children: [SUBTAB_ICONS[subTab.id], _jsx("span", { className: "settings-icon-label", children: subTab.label })] }, subTab.id))) })) : (_jsx("div", { className: "mb-4 shrink-0", children: _jsx("div", { className: "flex gap-1 border-b border-border", children: tabs.map((subTab) => {
@@ -0,0 +1,2 @@
1
+ export declare function SecurityPageView(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=SecurityPageView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SecurityPageView.d.ts","sourceRoot":"","sources":["../../src/components/SecurityPageView.tsx"],"names":[],"mappings":"AAgEA,wBAAgB,gBAAgB,4CA0K/B"}
@@ -0,0 +1,81 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from "@elizaos/ui";
3
+ import { useCallback, useEffect, useMemo, useState } from "react";
4
+ import { client, } from "../api";
5
+ import { formatDateTime } from "./format";
6
+ const SEVERITY_OPTIONS = [
7
+ { value: "", label: "All severities" },
8
+ { value: "critical", label: "Critical" },
9
+ { value: "error", label: "Error" },
10
+ { value: "warn", label: "Warn" },
11
+ { value: "info", label: "Info" },
12
+ ];
13
+ const SEVERITY_STYLES = {
14
+ critical: {
15
+ badge: "bg-red-500/15 text-red-300 border-red-500/30",
16
+ tone: "text-red-200",
17
+ },
18
+ error: {
19
+ badge: "bg-orange-500/15 text-orange-200 border-orange-500/30",
20
+ tone: "text-orange-100",
21
+ },
22
+ warn: {
23
+ badge: "bg-amber-500/15 text-amber-200 border-amber-500/30",
24
+ tone: "text-amber-100",
25
+ },
26
+ info: {
27
+ badge: "bg-sky-500/15 text-sky-200 border-sky-500/30",
28
+ tone: "text-sky-100",
29
+ },
30
+ };
31
+ function summarizeCounts(entries) {
32
+ return entries.reduce((counts, entry) => {
33
+ counts[entry.severity] += 1;
34
+ return counts;
35
+ }, {
36
+ critical: 0,
37
+ error: 0,
38
+ warn: 0,
39
+ info: 0,
40
+ });
41
+ }
42
+ function metadataPairs(entry) {
43
+ return Object.entries(entry.metadata ?? {}).map(([key, value]) => [
44
+ key,
45
+ String(value),
46
+ ]);
47
+ }
48
+ export function SecurityPageView() {
49
+ const [entries, setEntries] = useState([]);
50
+ const [totalBuffered, setTotalBuffered] = useState(0);
51
+ const [severity, setSeverity] = useState("");
52
+ const [loading, setLoading] = useState(true);
53
+ const [error, setError] = useState(null);
54
+ const loadAudit = useCallback(async () => {
55
+ setLoading(true);
56
+ setError(null);
57
+ try {
58
+ const response = await client.getSecurityAudit({
59
+ limit: 50,
60
+ severity: severity || undefined,
61
+ });
62
+ setEntries(response.entries);
63
+ setTotalBuffered(response.totalBuffered);
64
+ }
65
+ catch (err) {
66
+ setError(err instanceof Error ? err.message : "Failed to load audit log.");
67
+ }
68
+ finally {
69
+ setLoading(false);
70
+ }
71
+ }, [severity]);
72
+ useEffect(() => {
73
+ void loadAudit();
74
+ }, [loadAudit]);
75
+ const counts = useMemo(() => summarizeCounts(entries), [entries]);
76
+ return (_jsxs("section", { className: "flex h-full flex-col gap-4", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "m-0 text-lg font-bold", children: "Security Audit" }), _jsx("p", { className: "mt-1 text-sm text-[var(--muted)]", children: "Review privileged actions, policy decisions, and runtime security events." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("select", { "aria-label": "Security severity filter", className: "h-9 min-w-40 rounded-xl border border-border bg-bg px-3 text-sm text-txt", value: severity, onChange: (event) => setSeverity(event.target.value), children: SEVERITY_OPTIONS.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.label))) }), _jsx(Button, { type: "button", variant: "outline", size: "sm", className: "h-9 rounded-xl", onClick: () => void loadAudit(), disabled: loading, children: loading ? "Refreshing..." : "Refresh" })] })] }), _jsxs("div", { className: "grid gap-3 sm:grid-cols-2 xl:grid-cols-5", children: [_jsxs("div", { className: "rounded-2xl border border-border/60 bg-card/50 p-4", children: [_jsx("div", { className: "text-xs uppercase tracking-[0.16em] text-muted", children: "Buffered" }), _jsx("div", { className: "mt-2 text-2xl font-semibold", children: totalBuffered })] }), ["critical", "error", "warn", "info"].map((level) => (_jsxs("div", { className: "rounded-2xl border border-border/60 bg-card/50 p-4", children: [_jsx("div", { className: "text-xs uppercase tracking-[0.16em] text-muted", children: level }), _jsx("div", { className: `mt-2 text-2xl font-semibold ${SEVERITY_STYLES[level].tone}`, children: counts[level] })] }, level)))] }), error ? (_jsx("div", { className: "rounded-2xl border border-red-500/30 bg-red-500/10 px-4 py-3 text-sm text-red-200", children: error })) : null, _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto rounded-2xl border border-border/60 bg-card/35", children: loading && entries.length === 0 ? (_jsx("div", { className: "px-4 py-6 text-sm text-[var(--muted)]", children: "Loading security audit..." })) : entries.length === 0 ? (_jsx("div", { className: "px-4 py-6 text-sm text-[var(--muted)]", children: "No security events recorded for the current filter." })) : (_jsx("div", { className: "divide-y divide-border/50", children: entries.map((entry, index) => {
77
+ const metadata = metadataPairs(entry);
78
+ const severityStyle = SEVERITY_STYLES[entry.severity];
79
+ return (_jsxs("article", { className: "px-4 py-4", children: [_jsxs("div", { className: "flex flex-wrap items-start gap-3", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: `rounded-full border px-2 py-0.5 text-[11px] font-semibold uppercase tracking-[0.14em] ${severityStyle.badge}`, children: entry.severity }), _jsx("span", { className: "text-xs text-[var(--muted)]", children: entry.type })] }), _jsx("div", { className: "mt-2 text-sm font-medium text-txt", children: entry.summary })] }), _jsx("div", { className: "text-right text-xs text-[var(--muted)]", children: formatDateTime(entry.timestamp) })] }), entry.traceId ? (_jsxs("div", { className: "mt-2 text-xs text-[var(--muted)]", children: ["Trace:", " ", _jsx("span", { className: "font-mono text-txt", children: entry.traceId })] })) : null, metadata.length > 0 ? (_jsx("dl", { className: "mt-3 grid gap-2 sm:grid-cols-2 xl:grid-cols-3", children: metadata.map(([key, value]) => (_jsxs("div", { className: "rounded-xl border border-border/40 bg-bg/40 px-3 py-2", children: [_jsx("dt", { className: "text-[11px] uppercase tracking-[0.12em] text-muted", children: key }), _jsx("dd", { className: "mt-1 break-all font-mono text-xs text-txt", children: value })] }, `${entry.timestamp}-${key}`))) })) : null] }, `${entry.timestamp}-${entry.type}-${index}`));
80
+ }) })) })] }));
81
+ }
@@ -71,6 +71,7 @@ export * from "./RestartBanner";
71
71
  export * from "./RuntimeView";
72
72
  export * from "./SaveCommandModal";
73
73
  export * from "./SecretsView";
74
+ export * from "./SecurityPageView";
74
75
  export * from "./SettingsView";
75
76
  export * from "./ShellOverlays";
76
77
  export * from "./ShortcutsOverlay";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
@@ -71,6 +71,7 @@ export * from "./RestartBanner";
71
71
  export * from "./RuntimeView";
72
72
  export * from "./SaveCommandModal";
73
73
  export * from "./SecretsView";
74
+ export * from "./SecurityPageView";
74
75
  export * from "./SettingsView";
75
76
  export * from "./ShellOverlays";
76
77
  export * from "./ShortcutsOverlay";
@@ -11,7 +11,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
11
11
  */
12
12
  import { ChevronDown, X } from "lucide-react";
13
13
  import React, { useCallback, useRef, useState } from "react";
14
- import { useApp } from "../state";
14
+ import { useApp } from "../state/useApp";
15
15
  import { resolveDynamic } from "./config-catalog";
16
16
  // ── Action binding helper ──────────────────────────────────────────────
17
17
  /**
@@ -12,7 +12,7 @@ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
12
12
  * - Prompt generation: registry.catalog.prompt() for AI system prompts
13
13
  */
14
14
  import React, { forwardRef, useCallback, useImperativeHandle, useMemo, useState, } from "react";
15
- import { useApp } from "../state";
15
+ import { useApp } from "../state/useApp";
16
16
  import { defaultCatalog, defineRegistry, evaluateShowIf, evaluateVisibility, resolveFields, runValidation, } from "./config-catalog";
17
17
  import { ConfigField } from "./config-field";
18
18
  // ── Group icons ────────────────────────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elizaos/app-core",
3
- "version": "2.0.0-alpha.54",
3
+ "version": "2.0.0-alpha.55",
4
4
  "description": "Shared application core for elizaOS shells and white-label apps.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -68,8 +68,8 @@
68
68
  "@capacitor/haptics": "8.0.0",
69
69
  "@capacitor/keyboard": "8.0.0",
70
70
  "@capacitor/preferences": "^8.0.1",
71
- "@elizaos/autonomous": "2.0.0-alpha.54",
72
- "@elizaos/ui": "2.0.0-alpha.54",
71
+ "@elizaos/autonomous": "2.0.0-alpha.55",
72
+ "@elizaos/ui": "2.0.0-alpha.55",
73
73
  "@lifo-sh/core": "0.4.4",
74
74
  "@lifo-sh/ui": "0.4.2",
75
75
  "@pixiv/three-vrm": "^3.4.5",
@@ -89,5 +89,5 @@
89
89
  "tailwindcss": "^4.1.18",
90
90
  "typescript": "^5.9.3"
91
91
  },
92
- "gitHead": "2a2db284c54c4762fdd996be3c9a68458b6a041b"
92
+ "gitHead": "500b9377b46e9e674d0624b4e964bfd10ae7d9d8"
93
93
  }
@@ -25,10 +25,12 @@ import React, { type ReactNode, useState } from "react";
25
25
  import { CustomActionsView } from "./CustomActionsView";
26
26
  import { FineTuningView } from "./FineTuningView";
27
27
  import { LifoSandboxView } from "./LifoSandboxView";
28
+ import { SecurityPageView } from "./SecurityPageView";
28
29
  import { TrajectoriesView } from "./TrajectoriesView";
29
30
  import { TrajectoryDetailView } from "./TrajectoryDetailView";
30
31
 
31
32
  type SubTab =
33
+ | "actions"
32
34
  | "plugins"
33
35
  | "skills"
34
36
  | "fine-tuning"
@@ -40,6 +42,11 @@ type SubTab =
40
42
  | "security";
41
43
 
42
44
  const SUB_TABS: Array<{ id: SubTab; label: string; description: string }> = [
45
+ {
46
+ id: "actions",
47
+ label: "Actions",
48
+ description: "Custom agent commands and workflows",
49
+ },
43
50
  { id: "plugins", label: "Plugins", description: "Features and connectors" },
44
51
  { id: "skills", label: "Skills", description: "Custom agent skills" },
45
52
  // {
@@ -68,6 +75,11 @@ const SUB_TABS: Array<{ id: SubTab; label: string; description: string }> = [
68
75
  // description: "Browser-native shell sandbox and file explorer",
69
76
  // },
70
77
  { id: "logs", label: "Logs", description: "Runtime and service logs" },
78
+ {
79
+ id: "security",
80
+ label: "Security",
81
+ description: "Audit trail for privileged runtime activity",
82
+ },
71
83
  ];
72
84
 
73
85
  const MODAL_SUB_TABS = SUB_TABS.filter(
@@ -218,6 +230,8 @@ const SUBTAB_ICONS: Record<string, ReactNode> = {
218
230
 
219
231
  function mapTabToSubTab(tab: Tab): SubTab {
220
232
  switch (tab) {
233
+ case "actions":
234
+ return "actions";
221
235
  case "plugins":
222
236
  return "plugins";
223
237
  case "skills":
@@ -234,6 +248,8 @@ function mapTabToSubTab(tab: Tab): SubTab {
234
248
  return "lifo";
235
249
  case "logs":
236
250
  return "logs";
251
+ case "security":
252
+ return "security";
237
253
  default:
238
254
  return "plugins";
239
255
  }
@@ -255,6 +271,8 @@ export function AdvancedPageView({ inModal }: { inModal?: boolean } = {}) {
255
271
 
256
272
  const renderContent = () => {
257
273
  switch (currentSubTab) {
274
+ case "actions":
275
+ return <CustomActionsView />;
258
276
  case "plugins":
259
277
  return <PluginsPageView />;
260
278
  case "skills":
@@ -281,8 +299,10 @@ export function AdvancedPageView({ inModal }: { inModal?: boolean } = {}) {
281
299
  return <LifoSandboxView />;
282
300
  case "logs":
283
301
  return <LogsPageView />;
302
+ case "security":
303
+ return <SecurityPageView />;
284
304
  default:
285
- return inModal ? <CustomActionsView /> : <PluginsPageView />;
305
+ return <PluginsPageView />;
286
306
  }
287
307
  };
288
308
 
@@ -0,0 +1,235 @@
1
+ import { Button } from "@elizaos/ui";
2
+ import { useCallback, useEffect, useMemo, useState } from "react";
3
+ import {
4
+ client,
5
+ type SecurityAuditEntry,
6
+ type SecurityAuditSeverity,
7
+ } from "../api";
8
+ import { formatDateTime } from "./format";
9
+
10
+ const SEVERITY_OPTIONS: Array<{
11
+ value: "" | SecurityAuditSeverity;
12
+ label: string;
13
+ }> = [
14
+ { value: "", label: "All severities" },
15
+ { value: "critical", label: "Critical" },
16
+ { value: "error", label: "Error" },
17
+ { value: "warn", label: "Warn" },
18
+ { value: "info", label: "Info" },
19
+ ];
20
+
21
+ const SEVERITY_STYLES: Record<
22
+ SecurityAuditSeverity,
23
+ { badge: string; tone: string }
24
+ > = {
25
+ critical: {
26
+ badge: "bg-red-500/15 text-red-300 border-red-500/30",
27
+ tone: "text-red-200",
28
+ },
29
+ error: {
30
+ badge: "bg-orange-500/15 text-orange-200 border-orange-500/30",
31
+ tone: "text-orange-100",
32
+ },
33
+ warn: {
34
+ badge: "bg-amber-500/15 text-amber-200 border-amber-500/30",
35
+ tone: "text-amber-100",
36
+ },
37
+ info: {
38
+ badge: "bg-sky-500/15 text-sky-200 border-sky-500/30",
39
+ tone: "text-sky-100",
40
+ },
41
+ };
42
+
43
+ function summarizeCounts(entries: SecurityAuditEntry[]) {
44
+ return entries.reduce<Record<SecurityAuditSeverity, number>>(
45
+ (counts, entry) => {
46
+ counts[entry.severity] += 1;
47
+ return counts;
48
+ },
49
+ {
50
+ critical: 0,
51
+ error: 0,
52
+ warn: 0,
53
+ info: 0,
54
+ },
55
+ );
56
+ }
57
+
58
+ function metadataPairs(entry: SecurityAuditEntry): Array<[string, string]> {
59
+ return Object.entries(entry.metadata ?? {}).map(([key, value]) => [
60
+ key,
61
+ String(value),
62
+ ]);
63
+ }
64
+
65
+ export function SecurityPageView() {
66
+ const [entries, setEntries] = useState<SecurityAuditEntry[]>([]);
67
+ const [totalBuffered, setTotalBuffered] = useState(0);
68
+ const [severity, setSeverity] = useState<"" | SecurityAuditSeverity>("");
69
+ const [loading, setLoading] = useState(true);
70
+ const [error, setError] = useState<string | null>(null);
71
+
72
+ const loadAudit = useCallback(async () => {
73
+ setLoading(true);
74
+ setError(null);
75
+ try {
76
+ const response = await client.getSecurityAudit({
77
+ limit: 50,
78
+ severity: severity || undefined,
79
+ });
80
+ setEntries(response.entries);
81
+ setTotalBuffered(response.totalBuffered);
82
+ } catch (err) {
83
+ setError(err instanceof Error ? err.message : "Failed to load audit log.");
84
+ } finally {
85
+ setLoading(false);
86
+ }
87
+ }, [severity]);
88
+
89
+ useEffect(() => {
90
+ void loadAudit();
91
+ }, [loadAudit]);
92
+
93
+ const counts = useMemo(() => summarizeCounts(entries), [entries]);
94
+
95
+ return (
96
+ <section className="flex h-full flex-col gap-4">
97
+ <div className="flex flex-wrap items-start justify-between gap-3">
98
+ <div>
99
+ <h2 className="m-0 text-lg font-bold">Security Audit</h2>
100
+ <p className="mt-1 text-sm text-[var(--muted)]">
101
+ Review privileged actions, policy decisions, and runtime security
102
+ events.
103
+ </p>
104
+ </div>
105
+ <div className="flex items-center gap-2">
106
+ <select
107
+ aria-label="Security severity filter"
108
+ className="h-9 min-w-40 rounded-xl border border-border bg-bg px-3 text-sm text-txt"
109
+ value={severity}
110
+ onChange={(event) =>
111
+ setSeverity(event.target.value as "" | SecurityAuditSeverity)
112
+ }
113
+ >
114
+ {SEVERITY_OPTIONS.map((option) => (
115
+ <option key={option.label} value={option.value}>
116
+ {option.label}
117
+ </option>
118
+ ))}
119
+ </select>
120
+ <Button
121
+ type="button"
122
+ variant="outline"
123
+ size="sm"
124
+ className="h-9 rounded-xl"
125
+ onClick={() => void loadAudit()}
126
+ disabled={loading}
127
+ >
128
+ {loading ? "Refreshing..." : "Refresh"}
129
+ </Button>
130
+ </div>
131
+ </div>
132
+
133
+ <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-5">
134
+ <div className="rounded-2xl border border-border/60 bg-card/50 p-4">
135
+ <div className="text-xs uppercase tracking-[0.16em] text-muted">
136
+ Buffered
137
+ </div>
138
+ <div className="mt-2 text-2xl font-semibold">{totalBuffered}</div>
139
+ </div>
140
+ {(["critical", "error", "warn", "info"] as const).map((level) => (
141
+ <div
142
+ key={level}
143
+ className="rounded-2xl border border-border/60 bg-card/50 p-4"
144
+ >
145
+ <div className="text-xs uppercase tracking-[0.16em] text-muted">
146
+ {level}
147
+ </div>
148
+ <div
149
+ className={`mt-2 text-2xl font-semibold ${SEVERITY_STYLES[level].tone}`}
150
+ >
151
+ {counts[level]}
152
+ </div>
153
+ </div>
154
+ ))}
155
+ </div>
156
+
157
+ {error ? (
158
+ <div className="rounded-2xl border border-red-500/30 bg-red-500/10 px-4 py-3 text-sm text-red-200">
159
+ {error}
160
+ </div>
161
+ ) : null}
162
+
163
+ <div className="min-h-0 flex-1 overflow-y-auto rounded-2xl border border-border/60 bg-card/35">
164
+ {loading && entries.length === 0 ? (
165
+ <div className="px-4 py-6 text-sm text-[var(--muted)]">
166
+ Loading security audit...
167
+ </div>
168
+ ) : entries.length === 0 ? (
169
+ <div className="px-4 py-6 text-sm text-[var(--muted)]">
170
+ No security events recorded for the current filter.
171
+ </div>
172
+ ) : (
173
+ <div className="divide-y divide-border/50">
174
+ {entries.map((entry, index) => {
175
+ const metadata = metadataPairs(entry);
176
+ const severityStyle = SEVERITY_STYLES[entry.severity];
177
+ return (
178
+ <article
179
+ key={`${entry.timestamp}-${entry.type}-${index}`}
180
+ className="px-4 py-4"
181
+ >
182
+ <div className="flex flex-wrap items-start gap-3">
183
+ <div className="min-w-0 flex-1">
184
+ <div className="flex flex-wrap items-center gap-2">
185
+ <span
186
+ className={`rounded-full border px-2 py-0.5 text-[11px] font-semibold uppercase tracking-[0.14em] ${severityStyle.badge}`}
187
+ >
188
+ {entry.severity}
189
+ </span>
190
+ <span className="text-xs text-[var(--muted)]">
191
+ {entry.type}
192
+ </span>
193
+ </div>
194
+ <div className="mt-2 text-sm font-medium text-txt">
195
+ {entry.summary}
196
+ </div>
197
+ </div>
198
+ <div className="text-right text-xs text-[var(--muted)]">
199
+ {formatDateTime(entry.timestamp)}
200
+ </div>
201
+ </div>
202
+
203
+ {entry.traceId ? (
204
+ <div className="mt-2 text-xs text-[var(--muted)]">
205
+ Trace:{" "}
206
+ <span className="font-mono text-txt">{entry.traceId}</span>
207
+ </div>
208
+ ) : null}
209
+
210
+ {metadata.length > 0 ? (
211
+ <dl className="mt-3 grid gap-2 sm:grid-cols-2 xl:grid-cols-3">
212
+ {metadata.map(([key, value]) => (
213
+ <div
214
+ key={`${entry.timestamp}-${key}`}
215
+ className="rounded-xl border border-border/40 bg-bg/40 px-3 py-2"
216
+ >
217
+ <dt className="text-[11px] uppercase tracking-[0.12em] text-muted">
218
+ {key}
219
+ </dt>
220
+ <dd className="mt-1 break-all font-mono text-xs text-txt">
221
+ {value}
222
+ </dd>
223
+ </div>
224
+ ))}
225
+ </dl>
226
+ ) : null}
227
+ </article>
228
+ );
229
+ })}
230
+ </div>
231
+ )}
232
+ </div>
233
+ </section>
234
+ );
235
+ }
@@ -71,6 +71,7 @@ export * from "./RestartBanner";
71
71
  export * from "./RuntimeView";
72
72
  export * from "./SaveCommandModal";
73
73
  export * from "./SecretsView";
74
+ export * from "./SecurityPageView";
74
75
  export * from "./SettingsView";
75
76
  export * from "./ShellOverlays";
76
77
  export * from "./ShortcutsOverlay";
@@ -11,7 +11,7 @@
11
11
 
12
12
  import { ChevronDown, X } from "lucide-react";
13
13
  import React, { useCallback, useRef, useState } from "react";
14
- import { useApp } from "../state";
14
+ import { useApp } from "../state/useApp";
15
15
  import type { DynamicValue } from "../types";
16
16
  import type { FieldRenderer, FieldRenderProps } from "./config-catalog";
17
17
  import { resolveDynamic } from "./config-catalog";
@@ -18,7 +18,7 @@ import React, {
18
18
  useMemo,
19
19
  useState,
20
20
  } from "react";
21
- import { useApp } from "../state";
21
+ import { useApp } from "../state/useApp";
22
22
  import type { ConfigUiHint, PluginUiTheme } from "../types";
23
23
  import type {
24
24
  FieldRegistry,