Merge pull request #14049 from Kilo-Org/investigate-browser-automation-tool-exposure

fix(vscode): restore Playwright MCP browser tools
This commit is contained in:
Marius
2026-09-16 10:02:36 +02:00
committed by GitHub
68 changed files with 1197 additions and 106 deletions
@@ -0,0 +1,5 @@
---
"kilo-code": patch
---
Restore built-in Playwright browser automation and its settings under Web Tools. Keep the experimental Integrated Browser independent and allow its panel to open before selecting a session.
@@ -94,7 +94,9 @@ Set the `KILO_WEBSEARCH_PROVIDER` environment variable to force a provider:
### Browser Tools
The VS Code extension's experimental `browser_open` tool opens a local application in Agent Manager's Browser panel and returns a screenshot and diagnostics. Enable **Browser Automation** under **Settings > Experimental**. It requires installed Chrome or compatible Playwright Chromium.
The VS Code extension has a built-in browser automation tool powered by [Playwright MCP](https://www.npmjs.com/package/@playwright/mcp). Enable it in **Settings → Web Tools → Browser Automation**. When enabled, it registers an MCP server named `kilo-playwright` and exposes browser tools that follow the same permission model as all MCP tools.
The VS Code extension's experimental `browser_open` tool opens a local application in Agent Manager's Integrated Browser panel and returns a screenshot and diagnostics. Enable **Integrated Browser** under **Settings > Experimental**. It requires installed Chrome or compatible Playwright Chromium. It is independent from Playwright MCP.
The `browser_open` automation browser accepts HTTP URLs on `localhost` or `127.0.0.1` only, and blocks resources from other origins. See [Browser previews](/docs/automate/agent-manager#browser-previews) for setup and element feedback.
@@ -18,6 +18,10 @@ Browser Use requires an advanced agentic model. It is typically most reliable wi
Browser automation is built into the extension and requires no manual setup. Enable it from **Settings → Web Tools → Browser Automation** and Kilo handles the rest automatically.
{% callout type="note" title="Integrated Browser Is Separate" %}
The experimental **Integrated Browser** under **Settings → Experimental** is a different feature. It shows local application previews inside Agent Manager and does not replace Playwright browser automation. The two features have independent settings.
{% /callout %}
{% /tab %}
{% tab label="CLI" %}
+18 -2
View File
@@ -1091,7 +1091,7 @@
"type": "boolean",
"default": false,
"scope": "application",
"description": "Enable the experimental Agent Manager browser panel and browser_open tool."
"description": "Enable the experimental Integrated Browser panel and browser_open tool in Agent Manager."
},
"kilo-code.new.experimental.claudeMigration": {
"type": "boolean",
@@ -1147,10 +1147,26 @@
"maximum": 24,
"description": "Font size in pixels for the Kilo Code webview UI."
},
"kilo-code.new.browserAutomation.enabled": {
"type": "boolean",
"default": false,
"description": "Enable browser automation powered by Playwright. When enabled, the AI agent can interact with web pages in a visible Chrome window."
},
"kilo-code.new.browserAutomation.useSystemChrome": {
"type": "boolean",
"default": true,
"description": "Use system-installed Google Chrome. Disable only when a compatible Playwright Chromium browser is already installed."
"description": "Use your system's installed Chrome browser instead of downloading a separate Chromium instance."
},
"kilo-code.new.browserAutomation.headless": {
"type": "boolean",
"default": false,
"description": "Run browser automation in headless mode (no visible window). When disabled, you can watch the agent interact with the browser."
},
"kilo-code.new.agentManager.browser.useSystemChrome": {
"type": "boolean",
"default": true,
"scope": "application",
"description": "Use system-installed Google Chrome for the Integrated Browser. Disable only when a compatible Playwright Chromium browser is already installed."
},
"kilo-code.new.attention.enabled": {
"type": "boolean",
+12 -1
View File
@@ -58,6 +58,7 @@ import { resolveProjectDirectory } from "./project-directory"
import { seedSessionStatuses } from "./session-status"
import { normalizeEnhancePromptErrorMessage } from "./enhance-prompt-error"
import { retry } from "./services/cli-backend/retry"
import { integratedBrowserUseSystemChrome } from "./services/browser-automation/chrome-setting"
import { removeAgent } from "./services/agent-removal"
import { normalize, type SSEPayload, type SyncPayload, type WirePayload } from "./services/cli-backend/sdk-sse-adapter"
import { slimInfo, slimPart, slimParts } from "./kilo-provider/slim-metadata"
@@ -4078,6 +4079,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
multiProject: this.multiProjectSetting(),
claudeMigration: this.claudeMigrationSetting(),
browserAutomation: this.browserAutomationSetting(),
agentManagerBrowserUseSystemChrome: integratedBrowserUseSystemChrome(),
"agentManager.autoBranchNaming": naming.get<boolean>("autoBranchNaming", true),
"agentManager.branchPrefix": naming.get<string>("branchPrefix", ""),
"agentManager.worktreePool": naming.get<boolean>("worktreePool", true),
@@ -4349,6 +4351,10 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
}
await this.checkpoints.get(sid)
// Wait for Playwright MCP before the prompt so its tools are advertised.
// Kept outside withRetry so retryable prompt errors keep their backoff.
// The Integrated Browser does not use Playwright and is not affected.
await this.connectionService.prepareTools(dir)
await runWithMessageConfirmation(this.confirmations, messageID, "KiloProvider: Message request", () =>
this.withRetry(
() =>
@@ -4435,7 +4441,10 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
source: f.source,
}))
if (!control) await this.checkpoints.get(sid)
if (!control) {
await this.checkpoints.get(sid)
await this.connectionService.prepareTools(dir)
}
const send = () =>
this.client!.session.command({
sessionID: sid,
@@ -4830,7 +4839,9 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
this.postMessage({
type: "browserSettingsLoaded",
settings: {
enabled: config.get<boolean>("enabled", false),
useSystemChrome: config.get<boolean>("useSystemChrome", true),
headless: config.get<boolean>("headless", false),
},
})
}
+24 -4
View File
@@ -21,7 +21,11 @@ import { AttentionService, showOSNotification } from "./services/attention"
import { CaffeinationService } from "./services/caffeination"
import { confirmCaffeination } from "./services/caffeination/confirm"
import { createCaffeinationDriver } from "./services/caffeination/inhibitor"
import { BrowserBroker } from "./services/browser-automation"
import { BrowserAutomationService, BrowserBroker } from "./services/browser-automation"
import {
integratedBrowserUseSystemChrome,
migrateIntegratedBrowserUseSystemChrome,
} from "./services/browser-automation/chrome-setting"
import { TelemetryEventName, TelemetryProxy } from "./services/telemetry"
import { registerCommitMessageService } from "./services/commit-message"
import { registerCodeActions, registerTerminalActions, KiloCodeActionProvider } from "./services/code-actions"
@@ -62,16 +66,28 @@ export async function activate(context: vscode.ExtensionContext) {
const telemetry = TelemetryProxy.getInstance()
await migrateIntegratedBrowserUseSystemChrome().catch((error: unknown) =>
console.warn("[Kilo New] Integrated Browser Chrome preference migration failed:", error),
)
const browserBroker = new BrowserBroker({
log: (...args) => console.warn("[Kilo New] BrowserBroker:", ...args),
enabled: () => vscode.workspace.getConfiguration("kilo-code.new.experimental").get("browserAutomation", false),
trusted: () => vscode.workspace.isTrusted,
useSystemChrome: () =>
vscode.workspace.getConfiguration("kilo-code.new.browserAutomation").get("useSystemChrome", true),
useSystemChrome: () => integratedBrowserUseSystemChrome(),
})
// Create shared connection service (one server for all webviews)
const connectionService = new KiloConnectionService(context, () => browserBroker.env())
const connectionService = new KiloConnectionService(
context,
() => browserBroker.env(),
(dir): Promise<void> => browserAutomationService.ready(dir),
)
// Manages the built-in Playwright MCP server for ordinary sessions. This is
// independent from the Agent Manager browser broker above.
const browserAutomationService = new BrowserAutomationService(connectionService)
void browserAutomationService.syncWithSettings()
const notebookBridge = createNotebookBridge(connectionService)
let restore = context.workspaceState.get<RestoreState>(RESTORE_KEY) ?? {}
const remember = (patch: RestoreState) => {
@@ -88,6 +104,9 @@ export async function activate(context: vscode.ExtensionContext) {
const unsubscribeStateChange = connectionService.onStateChange((state) => {
if (state === "connected") {
void browserAutomationService
.reregisterIfEnabled()
.catch((error) => console.warn("[Kilo New] Playwright MCP re-registration failed:", error))
const config = connectionService.getServerConfig()
if (config) {
telemetry.configure(config.baseUrl, config.password)
@@ -747,6 +766,7 @@ export async function activate(context: vscode.ExtensionContext) {
unsubscribeStateChange()
attention.dispose()
browserBroker.dispose()
browserAutomationService.dispose()
provider.dispose()
notebookBridge.dispose()
connectionService.dispose()
@@ -0,0 +1,258 @@
import * as vscode from "vscode"
import type { KiloClient } from "@kilocode/sdk/v2/client"
import type { KiloConnectionService } from "../cli-backend"
import { playwrightCommand } from "./settings"
import { canonicalizePath, samePath } from "../../agent-manager/project/paths"
type BrowserAutomationState = "disabled" | "registering" | "connected" | "failed" | "disconnected"
/**
* Manages the built-in Playwright MCP browser server for ordinary Kilo sessions.
*
* This is independent from the Agent Manager browser broker. It must not read
* Agent Manager settings, and Agent Manager must not read its settings.
*/
export class BrowserAutomationService implements vscode.Disposable {
// MCP server name used when registering with the CLI backend
private static readonly MCP_SERVER_NAME = "kilo-playwright"
private readonly disposables: vscode.Disposable[] = []
private readonly registered = new Set<string>()
private queue: Promise<void> = Promise.resolve()
private disposed = false
private state: BrowserAutomationState = "disabled"
constructor(
private readonly connectionService: KiloConnectionService,
private readonly wait = 15_000,
) {
this.disposables.push(
vscode.workspace.onDidChangeConfiguration((event) => {
if (!event.affectsConfiguration("kilo-code.new.browserAutomation")) return
void this.syncWithSettings()
}),
vscode.workspace.onDidChangeWorkspaceFolders(() => this.enqueue(() => this.apply(true))),
{
dispose: connectionService.onEvent((event) => {
if (event.type !== "server.instance.disposed") return
return this.enqueue(async () => {
if (this.disposed) return
const root = canonicalizePath(event.properties.directory)
const dirs = [...new Set([...this.registered, ...this.directories()])].filter((dir) =>
samePath(canonicalizePath(dir), root),
)
if (!dirs.length) return
// Config saves and Reload discard MCP state without reconnecting SSE.
for (const dir of dirs) this.registered.delete(dir)
await this.apply(true)
})
}),
},
)
}
/**
* Read the Playwright settings and enable or disable the MCP server.
* Called on construction and when Playwright settings change.
*/
syncWithSettings(): Promise<void> {
return this.enqueue(() => this.apply())
}
/**
* Re-register the MCP server after the CLI backend reconnects.
*/
reregisterIfEnabled(): Promise<void> {
return this.enqueue(() => this.apply())
}
ready(directory: string): Promise<void> {
const task = this.enqueue(async () => {
if (this.disposed || !this.enabled() || !vscode.workspace.isTrusted) return
const dir = this.directories().find((dir) => samePath(canonicalizePath(dir), canonicalizePath(directory)))
if (!dir) return
const client = this.getClient()
if (!client) throw new Error("Playwright browser automation is waiting for the CLI connection.")
// A prompt can arrive before the disposal event or before MCP startup finishes.
const { data: status } = await client.mcp.status({ directory: dir }, { throwOnError: true })
const server = status[BrowserAutomationService.MCP_SERVER_NAME]
if (server?.status === "connected") return
// A failed server stays failed until settings change, reconnect, or
// disposal. Do not spawn another npx attempt on every prompt.
if (server?.status === "failed") throw BrowserAutomationService.failure((server as { error?: string }).error)
this.registered.delete(dir)
if (!this.enabled()) return
await this.register([dir])
if (this.enabled() && !this.registered.has(dir)) throw BrowserAutomationService.failure()
})
return BrowserAutomationService.bounded(task, this.wait)
}
/**
* Cap how long a prompt waits for Playwright MCP. A cold `npx` start can hold
* the shared queue for up to the MCP timeout, and a prompt should not stall
* that long; its tools arrive on a later turn instead.
*/
private static async bounded(task: Promise<void>, wait: number): Promise<void> {
const limit = Promise.withResolvers<"timeout">()
const timer = setTimeout(() => limit.resolve("timeout"), wait)
const outcome = task.then(
() => undefined,
(error) => {
console.warn("[Kilo New] BrowserAutomationService: readiness failed:", error)
return { error }
},
)
void outcome.then(() => clearTimeout(timer))
const result = await Promise.race([outcome, limit.promise])
if (result === "timeout") {
console.warn(
"[Kilo New] BrowserAutomationService: readiness timed out, submitting without waiting for Playwright MCP",
)
return
}
if (result) throw result.error
}
private static failure(detail?: string): Error {
return new Error(
`Playwright browser automation could not connect${detail ? ` (${detail})` : ""}. Check the Extension Host output, or disable Browser Automation in Web Tools to continue without it.`,
)
}
/**
* Run one settings transition at a time. Each transition reads the current
* settings when it runs, so a queued change cannot restore stale state.
*/
private enqueue(task: () => Promise<void>): Promise<void> {
const next = this.queue.then(task, task)
this.queue = next.then(
() => undefined,
() => undefined,
)
return next
}
private async apply(reconcile = false): Promise<void> {
if (this.disposed) return
if (!this.enabled()) {
await this.unregister()
return
}
if (!vscode.workspace.isTrusted) {
console.warn("[Kilo New] BrowserAutomationService: Workspace is not trusted, skipping Playwright MCP")
this.setState("disabled")
return
}
const dirs = this.directories()
const removed = [...this.registered].filter((dir) => !dirs.includes(dir))
if (removed.length) await this.unregister(removed)
await this.register(reconcile ? dirs.filter((dir) => !this.registered.has(dir)) : dirs)
}
private enabled(): boolean {
return vscode.workspace.getConfiguration("kilo-code.new.browserAutomation").get<boolean>("enabled", false) === true
}
private command(): string[] {
const config = vscode.workspace.getConfiguration("kilo-code.new.browserAutomation")
return playwrightCommand({
headless: config.get<boolean>("headless", false),
useSystemChrome: config.get<boolean>("useSystemChrome", true),
})
}
private directories(): string[] {
const folders = vscode.workspace.workspaceFolders ?? []
const dirs = folders.length > 0 ? folders.map((folder) => folder.uri.fsPath) : [process.cwd()]
return [...new Set(dirs)]
}
private async register(dirs: string[]): Promise<void> {
const client = this.getClient()
if (!client) {
this.setState("failed")
return
}
const command = this.command()
this.setState("registering")
let failure: unknown
for (const directory of dirs) {
try {
const { data: status } = await client.mcp.add(
{
name: BrowserAutomationService.MCP_SERVER_NAME,
config: {
type: "local",
command,
enabled: true,
timeout: 60000,
},
directory,
},
{ throwOnError: true },
)
const server = status[BrowserAutomationService.MCP_SERVER_NAME]
if (server?.status === "connected") {
this.registered.add(directory)
continue
}
this.registered.delete(directory)
if (server?.status === "failed") {
const detail = (server as { error?: string }).error
failure = new Error(`Playwright MCP failed to start${detail ? `: ${detail}` : ""}`)
}
} catch (error) {
this.registered.delete(directory)
failure = error
}
}
if (this.registered.size > 0) {
this.setState("connected")
return
}
if (failure) {
console.error("[Kilo New] BrowserAutomationService: Failed to register MCP server:", failure)
this.setState("failed")
return
}
this.setState("disconnected")
}
private async unregister(dirs = [...this.registered]): Promise<void> {
const client = this.getClient()
if (client) {
for (const directory of dirs) {
try {
await client.mcp.disconnect(
{ name: BrowserAutomationService.MCP_SERVER_NAME, directory },
{ throwOnError: true },
)
this.registered.delete(directory)
} catch (error) {
console.error("[Kilo New] BrowserAutomationService: Failed to disconnect MCP server:", error)
}
}
}
this.setState("disabled")
}
private getClient(): KiloClient | null {
try {
return this.connectionService.getClient()
} catch {
return null
}
}
private setState(state: BrowserAutomationState): void {
if (this.state === state) return
console.log(`[Kilo New] BrowserAutomationService: State ${this.state} -> ${state}`)
this.state = state
}
dispose(): void {
this.disposed = true
for (const disposable of this.disposables) disposable.dispose()
this.disposables.length = 0
}
}
@@ -475,8 +475,8 @@ export class BrowserBroker {
const detail = error instanceof Error ? error.message : String(error)
const action =
this.opts.useSystemChrome?.() === false
? "Install a compatible Playwright Chromium browser or enable Use System Chrome in Kilo Settings > Web Tools."
: "Install Google Chrome or select an existing Playwright Chromium browser in Kilo Settings > Web Tools."
? "Install a compatible Playwright Chromium browser or enable Use System Chrome in Kilo Settings > Experimental for the Integrated Browser."
: "Install Google Chrome or disable Use System Chrome in Kilo Settings > Experimental for the Integrated Browser to use an installed Playwright Chromium browser."
throw new Error(`${action} ${detail}`.slice(0, 1000), { cause: error })
} finally {
this.browserStarting = undefined
@@ -0,0 +1,32 @@
import * as vscode from "vscode"
const INTEGRATED_BROWSER = "kilo-code.new.agentManager.browser"
const BROWSER_AUTOMATION = "kilo-code.new.browserAutomation"
/**
* Read the Chrome preference for the Agent Manager Integrated Browser.
*
* The broker and the settings payload both use this so the toggle in Settings
* and the effective value stay in sync. The Playwright setting under Web Tools
* stays independent.
*/
export function integratedBrowserUseSystemChrome(): boolean {
return vscode.workspace.getConfiguration(INTEGRATED_BROWSER).get("useSystemChrome", true)
}
/**
* Copy a user-level Chrome preference that was stored before this setting had
* its own key.
*
* Runs once on activation and only when the current key has no explicit value,
* so the old Playwright preference is preserved without aliasing the two
* features afterwards. Workspace-scoped legacy values are left alone because
* the current key is application-scoped and cannot store them.
*/
export async function migrateIntegratedBrowserUseSystemChrome(): Promise<void> {
const browser = vscode.workspace.getConfiguration(INTEGRATED_BROWSER)
if (browser.inspect?.<boolean>("useSystemChrome")?.globalValue !== undefined) return
const value = vscode.workspace.getConfiguration(BROWSER_AUTOMATION).inspect?.<boolean>("useSystemChrome")?.globalValue
if (value === undefined) return
await browser.update("useSystemChrome", value, vscode.ConfigurationTarget.Global)
}
@@ -1,3 +1,4 @@
export { BrowserAutomationService } from "./browser-automation-service"
export { BrowserBroker, diagnostic } from "./browser-broker"
export type {
BrowserContextFactory,
@@ -0,0 +1,18 @@
import * as os from "os"
import * as path from "path"
export const PLAYWRIGHT_OUTPUT_DIR = path.join(os.tmpdir(), "kilo-playwright-mcp")
/**
* Build the Playwright MCP launch command.
*
* Default artifacts go outside the workspace. Explicit screenshot paths can
* bypass this directory, so this is not a guarantee against staging artifacts.
*/
export function playwrightCommand(input: { headless: boolean; useSystemChrome: boolean }): string[] {
const command = ["npx", "@playwright/mcp@latest"]
if (input.headless) command.push("--headless")
if (input.useSystemChrome) command.push("--browser", "chrome")
command.push("--output-dir", PLAYWRIGHT_OUTPUT_DIR)
return command
}
@@ -149,7 +149,11 @@ export class KiloConnectionService {
private viewedDirty = false
private unsubRemote: (() => void) | null = null
constructor(context: vscode.ExtensionContext, env?: () => Promise<Record<string, string>>) {
constructor(
context: vscode.ExtensionContext,
env?: () => Promise<Record<string, string>>,
private readonly prepare?: (directory: string) => Promise<void>,
) {
const state =
context.workspaceState ??
({
@@ -202,6 +206,10 @@ export class KiloConnectionService {
return this.client
}
async prepareTools(directory: string): Promise<void> {
await this.prepare?.(directory)
}
/**
* Get the shared SDK client, auto-connecting if not yet started.
* Accepts an optional directory to use as the workspace root; falls back
@@ -60,6 +60,7 @@ const mockVscode = {
}),
getConfiguration: () => ({
get: <T>(_key: string, value?: T) => value,
inspect: () => ({}),
update: async () => {},
}),
asRelativePath: (pathOrUri: string | { fsPath?: string }) => {
@@ -0,0 +1,68 @@
import { afterEach, describe, expect, test } from "bun:test"
import * as vscode from "vscode"
import {
integratedBrowserUseSystemChrome,
migrateIntegratedBrowserUseSystemChrome,
} from "../../src/services/browser-automation/chrome-setting"
const INTEGRATED_BROWSER = "kilo-code.new.agentManager.browser"
const BROWSER_AUTOMATION = "kilo-code.new.browserAutomation"
describe("Integrated Browser Chrome preference", () => {
const descriptors = Object.getOwnPropertyDescriptors(vscode.workspace)
let writes: Array<{ key: string; value: unknown; target: unknown }> = []
function config(input: { current?: boolean; previous?: boolean; previousWorkspace?: boolean }) {
writes = []
vscode.workspace.getConfiguration = ((section: string) =>
({
get: (_key: string, fallback?: unknown) =>
section === INTEGRATED_BROWSER ? (input.current ?? fallback) : fallback,
inspect: () =>
section === INTEGRATED_BROWSER
? { globalValue: input.current }
: { globalValue: input.previous, workspaceValue: input.previousWorkspace },
update: async (key: string, value: unknown, target: unknown) => {
writes.push({ key, value, target })
},
}) as unknown as vscode.WorkspaceConfiguration) as typeof vscode.workspace.getConfiguration
}
afterEach(() => {
Object.defineProperties(vscode.workspace, descriptors)
})
test("reads the preference from the Integrated Browser key", () => {
config({ current: false, previous: true })
expect(integratedBrowserUseSystemChrome()).toBe(false)
})
test("defaults to system Chrome when the key is unset", () => {
config({})
expect(integratedBrowserUseSystemChrome()).toBe(true)
})
test("copies a legacy preference once when the key is unset", async () => {
config({ previous: false })
await migrateIntegratedBrowserUseSystemChrome()
expect(writes).toEqual([{ key: "useSystemChrome", value: false, target: vscode.ConfigurationTarget.Global }])
})
test("keeps an existing Integrated Browser preference", async () => {
config({ current: true, previous: false })
await migrateIntegratedBrowserUseSystemChrome()
expect(writes).toEqual([])
})
test("does not write when no legacy preference exists", async () => {
config({})
await migrateIntegratedBrowserUseSystemChrome()
expect(writes).toEqual([])
})
test("does not promote a workspace-scoped legacy preference", async () => {
config({ previousWorkspace: false })
await migrateIntegratedBrowserUseSystemChrome()
expect(writes).toEqual([])
})
})
@@ -0,0 +1,300 @@
import { afterEach, beforeEach, describe, expect, test } from "bun:test"
import * as vscode from "vscode"
import { realpathSync } from "node:fs"
import { tmpdir } from "node:os"
import type { KiloClient } from "@kilocode/sdk/v2/client"
import type { KiloConnectionService } from "../../src/services/cli-backend"
import { BrowserAutomationService } from "../../src/services/browser-automation/browser-automation-service"
describe("Playwright MCP lifecycle", () => {
const descriptors = Object.getOwnPropertyDescriptors(vscode.workspace)
const listeners = new Set<() => Promise<void>>()
const events = new Set<Parameters<KiloConnectionService["onEvent"]>[0]>()
let service: BrowserAutomationService
let connection: KiloConnectionService
let enabled: boolean
let connected: boolean
let failed: boolean
let pending: Promise<void> | undefined
let additions: string[]
let removals: string[]
let active: Set<string>
let down: Set<string>
let started: ReturnType<typeof Promise.withResolvers<void>>
function folders(dirs: string[]) {
Object.defineProperty(vscode.workspace, "workspaceFolders", {
configurable: true,
value: dirs.map((dir, index) => ({ uri: vscode.Uri.file(dir), name: dir, index })),
})
}
beforeEach(() => {
enabled = true
connected = true
failed = false
pending = undefined
additions = []
removals = []
active = new Set()
down = new Set()
started = Promise.withResolvers<void>()
folders(["/repo"])
Object.defineProperty(vscode.workspace, "isTrusted", { configurable: true, value: true })
vscode.workspace.getConfiguration = (() => ({
get: (key: string, fallback: unknown) => (key === "enabled" ? enabled : fallback),
})) as typeof vscode.workspace.getConfiguration
Object.defineProperty(vscode.workspace, "onDidChangeWorkspaceFolders", {
configurable: true,
value: (listener: () => Promise<void>) => {
listeners.add(listener)
return { dispose: () => listeners.delete(listener) }
},
})
const client = {
mcp: {
status: async ({ directory }: { directory: string }) => ({
data: active.has(directory)
? { "kilo-playwright": { status: "connected" } }
: down.has(directory)
? { "kilo-playwright": { status: "failed", error: "MCP startup failed" } }
: {},
}),
add: async ({ name, directory }: { name: string; directory: string }) => {
additions.push(directory)
started.resolve()
await pending
if (failed) {
down.add(directory)
return { data: { [name]: { status: "failed", error: "MCP startup failed" } } }
}
down.delete(directory)
active.add(directory)
return { data: { [name]: { status: "connected" } } }
},
disconnect: async ({ directory }: { directory: string }) => {
removals.push(directory)
active.delete(directory)
down.delete(directory)
},
},
} as unknown as KiloClient
connection = {
onEvent: (listener: Parameters<KiloConnectionService["onEvent"]>[0]) => {
events.add(listener)
return () => events.delete(listener)
},
getClient: () => {
if (!connected) throw new Error("Disconnected")
return client
},
} as KiloConnectionService
service = new BrowserAutomationService(connection)
})
afterEach(() => {
service.dispose()
listeners.clear()
events.clear()
for (const key of Object.getOwnPropertyNames(vscode.workspace)) {
if (!(key in descriptors)) Reflect.deleteProperty(vscode.workspace, key)
}
Object.defineProperties(vscode.workspace, descriptors)
})
test("re-registers the same directory after a backend restart", async () => {
await service.syncWithSettings()
active.clear()
await service.reregisterIfEnabled()
expect(additions).toEqual(["/repo", "/repo"])
expect([...active]).toEqual(["/repo"])
})
test("prompt readiness waits for in-flight MCP startup without restarting it", async () => {
const gate = Promise.withResolvers<void>()
pending = gate.promise
const registration = service.syncWithSettings()
await started.promise
let sent = false
const prompt = service.ready("/repo").then(() => {
sent = true
})
await Promise.resolve()
expect(sent).toBe(false)
gate.resolve()
await Promise.all([registration, prompt])
expect(sent).toBe(true)
expect(additions).toEqual(["/repo"])
})
test("prompt readiness gives up after the wait instead of stalling on startup", async () => {
const gate = Promise.withResolvers<void>()
pending = gate.promise
service.dispose()
service = new BrowserAutomationService(connection, 5)
const registration = service.syncWithSettings()
await started.promise
await service.ready("/repo")
expect(active.size).toBe(0)
gate.resolve()
await registration
expect(active.has("/repo")).toBe(true)
})
test("prompt readiness repairs lost registration before the disposal event arrives", async () => {
await service.syncWithSettings()
active.clear()
await service.ready("/repo")
expect(additions).toEqual(["/repo", "/repo"])
expect(active.has("/repo")).toBe(true)
})
test("prompt readiness surfaces startup failures rather than submitting without tools", async () => {
failed = true
await expect(service.ready("/repo")).rejects.toThrow("Playwright browser automation could not connect")
expect(active.size).toBe(0)
})
test("a failed server is not respawned on every prompt", async () => {
failed = true
await expect(service.ready("/repo")).rejects.toThrow("could not connect")
await expect(service.ready("/repo")).rejects.toThrow("MCP startup failed")
expect(additions).toEqual(["/repo"])
failed = false
await service.syncWithSettings()
await service.ready("/repo")
expect(additions).toEqual(["/repo", "/repo"])
expect(active.has("/repo")).toBe(true)
})
test("disabled Playwright and unrelated worktrees do not block prompts", async () => {
await service.ready("/worktree")
enabled = false
await service.ready("/repo")
expect(additions).toEqual([])
})
async function invalidate(directory: string) {
active.delete(directory)
await Promise.all(
[...events].map((listener) =>
listener(
{
type: "server.instance.disposed",
properties: { directory },
},
directory,
),
),
)
}
test("restores registrations after config disposal without an SSE reconnect", async () => {
folders(["/repo", "/second"])
await service.syncWithSettings()
await invalidate("/repo")
expect(additions).toEqual(["/repo", "/second", "/repo"])
expect(active.has("/repo")).toBe(true)
expect(removals).toEqual([])
await invalidate("/second")
expect(active.size).toBe(2)
expect(additions).toEqual(["/repo", "/second", "/repo", "/second"])
})
test("ignores disposal for unrelated Agent Manager directories", async () => {
await service.syncWithSettings()
expect(events.size).toBe(1)
await invalidate("/worktree")
expect(additions).toEqual(["/repo"])
expect(removals).toEqual([])
})
test("matches canonical disposal paths to workspace aliases", async () => {
const dir = tmpdir()
folders([dir])
await service.syncWithSettings()
await invalidate(realpathSync(dir))
expect(additions).toEqual([dir, dir])
})
test("does not restore after disposal of the service", async () => {
await service.syncWithSettings()
service.dispose()
await invalidate("/repo")
expect(events.size).toBe(0)
expect(additions).toEqual(["/repo"])
})
test("does not restore a disposed registration when disabled", async () => {
await service.syncWithSettings()
enabled = false
expect(events.size).toBe(1)
await invalidate("/repo")
expect(additions).toEqual(["/repo"])
expect(removals).toEqual([])
expect(active.size).toBe(0)
// The handler ran: it dropped the directory, so a reconcile registers it again.
enabled = true
await Promise.all([...listeners].map((listener) => listener()))
expect(additions).toEqual(["/repo", "/repo"])
})
test("queues disposal behind an in-flight registration", async () => {
const gate = Promise.withResolvers<void>()
pending = gate.promise
const registration = service.syncWithSettings()
await started.promise
const reset = invalidate("/repo")
gate.resolve()
await Promise.all([registration, reset])
expect(additions).toEqual(["/repo", "/repo"])
expect(active.has("/repo")).toBe(true)
})
test("a queued disable wins over in-flight registration and reconnect", async () => {
const gate = Promise.withResolvers<void>()
pending = gate.promise
const registration = service.syncWithSettings()
await started.promise
const reconnect = service.reregisterIfEnabled()
enabled = false
const disable = service.syncWithSettings()
gate.resolve()
await Promise.all([registration, reconnect, disable])
expect(additions).toEqual(["/repo"])
expect(removals).toEqual(["/repo"])
expect(active.size).toBe(0)
})
test("retries a disable on reconnect without losing its directory", async () => {
await service.syncWithSettings()
connected = false
enabled = false
await service.syncWithSettings()
expect([...active]).toEqual(["/repo"])
connected = true
await service.reregisterIfEnabled()
expect(removals).toEqual(["/repo"])
expect(active.size).toBe(0)
})
test("reconciles added and removed folders without restarting retained registrations", async () => {
folders(["/repo", "/old"])
await service.syncWithSettings()
folders(["/repo", "/new"])
await Promise.all([...listeners].map((listener) => listener()))
expect(additions).toEqual(["/repo", "/old", "/new"])
expect(removals).toEqual(["/old"])
expect([...active]).toEqual(["/repo", "/new"])
enabled = false
await service.syncWithSettings()
folders(["/repo", "/disabled"])
await Promise.all([...listeners].map((listener) => listener()))
expect(additions).toEqual(["/repo", "/old", "/new"])
expect(active.size).toBe(0)
service.dispose()
expect(listeners.size).toBe(0)
expect(events.size).toBe(0)
})
})
@@ -0,0 +1,31 @@
import { describe, expect, it } from "bun:test"
import { PLAYWRIGHT_OUTPUT_DIR, playwrightCommand } from "../../src/services/browser-automation/settings"
describe("Playwright MCP command", () => {
it("uses system Chrome and a temp output directory by default", () => {
expect(playwrightCommand({ headless: false, useSystemChrome: true })).toEqual([
"npx",
"@playwright/mcp@latest",
"--browser",
"chrome",
"--output-dir",
PLAYWRIGHT_OUTPUT_DIR,
])
})
it("adds headless and drops the Chrome channel", () => {
expect(playwrightCommand({ headless: true, useSystemChrome: false })).toEqual([
"npx",
"@playwright/mcp@latest",
"--headless",
"--output-dir",
PLAYWRIGHT_OUTPUT_DIR,
])
})
it("keeps artifacts outside the workspace", () => {
const command = playwrightCommand({ headless: false, useSystemChrome: false })
const index = command.indexOf("--output-dir")
expect(command.at(index + 1)).not.toContain(process.cwd())
})
})
@@ -495,20 +495,25 @@ describe("BrowserBroker", () => {
expect(untrusted.sessions()).toEqual([])
})
test("explains how to recover when the selected browser runtime is missing", async () => {
const broker = new BrowserBroker({
log: () => {},
useSystemChrome: () => false,
launch: async () => {
throw new Error("Browser executable does not exist")
},
})
brokers.push(broker)
await expect(
broker.open({ sessionId: "missing-runtime", directory: "/tmp/project" }, "http://localhost:3000/"),
).rejects.toThrow("enable Use System Chrome")
expect(broker.sessions()).toEqual([])
})
test.each([false, true])(
"points at Agent Manager settings when the browser is missing (Chrome: %s)",
async (chrome) => {
const broker = new BrowserBroker({
log: () => {},
useSystemChrome: () => chrome,
launch: async () => {
throw new Error("Browser executable does not exist")
},
})
brokers.push(broker)
await expect(
broker.open({ sessionId: "missing-runtime", directory: "/tmp/project" }, "http://localhost:3000/"),
).rejects.toThrow(
`${chrome ? "disable" : "enable"} Use System Chrome in Kilo Settings > Experimental for the Integrated Browser`,
)
expect(broker.sessions()).toEqual([])
},
)
test("rejects unregistered browser sessions before launching Chrome", async () => {
const broker = new BrowserBroker({ log: () => {} })
@@ -226,6 +226,7 @@ function createConnection(client: ReturnType<typeof createClient> | null) {
getConnectionError: () => null,
resolveEventSessionId: () => undefined,
recordMessageSessionId: () => undefined,
prepareTools: async (_dir: string) => {},
notifyNotificationDismissed: () => undefined,
pruneSession: () => undefined,
registerVisible: () => undefined,
@@ -294,7 +295,7 @@ function makeProvider(
sent.push(message)
},
}
return { provider, internal, sent }
return { provider, internal, sent, connection }
}
function status(internal: ProviderInternals, type: "busy" | "idle", directory = "/repo", sessionID = "s1") {
@@ -1595,6 +1596,74 @@ describe("KiloProvider.handleLoadMessages / slim payload", () => {
expect(client.prompted).toHaveLength(1)
})
it("waits for browser tool readiness before submitting the prompt", async () => {
const client = createClient()
const { internal, connection } = makeProvider(client)
internal.currentSession = mkSession()
internal.gatherEditorContext = async () => ({})
const started = Promise.withResolvers<void>()
const ready = Promise.withResolvers<void>()
connection.prepareTools = async (dir) => {
expect(dir).toBe("/repo")
started.resolve()
await ready.promise
}
const send = internal.handleSendMessage("browser test", "m1", "s1")
await started.promise
expect(client.prompted).toHaveLength(0)
ready.resolve()
await send
expect(client.prompted).toHaveLength(1)
})
it("waits for browser tool readiness for Agent Manager worktree prompts too", async () => {
const client = createClient()
const { internal, connection } = makeProvider(client)
internal.gatherEditorContext = async () => ({})
const order: string[] = []
connection.prepareTools = async (dir) => {
order.push(`prepare:${dir}`)
}
client.session.promptAsync = async (params: Record<string, unknown>) => {
order.push(`prompt:${String(params.directory)}`)
return { data: undefined }
}
await internal.handleSendMessage(
"browser test",
"m1",
undefined,
"draft-1",
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
"worktree-ctx",
"/worktree",
)
expect(client.created).toEqual([expect.objectContaining({ directory: "/worktree" })])
expect(order).toEqual(["prepare:/worktree", "prompt:/worktree"])
})
it("reports a browser readiness failure instead of submitting without tools", async () => {
const client = createClient()
const { internal, connection, sent } = makeProvider(client)
internal.currentSession = mkSession()
internal.gatherEditorContext = async () => ({})
connection.prepareTools = async () => {
throw new Error("Playwright browser automation could not connect")
}
await internal.handleSendMessage("browser test", "m1", "s1")
expect(client.prompted).toHaveLength(0)
expect(sent).toContainEqual(
expect.objectContaining({
type: "sendMessageFailed",
error: "Playwright browser automation could not connect",
}),
)
})
it("aborts when the cost alert is stopped", async () => {
const client = createClient()
const { internal, sent } = makeProvider(client)
@@ -88,6 +88,7 @@ function mockConnection(getImpl?: (p: SessionGetParams) => Promise<unknown>, vcs
getConnectionError: () => null,
resolveEventSessionId: () => undefined,
recordMessageSessionId: () => undefined,
prepareTools: async () => {},
notifyNotificationDismissed: () => undefined,
} as unknown as ConstructorParameters<typeof KiloProvider>[1],
}
@@ -6,6 +6,76 @@ import { createProjectStore } from "../../webview-ui/agent-manager/project/store
import { setupVisible, updateSetup } from "../../webview-ui/agent-manager/project/progress"
describe("Agent Manager panel ownership", () => {
it("opens and closes the Integrated Browser before a session exists", () => {
createRoot((dispose) => {
const panels = createSidePanel({ project: () => "project", selection: () => "local", current: () => undefined })
panels.toggle(SidePanel.Browser)
expect(panels.panel()).toBe(SidePanel.Browser)
expect(panels.session()).toBeUndefined()
panels.toggle(SidePanel.Browser)
expect(panels.panel()).toBeNull()
panels.open(SidePanel.Browser)
panels.open(SidePanel.Documents)
expect(panels.panel()).toBe(SidePanel.Documents)
dispose()
})
})
it("keeps the empty browser separate from real sessions, projects, and worktrees", () => {
createRoot((dispose) => {
const [project, activate] = createSignal("project")
const [selection, select] = createSignal("local")
const [current, session] = createSignal<string>()
const panels = createSidePanel({ project, selection, current })
panels.open(SidePanel.Browser)
select("worktree")
expect(panels.panel()).toBeNull()
select("local")
activate("other")
expect(panels.panel()).toBeNull()
activate("project")
expect(panels.panel()).toBe(SidePanel.Browser)
session("real-session")
expect(panels.panel()).toBeNull()
panels.open(SidePanel.Browser)
session("sibling")
expect(panels.panel()).toBeNull()
session("real-session")
expect(panels.panel()).toBe(SidePanel.Browser)
panels.close()
session(undefined)
expect(panels.panel()).toBe(SidePanel.Browser)
dispose()
})
})
it("does not let a closed draft browser hide a worktree panel after the session ends", () => {
createRoot((dispose) => {
const [current, session] = createSignal<string>()
const panels = createSidePanel({ project: () => "project", selection: () => "local", current })
panels.open(SidePanel.Browser)
panels.close()
expect(panels.panel()).toBeNull()
session("real-session")
panels.open(SidePanel.Diff)
expect(panels.panel()).toBe(SidePanel.Diff)
session(undefined)
expect(panels.panel()).toBe(SidePanel.Diff)
dispose()
})
})
it("still requires a real session for other session-owned panels", () => {
createRoot((dispose) => {
const panels = createSidePanel({ project: () => "project", selection: () => "local", current: () => undefined })
panels.open(SidePanel.Subagents)
expect(panels.panel()).toBeNull()
panels.open(SidePanel.EditPreview)
expect(panels.panel()).toBeNull()
dispose()
})
})
it("restores Local Diff and session panels independently, including explicit closes", () => {
createRoot((dispose) => {
const [project, activate] = createSignal("project")
+2 -2
View File
@@ -422,7 +422,7 @@ export const dict = {
"agentManager.caffeination.armed": "تم تفعيل وضع إبقاء الكمبيوتر مستيقظًا لوكلاء Kilo؛ انقر لتعطيله",
"agentManager.caffeination.active": "يتم إبقاء الكمبيوتر مستيقظًا أثناء عمل وكلاء Kilo",
"agentManager.caffeination.unavailable": "وضع إبقاء الكمبيوتر مستيقظًا غير متاح على هذا النظام الأساسي",
"agentManager.browser.title": "المتصفح",
"agentManager.browser.title": "المتصفح المدمج",
"agentManager.browser.url": "URL التطبيق المحلي",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "فتح",
@@ -431,7 +431,7 @@ export const dict = {
"agentManager.browser.inspect": "تحديد عنصر",
"agentManager.browser.devtoolsTitle": "أدوات المطوّرين",
"agentManager.browser.empty": "افتح تطبيقًا محليًا لمعاينته هنا.",
"agentManager.browser.noSession": "اختر جلسة Agent Manager أولًا.",
"agentManager.browser.noSession": "ابدأ جلسة أو اختر جلسة في Agent Manager لاستعراض تطبيق محلي.",
"agentManager.browser.screenshotAlt": "صفحة المتصفح الحالية",
"agentManager.browser.errors": "مشكلات المتصفح: {{count}}",
"agentManager.browser.diagnostics": "تشخيص المتصفح",
+3 -2
View File
@@ -431,7 +431,7 @@ export const dict = {
"agentManager.caffeination.active": "Mantendo o computador acordado enquanto os agentes Kilo trabalham",
"agentManager.caffeination.unavailable":
"O modo de manter o computador acordado não está disponível nesta plataforma",
"agentManager.browser.title": "Navegador",
"agentManager.browser.title": "Navegador Integrado",
"agentManager.browser.url": "URL da aplicação local",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "Abrir",
@@ -440,7 +440,8 @@ export const dict = {
"agentManager.browser.refresh": "Atualizar navegador",
"agentManager.browser.close": "Fechar navegador",
"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.noSession":
"Inicie ou selecione uma sessão no Agent Manager para navegar em um aplicativo local.",
"agentManager.browser.screenshotAlt": "Página atual do navegador",
"agentManager.browser.errors": "Problemas do navegador: {{count}}",
"agentManager.browser.diagnostics": "Diagnóstico do navegador",
+3 -2
View File
@@ -427,7 +427,7 @@ export const dict = {
"Režim održavanja računara budnim je uključen za Kilo agente; kliknite da ga isključite",
"agentManager.caffeination.active": "Računar se održava budnim dok Kilo agenti rade",
"agentManager.caffeination.unavailable": "Režim održavanja računara budnim nije dostupan na ovoj platformi",
"agentManager.browser.title": "Preglednik",
"agentManager.browser.title": "Integrirani preglednik",
"agentManager.browser.url": "URL lokalne aplikacije",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "Otvori",
@@ -436,7 +436,8 @@ export const dict = {
"agentManager.browser.refresh": "Osvježi preglednik",
"agentManager.browser.close": "Zatvori preglednik",
"agentManager.browser.empty": "Otvorite lokalnu aplikaciju da biste je ovdje pregledali.",
"agentManager.browser.noSession": "Najprije odaberite sesiju aplikacije Agent Manager.",
"agentManager.browser.noSession":
"Pokrenite ili odaberite sesiju u Agent Manageru da biste pregledali lokalnu aplikaciju.",
"agentManager.browser.screenshotAlt": "Trenutna stranica preglednika",
"agentManager.browser.errors": "Problemi preglednika: {{count}}",
"agentManager.browser.diagnostics": "Dijagnostika preglednika",
+2 -2
View File
@@ -429,7 +429,7 @@ export const dict = {
"agentManager.caffeination.active": "Holder computeren vågen, mens Kilo-agenterne arbejder",
"agentManager.caffeination.unavailable":
"Tilstanden til at holde computeren vågen er ikke tilgængelig på denne platform",
"agentManager.browser.title": "Browser",
"agentManager.browser.title": "Integreret browser",
"agentManager.browser.url": "URL til lokal applikation",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "Åbn",
@@ -438,7 +438,7 @@ export const dict = {
"agentManager.browser.refresh": "Opdater browser",
"agentManager.browser.close": "Luk browser",
"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.noSession": "Start eller vælg en session i Agent Manager for at gennemse en lokal applikation.",
"agentManager.browser.screenshotAlt": "Aktuel browserside",
"agentManager.browser.errors": "Browserproblemer: {{count}}",
"agentManager.browser.diagnostics": "Browserdiagnostik",
@@ -434,7 +434,7 @@ export const dict = {
"agentManager.caffeination.armed": "Wachhaltemodus für Kilo-Agenten aktiviert; zum Deaktivieren klicken",
"agentManager.caffeination.active": "Computer wird wach gehalten, während Kilo-Agenten arbeiten",
"agentManager.caffeination.unavailable": "Der Wachhaltemodus ist auf dieser Plattform nicht verfügbar",
"agentManager.browser.title": "Browser",
"agentManager.browser.title": "Integrierter Browser",
"agentManager.browser.url": "URL der lokalen Anwendung",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "Öffnen",
@@ -443,7 +443,8 @@ export const dict = {
"agentManager.browser.refresh": "Browser aktualisieren",
"agentManager.browser.close": "Browser schließen",
"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.noSession":
"Starten oder wählen Sie eine Sitzung im Agent Manager, um eine lokale Anwendung zu öffnen.",
"agentManager.browser.screenshotAlt": "Aktuelle Browserseite",
"agentManager.browser.errors": "Browserprobleme: {{count}}",
"agentManager.browser.diagnostics": "Browserdiagnose",
@@ -435,7 +435,7 @@ export const dict = {
"agentManager.documents.preview": "Preview document",
"agentManager.documents.source": "Show source",
"agentManager.documents.comments": "{{count}} comments",
"agentManager.browser.title": "Browser",
"agentManager.browser.title": "Integrated Browser",
"agentManager.browser.url": "Local application URL",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "Open",
@@ -444,7 +444,7 @@ export const dict = {
"agentManager.browser.refresh": "Refresh browser",
"agentManager.browser.close": "Close browser",
"agentManager.browser.empty": "Open a local application to preview it here.",
"agentManager.browser.noSession": "Select an Agent Manager session first.",
"agentManager.browser.noSession": "Start or select a session in Agent Manager to browse a local application.",
"agentManager.browser.screenshotAlt": "Current browser page",
"agentManager.browser.errors": "Browser issues: {{count}}",
"agentManager.browser.diagnostics": "Browser diagnostics",
+3 -2
View File
@@ -434,7 +434,7 @@ export const dict = {
"agentManager.caffeination.active": "Manteniendo el equipo activo mientras trabajan los agentes de Kilo",
"agentManager.caffeination.unavailable":
"El modo para mantener el equipo activo no está disponible en esta plataforma",
"agentManager.browser.title": "Navegador",
"agentManager.browser.title": "Navegador integrado",
"agentManager.browser.url": "URL de la aplicación local",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "Abrir",
@@ -443,7 +443,8 @@ export const dict = {
"agentManager.browser.refresh": "Actualizar navegador",
"agentManager.browser.close": "Cerrar navegador",
"agentManager.browser.empty": "Abre una aplicación local para previsualizarla aquí.",
"agentManager.browser.noSession": "Selecciona primero una sesión de Agent Manager.",
"agentManager.browser.noSession":
"Inicia o selecciona una sesión en Agent Manager para navegar por una aplicación local.",
"agentManager.browser.screenshotAlt": "Página actual del navegador",
"agentManager.browser.errors": "Problemas del navegador: {{count}}",
"agentManager.browser.diagnostics": "Diagnóstico del navegador",
+2 -2
View File
@@ -430,7 +430,7 @@ export const dict = {
"حالت بیدار نگه داشتن رایانه برای عامل‌های Kilo فعال است؛ برای غیرفعال کردن کلیک کنید",
"agentManager.caffeination.active": "رایانه هنگام کار عامل‌های Kilo بیدار نگه داشته می‌شود",
"agentManager.caffeination.unavailable": "حالت بیدار نگه داشتن رایانه در این پلتفرم در دسترس نیست",
"agentManager.browser.title": "مرورگر",
"agentManager.browser.title": "مرورگر یکپارچه",
"agentManager.browser.url": "URL برنامه محلی",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "باز کردن",
@@ -439,7 +439,7 @@ export const dict = {
"agentManager.browser.inspect": "انتخاب عنصر",
"agentManager.browser.devtoolsTitle": "ابزارهای توسعه",
"agentManager.browser.empty": "برای پیش‌نمایش، یک برنامه محلی را باز کنید.",
"agentManager.browser.noSession": "ابتدا یک جلسه Agent Manager را انتخاب کنید.",
"agentManager.browser.noSession": "برای مرور یک برنامه محلی، یک جلسه در Agent Manager شروع یا انتخاب کنید.",
"agentManager.browser.screenshotAlt": "صفحه فعلی مرورگر",
"agentManager.browser.errors": "مشکلات مرورگر: {{count}}",
"agentManager.browser.diagnostics": "عیب‌یابی مرورگر",
+3 -2
View File
@@ -434,7 +434,7 @@ export const dict = {
"agentManager.caffeination.armed": "Mode anti-veille activé pour les agents Kilo ; cliquez pour désactiver",
"agentManager.caffeination.active": "Ordinateur maintenu éveillé pendant que les agents Kilo travaillent",
"agentManager.caffeination.unavailable": "Le mode veille active n'est pas disponible sur cette plateforme",
"agentManager.browser.title": "Navigateur",
"agentManager.browser.title": "Navigateur intégré",
"agentManager.browser.url": "URL de l'application locale",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "Ouvrir",
@@ -443,7 +443,8 @@ export const dict = {
"agentManager.browser.refresh": "Actualiser le navigateur",
"agentManager.browser.close": "Fermer le navigateur",
"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.noSession":
"Démarrez ou sélectionnez une session dans Agent Manager pour parcourir une application locale.",
"agentManager.browser.screenshotAlt": "Page actuelle du navigateur",
"agentManager.browser.errors": "Problèmes du navigateur : {{count}}",
"agentManager.browser.diagnostics": "Diagnostics du navigateur",
+3 -2
View File
@@ -440,7 +440,7 @@ export const dict = {
"agentManager.caffeination.active": "Computer mantenuto attivo mentre gli agenti Kilo lavorano",
"agentManager.caffeination.unavailable":
"La modalità per mantenere il computer attivo non è disponibile su questa piattaforma",
"agentManager.browser.title": "Browser",
"agentManager.browser.title": "Browser integrato",
"agentManager.browser.url": "URL dell'applicazione locale",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "Apri",
@@ -449,7 +449,8 @@ export const dict = {
"agentManager.browser.refresh": "Aggiorna browser",
"agentManager.browser.close": "Chiudi browser",
"agentManager.browser.empty": "Apri un'applicazione locale per visualizzarla qui.",
"agentManager.browser.noSession": "Seleziona prima una sessione di Agent Manager.",
"agentManager.browser.noSession":
"Avvia o seleziona una sessione in Agent Manager per navigare in un'applicazione locale.",
"agentManager.browser.screenshotAlt": "Pagina corrente del browser",
"agentManager.browser.errors": "Problemi del browser: {{count}}",
"agentManager.browser.diagnostics": "Diagnostica del browser",
+3 -2
View File
@@ -427,7 +427,7 @@ export const dict = {
"agentManager.caffeination.armed": "Kilo エージェント用のスリープ防止モードが有効です。クリックして無効にします",
"agentManager.caffeination.active": "Kilo エージェントの作業中もコンピューターをスリープさせません",
"agentManager.caffeination.unavailable": "このプラットフォームではスリープ防止モードを利用できません",
"agentManager.browser.title": "ブラウザー",
"agentManager.browser.title": "統合ブラウザー",
"agentManager.browser.url": "ローカルアプリケーション URL",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "開く",
@@ -436,7 +436,8 @@ export const dict = {
"agentManager.browser.inspect": "要素を選択",
"agentManager.browser.devtoolsTitle": "開発者ツール",
"agentManager.browser.empty": "ローカルアプリケーションを開くと、ここでプレビューできます。",
"agentManager.browser.noSession": "先に Agent Manager セッションを選択してください。",
"agentManager.browser.noSession":
"ローカルアプリケーションを表示するには、Agent Manager でセッションを開始または選択してください。",
"agentManager.browser.screenshotAlt": "現在のブラウザーページ",
"agentManager.browser.errors": "ブラウザーの問題: {{count}} 件",
"agentManager.browser.diagnostics": "ブラウザー診断",
+2 -2
View File
@@ -425,7 +425,7 @@ export const dict = {
"agentManager.caffeination.armed": "Kilo 에이전트용 절전 방지 모드가 활성화되었습니다. 클릭하여 비활성화",
"agentManager.caffeination.active": "Kilo 에이전트가 작업하는 동안 컴퓨터를 절전 모드로 전환하지 않습니다",
"agentManager.caffeination.unavailable": "이 플랫폼에서는 절전 방지 모드를 사용할 수 없습니다",
"agentManager.browser.title": "브라우저",
"agentManager.browser.title": "통합 브라우저",
"agentManager.browser.url": "로컬 애플리케이션 URL",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "열기",
@@ -434,7 +434,7 @@ export const dict = {
"agentManager.browser.inspect": "요소 선택",
"agentManager.browser.devtoolsTitle": "개발자 도구",
"agentManager.browser.empty": "로컬 애플리케이션을 열어 여기에서 미리 보세요.",
"agentManager.browser.noSession": "먼저 Agent Manager 세션을 선택하세요.",
"agentManager.browser.noSession": "로컬 애플리케이션을 탐색하려면 Agent Manager에서 세션을 시작하거나 선택하세요.",
"agentManager.browser.screenshotAlt": "현재 브라우저 페이지",
"agentManager.browser.errors": "브라우저 문제: {{count}}개",
"agentManager.browser.diagnostics": "브라우저 진단",
+3 -2
View File
@@ -436,7 +436,7 @@ export const dict = {
"agentManager.caffeination.active": "Computer wordt wakker gehouden terwijl Kilo-agents werken",
"agentManager.caffeination.unavailable":
"De modus om de computer wakker te houden is niet beschikbaar op dit platform",
"agentManager.browser.title": "Browser",
"agentManager.browser.title": "Geïntegreerde browser",
"agentManager.browser.url": "URL van lokale applicatie",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "Openen",
@@ -445,7 +445,8 @@ export const dict = {
"agentManager.browser.refresh": "Browser vernieuwen",
"agentManager.browser.close": "Browser sluiten",
"agentManager.browser.empty": "Open een lokale applicatie om deze hier te bekijken.",
"agentManager.browser.noSession": "Selecteer eerst een sessie in Agent Manager.",
"agentManager.browser.noSession":
"Start of selecteer een sessie in Agent Manager om een lokale applicatie te bekijken.",
"agentManager.browser.screenshotAlt": "Huidige browserpagina",
"agentManager.browser.errors": "Browserproblemen: {{count}}",
"agentManager.browser.diagnostics": "Browserdiagnostiek",
+2 -2
View File
@@ -427,7 +427,7 @@ export const dict = {
"agentManager.caffeination.active": "Holder datamaskinen våken mens Kilo-agentene arbeider",
"agentManager.caffeination.unavailable":
"Modus for å holde datamaskinen våken er ikke tilgjengelig på denne plattformen",
"agentManager.browser.title": "Nettleser",
"agentManager.browser.title": "Integrert nettleser",
"agentManager.browser.url": "URL for lokal applikasjon",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "Åpne",
@@ -436,7 +436,7 @@ export const dict = {
"agentManager.browser.refresh": "Oppdater nettleser",
"agentManager.browser.close": "Lukk nettleser",
"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.noSession": "Start eller velg en økt i Agent Manager for å bla i en lokal applikasjon.",
"agentManager.browser.screenshotAlt": "Gjeldende nettleserside",
"agentManager.browser.errors": "Nettleserproblemer: {{count}}",
"agentManager.browser.diagnostics": "Nettleserdiagnostikk",
+2 -2
View File
@@ -428,7 +428,7 @@ export const dict = {
"Tryb zapobiegania uśpieniu komputera włączony dla agentów Kilo; kliknij, aby wyłączyć",
"agentManager.caffeination.active": "Komputer pozostaje aktywny, gdy agenci Kilo pracują",
"agentManager.caffeination.unavailable": "Tryb utrzymywania komputera aktywnego jest niedostępny na tej platformie",
"agentManager.browser.title": "Przeglądarka",
"agentManager.browser.title": "Zintegrowana przeglądarka",
"agentManager.browser.url": "URL lokalnej aplikacji",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "Otwórz",
@@ -437,7 +437,7 @@ export const dict = {
"agentManager.browser.refresh": "Odśwież przeglądarkę",
"agentManager.browser.close": "Zamknij przeglądarkę",
"agentManager.browser.empty": "Otwórz lokalną aplikację, aby wyświetlić ją tutaj.",
"agentManager.browser.noSession": "Najpierw wybierz sesję aplikacji Agent Manager.",
"agentManager.browser.noSession": "Uruchom lub wybierz sesję w Agent Manager, aby przeglądać lokalną aplikację.",
"agentManager.browser.screenshotAlt": "Bieżąca strona przeglądarki",
"agentManager.browser.errors": "Problemy przeglądarki: {{count}}",
"agentManager.browser.diagnostics": "Diagnostyka przeglądarki",
+2 -2
View File
@@ -430,7 +430,7 @@ export const dict = {
"agentManager.caffeination.armed": "Режим предотвращения сна включён для агентов Kilo; нажмите для отключения",
"agentManager.caffeination.active": "Компьютер не переходит в спящий режим, пока работают агенты Kilo",
"agentManager.caffeination.unavailable": "Режим предотвращения сна недоступен на этой платформе",
"agentManager.browser.title": "Браузер",
"agentManager.browser.title": "Встроенный браузер",
"agentManager.browser.url": "URL локального приложения",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "Открыть",
@@ -439,7 +439,7 @@ export const dict = {
"agentManager.browser.inspect": "Выбрать элемент",
"agentManager.browser.devtoolsTitle": "Инструменты разработчика",
"agentManager.browser.empty": "Откройте локальное приложение, чтобы просмотреть его здесь.",
"agentManager.browser.noSession": "Сначала выберите сеанс Agent Manager.",
"agentManager.browser.noSession": "Запустите или выберите сеанс в Agent Manager, чтобы открыть локальное приложение.",
"agentManager.browser.screenshotAlt": "Текущая страница браузера",
"agentManager.browser.errors": "Проблемы браузера: {{count}}",
"agentManager.browser.diagnostics": "Диагностика браузера",
+2 -2
View File
@@ -419,7 +419,7 @@ export const dict = {
"agentManager.caffeination.armed": "เปิดโหมดป้องกันการพักเครื่องสำหรับเอเจนต์ Kilo แล้ว คลิกเพื่อปิดใช้งาน",
"agentManager.caffeination.active": "กำลังป้องกันคอมพิวเตอร์เข้าสู่โหมดพักขณะเอเจนต์ Kilo ทำงาน",
"agentManager.caffeination.unavailable": "โหมดป้องกันการพักเครื่องไม่พร้อมใช้งานบนแพลตฟอร์มนี้",
"agentManager.browser.title": "เบราว์เซอร์",
"agentManager.browser.title": "เบราว์เซอร์ในตัว",
"agentManager.browser.url": "URL ของแอปพลิเคชันในเครื่อง",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "เปิด",
@@ -428,7 +428,7 @@ export const dict = {
"agentManager.browser.inspect": "เลือกองค์ประกอบ",
"agentManager.browser.devtoolsTitle": "เครื่องมือสำหรับนักพัฒนา",
"agentManager.browser.empty": "เปิดแอปพลิเคชันในเครื่องเพื่อดูตัวอย่างที่นี่",
"agentManager.browser.noSession": "เลือกเซสชัน Agent Manager ก่อน",
"agentManager.browser.noSession": "เริ่มหรือเลือกเซสชันใน Agent Manager เพื่อเรียกดูแอปพลิเคชันในเครื่อง",
"agentManager.browser.screenshotAlt": "หน้าปัจจุบันของเบราว์เซอร์",
"agentManager.browser.errors": "ปัญหาเบราว์เซอร์: {{count}} รายการ",
"agentManager.browser.diagnostics": "การวินิจฉัยเบราว์เซอร์",
+3 -2
View File
@@ -436,7 +436,7 @@ export const dict = {
"Kilo ajanları için bilgisayarı uyanık tutma modu etkin; devre dışı bırakmak için tıklayın",
"agentManager.caffeination.active": "Kilo ajanları çalışırken bilgisayar uyanık tutuluyor",
"agentManager.caffeination.unavailable": "Bilgisayarı uyanık tutma modu bu platformda kullanılamıyor",
"agentManager.browser.title": "Tarayıcı",
"agentManager.browser.title": "Entegre Tarayıcı",
"agentManager.browser.url": "Yerel uygulama URL'si",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "Aç",
@@ -445,7 +445,8 @@ export const dict = {
"agentManager.browser.inspect": "Öğeyi seç",
"agentManager.browser.devtoolsTitle": "Geliştirici araçları",
"agentManager.browser.empty": "Burada önizlemek için yerel bir uygulama açın.",
"agentManager.browser.noSession": "Önce bir Agent Manager oturumu seçin.",
"agentManager.browser.noSession":
"Yerel bir uygulamada gezinmek için Agent Manager'da bir oturum başlatın veya seçin.",
"agentManager.browser.screenshotAlt": "Geçerli tarayıcı sayfası",
"agentManager.browser.errors": "Tarayıcı sorunları: {{count}}",
"agentManager.browser.diagnostics": "Tarayıcı tanılaması",
+2 -2
View File
@@ -438,7 +438,7 @@ export const dict = {
"agentManager.caffeination.armed": "Режим запобігання сну ввімкнено для агентів Kilo; натисніть, щоб вимкнути",
"agentManager.caffeination.active": "Комп'ютер не переходить у режим сну, доки працюють агенти Kilo",
"agentManager.caffeination.unavailable": "Режим запобігання сну недоступний на цій платформі",
"agentManager.browser.title": "Браузер",
"agentManager.browser.title": "Вбудований браузер",
"agentManager.browser.url": "URL локальної програми",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "Відкрити",
@@ -447,7 +447,7 @@ export const dict = {
"agentManager.browser.inspect": "Вибрати елемент",
"agentManager.browser.devtoolsTitle": "Інструменти розробника",
"agentManager.browser.empty": "Відкрийте локальну програму, щоб переглянути її тут.",
"agentManager.browser.noSession": "Спочатку виберіть сесію Agent Manager.",
"agentManager.browser.noSession": "Запустіть або виберіть сесію в Agent Manager, щоб відкрити локальний застосунок.",
"agentManager.browser.screenshotAlt": "Поточна сторінка браузера",
"agentManager.browser.errors": "Проблеми браузера: {{count}}",
"agentManager.browser.diagnostics": "Діагностика браузера",
+2 -2
View File
@@ -415,7 +415,7 @@ export const dict = {
"agentManager.caffeination.active": "Kilo 代理工作期间保持电脑唤醒",
"agentManager.caffeination.unavailable": "此平台不支持保持唤醒模式",
"agentManager.browser.title": "浏览器",
"agentManager.browser.title": "集成浏览器",
"agentManager.browser.url": "本地应用 URL",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "打开",
@@ -424,7 +424,7 @@ export const dict = {
"agentManager.browser.inspect": "选择元素",
"agentManager.browser.devtoolsTitle": "开发者工具",
"agentManager.browser.empty": "打开本地应用以在此处预览。",
"agentManager.browser.noSession": "请先选择 Agent Manager 会话。",
"agentManager.browser.noSession": "请 Agent Manager 中启动或选择会话以浏览本地应用。",
"agentManager.browser.screenshotAlt": "当前浏览器页面",
"agentManager.browser.errors": "浏览器问题:{{count}}",
"agentManager.browser.diagnostics": "浏览器诊断",
+2 -2
View File
@@ -414,7 +414,7 @@ export const dict = {
"agentManager.caffeination.armed": "已為 Kilo 代理啟用保持喚醒模式;點擊以停用",
"agentManager.caffeination.active": "Kilo 代理工作期間保持電腦喚醒",
"agentManager.caffeination.unavailable": "此平台無法使用保持喚醒模式",
"agentManager.browser.title": "瀏覽器",
"agentManager.browser.title": "整合瀏覽器",
"agentManager.browser.url": "本機應用程式 URL",
"agentManager.browser.urlPlaceholder": "http://localhost:3000",
"agentManager.browser.open": "開啟",
@@ -423,7 +423,7 @@ export const dict = {
"agentManager.browser.inspect": "選取元素",
"agentManager.browser.devtoolsTitle": "開發人員工具",
"agentManager.browser.empty": "開啟本機應用程式,即可在此處預覽。",
"agentManager.browser.noSession": "請先選取 Agent Manager 工作階段。",
"agentManager.browser.noSession": "請 Agent Manager 中啟動或選取工作階段以瀏覽本機應用程式。",
"agentManager.browser.screenshotAlt": "目前的瀏覽器頁面",
"agentManager.browser.errors": "瀏覽器問題:{{count}}",
"agentManager.browser.diagnostics": "瀏覽器診斷",
@@ -24,9 +24,10 @@ export function createSidePanel(opts: {
const id = opts.current()
return id ? JSON.stringify([opts.project() ?? "single", id]) : undefined
}
// A draft can show the browser's no-session guidance without creating a backend session.
const owner = () => session() ?? JSON.stringify([opts.project() ?? "single", opts.selection(), null])
const selected = () => {
const id = session()
const override = id ? sessions()[id] : undefined
const override = sessions()[owner()]
return override !== undefined ? override : (worktrees()[worktree()] ?? null)
}
const panel = () => {
@@ -36,21 +37,22 @@ export function createSidePanel(opts: {
const open = (value: SidePanel) => {
const id = session()
if (ownership[value] === "session") {
if (id) setSessions((prev) => ({ ...prev, [id]: value }))
if (id || value === SidePanel.Browser) setSessions((prev) => ({ ...prev, [owner()]: value }))
return
}
const key = worktree()
batch(() => {
setWorktrees((prev) => ({ ...prev, [key]: value }))
if (id) setSessions((prev) => ({ ...prev, [id]: undefined }))
setSessions((prev) => ({ ...prev, [owner()]: undefined }))
})
}
const close = (expected?: SidePanel) => {
const value = selected()
if (!value || (expected && value !== expected)) return
const id = session()
if (ownership[value] === "session" && id) {
setSessions((prev) => ({ ...prev, [id]: null }))
if (ownership[value] === "session") {
// A draft has no worktree panel to mask, so drop its entry instead of
// storing an authoritative null that would hide later worktree panels.
setSessions((prev) => ({ ...prev, [owner()]: session() ? null : undefined }))
return
}
setWorktrees((prev) => ({ ...prev, [worktree()]: null }))
@@ -29,7 +29,9 @@ const BrowserTab: Component = () => {
const { globalConfig, projectConfig, updateGlobalConfig } = useConfig()
const [settings, setSettings] = createSignal<BrowserSettings>({
enabled: false,
useSystemChrome: true,
headless: false,
})
onMount(() => {
@@ -118,6 +120,16 @@ const BrowserTab: Component = () => {
{t("settings.browser.description")}
</p>
<Card>
{/* Enable toggle */}
<SettingsRow
title={t("settings.browser.enable.title")}
description={t("settings.browser.enable.description")}
>
<Switch checked={settings().enabled} onChange={(checked: boolean) => update("enabled", checked)} hideLabel>
{t("settings.browser.enable.title")}
</Switch>
</SettingsRow>
{/* Use System Chrome */}
<SettingsRow
title={t("settings.browser.systemChrome.title")}
@@ -131,12 +143,18 @@ const BrowserTab: Component = () => {
{t("settings.browser.systemChrome.title")}
</Switch>
</SettingsRow>
{/* Headless mode */}
<SettingsRow
title={t("settings.browser.headless.title")}
description={t("settings.browser.headless.description")}
last
>
<Switch checked disabled hideLabel>
<Switch
checked={settings().headless}
onChange={(checked: boolean) => update("headless", checked)}
hideLabel
>
{t("settings.browser.headless.title")}
</Switch>
</SettingsRow>
@@ -231,15 +231,30 @@ const ExperimentalTab: Component = () => {
</SettingsRow>
<SettingsRow
title={language.t("settings.browser.enable.title")}
description={language.t("settings.browser.enable.description")}
title={language.t("settings.experimental.browserAutomation.title")}
description={language.t("settings.experimental.browserAutomation.description")}
>
<Switch
checked={settings().browserAutomation === true}
onChange={(checked) => applySetting("browserAutomation", checked, "experimental.browserAutomation")}
hideLabel
>
{language.t("settings.browser.enable.title")}
{language.t("settings.experimental.browserAutomation.title")}
</Switch>
</SettingsRow>
<SettingsRow
title={language.t("settings.experimental.browserAutomation.systemChrome.title")}
description={language.t("settings.experimental.browserAutomation.systemChrome.description")}
>
<Switch
checked={settings().agentManagerBrowserUseSystemChrome !== false}
onChange={(checked) =>
applySetting("agentManagerBrowserUseSystemChrome", checked, "agentManager.browser.useSystemChrome")
}
hideLabel
>
{language.t("settings.experimental.browserAutomation.systemChrome.title")}
</Switch>
</SettingsRow>
+7 -1
View File
@@ -827,7 +827,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "المهارات",
"settings.browser.description":
"عند التفعيل، يمكن لوكيل الذكاء الاصطناعي التفاعل مع صفحات الويب — التنقل والنقر والكتابة والتقاط لقطات الشاشة. سيتم فتح نافذة Chrome حتى تتمكن من مشاهدة الوكيل أثناء العمل.",
"تكوين أتمتة المتصفح المدمجة المدعومة من Playwright. يمكن لـ Kilo التنقل والتفاعل مع صفحات الويب والتقاط لقطات شاشة لها في جلساتك.",
"settings.browser.enable.title": "تفعيل أتمتة المتصفح",
"settings.browser.enable.description": "تسجيل خادم Playwright MCP مع الواجهة الخلفية لـ CLI.",
"settings.browser.systemChrome.title": "استخدام Chrome النظام",
@@ -1325,5 +1325,11 @@ export const dict = {
"chat.search.close": "إغلاق البحث",
"chat.search.invalidRegex": "تعبير عادي غير صالح",
"chat.search.noResults": "لا توجد نتائج",
"settings.experimental.browserAutomation.title": "المتصفح المدمج",
"settings.experimental.browserAutomation.description":
"عرض معاينات التطبيقات المحلية في Agent Manager وإتاحة أداة browser_open لجلسات Agent Manager.",
"settings.experimental.browserAutomation.systemChrome.title": "استخدام Chrome النظام",
"settings.experimental.browserAutomation.systemChrome.description":
"استخدام Google Chrome المثبّت للمتصفح المدمج. عطّله فقط عند تثبيت متصفح Playwright Chromium متوافق.",
"chat.search.searchingHistory": "جارٍ البحث في الرسائل السابقة…",
}
+7 -1
View File
@@ -850,7 +850,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "Habilidades",
"settings.browser.description":
"Quando ativado, o agente de IA pode interagir com páginas da web — navegar, clicar, digitar e capturar telas. Uma janela do Chrome será aberta para que você possa acompanhar o trabalho do agente.",
"Configure a automação de navegador integrada com tecnologia Playwright. O Kilo pode navegar, interagir e capturar telas de páginas da web nas suas sessões.",
"settings.browser.enable.title": "Ativar Automação do Navegador",
"settings.browser.enable.description": "Registrar o servidor Playwright MCP no backend CLI.",
"settings.browser.systemChrome.title": "Usar Chrome do Sistema",
@@ -1370,5 +1370,11 @@ export const dict = {
"chat.search.close": "Fechar pesquisa",
"chat.search.invalidRegex": "Expressão regular inválida",
"chat.search.noResults": "Nenhum resultado",
"settings.experimental.browserAutomation.title": "Navegador Integrado",
"settings.experimental.browserAutomation.description":
"Mostre pré-visualizações de aplicativos locais no Agent Manager e exponha a ferramenta browser_open para sessões do Agent Manager.",
"settings.experimental.browserAutomation.systemChrome.title": "Usar Chrome do Sistema",
"settings.experimental.browserAutomation.systemChrome.description":
"Use o Google Chrome instalado para o Navegador Integrado. Desative apenas quando um navegador Playwright Chromium compatível já estiver instalado.",
"chat.search.searchingHistory": "Pesquisando mensagens anteriores…",
}
+7 -1
View File
@@ -847,7 +847,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "Vještine",
"settings.browser.description":
"Kada je omogućeno, AI agent može komunicirati s web stranicama — navigirati, klikati, tipkati i snimati ekran. Chrome prozor će se otvoriti kako biste mogli pratiti rad agenta.",
"Konfigurirajte ugrađenu automatizaciju preglednika koju pokreće Playwright. Kilo može navigirati, komunicirati sa web stranicama i snimati ekran u vašim sesijama.",
"settings.browser.enable.title": "Omogući automatizaciju preglednika",
"settings.browser.enable.description": "Registriraj Playwright MCP server s CLI pozadinom.",
"settings.browser.systemChrome.title": "Koristi sistemski Chrome",
@@ -1361,5 +1361,11 @@ export const dict = {
"chat.search.close": "Zatvori pretragu",
"chat.search.invalidRegex": "Nevažeći regularni izraz",
"chat.search.noResults": "Nema rezultata",
"settings.experimental.browserAutomation.title": "Integrirani preglednik",
"settings.experimental.browserAutomation.description":
"Prikažite preglede lokalnih aplikacija u Agent Manageru i omogućite alat browser_open sesijama Agent Managera.",
"settings.experimental.browserAutomation.systemChrome.title": "Koristi sistemski Chrome",
"settings.experimental.browserAutomation.systemChrome.description":
"Koristite instalirani Google Chrome za Integrirani preglednik. Onemogućite samo kada je kompatibilni Playwright Chromium preglednik već instaliran.",
"chat.search.searchingHistory": "Pretraživanje ranijih poruka…",
}
+7 -1
View File
@@ -846,7 +846,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "Færdigheder",
"settings.browser.description":
"Når aktiveret kan AI-agenten interagere med websider — navigere, klikke, skrive og tage skærmbilleder. Et Chrome-vindue åbnes, så du kan se agenten arbejde.",
"Konfigurér indbygget browserautomatisering drevet af Playwright. Kilo kan navigere, interagere med og tage skærmbilleder af websider i dine sessioner.",
"settings.browser.enable.title": "Aktivér browserautomatisering",
"settings.browser.enable.description": "Registrér Playwright MCP-serveren hos CLI-backend'en.",
"settings.browser.systemChrome.title": "Brug system-Chrome",
@@ -1355,5 +1355,11 @@ export const dict = {
"chat.search.close": "Luk søgning",
"chat.search.invalidRegex": "Ugyldigt regulært udtryk",
"chat.search.noResults": "Ingen resultater",
"settings.experimental.browserAutomation.title": "Integreret browser",
"settings.experimental.browserAutomation.description":
"Vis forhåndsvisninger af lokale applikationer i Agent Manager, og gør værktøjet browser_open tilgængeligt for Agent Manager-sessioner.",
"settings.experimental.browserAutomation.systemChrome.title": "Brug system-Chrome",
"settings.experimental.browserAutomation.systemChrome.description":
"Brug den installerede Google Chrome til den integrerede browser. Deaktivér kun, når en kompatibel Playwright Chromium-browser allerede er installeret.",
"chat.search.searchingHistory": "Søger i tidligere beskeder…",
}
@@ -861,7 +861,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "Fähigkeiten",
"settings.browser.description":
"Wenn aktiviert, kann der KI-Agent mit Webseiten interagieren — navigieren, klicken, tippen und Screenshots erstellen. Ein Chrome-Fenster wird geöffnet, damit Sie dem Agenten bei der Arbeit zusehen können.",
"Integrierte Browser-Automatisierung auf Basis von Playwright konfigurieren. Kilo kann in Ihren Sitzungen Webseiten aufrufen, mit ihnen interagieren und Screenshots erstellen.",
"settings.browser.enable.title": "Browser-Automatisierung aktivieren",
"settings.browser.enable.description": "Den Playwright-MCP-Server beim CLI-Backend registrieren.",
"settings.browser.systemChrome.title": "System-Chrome verwenden",
@@ -1383,5 +1383,11 @@ export const dict = {
"chat.search.close": "Suche schließen",
"chat.search.invalidRegex": "Ungültiger regulärer Ausdruck",
"chat.search.noResults": "Keine Ergebnisse",
"settings.experimental.browserAutomation.title": "Integrierter Browser",
"settings.experimental.browserAutomation.description":
"Lokale Anwendungsvorschauen im Agent Manager anzeigen und das Tool browser_open für Agent Manager-Sitzungen bereitstellen.",
"settings.experimental.browserAutomation.systemChrome.title": "System-Chrome verwenden",
"settings.experimental.browserAutomation.systemChrome.description":
"Das installierte Google Chrome für den integrierten Browser verwenden. Nur deaktivieren, wenn bereits ein kompatibler Playwright-Chromium-Browser installiert ist.",
"chat.search.searchingHistory": "Frühere Nachrichten werden durchsucht…",
} satisfies Partial<Record<Keys, string>>
@@ -820,15 +820,14 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "Skills",
"settings.browser.description":
"Configure the browser runtime used by the experimental Agent Manager browser. The page preview stays in Agent Manager.",
"Configure built-in browser automation powered by Playwright. Kilo can navigate, interact with, and screenshot web pages in your sessions.",
"settings.browser.enable.title": "Enable Browser Automation",
"settings.browser.enable.description": "Enable the session-scoped Agent Manager browser for local applications.",
"settings.browser.enable.description": "Register the Playwright MCP server with the CLI backend.",
"settings.browser.systemChrome.title": "Use System Chrome",
"settings.browser.systemChrome.description":
"Use installed Google Chrome. Disable only when a compatible Playwright Chromium browser is already installed.",
"settings.browser.headless.title": "Headless Mode",
"settings.browser.headless.description":
"Agent Manager always runs the browser headlessly. The page preview appears in the Browser panel.",
"settings.browser.headless.description": "Run in headless mode (no visible browser window).",
"settings.language.description":
'Choose the language for the Kilo Code UI. "Auto" uses your VS Code display language.',
@@ -924,6 +923,12 @@ export const dict = {
"settings.experimental.multiProject.title": "Multi-Project Agent Manager",
"settings.experimental.multiProject.description":
"Enable managing sessions and worktrees across multiple repositories in Agent Manager. The current workspace repository is always the default project.",
"settings.experimental.browserAutomation.title": "Integrated Browser",
"settings.experimental.browserAutomation.description":
"Show local application previews in Agent Manager and expose the browser_open tool to Agent Manager sessions.",
"settings.experimental.browserAutomation.systemChrome.title": "Use System Chrome",
"settings.experimental.browserAutomation.systemChrome.description":
"Use installed Google Chrome for the Integrated Browser. Disable only when a compatible Playwright Chromium browser is already installed.",
"settings.experimental.claudeMigration.title": "Claude Code Migration",
"settings.experimental.claudeMigration.description":
"On the next backend start, import supported global CLAUDE.md instructions, simple skills, and disabled MCP definitions. This runs once with no automatic retry; global Claude instructions and skills are then handed off to Kilo. Claude files stay unchanged; keep them if you still use Claude Code.",
+7 -1
View File
@@ -853,7 +853,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "Habilidades",
"settings.browser.description":
"Cuando está activado, el agente de IA puede interactuar con páginas web: navegar, hacer clic, escribir y capturar pantallas. Se abrirá una ventana de Chrome para que puedas ver al agente trabajar.",
"Configura la automatización de navegador integrada basada en Playwright. Kilo puede navegar, interactuar y capturar pantallas de páginas web en tus sesiones.",
"settings.browser.enable.title": "Activar automatización del navegador",
"settings.browser.enable.description": "Registrar el servidor Playwright MCP con el backend CLI.",
"settings.browser.systemChrome.title": "Usar Chrome del sistema",
@@ -1371,5 +1371,11 @@ export const dict = {
"chat.search.close": "Cerrar búsqueda",
"chat.search.invalidRegex": "Expresión regular no válida",
"chat.search.noResults": "Sin resultados",
"settings.experimental.browserAutomation.title": "Navegador integrado",
"settings.experimental.browserAutomation.description":
"Muestra vistas previas de aplicaciones locales en Agent Manager y expone la herramienta browser_open a las sesiones de Agent Manager.",
"settings.experimental.browserAutomation.systemChrome.title": "Usar Chrome del sistema",
"settings.experimental.browserAutomation.systemChrome.description":
"Usa el Google Chrome instalado para el Navegador integrado. Desactívalo solo si ya hay instalado un navegador Playwright Chromium compatible.",
"chat.search.searchingHistory": "Buscando en mensajes anteriores…",
}
+7 -1
View File
@@ -827,7 +827,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "مهارت‌ها",
"settings.browser.description":
"وقتی فعال است، عامل هوش مصنوعی می‌تواند با صفحات وب تعامل داشته باشد — پیمایش، کلیک، تایپ و گرفتن اسکرین‌شات. یک پنجره Chrome باز می‌شود تا بتوانید عملکرد عامل را مشاهده کنید.",
"پیکربندی اتوماسیون مرورگر داخلی با پشتیبانی Playwright. Kilo می‌تواند در جلسات شما در صفحات وب پیمایش کند، با آن‌ها تعامل داشته باشد و اسکرین‌شات بگیرد.",
"settings.browser.enable.title": "فعال‌سازی اتوماسیون مرورگر",
"settings.browser.enable.description": "سرور Playwright MCP را با بک‌اند CLI ثبت کنید.",
"settings.browser.systemChrome.title": "استفاده از Chrome سیستم",
@@ -1355,5 +1355,11 @@ export const dict = {
"chat.search.close": "بستن جستجو",
"chat.search.invalidRegex": "عبارت منظم نامعتبر",
"chat.search.noResults": "نتیجه‌ای یافت نشد",
"settings.experimental.browserAutomation.title": "مرورگر یکپارچه",
"settings.experimental.browserAutomation.description":
"پیش‌نمایش برنامه‌های محلی را در Agent Manager نشان دهید و ابزار browser_open را در اختیار جلسات Agent Manager قرار دهید.",
"settings.experimental.browserAutomation.systemChrome.title": "استفاده از Chrome سیستم",
"settings.experimental.browserAutomation.systemChrome.description":
"از Google Chrome نصب‌شده برای مرورگر یکپارچه استفاده کنید. فقط زمانی غیرفعال کنید که مرورگر Playwright Chromium سازگار از قبل نصب شده باشد.",
"chat.search.searchingHistory": "در حال جستجو در پیام‌های قبلی…",
}
+7 -1
View File
@@ -863,7 +863,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "Compétences",
"settings.browser.description":
"Lorsqu'il est activé, l'agent IA peut interagir avec les pages web — naviguer, cliquer, saisir du texte et prendre des captures d'écran. Une fenêtre Chrome s'ouvrira pour que vous puissiez observer l'agent travailler.",
"Configurez l'automatisation de navigateur intégrée propulsée par Playwright. Kilo peut naviguer, interagir et prendre des captures d'écran de pages web dans vos sessions.",
"settings.browser.enable.title": "Activer l'automatisation du navigateur",
"settings.browser.enable.description": "Enregistrer le serveur Playwright MCP auprès du backend CLI.",
"settings.browser.systemChrome.title": "Utiliser le Chrome système",
@@ -1392,5 +1392,11 @@ export const dict = {
"chat.search.close": "Fermer la recherche",
"chat.search.invalidRegex": "Expression régulière non valide",
"chat.search.noResults": "Aucun résultat",
"settings.experimental.browserAutomation.title": "Navigateur intégré",
"settings.experimental.browserAutomation.description":
"Affichez des aperçus d'applications locales dans Agent Manager et exposez l'outil browser_open aux sessions Agent Manager.",
"settings.experimental.browserAutomation.systemChrome.title": "Utiliser le Chrome système",
"settings.experimental.browserAutomation.systemChrome.description":
"Utilisez le Google Chrome installé pour le Navigateur intégré. Désactivez uniquement lorsqu'un navigateur Playwright Chromium compatible est déjà installé.",
"chat.search.searchingHistory": "Recherche dans les messages précédents…",
}
+7 -1
View File
@@ -711,7 +711,7 @@ export const dict = {
"settings.agentBehaviour.subtab.workflows": "Workflow",
"settings.agentBehaviour.subtab.skills": "Skill",
"settings.browser.description":
"Quando è abilitato, l'agente AI può interagire con pagine web: navigare, fare clic, scrivere e acquisire screenshot. Si aprirà una finestra Chrome così puoi osservare il lavoro dell'agente.",
"Configura l'automazione del browser integrata basata su Playwright. Kilo può navigare, interagire e acquisire screenshot delle pagine web nelle tue sessioni.",
"settings.browser.enable.title": "Abilita automazione browser",
"settings.browser.enable.description": "Registra il server MCP Playwright con il backend CLI.",
"settings.browser.systemChrome.title": "Usa Chrome di sistema",
@@ -1337,5 +1337,11 @@ export const dict = {
"chat.search.close": "Chiudi ricerca",
"chat.search.invalidRegex": "Espressione regolare non valida",
"chat.search.noResults": "Nessun risultato",
"settings.experimental.browserAutomation.title": "Browser integrato",
"settings.experimental.browserAutomation.description":
"Mostra le anteprime delle applicazioni locali in Agent Manager ed esponi lo strumento browser_open alle sessioni di Agent Manager.",
"settings.experimental.browserAutomation.systemChrome.title": "Usa Chrome di sistema",
"settings.experimental.browserAutomation.systemChrome.description":
"Usa il Google Chrome installato per il Browser integrato. Disattivalo solo se è già installato un browser Playwright Chromium compatibile.",
"chat.search.searchingHistory": "Ricerca nei messaggi precedenti…",
} as const
+7 -1
View File
@@ -841,7 +841,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "スキル",
"settings.browser.description":
"有効にすると、AIエージェントがWebページを操作できるようになります — ナビゲーション、クリック、入力、スクリーンショット撮影。Chromeウィンドウが開き、エージェントの作業を確認できます。",
"Playwrightを利用した組み込みブラウザ自動化を設定します。Kiloはセッション内でWebページのナビゲーション、操作、スクリーンショット撮影を行えます。",
"settings.browser.enable.title": "ブラウザ自動化を有効にする",
"settings.browser.enable.description": "Playwright MCPサーバーをCLIバックエンドに登録します。",
"settings.browser.systemChrome.title": "システムChromeを使用",
@@ -1347,5 +1347,11 @@ export const dict = {
"chat.search.close": "検索を閉じる",
"chat.search.invalidRegex": "正規表現が無効です",
"chat.search.noResults": "見つかりませんでした",
"settings.experimental.browserAutomation.title": "統合ブラウザー",
"settings.experimental.browserAutomation.description":
"Agent Manager でローカルアプリケーションのプレビューを表示し、browser_open ツールを Agent Manager セッションに公開します。",
"settings.experimental.browserAutomation.systemChrome.title": "システムChromeを使用",
"settings.experimental.browserAutomation.systemChrome.description":
"統合ブラウザーにインストール済みの Google Chrome を使用します。互換性のある Playwright Chromium ブラウザーが既にインストールされている場合にのみ無効にしてください。",
"chat.search.searchingHistory": "以前のメッセージを検索しています…",
}
+7 -1
View File
@@ -839,7 +839,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "스킬",
"settings.browser.description":
"활성화하면 AI 에이전트가 웹 페이지와 상호작용할 수 있습니다 — 탐색, 클릭, 입력, 스크린샷 촬영. Chrome 창이 열려 에이전트의 작업을 확인할 수 있습니다.",
"Playwright 기반의 내장 브라우저 자동화를 구성합니다. Kilo는 세션에서 웹 페이지를 탐색하고 상호 작용하며 스크린샷을 찍을 수 있습니다.",
"settings.browser.enable.title": "브라우저 자동화 활성화",
"settings.browser.enable.description": "Playwright MCP 서버를 CLI 백엔드에 등록합니다.",
"settings.browser.systemChrome.title": "시스템 Chrome 사용",
@@ -1334,5 +1334,11 @@ export const dict = {
"chat.search.close": "검색 닫기",
"chat.search.invalidRegex": "정규식이 잘못되었습니다",
"chat.search.noResults": "검색 결과 없음",
"settings.experimental.browserAutomation.title": "통합 브라우저",
"settings.experimental.browserAutomation.description":
"Agent Manager에서 로컬 애플리케이션 미리보기를 표시하고 browser_open 도구를 Agent Manager 세션에 노출합니다.",
"settings.experimental.browserAutomation.systemChrome.title": "시스템 Chrome 사용",
"settings.experimental.browserAutomation.systemChrome.description":
"통합 브라우저에 설치된 Google Chrome을 사용합니다. 호환되는 Playwright Chromium 브라우저가 이미 설치된 경우에만 비활성화하세요.",
"chat.search.searchingHistory": "이전 메시지를 검색하는 중…",
}
+7 -1
View File
@@ -839,7 +839,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "Skills",
"settings.browser.description":
"Indien ingeschakeld kan de AI agent interactie hebben met webpagina's navigeren, klikken, typen en screenshots maken. Er wordt een Chrome-venster geopend zodat je de agent aan het werk kunt zien.",
"Configureer ingebouwde browserautomatisering mogelijk gemaakt door Playwright. Kilo kan in je sessies door webpagina's navigeren, ermee werken en schermafbeeldingen maken.",
"settings.browser.enable.title": "Browserautomatisering inschakelen",
"settings.browser.enable.description": "Registreer de Playwright MCP-server bij de CLI backend.",
"settings.browser.systemChrome.title": "Gebruik Systeem Chrome",
@@ -1383,5 +1383,11 @@ export const dict = {
"chat.search.close": "Zoeken sluiten",
"chat.search.invalidRegex": "Ongeldige reguliere expressie",
"chat.search.noResults": "Geen resultaten",
"settings.experimental.browserAutomation.title": "Geïntegreerde browser",
"settings.experimental.browserAutomation.description":
"Toon voorbeelden van lokale applicaties in Agent Manager en stel de tool browser_open beschikbaar aan Agent Manager-sessies.",
"settings.experimental.browserAutomation.systemChrome.title": "Gebruik Systeem Chrome",
"settings.experimental.browserAutomation.systemChrome.description":
"Gebruik de geïnstalleerde Google Chrome voor de geïntegreerde browser. Schakel dit alleen uit als er al een compatibele Playwright Chromium-browser is geïnstalleerd.",
"chat.search.searchingHistory": "Eerdere berichten doorzoeken…",
}
+7 -1
View File
@@ -807,7 +807,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "Ferdigheter",
"settings.browser.description":
"Når aktivert kan AI-agenten samhandle med nettsider — navigere, klikke, skrive og ta skjermbilder. Et Chrome-vindu åpnes slik at du kan se agenten jobbe.",
"Konfigurer innebygd nettleserautomatisering drevet av Playwright. Kilo kan navigere, samhandle med og ta skjermbilder av nettsider i øktene dine.",
"settings.browser.enable.title": "Aktiver nettleserautomatisering",
"settings.browser.enable.description": "Registrer Playwright MCP-serveren med CLI-backend.",
"settings.browser.systemChrome.title": "Bruk system-Chrome",
@@ -1352,5 +1352,11 @@ export const dict = {
"chat.search.close": "Lukk søk",
"chat.search.invalidRegex": "Ugyldig regulært uttrykk",
"chat.search.noResults": "Ingen resultater",
"settings.experimental.browserAutomation.title": "Integrert nettleser",
"settings.experimental.browserAutomation.description":
"Vis forhåndsvisninger av lokale applikasjoner i Agent Manager, og gjør verktøyet browser_open tilgjengelig for Agent Manager-økter.",
"settings.experimental.browserAutomation.systemChrome.title": "Bruk system-Chrome",
"settings.experimental.browserAutomation.systemChrome.description":
"Bruk den installerte Google Chrome for den integrerte nettleseren. Deaktiver bare når en kompatibel Playwright Chromium-nettleser allerede er installert.",
"chat.search.searchingHistory": "Søker i tidligere meldinger…",
} satisfies Partial<Record<Keys, string>>
+7 -1
View File
@@ -804,7 +804,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "Umiejętności",
"settings.browser.description":
"Po włączeniu agent AI może wchodzić w interakcję ze stronami internetowymi — nawigować, klikać, pisać i robić zrzuty ekranu. Otworzy się okno Chrome, abyś mógł obserwować pracę agenta.",
"Skonfiguruj wbudowaną automatyzację przeglądarki opartą na Playwright. Kilo może nawigować po stronach internetowych, wchodzić z nimi w interakcję i robić zrzuty ekranu w Twoich sesjach.",
"settings.browser.enable.title": "Włącz automatyzację przeglądarki",
"settings.browser.enable.description": "Zarejestruj serwer Playwright MCP w backendzie CLI.",
"settings.browser.systemChrome.title": "Użyj systemowego Chrome",
@@ -1360,5 +1360,11 @@ export const dict = {
"chat.search.close": "Zamknij wyszukiwanie",
"chat.search.invalidRegex": "Nieprawidłowe wyrażenie regularne",
"chat.search.noResults": "Brak wyników",
"settings.experimental.browserAutomation.title": "Zintegrowana przeglądarka",
"settings.experimental.browserAutomation.description":
"Wyświetlaj podglądy lokalnych aplikacji w Agent Manager i udostępniaj narzędzie browser_open sesjom Agent Manager.",
"settings.experimental.browserAutomation.systemChrome.title": "Użyj systemowego Chrome",
"settings.experimental.browserAutomation.systemChrome.description":
"Użyj zainstalowanej przeglądarki Google Chrome dla zintegrowanej przeglądarki. Wyłącz tylko wtedy, gdy zgodna przeglądarka Playwright Chromium jest już zainstalowana.",
"chat.search.searchingHistory": "Wyszukiwanie we wcześniejszych wiadomościach…",
}
+7 -1
View File
@@ -844,7 +844,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "Навыки",
"settings.browser.description":
"При включении ИИ-агент может взаимодействовать с веб-страницами — переходить по ссылкам, нажимать, вводить текст и делать скриншоты. Откроется окно Chrome, чтобы вы могли наблюдать за работой агента.",
"Настройте встроенную автоматизацию браузера на основе Playwright. Kilo может переходить по веб-страницам, взаимодействовать с ними и делать скриншоты в ваших сессиях.",
"settings.browser.enable.title": "Включить автоматизацию браузера",
"settings.browser.enable.description": "Зарегистрировать сервер Playwright MCP в CLI-бэкенде.",
"settings.browser.systemChrome.title": "Использовать системный Chrome",
@@ -1354,5 +1354,11 @@ export const dict = {
"chat.search.close": "Закрыть поиск",
"chat.search.invalidRegex": "Недопустимое регулярное выражение",
"chat.search.noResults": "Нет результатов",
"settings.experimental.browserAutomation.title": "Встроенный браузер",
"settings.experimental.browserAutomation.description":
"Показывайте предпросмотр локальных приложений в Agent Manager и предоставляйте инструмент browser_open сеансам Agent Manager.",
"settings.experimental.browserAutomation.systemChrome.title": "Использовать системный Chrome",
"settings.experimental.browserAutomation.systemChrome.description":
"Использовать установленный Google Chrome для встроенного браузера. Отключайте только если совместимый браузер Playwright Chromium уже установлен.",
"chat.search.searchingHistory": "Поиск в более ранних сообщениях…",
}
+7 -1
View File
@@ -834,7 +834,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "ทักษะ",
"settings.browser.description":
"เมื่อเปิดใช้งาน ตัวแทน AI สามารถโต้ตอบกับหน้าเว็บได้ — นำทาง คลิก พิมพ์ และจับภาพหน้าจอ หน้าต่าง Chrome จะเปิดขึ้นเพื่อให้คุณดูการทำงานของตัวแทน",
"กำหนดค่าการทำงานอัตโนมัติของเบราว์เซอร์ในตัวที่ขับเคลื่อนโดย Playwright Kilo สามารถนำทาง โต้ตอบ และจับภาพหน้าจอของหน้าเว็บในเซสชันของคุณได้",
"settings.browser.enable.title": "เปิดใช้งานการทำงานอัตโนมัติของเบราว์เซอร์",
"settings.browser.enable.description": "ลงทะเบียนเซิร์ฟเวอร์ Playwright MCP กับ CLI backend",
"settings.browser.systemChrome.title": "ใช้ Chrome ของระบบ",
@@ -1331,5 +1331,11 @@ export const dict = {
"chat.search.close": "ปิดการค้นหา",
"chat.search.invalidRegex": "นิพจน์ทั่วไปไม่ถูกต้อง",
"chat.search.noResults": "ไม่มีผลลัพธ์",
"settings.experimental.browserAutomation.title": "เบราว์เซอร์ในตัว",
"settings.experimental.browserAutomation.description":
"แสดงตัวอย่างแอปพลิเคชันในเครื่องใน Agent Manager และเปิดเผยเครื่องมือ browser_open ให้กับเซสชัน Agent Manager",
"settings.experimental.browserAutomation.systemChrome.title": "ใช้ Chrome ของระบบ",
"settings.experimental.browserAutomation.systemChrome.description":
"ใช้ Google Chrome ที่ติดตั้งไว้สำหรับเบราว์เซอร์ในตัว ปิดใช้งานเฉพาะเมื่อติดตั้งเบราว์เซอร์ Playwright Chromium ที่เข้ากันได้ไว้แล้วเท่านั้น",
"chat.search.searchingHistory": "กำลังค้นหาข้อความก่อนหน้า…",
}
+7 -1
View File
@@ -834,7 +834,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "Beceriler",
"settings.browser.description":
"Etkinleştirildiğinde, yapay zeka ajanı web sayfalarıyla etkileşime girebilir — gezinme, tıklama, yazma ve ekran görüntüsü alma. Ajanın çalışmasını izleyebilmeniz için bir Chrome penceresi açılacak.",
"Playwright ile çalışan yerleşik tarayıcı otomasyonunu yapılandırın. Kilo, oturumlarınızda web sayfalarında gezinebilir, bunlarla etkileşime girebilir ve ekran görüntüsü alabilir.",
"settings.browser.enable.title": "Tarayıcı Otomasyonunu Etkinleştir",
"settings.browser.enable.description": "Playwright MCP sunucusunu CLI arka ucuyla kaydet.",
"settings.browser.systemChrome.title": "Sistem Chrome'unu Kullan",
@@ -1370,5 +1370,11 @@ export const dict = {
"chat.search.close": "Aramayı kapat",
"chat.search.invalidRegex": "Geçersiz normal ifade",
"chat.search.noResults": "Sonuç yok",
"settings.experimental.browserAutomation.title": "Entegre Tarayıcı",
"settings.experimental.browserAutomation.description":
"Agent Manager'da yerel uygulama önizlemelerini gösterin ve browser_open aracını Agent Manager oturumlarına sunun.",
"settings.experimental.browserAutomation.systemChrome.title": "Sistem Chrome'unu Kullan",
"settings.experimental.browserAutomation.systemChrome.description":
"Entegre Tarayıcı için yüklü Google Chrome'u kullanın. Yalnızca uyumlu bir Playwright Chromium tarayıcısı zaten yüklüyse devre dışı bırakın.",
"chat.search.searchingHistory": "Önceki mesajlarda aranıyor…",
}
+7 -1
View File
@@ -834,7 +834,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "Навички",
"settings.browser.description":
"Після увімкнення агент ШІ може взаємодіяти з веб-сторінками — навігація, натискання, введення тексту та знімки екрана. Відкриється вікно Chrome, щоб ви могли стежити за роботою агента.",
"Налаштуйте вбудовану автоматизацію браузера на основі Playwright. Kilo може переходити веб-сторінками, взаємодіяти з ними та робити знімки екрана у ваших сесіях.",
"settings.browser.enable.title": "Увімкнути автоматизацію браузера",
"settings.browser.enable.description": "Зареєструвати MCP-сервер Playwright з CLI-бекендом.",
"settings.browser.systemChrome.title": "Використовувати системний Chrome",
@@ -1370,5 +1370,11 @@ export const dict = {
"chat.search.close": "Закрити пошук",
"chat.search.invalidRegex": "Недійсний регулярний вираз",
"chat.search.noResults": "Немає результатів",
"settings.experimental.browserAutomation.title": "Вбудований браузер",
"settings.experimental.browserAutomation.description":
"Показуйте попередній перегляд локальних застосунків в Agent Manager і надавайте інструмент browser_open сесіям Agent Manager.",
"settings.experimental.browserAutomation.systemChrome.title": "Використовувати системний Chrome",
"settings.experimental.browserAutomation.systemChrome.description":
"Використовувати встановлений Google Chrome для вбудованого браузера. Вимкніть лише якщо сумісний браузер Playwright Chromium уже встановлено.",
"chat.search.searchingHistory": "Пошук у попередніх повідомленнях…",
}
+7 -1
View File
@@ -814,7 +814,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "技能",
"settings.browser.description":
"启用后,AI 代理可以与网页交互 — 导航、点击、输入和截取屏幕截图。Chrome 窗口将打开,以便您观察代理的工作。",
"配置由 Playwright 提供支持的内置浏览器自动化。Kilo 可在你的会话中浏览网页、与网页交互并截取屏幕截图。",
"settings.browser.enable.title": "启用浏览器自动化",
"settings.browser.enable.description": "将 Playwright MCP 服务器注册到 CLI 后端。",
"settings.browser.systemChrome.title": "使用系统 Chrome",
@@ -1283,5 +1283,11 @@ export const dict = {
"chat.search.close": "关闭搜索",
"chat.search.invalidRegex": "正则表达式无效",
"chat.search.noResults": "无结果",
"settings.experimental.browserAutomation.title": "集成浏览器",
"settings.experimental.browserAutomation.description":
"在 Agent Manager 中显示本地应用预览,并向 Agent Manager 会话公开 browser_open 工具。",
"settings.experimental.browserAutomation.systemChrome.title": "使用系统 Chrome",
"settings.experimental.browserAutomation.systemChrome.description":
"为集成浏览器使用已安装的 Google Chrome。仅在已安装兼容的 Playwright Chromium 浏览器时才禁用。",
"chat.search.searchingHistory": "正在搜索更早的消息…",
} satisfies Partial<Record<Keys, string>>
+7 -1
View File
@@ -774,7 +774,7 @@ export const dict = {
"settings.agentBehaviour.subtab.skills": "Skills",
"settings.browser.description":
"啟用後,AI Agent 可以與網頁互動,可導覽、點選、輸入並擷取螢幕截圖。Chrome 視窗將開啟,方便觀察 Agent 的工作。",
"設定由 Playwright 提供支援的內建瀏覽器自動化。Kilo 可以在你的工作階段中瀏覽網頁、與網頁互動,並擷取螢幕截圖。",
"settings.browser.enable.title": "啟用瀏覽器自動化",
"settings.browser.enable.description": "將 Playwright MCP 伺服器註冊到 CLI 後端。",
"settings.browser.systemChrome.title": "使用系統 Chrome",
@@ -1286,5 +1286,11 @@ export const dict = {
"chat.search.close": "關閉搜尋",
"chat.search.invalidRegex": "規則運算式無效",
"chat.search.noResults": "無結果",
"settings.experimental.browserAutomation.title": "整合瀏覽器",
"settings.experimental.browserAutomation.description":
"在 Agent Manager 中顯示本機應用程式預覽,並向 Agent Manager 工作階段公開 browser_open 工具。",
"settings.experimental.browserAutomation.systemChrome.title": "使用系統 Chrome",
"settings.experimental.browserAutomation.systemChrome.description":
"為整合瀏覽器使用已安裝的 Google Chrome。僅在已安裝相容的 Playwright Chromium 瀏覽器時才停用。",
"chat.search.searchingHistory": "正在搜尋較早的訊息…",
} satisfies Partial<Record<Keys, string>>
@@ -128,7 +128,9 @@ export type KiloEmbeddingModelCatalog = {
export type IndexingStatus = SdkIndexingStatus
export interface BrowserSettings {
enabled: boolean
useSystemChrome: boolean
headless: boolean
}
export type TerminalCommandDisplay = "expanded" | "collapsed"
@@ -67,7 +67,7 @@ export const BrowserOpenTool = Tool.define<
) {
return {
title: "Browser unavailable",
output: "The Agent Manager browser is not available in this session.",
output: "The Integrated Browser is not available in this session.",
metadata: { status: "error", errors: 0 } satisfies Meta,
}
}
@@ -134,7 +134,7 @@ export const BrowserOpenTool = Tool.define<
state.logs?.length
? `Console diagnostics:\n${state.logs.map((line) => `- ${line}`).join("\n")}`
: undefined,
"The user can inspect this page in the Agent Manager Browser panel.",
"The user can inspect this page in the Integrated Browser panel in Agent Manager.",
]
.filter(Boolean)
.join("\n"),
@@ -1,4 +1,4 @@
Open the local application in the Browser panel for the current Agent Manager session.
Open the local application in the Integrated Browser panel for the current Agent Manager session.
Use this tool when the user asks you to inspect or verify a local web application.
The user can see the same browser page in Agent Manager. Reuse this browser instead