diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b43381e461c..4fb25b899d8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -625,12 +625,6 @@ importers: ui: dependencies: - '@lit-labs/signals': - specifier: ^0.2.0 - version: 0.2.0 - '@lit/context': - specifier: ^1.1.6 - version: 1.1.6 '@noble/ed25519': specifier: 3.0.1 version: 3.0.1 @@ -643,15 +637,6 @@ importers: marked: specifier: ^17.0.4 version: 17.0.4 - signal-polyfill: - specifier: ^0.2.2 - version: 0.2.2 - signal-utils: - specifier: ^0.21.1 - version: 0.21.1(signal-polyfill@0.2.2) - vite: - specifier: 8.0.0 - version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) devDependencies: '@vitest/browser-playwright': specifier: 4.1.0 @@ -662,6 +647,9 @@ importers: playwright: specifier: ^1.58.2 version: 1.58.2 + vite: + specifier: 8.0.0 + version: 8.0.0(@types/node@25.5.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) vitest: specifier: 4.1.0 version: 4.1.0(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(@vitest/browser-playwright@4.1.0)(jsdom@29.0.0(@noble/hashes@2.0.1))(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) diff --git a/ui/package.json b/ui/package.json index 71eb17fe80a..5d514f671cd 100644 --- a/ui/package.json +++ b/ui/package.json @@ -9,20 +9,16 @@ "test": "vitest run --config vitest.config.ts" }, "dependencies": { - "@lit-labs/signals": "^0.2.0", - "@lit/context": "^1.1.6", "@noble/ed25519": "3.0.1", "dompurify": "^3.3.3", "lit": "^3.3.2", - "marked": "^17.0.4", - "signal-polyfill": "^0.2.2", - "signal-utils": "^0.21.1", - "vite": "8.0.0" + "marked": "^17.0.4" }, "devDependencies": { "@vitest/browser-playwright": "4.1.0", "jsdom": "^29.0.0", "playwright": "^1.58.2", + "vite": "8.0.0", "vitest": "4.1.0" } } diff --git a/ui/src/styles/layout.mobile.css b/ui/src/styles/layout.mobile.css index e459bca2bca..6d943253804 100644 --- a/ui/src/styles/layout.mobile.css +++ b/ui/src/styles/layout.mobile.css @@ -249,6 +249,7 @@ .topnav-shell__content { display: none; + width: 100%; } .topbar-nav-toggle { @@ -650,75 +651,3 @@ font-size: 12px; } } - -/* =========================================== - Bottom Tabs (mobile navigation bar) - =========================================== */ - -.bottom-tabs { - display: none; -} - -@media (max-width: 768px) { - .bottom-tabs { - display: flex; - position: fixed; - bottom: 0; - left: 0; - right: 0; - z-index: 60; - background: var(--bg); - border-top: 1px solid var(--border); - padding: 4px 0 calc(4px + env(safe-area-inset-bottom, 0px)); - justify-content: space-around; - align-items: stretch; - } - - .bottom-tab { - display: flex; - flex-direction: column; - align-items: center; - gap: 2px; - flex: 1; - padding: 6px 4px; - border: none; - background: none; - color: var(--muted); - font-size: 10px; - cursor: pointer; - transition: - color var(--duration-fast) ease, - opacity var(--duration-fast) ease; - } - - .bottom-tab__icon { - display: flex; - align-items: center; - justify-content: center; - width: 24px; - height: 24px; - } - - .bottom-tab__icon svg { - width: 20px; - height: 20px; - stroke: currentColor; - fill: none; - stroke-width: 1.5px; - stroke-linecap: round; - stroke-linejoin: round; - } - - .bottom-tab__label { - font-weight: 500; - letter-spacing: 0.01em; - } - - .bottom-tab--active { - color: var(--accent); - } - - .bottom-tab:active { - opacity: 0.7; - } -} diff --git a/ui/src/ui/chat-export.ts b/ui/src/ui/chat-export.ts deleted file mode 100644 index ed5bbf931f8..00000000000 --- a/ui/src/ui/chat-export.ts +++ /dev/null @@ -1 +0,0 @@ -export { exportChatMarkdown } from "./chat/export.ts"; diff --git a/ui/src/ui/data/moonshot-kimi-k2.ts b/ui/src/ui/data/moonshot-kimi-k2.ts deleted file mode 100644 index f9aa8d1311e..00000000000 --- a/ui/src/ui/data/moonshot-kimi-k2.ts +++ /dev/null @@ -1,45 +0,0 @@ -export const MOONSHOT_KIMI_K2_DEFAULT_ID = "kimi-k2.5"; -export const MOONSHOT_KIMI_K2_CONTEXT_WINDOW = 256000; -export const MOONSHOT_KIMI_K2_MAX_TOKENS = 8192; -export const MOONSHOT_KIMI_K2_INPUT = ["text"] as const; -export const MOONSHOT_KIMI_K2_COST = { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, -} as const; - -export const MOONSHOT_KIMI_K2_MODELS = [ - { - id: "kimi-k2.5", - name: "Kimi K2.5", - alias: "Kimi K2.5", - reasoning: false, - }, - { - id: "kimi-k2-0905-preview", - name: "Kimi K2 0905 Preview", - alias: "Kimi K2", - reasoning: false, - }, - { - id: "kimi-k2-turbo-preview", - name: "Kimi K2 Turbo", - alias: "Kimi K2 Turbo", - reasoning: false, - }, - { - id: "kimi-k2-thinking", - name: "Kimi K2 Thinking", - alias: "Kimi K2 Thinking", - reasoning: true, - }, - { - id: "kimi-k2-thinking-turbo", - name: "Kimi K2 Thinking Turbo", - alias: "Kimi K2 Thinking Turbo", - reasoning: true, - }, -] as const; - -export type MoonshotKimiK2Model = (typeof MOONSHOT_KIMI_K2_MODELS)[number]; diff --git a/ui/src/ui/tool-labels.ts b/ui/src/ui/tool-labels.ts deleted file mode 100644 index e4818c49362..00000000000 --- a/ui/src/ui/tool-labels.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Map raw tool names to human-friendly labels for the chat UI. - * Unknown tools are title-cased with underscores replaced by spaces. - */ - -export const TOOL_LABELS: Record = { - exec: "Run Command", - bash: "Run Command", - read: "Read File", - write: "Write File", - edit: "Edit File", - apply_patch: "Apply Patch", - web_search: "Web Search", - web_fetch: "Fetch Page", - browser: "Browser", - message: "Send Message", - image: "Generate Image", - canvas: "Canvas", - cron: "Cron", - gateway: "Gateway", - nodes: "Nodes", - memory_search: "Search Memory", - memory_get: "Get Memory", - session_status: "Session Status", - sessions_list: "List Sessions", - sessions_history: "Session History", - sessions_send: "Send to Session", - sessions_spawn: "Spawn Session", - agents_list: "List Agents", -}; - -export function friendlyToolName(raw: string): string { - const mapped = TOOL_LABELS[raw]; - if (mapped) { - return mapped; - } - // Title-case fallback: "some_tool_name" → "Some Tool Name" - return raw.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()); -} diff --git a/ui/src/ui/views/bottom-tabs.ts b/ui/src/ui/views/bottom-tabs.ts deleted file mode 100644 index b8dfbebf39c..00000000000 --- a/ui/src/ui/views/bottom-tabs.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { html } from "lit"; -import { icons } from "../icons.ts"; -import type { Tab } from "../navigation.ts"; - -export type BottomTabsProps = { - activeTab: Tab; - onTabChange: (tab: Tab) => void; -}; - -const BOTTOM_TABS: Array<{ id: Tab; label: string; icon: keyof typeof icons }> = [ - { id: "overview", label: "Dashboard", icon: "barChart" }, - { id: "chat", label: "Chat", icon: "messageSquare" }, - { id: "sessions", label: "Sessions", icon: "fileText" }, - { id: "config", label: "Settings", icon: "settings" }, -]; - -export function renderBottomTabs(props: BottomTabsProps) { - return html` - - `; -} diff --git a/ui/src/ui/views/config-search.node.test.ts b/ui/src/ui/views/config-search.node.test.ts deleted file mode 100644 index d1a5a09d837..00000000000 --- a/ui/src/ui/views/config-search.node.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { - appendTagFilter, - getTagFilters, - hasTagFilter, - removeTagFilter, - replaceTagFilters, - toggleTagFilter, -} from "./config-search.ts"; - -describe("config search tag helper", () => { - it("adds a tag when query is empty", () => { - expect(appendTagFilter("", "security")).toBe("tag:security"); - }); - - it("appends a tag to existing text query", () => { - expect(appendTagFilter("token", "security")).toBe("token tag:security"); - }); - - it("deduplicates existing tag filters case-insensitively", () => { - expect(appendTagFilter("token tag:Security", "security")).toBe("token tag:Security"); - }); - - it("detects exact tag terms", () => { - expect(hasTagFilter("tag:security token", "security")).toBe(true); - expect(hasTagFilter("tag:security-hard token", "security")).toBe(false); - }); - - it("removes only the selected active tag", () => { - expect(removeTagFilter("token tag:security tag:auth", "security")).toBe("token tag:auth"); - }); - - it("toggle removes active tag and keeps text", () => { - expect(toggleTagFilter("token tag:security", "security")).toBe("token"); - }); - - it("toggle adds missing tag", () => { - expect(toggleTagFilter("token", "channels")).toBe("token tag:channels"); - }); - - it("extracts unique normalized tags from query", () => { - expect(getTagFilters("token tag:Security tag:auth tag:security")).toEqual(["security", "auth"]); - }); - - it("replaces only tag filters and preserves free text", () => { - expect(replaceTagFilters("token tag:security mode", ["auth", "channels"])).toBe( - "token mode tag:auth tag:channels", - ); - }); -}); diff --git a/ui/src/ui/views/config-search.ts b/ui/src/ui/views/config-search.ts deleted file mode 100644 index f6973d3a2cd..00000000000 --- a/ui/src/ui/views/config-search.ts +++ /dev/null @@ -1,92 +0,0 @@ -function escapeRegExp(value: string): string { - return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); -} - -function normalizeTag(tag: string): string { - return tag.trim().toLowerCase(); -} - -export function getTagFilters(query: string): string[] { - const seen = new Set(); - const tags: string[] = []; - const pattern = /(^|\s)tag:([^\s]+)/gi; - const raw = query.trim(); - let match: RegExpExecArray | null = pattern.exec(raw); - while (match) { - const normalized = normalizeTag(match[2] ?? ""); - if (normalized && !seen.has(normalized)) { - seen.add(normalized); - tags.push(normalized); - } - match = pattern.exec(raw); - } - return tags; -} - -export function hasTagFilter(query: string, tag: string): boolean { - const normalizedTag = normalizeTag(tag); - if (!normalizedTag) { - return false; - } - const pattern = new RegExp(`(^|\\s)tag:${escapeRegExp(normalizedTag)}(?=\\s|$)`, "i"); - return pattern.test(query.trim()); -} - -export function appendTagFilter(query: string, tag: string): string { - const normalizedTag = normalizeTag(tag); - const trimmed = query.trim(); - if (!normalizedTag) { - return trimmed; - } - if (!trimmed) { - return `tag:${normalizedTag}`; - } - if (hasTagFilter(trimmed, normalizedTag)) { - return trimmed; - } - return `${trimmed} tag:${normalizedTag}`; -} - -export function removeTagFilter(query: string, tag: string): string { - const normalizedTag = normalizeTag(tag); - const trimmed = query.trim(); - if (!normalizedTag || !trimmed) { - return trimmed; - } - const pattern = new RegExp(`(^|\\s)tag:${escapeRegExp(normalizedTag)}(?=\\s|$)`, "ig"); - return trimmed.replace(pattern, " ").replace(/\s+/g, " ").trim(); -} - -export function replaceTagFilters(query: string, tags: readonly string[]): string { - const uniqueTags: string[] = []; - const seen = new Set(); - for (const tag of tags) { - const normalized = normalizeTag(tag); - if (!normalized || seen.has(normalized)) { - continue; - } - seen.add(normalized); - uniqueTags.push(normalized); - } - - const trimmed = query.trim(); - const withoutTags = trimmed - .replace(/(^|\s)tag:([^\s]+)/gi, " ") - .replace(/\s+/g, " ") - .trim(); - const tagTokens = uniqueTags.map((tag) => `tag:${tag}`).join(" "); - if (withoutTags && tagTokens) { - return `${withoutTags} ${tagTokens}`; - } - if (withoutTags) { - return withoutTags; - } - return tagTokens; -} - -export function toggleTagFilter(query: string, tag: string): string { - if (hasTagFilter(query, tag)) { - return removeTagFilter(query, tag); - } - return appendTagFilter(query, tag); -} diff --git a/ui/src/ui/views/overview-quick-actions.ts b/ui/src/ui/views/overview-quick-actions.ts deleted file mode 100644 index b1358ca2e67..00000000000 --- a/ui/src/ui/views/overview-quick-actions.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { html } from "lit"; -import { t } from "../../i18n/index.ts"; -import { icons } from "../icons.ts"; - -export type OverviewQuickActionsProps = { - onNavigate: (tab: string) => void; - onRefresh: () => void; -}; - -export function renderOverviewQuickActions(props: OverviewQuickActionsProps) { - return html` -
- - - - -
- `; -}