diff --git a/.changeset/agent-manager-terminal-context.md b/.changeset/agent-manager-terminal-context.md new file mode 100644 index 00000000000..bfc2ad8df8f --- /dev/null +++ b/.changeset/agent-manager-terminal-context.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Capture `@terminal` from the focused Agent Manager terminal, including embedded Run and Setup terminals, instead of using an unrelated active VS Code terminal. diff --git a/.changeset/remove-agent-requirements.md b/.changeset/remove-agent-requirements.md new file mode 100644 index 00000000000..0d1136dbfd6 --- /dev/null +++ b/.changeset/remove-agent-requirements.md @@ -0,0 +1,6 @@ +--- +"@kilocode/cli": patch +"kilo-code": patch +--- + +Remove the experimental agent requirements check and its configuration flag. diff --git a/packages/core/src/v1/config/agent.ts b/packages/core/src/v1/config/agent.ts index ea49adb8b9c..6ac30d2f67d 100644 --- a/packages/core/src/v1/config/agent.ts +++ b/packages/core/src/v1/config/agent.ts @@ -9,62 +9,6 @@ const Color = Schema.Union([ Schema.Literals(["primary", "secondary", "accent", "success", "warning", "error", "info"]), ]) -// kilocode_change start - agent skill/MCP/VS Code extension requirements schema -const RequirementID = Schema.String.check( - Schema.isMinLength(1), - Schema.isMaxLength(128), - Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._-]*$/), -) -const RequirementName = Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(128), Schema.isPattern(/\S/)) - -export const VSCodeExtension = Schema.Struct({ - name: RequirementName, - id: RequirementID, -}) -export type VSCodeExtension = Schema.Schema.Type - -const RequirementGroup = Schema.mutable(Schema.Array(RequirementName)).check( - Schema.isMinLength(1), - Schema.isMaxLength(20), -) -const VSCodeExtensions = Schema.mutable(Schema.Array(VSCodeExtension)).check( - Schema.isMinLength(1), - Schema.isMaxLength(20), -) - -export const Requirements = Schema.Struct({ - skills: Schema.optional(RequirementGroup), - mcps: Schema.optional(RequirementGroup), - vscode_extensions: Schema.optional(VSCodeExtensions), -}).check( - Schema.makeFilter((input) => { - const issues: Schema.FilterIssue[] = [] - if (!input.skills && !input.mcps && !input.vscode_extensions) { - issues.push({ path: [], issue: "At least one requirement group is required" }) - } - - for (const group of ["skills", "mcps"] as const) { - const seen = new Set() - for (const [index, value] of (input[group] ?? []).entries()) { - if (seen.has(value)) issues.push({ path: [group, index], issue: `Duplicate ${group} requirement` }) - seen.add(value) - } - } - - const seen = new Set() - for (const [index, extension] of (input.vscode_extensions ?? []).entries()) { - if (seen.has(extension.id)) { - issues.push({ path: ["vscode_extensions", index, "id"], issue: "Duplicate vscode_extensions requirement" }) - } - seen.add(extension.id) - } - - return issues - }), -) -export type Requirements = Schema.Schema.Type -// kilocode_change end - const AgentSchema = Schema.StructWithRest( Schema.Struct({ model: Schema.optional(Schema.NullOr(Schema.String)), // kilocode_change - nullable for delete sentinel @@ -108,7 +52,6 @@ const AgentSchema = Schema.StructWithRest( // kilocode_change end maxSteps: Schema.optional(PositiveInt).annotate({ description: "@deprecated Use 'steps' field instead." }), permission: Schema.optional(ConfigPermissionV1.Info), - requirements: Schema.optional(Requirements), // kilocode_change }), [Schema.Record(Schema.String, Schema.Any)], ) @@ -132,7 +75,7 @@ const KNOWN_KEYS = new Set([ "permission", "disable", "tools", - "requirements", // kilocode_change + "requirements", // kilocode_change - ignore declarations from removed agent requirements feature ]) const normalize = (agent: Schema.Schema.Type): Schema.Schema.Type => { diff --git a/packages/core/src/v1/config/config.ts b/packages/core/src/v1/config/config.ts index 3c3e13ea4ba..5dd4d7612cc 100644 --- a/packages/core/src/v1/config/config.ts +++ b/packages/core/src/v1/config/config.ts @@ -301,9 +301,6 @@ export const Info = Schema.Struct({ image_generation_model: Schema.optional(Schema.String).annotate({ description: "Model ID to use for image generation (default: openrouter/auto)", }), - agent_requirements: Schema.optional(Schema.Boolean).annotate({ - description: "Require declared agent skills, MCPs, and VS Code extensions before VS Code prompts can run", - }), native_notebook_tools: Schema.optional(Schema.Boolean).annotate({ description: "Enable native tools for reading, editing, and executing VS Code notebooks", }), diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-requirements-checking-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-requirements-checking-chromium-linux.png deleted file mode 100644 index 254906a5329..00000000000 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-requirements-checking-chromium-linux.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a093b9658cc15d0789da5afebde7163ec51e743af59975e2a031aed3e9144d56 -size 22336 diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-requirements-malformed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-requirements-malformed-chromium-linux.png deleted file mode 100644 index f0ed1261382..00000000000 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-requirements-malformed-chromium-linux.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0b20e8e50b583cc6a884e08648a9f1efcdfc2a9561b97145811ebc9c24d244fd -size 23100 diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-requirements-missing-extension-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-requirements-missing-extension-chromium-linux.png deleted file mode 100644 index 033e4563cb3..00000000000 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-requirements-missing-extension-chromium-linux.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3b24b0d2694d2eeec0ea4cd827bd3a61bb47150605b838b43e4f422c9b960f0e -size 29744 diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-requirements-missing-tools-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-requirements-missing-tools-chromium-linux.png deleted file mode 100644 index 37195aeeea7..00000000000 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-requirements-missing-tools-chromium-linux.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fd27610a2518018c16e4227728221ed9bf67a7d3c8ab207b2835dc60964ec63d -size 33323 diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-requirements-ready-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-requirements-ready-chromium-linux.png deleted file mode 100644 index 01bfcc79738..00000000000 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-requirements-ready-chromium-linux.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d8ad46cc736472c6a2a46bb80e6622333f49960e74dcb6782d35aa72fa32378c -size 23725 diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index c288da5bf89..17493a1f21d 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -51,7 +51,6 @@ import { import { GitOps } from "./agent-manager/GitOps" import { GitStatsPoller, type LocalStats } from "./agent-manager/GitStatsPoller" import { createMarketplaceRemover, removeMcp } from "./kilo-provider/remove-config-item" -import { AgentRequirementsController } from "./kilo-provider/agent-requirements-controller" import type { RemoteStatusService } from "./services/RemoteStatusService" import { resolveProjectDirectory } from "./project-directory" import { seedSessionStatuses } from "./session-status" @@ -319,7 +318,7 @@ type ContextRequestMessage = | { type: "requestFileSearch"; query: string; requestId: string; sessionID?: string } | { type: "requestSessionSearch"; requestId: string; sessionID?: string } | { type: "requestFilePicker"; requestId: string } - | { type: "requestTerminalContext"; requestId: string; sessionID?: string } + | { type: "requestTerminalContext"; requestId: string; sessionID?: string; agentManagerContext?: string } export class KiloProvider implements vscode.WebviewViewProvider, TelemetryPropertiesProvider { public static readonly viewType = "kilo-code.SidebarProvider" @@ -467,7 +466,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper private diffVirtualProvider: import("./DiffVirtualProvider").DiffVirtualProvider | undefined private remoteService: RemoteStatusService | null = null private unsubscribeRemote: (() => void) | null = null - private readonly requirements: AgentRequirementsController constructor( private readonly extensionUri: vscode.Uri, @@ -480,24 +478,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper this.unsubscribeSandboxPreference = this.connectionService.sandboxPreference?.onChange(() => { if (this.connectionState === "connected") void this.fetchAndSendSandboxDefault() }) - this.requirements = new AgentRequirementsController({ - post: (msg) => this.postMessage(msg), - client: () => this.client, - connected: () => this.connectionState === "connected", - generation: () => this.connectionGeneration, - root: () => this.getRootDirectory(), - folders: () => vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath), - project: () => this.projectDirectory, - sessions: () => this.sessionDirectories, - worktrees: this.opts.worktreeDirectories, - extension: (id) => vscode.extensions.getExtension(id), - subscribe: - typeof vscode.extensions.onDidChange === "function" - ? (listener) => vscode.extensions.onDidChange(listener) - : undefined, - error: getErrorMessage, - }) - TelemetryProxy.getInstance().setProvider(this) } @@ -575,7 +555,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper this.cachedConfigMessage = null this.postMessage({ type: "workspaceDirectoryChanged", directory: directory ?? "" }) this.postMessage({ type: "configBindingExpired", reason: "project-changed" }) - this.requirements.clear() } public setDiffVirtualProvider(provider: import("./DiffVirtualProvider").DiffVirtualProvider): void { @@ -663,7 +642,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper this.cachedAgentsMessage = null this.cachedConfigMessage = null await Promise.all([this.fetchAndSendAgents(), this.fetchAndSendConfig()]) - this.requirements.clear() }, storage: this.extensionContext?.globalStorageUri, } @@ -840,7 +818,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper const current = this.sessionDirectories.get(sessionId) ?? this.getRootDirectory() this.aborts.preserve(sessionId, this.sessionStatusMap.get(sessionId), current) this.sessionDirectories.set(sessionId, directory) - this.requirements.clear() if (this.connectionState === "connected") void this.fetchAndSendSandboxStatus(sessionId) } @@ -848,7 +825,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper const current = this.sessionDirectories.get(sessionId) ?? this.getRootDirectory() this.aborts.preserve(sessionId, this.sessionStatusMap.get(sessionId), current) this.sessionDirectories.delete(sessionId) - this.requirements.clear() if (this.connectionState === "connected") void this.fetchAndSendSandboxStatus(sessionId) } @@ -1275,16 +1251,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper case "requestSkills": this.fetchAndSendSkills().catch((e) => console.error("[Kilo New] fetchAndSendSkills failed:", e)) break - case "requestAgentRequirements": - this.requirements - .fetch({ - agent: message.agent, - directory: message.directory, - sessionID: message.sessionID, - force: message.force === true, - }) - .catch((e) => console.error("[Kilo New] fetchAndSendAgentRequirements failed:", e)) - break case "requestCommands": this.fetchAndSendCommands().catch((e) => console.error("[Kilo New] fetchAndSendCommands failed:", e)) break @@ -1967,7 +1933,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper }) .catch((e: unknown) => console.warn("[Kilo New] KiloProvider: getSession failed (non-critical):", e)) this.postMessage({ type: "workspaceDirectoryChanged", directory: this.getWorkspaceDirectory(sessionID) }) - this.requirements.clear() this.client.session .status({ directory: dir }) .then((r) => { @@ -2661,7 +2626,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper this.cachedSkillsMessage = null this.cachedCommandsMessage = null await Promise.all([this.fetchAndSendSkills(), this.fetchAndSendCommands()]) - this.requirements.clear() return true } @@ -2678,7 +2642,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper } this.cachedAgentsMessage = null await this.fetchAndSendAgents() - this.requirements.clear() } private async handleRemoveMcp(name: string): Promise { @@ -2690,7 +2653,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper private async refreshMcpStatus(): Promise { await this.fetchAndSendMcpStatus() - this.requirements.clear() } private async fetchAndSendMcpStatus(): Promise { @@ -3277,7 +3239,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper settings: this.configSettings(), features: configFeatures(snapshot.effective), }) - this.requirements.clear() await Promise.all([ refreshProviders ? this.fetchAndSendProviders() : Promise.resolve(), refreshAgents ? this.fetchAndSendAgents() : Promise.resolve(), @@ -3740,7 +3701,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper } parts.push({ type: "text", text, metadata: review ? reviewMetadata(review) : undefined }) - await this.requirements.assertAgentRequirements(agent, dir) const editorContext = await this.gatherEditorContext(dir) if (draftID && this.closedDrafts.delete(draftID)) { for (const [k, v] of this.draftSessions) if (v.sid === sid) this.draftSessions.delete(k) @@ -3835,7 +3795,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper source: f.source, })) - await this.requirements.assertAgentRequirements(agent, dir) await this.checkpoints.get(sid) await runWithMessageConfirmation(this.confirmations, messageID, "KiloProvider: Command request", () => this.withRetry( @@ -4205,7 +4164,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper /** Re-fetch all server-side state after an auth change. */ private async reloadAfterAuthChange(): Promise { - this.requirements.clear() await this.fetchAndSendConfig() await Promise.all([ this.fetchAndSendProviders(), @@ -4511,7 +4469,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper // Fetch and push the updated config + refresh agents and providers so the // Settings panel and mode/model pickers reflect the change. if (event.type === "global.config.updated") { - this.requirements.clear() void Promise.all([this.fetchAndSendConfigUpdated(), this.fetchAndSendAgents(), this.fetchAndSendProviders()]) return } @@ -5151,7 +5108,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper this.anacondaDesktop.dispose() this.aborts.clear() this.sessionStatusMap.clear() - this.requirements.dispose() this.ignoreController?.dispose() this.chatAutocomplete?.dispose() disposeGitChangesTarget() diff --git a/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts b/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts index 8cfab373faf..1a5cbd986e4 100644 --- a/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts +++ b/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts @@ -643,7 +643,6 @@ export class AgentManagerProvider implements Disposable { }) return null } - if ( m.type === "requestSandboxDefault" || m.type === "setSandboxDefault" || @@ -668,9 +667,9 @@ export class AgentManagerProvider implements Disposable { this.activeSessionId = m.draftID return msg } - if (m.type === "requestTerminalContext") { - if (!m.sessionID || this.terminalManager.prepareContext(m.sessionID)) return msg + const ready = this.terminalManager.prepareContext(m.sessionID, m.agentManagerContext) + if (ready) return msg this.panel?.postMessage({ type: "terminalContextError", requestId: m.requestId, diff --git a/packages/kilo-vscode/src/agent-manager/SessionTerminalManager.ts b/packages/kilo-vscode/src/agent-manager/SessionTerminalManager.ts index 3fc41c11708..b87db85bc8b 100644 --- a/packages/kilo-vscode/src/agent-manager/SessionTerminalManager.ts +++ b/packages/kilo-vscode/src/agent-manager/SessionTerminalManager.ts @@ -180,7 +180,7 @@ export class SessionTerminalManager { /** * Show the terminal for a session if it already exists (used when switching sessions). * Returns true if the terminal was shown, false if no terminal exists for the session. - * Pass preserveFocus=true to keep focus on the current editor (default for session switching). + * Pass preserveFocus=true to keep focus on the current editor (the default). */ showExisting(sessionId: string, preserveFocus = true): boolean { return this.showExistingKey(SessionTerminalManager.sessionKey(sessionId), preserveFocus) @@ -211,10 +211,18 @@ export class SessionTerminalManager { return undefined } - prepareContext(sessionId: string): boolean { - if (this.showExisting(sessionId)) return true + prepareContext(sessionId?: string, context?: string): boolean { + const key = + context === undefined + ? undefined + : context === "local" + ? SessionTerminalManager.LOCAL_KEY + : SessionTerminalManager.worktreeKey(context) + if (sessionId && this.showExisting(sessionId, false)) return true + if (key && this.showExistingKey(key, false)) return true const active = this.activeKey() - return !active || active === SessionTerminalManager.sessionKey(sessionId) + if (active === undefined) return this.host.activeTerminal() !== undefined + return (sessionId !== undefined && active === SessionTerminalManager.sessionKey(sessionId)) || active === key } dispose(): void { diff --git a/packages/kilo-vscode/src/agent-manager/types.ts b/packages/kilo-vscode/src/agent-manager/types.ts index edfa7666f68..c4d78c35f39 100644 --- a/packages/kilo-vscode/src/agent-manager/types.ts +++ b/packages/kilo-vscode/src/agent-manager/types.ts @@ -893,6 +893,7 @@ interface RequestTerminalContextIn { type: "requestTerminalContext" requestId: string sessionID?: string + agentManagerContext?: string } interface ClearSessionIn { diff --git a/packages/kilo-vscode/src/kilo-provider/agent-requirements-controller.ts b/packages/kilo-vscode/src/kilo-provider/agent-requirements-controller.ts deleted file mode 100644 index f8277995228..00000000000 --- a/packages/kilo-vscode/src/kilo-provider/agent-requirements-controller.ts +++ /dev/null @@ -1,198 +0,0 @@ -import type { KiloClient } from "@kilocode/sdk/v2/client" -import { - applyVSCodeExtensionRequirements, - requirementDirectory, - requirementKey, - type BackendAgentRequirementResult, - type HostAgentRequirementResult, -} from "./agent-requirements" - -type AgentRequirementsClient = { - agentRequirements: ( - parameters: { agent: string; directory: string }, - options: { throwOnError: true }, - ) => Promise<{ data: BackendAgentRequirementResult }> -} - -type LoadedMessage = { - type: "agentRequirementsLoaded" - result: HostAgentRequirementResult -} - -type InvalidatedMessage = { - type: "agentRequirementsInvalidated" -} - -type Disposable = { - dispose(): void -} - -export type AgentRequirementsRequest = { - agent: string - directory: string - sessionID?: string - force?: boolean -} - -export type AgentRequirementsControllerOptions = { - post: (message: LoadedMessage | InvalidatedMessage) => void - client: () => KiloClient | null - connected: () => boolean - generation: () => number - root: () => string - folders: () => readonly string[] | undefined - project: () => string | null | undefined - sessions: () => ReadonlyMap - worktrees?: () => readonly string[] - extension: (id: string) => unknown - subscribe?: (listener: () => void) => Disposable - error: (error: unknown) => string -} - -export class AgentRequirementsController { - private readonly cache = new Map() - private readonly generations = new Map() - private readonly subscription: Disposable | undefined - - constructor(private readonly opts: AgentRequirementsControllerOptions) { - this.subscription = opts.subscribe?.(() => this.clear()) - } - - clear(): void { - const active = this.cache.size > 0 || this.generations.size > 0 - this.cache.clear() - this.generations.clear() - if (!active) return - this.opts.post({ type: "agentRequirementsInvalidated" }) - } - - dispose(): void { - this.subscription?.dispose() - this.cache.clear() - this.generations.clear() - } - - fetch(request: AgentRequirementsRequest): Promise { - const dir = this.scope(request.directory, request.sessionID) - if (!dir) { - this.error(request.agent, request.directory, "scope_mismatch", "The agent requirement scope is no longer active") - return Promise.resolve() - } - - return this.load(request.agent, dir, request.force === true).then( - (result) => { - if (!this.scope(dir, request.sessionID)) return - this.opts.post({ type: "agentRequirementsLoaded", result }) - }, - (error) => { - this.error(request.agent, dir, "request_failed", error) - }, - ) - } - - private scope(requested: string, sessionID?: string): string | undefined { - return requirementDirectory({ - requested, - sessionID, - workspaceDirectory: this.opts.root(), - workspaceDirectories: this.opts.folders(), - projectDirectory: this.opts.project(), - sessionDirectories: this.opts.sessions(), - worktreeDirectories: this.opts.worktrees, - }) - } - - private apply(result: BackendAgentRequirementResult, directory: string): HostAgentRequirementResult { - return applyVSCodeExtensionRequirements({ ...result, directory }, (id) => this.opts.extension(id)) - } - - private error(agent: string, directory: string, code: "scope_mismatch" | "request_failed", error: unknown): void { - this.opts.post({ - type: "agentRequirementsLoaded", - result: { - agent, - directory, - enabled: true, - state: "error", - skills: [], - mcps: [], - vscode_extensions: [], - error: { - code, - message: this.opts.error(error) || "Failed to check agent requirements", - }, - }, - }) - } - - async assertAgentRequirements(agent: string | undefined, directory: string): Promise { - if (!agent) return - - const dir = this.scope(directory) - if (!dir) throw new Error("The agent requirement scope is no longer active") - - const result = await this.load(agent, dir) - if (!this.blocked(result)) return - - this.opts.post({ type: "agentRequirementsLoaded", result }) - throw new Error(this.message(result)) - } - - private async load(agent: string, directory: string, force = false): Promise { - const key = requirementKey(agent, directory) - if (!force) { - const cached = this.cache.get(key) - if (cached) return cached - } - - const client = this.opts.client() - if (!client || !this.opts.connected()) throw new Error("Not connected to CLI backend") - - const connection = this.opts.generation() - const token = {} - this.generations.set(key, token) - - const endpoint = client.kilocode as typeof client.kilocode & AgentRequirementsClient - const response = await endpoint.agentRequirements({ agent, directory }, { throwOnError: true }).catch((error) => { - if (this.generations.get(key) === token) this.generations.delete(key) - throw error - }) - - if (this.opts.generation() !== connection || this.opts.client() !== client) { - if (this.generations.get(key) === token) this.generations.delete(key) - throw new Error("Connection changed while checking agent requirements") - } - if (this.generations.get(key) !== token) throw new Error("Agent requirement check was superseded") - - const result = this.apply(response.data, directory) - this.cache.set(key, result) - this.generations.delete(key) - return result - } - - private blocked(result: HostAgentRequirementResult): boolean { - if (!result.enabled || result.state === "disabled") return false - if (result.state === "blocked" || result.state === "error") return true - - return ( - result.skills.some((item) => item.status !== "ready") || - result.mcps.some((item) => item.status !== "ready") || - result.vscode_extensions.some((item) => item.status !== "ready") - ) - } - - private message(result: HostAgentRequirementResult): string { - if (result.error?.message) return result.error.message - - const missing = [ - ...result.skills.filter((item) => item.status !== "ready").map((item) => `skill ${item.name}`), - ...result.mcps.filter((item) => item.status !== "ready").map((item) => `MCP ${item.name}`), - ...result.vscode_extensions - .filter((item) => item.status !== "ready") - .map((item) => `VS Code extension ${item.name}`), - ] - - if (missing.length) return `Agent requirements are not met: ${missing.join(", ")}` - return "Agent requirements are not met" - } -} diff --git a/packages/kilo-vscode/src/kilo-provider/agent-requirements.ts b/packages/kilo-vscode/src/kilo-provider/agent-requirements.ts deleted file mode 100644 index 43e71d4b6aa..00000000000 --- a/packages/kilo-vscode/src/kilo-provider/agent-requirements.ts +++ /dev/null @@ -1,103 +0,0 @@ -import * as path from "path" -import { sameDirectory } from "../kilo-provider-utils" - -export type RequirementStatus = "ready" | "missing" | "error" - -export type RequirementState = "disabled" | "ready" | "blocked" | "error" - -export type RequirementErrorCode = - | "unknown_agent" - | "malformed_declaration" - | "discovery_failed" - | "mcp_status_failed" - | "scope_mismatch" - | "request_failed" - -export type RequirementItem = { - name: string - status: RequirementStatus - message?: string -} - -export type BackendVSCodeExtensionRequirement = { - name: string - id: string - message?: string -} - -export type BackendAgentRequirementResult = { - agent: string - directory: string - enabled: boolean - state: RequirementState - skills: RequirementItem[] - mcps: RequirementItem[] - vscode_extensions: BackendVSCodeExtensionRequirement[] - error?: { - code: RequirementErrorCode - message: string - } -} - -export type HostVSCodeExtensionRequirement = BackendVSCodeExtensionRequirement & { - status: RequirementStatus -} - -export type HostAgentRequirementResult = Omit & { - vscode_extensions: HostVSCodeExtensionRequirement[] -} - -export type RequirementDirectoryInput = { - requested: string - sessionID?: string - workspaceDirectory: string - workspaceDirectories?: readonly string[] - projectDirectory?: string | null - sessionDirectories: ReadonlyMap - worktreeDirectories?: () => readonly string[] -} - -export type VSCodeExtensionLookup = (id: string) => unknown - -function normalize(directory: string): string { - if (!directory) return "" - const resolved = path.resolve(directory) - return process.platform === "win32" ? resolved.toLowerCase() : resolved -} - -export function requirementKey(agent: string, directory: string): string { - return `${normalize(directory)}\0${agent}` -} - -export function requirementDirectory(input: RequirementDirectoryInput): string | undefined { - if (!input.requested) return undefined - - const dirs = [ - input.sessionID ? input.sessionDirectories.get(input.sessionID) : undefined, - input.workspaceDirectory, - ...(input.workspaceDirectories ?? []), - input.projectDirectory ?? undefined, - ...input.sessionDirectories.values(), - ...(input.worktreeDirectories?.() ?? []), - ].filter((dir): dir is string => !!dir) - - return dirs.find((dir) => sameDirectory(dir, input.requested)) -} - -export function applyVSCodeExtensionRequirements( - result: BackendAgentRequirementResult, - lookup: VSCodeExtensionLookup, -): HostAgentRequirementResult { - const extensions = result.vscode_extensions.map((extension) => { - const status: RequirementStatus = lookup(extension.id) ? "ready" : "missing" - return { ...extension, status } - }) - const blocked = - result.enabled && result.state === "ready" && extensions.some((extension) => extension.status !== "ready") - - return { - ...result, - state: blocked ? "blocked" : result.state, - vscode_extensions: extensions, - } -} diff --git a/packages/kilo-vscode/src/services/marketplace/types.ts b/packages/kilo-vscode/src/services/marketplace/types.ts index f7bf682ed20..3e380e50544 100644 --- a/packages/kilo-vscode/src/services/marketplace/types.ts +++ b/packages/kilo-vscode/src/services/marketplace/types.ts @@ -41,11 +41,6 @@ export interface AgentContent { prompt: string options?: Record permission?: Record - requirements?: { - skills?: string[] - mcps?: string[] - vscode_extensions?: Array<{ name: string; id: string }> - } } export interface AgentMarketplaceItem extends MarketplaceItemBase { 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 84c63ad8d3b..d3cfd234713 100644 --- a/packages/kilo-vscode/tests/unit/agent-manager-arch.test.ts +++ b/packages/kilo-vscode/tests/unit/agent-manager-arch.test.ts @@ -527,7 +527,7 @@ describe("Agent Manager Provider — onMessage routing", () => { it("terminal context reveals the terminal associated with the originating session", () => { const text = body("onSessionMessage") - const show = text.indexOf("this.terminalManager.prepareContext(m.sessionID)") + const show = text.indexOf("this.terminalManager.prepareContext(m.sessionID, m.agentManagerContext)") expect(show).toBeGreaterThan(-1) expect(text).toContain('type: "terminalContextError"') }) @@ -1113,7 +1113,6 @@ describe("Shared webview provider shell", () => { "ImageModelsProvider", "NotificationsProvider", "SessionProvider", - "AgentRequirementsProvider", "MemoryProvider", "FeedbackProvider", ]) diff --git a/packages/kilo-vscode/tests/unit/agent-manager-terminal-output.test.ts b/packages/kilo-vscode/tests/unit/agent-manager-terminal-output.test.ts new file mode 100644 index 00000000000..edc607d48f4 --- /dev/null +++ b/packages/kilo-vscode/tests/unit/agent-manager-terminal-output.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from "bun:test" +import { + readTerminalOutput, + registerTerminalOutput, + unregisterTerminalOutput, +} from "../../webview-ui/agent-manager/terminal/output" + +describe("Agent Manager terminal output", () => { + it("reads and unregisters a terminal buffer", () => { + registerTerminalOutput("term-1", () => "embedded output") + expect(readTerminalOutput("term-1")).toBe("embedded output") + unregisterTerminalOutput("term-1") + expect(readTerminalOutput("term-1")).toBeUndefined() + }) + + it("truncates large terminal buffers", () => { + registerTerminalOutput("term-2", () => Array.from({ length: 501 }, (_, index) => `line-${index}`).join("\n")) + const output = readTerminalOutput("term-2") + expect(output).toContain("[...1 lines omitted...]") + expect(output).toContain("line-0") + expect(output).toContain("line-500") + unregisterTerminalOutput("term-2") + }) +}) diff --git a/packages/kilo-vscode/tests/unit/agent-requirements.test.ts b/packages/kilo-vscode/tests/unit/agent-requirements.test.ts deleted file mode 100644 index 26290cff011..00000000000 --- a/packages/kilo-vscode/tests/unit/agent-requirements.test.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { describe, expect, it } from "bun:test" -import type { KiloClient } from "@kilocode/sdk/v2/client" -import { - applyVSCodeExtensionRequirements, - requirementDirectory, - requirementKey, - type BackendAgentRequirementResult, - type HostAgentRequirementResult, -} from "../../src/kilo-provider/agent-requirements" -import { AgentRequirementsController } from "../../src/kilo-provider/agent-requirements-controller" -import { keepAgentRequirementsResult } from "../../webview-ui/src/context/agent-requirements-state" - -const root = "/repo" - -function result(input: Partial = {}): BackendAgentRequirementResult { - return { - agent: "demo", - directory: root, - enabled: true, - state: "ready", - skills: [], - mcps: [], - vscode_extensions: [], - ...input, - } -} - -function client(value: BackendAgentRequirementResult | (() => BackendAgentRequirementResult)) { - const calls: Array<{ agent: string; directory: string }> = [] - const api = { - kilocode: { - agentRequirements: async (parameters: { agent: string; directory: string }) => { - calls.push(parameters) - return { data: typeof value === "function" ? value() : value } - }, - }, - } as unknown as KiloClient - return { calls, api } -} - -function controller( - input: { - api?: KiloClient | null - posts?: unknown[] - sessions?: ReadonlyMap - worktrees?: () => readonly string[] - extensions?: ReadonlySet - subscribe?: (listener: () => void) => { dispose(): void } - } = {}, -) { - const posts = input.posts ?? [] - return new AgentRequirementsController({ - post: (message) => posts.push(message), - client: () => input.api ?? null, - connected: () => true, - generation: () => 1, - root: () => root, - folders: () => [root, "/workspace"], - project: () => root, - sessions: () => input.sessions ?? new Map(), - worktrees: input.worktrees, - extension: (id) => input.extensions?.has(id), - subscribe: input.subscribe, - error: (error) => (error instanceof Error ? error.message : String(error)), - }) -} - -describe("agent requirement helpers", () => { - it("builds stable cache keys from normalized directories", () => { - expect(requirementKey("demo", "/repo/./subdir")).toBe(requirementKey("demo", "/repo/subdir")) - expect(requirementKey("other", "/repo/subdir")).not.toBe(requirementKey("demo", "/repo/subdir")) - }) - - it("scopes requests to active workspace, session, and worktree directories", () => { - const sessions = new Map([["session-1", "/repo/.kilo/worktrees/one"]]) - const base = { - workspaceDirectory: root, - workspaceDirectories: ["/workspace"], - projectDirectory: root, - sessionDirectories: sessions, - worktreeDirectories: () => ["/repo/.kilo/worktrees/two"], - } - - expect(requirementDirectory({ ...base, requested: "/repo" })).toBe(root) - expect(requirementDirectory({ ...base, requested: "/repo/.kilo/worktrees/one", sessionID: "session-1" })).toBe( - "/repo/.kilo/worktrees/one", - ) - expect(requirementDirectory({ ...base, requested: "/repo/.kilo/worktrees/two" })).toBe("/repo/.kilo/worktrees/two") - expect(requirementDirectory({ ...base, requested: "/other" })).toBeUndefined() - }) - - it("adds VS Code extension statuses and blocks ready backend results when extensions are missing", () => { - const checked = applyVSCodeExtensionRequirements( - result({ - vscode_extensions: [ - { name: "Ready Extension", id: "publisher.ready" }, - { name: "Missing Extension", id: "publisher.missing" }, - ], - }), - (id) => id === "publisher.ready", - ) - - expect(checked.state).toBe("blocked") - expect(checked.vscode_extensions).toEqual([ - { name: "Ready Extension", id: "publisher.ready", status: "ready" }, - { name: "Missing Extension", id: "publisher.missing", status: "missing" }, - ]) - }) -}) - -describe("agent requirement webview state", () => { - const blocked: HostAgentRequirementResult = { - ...result({ state: "blocked", skills: [{ name: "skill", status: "missing" }] }), - vscode_extensions: [], - } - - it("preserves ready, blocked, and error results only for the same agent and directory", () => { - expect(keepAgentRequirementsResult(blocked, "demo", root)).toBe(true) - expect(keepAgentRequirementsResult({ ...blocked, state: "error" }, "demo", root)).toBe(true) - expect(keepAgentRequirementsResult({ ...blocked, state: "ready" }, "demo", root)).toBe(true) - expect(keepAgentRequirementsResult({ ...blocked, state: "disabled" }, "demo", root)).toBe(false) - expect(keepAgentRequirementsResult(blocked, "other", root)).toBe(false) - expect(keepAgentRequirementsResult(blocked, "demo", "/other")).toBe(false) - }) -}) - -describe("AgentRequirementsController", () => { - it("caches fetched results until invalidated", async () => { - const posts: unknown[] = [] - const backend = client(result()) - const requirements = controller({ api: backend.api, posts }) - - await requirements.fetch({ agent: "demo", directory: root }) - await requirements.fetch({ agent: "demo", directory: root }) - requirements.clear() - await requirements.fetch({ agent: "demo", directory: root }) - - expect(backend.calls).toEqual([ - { agent: "demo", directory: root }, - { agent: "demo", directory: root }, - ]) - expect( - posts.filter((message) => (message as { type?: string }).type === "agentRequirementsInvalidated"), - ).toHaveLength(1) - }) - - it("posts scope mismatch errors for inactive directories", async () => { - const posts: unknown[] = [] - const backend = client(result()) - const requirements = controller({ api: backend.api, posts }) - - await requirements.fetch({ agent: "demo", directory: "/other" }) - - expect(backend.calls).toEqual([]) - expect(posts.at(-1)).toMatchObject({ - type: "agentRequirementsLoaded", - result: { state: "error", error: { code: "scope_mismatch" } }, - }) - }) - - it("clears requirements when the extension subscription fires", async () => { - const posts: unknown[] = [] - let listener: (() => void) | undefined - let disposed = false - const backend = client(result()) - const requirements = controller({ - api: backend.api, - posts, - subscribe: (fn) => { - listener = fn - return { dispose: () => void (disposed = true) } - }, - }) - - await requirements.fetch({ agent: "demo", directory: root }) - posts.length = 0 - listener?.() - requirements.dispose() - - expect(posts).toEqual([{ type: "agentRequirementsInvalidated" }]) - expect(disposed).toBe(true) - }) - - it("asserts and reports blocked requirements before host sends", async () => { - const posts: unknown[] = [] - const backend = client( - result({ - vscode_extensions: [{ name: "Missing Extension", id: "publisher.missing" }], - }), - ) - const requirements = controller({ api: backend.api, posts }) - - await expect(requirements.assertAgentRequirements("demo", root)).rejects.toThrow( - "VS Code extension Missing Extension", - ) - expect(posts.at(-1)).toMatchObject({ - type: "agentRequirementsLoaded", - result: { state: "blocked", vscode_extensions: [{ status: "missing" }] }, - }) - }) -}) diff --git a/packages/kilo-vscode/tests/unit/marketplace-installer.test.ts b/packages/kilo-vscode/tests/unit/marketplace-installer.test.ts index 37262e11533..ecc55493606 100644 --- a/packages/kilo-vscode/tests/unit/marketplace-installer.test.ts +++ b/packages/kilo-vscode/tests/unit/marketplace-installer.test.ts @@ -270,17 +270,12 @@ describe("MarketplaceInstaller skills", () => { }) describe("MarketplaceInstaller agents", () => { - it("preserves requirements in installed agent frontmatter", async () => { + it("preserves agent metadata in installed frontmatter", async () => { const installer = new MarketplaceInstaller(new TestPaths()) const item = agent({ mode: "all", description: "Requires local setup", prompt: "Use the available project tools.", - requirements: { - skills: ["project-skill"], - mcps: ["project-mcp"], - vscode_extensions: [{ name: "Project Helper", id: "publisher.project-helper" }], - }, }) const result = await installer.installAgent(item, "project", tmpDir) @@ -289,6 +284,6 @@ describe("MarketplaceInstaller agents", () => { expect(result.filePath).toBeDefined() if (!result.filePath) throw new Error("agent install did not return a file path") const data = await frontmatter(result.filePath) - expect(data.requirements).toEqual(item.content.requirements) + expect(data.description).toBe(item.content.description) }) }) diff --git a/packages/kilo-vscode/tests/unit/prompt-send-contract.test.ts b/packages/kilo-vscode/tests/unit/prompt-send-contract.test.ts index 67ddbe6a773..88ba398590b 100644 --- a/packages/kilo-vscode/tests/unit/prompt-send-contract.test.ts +++ b/packages/kilo-vscode/tests/unit/prompt-send-contract.test.ts @@ -358,10 +358,10 @@ describe("PromptInput send origin contract", () => { it("captures the real or pending tab before asynchronous attachment resolution", () => { expect(source).toMatch(/const origin = session\.currentSessionID\(\)[\s\S]*const id = origin \?\? pendingId/) - expect(source.indexOf("beginPendingSend(pendingId)")).toBeLessThan( - source.indexOf("await terminal.resolveAttachment"), + expect(source.indexOf("beginPending(pendingId)")).toBeLessThan( + source.indexOf("const terminalFile = await terminal"), ) - expect(source).toMatch(/await terminal\.resolveAttachment\(message, id\)/) + expect(source).toMatch(/resolveAttachment\(message, id, readTerminalContext\(props\.terminalContext\)\)/) expect(source).toMatch(/await git\.resolveAttachment\(message, id, context\)/) }) diff --git a/packages/kilo-vscode/tests/unit/session-terminal-manager.test.ts b/packages/kilo-vscode/tests/unit/session-terminal-manager.test.ts index 5669acaeac4..2eed4d6f045 100644 --- a/packages/kilo-vscode/tests/unit/session-terminal-manager.test.ts +++ b/packages/kilo-vscode/tests/unit/session-terminal-manager.test.ts @@ -139,10 +139,31 @@ describe("SessionTerminalManager structure", () => { it("rejects context capture from another managed session", () => { const text = body("prepareContext") - expect(text).toContain("this.showExisting(sessionId)") + expect(text).toContain("this.showExisting(sessionId, false)") expect(text).toContain("this.activeKey()") expect(text).toContain("SessionTerminalManager.sessionKey(sessionId)") }) + + it("allows a focused legacy Run terminal when no managed terminal exists", () => { + const active = {} + const host: TerminalHost = { + createTerminal() { + throw new Error("not used") + }, + activeTerminal: () => active, + repoPath: () => undefined, + showWarning() {}, + setContext() {}, + onTerminalClosed: () => ({ dispose() {} }), + onActiveTerminalChanged: () => ({ dispose() {} }), + registerCommand: () => ({ dispose() {} }), + executeCommand: () => Promise.resolve(), + } + const manager = new SessionTerminalManager(() => {}, host) + + expect(manager.prepareContext("session-1", "local")).toBe(true) + manager.dispose() + }) }) describe("SessionTerminalManager command restoration", () => { diff --git a/packages/kilo-vscode/tests/unit/terminal-architecture.test.ts b/packages/kilo-vscode/tests/unit/terminal-architecture.test.ts index b7f760b843a..a8ddfb478e9 100644 --- a/packages/kilo-vscode/tests/unit/terminal-architecture.test.ts +++ b/packages/kilo-vscode/tests/unit/terminal-architecture.test.ts @@ -22,19 +22,25 @@ describe("terminal context architecture", () => { const util = src("webview-ui/src/hooks/terminal-context-utils.ts") expect(prompt).toContain("useTerminalContext") + expect(prompt).toContain("resolveAttachment(message, id, readTerminalContext(props.terminalContext))") expect(prompt).not.toContain("requestTerminalContext") expect(prompt).not.toContain("data:text/plain") expect(hook).toContain("requestTerminalContext") + expect(hook).toContain("useVSCode()") expect(util).toContain("data:text/plain") }) it("keeps terminal output limits in the shared truncation helper", () => { const helper = src("src/services/terminal/truncate.ts") + const output = src("webview-ui/agent-manager/terminal/output.ts") const provider = src("src/KiloProvider.ts") const prompt = src("webview-ui/src/components/chat/PromptInput.tsx") expect(helper).toContain("TERMINAL_OUTPUT_LINE_LIMIT = 500") expect(helper).toContain("TERMINAL_OUTPUT_CHARACTER_LIMIT = 50_000") + expect(output).toContain('from "../../../src/services/terminal/truncate"') + expect(output).not.toContain("LINE_LIMIT = 500") + expect(output).not.toContain("CHAR_LIMIT = 50_000") expect(provider).not.toContain("TERMINAL_OUTPUT_LINE_LIMIT") expect(prompt).not.toContain("TERMINAL_OUTPUT_LINE_LIMIT") }) diff --git a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx index 10e72057ade..d2a63188d2e 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx @@ -72,7 +72,6 @@ import { NotificationsProvider } from "../src/context/notifications" import { FeedbackProvider } from "../src/context/feedback" import { MemoryProvider } from "../src/context/memory" import { SessionProvider, useSession } from "../src/context/session" -import { AgentRequirementsProvider } from "../src/context/agent-requirements" import { WorktreeModeProvider } from "../src/context/worktree-mode" import { ProviderShell } from "../src/context/provider-shell" import { ChatView } from "../src/components/chat" @@ -142,6 +141,7 @@ import { resolveRunScriptRequest, resolveVscodeTerminalRequest, } from "./terminal" +import { readTerminalOutput } from "./terminal/output" import { focusCurrentTab, renderTab, renderTerminalLayer, renderNewTabButton } from "./tab-rendering" import { useTabScroll } from "./tab-scroll" import { DiffPanel } from "./DiffPanel" @@ -372,6 +372,21 @@ const AgentManagerContent: Component = () => { const sel = selection() return sel === null ? null : nsKey(sel) }) + const resolveEmbeddedTerminal = async (context?: string) => { + const key = nsKey(context ?? LOCAL) + const side = terms.sidesForContext(key) + const tabs = terms.forSelection(key) + const focused = terms.focusedId() + const focusedTerm = side.find((term) => term.id === focused) ?? tabs.find((term) => term.id === focused) + const sideTerm = side.find((term) => term.id === terms.sideActiveFor(key)) + const tab = tabs.find((term) => term.id === terms.activeId()) + const id = focusedTerm?.id ?? sideTerm?.id + const target = id ?? tab?.id + if (!target) return undefined + const term = side.find((item) => item.id === target) ?? tabs.find((item) => item.id === target) + if (!term) return undefined + return readTerminalOutput(term.id) + } const requestChatFocus = createChatFocus({ term: () => terms.activeId(), history, @@ -2572,10 +2587,12 @@ const AgentManagerContent: Component = () => { readonly={readOnly()} continueInWorktree={selection() === LOCAL} promptBoxId={`agent-manager:${selection() ?? "unassigned"}`} + terminalContext={() => selection() ?? undefined} deferFocusToQuestion={hasQuestionOption} pendingSessionID={selection() === LOCAL ? activePendingId() : undefined} focusOnDraftChange={focusOnDraftChange} onFocusChange={rememberPromptFocus} + resolveEmbeddedTerminal={resolveEmbeddedTerminal} />
@@ -2765,7 +2782,6 @@ const AgentManagerContent: Component = () => {
) } - export const AgentManagerApp: Component = () => { return ( diff --git a/packages/kilo-vscode/webview-ui/agent-manager/terminal/TerminalTab.tsx b/packages/kilo-vscode/webview-ui/agent-manager/terminal/TerminalTab.tsx index bdf6ae8318b..3f125589043 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/terminal/TerminalTab.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/terminal/TerminalTab.tsx @@ -22,6 +22,7 @@ import { useLanguage } from "../../src/context/language" import { formatReviewCommentsMarkdown } from "../../src/utils/review-comment-markdown" import type { ScriptTerminalStatus, TerminalFont } from "./state" import { createInputBuffer, createReplayGate } from "./replay" +import { registerTerminalOutput, unregisterTerminalOutput } from "./output" interface Props { terminalId: string @@ -167,6 +168,13 @@ export const TerminalTab: Component = (props) => { const fit = new FitAddon() term.loadAddon(fit) term.open(host) + registerTerminalOutput(props.terminalId, () => { + const buffer = term.buffer.active + return Array.from( + { length: buffer.length }, + (_, index) => buffer.getLine(index)?.translateToString(true) ?? "", + ).join("\n") + }) // Unicode width must be configured before the first PTY bytes are parsed. // Loading it later can leave already-wrapped graphemes with stale cell // widths, which moves the cursor in narrow terminals. @@ -581,6 +589,7 @@ export const TerminalTab: Component = (props) => { onCleanup(() => { closed = true + unregisterTerminalOutput(props.terminalId) if (pendingFrame !== null) cancelAnimationFrame(pendingFrame) if (frame !== undefined) cancelAnimationFrame(frame) if (deferred !== undefined) cancelAnimationFrame(deferred) diff --git a/packages/kilo-vscode/webview-ui/agent-manager/terminal/output.ts b/packages/kilo-vscode/webview-ui/agent-manager/terminal/output.ts new file mode 100644 index 00000000000..411b08ff914 --- /dev/null +++ b/packages/kilo-vscode/webview-ui/agent-manager/terminal/output.ts @@ -0,0 +1,19 @@ +import { truncateTerminalOutput } from "../../../src/services/terminal/truncate" + +type Reader = () => string + +const readers = new Map() + +export function registerTerminalOutput(id: string, read: Reader): void { + readers.set(id, read) +} + +export function unregisterTerminalOutput(id: string): void { + readers.delete(id) +} + +export function readTerminalOutput(id: string): string | undefined { + const content = readers.get(id)?.() + if (content === undefined) return undefined + return truncateTerminalOutput(content).content +} diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/AgentRequirements.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/AgentRequirements.tsx deleted file mode 100644 index 1238718b4d0..00000000000 --- a/packages/kilo-vscode/webview-ui/src/components/chat/AgentRequirements.tsx +++ /dev/null @@ -1,193 +0,0 @@ -/** @jsxImportSource solid-js */ - -import { For, Show, type Component } from "solid-js" -import { Button } from "@kilocode/kilo-ui/button" -import { Card } from "@kilocode/kilo-ui/card" -import { Icon } from "@kilocode/kilo-ui/icon" -import { useAgentRequirements } from "../../context/agent-requirements" -import { useLanguage } from "../../context/language" -import { useVSCode } from "../../context/vscode" -import type { AgentRequirementMCP, AgentRequirementSkill, AgentRequirementVSCodeExtension } from "../../types/messages" - -type Status = "ready" | "missing" | "error" - -export const AgentRequirements: Component = () => { - const requirements = useAgentRequirements() - const language = useLanguage() - const vscode = useVSCode() - const result = requirements.result - const skills = () => result()?.skills ?? [] - const mcps = () => result()?.mcps ?? [] - const extensions = () => result()?.vscode_extensions ?? [] - const total = () => skills().length + mcps().length + extensions().length - const marketplace = () => - skills().some((item) => item.status !== "ready") || mcps().some((item) => item.status !== "ready") - const tools = () => { - if (skills().length && mcps().length) { - return `${language.t("agentRequirements.group.skills")} / ${language.t("agentRequirements.group.mcps")}` - } - if (skills().length) return language.t("agentRequirements.group.skills") - return language.t("agentRequirements.group.mcps") - } - const open = () => { - const current = result() - if (!current) return - vscode.postMessage({ type: "openMarketplacePanel", directory: current.directory }) - } - const title = () => - (result()?.agent ?? "") - .split(/[-_]/) - .filter(Boolean) - .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) - .join(" ") - - const error = () => { - const err = result()?.error - if (!err) return undefined - if (err.code === "unknown_agent") return language.t("agentRequirements.error.unknownAgent") - if (err.code === "malformed_declaration") return language.t("agentRequirements.error.malformedDeclaration") - if (err.code === "discovery_failed") return language.t("agentRequirements.error.discoveryFailed") - if (err.code === "mcp_status_failed") return language.t("agentRequirements.error.mcpStatusFailed") - if (err.code === "scope_mismatch") return language.t("agentRequirements.error.scopeMismatch") - return err.message || language.t("agentRequirements.error.requestFailed") - } - - const skill = (item: AgentRequirementSkill) => { - if (item.message) return item.message - if (item.status === "ready") return language.t("agentRequirements.skill.installed") - if (item.status === "error") return language.t("agentRequirements.skill.checkFailed") - return language.t("agentRequirements.skill.missing") - } - - const mcp = (item: AgentRequirementMCP) => { - if (item.message) return item.message - if (item.status === "ready") return language.t("agentRequirements.mcp.connected") - if (item.status === "error") return language.t("agentRequirements.mcp.checkFailed") - return language.t("agentRequirements.mcp.missing") - } - - const extension = (item: AgentRequirementVSCodeExtension) => { - if (item.message) return item.message - if (item.status === "ready") return language.t("agentRequirements.extension.installed") - if (item.status === "error") return language.t("agentRequirements.extension.checkFailed") - return language.t("agentRequirements.extension.missing") - } - - const StatusIcon = (props: { status: Status }) => ( - - ) - - return ( -
- -
-

- {language.t("agentRequirements.blocked.title", { agent: title() })} -

-

{language.t("agentRequirements.blocked.description")}

-
- - - {(message) =>
{message}
} -
- - -
- -
-

{tools()}

-
- -
-

{language.t("agentRequirements.group.skills")}

-
    - - {(item) => ( -
  • - -
    - {item.name} - {skill(item)} -
    -
  • - )} -
    -
-
-
- -
-

{language.t("agentRequirements.group.mcps")}

-
    - - {(item) => ( -
  • - -
    - {item.name} - {mcp(item)} -
    -
  • - )} -
    -
-
-
- -
- -
-
-
-
-
- - -
-
-

- {language.t("agentRequirements.group.extensions")} -

-

- {language.t("agentRequirements.extension.description")} -

-
-
-
-
    - - {(item) => ( -
  • - -
    - - {item.name} ({item.id}) - - {extension(item)} -
    -
  • - )} -
    -
-
-
-
-
-
-
-
-
- ) -} diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/ChatView.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/ChatView.tsx index 2d01055f04f..33e00a0306d 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/ChatView.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/ChatView.tsx @@ -14,7 +14,6 @@ import { showToast } from "@kilocode/kilo-ui/toast" import { DropdownMenu } from "@kilocode/kilo-ui/dropdown-menu" import { TaskHeader } from "./TaskHeader" import { MessageList } from "./MessageList" -import { AgentRequirements } from "./AgentRequirements" import { PromptInput } from "./PromptInput" import { PermissionDock } from "./PermissionDock" import { StartupErrorBanner } from "./StartupErrorBanner" @@ -25,7 +24,6 @@ import { useVSCode } from "../../context/vscode" import { useLanguage } from "../../context/language" import { useWorktreeMode } from "../../context/worktree-mode" import { useServer } from "../../context/server" -import { useAgentRequirements } from "../../context/agent-requirements" import { TranscriptSearchProvider } from "../../context/transcript-search" import { isPromptBlocked, isSuggesting, isQuestioning } from "./prompt-input-utils" import { showTabStrip } from "../../utils/local-tabs" @@ -39,11 +37,13 @@ interface ChatViewProps { /** When true, show the "Continue in Worktree" button. Defaults to true in the sidebar. */ continueInWorktree?: boolean promptBoxId?: string + terminalContext?: () => string | undefined deferFocusToQuestion?: () => boolean pendingSessionID?: string focusOnDraftChange?: () => boolean onFocusChange?: (focused: boolean) => void emptyState?: () => JSX.Element + resolveEmbeddedTerminal?: (context?: string) => Promise } export const ChatView: Component = (props) => { @@ -53,7 +53,6 @@ export const ChatView: Component = (props) => { const worktreeMode = useWorktreeMode() const server = useServer() const tabs = useLocalTabs() - const requirements = useAgentRequirements() // Show "Show Changes" only in the standalone sidebar, not inside Agent Manager const isSidebar = () => worktreeMode === undefined const pendingSessionID = () => props.pendingSessionID ?? tabs?.pending() @@ -83,11 +82,9 @@ export const ChatView: Component = (props) => { const standaloneQuestions = createMemo(() => familyQuestions().filter((q) => !q.tool)) const standaloneSuggestions = createMemo(() => familySuggestions().filter((s) => !s.tool)) const permissionRequest = () => familyPermissions().find((p) => p.sessionID === id()) ?? familyPermissions()[0] - // Questions and suggestions do not block input; permissions and agent requirements do. + // Questions and suggestions do not block input; permissions do. // Pending questions and suggestions are auto-dismissed in sendMessage/sendCommand. - const blocked = () => isPromptBlocked(familyPermissions().length) || (!props.readonly && requirements.blocked()) - const requirementReason = () => - !props.readonly && requirements.blocked() ? language.t("agentRequirements.prompt.blocked") : undefined + const blocked = () => isPromptBlocked(familyPermissions().length) // Session is busy only because a suggestion tool call is pending — prompt should behave as idle const suggesting = () => isSuggesting(blocked(), familySuggestions().length) // Session is busy only because a question tool call is pending — prompt should behave as idle @@ -342,24 +339,17 @@ export const ChatView: Component = (props) => {
- - } - > - - +
@@ -383,14 +373,15 @@ export const ChatView: Component = (props) => { diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx index 5bb00170cf4..01d66f8aa89 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx @@ -105,9 +105,12 @@ function beginPending(id: string | undefined) { if (id) beginPendingSend(id) } +function readTerminalContext(read: (() => string | undefined) | undefined): string | undefined { + return read?.() +} + interface PromptInputProps { blocked?: () => boolean - blockedReason?: () => string | undefined /** When true, session is busy only because a suggestion is pending — treat as idle for input */ suggesting?: () => boolean /** When true, session is busy only because a question is pending — treat as idle for input */ @@ -115,11 +118,13 @@ interface PromptInputProps { /** When true, defer prompt focus while switching to a pending question */ deferFocusToQuestion?: () => boolean boxId?: string + terminalContext?: () => string | undefined pendingSessionID?: string /** Agent Manager can suppress automatic prompt focus when this session last * used its side terminal instead. Other callers retain the old behavior. */ focusOnDraftChange?: () => boolean onFocusChange?: (focused: boolean) => void + resolveEmbeddedTerminal?: (context?: string) => Promise } function MentionItemContent(props: { item: MentionResult }) { @@ -189,7 +194,7 @@ export const PromptInput: Component = (props) => { } const hasGit = () => server.gitInstalled() const mention = useFileMention(vscode, sid, hasGit) - const terminal = useTerminalContext(vscode) + const terminal = useTerminalContext(props.resolveEmbeddedTerminal) const git = useGitChangesContext(vscode, ctx, hasGit) const imageAttach = useImageAttachments() imageAttach.setFilePathDropHandler((paths) => { @@ -536,8 +541,6 @@ export const PromptInput: Component = (props) => { !props.blocked?.() && (speech.state() === "recording" || (hasInput() && !speech.active())) const sendLabel = () => { - const reason = props.blockedReason?.() - if (reason) return reason if (props.blocked?.()) return language.t("prompt.action.send.blocked") if (speech.state() === "recording") return language.t("prompt.action.send.recording") return language.t("prompt.action.send") @@ -1214,10 +1217,12 @@ export const PromptInput: Component = (props) => { const context = ctx() const key = draftKey() - const terminalFile = await terminal.resolveAttachment(message, id).catch((err: Error) => { - showToast({ variant: "error", title: "Terminal context unavailable", description: err.message }) - return undefined - }) + const terminalFile = await terminal + .resolveAttachment(message, id, readTerminalContext(props.terminalContext)) + .catch((err: Error) => { + showToast({ variant: "error", title: "Terminal context unavailable", description: err.message }) + return undefined + }) if (hasTerminalMention(message) && !terminalFile) { finishPending(pendingId) return @@ -1495,19 +1500,11 @@ export const PromptInput: Component = (props) => { }} onScroll={syncHighlightScroll} aria-disabled={isDisabled()} - aria-describedby={props.blockedReason?.() ? blockedHelpId() : undefined} rows={1} dir="auto" /> - - {(reason) => ( - - {reason} - - )} -
@@ -1613,7 +1610,6 @@ export const PromptInput: Component = (props) => { size="small" onClick={handleSendClick} aria-disabled={!canSend()} - aria-describedby={props.blockedReason?.() ? blockedHelpId() : undefined} aria-label={sendLabel()} > diff --git a/packages/kilo-vscode/webview-ui/src/context/agent-requirements-state.ts b/packages/kilo-vscode/webview-ui/src/context/agent-requirements-state.ts deleted file mode 100644 index 5bbfc68eeb2..00000000000 --- a/packages/kilo-vscode/webview-ui/src/context/agent-requirements-state.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { AgentRequirementResult } from "../types/messages" - -export function keepAgentRequirementsResult( - value: AgentRequirementResult | undefined, - agent: string, - directory: string, -) { - if (!value || value.agent !== agent || value.directory !== directory) return false - return value.state === "ready" || value.state === "blocked" || value.state === "error" -} diff --git a/packages/kilo-vscode/webview-ui/src/context/agent-requirements.tsx b/packages/kilo-vscode/webview-ui/src/context/agent-requirements.tsx deleted file mode 100644 index d34e8e06d7e..00000000000 --- a/packages/kilo-vscode/webview-ui/src/context/agent-requirements.tsx +++ /dev/null @@ -1,104 +0,0 @@ -/** @jsxImportSource solid-js */ - -import { createContext, createEffect, createMemo, createSignal, onCleanup, useContext } from "solid-js" -import type { Accessor, ParentComponent } from "solid-js" -import { useConfig } from "./config" -import { useServer } from "./server" -import { useSession } from "./session" -import { useVSCode } from "./vscode" -import type { AgentRequirementResult } from "../types/messages" -import { keepAgentRequirementsResult } from "./agent-requirements-state" - -export interface AgentRequirementsContextValue { - result: Accessor - checking: Accessor - blocked: Accessor - visible: Accessor -} - -export const AgentRequirementsContext = createContext() - -export const AgentRequirementsProvider: ParentComponent = (props) => { - const vscode = useVSCode() - const session = useSession() - const server = useServer() - const config = useConfig() - const [result, setResult] = createSignal() - const [revision, setRevision] = createSignal(0) - const [pending, setPending] = createSignal(false) - const [requested, setRequested] = createSignal("") - - const enabled = () => config.config().experimental?.agent_requirements === true - const agent = () => session.selectedAgent() - const directory = () => server.workspaceDirectory() - const key = () => `${directory()}\0${agent()}` - const active = (value: { agent: string; directory: string }) => - value.agent === agent() && value.directory === directory() - - const request = () => { - if (!enabled() || !agent() || !directory()) return - setPending(true) - vscode.postMessage({ - type: "requestAgentRequirements", - agent: agent(), - directory: directory(), - sessionID: session.currentSessionID(), - }) - } - - const unsubscribe = vscode.onMessage((message) => { - if (message.type === "agentRequirementsLoaded") { - if (!active(message.result)) return - setPending(false) - setResult(message.result) - return - } - - if (message.type === "agentRequirementsInvalidated") { - setRequested("") - setRevision((value) => value + 1) - } - }) - - createEffect(() => { - revision() - if (!enabled()) { - setRequested("") - setPending(false) - setResult(undefined) - return - } - - const next = key() - if (!agent() || !directory() || next === requested()) return - setRequested(next) - setPending(true) - if (!keepAgentRequirementsResult(result(), agent(), directory())) setResult(undefined) - request() - }) - - const checking = createMemo(() => enabled() && pending()) - const blocked = createMemo(() => { - if (!enabled()) return false - const current = result() - return !current || current.state === "blocked" || current.state === "error" - }) - const visible = createMemo(() => { - const current = result() - return current?.state === "blocked" || current?.state === "error" - }) - - onCleanup(unsubscribe) - - return ( - - {props.children} - - ) -} - -export function useAgentRequirements(): AgentRequirementsContextValue { - const value = useContext(AgentRequirementsContext) - if (!value) throw new Error("useAgentRequirements must be used within an AgentRequirementsProvider") - return value -} diff --git a/packages/kilo-vscode/webview-ui/src/context/provider-shell.tsx b/packages/kilo-vscode/webview-ui/src/context/provider-shell.tsx index d457f5e4f00..aaee98b62aa 100644 --- a/packages/kilo-vscode/webview-ui/src/context/provider-shell.tsx +++ b/packages/kilo-vscode/webview-ui/src/context/provider-shell.tsx @@ -15,7 +15,6 @@ import { ProviderProvider } from "./provider" import { ConfigProvider } from "./config" import { DisplayProvider } from "./display" import { IndexingProvider } from "./indexing" -import { AgentRequirementsProvider } from "./agent-requirements" import { MemoryProvider } from "./memory" import { SessionProvider } from "./session" import { LanguageBridge } from "./language-bridge" @@ -91,11 +90,9 @@ const Session: ParentComponent = (props) => ( ) const Chat: ParentComponent = (props) => ( - - - {props.children} - - + + {props.children} + ) export const ProviderShell = { Root, Session, Chat } diff --git a/packages/kilo-vscode/webview-ui/src/hooks/useTerminalContext.ts b/packages/kilo-vscode/webview-ui/src/hooks/useTerminalContext.ts index 7409468198e..87869affd1a 100644 --- a/packages/kilo-vscode/webview-ui/src/hooks/useTerminalContext.ts +++ b/packages/kilo-vscode/webview-ui/src/hooks/useTerminalContext.ts @@ -1,6 +1,7 @@ import { createSignal, onCleanup } from "solid-js" import type { Accessor } from "solid-js" -import type { ExtensionMessage, FileAttachment, WebviewMessage } from "../types/messages" +import type { FileAttachment } from "../types/messages" +import { useVSCode } from "../context/vscode" import { buildTerminalAttachment, hasTerminalMention } from "./terminal-context-utils" const TERMINAL_CONTEXT_TIMEOUT_MS = 10_000 @@ -11,17 +12,15 @@ type Pending = { timer: ReturnType } -interface VSCodeContext { - postMessage: (message: WebviewMessage) => void - onMessage: (handler: (message: ExtensionMessage) => void) => () => void -} +type EmbeddedResolver = (context?: string) => Promise export interface TerminalContext { pending: Accessor - resolveAttachment: (text: string, sessionID?: string) => Promise + resolveAttachment: (text: string, sessionID?: string, context?: string) => Promise } -export function useTerminalContext(vscode: VSCodeContext): TerminalContext { +export function useTerminalContext(embedded?: EmbeddedResolver): TerminalContext { + const vscode = useVSCode() const [pending, setPending] = createSignal(false) const requests = new Map() let counter = 0 @@ -56,7 +55,7 @@ export function useTerminalContext(vscode: VSCodeContext): TerminalContext { requests.clear() }) - const request = (sessionID?: string) => + const request = (sessionID?: string, context?: string) => new Promise((resolve, reject) => { counter++ const requestId = `terminal-context-${counter}` @@ -66,13 +65,28 @@ export function useTerminalContext(vscode: VSCodeContext): TerminalContext { requests.set(requestId, { resolve, reject, timer }) setPending(true) - vscode.postMessage({ type: "requestTerminalContext", requestId, sessionID }) + if (!embedded) { + vscode.postMessage({ type: "requestTerminalContext", requestId, sessionID, agentManagerContext: context }) + return + } + void embedded(context).then( + (content) => { + if (content === undefined) { + vscode.postMessage({ type: "requestTerminalContext", requestId, sessionID, agentManagerContext: context }) + return + } + settle(requestId, (req) => req.resolve(content)) + }, + (error: unknown) => { + settle(requestId, (req) => req.reject(error instanceof Error ? error : new Error(String(error)))) + }, + ) }) - const resolveAttachment = async (text: string, sessionID?: string) => { + const resolveAttachment = async (text: string, sessionID?: string, context?: string) => { if (!hasTerminalMention(text)) return undefined - const content = await request(sessionID) + const content = await request(sessionID, context) if (!content.trim()) throw new Error("No terminal content available") return buildTerminalAttachment(text, content) } diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts index 5ad2710a011..7722e7a23b6 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts @@ -75,30 +75,6 @@ export const dict = { "command.session.compact": "ضغط الجلسة", "command.session.export": "تصدير سجل الجلسة", - "agentRequirements.skill.installed": "مثبت", - "agentRequirements.skill.checkFailed": "فشل فحص المهارة", - "agentRequirements.skill.missing": "غير مثبت", - "agentRequirements.mcp.connected": "متصل", - "agentRequirements.mcp.checkFailed": "فشل فحص MCP", - "agentRequirements.mcp.missing": "غير متصل", - "agentRequirements.extension.installed": "مثبت", - "agentRequirements.extension.checkFailed": "فشل فحص إضافة VS Code", - "agentRequirements.extension.missing": "غير مثبت", - "agentRequirements.extension.description": "ثبّت الإضافات الناقصة في VS Code.", - "agentRequirements.group.skills": "المهارات", - "agentRequirements.group.mcps": "MCPs", - "agentRequirements.group.extensions": "إضافات VS Code", - "agentRequirements.blocked.title": "متطلبات وكيل {{agent}}", - "agentRequirements.blocked.description": "يحتاج هذا الوكيل إلى الأدوات التالية قبل أن يتمكن من العمل.", - "agentRequirements.prompt.blocked": "أكمل الفحوصات المطلوبة لاستخدام هذا الوكيل أولاً", - "agentRequirements.action.openMarketplace": "فتح Marketplace", - "agentRequirements.error.unknownAgent": "تعذر العثور على الوكيل المحدد.", - "agentRequirements.error.malformedDeclaration": "لدى هذا الوكيل تعريف متطلبات غير صالح.", - "agentRequirements.error.discoveryFailed": "تعذر على Kilo فحص المهارات المتاحة.", - "agentRequirements.error.mcpStatusFailed": "تعذر على Kilo فحص حالة خادم MCP.", - "agentRequirements.error.scopeMismatch": "لم يعد فحص متطلبات هذا الوكيل نشطًا.", - "agentRequirements.error.requestFailed": "تعذر على Kilo فحص متطلبات الوكيل.", - "dialog.provider.search.placeholder": "البحث عن موفرين", "dialog.provider.empty": "لم يتم العثور على موفرين", "dialog.provider.group.other": "آخر", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/br.ts b/packages/kilo-vscode/webview-ui/src/i18n/br.ts index a2ec57c49c5..4f7c4a03cb3 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/br.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/br.ts @@ -78,30 +78,6 @@ export const dict = { "command.session.compact": "Compactar sessão", "command.session.export": "Exportar transcrição da sessão", - "agentRequirements.skill.installed": "Instalado", - "agentRequirements.skill.checkFailed": "A verificação da skill falhou", - "agentRequirements.skill.missing": "Não instalado", - "agentRequirements.mcp.connected": "Conectado", - "agentRequirements.mcp.checkFailed": "A verificação do MCP falhou", - "agentRequirements.mcp.missing": "Não conectado", - "agentRequirements.extension.installed": "Instalada", - "agentRequirements.extension.checkFailed": "A verificação da extensão do VS Code falhou", - "agentRequirements.extension.missing": "Não instalada", - "agentRequirements.extension.description": "Instale as extensões ausentes no VS Code.", - "agentRequirements.group.skills": "Skills", - "agentRequirements.group.mcps": "MCPs", - "agentRequirements.group.extensions": "Extensões do VS Code", - "agentRequirements.blocked.title": "Pré-requisitos do agente {{agent}}", - "agentRequirements.blocked.description": "Este agente precisa das seguintes ferramentas antes de poder executar.", - "agentRequirements.prompt.blocked": "Conclua primeiro as verificações necessárias para usar este agente", - "agentRequirements.action.openMarketplace": "Abrir Marketplace", - "agentRequirements.error.unknownAgent": "O agente selecionado não foi encontrado.", - "agentRequirements.error.malformedDeclaration": "Este agente tem uma declaração de requisitos inválida.", - "agentRequirements.error.discoveryFailed": "O Kilo não conseguiu verificar as skills disponíveis.", - "agentRequirements.error.mcpStatusFailed": "O Kilo não conseguiu verificar o status do servidor MCP.", - "agentRequirements.error.scopeMismatch": "Esta verificação de requisitos do agente não está mais ativa.", - "agentRequirements.error.requestFailed": "O Kilo não conseguiu verificar os requisitos do agente.", - "dialog.provider.search.placeholder": "Buscar provedores", "dialog.provider.empty": "Nenhum provedor encontrado", "dialog.provider.group.other": "Outro", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts index 917e9282529..b211df5c2b4 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts @@ -78,30 +78,6 @@ export const dict = { "command.session.compact": "Sažmi sesiju", "command.session.export": "Izvezi transkript sesije", - "agentRequirements.skill.installed": "Instalirano", - "agentRequirements.skill.checkFailed": "Provjera vještine nije uspjela", - "agentRequirements.skill.missing": "Nije instalirano", - "agentRequirements.mcp.connected": "Povezano", - "agentRequirements.mcp.checkFailed": "Provjera MCP-a nije uspjela", - "agentRequirements.mcp.missing": "Nije povezano", - "agentRequirements.extension.installed": "Instalirano", - "agentRequirements.extension.checkFailed": "Provjera VS Code ekstenzije nije uspjela", - "agentRequirements.extension.missing": "Nije instalirano", - "agentRequirements.extension.description": "Instalirajte nedostajuće ekstenzije u VS Code.", - "agentRequirements.group.skills": "Vještine", - "agentRequirements.group.mcps": "MCP-ovi", - "agentRequirements.group.extensions": "VS Code ekstenzije", - "agentRequirements.blocked.title": "Preduslovi za agenta {{agent}}", - "agentRequirements.blocked.description": "Ovom agentu su potrebni sljedeći alati prije pokretanja.", - "agentRequirements.prompt.blocked": "Prvo dovršite potrebne provjere da biste koristili ovog agenta", - "agentRequirements.action.openMarketplace": "Otvori Marketplace", - "agentRequirements.error.unknownAgent": "Odabrani agent nije pronađen.", - "agentRequirements.error.malformedDeclaration": "Ovaj agent ima neispravnu deklaraciju zahtjeva.", - "agentRequirements.error.discoveryFailed": "Kilo nije mogao provjeriti dostupne vještine.", - "agentRequirements.error.mcpStatusFailed": "Kilo nije mogao provjeriti status MCP servera.", - "agentRequirements.error.scopeMismatch": "Ova provjera zahtjeva agenta više nije aktivna.", - "agentRequirements.error.requestFailed": "Kilo nije mogao provjeriti zahtjeve agenta.", - "dialog.provider.search.placeholder": "Pretraži provajdere", "dialog.provider.empty": "Nema pronađenih provajdera", "dialog.provider.group.other": "Ostalo", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/da.ts b/packages/kilo-vscode/webview-ui/src/i18n/da.ts index b4de50119bf..bc765ace7ab 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/da.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/da.ts @@ -78,30 +78,6 @@ export const dict = { "command.session.compact": "Komprimér session", "command.session.export": "Eksporter sessionsudskrift", - "agentRequirements.skill.installed": "Installeret", - "agentRequirements.skill.checkFailed": "Skill-kontrollen mislykkedes", - "agentRequirements.skill.missing": "Ikke installeret", - "agentRequirements.mcp.connected": "Forbundet", - "agentRequirements.mcp.checkFailed": "MCP-kontrollen mislykkedes", - "agentRequirements.mcp.missing": "Ikke forbundet", - "agentRequirements.extension.installed": "Installeret", - "agentRequirements.extension.checkFailed": "Kontrollen af VS Code-udvidelsen mislykkedes", - "agentRequirements.extension.missing": "Ikke installeret", - "agentRequirements.extension.description": "Installer de manglende udvidelser i VS Code.", - "agentRequirements.group.skills": "Skills", - "agentRequirements.group.mcps": "MCP’er", - "agentRequirements.group.extensions": "VS Code-udvidelser", - "agentRequirements.blocked.title": "Forudsætninger for {{agent}}-agenten", - "agentRequirements.blocked.description": "Denne agent skal have følgende værktøjer, før den kan køre.", - "agentRequirements.prompt.blocked": "Fuldfør først de krævede kontroller for at bruge denne agent", - "agentRequirements.action.openMarketplace": "Åbn Marketplace", - "agentRequirements.error.unknownAgent": "Den valgte agent blev ikke fundet.", - "agentRequirements.error.malformedDeclaration": "Denne agent har en ugyldig kravdeklaration.", - "agentRequirements.error.discoveryFailed": "Kilo kunne ikke kontrollere de tilgængelige skills.", - "agentRequirements.error.mcpStatusFailed": "Kilo kunne ikke kontrollere MCP-serverstatus.", - "agentRequirements.error.scopeMismatch": "Denne agentkravskontrol er ikke længere aktiv.", - "agentRequirements.error.requestFailed": "Kilo kunne ikke kontrollere agentkravene.", - "dialog.provider.search.placeholder": "Søg udbydere", "dialog.provider.empty": "Ingen udbydere fundet", "dialog.provider.group.other": "Andre", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/de.ts b/packages/kilo-vscode/webview-ui/src/i18n/de.ts index c23587727a2..3bc893636bd 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/de.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/de.ts @@ -84,31 +84,6 @@ export const dict = { "command.session.compact": "Sitzung komprimieren", "command.session.export": "Sitzungsprotokoll exportieren", - "agentRequirements.skill.installed": "Installiert", - "agentRequirements.skill.checkFailed": "Die Skill-Prüfung ist fehlgeschlagen", - "agentRequirements.skill.missing": "Nicht installiert", - "agentRequirements.mcp.connected": "Verbunden", - "agentRequirements.mcp.checkFailed": "Die MCP-Prüfung ist fehlgeschlagen", - "agentRequirements.mcp.missing": "Nicht verbunden", - "agentRequirements.extension.installed": "Installiert", - "agentRequirements.extension.checkFailed": "Die Prüfung der VS Code-Erweiterung ist fehlgeschlagen", - "agentRequirements.extension.missing": "Nicht installiert", - "agentRequirements.extension.description": "Installiere die fehlenden Erweiterungen in VS Code.", - "agentRequirements.group.skills": "Skills", - "agentRequirements.group.mcps": "MCPs", - "agentRequirements.group.extensions": "VS Code-Erweiterungen", - "agentRequirements.blocked.title": "Voraussetzungen für den Agenten {{agent}}", - "agentRequirements.blocked.description": - "Dieser Agent benötigt die folgenden Werkzeuge, bevor er ausgeführt werden kann.", - "agentRequirements.prompt.blocked": "Schließe zuerst die erforderlichen Prüfungen ab, um diesen Agenten zu verwenden", - "agentRequirements.action.openMarketplace": "Marketplace öffnen", - "agentRequirements.error.unknownAgent": "Der ausgewählte Agent wurde nicht gefunden.", - "agentRequirements.error.malformedDeclaration": "Dieser Agent hat eine ungültige Anforderungsdeklaration.", - "agentRequirements.error.discoveryFailed": "Kilo konnte die verfügbaren Skills nicht prüfen.", - "agentRequirements.error.mcpStatusFailed": "Kilo konnte den MCP-Serverstatus nicht prüfen.", - "agentRequirements.error.scopeMismatch": "Diese Prüfung der Agentenanforderungen ist nicht mehr aktiv.", - "agentRequirements.error.requestFailed": "Kilo konnte die Agentenanforderungen nicht prüfen.", - "dialog.provider.search.placeholder": "Anbieter durchsuchen", "dialog.provider.empty": "Keine Anbieter gefunden", "dialog.provider.group.other": "Andere", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/en.ts b/packages/kilo-vscode/webview-ui/src/i18n/en.ts index 683c1dfd48b..4882ad5c7c6 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/en.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/en.ts @@ -77,30 +77,6 @@ export const dict = { "command.session.compact": "Compact session", "command.session.export": "Export session transcript", - "agentRequirements.skill.installed": "Installed", - "agentRequirements.skill.checkFailed": "The skill check failed", - "agentRequirements.skill.missing": "Not installed", - "agentRequirements.mcp.connected": "Connected", - "agentRequirements.mcp.checkFailed": "The MCP check failed", - "agentRequirements.mcp.missing": "Not connected", - "agentRequirements.extension.installed": "Installed", - "agentRequirements.extension.checkFailed": "The VS Code extension check failed", - "agentRequirements.extension.missing": "Not installed", - "agentRequirements.extension.description": "Install the missing extensions in VS Code.", - "agentRequirements.group.skills": "Skills", - "agentRequirements.group.mcps": "MCPs", - "agentRequirements.group.extensions": "VS Code Extensions", - "agentRequirements.blocked.title": "{{agent}} agent prerequisites", - "agentRequirements.blocked.description": "This agent needs the following tools before it can run.", - "agentRequirements.prompt.blocked": "Complete the required checks to use this agent first", - "agentRequirements.action.openMarketplace": "Open Marketplace", - "agentRequirements.error.unknownAgent": "The selected agent could not be found.", - "agentRequirements.error.malformedDeclaration": "This agent has an invalid requirement declaration.", - "agentRequirements.error.discoveryFailed": "Kilo could not check the available skills.", - "agentRequirements.error.mcpStatusFailed": "Kilo could not check MCP server status.", - "agentRequirements.error.scopeMismatch": "This agent requirement check is no longer active.", - "agentRequirements.error.requestFailed": "Kilo could not check the agent requirements.", - "dialog.provider.search.placeholder": "Search providers", "dialog.provider.empty": "No providers found", "dialog.provider.group.other": "Other", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/es.ts b/packages/kilo-vscode/webview-ui/src/i18n/es.ts index 4dbe1e5d9a0..a9b4a5661a2 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/es.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/es.ts @@ -78,31 +78,6 @@ export const dict = { "command.session.compact": "Compactar sesión", "command.session.export": "Exportar transcripción de la sesión", - "agentRequirements.skill.installed": "Instalada", - "agentRequirements.skill.checkFailed": "La comprobación de la habilidad falló", - "agentRequirements.skill.missing": "No instalada", - "agentRequirements.mcp.connected": "Conectado", - "agentRequirements.mcp.checkFailed": "La comprobación de MCP falló", - "agentRequirements.mcp.missing": "No conectado", - "agentRequirements.extension.installed": "Instalada", - "agentRequirements.extension.checkFailed": "La comprobación de la extensión de VS Code falló", - "agentRequirements.extension.missing": "No instalada", - "agentRequirements.extension.description": "Instala las extensiones que faltan en VS Code.", - "agentRequirements.group.skills": "Habilidades", - "agentRequirements.group.mcps": "MCPs", - "agentRequirements.group.extensions": "Extensiones de VS Code", - "agentRequirements.blocked.title": "Requisitos previos del agente {{agent}}", - "agentRequirements.blocked.description": - "Este agente necesita las siguientes herramientas antes de poder ejecutarse.", - "agentRequirements.prompt.blocked": "Completa primero las comprobaciones requeridas para usar este agente", - "agentRequirements.action.openMarketplace": "Abrir Marketplace", - "agentRequirements.error.unknownAgent": "No se pudo encontrar el agente seleccionado.", - "agentRequirements.error.malformedDeclaration": "Este agente tiene una declaración de requisitos no válida.", - "agentRequirements.error.discoveryFailed": "Kilo no pudo comprobar las habilidades disponibles.", - "agentRequirements.error.mcpStatusFailed": "Kilo no pudo comprobar el estado del servidor MCP.", - "agentRequirements.error.scopeMismatch": "Esta comprobación de requisitos del agente ya no está activa.", - "agentRequirements.error.requestFailed": "Kilo no pudo comprobar los requisitos del agente.", - "dialog.provider.search.placeholder": "Buscar proveedores", "dialog.provider.empty": "No se encontraron proveedores", "dialog.provider.group.other": "Otro", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/fa.ts b/packages/kilo-vscode/webview-ui/src/i18n/fa.ts index e75383ba04c..49a7bb70f49 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/fa.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/fa.ts @@ -78,30 +78,6 @@ export const dict = { "command.session.compact": "فشرده‌سازی جلسه", "command.session.export": "صدور رونوشت جلسه", - "agentRequirements.skill.installed": "نصب شده", - "agentRequirements.skill.checkFailed": "بررسی مهارت ناموفق بود", - "agentRequirements.skill.missing": "نصب نشده", - "agentRequirements.mcp.connected": "متصل", - "agentRequirements.mcp.checkFailed": "بررسی MCP ناموفق بود", - "agentRequirements.mcp.missing": "متصل نیست", - "agentRequirements.extension.installed": "نصب شده", - "agentRequirements.extension.checkFailed": "بررسی افزونه VS Code ناموفق بود", - "agentRequirements.extension.missing": "نصب نشده", - "agentRequirements.extension.description": "افزونه‌های مفقود را در VS Code نصب کنید.", - "agentRequirements.group.skills": "مهارت‌ها", - "agentRequirements.group.mcps": "MCPs", - "agentRequirements.group.extensions": "افزونه‌های VS Code", - "agentRequirements.blocked.title": "پیش‌نیازهای عامل {{agent}}", - "agentRequirements.blocked.description": "این عامل پیش از اجرا به ابزارهای زیر نیاز دارد.", - "agentRequirements.prompt.blocked": "ابتدا بررسی‌های لازم را تکمیل کنید تا بتوانید از این عامل استفاده کنید", - "agentRequirements.action.openMarketplace": "باز کردن Marketplace", - "agentRequirements.error.unknownAgent": "عامل انتخاب‌شده یافت نشد.", - "agentRequirements.error.malformedDeclaration": "این عامل دارای اعلان پیش‌نیاز نامعتبر است.", - "agentRequirements.error.discoveryFailed": "Kilo نتوانست مهارت‌های موجود را بررسی کند.", - "agentRequirements.error.mcpStatusFailed": "Kilo نتوانست وضعیت سرور MCP را بررسی کند.", - "agentRequirements.error.scopeMismatch": "این بررسی نیازمندی‌های عامل دیگر فعال نیست.", - "agentRequirements.error.requestFailed": "Kilo نتوانست نیازمندی‌های عامل را بررسی کند.", - "dialog.provider.search.placeholder": "جستجوی ارائه‌دهندگان", "dialog.provider.empty": "ارائه‌دهنده‌ای یافت نشد", "dialog.provider.group.other": "سایر", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts index 3c8dacfdfd4..0eb27e9b932 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts @@ -78,30 +78,6 @@ export const dict = { "command.session.compact": "Compacter la session", "command.session.export": "Exporter la transcription de la session", - "agentRequirements.skill.installed": "Installée", - "agentRequirements.skill.checkFailed": "La vérification de la compétence a échoué", - "agentRequirements.skill.missing": "Non installée", - "agentRequirements.mcp.connected": "Connecté", - "agentRequirements.mcp.checkFailed": "La vérification MCP a échoué", - "agentRequirements.mcp.missing": "Non connecté", - "agentRequirements.extension.installed": "Installée", - "agentRequirements.extension.checkFailed": "La vérification de l’extension VS Code a échoué", - "agentRequirements.extension.missing": "Non installée", - "agentRequirements.extension.description": "Installez les extensions manquantes dans VS Code.", - "agentRequirements.group.skills": "Compétences", - "agentRequirements.group.mcps": "MCP", - "agentRequirements.group.extensions": "Extensions VS Code", - "agentRequirements.blocked.title": "Prérequis de l’agent {{agent}}", - "agentRequirements.blocked.description": "Cet agent a besoin des outils suivants avant de pouvoir s’exécuter.", - "agentRequirements.prompt.blocked": "Terminez d’abord les vérifications requises pour utiliser cet agent", - "agentRequirements.action.openMarketplace": "Ouvrir Marketplace", - "agentRequirements.error.unknownAgent": "L’agent sélectionné est introuvable.", - "agentRequirements.error.malformedDeclaration": "Cet agent a une déclaration de prérequis invalide.", - "agentRequirements.error.discoveryFailed": "Kilo n’a pas pu vérifier les compétences disponibles.", - "agentRequirements.error.mcpStatusFailed": "Kilo n’a pas pu vérifier l’état du serveur MCP.", - "agentRequirements.error.scopeMismatch": "Cette vérification des prérequis de l’agent n’est plus active.", - "agentRequirements.error.requestFailed": "Kilo n’a pas pu vérifier les prérequis de l’agent.", - "dialog.provider.search.placeholder": "Rechercher des fournisseurs", "dialog.provider.empty": "Aucun fournisseur trouvé", "dialog.provider.group.other": "Autre", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/it.ts b/packages/kilo-vscode/webview-ui/src/i18n/it.ts index cc69196721d..5947ad81b61 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/it.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/it.ts @@ -1194,31 +1194,6 @@ export const dict = { // Session export "command.session.export": "Esporta trascrizione sessione", - "agentRequirements.skill.installed": "Installata", - "agentRequirements.skill.checkFailed": "Il controllo della skill non è riuscito", - "agentRequirements.skill.missing": "Non installata", - "agentRequirements.mcp.connected": "Connesso", - "agentRequirements.mcp.checkFailed": "Il controllo MCP non è riuscito", - "agentRequirements.mcp.missing": "Non connesso", - "agentRequirements.extension.installed": "Installata", - "agentRequirements.extension.checkFailed": "Il controllo dell’estensione VS Code non è riuscito", - "agentRequirements.extension.missing": "Non installata", - "agentRequirements.extension.description": "Installa le estensioni mancanti in VS Code.", - "agentRequirements.group.skills": "Skill", - "agentRequirements.group.mcps": "MCP", - "agentRequirements.group.extensions": "Estensioni VS Code", - "agentRequirements.blocked.title": "Prerequisiti dell’agente {{agent}}", - "agentRequirements.blocked.description": - "Questo agente richiede i seguenti strumenti prima di poter essere eseguito.", - "agentRequirements.prompt.blocked": "Completa prima i controlli richiesti per usare questo agente", - "agentRequirements.action.openMarketplace": "Apri Marketplace", - "agentRequirements.error.unknownAgent": "Impossibile trovare l’agente selezionato.", - "agentRequirements.error.malformedDeclaration": "Questo agente ha una dichiarazione dei requisiti non valida.", - "agentRequirements.error.discoveryFailed": "Kilo non ha potuto controllare le skill disponibili.", - "agentRequirements.error.mcpStatusFailed": "Kilo non ha potuto controllare lo stato del server MCP.", - "agentRequirements.error.scopeMismatch": "Questo controllo dei requisiti dell’agente non è più attivo.", - "agentRequirements.error.requestFailed": "Kilo non ha potuto controllare i requisiti dell’agente.", - // Model groups // Plan exit diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts index 98b3817df8a..6b5fad8cbcf 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts @@ -78,30 +78,6 @@ export const dict = { "command.session.compact": "セッションを圧縮", "command.session.export": "セッション記録をエクスポート", - "agentRequirements.skill.installed": "インストール済み", - "agentRequirements.skill.checkFailed": "スキルの確認に失敗しました", - "agentRequirements.skill.missing": "未インストール", - "agentRequirements.mcp.connected": "接続済み", - "agentRequirements.mcp.checkFailed": "MCP の確認に失敗しました", - "agentRequirements.mcp.missing": "未接続", - "agentRequirements.extension.installed": "インストール済み", - "agentRequirements.extension.checkFailed": "VS Code 拡張機能の確認に失敗しました", - "agentRequirements.extension.missing": "未インストール", - "agentRequirements.extension.description": "不足している拡張機能を VS Code にインストールしてください。", - "agentRequirements.group.skills": "スキル", - "agentRequirements.group.mcps": "MCP", - "agentRequirements.group.extensions": "VS Code 拡張機能", - "agentRequirements.blocked.title": "{{agent}} エージェントの前提条件", - "agentRequirements.blocked.description": "このエージェントを実行するには、次のツールが必要です。", - "agentRequirements.prompt.blocked": "このエージェントを使用するには、先に必要な確認を完了してください", - "agentRequirements.action.openMarketplace": "Marketplace を開く", - "agentRequirements.error.unknownAgent": "選択したエージェントが見つかりませんでした。", - "agentRequirements.error.malformedDeclaration": "このエージェントの要件宣言は無効です。", - "agentRequirements.error.discoveryFailed": "Kilo は利用可能なスキルを確認できませんでした。", - "agentRequirements.error.mcpStatusFailed": "Kilo は MCP サーバーの状態を確認できませんでした。", - "agentRequirements.error.scopeMismatch": "このエージェント要件の確認はもう有効ではありません。", - "agentRequirements.error.requestFailed": "Kilo はエージェント要件を確認できませんでした。", - "dialog.provider.search.placeholder": "プロバイダーを検索", "dialog.provider.empty": "プロバイダーが見つかりません", "dialog.provider.group.other": "その他", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts index 47f0796960b..596e55d4393 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts @@ -82,30 +82,6 @@ export const dict = { "command.session.compact": "세션 압축", "command.session.export": "세션 기록 내보내기", - "agentRequirements.skill.installed": "설치됨", - "agentRequirements.skill.checkFailed": "스킬 확인에 실패했습니다", - "agentRequirements.skill.missing": "설치되지 않음", - "agentRequirements.mcp.connected": "연결됨", - "agentRequirements.mcp.checkFailed": "MCP 확인에 실패했습니다", - "agentRequirements.mcp.missing": "연결되지 않음", - "agentRequirements.extension.installed": "설치됨", - "agentRequirements.extension.checkFailed": "VS Code 확장 확인에 실패했습니다", - "agentRequirements.extension.missing": "설치되지 않음", - "agentRequirements.extension.description": "VS Code에서 누락된 확장을 설치하세요.", - "agentRequirements.group.skills": "스킬", - "agentRequirements.group.mcps": "MCP", - "agentRequirements.group.extensions": "VS Code 확장", - "agentRequirements.blocked.title": "{{agent}} 에이전트 필수 조건", - "agentRequirements.blocked.description": "이 에이전트를 실행하려면 다음 도구가 필요합니다.", - "agentRequirements.prompt.blocked": "이 에이전트를 사용하려면 먼저 필요한 확인을 완료하세요", - "agentRequirements.action.openMarketplace": "Marketplace 열기", - "agentRequirements.error.unknownAgent": "선택한 에이전트를 찾을 수 없습니다.", - "agentRequirements.error.malformedDeclaration": "이 에이전트의 요구 사항 선언이 올바르지 않습니다.", - "agentRequirements.error.discoveryFailed": "Kilo가 사용 가능한 스킬을 확인하지 못했습니다.", - "agentRequirements.error.mcpStatusFailed": "Kilo가 MCP 서버 상태를 확인하지 못했습니다.", - "agentRequirements.error.scopeMismatch": "이 에이전트 요구 사항 확인은 더 이상 활성 상태가 아닙니다.", - "agentRequirements.error.requestFailed": "Kilo가 에이전트 요구 사항을 확인하지 못했습니다.", - "dialog.provider.search.placeholder": "공급자 검색", "dialog.provider.empty": "공급자 없음", "dialog.provider.group.other": "기타", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/nl.ts b/packages/kilo-vscode/webview-ui/src/i18n/nl.ts index 72c19b30079..918f9de2a12 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/nl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/nl.ts @@ -78,31 +78,6 @@ export const dict = { "command.session.compact": "Sessie comprimeren", "command.session.export": "Sessietranscript exporteren", - "agentRequirements.skill.installed": "Geïnstalleerd", - "agentRequirements.skill.checkFailed": "De skillcontrole is mislukt", - "agentRequirements.skill.missing": "Niet geïnstalleerd", - "agentRequirements.mcp.connected": "Verbonden", - "agentRequirements.mcp.checkFailed": "De MCP-controle is mislukt", - "agentRequirements.mcp.missing": "Niet verbonden", - "agentRequirements.extension.installed": "Geïnstalleerd", - "agentRequirements.extension.checkFailed": "De controle van de VS Code-extensie is mislukt", - "agentRequirements.extension.missing": "Niet geïnstalleerd", - "agentRequirements.extension.description": "Installeer de ontbrekende extensies in VS Code.", - "agentRequirements.group.skills": "Skills", - "agentRequirements.group.mcps": "MCP’s", - "agentRequirements.group.extensions": "VS Code-extensies", - "agentRequirements.blocked.title": "Vereisten voor agent {{agent}}", - "agentRequirements.blocked.description": - "Deze agent heeft de volgende tools nodig voordat deze kan worden uitgevoerd.", - "agentRequirements.prompt.blocked": "Voltooi eerst de vereiste controles om deze agent te gebruiken", - "agentRequirements.action.openMarketplace": "Marketplace openen", - "agentRequirements.error.unknownAgent": "De geselecteerde agent kon niet worden gevonden.", - "agentRequirements.error.malformedDeclaration": "Deze agent heeft een ongeldige vereistenverklaring.", - "agentRequirements.error.discoveryFailed": "Kilo kon de beschikbare skills niet controleren.", - "agentRequirements.error.mcpStatusFailed": "Kilo kon de MCP-serverstatus niet controleren.", - "agentRequirements.error.scopeMismatch": "Deze controle van agentvereisten is niet meer actief.", - "agentRequirements.error.requestFailed": "Kilo kon de agentvereisten niet controleren.", - "dialog.provider.search.placeholder": "Providers zoeken", "dialog.provider.empty": "Geen providers gevonden", "dialog.provider.group.other": "Overige", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/no.ts b/packages/kilo-vscode/webview-ui/src/i18n/no.ts index 10a34cdc9e7..f3e3b4730d5 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/no.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/no.ts @@ -81,30 +81,6 @@ export const dict = { "command.session.compact": "Komprimer sesjon", "command.session.export": "Eksporter sesjonsutskrift", - "agentRequirements.skill.installed": "Installert", - "agentRequirements.skill.checkFailed": "Skill-sjekken mislyktes", - "agentRequirements.skill.missing": "Ikke installert", - "agentRequirements.mcp.connected": "Tilkoblet", - "agentRequirements.mcp.checkFailed": "MCP-sjekken mislyktes", - "agentRequirements.mcp.missing": "Ikke tilkoblet", - "agentRequirements.extension.installed": "Installert", - "agentRequirements.extension.checkFailed": "Sjekken av VS Code-utvidelsen mislyktes", - "agentRequirements.extension.missing": "Ikke installert", - "agentRequirements.extension.description": "Installer de manglende utvidelsene i VS Code.", - "agentRequirements.group.skills": "Skills", - "agentRequirements.group.mcps": "MCP-er", - "agentRequirements.group.extensions": "VS Code-utvidelser", - "agentRequirements.blocked.title": "Forutsetninger for agenten {{agent}}", - "agentRequirements.blocked.description": "Denne agenten trenger følgende verktøy før den kan kjøre.", - "agentRequirements.prompt.blocked": "Fullfør først de nødvendige sjekkene for å bruke denne agenten", - "agentRequirements.action.openMarketplace": "Åpne Marketplace", - "agentRequirements.error.unknownAgent": "Den valgte agenten ble ikke funnet.", - "agentRequirements.error.malformedDeclaration": "Denne agenten har en ugyldig kravdeklarasjon.", - "agentRequirements.error.discoveryFailed": "Kilo kunne ikke sjekke tilgjengelige skills.", - "agentRequirements.error.mcpStatusFailed": "Kilo kunne ikke sjekke MCP-serverstatus.", - "agentRequirements.error.scopeMismatch": "Denne sjekken av agentkrav er ikke lenger aktiv.", - "agentRequirements.error.requestFailed": "Kilo kunne ikke sjekke agentkravene.", - "dialog.provider.search.placeholder": "Søk etter leverandører", "dialog.provider.empty": "Ingen leverandører funnet", "dialog.provider.group.other": "Andre", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts index e88d5202455..227c172c757 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts @@ -78,30 +78,6 @@ export const dict = { "command.session.compact": "Kompaktuj sesję", "command.session.export": "Eksportuj transkrypcję sesji", - "agentRequirements.skill.installed": "Zainstalowano", - "agentRequirements.skill.checkFailed": "Sprawdzanie umiejętności nie powiodło się", - "agentRequirements.skill.missing": "Nie zainstalowano", - "agentRequirements.mcp.connected": "Połączono", - "agentRequirements.mcp.checkFailed": "Sprawdzanie MCP nie powiodło się", - "agentRequirements.mcp.missing": "Nie połączono", - "agentRequirements.extension.installed": "Zainstalowano", - "agentRequirements.extension.checkFailed": "Sprawdzanie rozszerzenia VS Code nie powiodło się", - "agentRequirements.extension.missing": "Nie zainstalowano", - "agentRequirements.extension.description": "Zainstaluj brakujące rozszerzenia w VS Code.", - "agentRequirements.group.skills": "Umiejętności", - "agentRequirements.group.mcps": "MCP", - "agentRequirements.group.extensions": "Rozszerzenia VS Code", - "agentRequirements.blocked.title": "Wymagania wstępne agenta {{agent}}", - "agentRequirements.blocked.description": "Ten agent potrzebuje następujących narzędzi, zanim będzie mógł działać.", - "agentRequirements.prompt.blocked": "Najpierw ukończ wymagane sprawdzenia, aby użyć tego agenta", - "agentRequirements.action.openMarketplace": "Otwórz Marketplace", - "agentRequirements.error.unknownAgent": "Nie znaleziono wybranego agenta.", - "agentRequirements.error.malformedDeclaration": "Ten agent ma nieprawidłową deklarację wymagań.", - "agentRequirements.error.discoveryFailed": "Kilo nie mógł sprawdzić dostępnych umiejętności.", - "agentRequirements.error.mcpStatusFailed": "Kilo nie mógł sprawdzić stanu serwera MCP.", - "agentRequirements.error.scopeMismatch": "To sprawdzenie wymagań agenta nie jest już aktywne.", - "agentRequirements.error.requestFailed": "Kilo nie mógł sprawdzić wymagań agenta.", - "dialog.provider.search.placeholder": "Szukaj dostawców", "dialog.provider.empty": "Nie znaleziono dostawców", "dialog.provider.group.other": "Inne", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts index de0b47df85b..6b84169e6fa 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts @@ -78,30 +78,6 @@ export const dict = { "command.session.compact": "Сжать сессию", "command.session.export": "Экспортировать запись сеанса", - "agentRequirements.skill.installed": "Установлено", - "agentRequirements.skill.checkFailed": "Не удалось проверить навык", - "agentRequirements.skill.missing": "Не установлено", - "agentRequirements.mcp.connected": "Подключено", - "agentRequirements.mcp.checkFailed": "Не удалось проверить MCP", - "agentRequirements.mcp.missing": "Не подключено", - "agentRequirements.extension.installed": "Установлено", - "agentRequirements.extension.checkFailed": "Не удалось проверить расширение VS Code", - "agentRequirements.extension.missing": "Не установлено", - "agentRequirements.extension.description": "Установите отсутствующие расширения в VS Code.", - "agentRequirements.group.skills": "Навыки", - "agentRequirements.group.mcps": "MCP", - "agentRequirements.group.extensions": "Расширения VS Code", - "agentRequirements.blocked.title": "Требования агента {{agent}}", - "agentRequirements.blocked.description": "Этому агенту нужны следующие инструменты перед запуском.", - "agentRequirements.prompt.blocked": "Сначала выполните необходимые проверки, чтобы использовать этого агента", - "agentRequirements.action.openMarketplace": "Открыть Marketplace", - "agentRequirements.error.unknownAgent": "Выбранный агент не найден.", - "agentRequirements.error.malformedDeclaration": "У этого агента недопустимое объявление требований.", - "agentRequirements.error.discoveryFailed": "Kilo не смог проверить доступные навыки.", - "agentRequirements.error.mcpStatusFailed": "Kilo не смог проверить состояние сервера MCP.", - "agentRequirements.error.scopeMismatch": "Эта проверка требований агента больше не активна.", - "agentRequirements.error.requestFailed": "Kilo не смог проверить требования агента.", - "dialog.provider.search.placeholder": "Поиск провайдеров", "dialog.provider.empty": "Провайдеры не найдены", "dialog.provider.group.other": "Другие", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/th.ts b/packages/kilo-vscode/webview-ui/src/i18n/th.ts index 5e8aa7483d3..7564ebfe9af 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/th.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/th.ts @@ -77,30 +77,6 @@ export const dict = { "command.session.compact": "บีบอัดเซสชัน", "command.session.export": "ส่งออกบันทึกเซสชัน", - "agentRequirements.skill.installed": "ติดตั้งแล้ว", - "agentRequirements.skill.checkFailed": "การตรวจสอบสกิลล้มเหลว", - "agentRequirements.skill.missing": "ยังไม่ได้ติดตั้ง", - "agentRequirements.mcp.connected": "เชื่อมต่อแล้ว", - "agentRequirements.mcp.checkFailed": "การตรวจสอบ MCP ล้มเหลว", - "agentRequirements.mcp.missing": "ยังไม่ได้เชื่อมต่อ", - "agentRequirements.extension.installed": "ติดตั้งแล้ว", - "agentRequirements.extension.checkFailed": "การตรวจสอบส่วนขยาย VS Code ล้มเหลว", - "agentRequirements.extension.missing": "ยังไม่ได้ติดตั้ง", - "agentRequirements.extension.description": "ติดตั้งส่วนขยายที่ขาดหายใน VS Code", - "agentRequirements.group.skills": "สกิล", - "agentRequirements.group.mcps": "MCP", - "agentRequirements.group.extensions": "ส่วนขยาย VS Code", - "agentRequirements.blocked.title": "ข้อกำหนดเบื้องต้นของเอเจนต์ {{agent}}", - "agentRequirements.blocked.description": "เอเจนต์นี้ต้องใช้เครื่องมือต่อไปนี้ก่อนจึงจะทำงานได้", - "agentRequirements.prompt.blocked": "ทำการตรวจสอบที่จำเป็นให้เสร็จก่อนเพื่อใช้เอเจนต์นี้", - "agentRequirements.action.openMarketplace": "เปิด Marketplace", - "agentRequirements.error.unknownAgent": "ไม่พบเอเจนต์ที่เลือก", - "agentRequirements.error.malformedDeclaration": "เอเจนต์นี้มีการประกาศข้อกำหนดที่ไม่ถูกต้อง", - "agentRequirements.error.discoveryFailed": "Kilo ไม่สามารถตรวจสอบสกิลที่มีอยู่ได้", - "agentRequirements.error.mcpStatusFailed": "Kilo ไม่สามารถตรวจสอบสถานะเซิร์ฟเวอร์ MCP ได้", - "agentRequirements.error.scopeMismatch": "การตรวจสอบข้อกำหนดของเอเจนต์นี้ไม่ทำงานอีกต่อไป", - "agentRequirements.error.requestFailed": "Kilo ไม่สามารถตรวจสอบข้อกำหนดของเอเจนต์ได้", - "dialog.provider.search.placeholder": "ค้นหาผู้ให้บริการ", "dialog.provider.empty": "ไม่พบผู้ให้บริการ", "dialog.provider.group.other": "อื่น ๆ", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/tr.ts b/packages/kilo-vscode/webview-ui/src/i18n/tr.ts index 70d4999ee07..dc7049658a2 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/tr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/tr.ts @@ -78,30 +78,6 @@ export const dict = { "command.session.compact": "Oturumu sıkıştır", "command.session.export": "Oturum dökümünü dışa aktar", - "agentRequirements.skill.installed": "Yüklü", - "agentRequirements.skill.checkFailed": "Yetenek denetimi başarısız oldu", - "agentRequirements.skill.missing": "Yüklü değil", - "agentRequirements.mcp.connected": "Bağlı", - "agentRequirements.mcp.checkFailed": "MCP denetimi başarısız oldu", - "agentRequirements.mcp.missing": "Bağlı değil", - "agentRequirements.extension.installed": "Yüklü", - "agentRequirements.extension.checkFailed": "VS Code uzantısı denetimi başarısız oldu", - "agentRequirements.extension.missing": "Yüklü değil", - "agentRequirements.extension.description": "Eksik uzantıları VS Code içinde yükleyin.", - "agentRequirements.group.skills": "Yetenekler", - "agentRequirements.group.mcps": "MCP’ler", - "agentRequirements.group.extensions": "VS Code Uzantıları", - "agentRequirements.blocked.title": "{{agent}} ajanı ön koşulları", - "agentRequirements.blocked.description": "Bu ajanın çalışmadan önce aşağıdaki araçlara ihtiyacı var.", - "agentRequirements.prompt.blocked": "Bu ajanı kullanmak için önce gerekli denetimleri tamamlayın", - "agentRequirements.action.openMarketplace": "Marketplace’i Aç", - "agentRequirements.error.unknownAgent": "Seçili ajan bulunamadı.", - "agentRequirements.error.malformedDeclaration": "Bu ajanın geçersiz bir gereksinim bildirimi var.", - "agentRequirements.error.discoveryFailed": "Kilo mevcut yetenekleri denetleyemedi.", - "agentRequirements.error.mcpStatusFailed": "Kilo MCP sunucu durumunu denetleyemedi.", - "agentRequirements.error.scopeMismatch": "Bu ajan gereksinimi denetimi artık etkin değil.", - "agentRequirements.error.requestFailed": "Kilo ajan gereksinimlerini denetleyemedi.", - "dialog.provider.search.placeholder": "Sağlayıcı ara", "dialog.provider.empty": "Sağlayıcı bulunamadı", "dialog.provider.group.other": "Diğer", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/uk.ts b/packages/kilo-vscode/webview-ui/src/i18n/uk.ts index ac57b15f921..2a4a83f6a5d 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/uk.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/uk.ts @@ -78,30 +78,6 @@ export const dict = { "command.session.compact": "Стиснути сесію", "command.session.export": "Експортувати запис сеансу", - "agentRequirements.skill.installed": "Встановлено", - "agentRequirements.skill.checkFailed": "Не вдалося перевірити навичку", - "agentRequirements.skill.missing": "Не встановлено", - "agentRequirements.mcp.connected": "Підключено", - "agentRequirements.mcp.checkFailed": "Не вдалося перевірити MCP", - "agentRequirements.mcp.missing": "Не підключено", - "agentRequirements.extension.installed": "Встановлено", - "agentRequirements.extension.checkFailed": "Не вдалося перевірити розширення VS Code", - "agentRequirements.extension.missing": "Не встановлено", - "agentRequirements.extension.description": "Встановіть відсутні розширення у VS Code.", - "agentRequirements.group.skills": "Навички", - "agentRequirements.group.mcps": "MCP", - "agentRequirements.group.extensions": "Розширення VS Code", - "agentRequirements.blocked.title": "Передумови агента {{agent}}", - "agentRequirements.blocked.description": "Цьому агенту потрібні такі інструменти, перш ніж він зможе працювати.", - "agentRequirements.prompt.blocked": "Спочатку завершіть необхідні перевірки, щоб використати цього агента", - "agentRequirements.action.openMarketplace": "Відкрити Marketplace", - "agentRequirements.error.unknownAgent": "Вибраного агента не знайдено.", - "agentRequirements.error.malformedDeclaration": "Цей агент має недійсну декларацію вимог.", - "agentRequirements.error.discoveryFailed": "Kilo не зміг перевірити доступні навички.", - "agentRequirements.error.mcpStatusFailed": "Kilo не зміг перевірити стан сервера MCP.", - "agentRequirements.error.scopeMismatch": "Ця перевірка вимог агента більше не активна.", - "agentRequirements.error.requestFailed": "Kilo не зміг перевірити вимоги агента.", - "dialog.provider.search.placeholder": "Пошук провайдера", "dialog.provider.empty": "Провайдерів не знайдено", "dialog.provider.group.other": "Інші", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts index e26c9297327..9bcb98ec753 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts @@ -76,30 +76,6 @@ export const dict = { "command.session.compact": "精简会话", "command.session.export": "导出会话记录", - "agentRequirements.skill.installed": "已安装", - "agentRequirements.skill.checkFailed": "技能检查失败", - "agentRequirements.skill.missing": "未安装", - "agentRequirements.mcp.connected": "已连接", - "agentRequirements.mcp.checkFailed": "MCP 检查失败", - "agentRequirements.mcp.missing": "未连接", - "agentRequirements.extension.installed": "已安装", - "agentRequirements.extension.checkFailed": "VS Code 扩展检查失败", - "agentRequirements.extension.missing": "未安装", - "agentRequirements.extension.description": "在 VS Code 中安装缺少的扩展。", - "agentRequirements.group.skills": "技能", - "agentRequirements.group.mcps": "MCP", - "agentRequirements.group.extensions": "VS Code 扩展", - "agentRequirements.blocked.title": "{{agent}} 代理前置要求", - "agentRequirements.blocked.description": "此代理需要以下工具后才能运行。", - "agentRequirements.prompt.blocked": "请先完成所需检查,然后再使用此代理", - "agentRequirements.action.openMarketplace": "打开 Marketplace", - "agentRequirements.error.unknownAgent": "找不到所选代理。", - "agentRequirements.error.malformedDeclaration": "此代理的要求声明无效。", - "agentRequirements.error.discoveryFailed": "Kilo 无法检查可用技能。", - "agentRequirements.error.mcpStatusFailed": "Kilo 无法检查 MCP 服务器状态。", - "agentRequirements.error.scopeMismatch": "此代理要求检查已不再有效。", - "agentRequirements.error.requestFailed": "Kilo 无法检查代理要求。", - "dialog.provider.search.placeholder": "搜索提供商", "dialog.provider.empty": "未找到提供商", "dialog.provider.group.other": "其他", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts index 8261f0982aa..bd01b570536 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts @@ -76,30 +76,6 @@ export const dict = { "command.session.compact": "精簡工作階段", "command.session.export": "匯出會話紀錄", - "agentRequirements.skill.installed": "已安裝", - "agentRequirements.skill.checkFailed": "技能檢查失敗", - "agentRequirements.skill.missing": "未安裝", - "agentRequirements.mcp.connected": "已連線", - "agentRequirements.mcp.checkFailed": "MCP 檢查失敗", - "agentRequirements.mcp.missing": "未連線", - "agentRequirements.extension.installed": "已安裝", - "agentRequirements.extension.checkFailed": "VS Code 擴充功能檢查失敗", - "agentRequirements.extension.missing": "未安裝", - "agentRequirements.extension.description": "在 VS Code 中安裝缺少的擴充功能。", - "agentRequirements.group.skills": "技能", - "agentRequirements.group.mcps": "MCP", - "agentRequirements.group.extensions": "VS Code 擴充功能", - "agentRequirements.blocked.title": "{{agent}} 代理前置需求", - "agentRequirements.blocked.description": "此代理需要以下工具後才能執行。", - "agentRequirements.prompt.blocked": "請先完成必要檢查,才能使用此代理", - "agentRequirements.action.openMarketplace": "開啟 Marketplace", - "agentRequirements.error.unknownAgent": "找不到所選代理。", - "agentRequirements.error.malformedDeclaration": "此代理的需求宣告無效。", - "agentRequirements.error.discoveryFailed": "Kilo 無法檢查可用技能。", - "agentRequirements.error.mcpStatusFailed": "Kilo 無法檢查 MCP 伺服器狀態。", - "agentRequirements.error.scopeMismatch": "此代理需求檢查已不再有效。", - "agentRequirements.error.requestFailed": "Kilo 無法檢查代理需求。", - "dialog.provider.search.placeholder": "搜尋供應商", "dialog.provider.empty": "找不到供應商", "dialog.provider.group.other": "其他", diff --git a/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx b/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx index 4a9b503685b..02995df7b48 100644 --- a/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx +++ b/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx @@ -30,7 +30,6 @@ import { Diff } from "@kilocode/kilo-ui/diff" import { Code } from "@kilocode/kilo-ui/code" import { File } from "@kilocode/kilo-ui/file" import { SessionContext } from "../context/session" -import { AgentRequirementsContext, type AgentRequirementsContextValue } from "../context/agent-requirements" import { NotificationsContext } from "../context/notifications" import { LanguageContext } from "../context/language" import { IndexingProvider } from "../context/indexing" @@ -52,7 +51,6 @@ import type { SessionCloseReason, QuestionRequest, SuggestionRequest, - AgentRequirementResult, } from "../types/messages" type PluginSpec = string | [string, Record] @@ -299,9 +297,6 @@ interface StoryProvidersProps { questions?: QuestionRequest[] suggestions?: SuggestionRequest[] notifications?: KilocodeNotification[] - agentRequirements?: AgentRequirementResult - agentRequirementsChecking?: boolean - agentRequirementsBlocked?: boolean status?: string sessionID?: string /** When provided, injects a mock ConfigContext with this config instead of the real ConfigProvider. */ @@ -416,23 +411,6 @@ export const StoryProviders: ParentComponent = (props) => { }) const notifications = mockNotificationsValue(props.notifications) const [locale] = createSignal<"en">("en") - const result = () => props.agentRequirements - const visible = () => { - const value = result() - return value?.state === "blocked" || value?.state === "error" - } - const requirements: AgentRequirementsContextValue = { - result, - checking: () => props.agentRequirementsChecking ?? false, - blocked: () => { - if (props.agentRequirementsBlocked !== undefined) return props.agentRequirementsBlocked - const value = result() - if (!value) return props.agentRequirementsChecking === true - return value.enabled && (value.state === "blocked" || value.state === "error") - }, - visible, - } - return ( @@ -460,36 +438,34 @@ export const StoryProviders: ParentComponent = (props) => { "en", t, plural }}> - - - - - - - - - - - {props.noPadding ? ( - props.children - ) : ( -
{props.children}
- )} - - - - - - - - - - + + + + + + + + + + {props.noPadding ? ( + props.children + ) : ( +
{props.children}
+ )} +
+
+
+
+
+
+
+
+
diff --git a/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx b/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx index e141b2482d6..92fad1fd253 100644 --- a/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx +++ b/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx @@ -26,7 +26,6 @@ import { ProviderContext } from "../context/provider" import { ServerContext } from "../context/server" import { WorktreeModeProvider } from "../context/worktree-mode" import type { - AgentRequirementResult, Message, Part, QuestionRequest, @@ -40,68 +39,6 @@ import { reviewMetadata } from "../../../src/shared/review-comments" const SESSION_ID = "story-session-chat-001" -const missingToolsRequirements: AgentRequirementResult = { - agent: "code-review", - directory: "/project", - enabled: true, - state: "blocked", - skills: [ - { name: "review-checklist", status: "ready" }, - { name: "security-audit", status: "missing" }, - ], - mcps: [ - { name: "github", status: "missing" }, - { name: "filesystem", status: "ready" }, - ], - vscode_extensions: [], -} - -const missingExtensionRequirements: AgentRequirementResult = { - agent: "release-review", - directory: "/project", - enabled: true, - state: "blocked", - skills: [], - mcps: [], - vscode_extensions: [ - { - name: "GitHub Pull Requests", - id: "github.vscode-pull-request-github", - status: "missing", - }, - ], -} - -const malformedRequirements: AgentRequirementResult = { - agent: "malformed-agent", - directory: "/project", - enabled: true, - state: "error", - skills: [], - mcps: [], - vscode_extensions: [], - error: { - code: "malformed_declaration", - message: "Invalid requirements declaration.", - }, -} - -const readyRequirements: AgentRequirementResult = { - agent: "ready-agent", - directory: "/project", - enabled: true, - state: "ready", - skills: [{ name: "review-checklist", status: "ready" }], - mcps: [{ name: "filesystem", status: "ready" }], - vscode_extensions: [ - { - name: "GitHub Pull Requests", - id: "github.vscode-pull-request-github", - status: "ready", - }, - ], -} - // --------------------------------------------------------------------------- // Question fixtures // --------------------------------------------------------------------------- @@ -228,71 +165,6 @@ export const ChatViewWithMessages: Story = { }, } -export const ChatViewRequirementsChecking: Story = { - name: "ChatView — agent requirements checking", - render: () => ( - - -
- -
-
-
- ), -} - -export const ChatViewRequirementsMissingTools: Story = { - name: "ChatView — missing skills and MCPs", - render: () => ( - - -
- -
-
-
- ), -} - -export const ChatViewRequirementsMissingExtension: Story = { - name: "ChatView — missing VS Code extension", - render: () => ( - - -
- -
-
-
- ), -} - -export const ChatViewRequirementsMalformed: Story = { - name: "ChatView — malformed agent requirements", - render: () => ( - - -
- -
-
-
- ), -} - -export const ChatViewRequirementsReady: Story = { - name: "ChatView — requirements ready (no card)", - render: () => ( - - -
- -
-
-
- ), -} - export const ChatViewAgentManagerCompleted: Story = { name: "ChatView — completed Agent Manager session actions", render: () => { diff --git a/packages/kilo-vscode/webview-ui/src/styles/agent-requirements.css b/packages/kilo-vscode/webview-ui/src/styles/agent-requirements.css deleted file mode 100644 index 56ee5181ed2..00000000000 --- a/packages/kilo-vscode/webview-ui/src/styles/agent-requirements.css +++ /dev/null @@ -1,294 +0,0 @@ -/* ============================================ - Agent Requirements - ============================================ */ - -.agent-requirements { - height: 100%; - overflow: auto; - display: flex; - align-items: center; - justify-content: center; - box-sizing: border-box; - padding: 16px var(--chat-gutter, 16px); - animation: agent-requirements-enter 360ms ease-out 100ms both; -} - -[data-component="card"].agent-requirements-card { - width: 100%; - max-width: 430px; - display: flex; - flex-direction: column; - gap: 20px; - padding: 18px; - border: 1px solid var(--border-weak-base, var(--vscode-panel-border)); - border-radius: 10px; - background: var(--vscode-editorWidget-background); - color: var(--vscode-foreground); - text-align: left; - box-shadow: 0 12px 32px rgb(0 0 0 / 22%); -} - -@keyframes agent-requirements-enter { - from { - opacity: 0; - transform: translateY(10px); - } - - to { - opacity: 1; - transform: translateY(0); - } -} - -@media (prefers-reduced-motion: reduce) { - .agent-requirements { - animation: none; - } -} - -[data-slot="agent-requirements-copy"] { - display: flex; - flex-direction: column; - gap: 8px; -} - -[data-slot="agent-requirements-title-row"] { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; -} - -[data-slot="agent-requirements-title"] { - margin: 0; - color: var(--vscode-foreground); - font-size: var(--kilo-font-size-14); - font-weight: 650; - line-height: 1.35; -} - -[data-slot="agent-requirements-title-row"] > [data-component="icon"] { - --icon-base: var(--icon-success-base); - flex: 0 0 auto; -} - -[data-slot="agent-requirements-description"] { - margin: 0; - color: var(--text-weak-base, var(--vscode-descriptionForeground)); - font-size: var(--kilo-font-size-12); - line-height: 1.45; -} - -.agent-requirements-error { - margin: 0; - padding: 10px; - border: 1px solid var(--border-critical-base); - border-radius: 8px; - background: color-mix(in srgb, var(--surface-critical-base) 34%, var(--vscode-editor-background)); - color: var(--text-on-critical-base); - font-size: var(--kilo-font-size-12); - line-height: 1.45; -} - -[data-slot="agent-requirements-options"] { - display: grid; - grid-template-columns: 1fr; - gap: 16px; - min-width: 0; -} - -.agent-requirements-category { - display: flex; - flex-direction: column; - gap: 10px; - min-width: 0; -} - -[data-slot="agent-requirements-category-copy"] { - display: flex; - flex-direction: column; - gap: 4px; -} - -[data-slot="agent-requirements-category-title"] { - margin: 0; - color: var(--vscode-textLink-foreground); - font-size: var(--kilo-font-size-11); - font-weight: 650; - line-height: 1.25; - letter-spacing: 0.04em; - text-transform: uppercase; -} - -[data-slot="agent-requirements-category-description"] { - margin: 0; - color: var(--text-weak-base, var(--vscode-descriptionForeground)); - font-size: var(--kilo-font-size-12); - line-height: 1.4; -} - -[data-slot="agent-requirements-category-content"] { - display: flex; - flex-direction: column; - gap: 14px; - min-width: 0; -} - -.agent-requirements-group { - display: flex; - flex-direction: column; - gap: 8px; - min-width: 0; - color: var(--vscode-foreground); -} - -[data-slot="agent-requirements-group-title"] { - margin: 0; - color: var(--vscode-foreground); - font-size: var(--kilo-font-size-12); - font-weight: 650; - line-height: 1.35; -} - -[data-slot="agent-requirements-list"] { - display: flex; - flex-direction: column; - gap: 6px; - margin: 0; - padding: 0; - color: var(--vscode-foreground); - list-style: none; - font-size: var(--kilo-font-size-12); - line-height: 1.4; -} - -.agent-requirements-line { - display: flex; - align-items: center; - gap: 10px; - min-width: 0; - padding: 7px 0; - border-bottom: 1px solid color-mix(in srgb, var(--border-weak-base, var(--vscode-panel-border)) 60%, transparent); -} - -.agent-requirements-line:last-child { - border-bottom: 0; -} - -[data-slot="agent-requirements-status"] { - width: 22px; - height: 22px; - display: inline-flex; - align-items: center; - justify-content: center; - flex: 0 0 auto; - border-radius: 6px; -} - -[data-slot="agent-requirements-status"][data-status="ready"] { - color: var(--vscode-charts-green, #89d185); - background: color-mix(in srgb, var(--vscode-charts-green, #89d185) 12%, transparent); -} - -[data-slot="agent-requirements-status"][data-status="missing"] { - color: var(--vscode-charts-yellow, #e2c08d); - background: color-mix(in srgb, var(--vscode-charts-yellow, #e2c08d) 13%, transparent); -} - -[data-slot="agent-requirements-status"][data-status="error"] { - color: var(--icon-critical-base); - background: color-mix(in srgb, var(--surface-critical-base) 50%, transparent); -} - -[data-slot="agent-requirements-status"] [data-component="icon"], -[data-slot="agent-requirements-status"] [data-component="spinner"] { - width: 14px; - height: 14px; -} - -[data-slot="agent-requirements-line-row"] { - display: flex; - align-items: baseline; - justify-content: space-between; - flex: 1; - gap: 12px; - min-width: 0; -} - -[data-slot="agent-requirements-line-name"] { - min-width: 0; - overflow-wrap: anywhere; - color: var(--vscode-foreground); -} - -[data-slot="agent-requirements-line-detail"] { - flex: 0 0 auto; - max-width: 48%; - overflow-wrap: anywhere; - color: var(--text-weak-base, var(--vscode-descriptionForeground)); - font-size: var(--kilo-font-size-11); - line-height: 1.35; - text-align: right; -} - -.agent-requirements-line[data-status="ready"] [data-slot="agent-requirements-line-detail"] { - color: var(--vscode-charts-green, #89d185); - font-weight: 600; -} - -.agent-requirements-line[data-status="missing"] [data-slot="agent-requirements-line-detail"] { - color: var(--vscode-charts-yellow, #e2c08d); -} - -.agent-requirements-line[data-status="error"] [data-slot="agent-requirements-line-detail"] { - color: var(--text-on-critical-base, var(--vscode-errorForeground)); -} - -[data-slot="agent-requirements-extension-note"] { - margin: 0; - color: var(--text-weak-base, var(--vscode-descriptionForeground)); - font-size: var(--kilo-font-size-11); - line-height: 1.4; -} - -.agent-requirements-actions { - display: flex; - justify-content: flex-end; - flex-wrap: wrap; - gap: 8px; -} - -@container chat (max-width: 320px) { - .agent-requirements { - align-items: flex-start; - padding: 12px 8px; - } - - [data-component="card"].agent-requirements-card { - gap: 16px; - padding: 12px; - } - - [data-slot="agent-requirements-options"] { - gap: 12px; - } - - .agent-requirements-line { - align-items: flex-start; - } - - [data-slot="agent-requirements-line-row"] { - flex-direction: column; - align-items: flex-start; - gap: 2px; - } - - [data-slot="agent-requirements-line-detail"] { - max-width: 100%; - text-align: left; - } - - .agent-requirements-actions { - flex-direction: column; - } -} diff --git a/packages/kilo-vscode/webview-ui/src/styles/chat.css b/packages/kilo-vscode/webview-ui/src/styles/chat.css index 6f752069190..97026cb8f29 100644 --- a/packages/kilo-vscode/webview-ui/src/styles/chat.css +++ b/packages/kilo-vscode/webview-ui/src/styles/chat.css @@ -15,7 +15,6 @@ @import "./session-actions.css"; @import "./welcome.css"; @import "./prompt-input.css"; -@import "./agent-requirements.css"; @import "./prompt-dropdowns.css"; @import "./model-selector.css"; @import "./permission-dock.css"; diff --git a/packages/kilo-vscode/webview-ui/src/types/marketplace.ts b/packages/kilo-vscode/webview-ui/src/types/marketplace.ts index f0a8fea7c90..a56afcfd226 100644 --- a/packages/kilo-vscode/webview-ui/src/types/marketplace.ts +++ b/packages/kilo-vscode/webview-ui/src/types/marketplace.ts @@ -41,11 +41,6 @@ export interface AgentContent { prompt: string options?: Record permission?: Record - requirements?: { - skills?: string[] - mcps?: string[] - vscode_extensions?: Array<{ name: string; id: string }> - } } export interface AgentMarketplaceItem extends MarketplaceItemBase { diff --git a/packages/kilo-vscode/webview-ui/src/types/messages/agents.ts b/packages/kilo-vscode/webview-ui/src/types/messages/agents.ts index 928f3c6aaa4..ecf1f5de02c 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages/agents.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages/agents.ts @@ -32,51 +32,6 @@ export interface AgentInfo { permission?: PermissionRuleItem[] } -export interface AgentRequirementSkill { - name: string - status: "ready" | "missing" | "error" - message?: string -} - -export interface AgentRequirementMCP { - name: string - status: "ready" | "missing" | "error" - message?: string -} - -export interface AgentRequirementVSCodeExtension { - name: string - id: string - status: "ready" | "missing" | "error" - message?: string -} - -export interface AgentRequirementResult { - agent: string - directory: string - enabled: boolean - state: "disabled" | "ready" | "blocked" | "error" - skills: AgentRequirementSkill[] - mcps: AgentRequirementMCP[] - vscode_extensions: AgentRequirementVSCodeExtension[] - error?: { - code: - | "unknown_agent" - | "malformed_declaration" - | "discovery_failed" - | "mcp_status_failed" - | "scope_mismatch" - | "request_failed" - message: string - } -} - -export interface AgentRequirements { - skills?: string[] - mcps?: string[] - vscode_extensions?: Array<{ name: string; id: string }> -} - export interface AgentConfig { model?: string | null variant?: string | null @@ -88,6 +43,5 @@ export interface AgentConfig { temperature?: number | null top_p?: number | null steps?: number | null - requirements?: AgentRequirements permission?: PermissionConfig } diff --git a/packages/kilo-vscode/webview-ui/src/types/messages/config.ts b/packages/kilo-vscode/webview-ui/src/types/messages/config.ts index fc4af811365..ccca1426483 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages/config.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages/config.ts @@ -52,7 +52,6 @@ export interface ExperimentalConfig { batch_tool?: boolean image_generation?: boolean image_generation_model?: string - agent_requirements?: boolean native_notebook_tools?: boolean speech_to_text_model?: string primary_tools?: string[] diff --git a/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts index fda0c747d5a..e08d78352a1 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts @@ -20,7 +20,7 @@ import type { AnacondaDesktopExtensionMessage } from "../../../../src/shared/ana import type { QuestionRequest, SuggestionRequest, TodoItem } from "./questions" import type { ModelSelection, ModelUsageMap, Provider, ProviderAuthState } from "./providers" import type { SpeechToTextModelDef } from "../../../../src/speech-to-text/models" -import type { AgentInfo, AgentRequirementResult, SkillInfo, SlashCommandInfo } from "./agents" +import type { AgentInfo, SkillInfo, SlashCommandInfo } from "./agents" import type { BrowserSettings, Config, @@ -412,15 +412,6 @@ export interface SkillsLoadedMessage { skills: SkillInfo[] } -export interface AgentRequirementsLoadedMessage { - type: "agentRequirementsLoaded" - result: AgentRequirementResult -} - -export interface AgentRequirementsInvalidatedMessage { - type: "agentRequirementsInvalidated" -} - export interface CommandsLoadedMessage { type: "commandsLoaded" commands: SlashCommandInfo[] @@ -1335,8 +1326,6 @@ export type ExtensionMessage = | ProvidersLoadedMessage | AgentsLoadedMessage | SkillsLoadedMessage - | AgentRequirementsLoadedMessage - | AgentRequirementsInvalidatedMessage | CommandsLoadedMessage | AutocompleteSettingsLoadedMessage | ChatCompletionResultMessage diff --git a/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts index c271ceaca20..3f11882333b 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts @@ -273,14 +273,6 @@ export interface RequestSkillsMessage { type: "requestSkills" } -export interface RequestAgentRequirementsMessage { - type: "requestAgentRequirements" - agent: string - directory: string - sessionID?: string - force?: boolean -} - export interface RequestCommandsMessage { type: "requestCommands" } @@ -442,6 +434,7 @@ export interface RequestTerminalContextMessage { type: "requestTerminalContext" requestId: string sessionID?: string + agentManagerContext?: string } export interface RequestGitChangesContextMessage { @@ -1434,7 +1427,6 @@ export type WebviewMessage = | CompactRequest | RequestAgentsMessage | RequestSkillsMessage - | RequestAgentRequirementsMessage | RequestCommandsMessage | SendCommandRequest | RemoveSkillMessage diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts index 4ba811299b0..f43327030d9 100644 --- a/packages/opencode/src/agent/agent.ts +++ b/packages/opencode/src/agent/agent.ts @@ -30,9 +30,7 @@ import { AbsolutePath, type DeepMutable } from "@opencode-ai/core/schema" // kilocode_change start import * as KiloAgent from "@/kilocode/agent" import { RuntimeFlags } from "@/effect/runtime-flags" -import * as AgentRequirements from "@/kilocode/agent-requirements" import * as KiloReference from "@/kilocode/reference" -import { MCP } from "@/mcp" // kilocode_change end import { ProviderV2 } from "@opencode-ai/core/provider" import { ModelV2 } from "@opencode-ai/core/model" @@ -41,8 +39,6 @@ import { Reference } from "@opencode-ai/core/reference" import { Location } from "@opencode-ai/core/location" import { PluginV2 } from "@opencode-ai/core/plugin" -export type RequirementBlockedError = InstanceType // kilocode_change - export const Info = Schema.Struct({ name: Schema.String, // kilocode_change start @@ -67,7 +63,6 @@ export const Info = Schema.Struct({ variant: Schema.optional(Schema.String), prompt: Schema.optional(Schema.String), options: Schema.Record(Schema.String, Schema.Unknown), - requirements: Schema.optional(AgentRequirements.Requirements), // kilocode_change steps: Schema.optional(Schema.Finite), }).annotate({ identifier: "Agent" }) export type Info = DeepMutable> @@ -83,10 +78,6 @@ export interface Interface { readonly list: () => Effect.Effect readonly defaultInfo: () => Effect.Effect readonly defaultAgent: () => Effect.Effect - // kilocode_change start - readonly requirementStatus: (agent: string) => Effect.Effect - readonly guardRequirements: (agent: Info) => Effect.Effect - // kilocode_change end readonly generate: (input: { description: string model?: { providerID: ProviderV2.ID; modelID: ModelV2.ID } @@ -100,7 +91,7 @@ export interface Interface { > } -type State = Omit & { version: string } // kilocode_change +type State = Omit & { version: string } // kilocode_change export class Service extends Context.Service()("@opencode/Agent") {} @@ -113,7 +104,6 @@ const layer = Layer.effect( const auth = yield* Auth.Service const plugin = yield* Plugin.Service const skill = yield* Skill.Service - const mcp = yield* MCP.Service // kilocode_change const provider = yield* Provider.Service const flags = yield* RuntimeFlags.Service // kilocode_change const locations = yield* LocationServiceMap.Service @@ -376,7 +366,6 @@ const layer = Layer.effect( // kilocode_change start - carry metadata as typed fields, never as provider options item.displayName = value.displayName ?? item.displayName item.source = value.source ?? item.source - item.requirements = value.requirements ?? item.requirements // kilocode_change end item.options = mergeDeep(item.options, value.options ?? {}) item.permission = Permission.merge(item.permission, Permission.fromConfig(value.permission ?? {})) @@ -536,31 +525,6 @@ const layer = Layer.effect( return yield* select(yield* InstanceState.get(state)) }) - const requirementStatus = Effect.fn("Agent.requirementStatus")(function* (name: string) { - const ctx = yield* InstanceState.context - return yield* AgentRequirements.status({ - name, - directory: ctx.directory, - config, - skills: skill, - mcp, - agents: { get: (agent) => current((s) => s.get(agent)) }, - }) - }) - - const guardRequirements = Effect.fn("Agent.guardRequirements")(function* (agent: Info) { - const ctx = yield* InstanceState.context - yield* AgentRequirements.guard({ - agent, - directory: ctx.directory, - config, - skills: skill, - mcp, - agents: { get: (name) => current((s) => s.get(name)) }, - }) - }) - // kilocode_change end - return Service.of({ get: Effect.fn("Agent.get")(function* (agent: string) { return yield* current((s) => s.get(agent)) // kilocode_change @@ -574,10 +538,6 @@ const layer = Layer.effect( defaultAgent: Effect.fn("Agent.defaultAgent")(function* () { return yield* current((s) => s.defaultAgent()) // kilocode_change }), - // kilocode_change start - requirementStatus, - guardRequirements, - // kilocode_change end generate: Effect.fn("Agent.generate")(function* (input: { description: string model?: { providerID: ProviderV2.ID; modelID: ModelV2.ID } @@ -653,7 +613,7 @@ const locationServiceMapNode = LayerNode.make({ export const node = LayerNode.make({ service: Service, layer: layer, - deps: [Config.node, Auth.node, Plugin.node, Skill.node, Provider.node, MCP.node, RuntimeFlags.node, locationServiceMapNode], // kilocode_change + deps: [Config.node, Auth.node, Plugin.node, Skill.node, Provider.node, RuntimeFlags.node, locationServiceMapNode], // kilocode_change }) export * as Agent from "./agent" diff --git a/packages/opencode/src/kilocode/agent-requirements.ts b/packages/opencode/src/kilocode/agent-requirements.ts deleted file mode 100644 index f432e2bb2ff..00000000000 --- a/packages/opencode/src/kilocode/agent-requirements.ts +++ /dev/null @@ -1,261 +0,0 @@ -import type { Agent } from "@/agent/agent" -import type { Config } from "@/config/config" -import type { MCP } from "@/mcp" -import type { Skill } from "@/skill" -import { Flag } from "@opencode-ai/core/flag/flag" -import { NamedError } from "@opencode-ai/core/util/error" -import { Cause, Effect, Exit, Schema } from "effect" -import { ConfigAgentV1 } from "@opencode-ai/core/v1/config/agent" - -export const VSCodeExtension = ConfigAgentV1.VSCodeExtension -export type VSCodeExtension = ConfigAgentV1.VSCodeExtension - -export const Requirements = ConfigAgentV1.Requirements -export type Requirements = ConfigAgentV1.Requirements - -export const SkillItem = Schema.Struct({ - name: Schema.String, - status: Schema.Literals(["ready", "missing", "error"]), - message: Schema.optional(Schema.String), -}) -export type SkillItem = Schema.Schema.Type - -export const MCPItem = Schema.Struct({ - name: Schema.String, - status: Schema.Literals(["ready", "missing", "error"]), - message: Schema.optional(Schema.String), -}) -export type MCPItem = Schema.Schema.Type - -export const Result = Schema.Struct({ - agent: Schema.String, - directory: Schema.String, - enabled: Schema.Boolean, - state: Schema.Literals(["disabled", "ready", "blocked", "error"]), - skills: Schema.Array(SkillItem), - mcps: Schema.Array(MCPItem), - vscode_extensions: Schema.Array(VSCodeExtension), - error: Schema.optional( - Schema.Struct({ - code: Schema.Literals(["unknown_agent", "malformed_declaration", "discovery_failed", "mcp_status_failed"]), - message: Schema.String, - }), - ), -}).annotate({ identifier: "AgentRequirementResult" }) -export type Result = Schema.Schema.Type - -export const BlockedError = NamedError.create("AgentRequirementError", { - message: Schema.String, - agent: Schema.String, - directory: Schema.String, - state: Schema.Literals(["blocked", "error"]), - skills: Schema.mutable(Schema.Array(SkillItem)), - mcps: Schema.mutable(Schema.Array(MCPItem)), - vscode_extensions: Schema.mutable(Schema.Array(VSCodeExtension)), -}) - -type AgentInfo = Pick & { requirements?: unknown } - -type Services = { - config: Pick - agents: { get: (agent: string) => Effect.Effect } - skills: Pick - mcp: Pick -} - -function enabled(cfg: Config.Info) { - const experimental = cfg.experimental - return experimental !== undefined && "agent_requirements" in experimental && experimental.agent_requirements === true -} - -function ready(input: { agent: string; directory: string; enabled: boolean }): Result { - return { - ...input, - state: input.enabled ? "ready" : "disabled", - skills: [], - mcps: [], - vscode_extensions: [], - } -} - -function malformed(agent: AgentInfo, directory: string, message: string): Result { - return { - agent: agent.name, - directory, - enabled: true, - state: "error", - skills: [], - mcps: [], - vscode_extensions: [], - error: { code: "malformed_declaration", message }, - } -} - -function decode(agent: AgentInfo, directory: string): Requirements | Result { - if (agent.requirements === undefined) return ready({ agent: agent.name, directory, enabled: true }) - - const decoded = Schema.decodeUnknownExit(Requirements)(agent.requirements, { - errors: "all", - propertyOrder: "original", - }) - if (Exit.isFailure(decoded)) return malformed(agent, directory, Cause.pretty(decoded.cause)) - return decoded.value -} - -function item(name: string, status: MCP.Status | undefined): MCPItem { - if (status?.status === "connected") return { name, status: "ready" } - if (status?.status === "failed" || status?.status === "needs_client_registration") { - return { name, status: "error", message: status.error } - } - return { name, status: "missing" } -} - -export function evaluate(input: { - agent: AgentInfo - directory: string - enabled: boolean - requirements: Requirements - discovered?: ReadonlySet - discoveryError?: string - mcp?: Readonly> - mcpError?: string -}): Result { - if (!input.enabled) return ready({ agent: input.agent.name, directory: input.directory, enabled: false }) - - const skills = (input.requirements.skills ?? []).map((skill) => ({ - name: skill, - status: input.discoveryError - ? ("error" as const) - : input.discovered?.has(skill) - ? ("ready" as const) - : ("missing" as const), - ...(input.discoveryError ? { message: input.discoveryError } : {}), - })) - const mcps = (input.requirements.mcps ?? []).map((name) => { - if (input.mcpError) return { name, status: "error" as const, message: input.mcpError } - return item(name, input.mcp?.[name]) - }) - - if (input.discoveryError) { - return { - agent: input.agent.name, - directory: input.directory, - enabled: true, - state: "error", - skills, - mcps, - vscode_extensions: input.requirements.vscode_extensions ?? [], - error: { code: "discovery_failed", message: input.discoveryError }, - } - } - - if (input.mcpError) { - return { - agent: input.agent.name, - directory: input.directory, - enabled: true, - state: "error", - skills, - mcps, - vscode_extensions: input.requirements.vscode_extensions ?? [], - error: { code: "mcp_status_failed", message: input.mcpError }, - } - } - - const valid = skills.every((skill) => skill.status === "ready") && mcps.every((mcp) => mcp.status === "ready") - return { - agent: input.agent.name, - directory: input.directory, - enabled: true, - state: valid ? "ready" : "blocked", - skills, - mcps, - vscode_extensions: input.requirements.vscode_extensions ?? [], - } -} - -export const status = Effect.fn("AgentRequirements.status")(function* ( - input: Services & { name: string; directory: string }, -) { - const cfg = yield* input.config.get() - const active = enabled(cfg) - if (!active) return ready({ agent: input.name, directory: input.directory, enabled: false }) - - const agent = yield* input.agents.get(input.name) - if (!agent) { - return { - agent: input.name, - directory: input.directory, - enabled: true, - state: "error", - skills: [], - mcps: [], - vscode_extensions: [], - error: { code: "unknown_agent", message: `Agent not found: ${input.name}` }, - } satisfies Result - } - - const requirements = decode(agent, input.directory) - if ("state" in requirements) return requirements - - const skillStatus: Effect.Effect = requirements.skills?.length ? input.skills.all() : Effect.succeed([]) - const mcpStatus: Effect.Effect> = requirements.mcps?.length - ? input.mcp.status() - : Effect.succeed({}) - const [discovered, mcp] = yield* Effect.all([skillStatus.pipe(Effect.exit), mcpStatus.pipe(Effect.exit)]) - const discoveredSet: ReadonlySet | undefined = Exit.isSuccess(discovered) - ? new Set(discovered.value.map((skill) => skill.name)) - : undefined - - if (Exit.isFailure(discovered)) { - return evaluate({ - agent, - directory: input.directory, - enabled: active, - requirements, - discoveryError: Cause.pretty(discovered.cause), - mcp: Exit.isSuccess(mcp) ? mcp.value : undefined, - }) - } - - if (Exit.isFailure(mcp)) { - return evaluate({ - agent, - directory: input.directory, - enabled: active, - requirements, - discovered: discoveredSet, - mcpError: Cause.pretty(mcp.cause), - }) - } - - return evaluate({ - agent, - directory: input.directory, - enabled: active, - requirements, - discovered: discoveredSet, - mcp: mcp.value, - }) -}) - -export const guard = Effect.fn("AgentRequirements.guard")(function* ( - input: Services & { agent: AgentInfo; directory: string }, -) { - const result = yield* status({ ...input, name: input.agent.name }) - const unsupported = Flag.KILO_CLIENT !== "vscode" && result.vscode_extensions.length > 0 - if (result.state === "disabled" || (result.state === "ready" && !unsupported)) return - const state = result.state === "error" ? result.state : "blocked" - - return yield* Effect.fail( - new BlockedError({ - message: "Complete the required checks to use this agent first", - agent: result.agent, - directory: result.directory, - state, - skills: [...result.skills], - mcps: [...result.mcps], - vscode_extensions: [...result.vscode_extensions], - }), - ) -}) diff --git a/packages/opencode/src/kilocode/cli/agent-requirements.ts b/packages/opencode/src/kilocode/cli/agent-requirements.ts deleted file mode 100644 index 9f7aafce198..00000000000 --- a/packages/opencode/src/kilocode/cli/agent-requirements.ts +++ /dev/null @@ -1,116 +0,0 @@ -import type { AgentRequirementResult } from "@kilocode/sdk/v2" -import { isRecord } from "@/util/record" - -type Item = AgentRequirementResult["skills"][number] | AgentRequirementResult["mcps"][number] - -export type Client = { - kilocode: { - agentRequirements: ( - parameters: { agent: string; directory: string }, - options: { throwOnError: true }, - ) => Promise<{ data: AgentRequirementResult }> - } -} - -export type ErrorData = { - message: string - agent: string - directory: string - state: "blocked" | "error" - skills: AgentRequirementResult["skills"] - mcps: AgentRequirementResult["mcps"] - vscode_extensions: AgentRequirementResult["vscode_extensions"] -} - -export type RequirementError = { - name: "AgentRequirementError" - data: ErrorData -} - -export type Check = - | { ok: true; result: AgentRequirementResult } - | { ok: false; result: AgentRequirementResult; error: RequirementError } - -export async function check(input: { client: Client; agent: string; directory: string }): Promise { - const response = await input.client.kilocode.agentRequirements( - { agent: input.agent, directory: input.directory }, - { throwOnError: true }, - ) - if (!blocked(response.data)) return { ok: true, result: response.data } - return { ok: false, result: response.data, error: toError(response.data) } -} - -export function blocked(result: AgentRequirementResult) { - if (!result.enabled || result.state === "disabled") return false - if (result.vscode_extensions.length > 0) return true - return result.state === "blocked" || result.state === "error" -} - -export function toError(result: AgentRequirementResult): RequirementError { - const info = { - message: result.error?.message ?? "Complete the required checks to use this agent first", - agent: result.agent, - directory: result.directory, - state: result.state === "error" ? ("error" as const) : ("blocked" as const), - skills: result.skills, - mcps: result.mcps, - vscode_extensions: result.vscode_extensions, - } - - return { - name: "AgentRequirementError", - data: { - ...info, - message: format(info), - }, - } -} - -export function data(input: unknown): ErrorData | undefined { - if (!isRecord(input)) return undefined - if (input.name !== "AgentRequirementError" || !isRecord(input.data)) return undefined - - const info = input.data - if (typeof info.message !== "string") return undefined - if (typeof info.agent !== "string") return undefined - if (typeof info.directory !== "string") return undefined - if (info.state !== "blocked" && info.state !== "error") return undefined - if (!Array.isArray(info.skills)) return undefined - if (!Array.isArray(info.mcps)) return undefined - if (!Array.isArray(info.vscode_extensions)) return undefined - - return info as ErrorData -} - -export function format(input: ErrorData | RequirementError) { - const info = "data" in input ? input.data : input - const skills = pending(info.skills) - const mcps = pending(info.mcps) - const lines = [`Agent requirements are not met for "${info.agent}".`] - - if (info.vscode_extensions.length) { - lines.push( - "", - "VS Code extensions:", - ...info.vscode_extensions.map((ext) => `- ${ext.name} (${ext.id})`), - "This agent requires VS Code extensions and is not supported in this CLI environment. Use the Kilo VS Code extension instead.", - ) - } - - if (skills.length) lines.push("", "Skills:", ...skills.map((skill) => `- ${item(skill)}`)) - if (mcps.length) lines.push("", "MCP servers:", ...mcps.map((mcp) => `- ${item(mcp)}`)) - - if (skills.length || mcps.length) { - lines.push("", "Install the required skills and configure or connect the required MCP servers, then retry.") - } - return lines.join("\n") -} - -function pending(items: T[]) { - return items.filter((item) => item.status !== "ready") -} - -function item(input: Item) { - const status = input.status === "missing" ? "missing" : "error" - return input.message ? `${input.name} (${status}: ${input.message})` : `${input.name} (${status})` -} diff --git a/packages/opencode/src/kilocode/project-id.ts b/packages/opencode/src/kilocode/project-id.ts index 02d016d9fd6..d0dc68b9493 100644 --- a/packages/opencode/src/kilocode/project-id.ts +++ b/packages/opencode/src/kilocode/project-id.ts @@ -1,6 +1,6 @@ -import { Context, Effect, Layer } from "effect" +import { Cache, Context, Effect, Layer } from "effect" import { Instance } from "@/kilocode/instance" -import { InstanceState } from "@/effect/instance-state" +import { registerDisposer } from "@/effect/instance-registry" import { makeRuntime } from "@/effect/run-service" import path from "path" import { $ } from "bun" @@ -83,9 +83,7 @@ async function getProjectIdFromGit(directory: string): Promise .kilocode/config.json -> git origin URL * @returns Normalized project ID or undefined */ -async function resolveProjectId(): Promise { - const dir = Instance.directory - +async function resolveProjectId(dir: string): Promise { // Priority 1: .kilo/config.json (falls back to .kilocode/config.json) const id = await getProjectIdFromConfig(dir) if (id) return id @@ -104,13 +102,15 @@ export namespace KiloProjectID { export const layer = Layer.effect( Service, Effect.gen(function* () { - const state = yield* InstanceState.make( - Effect.fn("KiloProjectID.state")(function* () { - return { id: yield* Effect.promise(() => resolveProjectId()) } - }), - ) + const cache = yield* Cache.make({ + capacity: Number.POSITIVE_INFINITY, + lookup: (directory) => Effect.promise(() => resolveProjectId(directory)), + }) + const off = registerDisposer((directory) => Effect.runPromise(Cache.invalidate(cache, directory))) + yield* Effect.addFinalizer(() => Effect.sync(off)) + return Service.of({ - get: () => InstanceState.use(state, (s) => s.id), + get: () => Cache.get(cache, Instance.directory), }) }), ) diff --git a/packages/opencode/src/kilocode/server/httpapi/groups/kilocode.ts b/packages/opencode/src/kilocode/server/httpapi/groups/kilocode.ts index b5c486ee970..695bd7468fe 100644 --- a/packages/opencode/src/kilocode/server/httpapi/groups/kilocode.ts +++ b/packages/opencode/src/kilocode/server/httpapi/groups/kilocode.ts @@ -5,11 +5,9 @@ import { InstanceContextMiddleware } from "@/server/routes/instance/httpapi/midd import { WorkspaceRoutingMiddleware, WorkspaceRoutingQuery, - WorkspaceRoutingQueryFields, } from "@/server/routes/instance/httpapi/middleware/workspace-routing" import { described } from "@/server/routes/instance/httpapi/groups/metadata" import { AnacondaDesktopApi } from "./anaconda-desktop" -import { Result as AgentRequirementResult } from "@/kilocode/agent-requirements" import { Failure as AgentManagerFailure, Request as AgentManagerRequest, @@ -42,10 +40,6 @@ export const RemoveAgentPayload = Schema.Struct({ scope: Schema.optional(Scope), }) -export const AgentRequirementQuery = Schema.Struct({ - ...WorkspaceRoutingQueryFields, - agent: Schema.String, -}) export const NotebookReplyPayload = Schema.Struct({ result: NotebookResult }) export const NotebookRejectPayload = Schema.Struct({ error: NotebookFailure }) export const AgentManagerReplyPayload = Schema.Struct({ result: AgentManagerResult }) @@ -53,7 +47,6 @@ export const AgentManagerRejectPayload = Schema.Struct({ error: AgentManagerFail export const KilocodePaths = { heapSnapshot: `${root}/heap/snapshot`, - agentRequirements: `${root}/agent/requirements`, commandFiles: `${root}/command/files`, removeCommand: `${root}/command/remove`, removeSkill: `${root}/skill/remove`, @@ -82,16 +75,6 @@ export const KilocodeApi = HttpApi.make("kilocode") description: "Write a heap snapshot for the CLI process to the log directory.", }), ), - HttpApiEndpoint.get("agentRequirements", KilocodePaths.agentRequirements, { - query: AgentRequirementQuery, - success: described(AgentRequirementResult, "Agent requirement status"), - }).annotateMerge( - OpenApi.annotations({ - identifier: "kilocode.agentRequirements", - summary: "Check agent requirements", - description: "Check whether the selected agent's requirements are available in the request directory.", - }), - ), HttpApiEndpoint.get("commandFiles", KilocodePaths.commandFiles, { query: WorkspaceRoutingQuery, success: described(Schema.Array(CommandFiles.Info), "Command files"), diff --git a/packages/opencode/src/kilocode/server/httpapi/handlers/kilocode.ts b/packages/opencode/src/kilocode/server/httpapi/handlers/kilocode.ts index 922a9dbfa04..fb7698747a4 100644 --- a/packages/opencode/src/kilocode/server/httpapi/handlers/kilocode.ts +++ b/packages/opencode/src/kilocode/server/httpapi/handlers/kilocode.ts @@ -42,12 +42,6 @@ export const kilocodeHandlers = HttpApiBuilder.group(InstanceHttpApi, "kilocode" return yield* Effect.sync(() => HeapSnapshot.write()) }) - const agentRequirements = Effect.fn("KilocodeHttpApi.agentRequirements")(function* (ctx: { - query: { agent: string } - }) { - return yield* agents.requirementStatus(ctx.query.agent) - }) - const commandFiles = Effect.fn("KilocodeHttpApi.commandFiles")(function* () { const instance = yield* InstanceState.context const dirs = yield* config.directories() @@ -177,7 +171,6 @@ export const kilocodeHandlers = HttpApiBuilder.group(InstanceHttpApi, "kilocode" return handlers .handle("heapSnapshot", heapSnapshot) - .handle("agentRequirements", agentRequirements) .handle("commandFiles", commandFiles) .handle("removeCommand", removeCommand) .handle("removeSkill", removeSkill) diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts index 21e4bc65021..ec1a3e0ac0c 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts @@ -1,7 +1,6 @@ import { Image } from "@/image/image" // kilocode_change - classify user image validation defects import { busyMessage, isBusy } from "@/kilocode/database/sqlite-error" // kilocode_change import { KiloSessionHttpApi } from "@/kilocode/server/httpapi/session-fork" // kilocode_change -import { BlockedError as AgentRequirementError } from "@/kilocode/agent-requirements" // kilocode_change import { KiloSessionPromptQueue } from "@/kilocode/session/prompt-queue" // kilocode_change import { PermissionV1 } from "@opencode-ai/core/v1/permission" import { KiloViewers } from "@/kilocode/presence/service" // kilocode_change @@ -342,9 +341,7 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", // kilocode_change end yield* events.publish(Session.Event.Error, { sessionID: ctx.params.sessionID, - error: AgentRequirementError.isInstance(error) - ? error.toObject() - : busy // kilocode_change + error: busy // kilocode_change ? new NamedError.Unknown({ message: busyMessage }).toObject() // kilocode_change : new NamedError.Unknown({ message: Cause.pretty(cause) }).toObject(), // kilocode_change }) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index ded1a808eb1..d325e3937db 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -138,18 +138,14 @@ function isOrphanedInterruptedTool(part: SessionV1.ToolPart) { export interface Interface { readonly cancel: (sessionID: SessionID) => Effect.Effect - // kilocode_change start - prompt can fail on unmet agent requirements readonly prompt: ( input: PromptInput, - ) => Effect.Effect - // kilocode_change end + ) => Effect.Effect readonly loop: (input: LoopInput) => Effect.Effect readonly shell: (input: ShellInput) => Effect.Effect - // kilocode_change start - commands can fail on unmet agent requirements or resume errors readonly command: ( input: CommandInput, - ) => Effect.Effect - // kilocode_change end + ) => Effect.Effect readonly resolvePromptParts: (template: string) => Effect.Effect } @@ -825,8 +821,6 @@ export const layer = Layer.effect( yield* events.publish(Session.Event.Error, { sessionID: input.sessionID, error: error.toObject() }) throw error } - yield* agents.guardRequirements(ag) // kilocode_change - enforce requirements before creating a turn - const model = input.model ?? ag.model ?? (yield* currentModel(input.sessionID)) // kilocode_change start - retain the source session variant across Agent Manager's model-less fork handoff const stored = !input.model && !ag.model ? model : undefined @@ -1984,8 +1978,6 @@ export const layer = Layer.effect( yield* events.publish(Session.Event.Error, { sessionID: input.cmdInput.sessionID, error: error.toObject() }) return yield* Effect.fail(error) } - yield* agents.guardRequirements(agent) - // Resolve model const model = yield* Effect.gen(function* () { if (input.cmdInput.model) return Provider.parseModel(input.cmdInput.model) @@ -2408,8 +2400,6 @@ export const layer = Layer.effect( yield* events.publish(Session.Event.Error, { sessionID: input.sessionID, error: error.toObject() }) throw error } - yield* agents.guardRequirements(agent) // kilocode_change - command agent overrides must satisfy requirements - // kilocode_change start const variant = KiloWorkflowVariant.resolve({ command: cmd, diff --git a/packages/opencode/src/session/session.ts b/packages/opencode/src/session/session.ts index d27e7abcc2c..8bfc34f2cdb 100644 --- a/packages/opencode/src/session/session.ts +++ b/packages/opencode/src/session/session.ts @@ -43,7 +43,6 @@ import { KiloSessionEvent } from "@/kilocode/session/event" import { SessionExport } from "@/kilocode/session-export" import * as SandboxPolicy from "@/kilocode/sandbox/policy" import { carryForkDiff } from "@/kilocode/session-portability/cumulative-diff" // kilocode_change -import { BlockedError as AgentRequirementError } from "@/kilocode/agent-requirements" // kilocode_change end import { Effect, Layer, Option, Context, Schema, Types } from "effect" import { NonNegativeInt, optionalOmitUndefined } from "@opencode-ai/core/schema" @@ -399,8 +398,7 @@ export const Event = { sessionID: Schema.optional(SessionID), // Reuses SessionV1.Assistant.fields.error (already Schema.optional) so // the derived schema keeps the same discriminated-union shape on the event stream. - // kilocode_change - carry pre-message requirement failures over session.error - error: Schema.optional(Schema.Union([SessionV1.Assistant.fields.error, AgentRequirementError.EffectSchema])), + error: SessionV1.Assistant.fields.error, }, }), // kilocode_change start diff --git a/packages/opencode/test/config/config.test.ts b/packages/opencode/test/config/config.test.ts index 3a0f59b3a35..f6af08db5ad 100644 --- a/packages/opencode/test/config/config.test.ts +++ b/packages/opencode/test/config/config.test.ts @@ -1,5 +1,6 @@ import { test, expect, describe, afterEach, beforeEach, spyOn } from "bun:test" import { ConfigV1 } from "@opencode-ai/core/v1/config/config" +import { ConfigAgentV1 } from "@opencode-ai/core/v1/config/agent" // kilocode_change import { LayerNode } from "@opencode-ai/core/effect/layer-node" import { httpClient } from "@opencode-ai/core/effect/app-node-platform" import { Cause, Effect, Exit, Layer, Option } from "effect" @@ -1585,6 +1586,23 @@ test("config parser preserves permission order while rejecting unknown top-level } }) +// kilocode_change start - preserve legacy agent requirement declarations without forwarding them +test("config parser ignores legacy agent requirements", () => { + const config = ConfigParse.schema( + ConfigAgentV1.Info, + { + name: "demo", + requirements: { skills: ["needed"] }, + custom: true, + }, + "agent/demo.md", + ) + + expect(config.options).toEqual({ custom: true }) + expect(config.options).not.toHaveProperty("requirements") +}) +// kilocode_change end + // MCP config merging tests // kilocode_change start - regression for `env` alias on local MCP entries diff --git a/packages/opencode/test/kilocode/agent-requirements-cli.test.ts b/packages/opencode/test/kilocode/agent-requirements-cli.test.ts deleted file mode 100644 index 533269e5f3d..00000000000 --- a/packages/opencode/test/kilocode/agent-requirements-cli.test.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { describe, expect, test } from "bun:test" -import type { AgentRequirementResult } from "@kilocode/sdk/v2" -import { formatError as formatStreamError } from "@/cli/cmd/run/session-data" -import * as Requirements from "@/kilocode/cli/agent-requirements" - -const dir = "/tmp/agent-requirements-cli" - -function result(input: Partial = {}): AgentRequirementResult { - return { - agent: "demo", - directory: dir, - enabled: true, - state: "ready", - skills: [], - mcps: [], - vscode_extensions: [], - ...input, - } -} - -function client(value: AgentRequirementResult): Requirements.Client { - return { - kilocode: { - agentRequirements: async (parameters, options) => { - expect(parameters).toEqual({ agent: value.agent, directory: value.directory }) - expect(options).toEqual({ throwOnError: true }) - return { data: value } - }, - }, - } -} - -async function check(value: AgentRequirementResult) { - return Requirements.check({ client: client(value), agent: value.agent, directory: value.directory }) -} - -describe("CLI agent requirements", () => { - test("allows disabled requirements", async () => { - const output = await check(result({ enabled: false, state: "disabled" })) - - expect(output.ok).toBe(true) - }) - - test("allows ready requirements", async () => { - const output = await check( - result({ - skills: [{ name: "ready-skill", status: "ready" }], - mcps: [{ name: "ready-mcp", status: "ready" }], - }), - ) - - expect(output.ok).toBe(true) - }) - - test("blocks missing skills", async () => { - const output = await check( - result({ - state: "blocked", - skills: [ - { name: "ready-skill", status: "ready" }, - { name: "missing-skill", status: "missing" }, - ], - }), - ) - - expect(output.ok).toBe(false) - if (output.ok) return - expect(output.error).toMatchObject({ - name: "AgentRequirementError", - data: { agent: "demo", state: "blocked" }, - }) - expect(output.error.data.skills).toContainEqual({ name: "missing-skill", status: "missing" }) - }) - - test("blocks missing and error MCPs", async () => { - const output = await check( - result({ - state: "blocked", - mcps: [ - { name: "missing-mcp", status: "missing" }, - { name: "error-mcp", status: "error", message: "server crashed" }, - ], - }), - ) - - expect(output.ok).toBe(false) - if (output.ok) return - expect(output.error.data.mcps).toEqual([ - { name: "missing-mcp", status: "missing" }, - { name: "error-mcp", status: "error", message: "server crashed" }, - ]) - }) - - test("blocks VS Code extension declarations", async () => { - const output = await check( - result({ - vscode_extensions: [{ name: "Sample Extension", id: "publisher.extension" }], - }), - ) - - expect(output.ok).toBe(false) - if (output.ok) return - expect(output.error.data.state).toBe("blocked") - expect(output.error.data.vscode_extensions).toEqual([{ name: "Sample Extension", id: "publisher.extension" }]) - const text = Requirements.format(output.error) - expect(text).toContain("Use the Kilo VS Code extension instead") - expect(text).not.toContain("Install the required skills and configure or connect the required MCP servers") - }) - - test("formats grouped actionable guidance", () => { - const text = Requirements.format( - Requirements.toError( - result({ - state: "error", - error: { code: "discovery_failed", message: "skill scan failed" }, - skills: [ - { name: "ready-skill", status: "ready" }, - { name: "missing-skill", status: "missing" }, - { name: "error-skill", status: "error", message: "skill scan failed" }, - ], - mcps: [ - { name: "missing-mcp", status: "missing" }, - { name: "error-mcp", status: "error", message: "auth failed" }, - ], - vscode_extensions: [{ name: "Sample Extension", id: "publisher.extension" }], - }), - ), - ) - - expect(text).toContain('Agent requirements are not met for "demo".') - expect(text).toContain("VS Code extensions:") - expect(text).toContain("Sample Extension (publisher.extension)") - expect(text).toContain("Skills:") - expect(text).toContain("missing-skill (missing)") - expect(text).toContain("error-skill (error: skill scan failed)") - expect(text).not.toContain("ready-skill (ready)") - expect(text).toContain("MCP servers:") - expect(text).toContain("missing-mcp (missing)") - expect(text).toContain("error-mcp (error: auth failed)") - expect(text).toContain("Install the required skills and configure or connect the required MCP servers, then retry.") - }) - - test("recognizes AgentRequirementError objects", () => { - const error = Requirements.toError(result({ state: "blocked" })) - - expect(Requirements.data(error)).toEqual(error.data) - expect(Requirements.data({ name: "OtherError", data: error.data })).toBeUndefined() - }) - - test("stores grouped guidance on AgentRequirementError message", () => { - const error = Requirements.toError( - result({ - state: "blocked", - skills: [{ name: "missing-skill", status: "missing" }], - }), - ) - const text = Requirements.format(error) - - expect(text).toContain('Agent requirements are not met for "demo".') - expect(text).toContain("Skills:") - expect(text).toContain("missing-skill (missing)") - expect(error.data.message).toBe(text) - }) - - test("formats AgentRequirementError in interactive session errors", () => { - const error = Requirements.toError( - result({ - state: "blocked", - mcps: [{ name: "missing-mcp", status: "missing" }], - }), - ) - const text = Requirements.format(error) - - expect(formatStreamError(error)).toBe(text) - }) -}) diff --git a/packages/opencode/test/kilocode/agent-requirements.test.ts b/packages/opencode/test/kilocode/agent-requirements.test.ts deleted file mode 100644 index 0f7ce55e6ca..00000000000 --- a/packages/opencode/test/kilocode/agent-requirements.test.ts +++ /dev/null @@ -1,307 +0,0 @@ -import { describe, expect, test } from "bun:test" -import { Cause, Effect, Exit } from "effect" -import { ConfigAgentV1 } from "@opencode-ai/core/v1/config/agent" -import { ConfigParse } from "@/config/parse" -import * as AgentRequirements from "@/kilocode/agent-requirements" -import type { MCP } from "@/mcp" -import type { Skill } from "@/skill" - -type Agent = { - name: string - requirements?: unknown -} - -type Input = { - active?: boolean - agents?: Record - skills?: string[] - skillError?: string - mcp?: Record - mcpError?: string -} - -const dir = "/tmp/agent-requirements" - -function services(input: Input = {}) { - return { - config: { - get: () => Effect.succeed({ experimental: input.active ? { agent_requirements: true } : {} }), - }, - agents: { - get: (name: string) => Effect.succeed(input.agents?.[name]), - }, - skills: { - all: () => { - if (input.skillError) return Effect.die(new Error(input.skillError)) - const skills = (input.skills ?? []).map( - (name) => ({ name, location: "test", content: "" }) satisfies Skill.Info, - ) - return Effect.succeed(skills) - }, - }, - mcp: { - status: () => { - if (input.mcpError) return Effect.die(new Error(input.mcpError)) - return Effect.succeed(input.mcp ?? {}) - }, - }, - } -} - -function status(name: string, input: Input) { - return Effect.runPromise(AgentRequirements.status({ ...services(input), name, directory: dir })) -} - -async function client(value: string | undefined, run: () => Promise) { - const prev = process.env.KILO_CLIENT - try { - if (value === undefined) delete process.env.KILO_CLIENT - if (value !== undefined) process.env.KILO_CLIENT = value - await run() - } finally { - if (prev === undefined) delete process.env.KILO_CLIENT - if (prev !== undefined) process.env.KILO_CLIENT = prev - } -} - -describe("agent requirements", () => { - test("returns disabled when the experimental flag is absent", async () => { - const result = await status("missing", {}) - - expect(result).toMatchObject({ - agent: "missing", - directory: dir, - enabled: false, - state: "disabled", - skills: [], - mcps: [], - vscode_extensions: [], - }) - }) - - test("returns ready for agents without requirements", async () => { - const result = await status("demo", { active: true, agents: { demo: { name: "demo" } } }) - - expect(result).toMatchObject({ agent: "demo", directory: dir, enabled: true, state: "ready" }) - }) - - test("reports unknown agents while requirements are enabled", async () => { - const result = await status("missing", { active: true }) - - expect(result.state).toBe("error") - expect(result.error?.code).toBe("unknown_agent") - }) - - test("reports discovered and missing skills", async () => { - const result = await status("demo", { - active: true, - agents: { demo: { name: "demo", requirements: { skills: ["ready", "absent"] } } }, - skills: ["ready"], - }) - - expect(result.state).toBe("blocked") - expect(result.skills).toEqual([ - { name: "ready", status: "ready" }, - { name: "absent", status: "missing" }, - ]) - }) - - test("accepts non-empty marketplace skill and MCP IDs", async () => { - const result = await status("demo", { - active: true, - agents: { - demo: { - name: "demo", - requirements: { skills: ["skill with space"], mcps: ["mcp/with/slash"] }, - }, - }, - skills: ["skill with space"], - mcp: { "mcp/with/slash": { status: "connected" } }, - }) - - expect(result.state).toBe("ready") - expect(result.skills).toEqual([{ name: "skill with space", status: "ready" }]) - expect(result.mcps).toEqual([{ name: "mcp/with/slash", status: "ready" }]) - }) - - test("reports skill discovery failures as errors", async () => { - const result = await status("demo", { - active: true, - agents: { demo: { name: "demo", requirements: { skills: ["needed"] } } }, - skillError: "skill scan failed", - }) - - expect(result.state).toBe("error") - expect(result.error?.code).toBe("discovery_failed") - expect(result.skills[0]?.status).toBe("error") - expect(result.skills[0]?.message).toContain("skill scan failed") - }) - - test("reports malformed and duplicate declarations", async () => { - const empty = await status("empty", { - active: true, - agents: { empty: { name: "empty", requirements: {} } }, - }) - const duplicate = await status("duplicate", { - active: true, - agents: { duplicate: { name: "duplicate", requirements: { skills: ["one", "one"] } } }, - }) - const legacy = await status("legacy", { - active: true, - agents: { legacy: { name: "legacy", requirements: { vscode_extensions: ["publisher.extension"] } } }, - }) - - expect(empty.error?.code).toBe("malformed_declaration") - expect(duplicate.error?.code).toBe("malformed_declaration") - expect(legacy.error?.code).toBe("malformed_declaration") - }) - - test("validates VS Code extension objects", async () => { - const valid = await status("valid", { - active: true, - agents: { - valid: { - name: "valid", - requirements: { vscode_extensions: [{ name: "Sample Extension", id: "publisher.extension" }] }, - }, - }, - }) - const invalid = await status("invalid", { - active: true, - agents: { - invalid: { - name: "invalid", - requirements: { vscode_extensions: [{ name: " ", id: "publisher.extension" }] }, - }, - }, - }) - - expect(valid).toMatchObject({ - state: "ready", - vscode_extensions: [{ name: "Sample Extension", id: "publisher.extension" }], - }) - expect(invalid.state).toBe("error") - expect(invalid.error?.code).toBe("malformed_declaration") - }) - - test("reports MCP connected, missing, and error states", async () => { - const result = await status("demo", { - active: true, - agents: { - demo: { - name: "demo", - requirements: { mcps: ["connected", "disabled", "failed", "registration"] }, - }, - }, - mcp: { - connected: { status: "connected" }, - disabled: { status: "disabled" }, - failed: { status: "failed", error: "server crashed" }, - registration: { status: "needs_client_registration", error: "OAuth required" }, - }, - }) - - expect(result.state).toBe("blocked") - expect(result.mcps).toEqual([ - { name: "connected", status: "ready" }, - { name: "disabled", status: "missing" }, - { name: "failed", status: "error", message: "server crashed" }, - { name: "registration", status: "error", message: "OAuth required" }, - ]) - }) - - test("reports MCP status service failures", async () => { - const result = await status("demo", { - active: true, - agents: { demo: { name: "demo", requirements: { mcps: ["needed"] } } }, - mcpError: "status unavailable", - }) - - expect(result.state).toBe("error") - expect(result.error?.code).toBe("mcp_status_failed") - expect(result.mcps[0]?.status).toBe("error") - expect(result.mcps[0]?.message).toContain("status unavailable") - }) - - test("guards unmet requirements for all clients", async () => { - const missing = { - active: true, - agents: { demo: { name: "demo", requirements: { skills: ["missing"] } } }, - } - - await client("cli", async () => { - const exit = await Effect.runPromiseExit( - AgentRequirements.guard({ ...services(missing), agent: missing.agents.demo, directory: dir }), - ) - expect(Exit.isFailure(exit)).toBe(true) - if (Exit.isSuccess(exit)) return - const error = Cause.squash(exit.cause) - expect(AgentRequirements.BlockedError.isInstance(error)).toBe(true) - }) - - await client("vscode", async () => { - const exit = await Effect.runPromiseExit( - AgentRequirements.guard({ ...services(missing), agent: missing.agents.demo, directory: dir }), - ) - expect(Exit.isFailure(exit)).toBe(true) - if (Exit.isSuccess(exit)) return - const error = Cause.squash(exit.cause) - expect(AgentRequirements.BlockedError.isInstance(error)).toBe(true) - }) - }) - - test("blocks VS Code extension requirements outside VS Code", async () => { - const input = { - active: true, - agents: { - demo: { - name: "demo", - requirements: { vscode_extensions: [{ name: "Jupyter", id: "ms-toolsai.jupyter" }] }, - }, - }, - } - - await client("cli", async () => { - const exit = await Effect.runPromiseExit( - AgentRequirements.guard({ ...services(input), agent: input.agents.demo, directory: dir }), - ) - expect(Exit.isFailure(exit)).toBe(true) - if (Exit.isSuccess(exit)) return - const error = Cause.squash(exit.cause) - expect(AgentRequirements.BlockedError.isInstance(error)).toBe(true) - }) - - await client("vscode", async () => { - await Effect.runPromise(AgentRequirements.guard({ ...services(input), agent: input.agents.demo, directory: dir })) - }) - }) - - test("allows non-VS Code clients when requirements are ready", async () => { - const input = { - active: true, - agents: { demo: { name: "demo", requirements: { skills: ["ready"], mcps: ["connected"] } } }, - skills: ["ready"], - mcp: { connected: { status: "connected" as const } }, - } - - await client("cli", async () => { - await Effect.runPromise(AgentRequirements.guard({ ...services(input), agent: input.agents.demo, directory: dir })) - }) - }) - - test("keeps requirements out of agent options", () => { - const agent = ConfigParse.schema( - ConfigAgentV1.Info, - { - name: "demo", - requirements: { skills: ["needed"] }, - custom: true, - }, - "agent/demo.md", - ) - - expect(agent.requirements).toEqual({ skills: ["needed"] }) - expect(agent.options).toEqual({ custom: true }) - expect(agent.options).not.toHaveProperty("requirements") - }) -}) diff --git a/packages/opencode/test/kilocode/project-id.test.ts b/packages/opencode/test/kilocode/project-id.test.ts index d93dc7a85d0..5d59b7d242e 100644 --- a/packages/opencode/test/kilocode/project-id.test.ts +++ b/packages/opencode/test/kilocode/project-id.test.ts @@ -2,8 +2,9 @@ import { test, expect, describe } from "bun:test" import { tmpdir } from "../fixture/fixture" import path from "path" import fs from "fs/promises" -import { provideTestInstance } from "../fixture/fixture" +import { provideTestInstance, withTestInstance } from "../fixture/fixture" import { getKiloProjectId } from "../../src/kilocode/project-id" +import { disposeInstance } from "../../src/effect/instance-registry" describe("project-id", () => { describe("normalization", () => { @@ -365,26 +366,49 @@ describe("project-id", () => { }) describe("caching", () => { - test("caches project ID per Instance", async () => { - await using tmp = await tmpdir({ - git: true, + test("keeps project IDs isolated across active project contexts", async () => { + await using first = await tmpdir({ init: async (dir) => { - await Bun.$`git remote add origin https://github.com/Kilo-Org/handbook.git`.cwd(dir).quiet() + await fs.mkdir(path.join(dir, ".kilo"), { recursive: true }) + await Bun.write(path.join(dir, ".kilo", "config.json"), JSON.stringify({ project: { id: "first" } })) + }, + }) + await using second = await tmpdir({ + init: async (dir) => { + await fs.mkdir(path.join(dir, ".kilo"), { recursive: true }) + await Bun.write(path.join(dir, ".kilo", "config.json"), JSON.stringify({ project: { id: "second" } })) }, }) - const id1 = await provideTestInstance({ - directory: tmp.path, - fn: () => getKiloProjectId(), + const ids = await Promise.all([ + withTestInstance({ directory: first.path, fn: () => getKiloProjectId() }), + withTestInstance({ directory: second.path, fn: () => getKiloProjectId() }), + ]) + + expect(ids).toEqual(["first", "second"]) + }) + + test("invalidates the cached project ID when the instance is disposed", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await fs.mkdir(path.join(dir, ".kilo"), { recursive: true }) + await Bun.write(path.join(dir, ".kilo", "config.json"), JSON.stringify({ project: { id: "first" } })) + }, }) - const id2 = await provideTestInstance({ + const ids = await provideTestInstance({ directory: tmp.path, - fn: () => getKiloProjectId(), + fn: async (ctx) => { + const first = await getKiloProjectId() + await Bun.write(path.join(tmp.path, ".kilo", "config.json"), JSON.stringify({ project: { id: "second" } })) + const cached = await getKiloProjectId() + await disposeInstance(ctx.directory) + const refreshed = await getKiloProjectId() + return { first, cached, refreshed } + }, }) - expect(id1).toBe(id2) - expect(id1).toBe("handbook") + expect(ids).toEqual({ first: "first", cached: "first", refreshed: "second" }) }) }) diff --git a/packages/opencode/test/kilocode/server/httpapi-exercise-scenarios.ts b/packages/opencode/test/kilocode/server/httpapi-exercise-scenarios.ts index 53f65a371b7..c1fac465263 100644 --- a/packages/opencode/test/kilocode/server/httpapi-exercise-scenarios.ts +++ b/packages/opencode/test/kilocode/server/httpapi-exercise-scenarios.ts @@ -556,19 +556,6 @@ export const kiloScenarios: Scenario[] = [ yield* Effect.promise(() => rm(body, { force: true })) }), ), - http.protected - .get("/kilocode/agent/requirements", "kilocode.agentRequirements") - .at((ctx) => ({ path: "/kilocode/agent/requirements?agent=httpapi-agent", headers: ctx.headers() })) - .json(200, (body, ctx) => { - object(body) - check(body.agent === "httpapi-agent", "agent requirements should echo the requested agent") - check(body.directory === ctx.directory, "agent requirements should use the routed workspace directory") - check(body.enabled === false, "agent requirements should report disabled when the experiment is off") - check(body.state === "disabled", "agent requirements should return the disabled state") - array(body.skills) - array(body.mcps) - array(body.vscode_extensions) - }), http.protected .get("/kilocode/command/files", "kilocode.commandFiles") .inProject({ git: true, init: command }) diff --git a/packages/opencode/test/kilocode/session-export/e2e.test.ts b/packages/opencode/test/kilocode/session-export/e2e.test.ts deleted file mode 100644 index f2ddfbefe5c..00000000000 --- a/packages/opencode/test/kilocode/session-export/e2e.test.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { afterEach, describe, expect, test } from "bun:test" -import { $ } from "bun" -import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs" -import { tmpdir } from "node:os" -import { join } from "node:path" -import type { ExportEvent } from "@/kilocode/session-export/events" -import { Capture } from "@/kilocode/session-export/capture" -import { createWorkspaceProvider } from "@/kilocode/session-export/workspace-provider" - -describe("session export worker e2e", () => { - const dirs: string[] = [] - - afterEach(() => { - for (const dir of dirs.splice(0)) rmSync(dir, { recursive: true, force: true }) - }) - - test("captures git repository state from a leaf directory through capture", async () => { - const dir = mkdtempSync(join(tmpdir(), "session-export-git-e2e-")) - dirs.push(dir) - mkdirSync(join(dir, "app", "src"), { recursive: true }) - writeFileSync(join(dir, "package.json"), '{"name":"repo"}\n') - writeFileSync(join(dir, "app", "src", "index.ts"), "export const value = 1\n") - await $`git init`.cwd(dir).quiet() - - const posted: unknown[] = [] - const cap = capture(posted, createWorkspaceProvider({ root: join(dir, "app", "src") })) - - cap.beforeRequest(request("git-session")) - await until(() => Boolean(envelope(posted, "workspace_baseline_completed"))) - - const env = envelope(posted, "workspace_baseline_completed") - expect(env?.type).toBe("workspace_baseline_completed") - if (env?.type !== "workspace_baseline_completed") return - expect(env.capture?.mode).toBe("git-tracked-and-untracked") - expect(env.files.map((file) => file.path)).toEqual(["app/src/index.ts", "package.json"]) - }) - - test("does not capture non-git filesystem state through capture", async () => { - const dir = mkdtempSync(join(tmpdir(), "session-export-nongit-e2e-")) - dirs.push(dir) - writeFileSync(join(dir, "loose.txt"), "do not sync me\n") - - const posted: unknown[] = [] - const cap = capture(posted, createWorkspaceProvider({ root: dir })) - - cap.beforeRequest(request("nongit-session")) - await until(() => Boolean(envelope(posted, "workspace_baseline_completed"))) - - const env = envelope(posted, "workspace_baseline_completed") - expect(env?.type).toBe("workspace_baseline_completed") - if (env?.type !== "workspace_baseline_completed") return - expect(env.capture?.mode).toBe("none") - expect(env.files).toEqual([]) - }) -}) - -async function until(check: () => boolean): Promise { - const start = Date.now() - // The capture worker competes for CPU with the rest of the suite on a loaded CI - // shard; the loop returns on success, so a generous deadline costs healthy runs nothing. - while (Date.now() - start < 15_000) { - if (check()) return - await new Promise((resolve) => setTimeout(resolve, 10)) - } - throw new Error("timed out waiting for worker rows") -} - -function capture(posted: unknown[], snap: ConstructorParameters[0]["snapshotProvider"]) { - const seq = { value: 0 } - return new Capture({ - worker: { - postMessage: (msg) => posted.push(msg), - terminate: () => {}, - }, - agentVersion: "v0", - nowMs: () => 100, - syncSeq: () => seq.value++, - snapshotProvider: snap, - // Must match the generous until() budget below: on a loaded CI shard the git - // snapshot can exceed 1s, and a truncated baseline emits an empty envelope that - // makes the assertions fail no matter how long the test itself waits. - baselineTimeoutMs: 15_000, - }) -} - -function envelope(posted: unknown[], type: ExportEvent["type"]): ExportEvent | undefined { - return posted - .map((item) => (item as { envelope?: ExportEvent }).envelope) - .find((item): item is ExportEvent => item?.type === type) -} - -function request(sessionId: string): Parameters[0] { - return { - input: { model: { api: { npm: "@kilocode/kilo-gateway" }, isFree: true }, org: { type: "personal" } }, - requestMeta: { - sessionId, - rootSessionId: sessionId, - requestId: `${sessionId}-request`, - userMessageId: `${sessionId}-user`, - agent: "build", - modeId: "build", - }, - assembled: { - system: [], - messages: [{ role: "user", content: "hello" }], - tools: {}, - permissions: [], - params: {}, - }, - } -} diff --git a/packages/opencode/test/kilocode/session-export/sequence.test.ts b/packages/opencode/test/kilocode/session-export/sequence.test.ts index c7be7f3b66d..32b41a47a73 100644 --- a/packages/opencode/test/kilocode/session-export/sequence.test.ts +++ b/packages/opencode/test/kilocode/session-export/sequence.test.ts @@ -24,47 +24,4 @@ describe("session export sequencer", () => { } }) - test("waits for worker sqlite writes instead of failing on a transient lock", async () => { - const dir = mkdtempSync(join(tmpdir(), "session-export-seq-lock-")) - const db = join(dir, "session-export.db") - const worker = locker() - try { - const first = createSequencer(db) - await new Promise((resolve, reject) => { - const timer = setTimeout(() => reject(new Error("lock worker timeout")), 1_000) - worker.onmessage = (event: MessageEvent) => { - if ((event.data as { kind?: string }).kind !== "locked") return - clearTimeout(timer) - resolve() - } - worker.onerror = (event) => { - clearTimeout(timer) - reject(event.error) - } - worker.postMessage(db) - }) - expect(first.next("s1")).toBe(0) - first.close() - } finally { - worker.terminate() - rmSync(dir, { recursive: true, force: true }) - } - }) }) - -function locker() { - const code = ` - import { Database } from "bun:sqlite" - self.onmessage = async (event) => { - const sqlite = new Database(event.data, { create: true }) - sqlite.exec("PRAGMA journal_mode = WAL") - sqlite.exec("CREATE TABLE IF NOT EXISTS hold (id INTEGER PRIMARY KEY)") - sqlite.exec("BEGIN IMMEDIATE") - self.postMessage({ kind: "locked" }) - await new Promise((resolve) => setTimeout(resolve, 100)) - sqlite.exec("COMMIT") - sqlite.close() - } - ` - return new Worker(URL.createObjectURL(new Blob([code], { type: "text/javascript" }))) -} diff --git a/packages/opencode/test/kilocode/session-export/worker.test.ts b/packages/opencode/test/kilocode/session-export/worker.test.ts deleted file mode 100644 index fa0255a228a..00000000000 --- a/packages/opencode/test/kilocode/session-export/worker.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { describe, test, expect } from "bun:test" - -describe("worker entry", () => { - test("processes a posted event end-to-end", async () => { - const worker = new Worker(new URL("../../../src/kilocode/session-export/worker.ts", import.meta.url)) - const ready = new Promise((resolve, reject) => { - const timer = setTimeout(() => reject(new Error("worker ready timeout")), 1_000) - worker.onerror = (event) => { - clearTimeout(timer) - reject(event.error) - } - worker.onmessage = (event: MessageEvent) => { - if ((event.data as { kind?: string }).kind === "ready") { - clearTimeout(timer) - resolve() - } - } - }) - - worker.postMessage({ kind: "init", dbPath: ":memory:" }) - await ready - - worker.postMessage({ - kind: "event", - approxBytes: 100, - envelope: { - id: "01N", - schemaVersion: 1, - type: "llm_request_started", - sessionId: "s1", - rootSessionId: "s1", - seq: 0, - ts: 100, - agentVersion: "v0", - requestId: "r1", - userMessageId: "u1", - agent: "claude", - modeId: "build", - model: { providerId: "kilo", modelId: "free-1", isFree: true }, - input: { system: ["hi"], messages: [], tools: {}, permissions: [], params: {} }, - time: { created: 0 }, - }, - }) - - const done = new Promise<{ count: number }>((resolve, reject) => { - const timer = setTimeout(() => reject(new Error("worker count timeout")), 1_000) - worker.onmessage = (event: MessageEvent) => { - const msg = event.data as { kind?: string; count?: number } - if (msg.kind === "test_event_count") { - clearTimeout(timer) - resolve({ count: msg.count ?? 0 }) - } - } - }) - worker.postMessage({ kind: "test_event_count" }) - const result = await done - expect(result.count).toBe(1) - - worker.postMessage({ kind: "shutdown", timeoutMs: 500 }) - worker.terminate() - }) -}) diff --git a/packages/opencode/test/kilocode/session-resume-integration.test.ts b/packages/opencode/test/kilocode/session-resume-integration.test.ts index ec2d6b600a7..2ee9beef624 100644 --- a/packages/opencode/test/kilocode/session-resume-integration.test.ts +++ b/packages/opencode/test/kilocode/session-resume-integration.test.ts @@ -74,7 +74,6 @@ const fastAgents = Layer.mock(AgentSvc.Service)({ list: () => Effect.succeed([agent]), defaultInfo: () => Effect.succeed(agent), defaultAgent: () => Effect.succeed(agent.name), - guardRequirements: () => Effect.void, }) const summary = Layer.succeed( diff --git a/packages/opencode/test/kilocode/tool/memory-runtime.ts b/packages/opencode/test/kilocode/tool/memory-runtime.ts index 118cadcf750..6df226655cc 100644 --- a/packages/opencode/test/kilocode/tool/memory-runtime.ts +++ b/packages/opencode/test/kilocode/tool/memory-runtime.ts @@ -16,17 +16,6 @@ const agents = Agent.Service.of({ list: () => Effect.succeed([info]), defaultInfo: () => Effect.succeed(info), defaultAgent: () => Effect.succeed("code"), - requirementStatus: () => - Effect.succeed({ - agent: "code", - directory: "", - enabled: false, - state: "ready", - skills: [], - mcps: [], - vscode_extensions: [], - }), - guardRequirements: () => Effect.void, generate: () => Effect.succeed({ identifier: "code", whenToUse: "", systemPrompt: "" }), }) diff --git a/packages/opencode/test/kilocode/tool/notify-user.test.ts b/packages/opencode/test/kilocode/tool/notify-user.test.ts index 9b98f70c85b..cf38f78906a 100644 --- a/packages/opencode/test/kilocode/tool/notify-user.test.ts +++ b/packages/opencode/test/kilocode/tool/notify-user.test.ts @@ -20,17 +20,6 @@ const agents = Agent.Service.of({ list: () => Effect.succeed([agentInfo]), defaultInfo: () => Effect.succeed(agentInfo), defaultAgent: () => Effect.succeed("code"), - requirementStatus: () => - Effect.succeed({ - agent: "code", - directory: "", - enabled: false, - state: "ready", - skills: [], - mcps: [], - vscode_extensions: [], - }), - guardRequirements: () => Effect.void, generate: () => Effect.succeed({ identifier: "code", whenToUse: "", systemPrompt: "" }), }) diff --git a/packages/opencode/test/kilocode/tool/send-file.test.ts b/packages/opencode/test/kilocode/tool/send-file.test.ts index db5d914684b..e383d94cab0 100644 --- a/packages/opencode/test/kilocode/tool/send-file.test.ts +++ b/packages/opencode/test/kilocode/tool/send-file.test.ts @@ -26,17 +26,6 @@ const agents = Agent.Service.of({ list: () => Effect.succeed([agentInfo]), defaultInfo: () => Effect.succeed(agentInfo), defaultAgent: () => Effect.succeed("code"), - requirementStatus: () => - Effect.succeed({ - agent: "code", - directory: "", - enabled: false, - state: "ready", - skills: [], - mcps: [], - vscode_extensions: [], - }), - guardRequirements: () => Effect.void, generate: () => Effect.succeed({ identifier: "code", whenToUse: "", systemPrompt: "" }), }) diff --git a/packages/opencode/test/session/prompt.test.ts b/packages/opencode/test/session/prompt.test.ts index a722b1f0500..1205bb897dd 100644 --- a/packages/opencode/test/session/prompt.test.ts +++ b/packages/opencode/test/session/prompt.test.ts @@ -189,7 +189,6 @@ const fastAgents = Layer.mock(AgentSvc.Service)({ list: () => Effect.succeed([agent]), defaultInfo: () => Effect.succeed(agent), defaultAgent: () => Effect.succeed(agent.name), - guardRequirements: () => Effect.void, }) const processorCreateStarted: Deferred.Deferred[] = [] diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index ac28034a203..bb2ea6527b5 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -181,8 +181,6 @@ import type { KilocodeAgentManagerRejectResponses, KilocodeAgentManagerReplyErrors, KilocodeAgentManagerReplyResponses, - KilocodeAgentRequirementsErrors, - KilocodeAgentRequirementsResponses, KilocodeCommandFilesErrors, KilocodeCommandFilesResponses, KilocodeHeapSnapshotErrors, @@ -8074,42 +8072,6 @@ export class SessionImport extends HeyApiClient { } export class Kilocode extends HeyApiClient { - /** - * Check agent requirements - * - * Check whether the selected agent's requirements are available in the request directory. - */ - public agentRequirements( - parameters: { - directory?: string - workspace?: string - agent: string - }, - options?: Options, - ) { - const params = buildClientParams( - [parameters], - [ - { - args: [ - { in: "query", key: "directory" }, - { in: "query", key: "workspace" }, - { in: "query", key: "agent" }, - ], - }, - ], - ) - return (options?.client ?? this.client).get< - KilocodeAgentRequirementsResponses, - KilocodeAgentRequirementsErrors, - ThrowOnError - >({ - url: "/kilocode/agent/requirements", - ...options, - ...params, - }) - } - /** * List command files * diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 36c1582ff07..0acdc944a40 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -2707,7 +2707,6 @@ export type Config = { batch_tool?: boolean image_generation?: boolean image_generation_model?: string - agent_requirements?: boolean native_notebook_tools?: boolean speech_to_text_model?: string openTelemetry?: boolean @@ -4165,31 +4164,6 @@ export type CloudSessionImportError = { error: string } -export type AgentRequirementResult = { - agent: string - directory: string - enabled: boolean - state: "disabled" | "ready" | "blocked" | "error" - skills: Array<{ - name: string - status: "ready" | "missing" | "error" - message?: string - }> - mcps: Array<{ - name: string - status: "ready" | "missing" | "error" - message?: string - }> - vscode_extensions: Array<{ - name: string - id: string - }> - error?: { - code: "unknown_agent" | "malformed_declaration" | "discovery_failed" | "mcp_status_failed" - message: string - } -} - export type CommandFile = { name: string description?: string @@ -16542,36 +16516,6 @@ export type KilocodeHeapSnapshotResponses = { export type KilocodeHeapSnapshotResponse = KilocodeHeapSnapshotResponses[keyof KilocodeHeapSnapshotResponses] -export type KilocodeAgentRequirementsData = { - body?: never - path?: never - query: { - directory?: string - workspace?: string - agent: string - } - url: "/kilocode/agent/requirements" -} - -export type KilocodeAgentRequirementsErrors = { - /** - * Bad request - */ - 400: BadRequestError -} - -export type KilocodeAgentRequirementsError = KilocodeAgentRequirementsErrors[keyof KilocodeAgentRequirementsErrors] - -export type KilocodeAgentRequirementsResponses = { - /** - * Agent requirement status - */ - 200: AgentRequirementResult -} - -export type KilocodeAgentRequirementsResponse = - KilocodeAgentRequirementsResponses[keyof KilocodeAgentRequirementsResponses] - export type KilocodeCommandFilesData = { body?: never path?: never diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index cbe83dbbbb9..dae48bde11d 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -14930,68 +14930,6 @@ ] } }, - "/kilocode/agent/requirements": { - "get": { - "tags": ["kilocode"], - "operationId": "kilocode.agentRequirements", - "parameters": [ - { - "name": "directory", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "workspace", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "agent", - "in": "query", - "schema": { - "type": "string" - }, - "required": true - } - ], - "responses": { - "200": { - "description": "Agent requirement status", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AgentRequirementResult" - } - } - } - }, - "400": { - "description": "Bad request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/BadRequestError" - } - } - } - } - }, - "description": "Check whether the selected agent's requirements are available in the request directory.", - "summary": "Check agent requirements", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createKiloClient } from \"@kilocode/sdk\"\n\nconst client = createKiloClient()\nawait client.kilocode.agentRequirements({\n ...\n})" - } - ] - } - }, "/kilocode/command/files": { "get": { "tags": ["kilocode"], @@ -34036,9 +33974,6 @@ "image_generation_model": { "type": "string" }, - "agent_requirements": { - "type": "boolean" - }, "native_notebook_tools": { "type": "boolean" }, @@ -38566,102 +38501,6 @@ "required": ["error"], "additionalProperties": false }, - "AgentRequirementResult": { - "type": "object", - "properties": { - "agent": { - "type": "string" - }, - "directory": { - "type": "string" - }, - "enabled": { - "type": "boolean" - }, - "state": { - "type": "string", - "enum": ["disabled", "ready", "blocked", "error"] - }, - "skills": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "status": { - "type": "string", - "enum": ["ready", "missing", "error"] - }, - "message": { - "type": "string" - } - }, - "required": ["name", "status"], - "additionalProperties": false - } - }, - "mcps": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "status": { - "type": "string", - "enum": ["ready", "missing", "error"] - }, - "message": { - "type": "string" - } - }, - "required": ["name", "status"], - "additionalProperties": false - } - }, - "vscode_extensions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1, - "maxLength": 128, - "pattern": "\\S" - }, - "id": { - "type": "string", - "minLength": 1, - "maxLength": 128, - "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$" - } - }, - "required": ["name", "id"], - "additionalProperties": false - } - }, - "error": { - "type": "object", - "properties": { - "code": { - "type": "string", - "enum": ["unknown_agent", "malformed_declaration", "discovery_failed", "mcp_status_failed"] - }, - "message": { - "type": "string" - } - }, - "required": ["code", "message"], - "additionalProperties": false - } - }, - "required": ["agent", "directory", "enabled", "state", "skills", "mcps", "vscode_extensions"], - "additionalProperties": false - }, "CommandFile": { "type": "object", "properties": { diff --git a/packages/tui/src/component/prompt/index.tsx b/packages/tui/src/component/prompt/index.tsx index 3449a9b0996..ea420efcd85 100644 --- a/packages/tui/src/component/prompt/index.tsx +++ b/packages/tui/src/component/prompt/index.tsx @@ -55,7 +55,6 @@ import { useArgs } from "../../context/args" // kilocode_change start import { KiloSessionTuiSync } from "@/kilocode/session/tui-sync" import { slashMatches } from "@/kilocode/cli/cmd/command-display" -import * as AgentRequirements from "@/kilocode/cli/agent-requirements" import { createCostAlertController } from "@/kilocode/cli/cmd/tui/cost-alert" import { MemoryPrompt } from "@/kilocode/cli/cmd/tui/component/memory-prompt" // kilocode_change end @@ -1087,29 +1086,6 @@ export function Prompt(props: PromptProps) { return false } - // kilocode_change start - gate TUI sends on declared agent requirements - const requirements = await AgentRequirements.check({ - client: sdk.client, - agent: agent.name, - directory: project.instance.directory() || sdk.directory || process.cwd(), - }).catch((error) => { - toast.show({ - message: errorMessage(error), - variant: "error", - }) - return undefined - }) - if (!requirements) return false - if (!requirements.ok) { - toast.show({ - title: "Agent requirements", - message: requirements.error.data.message, - variant: "error", - }) - return false - } - // kilocode_change end - const workspaceSession = props.sessionID ? sync.session.get(props.sessionID) : undefined const workspaceID = workspaceSession?.workspaceID const workspaceStatus = workspaceID ? (project.workspace.status(workspaceID) ?? "error") : undefined diff --git a/script/architecture-allowlist.json b/script/architecture-allowlist.json index bfff1b4eb51..212223c34f5 100644 --- a/script/architecture-allowlist.json +++ b/script/architecture-allowlist.json @@ -10,7 +10,6 @@ "packages/opencode/src/kilocode/agent-manager/service.ts": { "count": 1, "owner": "agent-manager", "reason": "Agent Manager multi-project worktree state" }, "packages/opencode/src/kilocode/background-process/index.ts": { "count": 1, "owner": "process-runtime", "reason": "Directory-keyed background process registry" }, "packages/opencode/src/kilocode/interactive-terminal/index.ts": { "count": 1, "owner": "terminal-runtime", "reason": "Interactive terminal manager state" }, - "packages/opencode/src/kilocode/project-id.ts": { "count": 1, "owner": "project-runtime", "reason": "Cached project identifier resolution" }, "packages/opencode/src/kilocode/watcher.ts": { "count": 1, "owner": "watcher-runtime", "reason": "Eager location watcher subscription" } } },