From 71e21a30ec136fdc0ef867f8103913aa2b0e9258 Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Mon, 31 Aug 2026 13:26:55 +0200 Subject: [PATCH] fix(agent-manager): clarify browser diagnostics and restore DevTools --- .changeset/agent-manager-browser-context.md | 2 +- .../browser-automation/browser-broker.ts | 16 ++--- .../browser-automation/browser-devtools.ts | 1 - .../tests/fixtures/browser-panel-render.tsx | 35 +++++++++ .../tests/unit/browser-broker.test.ts | 49 +++++++++++-- .../webview-ui/agent-manager/BrowserPanel.tsx | 2 + .../webview-ui/agent-manager/i18n/ar.ts | 5 +- .../webview-ui/agent-manager/i18n/br.ts | 5 +- .../webview-ui/agent-manager/i18n/bs.ts | 5 +- .../webview-ui/agent-manager/i18n/da.ts | 5 +- .../webview-ui/agent-manager/i18n/de.ts | 5 +- .../webview-ui/agent-manager/i18n/en.ts | 5 +- .../webview-ui/agent-manager/i18n/es.ts | 5 +- .../webview-ui/agent-manager/i18n/fa.ts | 4 +- .../webview-ui/agent-manager/i18n/fr.ts | 5 +- .../webview-ui/agent-manager/i18n/it.ts | 5 +- .../webview-ui/agent-manager/i18n/ja.ts | 5 +- .../webview-ui/agent-manager/i18n/ko.ts | 4 +- .../webview-ui/agent-manager/i18n/nl.ts | 5 +- .../webview-ui/agent-manager/i18n/no.ts | 5 +- .../webview-ui/agent-manager/i18n/pl.ts | 5 +- .../webview-ui/agent-manager/i18n/ru.ts | 5 +- .../webview-ui/agent-manager/i18n/th.ts | 5 +- .../webview-ui/agent-manager/i18n/tr.ts | 5 +- .../webview-ui/agent-manager/i18n/uk.ts | 5 +- .../webview-ui/agent-manager/i18n/zh.ts | 4 +- .../webview-ui/agent-manager/i18n/zht.ts | 4 +- .../webview-ui/browser/BrowserPanel.tsx | 71 +++++++++++-------- .../webview-ui/browser/browser.css | 48 ++++++++----- .../kilo-vscode/webview-ui/browser/types.ts | 2 + 30 files changed, 240 insertions(+), 87 deletions(-) diff --git a/.changeset/agent-manager-browser-context.md b/.changeset/agent-manager-browser-context.md index 2362ea4ca8..3701884697 100644 --- a/.changeset/agent-manager-browser-context.md +++ b/.changeset/agent-manager-browser-context.md @@ -3,4 +3,4 @@ "kilo-code": minor --- -Inspect local applications in Agent Manager with embedded developer tools and review-style element feedback for precise frontend changes. +Preview local applications in Agent Manager with embedded developer tools, grouped diagnostics, and review-style element feedback for precise frontend changes. diff --git a/packages/kilo-vscode/src/services/browser-automation/browser-broker.ts b/packages/kilo-vscode/src/services/browser-automation/browser-broker.ts index 08f95818e9..7556fd28c6 100644 --- a/packages/kilo-vscode/src/services/browser-automation/browser-broker.ts +++ b/packages/kilo-vscode/src/services/browser-automation/browser-broker.ts @@ -495,14 +495,6 @@ export class BrowserBroker { entry.response = response.status() } }) - entry.page.on("requestfailed", (request) => { - const target = request.url() - if (this.allowed(entry, target)) return - entry.state.errors++ - entry.state.error = `Blocked browser request: ${new URL(target).origin}` - this.record(entry, entry.state.error) - this.emit(entry.state) - }) entry.page.on("console", (message) => { const type = message.type() if (type === "error") entry.state.errors++ @@ -516,8 +508,7 @@ export class BrowserBroker { }) entry.page.on("popup", (page) => { entry.state.errors++ - entry.state.error = "Blocked browser popup" - this.record(entry, entry.state.error) + this.record(entry, "Blocked browser popup") this.emit(entry.state) void page.close().catch((error: unknown) => this.opts.log("Browser popup close failed", error)) }) @@ -536,6 +527,9 @@ export class BrowserBroker { } const origin = URL.canParse(target) ? new URL(target).origin : "invalid" this.opts.log("Blocked browser request", { sessionId: entry.route.sessionId, origin }) + entry.state.errors++ + this.record(entry, `Blocked browser request: ${origin}`) + this.emit(entry.state) await route.abort("blockedbyclient") }) await entry.context.routeWebSocket("**/*", async (socket) => { @@ -547,7 +541,7 @@ export class BrowserBroker { const origin = URL.canParse(target) ? new URL(target).origin : "invalid" this.opts.log("Blocked browser WebSocket", { sessionId: entry.route.sessionId, origin }) entry.state.errors++ - entry.state.error = `Blocked browser request: ${origin}` + this.record(entry, `Blocked browser request: ${origin}`) this.emit(entry.state) await socket.close({ code: 1008, reason: "Blocked browser origin" }) }) diff --git a/packages/kilo-vscode/src/services/browser-automation/browser-devtools.ts b/packages/kilo-vscode/src/services/browser-automation/browser-devtools.ts index 8050e536ca..8edbcc5f5b 100644 --- a/packages/kilo-vscode/src/services/browser-automation/browser-devtools.ts +++ b/packages/kilo-vscode/src/services/browser-automation/browser-devtools.ts @@ -103,7 +103,6 @@ export class BrowserDevtools { this.targets.set(browser, target) const path = `/browser/devtools/${browser}/${secret}` const query = new URLSearchParams({ - can_dock: "false", ws: `127.0.0.1:${this.port}${path}/connect`, }) return `http://127.0.0.1:${this.port}${path}/inspector.html?${query}` diff --git a/packages/kilo-vscode/tests/fixtures/browser-panel-render.tsx b/packages/kilo-vscode/tests/fixtures/browser-panel-render.tsx index c1406f4a39..c3ad9695fb 100644 --- a/packages/kilo-vscode/tests/fixtures/browser-panel-render.tsx +++ b/packages/kilo-vscode/tests/fixtures/browser-panel-render.tsx @@ -16,6 +16,7 @@ Object.assign(globalThis, { ResizeObserver: window.ResizeObserver, Event: window.Event, MouseEvent: window.MouseEvent, + getComputedStyle: window.getComputedStyle.bind(window), requestAnimationFrame: window.requestAnimationFrame.bind(window), cancelAnimationFrame: window.cancelAnimationFrame.bind(window), }) @@ -42,6 +43,8 @@ const [labels, update] = createSignal({ close: "Close", inspect: "Select element", devtoolsTitle: "Developer tools", + diagnostics: "Browser diagnostics", + diagnosticsHint: "Recent events from the automation browser. Security blocks are not console errors.", empty: "Open a local page", noSession: "Choose a session", screenshotAlt: "Preview", @@ -82,8 +85,11 @@ assert.equal(root.querySelector('[role="alert"]'), null) await window.happyDOM.waitUntilComplete() const frame = root.querySelector(".am-browser-frame") assert.ok(frame) +assert.equal(root.querySelector(".am-browser-site"), null) receive?.({ type: "state", value: { ...state, logs: ["[info] Updated"] } }) assert.equal(root.querySelector(".am-browser-frame"), frame) +assert.equal(root.querySelector(".am-browser-diagnostics button")?.textContent, "Browser diagnostics") +assert.equal(root.querySelector(".am-browser-console"), null) ;(root.querySelector("button[aria-label=Reload]") as HTMLButtonElement).click() assert.deepEqual(sent.at(-1), { type: "refresh", scope }) receive?.({ type: "state", value: { ...state, navigation: 1 } }) @@ -135,8 +141,37 @@ assert.equal(references[0]?.selector, "#save") update((value) => ({ ...value, close: "Fermer" })) await window.happyDOM.waitUntilComplete() assert.ok(root.querySelector("button[aria-label=Fermer]")) +const blocked = "Blocked browser request: http://127.0.0.1:4097" +const other = "Blocked browser request: http://127.0.0.1:4098" +receive?.({ + type: "state", + value: { ...state, navigation: 1, errors: 5, logs: [blocked, blocked, other, blocked, "[error] Failed to load"] }, +}) +assert.equal(root.querySelector('[role="alert"]'), null) +assert.equal(root.querySelector(".am-browser-error-count"), null) +assert.ok(root.querySelector(".am-browser-tools-action button[aria-label='Developer tools']")) +const diagnostics = root.querySelector(".am-browser-diagnostics button") as HTMLButtonElement +assert.equal(diagnostics.textContent, "5 errors") +assert.equal(diagnostics.getAttribute("aria-expanded"), "false") +assert.equal(root.querySelector(".am-browser-console"), null) +diagnostics.click() +await window.happyDOM.waitUntilComplete() +assert.equal(diagnostics.getAttribute("aria-expanded"), "true") +const entries = [...root.querySelectorAll(".am-browser-console-entry")] +assert.equal(entries.length, 3, root.querySelector(".am-browser-diagnostics")?.outerHTML) +assert.equal(entries.at(0)?.textContent, `${blocked}×3`) +assert.equal(entries.at(1)?.textContent, other) +assert.equal(entries.at(2)?.textContent, "[error] Failed to load") +assert.equal(root.querySelector(".am-browser-frame"), refreshed) ;(root.querySelector(".am-browser-tools-action button") as HTMLButtonElement).click() assert.deepEqual(sent.at(-1), { type: "devtools", scope, theme: "light" }) +receive?.({ type: "devtools", value: { scope, browserId: state.browserId, url: "about:blank" } }) +await window.happyDOM.waitUntilComplete() +assert.ok(root.querySelector(".am-browser-devtools-frame")) +assert.equal(root.querySelectorAll(".am-browser-console-entry").length, 3) +assert.equal(diagnostics.getAttribute("aria-expanded"), "true") +receive?.({ type: "state", value: { ...state, navigation: 2 } }) +assert.equal(root.querySelector(".am-browser-diagnostics"), null) ;(root.querySelector("button[aria-label=Fermer]") as HTMLButtonElement).click() assert.equal(closed, 1) assert.deepEqual(sent.at(-1), { type: "close", scope }) diff --git a/packages/kilo-vscode/tests/unit/browser-broker.test.ts b/packages/kilo-vscode/tests/unit/browser-broker.test.ts index 59d8c044dd..8fbd650eed 100644 --- a/packages/kilo-vscode/tests/unit/browser-broker.test.ts +++ b/packages/kilo-vscode/tests/unit/browser-broker.test.ts @@ -284,6 +284,7 @@ describe("BrowserBroker", () => { const second = await broker.devtools("second", "project", "light") expect(first.browserId).not.toBe(second.browserId) expect(first.url).not.toContain(env.KILO_BROWSER_BROKER_TOKEN) + expect(new URL(first.url).searchParams.has("can_dock")).toBe(false) const frontend = await fetch(first.url) expect(frontend.status).toBe(200) expect(await frontend.text()).toContain('') @@ -414,8 +415,9 @@ describe("BrowserBroker", () => { expect(broker.sessions()).toEqual([]) }) - test("keeps browser contexts isolated by session", async () => { + test("keeps browser contexts and HTTP rejection diagnostics isolated by session", async () => { const contexts: Array<{ close: () => Promise }> = [] + const listeners = new Map void>() let routeHandler: | (( route: { continue: () => Promise; abort: () => Promise }, @@ -429,7 +431,9 @@ describe("BrowserBroker", () => { url: () => "http://localhost:3000", title: async () => "Local app", screenshot: async () => Buffer.from("jpeg"), - on: (_type: string, _listener: (...args: never[]) => void) => undefined, + on: (type: string, listener: (value: unknown) => void) => { + listeners.set(type, listener) + }, mainFrame: () => undefined, goto: async () => undefined, } @@ -447,6 +451,7 @@ describe("BrowserBroker", () => { close: async () => undefined, } const broker = new BrowserBroker({ log: () => {}, launch: async () => browser }) + brokers.push(broker) await broker.open({ sessionId: "one", directory: "/tmp/project" }, "http://localhost:3000") await broker.open({ sessionId: "two", directory: "/tmp/project" }, "http://localhost:3000") expect(contexts).toHaveLength(2) @@ -456,12 +461,26 @@ describe("BrowserBroker", () => { { url: () => "http://example.com" }, ) expect(aborted).toBe(true) + const blocked = broker.get("two") + expect(blocked).toMatchObject({ + errors: 1, + logs: ["Blocked browser request: http://example.com"], + error: undefined, + }) + listeners.get("requestfailed")?.({ url: () => "http://example.com" }) + expect(broker.get("two")).toEqual(blocked) + expect(broker.get("one")).toMatchObject({ errors: 0, logs: [], error: undefined }) aborted = false await routeHandler!( { continue: async () => undefined, abort: async () => void (aborted = true) }, { url: () => "data:text/html,", isNavigationRequest: () => true }, ) expect(aborted).toBe(true) + expect(broker.get("two")).toMatchObject({ + errors: 2, + logs: ["Blocked browser request: http://example.com", "Blocked browser request: null"], + error: undefined, + }) await broker.close("one") expect(broker.get("two")?.status).toBe("ready") }) @@ -744,7 +763,7 @@ describe("BrowserBroker", () => { expect(broker.get("feedback", "project")?.logs).toHaveLength(20) }) - test("blocks browser popups instead of opening a second page", async () => { + test("blocks browser popups without replacing navigation failures", async () => { const listeners = new Map void>() const page = { url: () => "http://localhost:3000/", @@ -755,13 +774,26 @@ describe("BrowserBroker", () => { }, mainFrame: () => undefined, goto: async () => undefined, + reload: async () => { + throw new Error("Navigation failed") + }, } const broker = fixture(page) await broker.open({ sessionId: "popup", directory: "/tmp/project" }, "http://localhost:3000/") let closed = false listeners.get("popup")!({ close: async () => void (closed = true) } as never) expect(closed).toBe(true) - expect(broker.get("popup")?.error).toBe("Blocked browser popup") + expect(broker.get("popup")).toMatchObject({ errors: 1, logs: ["Blocked browser popup"], error: undefined }) + await expect(broker.refresh("popup")).rejects.toThrow("Navigation failed") + closed = false + listeners.get("popup")!({ close: async () => void (closed = true) } as never) + expect(closed).toBe(true) + expect(broker.get("popup")).toMatchObject({ + status: "error", + errors: 1, + logs: ["Blocked browser popup"], + error: "Navigation failed", + }) }) test("allows only same-origin WebSockets", async () => { @@ -799,12 +831,19 @@ describe("BrowserBroker", () => { }) expect(connected).toBe(true) expect(closed).toBe(false) + expect(broker.get("socket")).toMatchObject({ errors: 0, logs: [], error: undefined }) + connected = false await handler!({ url: () => "ws://localhost:4000/private", connectToServer: () => void (connected = true), close: async () => void (closed = true), }) + expect(connected).toBe(false) expect(closed).toBe(true) - expect(broker.get("socket")?.error).toBe("Blocked browser request: ws://localhost:4000") + expect(broker.get("socket")).toMatchObject({ + errors: 1, + logs: ["Blocked browser request: ws://localhost:4000"], + error: undefined, + }) }) }) diff --git a/packages/kilo-vscode/webview-ui/agent-manager/BrowserPanel.tsx b/packages/kilo-vscode/webview-ui/agent-manager/BrowserPanel.tsx index 744bb79dca..ca32da4a15 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/BrowserPanel.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/BrowserPanel.tsx @@ -143,6 +143,8 @@ function BrowserAdapter(props: { close: language.t("agentManager.browser.close"), inspect: language.t("agentManager.browser.inspect"), devtoolsTitle: language.t("agentManager.browser.devtoolsTitle"), + diagnostics: language.t("agentManager.browser.diagnostics"), + diagnosticsHint: language.t("agentManager.browser.diagnosticsHint"), empty: language.t("agentManager.browser.empty"), noSession: language.t("agentManager.browser.noSession"), screenshotAlt: language.t("agentManager.browser.screenshotAlt"), diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ar.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ar.ts index 562f0259b3..efb0cdd7d3 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ar.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ar.ts @@ -253,7 +253,10 @@ export const dict = { "agentManager.browser.empty": "افتح تطبيقًا محليًا لمعاينته هنا.", "agentManager.browser.noSession": "اختر جلسة Agent Manager أولًا.", "agentManager.browser.screenshotAlt": "صفحة المتصفح الحالية", - "agentManager.browser.errors": "{{count}} أخطاء في وحدة التحكم", + "agentManager.browser.errors": "مشكلات المتصفح: {{count}}", + "agentManager.browser.diagnostics": "تشخيص المتصفح", + "agentManager.browser.diagnosticsHint": + "الأحداث الأخيرة من متصفح الأتمتة. عمليات الحظر لأسباب أمنية ليست أخطاء في وحدة التحكم.", "agentManager.pr.error.gh_auth.title": "مصادقة GitHub مطلوبة", "agentManager.pr.error.gh_auth.description": "شغّل 'gh auth login' في الطرفية لاستعادة حالة PR.", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/br.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/br.ts index 2ef9def78c..3d047b4e1f 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/br.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/br.ts @@ -258,7 +258,10 @@ export const dict = { "agentManager.browser.empty": "Abra uma aplicação local para visualizá-la aqui.", "agentManager.browser.noSession": "Selecione primeiro uma sessão do Agent Manager.", "agentManager.browser.screenshotAlt": "Página atual do navegador", - "agentManager.browser.errors": "{{count}} erros do console", + "agentManager.browser.errors": "Problemas do navegador: {{count}}", + "agentManager.browser.diagnostics": "Diagnóstico do navegador", + "agentManager.browser.diagnosticsHint": + "Eventos recentes do navegador de automação. Bloqueios de segurança não são erros do console.", "agentManager.pr.error.gh_auth.title": "Autenticação do GitHub necessária", "agentManager.pr.error.gh_auth.description": "Execute 'gh auth login' no terminal para restaurar o status do PR.", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/bs.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/bs.ts index e6af43db27..975e13a242 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/bs.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/bs.ts @@ -256,7 +256,10 @@ export const dict = { "agentManager.browser.empty": "Otvorite lokalnu aplikaciju da biste je ovdje pregledali.", "agentManager.browser.noSession": "Najprije odaberite sesiju aplikacije Agent Manager.", "agentManager.browser.screenshotAlt": "Trenutna stranica preglednika", - "agentManager.browser.errors": "{{count}} grešaka konzole", + "agentManager.browser.errors": "Problemi preglednika: {{count}}", + "agentManager.browser.diagnostics": "Dijagnostika preglednika", + "agentManager.browser.diagnosticsHint": + "Nedavni događaji iz preglednika za automatizaciju. Sigurnosne blokade nisu greške konzole.", "agentManager.pr.error.gh_auth.title": "Potrebna GitHub autentikacija", "agentManager.pr.error.gh_auth.description": "Pokrenite 'gh auth login' u terminalu da vratite status PR-a.", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/da.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/da.ts index 847b5ac6fc..d78bd7afb5 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/da.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/da.ts @@ -258,7 +258,10 @@ export const dict = { "agentManager.browser.empty": "Åbn en lokal applikation for at få vist en forhåndsvisning her.", "agentManager.browser.noSession": "Vælg først en session i Agent Manager.", "agentManager.browser.screenshotAlt": "Aktuel browserside", - "agentManager.browser.errors": "{{count}} konsolfejl", + "agentManager.browser.errors": "Browserproblemer: {{count}}", + "agentManager.browser.diagnostics": "Browserdiagnostik", + "agentManager.browser.diagnosticsHint": + "Seneste hændelser fra automatiseringsbrowseren. Sikkerhedsblokeringer er ikke konsolfejl.", "agentManager.pr.error.gh_auth.title": "GitHub-godkendelse påkrævet", "agentManager.pr.error.gh_auth.description": "Kør 'gh auth login' i din terminal for at gendanne PR-status.", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/de.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/de.ts index c30338ec29..73f045e45d 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/de.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/de.ts @@ -260,7 +260,10 @@ export const dict = { "agentManager.browser.empty": "Öffnen Sie eine lokale Anwendung, um sie hier in der Vorschau anzuzeigen.", "agentManager.browser.noSession": "Wählen Sie zuerst eine Sitzung im Agent Manager aus.", "agentManager.browser.screenshotAlt": "Aktuelle Browserseite", - "agentManager.browser.errors": "{{count}} Konsolenfehler", + "agentManager.browser.errors": "Browserprobleme: {{count}}", + "agentManager.browser.diagnostics": "Browserdiagnose", + "agentManager.browser.diagnosticsHint": + "Aktuelle Ereignisse aus dem Automatisierungsbrowser. Sicherheitsblockierungen sind keine Konsolenfehler.", "agentManager.pr.error.gh_auth.title": "GitHub-Authentifizierung erforderlich", "agentManager.pr.error.gh_auth.description": diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/en.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/en.ts index 054bdcca10..d531e94fac 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/en.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/en.ts @@ -247,7 +247,10 @@ export const dict = { "agentManager.browser.empty": "Open a local application to preview it here.", "agentManager.browser.noSession": "Select an Agent Manager session first.", "agentManager.browser.screenshotAlt": "Current browser page", - "agentManager.browser.errors": "{{count}} console errors", + "agentManager.browser.errors": "Browser issues: {{count}}", + "agentManager.browser.diagnostics": "Browser diagnostics", + "agentManager.browser.diagnosticsHint": + "Recent events from the automation browser. Security blocks are not console errors.", "agentManager.import.pullRequest": "Pull Request", "agentManager.import.pastePrUrl": "Paste PR URL...", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/es.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/es.ts index 294ab58ee2..7ec2a010c4 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/es.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/es.ts @@ -259,7 +259,10 @@ export const dict = { "agentManager.browser.empty": "Abre una aplicación local para previsualizarla aquí.", "agentManager.browser.noSession": "Selecciona primero una sesión de Agent Manager.", "agentManager.browser.screenshotAlt": "Página actual del navegador", - "agentManager.browser.errors": "{{count}} errores de consola", + "agentManager.browser.errors": "Problemas del navegador: {{count}}", + "agentManager.browser.diagnostics": "Diagnóstico del navegador", + "agentManager.browser.diagnosticsHint": + "Eventos recientes del navegador de automatización. Los bloqueos de seguridad no son errores de consola.", "agentManager.pr.error.gh_auth.title": "Se requiere autenticación de GitHub", "agentManager.pr.error.gh_auth.description": diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/fa.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/fa.ts index 2b513a3926..3356516cfd 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/fa.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/fa.ts @@ -261,7 +261,9 @@ export const dict = { "agentManager.browser.empty": "برای پیش‌نمایش، یک برنامه محلی را باز کنید.", "agentManager.browser.noSession": "ابتدا یک جلسه Agent Manager را انتخاب کنید.", "agentManager.browser.screenshotAlt": "صفحه فعلی مرورگر", - "agentManager.browser.errors": "{{count}} خطای کنسول", + "agentManager.browser.errors": "مشکلات مرورگر: {{count}}", + "agentManager.browser.diagnostics": "عیب‌یابی مرورگر", + "agentManager.browser.diagnosticsHint": "رویدادهای اخیر مرورگر خودکار. مسدودسازی‌های امنیتی خطاهای کنسول نیستند.", "agentManager.pr.error.gh_auth.title": "احراز هویت GitHub لازم است", "agentManager.pr.error.gh_auth.description": "برای بازیابی وضعیت PR، دستور 'gh auth login' را در ترمینال اجرا کنید.", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/fr.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/fr.ts index cb8df1bd07..bbd3595386 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/fr.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/fr.ts @@ -260,7 +260,10 @@ export const dict = { "agentManager.browser.empty": "Ouvrez une application locale pour l'afficher ici en aperçu.", "agentManager.browser.noSession": "Sélectionnez d'abord une session dans Agent Manager.", "agentManager.browser.screenshotAlt": "Page actuelle du navigateur", - "agentManager.browser.errors": "{{count}} erreurs de console", + "agentManager.browser.errors": "Problèmes du navigateur : {{count}}", + "agentManager.browser.diagnostics": "Diagnostics du navigateur", + "agentManager.browser.diagnosticsHint": + "Événements récents du navigateur d'automatisation. Les blocages de sécurité ne sont pas des erreurs de console.", "agentManager.pr.error.gh_auth.title": "Authentification GitHub requise", "agentManager.pr.error.gh_auth.description": diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/it.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/it.ts index 019066beb3..8e0cf1bd54 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/it.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/it.ts @@ -266,7 +266,10 @@ export const dict = { "agentManager.browser.empty": "Apri un'applicazione locale per visualizzarla qui.", "agentManager.browser.noSession": "Seleziona prima una sessione di Agent Manager.", "agentManager.browser.screenshotAlt": "Pagina corrente del browser", - "agentManager.browser.errors": "{{count}} errori della console", + "agentManager.browser.errors": "Problemi del browser: {{count}}", + "agentManager.browser.diagnostics": "Diagnostica del browser", + "agentManager.browser.diagnosticsHint": + "Eventi recenti del browser di automazione. I blocchi di sicurezza non sono errori della console.", "agentManager.pr.error.gh_auth.title": "Autenticazione GitHub richiesta", "agentManager.pr.error.gh_auth.description": diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ja.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ja.ts index f20ae88be7..7066b41e26 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ja.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ja.ts @@ -257,7 +257,10 @@ export const dict = { "agentManager.browser.empty": "ローカルアプリケーションを開くと、ここでプレビューできます。", "agentManager.browser.noSession": "先に Agent Manager セッションを選択してください。", "agentManager.browser.screenshotAlt": "現在のブラウザーページ", - "agentManager.browser.errors": "{{count}} 件のコンソールエラー", + "agentManager.browser.errors": "ブラウザーの問題: {{count}} 件", + "agentManager.browser.diagnostics": "ブラウザー診断", + "agentManager.browser.diagnosticsHint": + "自動操作用ブラウザーの最近のイベントです。セキュリティによるブロックはコンソールエラーではありません。", "agentManager.pr.error.gh_auth.title": "GitHub認証が必要です", "agentManager.pr.error.gh_auth.description": diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ko.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ko.ts index a07f0ffe2c..95ac113b40 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ko.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ko.ts @@ -255,7 +255,9 @@ export const dict = { "agentManager.browser.empty": "로컬 애플리케이션을 열어 여기에서 미리 보세요.", "agentManager.browser.noSession": "먼저 Agent Manager 세션을 선택하세요.", "agentManager.browser.screenshotAlt": "현재 브라우저 페이지", - "agentManager.browser.errors": "{{count}}개 콘솔 오류", + "agentManager.browser.errors": "브라우저 문제: {{count}}개", + "agentManager.browser.diagnostics": "브라우저 진단", + "agentManager.browser.diagnosticsHint": "자동화 브라우저의 최근 이벤트입니다. 보안 차단은 콘솔 오류가 아닙니다.", "agentManager.pr.error.gh_auth.title": "GitHub 인증 필요", "agentManager.pr.error.gh_auth.description": "PR 상태를 복원하려면 터미널에서 'gh auth login'을 실행하세요.", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/nl.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/nl.ts index de22b357bf..5da00dcc63 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/nl.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/nl.ts @@ -263,7 +263,10 @@ export const dict = { "agentManager.browser.empty": "Open een lokale applicatie om deze hier te bekijken.", "agentManager.browser.noSession": "Selecteer eerst een sessie in Agent Manager.", "agentManager.browser.screenshotAlt": "Huidige browserpagina", - "agentManager.browser.errors": "{{count}} consolefouten", + "agentManager.browser.errors": "Browserproblemen: {{count}}", + "agentManager.browser.diagnostics": "Browserdiagnostiek", + "agentManager.browser.diagnosticsHint": + "Recente gebeurtenissen van de automatiseringsbrowser. Beveiligingsblokkeringen zijn geen consolefouten.", "agentManager.pr.error.gh_auth.title": "GitHub-authenticatie vereist", "agentManager.pr.error.gh_auth.description": "Voer 'gh auth login' uit in je terminal om de PR-status te herstellen.", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/no.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/no.ts index 34ad76a6d7..e09e2bbaed 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/no.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/no.ts @@ -255,7 +255,10 @@ export const dict = { "agentManager.browser.empty": "Åpne en lokal applikasjon for å forhåndsvise den her.", "agentManager.browser.noSession": "Velg en økt i Agent Manager først.", "agentManager.browser.screenshotAlt": "Gjeldende nettleserside", - "agentManager.browser.errors": "{{count}} konsollfeil", + "agentManager.browser.errors": "Nettleserproblemer: {{count}}", + "agentManager.browser.diagnostics": "Nettleserdiagnostikk", + "agentManager.browser.diagnosticsHint": + "Nylige hendelser fra automatiseringsnettleseren. Sikkerhetsblokkeringer er ikke konsollfeil.", "agentManager.pr.error.gh_auth.title": "GitHub-autentisering kreves", "agentManager.pr.error.gh_auth.description": "Kjør 'gh auth login' i terminalen for å gjenopprette PR-status.", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/pl.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/pl.ts index f66b4716a6..e45f1b49bc 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/pl.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/pl.ts @@ -256,7 +256,10 @@ export const dict = { "agentManager.browser.empty": "Otwórz lokalną aplikację, aby wyświetlić ją tutaj.", "agentManager.browser.noSession": "Najpierw wybierz sesję aplikacji Agent Manager.", "agentManager.browser.screenshotAlt": "Bieżąca strona przeglądarki", - "agentManager.browser.errors": "{{count}} błędów konsoli", + "agentManager.browser.errors": "Problemy przeglądarki: {{count}}", + "agentManager.browser.diagnostics": "Diagnostyka przeglądarki", + "agentManager.browser.diagnosticsHint": + "Ostatnie zdarzenia z przeglądarki używanej do automatyzacji. Blokady ze względów bezpieczeństwa nie są błędami konsoli.", "agentManager.pr.error.gh_auth.title": "Wymagana autoryzacja GitHub", "agentManager.pr.error.gh_auth.description": "Uruchom 'gh auth login' w terminalu, aby przywrócić status PR.", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ru.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ru.ts index 1aea044417..3ee764f189 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ru.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ru.ts @@ -258,7 +258,10 @@ export const dict = { "agentManager.browser.empty": "Откройте локальное приложение, чтобы просмотреть его здесь.", "agentManager.browser.noSession": "Сначала выберите сеанс Agent Manager.", "agentManager.browser.screenshotAlt": "Текущая страница браузера", - "agentManager.browser.errors": "{{count}} ошибок в консоли", + "agentManager.browser.errors": "Проблемы браузера: {{count}}", + "agentManager.browser.diagnostics": "Диагностика браузера", + "agentManager.browser.diagnosticsHint": + "Последние события из браузера, используемого для автоматизации. Блокировки в целях безопасности не являются ошибками консоли.", "agentManager.pr.error.gh_auth.title": "Требуется аутентификация GitHub", "agentManager.pr.error.gh_auth.description": "Выполните 'gh auth login' в терминале, чтобы восстановить статус PR.", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/th.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/th.ts index 221aec045c..2fe6967c85 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/th.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/th.ts @@ -251,7 +251,10 @@ export const dict = { "agentManager.browser.empty": "เปิดแอปพลิเคชันในเครื่องเพื่อดูตัวอย่างที่นี่", "agentManager.browser.noSession": "เลือกเซสชัน Agent Manager ก่อน", "agentManager.browser.screenshotAlt": "หน้าปัจจุบันของเบราว์เซอร์", - "agentManager.browser.errors": "{{count}} ข้อผิดพลาดในคอนโซล", + "agentManager.browser.errors": "ปัญหาเบราว์เซอร์: {{count}} รายการ", + "agentManager.browser.diagnostics": "การวินิจฉัยเบราว์เซอร์", + "agentManager.browser.diagnosticsHint": + "เหตุการณ์ล่าสุดจากเบราว์เซอร์สำหรับงานอัตโนมัติ การบล็อกเพื่อความปลอดภัยไม่ใช่ข้อผิดพลาดในคอนโซล", "agentManager.pr.error.gh_auth.title": "ต้องยืนยันตัวตน GitHub", "agentManager.pr.error.gh_auth.description": "รันคำสั่ง 'gh auth login' ในเทอร์มินัลเพื่อกู้คืนสถานะ PR", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/tr.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/tr.ts index de869178d0..c455aed808 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/tr.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/tr.ts @@ -265,7 +265,10 @@ export const dict = { "agentManager.browser.empty": "Burada önizlemek için yerel bir uygulama açın.", "agentManager.browser.noSession": "Önce bir Agent Manager oturumu seçin.", "agentManager.browser.screenshotAlt": "Geçerli tarayıcı sayfası", - "agentManager.browser.errors": "{{count}} konsol hatası", + "agentManager.browser.errors": "Tarayıcı sorunları: {{count}}", + "agentManager.browser.diagnostics": "Tarayıcı tanılaması", + "agentManager.browser.diagnosticsHint": + "Otomasyon tarayıcısındaki son olaylar. Güvenlik engellemeleri konsol hatası değildir.", "agentManager.pr.error.gh_auth.title": "GitHub kimlik doğrulaması gerekli", "agentManager.pr.error.gh_auth.description": diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/uk.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/uk.ts index ffbe1f854e..efb3afb666 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/uk.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/uk.ts @@ -266,7 +266,10 @@ export const dict = { "agentManager.browser.empty": "Відкрийте локальну програму, щоб переглянути її тут.", "agentManager.browser.noSession": "Спочатку виберіть сесію Agent Manager.", "agentManager.browser.screenshotAlt": "Поточна сторінка браузера", - "agentManager.browser.errors": "{{count}} помилок консолі", + "agentManager.browser.errors": "Проблеми браузера: {{count}}", + "agentManager.browser.diagnostics": "Діагностика браузера", + "agentManager.browser.diagnosticsHint": + "Останні події з браузера для автоматизації. Блокування з міркувань безпеки не є помилками консолі.", "agentManager.pr.error.gh_auth.title": "Потрібна автентифікація GitHub", "agentManager.pr.error.gh_auth.description": "Виконайте 'gh auth login' у терміналі, щоб відновити статус PR.", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/zh.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/zh.ts index 68c0c4b46f..2350dce4e3 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/zh.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/zh.ts @@ -250,7 +250,9 @@ export const dict = { "agentManager.browser.empty": "打开本地应用以在此处预览。", "agentManager.browser.noSession": "请先选择 Agent Manager 会话。", "agentManager.browser.screenshotAlt": "当前浏览器页面", - "agentManager.browser.errors": "{{count}} 个控制台错误", + "agentManager.browser.errors": "浏览器问题:{{count}}", + "agentManager.browser.diagnostics": "浏览器诊断", + "agentManager.browser.diagnosticsHint": "来自自动化浏览器的近期事件。安全拦截不是控制台错误。", "agentManager.pr.error.gh_auth.title": "需要 GitHub 身份验证", "agentManager.pr.error.gh_auth.description": "在终端中运行 'gh auth login' 以恢复 PR 状态。", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/zht.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/zht.ts index 33064e1af3..a0f95aedb0 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/zht.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/zht.ts @@ -249,7 +249,9 @@ export const dict = { "agentManager.browser.empty": "開啟本機應用程式,即可在此處預覽。", "agentManager.browser.noSession": "請先選取 Agent Manager 工作階段。", "agentManager.browser.screenshotAlt": "目前的瀏覽器頁面", - "agentManager.browser.errors": "{{count}} 個主控台錯誤", + "agentManager.browser.errors": "瀏覽器問題:{{count}}", + "agentManager.browser.diagnostics": "瀏覽器診斷", + "agentManager.browser.diagnosticsHint": "來自自動化瀏覽器的近期事件。安全性封鎖不是主控台錯誤。", "agentManager.pr.error.gh_auth.title": "需要 GitHub 驗證", "agentManager.pr.error.gh_auth.description": "在終端機中執行 'gh auth login' 以還原 PR 狀態。", diff --git a/packages/kilo-vscode/webview-ui/browser/BrowserPanel.tsx b/packages/kilo-vscode/webview-ui/browser/BrowserPanel.tsx index e723d7468f..eb6bbfc648 100644 --- a/packages/kilo-vscode/webview-ui/browser/BrowserPanel.tsx +++ b/packages/kilo-vscode/webview-ui/browser/BrowserPanel.tsx @@ -1,5 +1,6 @@ -import { For, Show, type Accessor, type Component } from "solid-js" +import { For, Show, createMemo, type Accessor, type Component } from "solid-js" import { Card } from "@kilocode/kilo-ui/card" +import { Collapsible } from "@kilocode/kilo-ui/collapsible" import { Icon } from "@kilocode/kilo-ui/icon" import { IconButton } from "@kilocode/kilo-ui/icon-button" import { Spinner } from "@kilocode/kilo-ui/spinner" @@ -28,10 +29,6 @@ const Toolbar: Component<{ active: boolean }> = (props) => { const ready = () => !!props.controller.state()?.url && props.controller.state()?.status !== "closed" - const diagnostics = () => - props.controller.state()?.errors - ? `${props.labels.devtoolsTitle}, ${props.labels.errors(props.controller.state()!.errors)}` - : props.labels.devtoolsTitle return (
@@ -52,11 +49,11 @@ const Toolbar: Component<{ if (props.active && props.controller.url().trim() && !props.controller.loading()) props.controller.open() }} > - + +
- + - 0}> - -
= (props) => ( ) -const Diagnostics: Component<{ logs: string[] }> = (props) => ( - -
- - {(line) => ( -
- {line} +const Diagnostics: Component<{ logs: string[]; errors: number; labels: BrowserLabels }> = (props) => { + const entries = createMemo(() => { + const counts = new Map() + for (const text of props.logs) counts.set(text, (counts.get(text) ?? 0) + 1) + return Array.from(counts, ([text, count]) => ({ text, count })) + }) + return ( + + + + {props.errors ? props.labels.errors(props.errors) : props.labels.diagnostics} + + + +
{props.labels.diagnosticsHint}
+
+ + {(entry) => ( +
+ {entry.text} + 1}> + ×{entry.count} + +
+ )} +
- )} - -
- -) + + + + ) +} export interface BrowserPanelProps { scope: Accessor @@ -278,9 +289,7 @@ export const BrowserPanel: Component = (props) => { {(entry) => }
- - - +
) } diff --git a/packages/kilo-vscode/webview-ui/browser/browser.css b/packages/kilo-vscode/webview-ui/browser/browser.css index 2446ae54b0..e0634a87e6 100644 --- a/packages/kilo-vscode/webview-ui/browser/browser.css +++ b/packages/kilo-vscode/webview-ui/browser/browser.css @@ -74,21 +74,6 @@ flex-shrink: 0; } -.am-browser-error-count { - position: absolute; - top: -3px; - right: -3px; - min-width: 12px; - padding: 0 3px; - font-size: var(--kilo-font-size-11); - line-height: 14px; - color: var(--text-on-accent); - text-align: center; - pointer-events: none; - background: var(--syntax-diff-delete, #da3319); - border-radius: 7px; -} - .am-browser-workspace { display: flex; flex: 1; @@ -193,20 +178,49 @@ transform: none; } +[data-component="collapsible"].am-browser-diagnostics { + flex-shrink: 0; + border-top: 1px solid var(--border-weak-base); + border-radius: 0; +} + +[data-component="collapsible"].am-browser-diagnostics > [data-slot="collapsible-trigger"] { + justify-content: space-between; + padding: 0 12px; +} + +.am-browser-diagnostics [data-slot="collapsible-arrow"] { + opacity: 1; +} + +.am-browser-diagnostics-hint { + padding: 0 12px 4px; + font-size: var(--font-size-small); + color: var(--text-weak); +} + .am-browser-console { max-height: 140px; - padding: 8px 12px; + padding: 4px 12px 8px; overflow: auto; font-family: var(--font-family-mono); font-size: var(--font-size-small); color: var(--text-weak); - border-top: 1px solid var(--border-weak-base); } .am-browser-console-entry { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 8px; overflow-wrap: anywhere; } +.am-browser-console-count { + flex-shrink: 0; + color: var(--text-weak); +} + .am-browser-console-entry[data-level="warning"], .am-browser-console-entry[data-level="warn"] { color: var(--text-warning, #d6a23a); diff --git a/packages/kilo-vscode/webview-ui/browser/types.ts b/packages/kilo-vscode/webview-ui/browser/types.ts index 2775cf9314..254a789282 100644 --- a/packages/kilo-vscode/webview-ui/browser/types.ts +++ b/packages/kilo-vscode/webview-ui/browser/types.ts @@ -82,6 +82,8 @@ export interface BrowserLabels { close: string inspect: string devtoolsTitle: string + diagnostics: string + diagnosticsHint: string empty: string noSession: string screenshotAlt: string