diff --git a/.changeset/agent-manager-settings-tab.md b/.changeset/agent-manager-settings-tab.md new file mode 100644 index 00000000000..18f88712ef2 --- /dev/null +++ b/.changeset/agent-manager-settings-tab.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Move Agent Manager worktree settings into the Kilo Settings editor and add project selection for multi-project workspaces. diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-panel-comments-200-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-panel-comments-200-chromium-linux.png index 4eb665f771d..8f221c78b84 100644 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-panel-comments-200-chromium-linux.png +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-panel-comments-200-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:82b91b6fcb81a7500e37dfcc335d2977955cab4f786efa30f35880c09cd8987c -size 34732 +oid sha256:e9b217741df7ecac772898be685b192360d65c8709fce6ff65c133aba50715e2 +size 34695 diff --git a/packages/kilo-vscode/script/launch.ts b/packages/kilo-vscode/script/launch.ts index 47cd3a0423e..721161b1247 100644 --- a/packages/kilo-vscode/script/launch.ts +++ b/packages/kilo-vscode/script/launch.ts @@ -37,6 +37,7 @@ import { spawn } from "node:child_process" const win = process.platform === "win32" const root = join(import.meta.dir, "..") const repo = resolve(root, "..", "..") +const temp = tmpdir().trimEnd() // --------------------------------------------------------------------------- // Argument parsing @@ -102,7 +103,7 @@ const base = ? expand(opts["state-dir"]) : isolated ? join(dev, "vscode") - : join(tmpdir(), `kilo-vscode-dev-${hash}`) + : join(temp, `kilo-vscode-dev-${hash}`) const userDir = join(base, "user-data") const extDir = join(base, "extensions") const kilo = diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index 903ea4101f5..a7c385d8bf5 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -444,6 +444,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper private ignoreControllerDir: string | null = null private chatAutocomplete: ChatTextAreaAutocomplete | null = null private projectDirectory: string | null | undefined + private settingsGeneration = 0 private indexingProjectId: string | undefined private indexingSettingsRequest = 0 private indexingStatusRequest = 0 @@ -1048,6 +1049,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper return } if (this.handleEditorOpenMessage(message)) return + if (await this.handleAgentManagerSettingsMessage(message)) return if ( await handleWorkStyleMessage({ message, @@ -1201,7 +1203,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper } break case "openSettingsPanel": - vscode.commands.executeCommand("kilo-code.new.settingsButtonClicked", message.tab) + vscode.commands.executeCommand("kilo-code.new.settingsButtonClicked", message.tab, message.projectId) break case "openKiloClaw": vscode.commands.executeCommand("kilo-code.new.kiloClawOpen") @@ -3714,6 +3716,94 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper return this.projectDirectory ?? this.getRootDirectory() } + private async handleAgentManagerSettingsMessage( + message: TypedWebviewMessage & { projectId?: string; branch?: string; requestId?: string }, + ): Promise { + const handler = this.opts.agentManagerSettings + if (!handler) return false + const requestId = message.requestId + if (typeof requestId !== "string") return false + // Only Agent Manager settings messages participate in the generation + // guard: unrelated Settings-panel requests also carry requestId and must + // not invalidate an in-flight projects/branches response. + if ( + message.type !== "requestAgentManagerSettings" && + message.type !== "requestAgentManagerSettingsBranches" && + message.type !== "setAgentManagerDefaultBaseBranch" && + message.type !== "configureAgentManagerSetupScript" + ) + return false + // The settings handler is project-scoped by projectId; the panel's own + // project directory (config bindings, saves, local-config opens) must + // stay untouched so Agent Manager tab traffic cannot expire unsaved + // config edits. + const generation = ++this.settingsGeneration + if (message.type === "requestAgentManagerSettings") { + await this.sendAgentManagerSettings(message.projectId, false, generation, requestId) + return true + } + if (message.type === "requestAgentManagerSettingsBranches" && message.projectId) { + await this.sendAgentManagerSettingsBranches(message.projectId, generation, requestId) + return true + } + if (message.type === "setAgentManagerDefaultBaseBranch" && message.projectId) { + await handler.setDefaultBaseBranch(message.projectId, message.branch) + if (this.settingsGeneration !== generation) return true + await this.sendAgentManagerSettings(message.projectId, false, generation, requestId) + return true + } + if (message.type === "configureAgentManagerSetupScript" && message.projectId) { + await handler.configureSetupScript(message.projectId) + if (this.settingsGeneration !== generation) return true + await this.sendAgentManagerSettings(message.projectId, false, generation, requestId) + return true + } + return false + } + + private async sendAgentManagerSettings( + projectId: string | undefined, + withBranches: boolean, + generation: number, + requestId: string, + ): Promise { + const handler = this.opts.agentManagerSettings + if (!handler) return + const projects = await handler.projects(projectId) + if (this.settingsGeneration !== generation) return + const selected = projects.some((project) => project.id === projectId) ? projectId : projects[0]?.id + const branch = selected ? await handler.defaultBranch(selected) : undefined + if (this.settingsGeneration !== generation) return + const items = selected + ? projects.map((project) => (project.id === selected ? { ...project, defaultBranch: branch } : project)) + : projects + this.postMessage({ type: "agentManagerSettingsLoaded", projects: items, projectId: selected, requestId }) + if (withBranches && selected) await this.sendAgentManagerSettingsBranches(selected, generation, requestId) + } + + private async sendAgentManagerSettingsBranches( + projectId: string, + generation: number, + requestId: string, + ): Promise { + const handler = this.opts.agentManagerSettings + if (!handler) return + const data = await handler.branches(projectId) + if (this.settingsGeneration !== generation) return + this.postMessage( + data + ? { type: "agentManagerSettingsBranchesLoaded", ...data, requestId } + : { + type: "agentManagerSettingsBranchesLoaded", + projectId, + branches: [], + defaultBranch: "", + requestId, + error: true, + }, + ) + } + private bindingsFor( directory: string, targets: @@ -5182,6 +5272,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper // VS Code's native toolbar (restored in package.json) works everywhere. topBar: this.opts.hideTopBar !== true && isCursorHost(), topBarSurface: this.opts.topBarSurface === "tab" ? "tab_title" : "sidebar_title", + agentManagerSettings: this.opts.agentManagerSettings !== undefined, }) } diff --git a/packages/kilo-vscode/src/SettingsEditorProvider.ts b/packages/kilo-vscode/src/SettingsEditorProvider.ts index f03657921a8..fff1a91d171 100644 --- a/packages/kilo-vscode/src/SettingsEditorProvider.ts +++ b/packages/kilo-vscode/src/SettingsEditorProvider.ts @@ -3,6 +3,7 @@ import { KiloProvider } from "./KiloProvider" import { resolvePanelProjectDirectory } from "./project-directory" import type { KiloConnectionService } from "./services/cli-backend" import type { RemoteStatusService } from "./services/RemoteStatusService" +import type { AgentManagerSettingsHandler } from "./kilo-provider/options" type PanelView = "settings" | "profile" | "indexing" @@ -27,15 +28,18 @@ export class SettingsEditorProvider implements vscode.Disposable { private panels = new Map() private providers = new Map() private tabs = new Map() + private projects = new Map() private remoteService: RemoteStatusService | null = null constructor( private readonly extensionUri: vscode.Uri, private readonly connectionService: KiloConnectionService, private readonly context: vscode.ExtensionContext, + private readonly agentManagerSettings?: AgentManagerSettingsHandler, ) {} - private getProjectDirectory(): string | null { + private getProjectDirectory(projectId?: string): string | null { + if (projectId) return this.agentManagerSettings?.projectDirectory(projectId) ?? null const editor = vscode.window.activeTextEditor const active = editor?.document.uri.scheme === "file" @@ -53,19 +57,22 @@ export class SettingsEditorProvider implements vscode.Disposable { return view } - openPanel(view: PanelView, tab?: string): void { + openPanel(view: PanelView, tab?: string, projectId?: string): void { if (tab) this.tabs.set(view, tab) + if (projectId) this.projects.set(view, projectId) + else this.projects.delete(view) - const projectDirectory = this.getProjectDirectory() + const projectDirectory = this.getProjectDirectory(projectId) const existing = this.panels.get(view) if (existing) { this.providers.get(view)?.setProjectDirectory(projectDirectory) - if (tab) { - const provider = this.providers.get(view) - provider?.postMessage({ type: "navigate", view, tab }) - } existing.reveal(vscode.ViewColumn.Active) - this.providers.get(view)?.postMessage({ type: "navigate", view, ...(tab ? { tab } : {}) }) + this.providers.get(view)?.postMessage({ + type: "navigate", + view, + ...(tab ? { tab } : {}), + ...(projectId ? { projectId } : {}), + }) return } @@ -90,7 +97,7 @@ export class SettingsEditorProvider implements vscode.Disposable { panel.dispose() return } - this.wirePanel(panel, view, this.getProjectDirectory()) + this.wirePanel(panel, view, this.getProjectDirectory(this.projects.get(view))) } private wirePanel(panel: vscode.WebviewPanel, view: PanelView, projectDirectory: string | null): void { @@ -104,6 +111,7 @@ export class SettingsEditorProvider implements vscode.Disposable { const provider = new KiloProvider(this.extensionUri, this.connectionService, this.context, { projectDirectory, hideTopBar: true, + agentManagerSettings: view === "settings" ? this.agentManagerSettings : undefined, }) if (this.remoteService) { provider.setRemoteService(this.remoteService) @@ -123,7 +131,12 @@ export class SettingsEditorProvider implements vscode.Disposable { if (msg.type === "webviewReady") { // Small delay to let KiloProvider's own webviewReady handler finish first setTimeout(() => { - provider.postMessage({ type: "navigate", view, tab: this.tabs.get(view) }) + provider.postMessage({ + type: "navigate", + view, + tab: this.tabs.get(view), + projectId: this.projects.get(view), + }) }, 50) } }) @@ -148,6 +161,7 @@ export class SettingsEditorProvider implements vscode.Disposable { this.panels.delete(view) this.providers.delete(view) this.tabs.delete(view) + this.projects.delete(view) }) } @@ -166,5 +180,6 @@ export class SettingsEditorProvider implements vscode.Disposable { this.panels.clear() this.providers.clear() this.tabs.clear() + this.projects.clear() } } diff --git a/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts b/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts index d4abec3fe97..99eab29e3eb 100644 --- a/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts +++ b/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts @@ -75,7 +75,7 @@ import { ProjectContexts } from "./project/contexts" import { hydrateExpanded } from "./project/hydrate" import { createMultiVersion, type MultiVersionHost } from "./provider-multi-version" import { handleProjectMessage, type ProjectMessageDeps } from "./project/messages" -import { createProjectWiring } from "./project/wiring" +import { createProjectWiring, type ProjectWiring } from "./project/wiring" import { ProjectScope } from "./project/scope" import type { AgentManagerOutMessage, AgentManagerInMessage } from "./types" import type { Host, PanelContext, OutputHandle, Disposable } from "./host" @@ -116,10 +116,9 @@ export class AgentManagerProvider implements Disposable { private destination = new DestinationState() private closing: Promise | undefined private onVisibilityChange: ((visible: boolean) => void) | undefined - // Tracks sessions owned by this panel until they are explicitly closed. private panelSessions = new Set() private busySessions = new Set() - + readonly settings: ProjectWiring["settings"] /** Session ID most recently loaded via `loadMessages`; updated synchronously. */ private activeSessionId: string | undefined private visiblePresence = new AgentManagerVisiblePresence( @@ -195,12 +194,13 @@ export class AgentManagerProvider implements Disposable { expand: (ctx) => this.initExpanded(ctx), ready: (ctx) => initContextState(ctx, (...args) => this.log(...args)), push: () => this.pushProjects(), + pushState: (ctx) => this.pushState(ctx), changed: () => this.onWorkspaceChanged(), - refresh: () => this.pushState(), selected: (target) => this.postToWebview({ type: "agentManager.selectionActivated", target }), }) this.registry = wiring.registry this.contexts = wiring.contexts + this.settings = wiring.settings this.projects = wiring.messages this.unsubProjects = () => wiring.dispose() this.naming = new BranchNamingController({ diff --git a/packages/kilo-vscode/src/agent-manager/__tests__/AgentManagerProvider.spec.ts b/packages/kilo-vscode/src/agent-manager/__tests__/AgentManagerProvider.spec.ts index 92c6c1a6612..db7dd2451aa 100644 --- a/packages/kilo-vscode/src/agent-manager/__tests__/AgentManagerProvider.spec.ts +++ b/packages/kilo-vscode/src/agent-manager/__tests__/AgentManagerProvider.spec.ts @@ -82,6 +82,7 @@ function createMockHost(): Host { copyToClipboard: vi.fn(), capture: vi.fn(), openExternal: vi.fn(), + openSettings: vi.fn(), refreshGit: vi.fn(), dispose: vi.fn(), } diff --git a/packages/kilo-vscode/src/agent-manager/host.ts b/packages/kilo-vscode/src/agent-manager/host.ts index 6d8b8a72eff..45d3f1ee2e9 100644 --- a/packages/kilo-vscode/src/agent-manager/host.ts +++ b/packages/kilo-vscode/src/agent-manager/host.ts @@ -178,6 +178,9 @@ export interface Host { /** Open a URL in the user's default browser. */ openExternal(url: string): void + /** Open Kilo Settings, optionally focused on a tab and project. */ + openSettings(tab?: string, projectId?: string): void + /** Ask VS Code's git extension to re-scan repositories (e.g. after worktree ref migration). */ refreshGit(): void diff --git a/packages/kilo-vscode/src/agent-manager/project/messages.ts b/packages/kilo-vscode/src/agent-manager/project/messages.ts index a6b9cc9f9cb..c9bf7ef77d7 100644 --- a/packages/kilo-vscode/src/agent-manager/project/messages.ts +++ b/packages/kilo-vscode/src/agent-manager/project/messages.ts @@ -31,6 +31,8 @@ export interface ProjectMessageDeps { selected: (target: SidebarTarget) => void /** Show a user-facing error. */ error: (message: string) => void + /** Open the Kilo Settings editor, optionally on a tab and project. */ + openSettings: (tab?: string, projectId?: string) => void /** Ensure a context's repository state is ready (no-op once initialized). */ ready: (ctx: ProjectContext) => Promise log: (...args: unknown[]) => void @@ -38,6 +40,10 @@ export interface ProjectMessageDeps { /** Handle a project-management message. Returns true when the message was consumed. */ export async function handleProjectMessage(m: AgentManagerInMessage, deps: ProjectMessageDeps): Promise { + if (m.type === "openSettingsPanel") { + deps.openSettings(m.tab, m.projectId) + return true + } if (m.type === "agentManager.requestProjects") { deps.push() return true diff --git a/packages/kilo-vscode/src/agent-manager/project/settings.ts b/packages/kilo-vscode/src/agent-manager/project/settings.ts new file mode 100644 index 00000000000..a2c763cf113 --- /dev/null +++ b/packages/kilo-vscode/src/agent-manager/project/settings.ts @@ -0,0 +1,168 @@ +import type { BranchListItem } from "../git-import" +import { normalizeBaseBranch } from "../base-branch" +import { initContextState } from "./init" +import type { ProjectContext } from "./context" +import type { ProjectContexts, ProjectSnapshot } from "./contexts" + +export interface SettingsProject { + id: string + root: string + label: string + pinned: boolean + missing: boolean + defaultBaseBranch?: string + defaultBranch?: string + setupScriptPath?: string +} + +export interface SettingsBranches { + projectId: string + branches: BranchListItem[] + defaultBranch: string + configuredBaseBranch?: string + setupScriptPath?: string +} + +export interface SettingsHandler { + projects(projectId?: string): Promise + projectDirectory(projectId: string): string | undefined + defaultBranch(projectId: string): Promise + branches(projectId: string): Promise + setDefaultBaseBranch(projectId: string, branch?: string): Promise + configureSetupScript(projectId: string): Promise +} + +export function createSettingsHandler(opts: { + contexts: ProjectContexts + open: (path: string) => Promise + push: (ctx: ProjectContext) => void + log: (...args: unknown[]) => void +}): SettingsHandler { + return { + projects: (projectId) => loadSettingsProjects(opts.contexts, projectId, opts.log), + projectDirectory: (id) => settingsDirectory(opts.contexts, id), + defaultBranch: (id) => settingsDefaultBranch(opts.contexts, id, opts.log), + branches: (id) => settingsBranches(opts.contexts, id, opts.log, opts.push), + setDefaultBaseBranch: (id, branch) => setSettingsDefaultBaseBranch(opts.contexts, id, branch, opts.log, opts.push), + configureSetupScript: (id) => configureSettingsSetupScript(opts.contexts, id, opts.open, opts.log), + } +} + +export function settingsProjects(contexts: ProjectContexts): SettingsProject[] { + return contexts.snapshots().map((project) => settingsProject(contexts, project)) +} + +async function loadSettingsProjects( + contexts: ProjectContexts, + projectId: string | undefined, + log: (...args: unknown[]) => void, +): Promise { + const snapshots = contexts.snapshots() + const selected = snapshots.some((project) => project.id === projectId) ? projectId : snapshots.at(0)?.id + const ctx = selected ? contexts.resolve(selected) : undefined + if (ctx && !ctx.missing()) { + const init = await initContextState(ctx, log) + if (init.ok && init.current) ctx.setupService() + } + return settingsProjects(contexts) +} + +function settingsProject(contexts: ProjectContexts, project: ProjectSnapshot): SettingsProject { + const ctx = contexts.get(project.id) + return { + id: project.id, + root: project.root, + label: project.label, + pinned: project.pinned, + missing: project.missing, + defaultBaseBranch: ctx?.peekState()?.getDefaultBaseBranch(), + setupScriptPath: ctx?.peekSetup()?.resolveScript()?.path, + } +} + +export function settingsDirectory(contexts: ProjectContexts, projectId: string): string | undefined { + return contexts.resolve(projectId)?.root +} + +export async function settingsDefaultBranch( + contexts: ProjectContexts, + projectId: string, + log: (...args: unknown[]) => void, +): Promise { + const ctx = contexts.resolve(projectId) + if (!ctx || ctx.missing()) return undefined + return ctx + .worktreeManager() + .defaultBranch() + .catch((err) => { + log(`Failed to load settings default branch for ${projectId}:`, err) + return undefined + }) +} + +export async function settingsBranches( + contexts: ProjectContexts, + projectId: string, + log: (...args: unknown[]) => void, + push: (ctx: ProjectContext) => void, +): Promise { + const ctx = contexts.resolve(projectId) + if (!ctx || ctx.missing()) return undefined + const init = await initContextState(ctx, log) + if (!init.ok || !init.current) return undefined + const result = await ctx + .worktreeManager() + .listBranches() + .catch((err) => { + log(`Failed to load settings branches for ${projectId}:`, err) + return undefined + }) + if (!result) return undefined + const configured = ctx.peekState()?.getDefaultBaseBranch() + const valid = configured && result.branches.some((branch) => branch.name === configured) + if (configured && !valid) { + ctx.peekState()?.setDefaultBaseBranch(undefined) + push(ctx) + } + return { + projectId, + branches: result.branches, + defaultBranch: result.defaultBranch, + configuredBaseBranch: valid ? configured : undefined, + setupScriptPath: ctx.setupService().resolveScript()?.path, + } +} + +export async function setSettingsDefaultBaseBranch( + contexts: ProjectContexts, + projectId: string, + branch: string | undefined, + log: (...args: unknown[]) => void, + push: (ctx: ProjectContext) => void, +): Promise { + const ctx = contexts.resolve(projectId) + if (!ctx || ctx.missing()) return + const init = await initContextState(ctx, log) + if (!init.ok || !init.current) return + ctx.peekState()?.setDefaultBaseBranch(normalizeBaseBranch(branch)) + push(ctx) +} + +export async function configureSettingsSetupScript( + contexts: ProjectContexts, + projectId: string, + open: (path: string) => Promise, + log: (...args: unknown[]) => void, +): Promise { + const ctx = contexts.resolve(projectId) + if (!ctx || ctx.missing()) return + const service = ctx.setupService() + try { + if (!service.hasScript()) await service.createDefaultScript() + const script = service.resolveScript() + if (!script) return + await open(script.path) + } catch (err) { + log(`Failed to open setup script for ${projectId}:`, err) + } +} diff --git a/packages/kilo-vscode/src/agent-manager/project/wiring.ts b/packages/kilo-vscode/src/agent-manager/project/wiring.ts index 5d93cc4b7fa..56dfb5602e7 100644 --- a/packages/kilo-vscode/src/agent-manager/project/wiring.ts +++ b/packages/kilo-vscode/src/agent-manager/project/wiring.ts @@ -12,10 +12,13 @@ import { ProjectRegistry } from "./registry" import type { ProjectContext, ProjectInitResult } from "./context" import { ProjectContexts, type ProjectSnapshot } from "./contexts" import type { ProjectMessageDeps } from "./messages" +import { createSettingsHandler, type SettingsHandler } from "./settings" export interface ProjectWiring { registry: ProjectRegistry contexts: ProjectContexts + /** Project-scoped settings handler shared with the Kilo Settings editor. */ + settings: SettingsHandler messages: ProjectMessageDeps /** Payload for the agentManager.projects webview message. */ snapshots(): { type: "agentManager.projects"; multiProject: boolean; projects: ProjectSnapshot[] } @@ -35,10 +38,10 @@ export function createProjectWiring(opts: { ready: (ctx: ProjectContext) => Promise /** Push the project catalog to the webview. */ push: () => void + /** Push one project's state (or every context when omitted) to the webview. */ + pushState: (ctx?: ProjectContext) => void /** Re-derive the pinned project after workspace folder changes. */ changed: () => void - /** Re-push worktree state (e.g. after the flag toggles). */ - refresh: () => void /** Acknowledge an atomically validated sidebar selection. */ selected: (target: import("./route").SidebarTarget) => void }): ProjectWiring { @@ -64,8 +67,15 @@ export function createProjectWiring(opts: { push: opts.push, selected: opts.selected, error: (message) => opts.host.showError(message), + openSettings: (tab, projectId) => opts.host.openSettings(tab, projectId), log: opts.log, } + const settings = createSettingsHandler({ + contexts, + open: (path) => opts.host.openDocument(path), + push: opts.pushState, + log: opts.log, + }) const listeners: Disposable[] = [ opts.host.onDidChangeWorkspaceFolders(() => opts.changed()), opts.host.onDidChangeMultiProject((enabled) => { @@ -74,12 +84,13 @@ export function createProjectWiring(opts: { if (pinned) opts.activate(pinned) } opts.push() - opts.refresh() + opts.pushState() }), ] return { registry, contexts, + settings, messages, snapshots: () => ({ type: "agentManager.projects", diff --git a/packages/kilo-vscode/src/agent-manager/types.ts b/packages/kilo-vscode/src/agent-manager/types.ts index 7df3cbaa252..a7fb6395158 100644 --- a/packages/kilo-vscode/src/agent-manager/types.ts +++ b/packages/kilo-vscode/src/agent-manager/types.ts @@ -673,6 +673,12 @@ interface RenameWorktreeIn { label: string } +interface OpenSettingsPanelIn { + type: "openSettingsPanel" + tab?: string + projectId?: string +} + interface RequestStateIn { type: "agentManager.requestState" } @@ -1093,6 +1099,7 @@ export type AgentManagerInMessage = | RequestRepoInfoIn | CreateMultiVersionIn | RenameWorktreeIn + | OpenSettingsPanelIn | RequestStateIn | RequestBranchesIn | SetTabOrderIn diff --git a/packages/kilo-vscode/src/agent-manager/vscode-host.ts b/packages/kilo-vscode/src/agent-manager/vscode-host.ts index a08ee038aae..943387890de 100644 --- a/packages/kilo-vscode/src/agent-manager/vscode-host.ts +++ b/packages/kilo-vscode/src/agent-manager/vscode-host.ts @@ -320,6 +320,10 @@ export class VscodeHost implements Host { void vscode.env.openExternal(vscode.Uri.parse(url)) } + openSettings(tab?: string, projectId?: string): void { + void vscode.commands.executeCommand("kilo-code.new.settingsButtonClicked", tab, projectId) + } + refreshGit(): void { void vscode.commands.executeCommand("git.refresh") } diff --git a/packages/kilo-vscode/src/extension.ts b/packages/kilo-vscode/src/extension.ts index 2ca7a0f5fde..428ca16864b 100644 --- a/packages/kilo-vscode/src/extension.ts +++ b/packages/kilo-vscode/src/extension.ts @@ -295,7 +295,9 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push(diffVirtualProvider) // Create standalone editor providers (open in editor area, not sidebar) - const settingsEditorProvider = new SettingsEditorProvider(context.extensionUri, connectionService, context) + const settingsEditorProvider = new SettingsEditorProvider(context.extensionUri, connectionService, context, { + ...agentManagerProvider.settings, + }) settingsEditorProvider.setRemoteService(remoteService) const marketplacePanelProvider = new MarketplacePanelProvider(context.extensionUri, connectionService, context) context.subscriptions.push(settingsEditorProvider, marketplacePanelProvider) @@ -429,8 +431,8 @@ export function activate(context: vscode.ExtensionContext) { vscode.commands.registerCommand("kilo-code.new.profileButtonClicked", () => { settingsEditorProvider.openPanel("profile") }), - vscode.commands.registerCommand("kilo-code.new.settingsButtonClicked", (tab?: string) => { - settingsEditorProvider.openPanel("settings", tab) + vscode.commands.registerCommand("kilo-code.new.settingsButtonClicked", (tab?: string, projectId?: string) => { + settingsEditorProvider.openPanel("settings", tab, projectId) }), vscode.commands.registerCommand("kilo-code.new.openIndexingSettings", () => { settingsEditorProvider.openPanel("settings", "indexing") diff --git a/packages/kilo-vscode/src/kilo-provider/options.ts b/packages/kilo-vscode/src/kilo-provider/options.ts index df62bdf9fb4..1bde4dc012c 100644 --- a/packages/kilo-vscode/src/kilo-provider/options.ts +++ b/packages/kilo-vscode/src/kilo-provider/options.ts @@ -1,4 +1,7 @@ import type { ProjectRouteService } from "../agent-manager/project/route" +import type { SettingsHandler } from "../agent-manager/project/settings" + +export type AgentManagerSettingsHandler = SettingsHandler export type KiloProviderOptions = { /** Context key updated from focus events reported by this provider's webview. */ @@ -47,4 +50,6 @@ export type KiloProviderOptions = { hideTopBar?: boolean /** Reports "Open in Tab" as the top bar's telemetry surface instead of the sidebar default. */ topBarSurface?: "tab" + /** Project-aware settings used by the standalone Agent Manager settings tab. */ + agentManagerSettings?: AgentManagerSettingsHandler } diff --git a/packages/kilo-vscode/src/utils.ts b/packages/kilo-vscode/src/utils.ts index 6e3b6b49c05..ce17c8d7549 100644 --- a/packages/kilo-vscode/src/utils.ts +++ b/packages/kilo-vscode/src/utils.ts @@ -65,6 +65,7 @@ export function buildWebviewHtml( /** Sidebar top bar visibility and telemetry surface for the shared webview bundle (App.tsx). Unused by the Agent Manager bundle. */ topBar?: boolean topBarSurface?: string + agentManagerSettings?: boolean }, ): string { const nonce = getNonce() @@ -107,7 +108,7 @@ export function buildWebviewHtml(
- + ` diff --git a/packages/kilo-vscode/tests/unit/agent-manager-arch.test.ts b/packages/kilo-vscode/tests/unit/agent-manager-arch.test.ts index bcfa9d8369e..fff186c1890 100644 --- a/packages/kilo-vscode/tests/unit/agent-manager-arch.test.ts +++ b/packages/kilo-vscode/tests/unit/agent-manager-arch.test.ts @@ -59,7 +59,6 @@ const TSX_FILES = [ path.join(ROOT, "webview-ui/agent-manager/ClosableTab.tsx"), path.join(ROOT, "webview-ui/agent-manager/InspectorTabStrip.tsx"), path.join(ROOT, "webview-ui/agent-manager/ProjectBranchDialog.tsx"), - path.join(ROOT, "webview-ui/agent-manager/DefaultBaseBranchDialog.tsx"), path.join(ROOT, "webview-ui/agent-manager/tab-rendering.tsx"), path.join(ROOT, "webview-ui/agent-manager/terminal/TerminalTab.tsx"), path.join(ROOT, "webview-ui/agent-manager/terminal/SideTerminalPanel.tsx"), @@ -904,35 +903,6 @@ describe("KiloProvider — pending session refresh on reconnect", () => { }) // --------------------------------------------------------------------------- -// handleChangeDefaultBaseBranch — listener leak fix -// --------------------------------------------------------------------------- - -describe("Agent Manager — dialog listener cleanup", () => { - const tsx = fs.readFileSync(path.join(ROOT, "webview-ui/agent-manager/DefaultBaseBranchDialog.tsx"), "utf-8") - - /** - * Regression: handleChangeDefaultBaseBranch subscribes to vscode.onMessage - * for branch data. Previously unsub() was only called inside selectBranch() - * and the Escape keydown handler. If the dialog closed via backdrop click or - * external dialog.close(), the listener leaked and stacked on every reopen. - * - * The fix ties unsub() to the dialog component's Solid cleanup so it always - * disposes regardless of how the dialog closes. - */ - it("DefaultBaseBranchDialog disposes its message listener on cleanup", () => { - expect(tsx).toContain("const unsub = vscode.onMessage") - expect(tsx).toContain("onCleanup(unsub)") - }) - - it("select does not manually call unsub (handled by onCleanup)", () => { - const selStart = tsx.indexOf("const select =") - expect(selStart, "select must exist").toBeGreaterThan(-1) - const selEnd = tsx.indexOf("}", selStart + 40) - const selBody = tsx.slice(selStart, selEnd + 1) - expect(selBody, "select should not call unsub() directly").not.toContain("unsub()") - }) -}) - describe("SetupScriptRunner — task execution model", () => { const runner = fs.readFileSync(SETUP_SCRIPT_RUNNER_FILE, "utf-8") const taskAdapter = fs.readFileSync(path.join(ROOT, "src/agent-manager/task-runner.ts"), "utf-8") diff --git a/packages/kilo-vscode/tests/unit/agent-manager-settings.test.ts b/packages/kilo-vscode/tests/unit/agent-manager-settings.test.ts new file mode 100644 index 00000000000..6e60176f25b --- /dev/null +++ b/packages/kilo-vscode/tests/unit/agent-manager-settings.test.ts @@ -0,0 +1,50 @@ +import { describe, expect, it } from "bun:test" +import { readFileSync } from "node:fs" +import { join } from "node:path" + +const ROOT = join(import.meta.dir, "..", "..") + +describe("Agent Manager settings navigation", () => { + const actions = readFileSync(join(ROOT, "webview-ui", "agent-manager", "ProjectActions.tsx"), "utf8") + const project = readFileSync(join(ROOT, "webview-ui", "agent-manager", "ProjectSidebarBody.tsx"), "utf8") + const settings = readFileSync(join(ROOT, "webview-ui", "src", "components", "settings", "Settings.tsx"), "utf8") + const branchDialog = readFileSync(join(ROOT, "webview-ui", "agent-manager", "ProjectBranchDialog.tsx"), "utf8") + + it("opens the project settings tab with the owning project id", () => { + expect(actions).toContain("onClick={props.onSettings}") + expect(project).toContain('tab: "agentManager"') + expect(project).toContain("projectId: props.project.id") + }) + + it("renders a project selector and project-scoped settings controls", () => { + expect(settings).toContain('type: "requestAgentManagerSettings"') + expect(settings).toContain('type: "requestAgentManagerSettingsBranches"') + expect(settings).toContain('type: "setAgentManagerDefaultBaseBranch"') + expect(settings).toContain('type: "configureAgentManagerSetupScript"') + }) + + it("keeps the repository default branch selectable without an empty value", () => { + expect(settings).toContain(" select()") + }) + + it("places the Agent Manager settings tab under Auto-Approve", () => { + const autoApprove = settings.indexOf('value="autoApprove"') + const agentManager = settings.indexOf('value="agentManager"') + const browser = settings.indexOf('value="browser"') + expect(autoApprove).toBeGreaterThan(-1) + expect(autoApprove).toBeLessThan(agentManager) + expect(agentManager).toBeLessThan(browser) + }) + + it("loads branches only when the default branch picker opens", () => { + expect(settings).toContain("loadBranches(id)") + expect(settings).toContain("dialog.show(() =>") + }) + + it("opens the existing branch picker dialog", () => { + expect(settings).toContain("dialog.show(() =>") + expect(settings).toContain(" { const [sessionsLoaded, setSessionsLoaded] = createSignal(false) const [isGitRepo, setIsGitRepo] = createSignal(true) const [repoDetectedBranch, setRepoDetectedBranch] = createSignal() - const defaultBaseBranch = () => registry.active().defaultBaseBranch() - const setDefaultBaseBranch = (v: Parameters>[0]) => - registry.active().setDefaultBaseBranch(v) const [projectList, setProjectList] = createSignal([]) const [multiProject, setMultiProject] = createSignal(false) const [currentProjectId, setCurrentProjectId] = createSignal() @@ -274,7 +270,9 @@ const AgentManagerContent: Component = () => { ) const isActivePayload = (pid: string | undefined) => projectList().length === 0 || pid === undefined || pid === activeProjectId() - const repoDefaultBranch = () => defaultBaseBranch() ?? repoDetectedBranch() ?? "main" + + const repoDefaultBranch = () => repoDetectedBranch() ?? "main" + const DEFAULT_SIDEBAR_WIDTH = 260 const MIN_SIDEBAR_WIDTH = 200 const MAX_SIDEBAR_WIDTH_RATIO = 0.4 @@ -1757,23 +1755,6 @@ const AgentManagerContent: Component = () => { const revertCtl = createRevertFile(diffScopeId, diffCtx, () => review.scope(), vscode, showToast, t, activeProjectId) - const handleConfigureSetupScript = () => { - vscode.postMessage({ type: "agentManager.configureSetupScript" }) - } - const setupScript = metrics.click("configure_setup_script", "worktree_settings", handleConfigureSetupScript) - - const handleChangeDefaultBaseBranch = () => { - dialog.show(() => ( - dialog.close()} - /> - )) - } - const handleShowKeyboardShortcuts = () => { const categories = buildShortcutCategories(kb(), t) dialog.show(() => ( @@ -2364,8 +2345,7 @@ const AgentManagerContent: Component = () => { onNewWorktree={showNewWorktreeDialog} onNewSection={newSection} onShortcuts={metrics.click("keyboard_shortcuts", "worktrees_header", handleShowKeyboardShortcuts)} - onSetup={setupScript} - onBranch={handleChangeDefaultBaseBranch} + projectId={activeProjectId()} sections={sections} sortedWorktrees={sortedWorktrees} worktrees={worktrees} diff --git a/packages/kilo-vscode/webview-ui/agent-manager/DefaultBaseBranchDialog.tsx b/packages/kilo-vscode/webview-ui/agent-manager/DefaultBaseBranchDialog.tsx deleted file mode 100644 index 4b4abbba1c7..00000000000 --- a/packages/kilo-vscode/webview-ui/agent-manager/DefaultBaseBranchDialog.tsx +++ /dev/null @@ -1,110 +0,0 @@ -/** @jsxImportSource solid-js */ - -import { createMemo, createSignal, onCleanup, type Component } from "solid-js" -import { Dialog } from "@kilocode/kilo-ui/dialog" -import { BranchSelect } from "../src/components/shared/BranchSelect" -import { useLanguage } from "../src/context/language" -import { useVSCode } from "../src/context/vscode" -import type { AgentManagerBranchesMessage, BranchInfo } from "../src/types/messages" - -interface Props { - selected?: string - detected?: string - onSelect: (branch?: string) => void - onDetected: (branch: string) => void - onClose: () => void -} - -export const DefaultBaseBranchDialog: Component = (props) => { - const { t } = useLanguage() - const vscode = useVSCode() - const [search, setSearch] = createSignal("") - const [branches, setBranches] = createSignal([]) - const [loading, setLoading] = createSignal(true) - const [highlighted, setHighlighted] = createSignal(-1) - const filtered = createMemo(() => { - const value = search().toLowerCase() - return value ? branches().filter((branch) => branch.name.toLowerCase().includes(value)) : branches() - }) - const select = (branch?: string) => { - vscode.postMessage({ type: "agentManager.setDefaultBaseBranch", branch }) - props.onSelect(branch) - props.onClose() - } - const unsub = vscode.onMessage((message) => { - if (message.type !== "agentManager.branches") return - const event = message as AgentManagerBranchesMessage - setBranches(event.branches) - if (event.defaultBranch) props.onDetected(event.defaultBranch) - setLoading(false) - }) - onCleanup(unsub) - vscode.postMessage({ type: "agentManager.requestBranches" }) - - const keydown = (event: KeyboardEvent) => { - const items = filtered() - const total = items.length + 1 - if (event.key === "ArrowDown") { - event.preventDefault() - event.stopPropagation() - setHighlighted((value) => Math.min(value + 1, total - 2)) - return - } - if (event.key === "ArrowUp") { - event.preventDefault() - event.stopPropagation() - setHighlighted((value) => Math.max(value - 1, -1)) - return - } - if (event.key === "Enter") { - event.preventDefault() - event.stopPropagation() - const index = highlighted() - if (index === -1) { - select() - return - } - const branch = items[index] - if (branch) select(branch.name) - return - } - if (event.key !== "Escape") return - event.preventDefault() - event.stopPropagation() - props.onClose() - } - - return ( - -
- { - setSearch(value) - setHighlighted(-1) - }} - onSelect={(branch) => select(branch.name)} - onSearchKeyDown={keydown} - selected={props.selected} - highlighted={highlighted()} - onHighlight={setHighlighted} - searchPlaceholder={t("agentManager.dialog.searchBranches")} - emptyLabel={t("agentManager.import.noMatchingBranches")} - loadingLabel={t("agentManager.import.loadingBranches")} - defaultLabel={t("agentManager.dialog.branchBadge.default")} - remoteLabel={t("agentManager.dialog.branchBadge.remote")} - defaultName={props.selected} - autoOption={{ - label: t("agentManager.worktree.defaultBaseBranchAuto"), - hint: props.detected, - active: !props.selected, - highlighted: highlighted() === -1, - onSelect: () => select(), - }} - /> -
-
- ) -} diff --git a/packages/kilo-vscode/webview-ui/agent-manager/ProjectActions.tsx b/packages/kilo-vscode/webview-ui/agent-manager/ProjectActions.tsx index 80d44c36be7..210e77c1af8 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/ProjectActions.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/ProjectActions.tsx @@ -16,8 +16,7 @@ interface Props { onCreate: () => void onNew: () => void onSection: () => void - onSetup: () => void - onBranch: () => void + onSettings: () => void } export const ProjectActions: Component = (props) => ( @@ -70,27 +69,12 @@ export const ProjectActions: Component = (props) => ( - - - - - - {props.t("agentManager.worktree.setupScript")} - - - - - {props.t("agentManager.worktree.defaultBaseBranch")}: {props.branch} - - - - - + ) diff --git a/packages/kilo-vscode/webview-ui/agent-manager/ProjectBranchDialog.tsx b/packages/kilo-vscode/webview-ui/agent-manager/ProjectBranchDialog.tsx index 9ef48569037..127782444fb 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/ProjectBranchDialog.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/ProjectBranchDialog.tsx @@ -1,67 +1,92 @@ /** @jsxImportSource solid-js */ -import { createMemo, createSignal, onCleanup, onMount, type Component } from "solid-js" +import { createMemo, createSignal, type Component } from "solid-js" import { Dialog } from "@kilocode/kilo-ui/dialog" +import "./agent-manager.css" +import "./agent-manager-review.css" import { BranchSelect } from "../src/components/shared/BranchSelect" import { useLanguage } from "../src/context/language" -import { useVSCode } from "../src/context/vscode" -import type { AgentManagerBranchesMessage, BranchInfo } from "../src/types/messages" +import type { BranchInfo } from "../src/types/messages" interface Props { - projectId: string selected?: string detected?: string + branches: () => BranchInfo[] + loading: () => boolean + onSelect: (branch?: string) => void onClose: () => void } export const ProjectBranchDialog: Component = (props) => { - const { t } = useLanguage() - const vscode = useVSCode() + const language = useLanguage() const [search, setSearch] = createSignal("") - const [branches, setBranches] = createSignal([]) - const [loading, setLoading] = createSignal(true) const [highlighted, setHighlighted] = createSignal(-1) const filtered = createMemo(() => { const value = search().toLowerCase() - return value ? branches().filter((branch) => branch.name.toLowerCase().includes(value)) : branches() + const items = props.branches() + return value ? items.filter((branch) => branch.name.toLowerCase().includes(value)) : items }) const select = (branch?: string) => { - vscode.postMessage({ type: "agentManager.setDefaultBaseBranch", projectId: props.projectId, branch }) + props.onSelect(branch) + props.onClose() + } + const keydown = (event: KeyboardEvent) => { + const items = filtered() + const total = items.length + 1 + if (event.key === "ArrowDown") { + event.preventDefault() + event.stopPropagation() + setHighlighted((value) => Math.min(value + 1, total - 2)) + return + } + if (event.key === "ArrowUp") { + event.preventDefault() + event.stopPropagation() + setHighlighted((value) => Math.max(value - 1, -1)) + return + } + if (event.key === "Enter") { + event.preventDefault() + event.stopPropagation() + const index = highlighted() + if (index === -1) { + select() + return + } + const branch = items[index] + if (branch) select(branch.name) + return + } + if (event.key !== "Escape") return + event.preventDefault() + event.stopPropagation() props.onClose() } - const unsubscribe = vscode.onMessage((message) => { - if (message.type !== "agentManager.branches") return - const event = message as AgentManagerBranchesMessage - if (event.projectId !== props.projectId) return - setBranches(event.branches) - setLoading(false) - }) - onCleanup(unsubscribe) - onMount(() => vscode.postMessage({ type: "agentManager.requestBranches", projectId: props.projectId })) return ( - +
{ setSearch(value) setHighlighted(-1) }} onSelect={(branch) => select(branch.name)} + onSearchKeyDown={keydown} selected={props.selected} highlighted={highlighted()} onHighlight={setHighlighted} - searchPlaceholder={t("agentManager.dialog.searchBranches")} - emptyLabel={t("agentManager.import.noMatchingBranches")} - loadingLabel={t("agentManager.import.loadingBranches")} - defaultLabel={t("agentManager.dialog.branchBadge.default")} - remoteLabel={t("agentManager.dialog.branchBadge.remote")} + searchPlaceholder={language.t("agentManager.dialog.searchBranches")} + emptyLabel={language.t("agentManager.import.noMatchingBranches")} + loadingLabel={language.t("agentManager.import.loadingBranches")} + defaultLabel={language.t("agentManager.dialog.branchBadge.default")} + remoteLabel={language.t("agentManager.dialog.branchBadge.remote")} defaultName={props.selected ?? props.detected} autoOption={{ - label: t("agentManager.worktree.defaultBaseBranchAuto"), + label: language.t("agentManager.worktree.defaultBaseBranchAuto"), hint: props.detected, active: !props.selected, highlighted: highlighted() === -1, diff --git a/packages/kilo-vscode/webview-ui/agent-manager/ProjectList.tsx b/packages/kilo-vscode/webview-ui/agent-manager/ProjectList.tsx index f589d9bdafd..93b42482a9f 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/ProjectList.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/ProjectList.tsx @@ -18,7 +18,6 @@ import { SidebarSearchMenu, type SidebarSearchMenuRef } from "./SidebarSearchMen import type { SidebarSearchItem } from "./sidebar-search" import { LOCAL } from "./navigate" import { NewWorktreeDialog } from "./NewWorktreeDialog" -import { ProjectBranchDialog } from "./ProjectBranchDialog" import type { ProjectStore } from "./project/store" import type { ModeRouter } from "./mode-router" @@ -155,15 +154,6 @@ export const ProjectList: Component = (props) => { /> )) } - const defaultBranch = (projectId: string, selected?: string, detected?: string) => - dialog.show(() => ( - dialog.close()} - /> - )) return ( = (props) => { onSelectWorktree={(projectId, worktreeId) => select({ projectId, kind: "worktree", worktreeId })} onSelectSession={(projectId, sessionId) => select({ projectId, kind: "session", sessionId })} onNewWorktree={newWorktree} - onDefaultBranch={defaultBranch} shortcutMap={props.shortcutMap} /> )} diff --git a/packages/kilo-vscode/webview-ui/agent-manager/ProjectSidebarBody.tsx b/packages/kilo-vscode/webview-ui/agent-manager/ProjectSidebarBody.tsx index f5200872a7a..176449c5e4e 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/ProjectSidebarBody.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/ProjectSidebarBody.tsx @@ -57,7 +57,6 @@ interface Props { onSelectWorktree: (projectId: string, worktreeId: string) => void onSelectSession: (projectId: string, sessionId: string) => void onNewWorktree: (projectId: string) => void - onDefaultBranch: (projectId: string, selected?: string, detected?: string) => void shortcutMap?: () => Map } @@ -366,8 +365,9 @@ export const ProjectSidebarBody: Component = (props) => { onCreate={() => post({ type: "agentManager.createWorktree" })} onNew={() => props.onNewWorktree(props.project.id)} onSection={() => createSection()} - onSetup={() => post({ type: "agentManager.configureSetupScript" })} - onBranch={() => props.onDefaultBranch(props.project.id, state()?.defaultBaseBranch, props.local?.branch)} + onSettings={() => + vscode.postMessage({ type: "openSettingsPanel", tab: "agentManager", projectId: props.project.id }) + } /> } /> diff --git a/packages/kilo-vscode/webview-ui/agent-manager/SidebarBody.tsx b/packages/kilo-vscode/webview-ui/agent-manager/SidebarBody.tsx index 2c4de2b253f..f1ab0bbeb80 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/SidebarBody.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/SidebarBody.tsx @@ -63,8 +63,6 @@ export interface SidebarBodyProps { onNewWorktree: () => void onNewSection: () => void onShortcuts: () => void - onSetup: () => void - onBranch: () => void sections: () => SectionState[] sortedWorktrees: () => WorktreeState[] worktrees: () => WorktreeState[] @@ -205,8 +203,9 @@ export const SidebarBody: Component = (props) => { onNew={props.onNewWorktree} onSection={props.onNewSection} onShortcuts={props.onShortcuts} - onSetup={props.onSetup} - onBranch={props.onBranch} + onSettings={() => + vscode.postMessage({ type: "openSettingsPanel", tab: "agentManager", projectId: props.projectId }) + } /> } /> diff --git a/packages/kilo-vscode/webview-ui/agent-manager/WorktreeSectionActions.tsx b/packages/kilo-vscode/webview-ui/agent-manager/WorktreeSectionActions.tsx index 7517e3f3905..e84d3a369fd 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/WorktreeSectionActions.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/WorktreeSectionActions.tsx @@ -25,8 +25,7 @@ interface WorktreeSectionActionsProps { onNew: () => void onSection: () => void onShortcuts: () => void - onSetup: () => void - onBranch: () => void + onSettings: () => void } export const WorktreeSectionActions: Component = (props) => ( @@ -108,28 +107,13 @@ export const WorktreeSectionActions: Component = (p onClick={props.onShortcuts} /> - - - - - - {props.t("agentManager.worktree.setupScript")} - - - - - {props.t("agentManager.worktree.defaultBaseBranch")}: {props.branch} - - - - - +
) diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ar.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ar.ts index f17534484d4..a87e28316ed 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ar.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ar.ts @@ -5,6 +5,14 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "الجلسات", "agentManager.projects": "المشاريع", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "المشروع", + "agentManager.settings.project.description": "اختر repository الذي تريد تعديل إعدادات worktree الخاصة به.", + "agentManager.settings.project.empty": "لا تتوفر أي مشاريع في Agent Manager.", + "agentManager.settings.defaultBaseBranch.description": "branch المستخدم كنقطة بداية لـ worktrees جديدة.", + "agentManager.settings.setupScript.description": "شغّل قبل أن يبدأ agent في worktree جديد.", + "agentManager.settings.setupScript.create": "إنشاء script", + "agentManager.settings.setupScript.edit": "تحرير script", "agentManager.project.add": "إضافة مشروع", "agentManager.project.remove": "إزالة من Agent Manager", "agentManager.project.missing": "المستودع غير موجود", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/br.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/br.ts index b8604ec7298..6405f8445b9 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/br.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/br.ts @@ -5,6 +5,15 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "SESSÕES", "agentManager.projects": "PROJETOS", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "Projeto", + "agentManager.settings.project.description": + "Escolha o repository cujas configurações de worktree você deseja editar.", + "agentManager.settings.project.empty": "Nenhum projeto do Agent Manager está disponível.", + "agentManager.settings.defaultBaseBranch.description": "O branch usado como ponto de partida para novos worktrees.", + "agentManager.settings.setupScript.description": "Execute antes que um agent comece em um novo worktree.", + "agentManager.settings.setupScript.create": "Criar script", + "agentManager.settings.setupScript.edit": "Editar script", "agentManager.project.add": "Adicionar projeto", "agentManager.project.remove": "Remover do Agent Manager", "agentManager.project.missing": "Repositório não encontrado", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/bs.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/bs.ts index e22dc11ff21..7c8332ebc1a 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/bs.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/bs.ts @@ -5,6 +5,14 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "SESIJE", "agentManager.projects": "PROJEKTI", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "Projekat", + "agentManager.settings.project.description": "Izaberite repository čije worktree postavke želite urediti.", + "agentManager.settings.project.empty": "Nema dostupnih projekata u Agent Manager.", + "agentManager.settings.defaultBaseBranch.description": "branch koji se koristi kao početna tačka za nove worktrees.", + "agentManager.settings.setupScript.description": "Pokrenite prije nego što agent počne u novom worktree.", + "agentManager.settings.setupScript.create": "Kreiraj script", + "agentManager.settings.setupScript.edit": "Uredi script", "agentManager.project.add": "Dodaj projekat", "agentManager.project.remove": "Ukloni iz Agent Manager-a", "agentManager.project.missing": "Repozitorij nije pronađen", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/da.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/da.ts index 7f98c83c705..59d096951b4 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/da.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/da.ts @@ -5,6 +5,14 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "SESSIONER", "agentManager.projects": "PROJEKTER", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "Projekt", + "agentManager.settings.project.description": "Vælg det repository, hvis worktree-indstillinger du vil redigere.", + "agentManager.settings.project.empty": "Der er ingen tilgængelige projekter i Agent Manager.", + "agentManager.settings.defaultBaseBranch.description": "Den branch, der bruges som udgangspunkt for nye worktrees.", + "agentManager.settings.setupScript.description": "Kør, før en agent starter i et nyt worktree.", + "agentManager.settings.setupScript.create": "Opret script", + "agentManager.settings.setupScript.edit": "Rediger script", "agentManager.project.add": "Tilføj projekt", "agentManager.project.remove": "Fjern fra Agent Manager", "agentManager.project.missing": "Repository ikke fundet", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/de.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/de.ts index 870f4ef0afa..27bee14671a 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/de.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/de.ts @@ -5,6 +5,16 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "SITZUNGEN", "agentManager.projects": "PROJEKTE", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "Projekt", + "agentManager.settings.project.description": + "Wählen Sie das repository aus, dessen worktree-Einstellungen Sie bearbeiten möchten.", + "agentManager.settings.project.empty": "Keine Agent Manager-Projekte verfügbar.", + "agentManager.settings.defaultBaseBranch.description": + "Der branch, der als Ausgangspunkt für neue worktrees verwendet wird.", + "agentManager.settings.setupScript.description": "Vor dem Start eines agent in einem neuen worktree ausführen.", + "agentManager.settings.setupScript.create": "Script erstellen", + "agentManager.settings.setupScript.edit": "Script bearbeiten", "agentManager.project.add": "Projekt hinzufügen", "agentManager.project.remove": "Aus Agent Manager entfernen", "agentManager.project.missing": "Repository nicht gefunden", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/en.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/en.ts index 98ac2cbb486..444e04f4394 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/en.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/en.ts @@ -5,6 +5,14 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "SESSIONS", "agentManager.projects": "PROJECTS", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "Project", + "agentManager.settings.project.description": "Choose the repository whose worktree settings you want to edit.", + "agentManager.settings.project.empty": "No Agent Manager projects are available.", + "agentManager.settings.defaultBaseBranch.description": "The branch used as the starting point for new worktrees.", + "agentManager.settings.setupScript.description": "Run before an agent starts in a new worktree.", + "agentManager.settings.setupScript.create": "Create script", + "agentManager.settings.setupScript.edit": "Edit script", "agentManager.project.add": "Add project", "agentManager.project.remove": "Remove from Agent Manager", "agentManager.project.missing": "Repository not found", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/es.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/es.ts index 361ddc45642..e85ae50571b 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/es.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/es.ts @@ -5,6 +5,15 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "SESIONES", "agentManager.projects": "PROYECTOS", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "Proyecto", + "agentManager.settings.project.description": "Elige el repository cuyos ajustes de worktree quieres editar.", + "agentManager.settings.project.empty": "No hay proyectos de Agent Manager disponibles.", + "agentManager.settings.defaultBaseBranch.description": + "El branch que se usa como punto de partida para nuevos worktrees.", + "agentManager.settings.setupScript.description": "Ejecutar antes de que un agent se inicie en un nuevo worktree.", + "agentManager.settings.setupScript.create": "Crear script", + "agentManager.settings.setupScript.edit": "Editar script", "agentManager.project.add": "Añadir proyecto", "agentManager.project.remove": "Eliminar de Agent Manager", "agentManager.project.missing": "Repositorio no encontrado", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/fa.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/fa.ts index c4bafd3fabe..c856919da06 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/fa.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/fa.ts @@ -5,6 +5,15 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "جلسات", "agentManager.projects": "پروژه‌ها", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "پروژه", + "agentManager.settings.project.description": + "repository موردنظر را انتخاب کنید تا تنظیمات worktree آن را ویرایش کنید.", + "agentManager.settings.project.empty": "هیچ پروژه‌ای در Agent Manager در دسترس نیست.", + "agentManager.settings.defaultBaseBranch.description": "branch مورد استفاده به‌عنوان نقطه شروع برای worktrees جدید.", + "agentManager.settings.setupScript.description": "قبل از شروع agent در یک worktree جدید اجرا شود.", + "agentManager.settings.setupScript.create": "ایجاد script", + "agentManager.settings.setupScript.edit": "ویرایش script", "agentManager.project.add": "افزودن پروژه", "agentManager.project.remove": "حذف از Agent Manager", "agentManager.project.missing": "مخزن یافت نشد", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/fr.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/fr.ts index 7668580f55e..5162d1784e6 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/fr.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/fr.ts @@ -5,6 +5,16 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "SESSIONS", "agentManager.projects": "PROJETS", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "Projet", + "agentManager.settings.project.description": + "Choisissez le repository dont vous souhaitez modifier les paramètres du worktree.", + "agentManager.settings.project.empty": "Aucun projet Agent Manager n'est disponible.", + "agentManager.settings.defaultBaseBranch.description": + "Le branch utilisé comme point de départ pour les nouveaux worktrees.", + "agentManager.settings.setupScript.description": "Exécuter avant qu'un agent ne démarre dans un nouveau worktree.", + "agentManager.settings.setupScript.create": "Créer script", + "agentManager.settings.setupScript.edit": "Modifier script", "agentManager.project.add": "Ajouter un projet", "agentManager.project.remove": "Retirer d'Agent Manager", "agentManager.project.missing": "Dépôt introuvable", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/it.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/it.ts index 306f4397772..6f124aa04e4 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/it.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/it.ts @@ -5,6 +5,16 @@ export const dict = { "agentManager.section.worktrees": "WORKTREE", "agentManager.section.sessions": "SESSIONI", "agentManager.projects": "PROGETTI", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "Progetto", + "agentManager.settings.project.description": + "Scegli il repository di cui vuoi modificare le impostazioni del worktree.", + "agentManager.settings.project.empty": "Non sono disponibili progetti di Agent Manager.", + "agentManager.settings.defaultBaseBranch.description": + "Il branch usato come punto di partenza per i nuovi worktrees.", + "agentManager.settings.setupScript.description": "Esegui prima che un agent inizi in un nuovo worktree.", + "agentManager.settings.setupScript.create": "Crea script", + "agentManager.settings.setupScript.edit": "Modifica script", "agentManager.project.add": "Aggiungi progetto", "agentManager.project.remove": "Rimuovi da Agent Manager", "agentManager.project.missing": "Repository non trovata", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ja.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ja.ts index 4938e07895b..86234a5ccc7 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ja.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ja.ts @@ -5,6 +5,14 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "セッション", "agentManager.projects": "プロジェクト", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "プロジェクト", + "agentManager.settings.project.description": "編集する worktree 設定の repository を選択してください。", + "agentManager.settings.project.empty": "利用可能な Agent Manager プロジェクトはありません。", + "agentManager.settings.defaultBaseBranch.description": "新しい worktrees の開始点として使用する branch。", + "agentManager.settings.setupScript.description": "新しい worktree で agent が開始する前に実行します。", + "agentManager.settings.setupScript.create": "script を作成", + "agentManager.settings.setupScript.edit": "script を編集", "agentManager.project.add": "プロジェクトを追加", "agentManager.project.remove": "Agent Managerから削除", "agentManager.project.missing": "リポジトリが見つかりません", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ko.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ko.ts index 60ab9d8a9c8..8e9b27e13ac 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ko.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ko.ts @@ -5,6 +5,14 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "세션", "agentManager.projects": "프로젝트", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "프로젝트", + "agentManager.settings.project.description": "편집하려는 worktree 설정의 repository를 선택하세요.", + "agentManager.settings.project.empty": "사용 가능한 Agent Manager 프로젝트가 없습니다.", + "agentManager.settings.defaultBaseBranch.description": "새 worktrees의 시작점으로 사용할 branch입니다.", + "agentManager.settings.setupScript.description": "새 worktree에서 agent가 시작하기 전에 실행합니다.", + "agentManager.settings.setupScript.create": "script 만들기", + "agentManager.settings.setupScript.edit": "script 편집", "agentManager.project.add": "프로젝트 추가", "agentManager.project.remove": "Agent Manager에서 제거", "agentManager.project.missing": "저장소를 찾을 수 없음", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/nl.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/nl.ts index 28fc682c601..b4a633971db 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/nl.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/nl.ts @@ -5,6 +5,15 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "SESSIES", "agentManager.projects": "PROJECTEN", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "Project", + "agentManager.settings.project.description": "Kies de repository waarvan je de worktree-instellingen wilt bewerken.", + "agentManager.settings.project.empty": "Er zijn geen Agent Manager-projecten beschikbaar.", + "agentManager.settings.defaultBaseBranch.description": + "De branch die als startpunt voor nieuwe worktrees wordt gebruikt.", + "agentManager.settings.setupScript.description": "Uitvoeren voordat een agent in een nieuwe worktree start.", + "agentManager.settings.setupScript.create": "script maken", + "agentManager.settings.setupScript.edit": "script bewerken", "agentManager.project.add": "Project toevoegen", "agentManager.project.remove": "Verwijderen uit Agent Manager", "agentManager.project.missing": "Repository niet gevonden", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/no.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/no.ts index ac00ffa1174..93a7bc0d1d3 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/no.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/no.ts @@ -5,6 +5,14 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "ØKTER", "agentManager.projects": "PROSJEKTER", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "Prosjekt", + "agentManager.settings.project.description": "Velg repository hvis worktree-innstillinger du vil redigere.", + "agentManager.settings.project.empty": "Ingen Agent Manager-prosjekter er tilgjengelige.", + "agentManager.settings.defaultBaseBranch.description": "branch som brukes som utgangspunkt for nye worktrees.", + "agentManager.settings.setupScript.description": "Kjør før en agent starter i et nytt worktree.", + "agentManager.settings.setupScript.create": "Opprett script", + "agentManager.settings.setupScript.edit": "Rediger script", "agentManager.project.add": "Legg til prosjekt", "agentManager.project.remove": "Fjern fra Agent Manager", "agentManager.project.missing": "Repository ikke funnet", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/pl.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/pl.ts index 604fe538f5a..71d7e8b31d7 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/pl.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/pl.ts @@ -5,6 +5,14 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "SESJE", "agentManager.projects": "PROJEKTY", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "Projekt", + "agentManager.settings.project.description": "Wybierz repository, którego ustawienia worktree chcesz edytować.", + "agentManager.settings.project.empty": "Brak dostępnych projektów Agent Manager.", + "agentManager.settings.defaultBaseBranch.description": "branch używany jako punkt wyjścia dla nowych worktrees.", + "agentManager.settings.setupScript.description": "Uruchom przed tym, jak agent rozpocznie pracę w nowym worktree.", + "agentManager.settings.setupScript.create": "Utwórz script", + "agentManager.settings.setupScript.edit": "Edytuj script", "agentManager.project.add": "Dodaj projekt", "agentManager.project.remove": "Usuń z Agent Manager", "agentManager.project.missing": "Nie znaleziono repozytorium", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ru.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ru.ts index eaec5e77e82..2b4b4158829 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/ru.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/ru.ts @@ -5,6 +5,15 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "СЕССИИ", "agentManager.projects": "ПРОЕКТЫ", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "Проект", + "agentManager.settings.project.description": "Выберите repository, настройки worktree которого хотите изменить.", + "agentManager.settings.project.empty": "Нет доступных проектов Agent Manager.", + "agentManager.settings.defaultBaseBranch.description": + "branch, используемый как отправная точка для новых worktrees.", + "agentManager.settings.setupScript.description": "Запустите перед тем, как agent начнёт работу в новом worktree.", + "agentManager.settings.setupScript.create": "Создать script", + "agentManager.settings.setupScript.edit": "Изменить script", "agentManager.project.add": "Добавить проект", "agentManager.project.remove": "Удалить из Agent Manager", "agentManager.project.missing": "Репозиторий не найден", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/th.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/th.ts index 8a49bd7d676..22ec68c7e51 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/th.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/th.ts @@ -5,6 +5,14 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "เซสชัน", "agentManager.projects": "โปรเจกต์", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "โปรเจกต์", + "agentManager.settings.project.description": "เลือก repository ที่มีการตั้งค่า worktree ที่คุณต้องการแก้ไข", + "agentManager.settings.project.empty": "ไม่มีโปรเจกต์ Agent Manager ที่พร้อมใช้งาน", + "agentManager.settings.defaultBaseBranch.description": "branch ที่ใช้เป็นจุดเริ่มต้นสำหรับ worktrees ใหม่", + "agentManager.settings.setupScript.description": "เรียกใช้ก่อนที่ agent จะเริ่มทำงานใน worktree ใหม่", + "agentManager.settings.setupScript.create": "สร้าง script", + "agentManager.settings.setupScript.edit": "แก้ไข script", "agentManager.project.add": "เพิ่มโปรเจกต์", "agentManager.project.remove": "ลบออกจาก Agent Manager", "agentManager.project.missing": "ไม่พบ Repository", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/tr.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/tr.ts index c591acfbe07..b2a32c27221 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/tr.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/tr.ts @@ -5,6 +5,15 @@ export const dict = { "agentManager.section.worktrees": "WORKTREE'LER", "agentManager.section.sessions": "OTURUMLAR", "agentManager.projects": "PROJELER", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "Proje", + "agentManager.settings.project.description": "Worktree ayarlarını düzenlemek istediğiniz repository'yi seçin.", + "agentManager.settings.project.empty": "Kullanılabilir Agent Manager projesi yok.", + "agentManager.settings.defaultBaseBranch.description": + "Yeni worktrees için başlangıç noktası olarak kullanılan branch.", + "agentManager.settings.setupScript.description": "Yeni bir worktree'de agent başlamadan önce çalıştırın.", + "agentManager.settings.setupScript.create": "script oluştur", + "agentManager.settings.setupScript.edit": "script düzenle", "agentManager.project.add": "Proje ekle", "agentManager.project.remove": "Agent Manager'dan kaldır", "agentManager.project.missing": "Depo bulunamadı", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/uk.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/uk.ts index e7dcf15eab8..2c9a890d44d 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/uk.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/uk.ts @@ -5,6 +5,15 @@ export const dict = { "agentManager.section.worktrees": "РОБОЧІ ДЕРЕВА", "agentManager.section.sessions": "СЕСІЇ", "agentManager.projects": "ПРОЄКТИ", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "Проєкт", + "agentManager.settings.project.description": "Виберіть repository, налаштування worktree якого потрібно змінити.", + "agentManager.settings.project.empty": "Немає доступних проєктів Agent Manager.", + "agentManager.settings.defaultBaseBranch.description": + "branch, який використовується як початкова точка для нових worktrees.", + "agentManager.settings.setupScript.description": "Запускайте перед початком роботи agent у новому worktree.", + "agentManager.settings.setupScript.create": "Створити script", + "agentManager.settings.setupScript.edit": "Редагувати script", "agentManager.project.add": "Додати проєкт", "agentManager.project.remove": "Видалити з Agent Manager", "agentManager.project.missing": "Репозиторій не знайдено", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/zh.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/zh.ts index b616af3abfa..d3a1450c79a 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/zh.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/zh.ts @@ -5,6 +5,14 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "会话", "agentManager.projects": "项目", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "项目", + "agentManager.settings.project.description": "选择要编辑其 worktree 设置的 repository。", + "agentManager.settings.project.empty": "没有可用的 Agent Manager 项目。", + "agentManager.settings.defaultBaseBranch.description": "用于新 worktrees 起始点的 branch。", + "agentManager.settings.setupScript.description": "在 agent 于新 worktree 中启动前运行。", + "agentManager.settings.setupScript.create": "创建 script", + "agentManager.settings.setupScript.edit": "编辑 script", "agentManager.project.add": "添加项目", "agentManager.project.remove": "从 Agent Manager 移除", "agentManager.project.missing": "未找到仓库", diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/zht.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/zht.ts index 6ac5ed1493c..535540d869e 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/i18n/zht.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/zht.ts @@ -5,6 +5,14 @@ export const dict = { "agentManager.section.worktrees": "WORKTREES", "agentManager.section.sessions": "工作階段", "agentManager.projects": "專案", + "agentManager.settings.title": "Agent Manager", + "agentManager.settings.project.title": "專案", + "agentManager.settings.project.description": "選擇要編輯其 worktree 設定的 repository。", + "agentManager.settings.project.empty": "沒有可用的 Agent Manager 專案。", + "agentManager.settings.defaultBaseBranch.description": "用作新 worktrees 起始點的 branch。", + "agentManager.settings.setupScript.description": "在 agent 於新的 worktree 中啟動前執行。", + "agentManager.settings.setupScript.create": "建立 script", + "agentManager.settings.setupScript.edit": "編輯 script", "agentManager.project.add": "新增專案", "agentManager.project.remove": "從 Agent Manager 移除", "agentManager.project.missing": "找不到儲存庫", diff --git a/packages/kilo-vscode/webview-ui/src/App.tsx b/packages/kilo-vscode/webview-ui/src/App.tsx index 54fca2628ac..8e838807a9c 100644 --- a/packages/kilo-vscode/webview-ui/src/App.tsx +++ b/packages/kilo-vscode/webview-ui/src/App.tsx @@ -220,6 +220,7 @@ export const DataBridge: Component<{ children: any }> = (props) => { const AppContent: Component = () => { const [currentView, setCurrentView] = createSignal("newTask") const [settingsTab, setSettingsTab] = createSignal() + const [agentManagerProjectId, setAgentManagerProjectId] = createSignal() // legacy-migration: state-driven flag independent of currentView to avoid // race conditions with SettingsEditorProvider's navigate messages. const [migrationNeeded, setMigrationNeeded] = createSignal(false) @@ -294,6 +295,7 @@ const AppContent: Component = () => { if (message?.type === "navigate" && message.view && VALID_VIEWS.has(message.view)) { console.log("[Kilo New] App: 🧭 navigate:", message.view, message.tab ? `tab=${message.tab}` : "") if (message.tab) setSettingsTab(message.tab) + setAgentManagerProjectId(message.projectId) setCurrentView(message.view as ViewType) vscode.postMessage({ type: "settingsTabChanged", tab: message.tab }) } @@ -341,7 +343,11 @@ const AppContent: Component = () => { // VS Code's native title bar toolbar already covers those. Defaults to // true only when unset entirely (e.g. Storybook, which doesn't render the // real page HTML). - const host = window as { KILO_TOP_BAR?: boolean; KILO_TOP_BAR_SURFACE?: string } + const host = window as { + KILO_TOP_BAR?: boolean + KILO_TOP_BAR_SURFACE?: string + KILO_AGENT_MANAGER_SETTINGS?: boolean + } const showTopBar = host.KILO_TOP_BAR !== false const topBarSurface = host.KILO_TOP_BAR_SURFACE ?? "sidebar_title" @@ -396,6 +402,8 @@ const AppContent: Component = () => { { setMigrationSource(source) diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/Settings.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/Settings.tsx index ab8a5e99fba..22ff8dadc0a 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/Settings.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/Settings.tsx @@ -1,7 +1,8 @@ -import { Component, createSignal, createEffect, createMemo, on, Show } from "solid-js" +import { Component, createSignal, createEffect, createMemo, on, Show, onCleanup } from "solid-js" import { Icon } from "@kilocode/kilo-ui/icon" import { Tabs } from "@kilocode/kilo-ui/tabs" import { Button } from "@kilocode/kilo-ui/button" +import { useDialog } from "@kilocode/kilo-ui/context/dialog" import { Tooltip } from "@kilocode/kilo-ui/tooltip" import { showToast } from "@kilocode/kilo-ui/toast" import { useVSCode } from "../../context/vscode" @@ -29,13 +30,192 @@ import * as Sandboxing from "./sandboxing" import { useServer } from "../../context/server" import type { MigrationSource } from "../../types/messages" import { configMessage } from "../../utils/open-config" +import type { + AgentManagerSettingsBranchesLoadedMessage, + AgentManagerSettingsLoadedMessage, + AgentManagerSettingsProject, + ExtensionMessage, +} from "../../types/messages" +import { Select } from "@kilocode/kilo-ui/select" +import { Card } from "@kilocode/kilo-ui/card" +import { Spinner } from "@kilocode/kilo-ui/spinner" +import SettingsRow from "./SettingsRow" +import { ProjectBranchDialog } from "../../../agent-manager/ProjectBranchDialog" export interface SettingsProps { tab?: string + agentManagerProjectId?: string + agentManagerSettings?: boolean onTabChange?: (tab: string) => void onMigrationClick?: (source: MigrationSource) => void // legacy-migration } +const AgentManagerTab: Component<{ projectId?: string }> = (props) => { + const language = useLanguage() + const vscode = useVSCode() + const dialog = useDialog() + const [projects, setProjects] = createSignal([]) + const remembered = vscode.getState<{ agentManagerProjectId?: string }>()?.agentManagerProjectId + const [selected, setSelected] = createSignal(props.projectId ?? remembered) + const [branches, setBranches] = createSignal() + const [branchLoading, setBranchLoading] = createSignal(false) + const [loading, setLoading] = createSignal(true) + let count = 0 + let latestSettings = "" + let latestBranches = "" + const issue = () => { + return `${Date.now() * 1000 + ++count}` + } + const scriptPath = () => + projects().find((item) => item.id === selected())?.setupScriptPath ?? branches()?.setupScriptPath + const load = (projectId?: string) => { + if (!projectId) return + setSelected(projectId) + setBranches(undefined) + setBranchLoading(false) + vscode.setState({ ...vscode.getState>(), agentManagerProjectId: projectId }) + latestSettings = issue() + latestBranches = latestSettings + vscode.postMessage({ type: "requestAgentManagerSettings", projectId, requestId: latestSettings }) + } + const loadBranches = (projectId?: string) => { + if (!projectId || (branches()?.projectId === projectId && !branches()?.error) || branchLoading()) return + setBranchLoading(true) + latestBranches = issue() + vscode.postMessage({ type: "requestAgentManagerSettingsBranches", projectId, requestId: latestBranches }) + } + createEffect(() => { + if (props.projectId && props.projectId !== selected()) load(props.projectId) + }) + const onMessage = (message: ExtensionMessage) => { + if (message.type === "agentManagerSettingsLoaded") { + const event = message as AgentManagerSettingsLoadedMessage + if (event.requestId !== latestSettings) return + setProjects(event.projects) + const current = selected() + const next = event.projects.some((project) => project.id === current) ? current : event.projectId + setSelected(next) + setLoading(false) + return + } + if (message.type === "agentManagerSettingsBranchesLoaded") { + const event = message as AgentManagerSettingsBranchesLoadedMessage + if (event.requestId !== latestBranches) return + if (event.projectId === selected()) { + setBranches(event.error ? undefined : event) + setBranchLoading(false) + } + } + } + const initial = props.projectId ?? remembered + const timeout = setTimeout(() => setLoading(false), 3000) + const unsubscribe = vscode.onMessage(onMessage) + onCleanup(() => { + unsubscribe() + clearTimeout(timeout) + }) + latestSettings = issue() + vscode.postMessage({ type: "requestAgentManagerSettings", projectId: initial, requestId: latestSettings }) + const project = () => projects().find((item) => item.id === selected()) + const projectText = (item: AgentManagerSettingsProject) => `${item.label} - ${item.root}` + const branchLabel = () => { + const data = branches() + const configured = data ? data.configuredBaseBranch : project()?.defaultBaseBranch + if (configured) return configured + const detected = data?.defaultBranch ?? project()?.defaultBranch + return `${language.t("agentManager.worktree.defaultBaseBranchAuto")}${detected ? ` (${detected})` : ""}` + } + const setBranch = (branch?: string) => { + const id = selected() + if (!id) return + setBranches((current) => (current ? { ...current, configuredBaseBranch: branch } : current)) + latestSettings = issue() + latestBranches = latestSettings + vscode.postMessage({ type: "setAgentManagerDefaultBaseBranch", projectId: id, branch, requestId: latestSettings }) + } + const openBranches = () => { + const id = selected() + if (!id || project()?.missing) return + loadBranches(id) + dialog.show(() => ( + branches()?.branches ?? []} + loading={branchLoading} + onClose={() => dialog.close()} + onSelect={setBranch} + /> + )) + } + return ( + }> +
+ + +