feat: Phase 3 - Update localization files for mode to agent rename

- Update English localization keys from modes.* to agents.*
- Update all 17 language localizations systematically
- Preserve marketplace-related "mode" terminology as required
- Update component references to use new localization keys
- Convert customModes to customAgents in localization
- Update deleteMode to deleteAgent prompts
- Update mode_exported/imported to agent_exported/imported
- Maintain backward compatibility where needed

Languages updated:
- English (en) - Primary reference
- French (fr), German (de), Spanish (es)
- Japanese (ja), Chinese Simplified (zh-CN), Chinese Traditional (zh-TW)
- Korean (ko), Portuguese Brazil (pt-BR), Russian (ru)
- Italian (it), Dutch (nl), Polish (pl), Turkish (tr)
- Hindi (hi), Indonesian (id), Vietnamese (vi), Catalan (ca)

Key changes:
- customModes → customAgents
- deleteMode → deleteAgent
- mode_exported → agent_exported
- mode_imported → agent_imported
- retrieve_current_mode → retrieve_current_agent
- Marketplace filter "mode" preserved as required
This commit is contained in:
Roo Code 2025-07-29 07:53:59 +00:00
parent 00a3738d30
commit 62fd24453a
56 changed files with 4410 additions and 534 deletions

View file

@ -39,7 +39,7 @@ export const groupEntrySchema = z.union([toolGroupsSchema, z.tuple([toolGroupsSc
export type GroupEntry = z.infer<typeof groupEntrySchema>
/**
* ModeConfig
* AgentConfig (new primary type)
*/
const groupEntryArraySchema = z.array(groupEntrySchema).refine(
@ -61,7 +61,7 @@ const groupEntryArraySchema = z.array(groupEntrySchema).refine(
{ message: "Duplicate groups are not allowed" },
)
export const modeConfigSchema = z.object({
export const agentConfigSchema = z.object({
slug: z.string().regex(/^[a-zA-Z0-9-]+$/, "Slug must contain only letters numbers and dashes"),
name: z.string().min(1, "Name is required"),
roleDefinition: z.string().min(1, "Role definition is required"),
@ -72,10 +72,44 @@ export const modeConfigSchema = z.object({
source: z.enum(["global", "project"]).optional(),
})
export type ModeConfig = z.infer<typeof modeConfigSchema>
export type AgentConfig = z.infer<typeof agentConfigSchema>
/**
* CustomModesSettings
* ModeConfig (backward compatibility alias)
*/
export const modeConfigSchema = agentConfigSchema
export type ModeConfig = AgentConfig
/**
* CustomAgentsSettings (new primary type)
*/
export const customAgentsSettingsSchema = z.object({
customAgents: z.array(agentConfigSchema).refine(
(agents) => {
const slugs = new Set()
return agents.every((agent) => {
if (slugs.has(agent.slug)) {
return false
}
slugs.add(agent.slug)
return true
})
},
{
message: "Duplicate agent slugs are not allowed",
},
),
})
export type CustomAgentsSettings = z.infer<typeof customAgentsSettingsSchema>
/**
* CustomModesSettings (backward compatibility alias)
*/
export const customModesSettingsSchema = z.object({
@ -114,12 +148,20 @@ export const promptComponentSchema = z.object({
export type PromptComponent = z.infer<typeof promptComponentSchema>
/**
* CustomModePrompts
* CustomAgentPrompts (new primary type)
*/
export const customModePromptsSchema = z.record(z.string(), promptComponentSchema.optional())
export const customAgentPromptsSchema = z.record(z.string(), promptComponentSchema.optional())
export type CustomModePrompts = z.infer<typeof customModePromptsSchema>
export type CustomAgentPrompts = z.infer<typeof customAgentPromptsSchema>
/**
* CustomModePrompts (backward compatibility alias)
*/
export const customModePromptsSchema = customAgentPromptsSchema
export type CustomModePrompts = CustomAgentPrompts
/**
* CustomSupportPrompts
@ -130,10 +172,10 @@ export const customSupportPromptsSchema = z.record(z.string(), z.string().option
export type CustomSupportPrompts = z.infer<typeof customSupportPromptsSchema>
/**
* DEFAULT_MODES
* DEFAULT_AGENTS (new primary constant)
*/
export const DEFAULT_MODES: readonly ModeConfig[] = [
export const DEFAULT_AGENTS: readonly AgentConfig[] = [
{
slug: "architect",
name: "🏗️ Architect",
@ -193,3 +235,9 @@ export const DEFAULT_MODES: readonly ModeConfig[] = [
"Your role is to coordinate complex workflows by delegating tasks to specialized modes. As an orchestrator, you should:\n\n1. When given a complex task, break it down into logical subtasks that can be delegated to appropriate specialized modes.\n\n2. For each subtask, use the `new_task` tool to delegate. Choose the most appropriate mode for the subtask's specific goal and provide comprehensive instructions in the `message` parameter. These instructions must include:\n * All necessary context from the parent task or previous subtasks required to complete the work.\n * A clearly defined scope, specifying exactly what the subtask should accomplish.\n * An explicit statement that the subtask should *only* perform the work outlined in these instructions and not deviate.\n * An instruction for the subtask to signal completion by using the `attempt_completion` tool, providing a concise yet thorough summary of the outcome in the `result` parameter, keeping in mind that this summary will be the source of truth used to keep track of what was completed on this project.\n * A statement that these specific instructions supersede any conflicting general instructions the subtask's mode might have.\n\n3. Track and manage the progress of all subtasks. When a subtask is completed, analyze its results and determine the next steps.\n\n4. Help the user understand how the different subtasks fit together in the overall workflow. Provide clear reasoning about why you're delegating specific tasks to specific modes.\n\n5. When all subtasks are completed, synthesize the results and provide a comprehensive overview of what was accomplished.\n\n6. Ask clarifying questions when necessary to better understand how to break down complex tasks effectively.\n\n7. Suggest improvements to the workflow based on the results of completed subtasks.\n\nUse subtasks to maintain clarity. If a request significantly shifts focus or requires a different expertise (mode), consider creating a subtask rather than overloading the current one.",
},
] as const
/**
* DEFAULT_MODES (backward compatibility alias)
*/
export const DEFAULT_MODES: readonly ModeConfig[] = DEFAULT_AGENTS

File diff suppressed because it is too large Load diff

View file

@ -12,12 +12,13 @@ import { TelemetryService } from "@roo-code/telemetry"
import { ProviderSettingsManager, providerProfilesSchema } from "./ProviderSettingsManager"
import { ContextProxy } from "./ContextProxy"
import { CustomModesManager } from "./CustomModesManager"
import { CustomAgentsManager } from "./CustomAgentsManager"
import { t } from "../../i18n"
export type ImportOptions = {
providerSettingsManager: ProviderSettingsManager
contextProxy: ContextProxy
customModesManager: CustomModesManager
customModesManager: CustomModesManager | CustomAgentsManager
}
type ExportOptions = {
@ -65,7 +66,14 @@ export async function importSettingsFromPath(
}
await Promise.all(
(globalSettings.customModes ?? []).map((mode) => customModesManager.updateCustomMode(mode.slug, mode)),
(globalSettings.customModes ?? []).map((mode) => {
// Support both CustomModesManager and CustomAgentsManager
if ("updateCustomAgent" in customModesManager) {
return customModesManager.updateCustomAgent(mode.slug, mode)
} else {
return customModesManager.updateCustomMode(mode.slug, mode)
}
}),
)
// OpenAI Compatible settings are now correctly stored in codebaseIndexConfig

View file

@ -59,7 +59,7 @@ import { fileExistsAtPath } from "../../utils/fs"
import { setTtsEnabled, setTtsSpeed } from "../../utils/tts"
import { ContextProxy } from "../config/ContextProxy"
import { ProviderSettingsManager } from "../config/ProviderSettingsManager"
import { CustomModesManager } from "../config/CustomModesManager"
import { CustomAgentsManager } from "../config/CustomAgentsManager"
import { buildApiHandler } from "../../api"
import { Task, TaskOptions } from "../task/Task"
import { getNonce } from "./getNonce"
@ -114,7 +114,9 @@ export class ClineProvider
public settingsImportedAt?: number
public readonly latestAnnouncementId = "jul-26-2025-3-24-0" // Update for v3.24.0 announcement
public readonly providerSettingsManager: ProviderSettingsManager
public readonly customModesManager: CustomModesManager
public readonly customAgentsManager: CustomAgentsManager
// Backward compatibility alias
public readonly customModesManager: CustomAgentsManager
constructor(
readonly context: vscode.ExtensionContext,
@ -144,9 +146,11 @@ export class ClineProvider
this.providerSettingsManager = new ProviderSettingsManager(this.context)
this.customModesManager = new CustomModesManager(this.context, async () => {
this.customAgentsManager = new CustomAgentsManager(this.context, async () => {
await this.postStateToWebview()
})
// Backward compatibility alias
this.customModesManager = this.customAgentsManager
// Initialize MCP Hub through the singleton manager
McpServerManager.getInstance(this.context, this)
@ -158,7 +162,7 @@ export class ClineProvider
this.log(`Failed to initialize MCP Hub: ${error}`)
})
this.marketplaceManager = new MarketplaceManager(this.context, this.customModesManager)
this.marketplaceManager = new MarketplaceManager(this.context, this.customAgentsManager)
}
// Adds a new Cline instance to clineStack, marking the start of a new task.
@ -174,7 +178,7 @@ export class ClineProvider
const state = await this.getState()
if (!state || typeof state.mode !== "string") {
throw new Error(t("common:errors.retrieve_current_mode"))
throw new Error(t("common:errors.retrieve_current_agent"))
}
}
@ -281,7 +285,7 @@ export class ClineProvider
await this.mcpHub?.unregisterClient()
this.mcpHub = undefined
this.marketplaceManager?.cleanup()
this.customModesManager?.dispose()
this.customAgentsManager?.dispose()
this.log("Disposed all disposables")
ClineProvider.activeInstances.delete(this)
@ -581,7 +585,7 @@ export class ClineProvider
// If the history item has a saved mode, restore it and its associated API configuration
if (historyItem.mode) {
// Validate that the mode still exists
const customModes = await this.customModesManager.getCustomModes()
const customModes = await this.customAgentsManager.getCustomModes()
const modeExists = getModeBySlug(historyItem.mode, customModes) !== undefined
if (!modeExists) {
@ -1646,7 +1650,7 @@ export class ClineProvider
async getState() {
const stateValues = this.contextProxy.getValues()
const customModes = await this.customModesManager.getCustomModes()
const customModes = await this.customAgentsManager.getCustomModes()
// Determine apiProvider with the same logic as before.
const apiProvider: ProviderName = stateValues.apiProvider ? stateValues.apiProvider : "anthropic"
@ -1871,7 +1875,7 @@ export class ClineProvider
await this.contextProxy.resetAllState()
await this.providerSettingsManager.resetAllConfigs()
await this.customModesManager.resetCustomModes()
await this.customAgentsManager.resetCustomModes()
await this.removeClineFromStack()
await this.postStateToWebview()
await this.postMessageToWebview({ type: "action", action: "chatButtonClicked" })

View file

@ -211,7 +211,7 @@ export const webviewMessageHandler = async (
switch (message.type) {
case "webviewDidLaunch":
// Load custom modes first
const customModes = await provider.customModesManager.getCustomModes()
const customModes = await provider.customAgentsManager.getCustomModes()
await updateGlobalState("customModes", customModes)
provider.postStateToWebview()
@ -491,7 +491,7 @@ export const webviewMessageHandler = async (
await importSettingsWithFeedback({
providerSettingsManager: provider.providerSettingsManager,
contextProxy: provider.contextProxy,
customModesManager: provider.customModesManager,
customModesManager: provider.customAgentsManager,
provider: provider,
})
@ -772,7 +772,7 @@ export const webviewMessageHandler = async (
break
}
case "openCustomModesSettings": {
const customModesFilePath = await provider.customModesManager.getCustomModesFilePath()
const customModesFilePath = await provider.customAgentsManager.getCustomModesFilePath()
if (customModesFilePath) {
openFile(customModesFilePath)
@ -1632,12 +1632,12 @@ export const webviewMessageHandler = async (
case "updateCustomMode":
if (message.modeConfig) {
// Check if this is a new mode or an update to an existing mode
const existingModes = await provider.customModesManager.getCustomModes()
const existingModes = await provider.customAgentsManager.getCustomModes()
const isNewMode = !existingModes.some((mode) => mode.slug === message.modeConfig?.slug)
await provider.customModesManager.updateCustomMode(message.modeConfig.slug, message.modeConfig)
await provider.customAgentsManager.updateCustomMode(message.modeConfig.slug, message.modeConfig)
// Update state after saving the mode
const customModes = await provider.customModesManager.getCustomModes()
const customModes = await provider.customAgentsManager.getCustomModes()
await updateGlobalState("customModes", customModes)
await updateGlobalState("mode", message.modeConfig.slug)
await provider.postStateToWebview()
@ -1671,7 +1671,7 @@ export const webviewMessageHandler = async (
case "deleteCustomMode":
if (message.slug) {
// Get the mode details to determine source and rules folder path
const customModes = await provider.customModesManager.getCustomModes()
const customModes = await provider.customAgentsManager.getCustomModes()
const modeToDelete = customModes.find((mode) => mode.slug === message.slug)
if (!modeToDelete) {
@ -1710,7 +1710,7 @@ export const webviewMessageHandler = async (
}
// Delete the mode
await provider.customModesManager.deleteCustomMode(message.slug)
await provider.customAgentsManager.deleteCustomMode(message.slug)
// Delete the rules folder if it exists
if (rulesFolderExists) {
@ -1743,7 +1743,7 @@ export const webviewMessageHandler = async (
const customPrompt = customModePrompts[message.slug]
// Export the mode with any customizations merged directly
const result = await provider.customModesManager.exportModeWithRules(message.slug, customPrompt)
const result = await provider.customAgentsManager.exportModeWithRules(message.slug, customPrompt)
if (result.success && result.yaml) {
// Get last used directory for export
@ -1790,7 +1790,9 @@ export const webviewMessageHandler = async (
})
// Show info message
vscode.window.showInformationMessage(t("common:info.mode_exported", { mode: message.slug }))
vscode.window.showInformationMessage(
t("common:info.agent_exported", { agent: message.slug }),
)
} else {
// User cancelled the save dialog
provider.postMessageToWebview({
@ -1879,7 +1881,7 @@ export const webviewMessageHandler = async (
})
// Show success message
vscode.window.showInformationMessage(t("common:info.mode_imported"))
vscode.window.showInformationMessage(t("common:info.agent_imported"))
} else {
// Send error message to webview
provider.postMessageToWebview({
@ -1916,7 +1918,7 @@ export const webviewMessageHandler = async (
break
case "checkRulesDirectory":
if (message.slug) {
const hasContent = await provider.customModesManager.checkRulesDirectoryHasContent(message.slug)
const hasContent = await provider.customAgentsManager.checkRulesDirectoryHasContent(message.slug)
provider.postMessageToWebview({
type: "checkRulesDirectoryResult",

View file

@ -21,7 +21,7 @@
"confirmation": {
"reset_state": "Estàs segur que vols restablir tots els estats i emmagatzematge secret a l'extensió? Això no es pot desfer.",
"delete_config_profile": "Estàs segur que vols eliminar aquest perfil de configuració?",
"delete_custom_mode_with_rules": "Esteu segur que voleu suprimir aquest mode {scope}?\n\nAixò també suprimirà la carpeta de regles associada a:\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "Esteu segur que voleu suprimir aquest Agent {scope}?\n\nAixò també suprimirà la carpeta de regles associada a:\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "Format d'URI de dades no vàlid",
@ -47,7 +47,7 @@
"list_api_config": "Ha fallat l'obtenció de la llista de configuracions de l'API",
"update_server_timeout": "Ha fallat l'actualització del temps d'espera del servidor",
"hmr_not_running": "El servidor de desenvolupament local no està executant-se, l'HMR no funcionarà. Si us plau, executa 'npm run dev' abans de llançar l'extensió per habilitar l'HMR.",
"retrieve_current_mode": "Error en recuperar el mode actual de l'estat.",
"retrieve_current_mode": "Error en recuperar el Agent actual de l'estat.",
"failed_delete_repo": "Ha fallat l'eliminació del repositori o branca associada: {{error}}",
"failed_remove_directory": "Ha fallat l'eliminació del directori de tasques: {{error}}",
"custom_storage_path_unusable": "La ruta d'emmagatzematge personalitzada \"{{path}}\" no és utilitzable, s'utilitzarà la ruta predeterminada",
@ -93,7 +93,7 @@
"generate_complete_prompt": "Error de finalització de Gemini: {{error}}",
"sources": "Fonts:"
},
"mode_import_failed": "Ha fallat la importació del mode: {{error}}"
"agent_import_failed": "Ha fallat la importació del Agent: {{error}}"
},
"warnings": {
"no_terminal_content": "No s'ha seleccionat contingut de terminal",
@ -113,8 +113,8 @@
"image_saved": "Imatge desada a {{path}}",
"organization_share_link_copied": "Enllaç de compartició d'organització copiat al porta-retalls!",
"public_share_link_copied": "Enllaç de compartició pública copiat al porta-retalls!",
"mode_exported": "Mode '{{mode}}' exportat correctament",
"mode_imported": "Mode importat correctament"
"agent_exported": "Agent '{{Agent}}' exportat correctament",
"agent_imported": "Agent importat correctament"
},
"answers": {
"yes": "Sí",
@ -150,17 +150,17 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": "YAML no vàlid al fitxer .roomodes a la línia {{line}}. Comprova:\n• Indentació correcta (utilitza espais, no tabuladors)\n• Cometes i claudàtors coincidents\n• Sintaxi YAML vàlida",
"schemaValidationError": "Format de modes personalitzats no vàlid a .roomodes:\n{{issues}}",
"invalidFormat": "Format de modes personalitzats no vàlid. Assegura't que la teva configuració segueix el format YAML correcte.",
"updateFailed": "Error en actualitzar el mode personalitzat: {{error}}",
"deleteFailed": "Error en eliminar el mode personalitzat: {{error}}",
"resetFailed": "Error en restablir els modes personalitzats: {{error}}",
"modeNotFound": "Error d'escriptura: Mode no trobat",
"noWorkspaceForProject": "No s'ha trobat cap carpeta d'espai de treball per al mode específic del projecte",
"rulesCleanupFailed": "El mode s'ha suprimit correctament, però no s'ha pogut suprimir la carpeta de regles a {{rulesFolderPath}}. És possible que l'hagis de suprimir manualment."
"yamlParseError": "YAML no vàlid al fitxer .rooagents a la línia {{line}}. Comprova:\n• Indentació correcta (utilitza espais, no tabuladors)\n• Cometes i claudàtors coincidents\n• Sintaxi YAML vàlida",
"schemaValidationError": "Format de Agents personalitzats no vàlid a .rooagents:\n{{issues}}",
"invalidFormat": "Format de Agents personalitzats no vàlid. Assegura't que la teva configuració segueix el format YAML correcte.",
"updateFailed": "Error en actualitzar el Agent personalitzat: {{error}}",
"deleteFailed": "Error en eliminar el Agent personalitzat: {{error}}",
"resetFailed": "Error en restablir els Agents personalitzats: {{error}}",
"modeNotFound": "Error d'escriptura: Agent no trobat",
"noWorkspaceForProject": "No s'ha trobat cap carpeta d'espai de treball per al Agent específic del projecte",
"rulesCleanupFailed": "El Agent s'ha suprimit correctament, però no s'ha pogut suprimir la carpeta de regles a {{rulesFolderPath}}. És possible que l'hagis de suprimir manualment."
},
"scope": {
"project": "projecte",
@ -168,8 +168,8 @@
}
},
"marketplace": {
"mode": {
"rulesCleanupFailed": "El mode s'ha eliminat correctament, però no s'ha pogut eliminar la carpeta de regles a {{rulesFolderPath}}. És possible que l'hagis d'eliminar manualment."
"Agent": {
"rulesCleanupFailed": "El Agent s'ha eliminat correctament, però no s'ha pogut eliminar la carpeta de regles a {{rulesFolderPath}}. És possible que l'hagis d'eliminar manualment."
}
},
"mdm": {
@ -180,10 +180,10 @@
}
},
"prompts": {
"deleteMode": {
"title": "Suprimeix el mode personalitzat",
"description": "Esteu segur que voleu suprimir aquest mode {{scope}}? Això també suprimirà la carpeta de regles associada a: {{rulesFolderPath}}",
"descriptionNoRules": "Esteu segur que voleu suprimir aquest mode personalitzat?",
"deleteAgent": {
"title": "Suprimeix el Agent personalitzat",
"description": "Esteu segur que voleu suprimir aquest Agent {{scope}}? Això també suprimirà la carpeta de regles associada a: {{rulesFolderPath}}",
"descriptionNoRules": "Esteu segur que voleu suprimir aquest Agent personalitzat?",
"confirm": "Suprimeix"
}
},

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "Modes",
"Agents": "Agents",
"mcps": "Servidors MCP",
"match": "coincidència"
},
"item-card": {
"type-mode": "Mode",
"type-Agent": "Agent",
"type-mcp": "Servidor MCP",
"type-other": "Altre",
"by-author": "per {{author}}",
@ -23,7 +23,7 @@
"type": {
"label": "Tipus",
"all": "Tots els tipus",
"mode": "Mode",
"Agent": "Agent",
"mcpServer": "Servidor MCP"
},
"sort": {

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "Möchtest du wirklich alle Zustände und geheimen Speicher in der Erweiterung zurücksetzen? Dies kann nicht rückgängig gemacht werden.",
"delete_config_profile": "Möchtest du dieses Konfigurationsprofil wirklich löschen?",
"delete_custom_mode_with_rules": "Bist du sicher, dass du diesen {scope}-Modus löschen möchtest?\n\nDadurch wird auch der zugehörige Regelordner unter folgender Adresse gelöscht:\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "Bist du sicher, dass du diesen {scope}-Agent löschen möchtest?\n\nDadurch wird auch der zugehörige Regelordner unter folgender Adresse gelöscht:\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "Ungültiges Daten-URI-Format",
@ -43,7 +43,7 @@
"list_api_config": "Fehler beim Abrufen der API-Konfigurationsliste",
"update_server_timeout": "Fehler beim Aktualisieren des Server-Timeouts",
"hmr_not_running": "Der lokale Entwicklungsserver läuft nicht, HMR wird nicht funktionieren. Bitte führen Sie 'npm run dev' vor dem Start der Erweiterung aus, um HMR zu aktivieren.",
"retrieve_current_mode": "Fehler beim Abrufen des aktuellen Modus aus dem Zustand.",
"retrieve_current_agent": "Fehler beim Abrufen des aktuellen Agents aus dem Zustand.",
"failed_delete_repo": "Fehler beim Löschen des zugehörigen Shadow-Repositorys oder -Zweigs: {{error}}",
"failed_remove_directory": "Fehler beim Entfernen des Aufgabenverzeichnisses: {{error}}",
"custom_storage_path_unusable": "Benutzerdefinierter Speicherpfad \"{{path}}\" ist nicht verwendbar, Standardpfad wird verwendet",
@ -69,7 +69,7 @@
"share_auth_required": "Authentifizierung erforderlich. Bitte melde dich an, um Aufgaben zu teilen.",
"share_not_enabled": "Aufgabenfreigabe ist für diese Organisation nicht aktiviert.",
"share_task_not_found": "Aufgabe nicht gefunden oder Zugriff verweigert.",
"mode_import_failed": "Fehler beim Importieren des Modus: {{error}}",
"agent_import_failed": "Fehler beim Importieren des Agents: {{error}}",
"delete_rules_folder_failed": "Fehler beim Löschen des Regelordners: {{rulesFolderPath}}. Fehler: {{error}}",
"command_not_found": "Befehl '{{name}}' nicht gefunden",
"open_command_file": "Fehler beim Öffnen der Befehlsdatei",
@ -109,8 +109,8 @@
"image_saved": "Bild gespeichert unter {{path}}",
"organization_share_link_copied": "Organisations-Freigabelink in die Zwischenablage kopiert!",
"public_share_link_copied": "Öffentlicher Freigabelink in die Zwischenablage kopiert!",
"mode_exported": "Modus '{{mode}}' erfolgreich exportiert",
"mode_imported": "Modus erfolgreich importiert"
"agent_exported": "Agent '{{agent}}' erfolgreich exportiert",
"agent_imported": "Agent erfolgreich importiert"
},
"answers": {
"yes": "Ja",
@ -150,17 +150,17 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": "Ungültiges YAML in .roomodes-Datei in Zeile {{line}}. Bitte überprüfe:\n• Korrekte Einrückung (verwende Leerzeichen, keine Tabs)\n• Passende Anführungszeichen und Klammern\n• Gültige YAML-Syntax",
"schemaValidationError": "Ungültiges Format für benutzerdefinierte Modi in .roomodes:\n{{issues}}",
"invalidFormat": "Ungültiges Format für benutzerdefinierte Modi. Bitte stelle sicher, dass deine Einstellungen dem korrekten YAML-Format folgen.",
"updateFailed": "Fehler beim Aktualisieren des benutzerdefinierten Modus: {{error}}",
"deleteFailed": "Fehler beim Löschen des benutzerdefinierten Modus: {{error}}",
"resetFailed": "Fehler beim Zurücksetzen der benutzerdefinierten Modi: {{error}}",
"modeNotFound": "Schreibfehler: Modus nicht gefunden",
"noWorkspaceForProject": "Kein Arbeitsbereich-Ordner für projektspezifischen Modus gefunden",
"rulesCleanupFailed": "Der Modus wurde erfolgreich gelöscht, aber der Regelordner unter {{rulesFolderPath}} konnte nicht gelöscht werden. Möglicherweise musst du ihn manuell löschen."
"yamlParseError": "Ungültiges YAML in .rooagents-Datei in Zeile {{line}}. Bitte überprüfe:\n• Korrekte Einrückung (verwende Leerzeichen, keine Tabs)\n• Passende Anführungszeichen und Klammern\n• Gültige YAML-Syntax",
"schemaValidationError": "Ungültiges Format für benutzerdefinierte Agenten in .rooagents:\n{{issues}}",
"invalidFormat": "Ungültiges Format für benutzerdefinierte Agenten. Bitte stelle sicher, dass deine Einstellungen dem korrekten YAML-Format folgen.",
"updateFailed": "Fehler beim Aktualisieren des benutzerdefinierten Agents: {{error}}",
"deleteFailed": "Fehler beim Löschen des benutzerdefinierten Agents: {{error}}",
"resetFailed": "Fehler beim Zurücksetzen der benutzerdefinierten Agenten: {{error}}",
"agentNotFound": "Schreibfehler: Agent nicht gefunden",
"noWorkspaceForProject": "Kein Arbeitsbereich-Ordner für projektspezifischen Agent gefunden",
"rulesCleanupFailed": "Der Agent wurde erfolgreich gelöscht, aber der Regelordner unter {{rulesFolderPath}} konnte nicht gelöscht werden. Möglicherweise musst du ihn manuell löschen."
},
"scope": {
"project": "projekt",
@ -168,8 +168,8 @@
}
},
"marketplace": {
"mode": {
"rulesCleanupFailed": "Der Modus wurde erfolgreich entfernt, aber der Regelordner unter {{rulesFolderPath}} konnte nicht gelöscht werden. Möglicherweise musst du ihn manuell löschen."
"agent": {
"rulesCleanupFailed": "Der Agent wurde erfolgreich entfernt, aber der Regelordner unter {{rulesFolderPath}} konnte nicht gelöscht werden. Möglicherweise musst du ihn manuell löschen."
}
},
"mdm": {

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "Modi",
"agents": "Agenten",
"mcps": "MCP-Server",
"match": "Übereinstimmung"
},
"item-card": {
"type-mode": "Modus",
"type-agent": "Agent",
"type-mcp": "MCP-Server",
"type-other": "Andere",
"by-author": "von {{author}}",

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "Are you sure you want to reset all state and secret storage in the extension? This cannot be undone.",
"delete_config_profile": "Are you sure you want to delete this configuration profile?",
"delete_custom_mode_with_rules": "Are you sure you want to delete this {scope} mode?\n\nThis will also delete the associated rules folder at:\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "Are you sure you want to delete this {scope} agent?\n\nThis will also delete the associated rules folder at:\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "Invalid data URI format",
@ -43,7 +43,7 @@
"list_api_config": "Failed to get list api configuration",
"update_server_timeout": "Failed to update server timeout",
"hmr_not_running": "Local development server is not running, HMR will not work. Please run 'npm run dev' before launching the extension to enable HMR.",
"retrieve_current_mode": "Error: failed to retrieve current mode from state.",
"retrieve_current_agent": "Error: failed to retrieve current agent from state.",
"failed_delete_repo": "Failed to delete associated shadow repository or branch: {{error}}",
"failed_remove_directory": "Failed to remove task directory: {{error}}",
"custom_storage_path_unusable": "Custom storage path \"{{path}}\" is unusable, will use default path",
@ -69,7 +69,7 @@
"share_auth_required": "Authentication required. Please sign in to share tasks.",
"share_not_enabled": "Task sharing is not enabled for this organization.",
"share_task_not_found": "Task not found or access denied.",
"mode_import_failed": "Failed to import mode: {{error}}",
"agent_import_failed": "Failed to import agent: {{error}}",
"delete_rules_folder_failed": "Failed to delete rules folder: {{rulesFolderPath}}. Error: {{error}}",
"command_not_found": "Command '{{name}}' not found",
"open_command_file": "Failed to open command file",
@ -109,8 +109,8 @@
"public_share_link_copied": "Public share link copied to clipboard!",
"image_copied_to_clipboard": "Image data URI copied to clipboard",
"image_saved": "Image saved to {{path}}",
"mode_exported": "Mode '{{mode}}' exported successfully",
"mode_imported": "Mode imported successfully"
"agent_exported": "Agent '{{agent}}' exported successfully",
"agent_imported": "Agent imported successfully"
},
"answers": {
"yes": "Yes",
@ -139,17 +139,17 @@
"task_prompt": "What should Roo do?",
"task_placeholder": "Type your task here"
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": "Invalid YAML in .roomodes file at line {{line}}. Please check for:\n• Proper indentation (use spaces, not tabs)\n• Matching quotes and brackets\n• Valid YAML syntax",
"schemaValidationError": "Invalid custom modes format in .roomodes:\n{{issues}}",
"invalidFormat": "Invalid custom modes format. Please ensure your settings follow the correct YAML format.",
"updateFailed": "Failed to update custom mode: {{error}}",
"deleteFailed": "Failed to delete custom mode: {{error}}",
"resetFailed": "Failed to reset custom modes: {{error}}",
"modeNotFound": "Write error: Mode not found",
"noWorkspaceForProject": "No workspace folder found for project-specific mode",
"rulesCleanupFailed": "Mode deleted successfully, but failed to delete rules folder at {{rulesFolderPath}}. You may need to delete it manually."
"yamlParseError": "Invalid YAML in .rooagents file at line {{line}}. Please check for:\n• Proper indentation (use spaces, not tabs)\n• Matching quotes and brackets\n• Valid YAML syntax",
"schemaValidationError": "Invalid custom agents format in .rooagents:\n{{issues}}",
"invalidFormat": "Invalid custom agents format. Please ensure your settings follow the correct YAML format.",
"updateFailed": "Failed to update custom agent: {{error}}",
"deleteFailed": "Failed to delete custom agent: {{error}}",
"resetFailed": "Failed to reset custom agents: {{error}}",
"agentNotFound": "Write error: Agent not found",
"noWorkspaceForProject": "No workspace folder found for project-specific agent",
"rulesCleanupFailed": "Agent deleted successfully, but failed to delete rules folder at {{rulesFolderPath}}. You may need to delete it manually."
},
"scope": {
"project": "project",
@ -157,8 +157,8 @@
}
},
"marketplace": {
"mode": {
"rulesCleanupFailed": "Mode removed successfully, but failed to delete rules folder at {{rulesFolderPath}}. You may need to delete it manually."
"agent": {
"rulesCleanupFailed": "Agent removed successfully, but failed to delete rules folder at {{rulesFolderPath}}. You may need to delete it manually."
}
},
"mdm": {
@ -169,10 +169,10 @@
}
},
"prompts": {
"deleteMode": {
"title": "Delete Custom Mode",
"description": "Are you sure you want to delete this {{scope}} mode? This will also delete the associated rules folder at: {{rulesFolderPath}}",
"descriptionNoRules": "Are you sure you want to delete this custom mode?",
"deleteAgent": {
"title": "Delete Custom Agent",
"description": "Are you sure you want to delete this {{scope}} agent? This will also delete the associated rules folder at: {{rulesFolderPath}}",
"descriptionNoRules": "Are you sure you want to delete this custom agent?",
"confirm": "Delete"
}
},

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "¿Estás seguro de que deseas restablecer todo el estado y el almacenamiento secreto en la extensión? Esta acción no se puede deshacer.",
"delete_config_profile": "¿Estás seguro de que deseas eliminar este perfil de configuración?",
"delete_custom_mode_with_rules": "¿Estás seguro de que quieres eliminar este modo {scope}?\n\nEsto también eliminará la carpeta de reglas asociada en:\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "¿Estás seguro de que quieres eliminar este agente {scope}?\n\nEsto también eliminará la carpeta de reglas asociada en:\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "Formato de URI de datos no válido",
@ -43,7 +43,7 @@
"list_api_config": "Error al obtener la lista de configuraciones de API",
"update_server_timeout": "Error al actualizar el tiempo de espera del servidor",
"hmr_not_running": "El servidor de desarrollo local no está en ejecución, HMR no funcionará. Por favor, ejecuta 'npm run dev' antes de lanzar la extensión para habilitar HMR.",
"retrieve_current_mode": "Error al recuperar el modo actual del estado.",
"retrieve_current_agent": "Error al recuperar el agente actual del estado.",
"failed_delete_repo": "Error al eliminar el repositorio o rama asociada: {{error}}",
"failed_remove_directory": "Error al eliminar el directorio de tareas: {{error}}",
"custom_storage_path_unusable": "La ruta de almacenamiento personalizada \"{{path}}\" no es utilizable, se usará la ruta predeterminada",
@ -69,7 +69,7 @@
"share_auth_required": "Se requiere autenticación. Por favor, inicia sesión para compartir tareas.",
"share_not_enabled": "La compartición de tareas no está habilitada para esta organización.",
"share_task_not_found": "Tarea no encontrada o acceso denegado.",
"mode_import_failed": "Error al importar el modo: {{error}}",
"agent_import_failed": "Error al importar el agente: {{error}}",
"delete_rules_folder_failed": "Error al eliminar la carpeta de reglas: {{rulesFolderPath}}. Error: {{error}}",
"command_not_found": "Comando '{{name}}' no encontrado",
"open_command_file": "Error al abrir el archivo de comandos",
@ -109,8 +109,8 @@
"image_saved": "Imagen guardada en {{path}}",
"organization_share_link_copied": "¡Enlace de compartición de organización copiado al portapapeles!",
"public_share_link_copied": "¡Enlace de compartición pública copiado al portapapeles!",
"mode_exported": "Modo '{{mode}}' exportado correctamente",
"mode_imported": "Modo importado correctamente"
"agent_exported": "Agente '{{agent}}' exportado correctamente",
"agent_imported": "Agente importado correctamente"
},
"answers": {
"yes": "Sí",
@ -168,8 +168,8 @@
}
},
"marketplace": {
"mode": {
"rulesCleanupFailed": "El modo se eliminó correctamente, pero no se pudo eliminar la carpeta de reglas en {{rulesFolderPath}}. Es posible que debas eliminarla manually."
"agent": {
"rulesCleanupFailed": "El agente se eliminó correctamente, pero no se pudo eliminar la carpeta de reglas en {{rulesFolderPath}}. Es posible que debas eliminarla manualmente."
}
},
"mdm": {
@ -180,10 +180,10 @@
}
},
"prompts": {
"deleteMode": {
"title": "Eliminar modo personalizado",
"description": "¿Estás seguro de que quieres eliminar este modo {{scope}}? Esto también eliminará la carpeta de reglas asociada en: {{rulesFolderPath}}",
"descriptionNoRules": "¿Estás seguro de que quieres eliminar este modo personalizado?",
"deleteAgent": {
"title": "Eliminar agente personalizado",
"description": "¿Estás seguro de que quieres eliminar este agente {{scope}}? Esto también eliminará la carpeta de reglas asociada en: {{rulesFolderPath}}",
"descriptionNoRules": "¿Estás seguro de que quieres eliminar este agente personalizado?",
"confirm": "Eliminar"
}
},

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "Modos",
"agents": "Agentes",
"mcps": "Servidores MCP",
"match": "coincidencia"
},
"item-card": {
"type-mode": "Modo",
"type-agent": "Agente",
"type-mcp": "Servidor MCP",
"type-other": "Otro",
"by-author": "por {{author}}",

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "Êtes-vous sûr de vouloir réinitialiser le global state et le stockage de secrets de l'extension ? Cette action est irréversible.",
"delete_config_profile": "Êtes-vous sûr de vouloir supprimer ce profil de configuration ?",
"delete_custom_mode_with_rules": "Êtes-vous sûr de vouloir supprimer ce mode {scope} ?\n\nCela supprimera également le dossier de règles associé à l'adresse :\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "Êtes-vous sûr de vouloir supprimer cet agent {scope} ?\n\nCela supprimera également le dossier de règles associé à l'adresse :\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "Format d'URI de données invalide",
@ -43,7 +43,7 @@
"list_api_config": "Erreur lors de l'obtention de la liste des configurations API",
"update_server_timeout": "Erreur lors de la mise à jour du délai d'attente du serveur",
"hmr_not_running": "Le serveur de développement local n'est pas en cours d'exécution, HMR ne fonctionnera pas. Veuillez exécuter 'npm run dev' avant de lancer l'extension pour activer l'HMR.",
"retrieve_current_mode": "Erreur lors de la récupération du mode actuel à partir du state.",
"retrieve_current_agent": "Erreur lors de la récupération de l'agent actuel à partir du state.",
"failed_delete_repo": "Échec de la suppression du repo fantôme ou de la branche associée : {{error}}",
"failed_remove_directory": "Échec de la suppression du répertoire de tâches : {{error}}",
"custom_storage_path_unusable": "Le chemin de stockage personnalisé \"{{path}}\" est inutilisable, le chemin par défaut sera utilisé",
@ -69,7 +69,7 @@
"share_auth_required": "Authentification requise. Veuillez vous connecter pour partager des tâches.",
"share_not_enabled": "Le partage de tâches n'est pas activé pour cette organisation.",
"share_task_not_found": "Tâche non trouvée ou accès refusé.",
"mode_import_failed": "Échec de l'importation du mode : {{error}}",
"agent_import_failed": "Échec de l'importation de l'agent : {{error}}",
"delete_rules_folder_failed": "Échec de la suppression du dossier de règles : {{rulesFolderPath}}. Erreur : {{error}}",
"command_not_found": "Commande '{{name}}' introuvable",
"open_command_file": "Échec de l'ouverture du fichier de commande",
@ -109,8 +109,8 @@
"image_saved": "Image enregistrée dans {{path}}",
"organization_share_link_copied": "Lien de partage d'organisation copié dans le presse-papiers !",
"public_share_link_copied": "Lien de partage public copié dans le presse-papiers !",
"mode_exported": "Mode '{{mode}}' exporté avec succès",
"mode_imported": "Mode importé avec succès"
"agent_exported": "Agent '{{agent}}' exporté avec succès",
"agent_imported": "Agent importé avec succès"
},
"answers": {
"yes": "Oui",
@ -150,17 +150,17 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": "YAML invalide dans le fichier .roomodes à la ligne {{line}}. Vérifie :\n• L'indentation correcte (utilise des espaces, pas de tabulations)\n• Les guillemets et crochets correspondants\n• La syntaxe YAML valide",
"schemaValidationError": "Format invalide des modes personnalisés dans .roomodes :\n{{issues}}",
"invalidFormat": "Format invalide des modes personnalisés. Assure-toi que tes paramètres suivent le format YAML correct.",
"updateFailed": "Échec de la mise à jour du mode personnalisé : {{error}}",
"deleteFailed": "Échec de la suppression du mode personnalisé : {{error}}",
"resetFailed": "Échec de la réinitialisation des modes personnalisés : {{error}}",
"modeNotFound": "Erreur d'écriture : Mode non trouvé",
"noWorkspaceForProject": "Aucun dossier d'espace de travail trouvé pour le mode spécifique au projet",
"rulesCleanupFailed": "Le mode a été supprimé avec succès, mais la suppression du dossier de règles à l'adresse {{rulesFolderPath}} a échoué. Vous devrez peut-être le supprimer manuellement."
"yamlParseError": "YAML invalide dans le fichier .rooagents à la ligne {{line}}. Vérifie :\n• L'indentation correcte (utilise des espaces, pas de tabulations)\n• Les guillemets et crochets correspondants\n• La syntaxe YAML valide",
"schemaValidationError": "Format invalide des agents personnalisés dans .rooagents :\n{{issues}}",
"invalidFormat": "Format invalide des agents personnalisés. Assure-toi que tes paramètres suivent le format YAML correct.",
"updateFailed": "Échec de la mise à jour de l'agent personnalisé : {{error}}",
"deleteFailed": "Échec de la suppression de l'agent personnalisé : {{error}}",
"resetFailed": "Échec de la réinitialisation des agents personnalisés : {{error}}",
"agentNotFound": "Erreur d'écriture : Agent non trouvé",
"noWorkspaceForProject": "Aucun dossier d'espace de travail trouvé pour l'agent spécifique au projet",
"rulesCleanupFailed": "L'agent a été supprimé avec succès, mais la suppression du dossier de règles à l'adresse {{rulesFolderPath}} a échoué. Vous devrez peut-être le supprimer manuellement."
},
"scope": {
"project": "projet",
@ -168,8 +168,8 @@
}
},
"marketplace": {
"mode": {
"rulesCleanupFailed": "Le mode a été supprimé avec succès, mais la suppression du dossier de règles à l'adresse {{rulesFolderPath}} a échoué. Vous devrez peut-être le supprimer manuellement."
"agent": {
"rulesCleanupFailed": "L'agent a été supprimé avec succès, mais la suppression du dossier de règles à l'adresse {{rulesFolderPath}} a échoué. Vous devrez peut-être le supprimer manuellement."
}
},
"mdm": {
@ -180,10 +180,10 @@
}
},
"prompts": {
"deleteMode": {
"title": "Supprimer le mode personnalisé",
"description": "Êtes-vous sûr de vouloir supprimer ce mode {{scope}} ? Cela supprimera également le dossier de règles associé à l'adresse : {{rulesFolderPath}}",
"descriptionNoRules": "Êtes-vous sûr de vouloir supprimer ce mode personnalisé ?",
"deleteAgent": {
"title": "Supprimer l'agent personnalisé",
"description": "Êtes-vous sûr de vouloir supprimer cet agent {{scope}} ? Cela supprimera également le dossier de règles associé à l'adresse : {{rulesFolderPath}}",
"descriptionNoRules": "Êtes-vous sûr de vouloir supprimer cet agent personnalisé ?",
"confirm": "Supprimer"
}
},

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "Modes",
"agents": "Agents",
"mcps": "Serveurs MCP",
"match": "correspondance"
},
"item-card": {
"type-mode": "Mode",
"type-agent": "Agent",
"type-mcp": "Serveur MCP",
"type-other": "Autre",
"by-author": "par {{author}}",

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "क्या आप वाकई एक्सटेंशन में सभी स्टेट और गुप्त स्टोरेज रीसेट करना चाहते हैं? इसे पूर्ववत नहीं किया जा सकता है।",
"delete_config_profile": "क्या आप वाकई इस कॉन्फ़िगरेशन प्रोफ़ाइल को हटाना चाहते हैं?",
"delete_custom_mode_with_rules": "क्या आप वाकई इस {scope} मोड को हटाना चाहते हैं?\n\nयह संबंधित नियम फ़ोल्डर को भी यहाँ हटा देगा:\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "क्या आप वाकई इस {scope} मोड को हटाना चाहते हैं?\n\nयह संबंधित नियम फ़ोल्डर को भी यहाँ हटा देगा:\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "अमान्य डेटा URI फॉर्मेट",
@ -69,7 +69,7 @@
"share_auth_required": "प्रमाणीकरण आवश्यक है। कार्य साझा करने के लिए कृपया साइन इन करें।",
"share_not_enabled": "इस संगठन के लिए कार्य साझाकरण सक्षम नहीं है।",
"share_task_not_found": "कार्य नहीं मिला या पहुंच अस्वीकृत।",
"mode_import_failed": "मोड आयात करने में विफल: {{error}}",
"agent_import_failed": "मोड आयात करने में विफल: {{error}}",
"delete_rules_folder_failed": "नियम फ़ोल्डर हटाने में विफल: {{rulesFolderPath}}। त्रुटि: {{error}}",
"command_not_found": "कमांड '{{name}}' नहीं मिला",
"open_command_file": "कमांड फ़ाइल खोलने में विफल",
@ -109,8 +109,8 @@
"image_saved": "छवि {{path}} में सहेजी गई",
"organization_share_link_copied": "संगठन साझाकरण लिंक क्लिपबोर्ड में कॉपी किया गया!",
"public_share_link_copied": "सार्वजनिक साझाकरण लिंक क्लिपबोर्ड में कॉपी किया गया!",
"mode_exported": "मोड '{{mode}}' सफलतापूर्वक निर्यात किया गया",
"mode_imported": "मोड सफलतापूर्वक आयात किया गया"
"agent_exported": "मोड '{{एजेंट}}' सफलतापूर्वक निर्यात किया गया",
"agent_imported": "मोड सफलतापूर्वक आयात किया गया"
},
"answers": {
"yes": "हां",
@ -150,10 +150,10 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": ".roomodes फ़ाइल में लाइन {{line}} पर अमान्य YAML। कृपया जांचें:\n• सही इंडेंटेशन (टैब नहीं, स्पेस का उपयोग करें)\n• मैचिंग कोट्स और ब्रैकेट्स\n• वैध YAML सिंटैक्स",
"schemaValidationError": ".roomodes में अमान्य कस्टम मोड फॉर्मेट:\n{{issues}}",
"yamlParseError": ".rooagents फ़ाइल में लाइन {{line}} पर अमान्य YAML। कृपया जांचें:\n• सही इंडेंटेशन (टैब नहीं, स्पेस का उपयोग करें)\n• मैचिंग कोट्स और ब्रैकेट्स\n• वैध YAML सिंटैक्स",
"schemaValidationError": ".rooagents में अमान्य कस्टम मोड फॉर्मेट:\n{{issues}}",
"invalidFormat": "अमान्य कस्टम मोड फॉर्मेट। कृपया सुनिश्चित करें कि आपकी सेटिंग्स सही YAML फॉर्मेट का पालन करती हैं।",
"updateFailed": "कस्टम मोड अपडेट विफल: {{error}}",
"deleteFailed": "कस्टम मोड डिलीट विफल: {{error}}",
@ -168,7 +168,7 @@
}
},
"marketplace": {
"mode": {
"एजेंट": {
"rulesCleanupFailed": "मोड सफलतापूर्वक हटा दिया गया, लेकिन {{rulesFolderPath}} पर नियम फ़ोल्डर को हटाने में विफल रहा। आपको इसे मैन्युअल रूप से हटाना पड़ सकता है।"
}
},
@ -180,7 +180,7 @@
}
},
"prompts": {
"deleteMode": {
"deleteAgent": {
"title": "कस्टम मोड हटाएं",
"description": "क्या आप वाकई इस {{scope}} मोड को हटाना चाहते हैं? यह संबंधित नियम फ़ोल्डर को भी {{rulesFolderPath}} पर हटा देगा",
"descriptionNoRules": "क्या आप वाकई इस कस्टम मोड को हटाना चाहते हैं?",

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "मोड्स",
"एजेंट": "मोड्स",
"mcps": "MCP सर्वर",
"match": "मैच"
},
"item-card": {
"type-mode": "मोड",
"type-एजेंट": "मोड",
"type-mcp": "MCP सर्वर",
"type-other": "अन्य",
"by-author": "{{author}} द्वारा",
@ -23,7 +23,7 @@
"type": {
"label": "प्रकार",
"all": "सभी प्रकार",
"mode": "मोड",
"एजेंट": "मोड",
"mcpServer": "MCP सर्वर"
},
"sort": {

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "Apakah kamu yakin ingin mereset semua state dan secret storage di ekstensi? Ini tidak dapat dibatalkan.",
"delete_config_profile": "Apakah kamu yakin ingin menghapus profil konfigurasi ini?",
"delete_custom_mode_with_rules": "Anda yakin ingin menghapus mode {scope} ini?\n\nIni juga akan menghapus folder aturan terkait di:\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "Anda yakin ingin menghapus Agen {scope} ini?\n\nIni juga akan menghapus folder aturan terkait di:\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "Format data URI tidak valid",
@ -43,7 +43,7 @@
"list_api_config": "Gagal mendapatkan daftar konfigurasi api",
"update_server_timeout": "Gagal memperbarui timeout server",
"hmr_not_running": "Server pengembangan lokal tidak berjalan, HMR tidak akan bekerja. Silakan jalankan 'npm run dev' sebelum meluncurkan ekstensi untuk mengaktifkan HMR.",
"retrieve_current_mode": "Error: gagal mengambil mode saat ini dari state.",
"retrieve_current_mode": "Error: gagal mengambil Agen saat ini dari state.",
"failed_delete_repo": "Gagal menghapus shadow repository atau branch yang terkait: {{error}}",
"failed_remove_directory": "Gagal menghapus direktori tugas: {{error}}",
"custom_storage_path_unusable": "Path penyimpanan kustom \"{{path}}\" tidak dapat digunakan, akan menggunakan path default",
@ -69,7 +69,7 @@
"share_auth_required": "Autentikasi diperlukan. Silakan masuk untuk berbagi tugas.",
"share_not_enabled": "Berbagi tugas tidak diaktifkan untuk organisasi ini.",
"share_task_not_found": "Tugas tidak ditemukan atau akses ditolak.",
"mode_import_failed": "Gagal mengimpor mode: {{error}}",
"agent_import_failed": "Gagal mengimpor Agen: {{error}}",
"delete_rules_folder_failed": "Gagal menghapus folder aturan: {{rulesFolderPath}}. Error: {{error}}",
"command_not_found": "Perintah '{{name}}' tidak ditemukan",
"open_command_file": "Gagal membuka file perintah",
@ -109,8 +109,8 @@
"image_saved": "Gambar disimpan ke {{path}}",
"organization_share_link_copied": "Tautan berbagi organisasi disalin ke clipboard!",
"public_share_link_copied": "Tautan berbagi publik disalin ke clipboard!",
"mode_exported": "Mode '{{mode}}' berhasil diekspor",
"mode_imported": "Mode berhasil diimpor"
"agent_exported": "Agen '{{Agen}}' berhasil diekspor",
"agent_imported": "Agen berhasil diimpor"
},
"answers": {
"yes": "Ya",
@ -150,17 +150,17 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": "YAML tidak valid dalam file .roomodes pada baris {{line}}. Silakan periksa:\n• Indentasi yang benar (gunakan spasi, bukan tab)\n• Tanda kutip dan kurung yang cocok\n• Sintaks YAML yang valid",
"schemaValidationError": "Format mode kustom tidak valid dalam .roomodes:\n{{issues}}",
"invalidFormat": "Format mode kustom tidak valid. Pastikan pengaturan kamu mengikuti format YAML yang benar.",
"updateFailed": "Gagal memperbarui mode kustom: {{error}}",
"deleteFailed": "Gagal menghapus mode kustom: {{error}}",
"resetFailed": "Gagal mereset mode kustom: {{error}}",
"modeNotFound": "Kesalahan tulis: Mode tidak ditemukan",
"noWorkspaceForProject": "Tidak ditemukan folder workspace untuk mode khusus proyek",
"rulesCleanupFailed": "Mode berhasil dihapus, tetapi gagal menghapus folder aturan di {{rulesFolderPath}}. Kamu mungkin perlu menghapusnya secara manual."
"yamlParseError": "YAML tidak valid dalam file .rooagents pada baris {{line}}. Silakan periksa:\n• Indentasi yang benar (gunakan spasi, bukan tab)\n• Tanda kutip dan kurung yang cocok\n• Sintaks YAML yang valid",
"schemaValidationError": "Format Agen kustom tidak valid dalam .rooagents:\n{{issues}}",
"invalidFormat": "Format Agen kustom tidak valid. Pastikan pengaturan kamu mengikuti format YAML yang benar.",
"updateFailed": "Gagal memperbarui Agen kustom: {{error}}",
"deleteFailed": "Gagal menghapus Agen kustom: {{error}}",
"resetFailed": "Gagal mereset Agen kustom: {{error}}",
"modeNotFound": "Kesalahan tulis: Agen tidak ditemukan",
"noWorkspaceForProject": "Tidak ditemukan folder workspace untuk Agen khusus proyek",
"rulesCleanupFailed": "Agen berhasil dihapus, tetapi gagal menghapus folder aturan di {{rulesFolderPath}}. Kamu mungkin perlu menghapusnya secara manual."
},
"scope": {
"project": "proyek",
@ -168,8 +168,8 @@
}
},
"marketplace": {
"mode": {
"rulesCleanupFailed": "Mode berhasil dihapus, tetapi gagal menghapus folder aturan di {{rulesFolderPath}}. Kamu mungkin perlu menghapusnya secara manual."
"Agen": {
"rulesCleanupFailed": "Agen berhasil dihapus, tetapi gagal menghapus folder aturan di {{rulesFolderPath}}. Kamu mungkin perlu menghapusnya secara manual."
}
},
"mdm": {
@ -180,10 +180,10 @@
}
},
"prompts": {
"deleteMode": {
"title": "Hapus Mode Kustom",
"description": "Anda yakin ingin menghapus mode {{scope}} ini? Ini juga akan menghapus folder aturan terkait di: {{rulesFolderPath}}",
"descriptionNoRules": "Anda yakin ingin menghapus mode kustom ini?",
"deleteAgent": {
"title": "Hapus Agen Kustom",
"description": "Anda yakin ingin menghapus Agen {{scope}} ini? Ini juga akan menghapus folder aturan terkait di: {{rulesFolderPath}}",
"descriptionNoRules": "Anda yakin ingin menghapus Agen kustom ini?",
"confirm": "Hapus"
}
},

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "Mode",
"Agen": "Agen",
"mcps": "Server MCP",
"match": "cocok"
},
"item-card": {
"type-mode": "Mode",
"type-Agen": "Agen",
"type-mcp": "Server MCP",
"type-other": "Lainnya",
"by-author": "oleh {{author}}",
@ -23,7 +23,7 @@
"type": {
"label": "Tipe",
"all": "Semua Tipe",
"mode": "Mode",
"Agen": "Agen",
"mcpServer": "Server MCP"
},
"sort": {

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "Sei sicuro di voler reimpostare tutti gli stati e l'archiviazione segreta nell'estensione? Questa azione non può essere annullata.",
"delete_config_profile": "Sei sicuro di voler eliminare questo profilo di configurazione?",
"delete_custom_mode_with_rules": "Sei sicuro di voler eliminare questa modalità {scope}?\n\nQuesto eliminerà anche la cartella delle regole associata in:\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "Sei sicuro di voler eliminare questa modalità {scope}?\n\nQuesto eliminerà anche la cartella delle regole associata in:\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "Formato URI dati non valido",
@ -69,7 +69,7 @@
"share_auth_required": "Autenticazione richiesta. Accedi per condividere le attività.",
"share_not_enabled": "La condivisione delle attività non è abilitata per questa organizzazione.",
"share_task_not_found": "Attività non trovata o accesso negato.",
"mode_import_failed": "Importazione della modalità non riuscita: {{error}}",
"agent_import_failed": "Importazione della modalità non riuscita: {{error}}",
"delete_rules_folder_failed": "Impossibile eliminare la cartella delle regole: {{rulesFolderPath}}. Errore: {{error}}",
"command_not_found": "Comando '{{name}}' non trovato",
"open_command_file": "Impossibile aprire il file di comando",
@ -109,8 +109,8 @@
"image_saved": "Immagine salvata in {{path}}",
"organization_share_link_copied": "Link di condivisione organizzazione copiato negli appunti!",
"public_share_link_copied": "Link di condivisione pubblica copiato negli appunti!",
"mode_exported": "Modalità '{{mode}}' esportata con successo",
"mode_imported": "Modalità importata con successo"
"agent_exported": "Modalità '{{Agente}}' esportata con successo",
"agent_imported": "Modalità importata con successo"
},
"answers": {
"yes": "Sì",
@ -150,10 +150,10 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": "YAML non valido nel file .roomodes alla riga {{line}}. Controlla:\n• Indentazione corretta (usa spazi, non tab)\n• Virgolette e parentesi corrispondenti\n• Sintassi YAML valida",
"schemaValidationError": "Formato modalità personalizzate non valido in .roomodes:\n{{issues}}",
"yamlParseError": "YAML non valido nel file .rooagents alla riga {{line}}. Controlla:\n• Indentazione corretta (usa spazi, non tab)\n• Virgolette e parentesi corrispondenti\n• Sintassi YAML valida",
"schemaValidationError": "Formato modalità personalizzate non valido in .rooagents:\n{{issues}}",
"invalidFormat": "Formato modalità personalizzate non valido. Assicurati che le tue impostazioni seguano il formato YAML corretto.",
"updateFailed": "Aggiornamento modalità personalizzata fallito: {{error}}",
"deleteFailed": "Eliminazione modalità personalizzata fallita: {{error}}",
@ -168,7 +168,7 @@
}
},
"marketplace": {
"mode": {
"Agente": {
"rulesCleanupFailed": "La modalità è stata rimossa con successo, ma non è stato possibile eliminare la cartella delle regole in {{rulesFolderPath}}. Potrebbe essere necessario eliminarla manualmente."
}
},
@ -180,7 +180,7 @@
}
},
"prompts": {
"deleteMode": {
"deleteAgent": {
"title": "Elimina Modalità Personalizzata",
"description": "Sei sicuro di voler eliminare questa modalità {{scope}}? Questo eliminerà anche la cartella delle regole associata a: {{rulesFolderPath}}",
"descriptionNoRules": "Sei sicuro di voler eliminare questa modalità personalizzata?",

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "Modalità",
"Agenti": "Modalità",
"mcps": "Server MCP",
"match": "corrispondenza"
},
"item-card": {
"type-mode": "Modalità",
"type-Agente": "Modalità",
"type-mcp": "Server MCP",
"type-other": "Altro",
"by-author": "di {{author}}",
@ -23,7 +23,7 @@
"type": {
"label": "Tipo",
"all": "Tutti i tipi",
"mode": "Modalità",
"Agente": "Modalità",
"mcpServer": "Server MCP"
},
"sort": {

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "拡張機能のすべての状態とシークレットストレージをリセットしてもよろしいですか?この操作は元に戻せません。",
"delete_config_profile": "この設定プロファイルを削除してもよろしいですか?",
"delete_custom_mode_with_rules": "この{scope}モードを削除してもよろしいですか?\n\nこれにより、関連するルールフォルダも次の場所で削除されます:\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "この{scope}エージェントを削除してもよろしいですか?\n\nこれにより、関連するルールフォルダも次の場所で削除されます:\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "データURIフォーマットが無効です",
@ -43,7 +43,7 @@
"list_api_config": "API設定リストの取得に失敗しました",
"update_server_timeout": "サーバータイムアウトの更新に失敗しました",
"hmr_not_running": "ローカル開発サーバーが実行されていないため、HMRは機能しません。HMRを有効にするには、拡張機能を起動する前に'npm run dev'を実行してください。",
"retrieve_current_mode": "現在のモードを状態から取得する際にエラーが発生しました。",
"retrieve_current_agent": "現在のエージェントを状態から取得する際にエラーが発生しました。",
"failed_delete_repo": "関連するシャドウリポジトリまたはブランチの削除に失敗しました:{{error}}",
"failed_remove_directory": "タスクディレクトリの削除に失敗しました:{{error}}",
"custom_storage_path_unusable": "カスタムストレージパス \"{{path}}\" が使用できないため、デフォルトパスを使用します",
@ -69,7 +69,7 @@
"share_auth_required": "認証が必要です。タスクを共有するにはサインインしてください。",
"share_not_enabled": "この組織ではタスク共有が有効になっていません。",
"share_task_not_found": "タスクが見つからないか、アクセスが拒否されました。",
"mode_import_failed": "モードのインポートに失敗しました:{{error}}",
"agent_import_failed": "エージェントのインポートに失敗しました:{{error}}",
"delete_rules_folder_failed": "ルールフォルダの削除に失敗しました:{{rulesFolderPath}}。エラー:{{error}}",
"command_not_found": "コマンド '{{name}}' が見つかりません",
"open_command_file": "コマンドファイルを開けませんでした",
@ -109,8 +109,8 @@
"image_saved": "画像を{{path}}に保存しました",
"organization_share_link_copied": "組織共有リンクがクリップボードにコピーされました!",
"public_share_link_copied": "公開共有リンクがクリップボードにコピーされました!",
"mode_exported": "モード「{{mode}}」が正常にエクスポートされました",
"mode_imported": "モードが正常にインポートされました"
"agent_exported": "エージェント「{{agent}}」が正常にエクスポートされました",
"agent_imported": "エージェントが正常にインポートされました"
},
"answers": {
"yes": "はい",
@ -150,17 +150,17 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": ".roomodes ファイルの {{line}} 行目で無効な YAML です。以下を確認してください:\n• 正しいインデント(タブではなくスペースを使用)\n• 引用符と括弧の対応\n• 有効な YAML 構文",
"schemaValidationError": ".roomodes のカスタムモード形式が無効です:\n{{issues}}",
"invalidFormat": "カスタムモード形式が無効です。設定が正しい YAML 形式に従っていることを確認してください。",
"updateFailed": "カスタムモードの更新に失敗しました:{{error}}",
"deleteFailed": "カスタムモードの削除に失敗しました:{{error}}",
"resetFailed": "カスタムモードのリセットに失敗しました:{{error}}",
"modeNotFound": "書き込みエラー:モードが見つかりません",
"noWorkspaceForProject": "プロジェクト固有モード用のワークスペースフォルダーが見つかりません",
"rulesCleanupFailed": "モードは正常に削除されましたが、{{rulesFolderPath}} にあるルールフォルダの削除に失敗しました。手動で削除する必要がある場合があります。"
"yamlParseError": ".rooagents ファイルの {{line}} 行目で無効な YAML です。以下を確認してください:\n• 正しいインデント(タブではなくスペースを使用)\n• 引用符と括弧の対応\n• 有効な YAML 構文",
"schemaValidationError": ".rooagents のカスタムエージェント形式が無効です:\n{{issues}}",
"invalidFormat": "カスタムエージェント形式が無効です。設定が正しい YAML 形式に従っていることを確認してください。",
"updateFailed": "カスタムエージェントの更新に失敗しました:{{error}}",
"deleteFailed": "カスタムエージェントの削除に失敗しました:{{error}}",
"resetFailed": "カスタムエージェントのリセットに失敗しました:{{error}}",
"agentNotFound": "書き込みエラー:エージェントが見つかりません",
"noWorkspaceForProject": "プロジェクト固有エージェント用のワークスペースフォルダーが見つかりません",
"rulesCleanupFailed": "エージェントは正常に削除されましたが、{{rulesFolderPath}} にあるルールフォルダの削除に失敗しました。手動で削除する必要がある場合があります。"
},
"scope": {
"project": "プロジェクト",
@ -168,8 +168,8 @@
}
},
"marketplace": {
"mode": {
"rulesCleanupFailed": "モードは正常に削除されましたが、{{rulesFolderPath}} にあるルールフォルダの削除に失敗しました。手動で削除する必要がある場合があります。"
"agent": {
"rulesCleanupFailed": "エージェントは正常に削除されましたが、{{rulesFolderPath}} にあるルールフォルダの削除に失敗しました。手動で削除する必要がある場合があります。"
}
},
"mdm": {

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "モード",
"agents": "エージェント",
"mcps": "MCPサーバー",
"match": "マッチ"
},
"item-card": {
"type-mode": "モード",
"type-agent": "エージェント",
"type-mcp": "MCPサーバー",
"type-other": "その他",
"by-author": "{{author}}による",

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "확장 프로그램의 모든 상태와 보안 저장소를 재설정하시겠습니까? 이 작업은 취소할 수 없습니다.",
"delete_config_profile": "이 구성 프로필을 삭제하시겠습니까?",
"delete_custom_mode_with_rules": "이 {scope} 모드를 삭제하시겠습니까?\n\n이렇게 하면 연결된 규칙 폴더도 다음 위치에서 삭제됩니다:\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "이 {scope} 모드를 삭제하시겠습니까?\n\n이렇게 하면 연결된 규칙 폴더도 다음 위치에서 삭제됩니다:\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "잘못된 데이터 URI 형식",
@ -69,7 +69,7 @@
"share_auth_required": "인증이 필요합니다. 작업을 공유하려면 로그인하세요.",
"share_not_enabled": "이 조직에서는 작업 공유가 활성화되지 않았습니다.",
"share_task_not_found": "작업을 찾을 수 없거나 액세스가 거부되었습니다.",
"mode_import_failed": "모드 가져오기 실패: {{error}}",
"agent_import_failed": "모드 가져오기 실패: {{error}}",
"delete_rules_folder_failed": "규칙 폴더 삭제 실패: {{rulesFolderPath}}. 오류: {{error}}",
"command_not_found": "'{{name}}' 명령을 찾을 수 없습니다",
"open_command_file": "명령 파일을 열 수 없습니다",
@ -109,8 +109,8 @@
"image_saved": "이미지가 {{path}}에 저장되었습니다",
"organization_share_link_copied": "조직 공유 링크가 클립보드에 복사되었습니다!",
"public_share_link_copied": "공개 공유 링크가 클립보드에 복사되었습니다!",
"mode_exported": "'{{mode}}' 모드가 성공적으로 내보내졌습니다",
"mode_imported": "모드를 성공적으로 가져왔습니다"
"agent_exported": "'{{에이전트}}' 모드가 성공적으로 내보내졌습니다",
"agent_imported": "모드를 성공적으로 가져왔습니다"
},
"answers": {
"yes": "예",
@ -150,10 +150,10 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": ".roomodes 파일의 {{line}}번째 줄에서 유효하지 않은 YAML입니다. 다음을 확인하세요:\n• 올바른 들여쓰기 (탭이 아닌 공백 사용)\n• 일치하는 따옴표와 괄호\n• 유효한 YAML 구문",
"schemaValidationError": ".roomodes의 사용자 정의 모드 형식이 유효하지 않습니다:\n{{issues}}",
"yamlParseError": ".rooagents 파일의 {{line}}번째 줄에서 유효하지 않은 YAML입니다. 다음을 확인하세요:\n• 올바른 들여쓰기 (탭이 아닌 공백 사용)\n• 일치하는 따옴표와 괄호\n• 유효한 YAML 구문",
"schemaValidationError": ".rooagents의 사용자 정의 모드 형식이 유효하지 않습니다:\n{{issues}}",
"invalidFormat": "사용자 정의 모드 형식이 유효하지 않습니다. 설정이 올바른 YAML 형식을 따르는지 확인하세요.",
"updateFailed": "사용자 정의 모드 업데이트 실패: {{error}}",
"deleteFailed": "사용자 정의 모드 삭제 실패: {{error}}",
@ -168,7 +168,7 @@
}
},
"marketplace": {
"mode": {
"에이전트": {
"rulesCleanupFailed": "모드가 성공적으로 제거되었지만 {{rulesFolderPath}}의 규칙 폴더를 삭제하지 못했습니다. 수동으로 삭제해야 할 수도 있습니다."
}
},
@ -180,7 +180,7 @@
}
},
"prompts": {
"deleteMode": {
"deleteAgent": {
"title": "사용자 정의 모드 삭제",
"description": "이 {{scope}} 모드를 삭제하시겠습니까? 이렇게 하면 {{rulesFolderPath}}의 관련 규칙 폴더도 삭제됩니다.",
"descriptionNoRules": "이 사용자 정의 모드를 삭제하시겠습니까?",

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "모드",
"에이전트": "모드",
"mcps": "MCP 서버",
"match": "일치"
},
"item-card": {
"type-mode": "모드",
"type-에이전트": "모드",
"type-mcp": "MCP 서버",
"type-other": "기타",
"by-author": "{{author}} 작성",
@ -23,7 +23,7 @@
"type": {
"label": "유형",
"all": "모든 유형",
"mode": "모드",
"에이전트": "모드",
"mcpServer": "MCP 서버"
},
"sort": {

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "Weet je zeker dat je alle status en geheime opslag in de extensie wilt resetten? Dit kan niet ongedaan worden gemaakt.",
"delete_config_profile": "Weet je zeker dat je dit configuratieprofiel wilt verwijderen?",
"delete_custom_mode_with_rules": "Weet je zeker dat je deze {scope}-modus wilt verwijderen?\n\nDit verwijdert ook de bijbehorende regelsmap op:\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "Weet je zeker dat je deze {scope}-modus wilt verwijderen?\n\nDit verwijdert ook de bijbehorende regelsmap op:\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "Ongeldig data-URI-formaat",
@ -69,7 +69,7 @@
"share_auth_required": "Authenticatie vereist. Log in om taken te delen.",
"share_not_enabled": "Taken delen is niet ingeschakeld voor deze organisatie.",
"share_task_not_found": "Taak niet gevonden of toegang geweigerd.",
"mode_import_failed": "Importeren van modus mislukt: {{error}}",
"agent_import_failed": "Importeren van modus mislukt: {{error}}",
"delete_rules_folder_failed": "Kan regelmap niet verwijderen: {{rulesFolderPath}}. Fout: {{error}}",
"command_not_found": "Opdracht '{{name}}' niet gevonden",
"open_command_file": "Kan opdrachtbestand niet openen",
@ -109,8 +109,8 @@
"image_saved": "Afbeelding opgeslagen naar {{path}}",
"organization_share_link_copied": "Organisatie deel-link gekopieerd naar klembord!",
"public_share_link_copied": "Openbare deel-link gekopieerd naar klembord!",
"mode_exported": "Modus '{{mode}}' succesvol geëxporteerd",
"mode_imported": "Modus succesvol geïmporteerd"
"agent_exported": "Modus '{{Agent}}' succesvol geëxporteerd",
"agent_imported": "Modus succesvol geïmporteerd"
},
"answers": {
"yes": "Ja",
@ -150,10 +150,10 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": "Ongeldige YAML in .roomodes bestand op regel {{line}}. Controleer:\n• Juiste inspringing (gebruik spaties, geen tabs)\n• Overeenkomende aanhalingstekens en haakjes\n• Geldige YAML syntaxis",
"schemaValidationError": "Ongeldig aangepaste modi formaat in .roomodes:\n{{issues}}",
"yamlParseError": "Ongeldige YAML in .rooagents bestand op regel {{line}}. Controleer:\n• Juiste inspringing (gebruik spaties, geen tabs)\n• Overeenkomende aanhalingstekens en haakjes\n• Geldige YAML syntaxis",
"schemaValidationError": "Ongeldig aangepaste modi formaat in .rooagents:\n{{issues}}",
"invalidFormat": "Ongeldig aangepaste modi formaat. Zorg ervoor dat je instellingen het juiste YAML formaat volgen.",
"updateFailed": "Aangepaste modus bijwerken mislukt: {{error}}",
"deleteFailed": "Aangepaste modus verwijderen mislukt: {{error}}",
@ -168,7 +168,7 @@
}
},
"marketplace": {
"mode": {
"Agent": {
"rulesCleanupFailed": "Modus succesvol verwijderd, maar het verwijderen van de regelsmap op {{rulesFolderPath}} is mislukt. Je moet deze mogelijk handmatig verwijderen."
}
},
@ -180,7 +180,7 @@
}
},
"prompts": {
"deleteMode": {
"deleteAgent": {
"title": "Aangepaste modus verwijderen",
"description": "Weet je zeker dat je deze {{scope}}-modus wilt verwijderen? Dit zal ook de bijbehorende regelsmap op {{rulesFolderPath}} verwijderen",
"descriptionNoRules": "Weet je zeker dat je deze aangepaste modus wilt verwijderen?",

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "Modi",
"Agenten": "Modi",
"mcps": "MCP Servers",
"match": "overeenkomst"
},
"item-card": {
"type-mode": "Modus",
"type-Agent": "Modus",
"type-mcp": "MCP Server",
"type-other": "Andere",
"by-author": "door {{author}}",
@ -23,7 +23,7 @@
"type": {
"label": "Type",
"all": "Alle types",
"mode": "Modus",
"Agent": "Modus",
"mcpServer": "MCP Server"
},
"sort": {

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "Czy na pewno chcesz zresetować wszystkie stany i tajne magazyny w rozszerzeniu? Tej operacji nie można cofnąć.",
"delete_config_profile": "Czy na pewno chcesz usunąć ten profil konfiguracyjny?",
"delete_custom_mode_with_rules": "Czy na pewno chcesz usunąć ten tryb {scope}?\n\nSpowoduje to również usunięcie powiązanego folderu reguł pod adresem:\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "Czy na pewno chcesz usunąć ten tryb {scope}?\n\nSpowoduje to również usunięcie powiązanego folderu reguł pod adresem:\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "Nieprawidłowy format URI danych",
@ -69,7 +69,7 @@
"share_auth_required": "Wymagana autoryzacja. Zaloguj się, aby udostępniać zadania.",
"share_not_enabled": "Udostępnianie zadań nie jest włączone dla tej organizacji.",
"share_task_not_found": "Zadanie nie znalezione lub dostęp odmówiony.",
"mode_import_failed": "Import trybu nie powiódł się: {{error}}",
"agent_import_failed": "Import trybu nie powiódł się: {{error}}",
"delete_rules_folder_failed": "Nie udało się usunąć folderu reguł: {{rulesFolderPath}}. Błąd: {{error}}",
"command_not_found": "Polecenie '{{name}}' nie zostało znalezione",
"open_command_file": "Nie udało się otworzyć pliku polecenia",
@ -109,8 +109,8 @@
"image_saved": "Obraz zapisany w {{path}}",
"organization_share_link_copied": "Link udostępniania organizacji skopiowany do schowka!",
"public_share_link_copied": "Publiczny link udostępniania skopiowany do schowka!",
"mode_exported": "Tryb '{{mode}}' pomyślnie wyeksportowany",
"mode_imported": "Tryb pomyślnie zaimportowany"
"agent_exported": "Tryb '{{Agent}}' pomyślnie wyeksportowany",
"agent_imported": "Tryb pomyślnie zaimportowany"
},
"answers": {
"yes": "Tak",
@ -150,10 +150,10 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": "Nieprawidłowy YAML w pliku .roomodes w linii {{line}}. Sprawdź:\n• Prawidłowe wcięcia (używaj spacji, nie tabulatorów)\n• Pasujące cudzysłowy i nawiasy\n• Prawidłową składnię YAML",
"schemaValidationError": "Nieprawidłowy format trybów niestandardowych w .roomodes:\n{{issues}}",
"yamlParseError": "Nieprawidłowy YAML w pliku .rooagents w linii {{line}}. Sprawdź:\n• Prawidłowe wcięcia (używaj spacji, nie tabulatorów)\n• Pasujące cudzysłowy i nawiasy\n• Prawidłową składnię YAML",
"schemaValidationError": "Nieprawidłowy format trybów niestandardowych w .rooagents:\n{{issues}}",
"invalidFormat": "Nieprawidłowy format trybów niestandardowych. Upewnij się, że twoje ustawienia są zgodne z prawidłowym formatem YAML.",
"updateFailed": "Aktualizacja trybu niestandardowego nie powiodła się: {{error}}",
"deleteFailed": "Usunięcie trybu niestandardowego nie powiodło się: {{error}}",
@ -168,7 +168,7 @@
}
},
"marketplace": {
"mode": {
"Agent": {
"rulesCleanupFailed": "Tryb został pomyślnie usunięty, ale nie udało się usunąć folderu reguł w {{rulesFolderPath}}. Może być konieczne ręczne usunięcie."
}
},
@ -180,7 +180,7 @@
}
},
"prompts": {
"deleteMode": {
"deleteAgent": {
"title": "Usuń tryb niestandardowy",
"description": "Czy na pewno chcesz usunąć ten tryb {{scope}}? Spowoduje to również usunięcie powiązanego folderu z regułami w {{rulesFolderPath}}",
"descriptionNoRules": "Czy na pewno chcesz usunąć ten tryb niestandardowy?",

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "Tryby",
"Agenci": "Tryby",
"mcps": "Serwery MCP",
"match": "dopasowanie"
},
"item-card": {
"type-mode": "Tryb",
"type-Agent": "Tryb",
"type-mcp": "Serwer MCP",
"type-other": "Inne",
"by-author": "przez {{author}}",
@ -23,7 +23,7 @@
"type": {
"label": "Typ",
"all": "Wszystkie typy",
"mode": "Tryb",
"Agent": "Tryb",
"mcpServer": "Serwer MCP"
},
"sort": {

View file

@ -21,7 +21,7 @@
"confirmation": {
"reset_state": "Tem certeza de que deseja redefinir todo o estado e armazenamento secreto na extensão? Isso não pode ser desfeito.",
"delete_config_profile": "Tem certeza de que deseja excluir este perfil de configuração?",
"delete_custom_mode_with_rules": "Tem certeza de que deseja excluir este modo {scope}?\n\nIsso também excluirá a pasta de regras associada em:\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "Tem certeza de que deseja excluir este modo {scope}?\n\nIsso também excluirá a pasta de regras associada em:\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "Formato de URI de dados inválido",
@ -73,7 +73,7 @@
"share_auth_required": "Autenticação necessária. Faça login para compartilhar tarefas.",
"share_not_enabled": "O compartilhamento de tarefas não está habilitado para esta organização.",
"share_task_not_found": "Tarefa não encontrada ou acesso negado.",
"mode_import_failed": "Falha ao importar o modo: {{error}}",
"agent_import_failed": "Falha ao importar o modo: {{error}}",
"delete_rules_folder_failed": "Falha ao excluir pasta de regras: {{rulesFolderPath}}. Erro: {{error}}",
"command_not_found": "Comando '{{name}}' não encontrado",
"open_command_file": "Falha ao abrir arquivo de comando",
@ -113,8 +113,8 @@
"image_saved": "Imagem salva em {{path}}",
"organization_share_link_copied": "Link de compartilhamento da organização copiado para a área de transferência!",
"public_share_link_copied": "Link de compartilhamento público copiado para a área de transferência!",
"mode_exported": "Modo '{{mode}}' exportado com sucesso",
"mode_imported": "Modo importado com sucesso"
"agent_exported": "Modo '{{Agente}}' exportado com sucesso",
"agent_imported": "Modo importado com sucesso"
},
"answers": {
"yes": "Sim",
@ -150,10 +150,10 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": "YAML inválido no arquivo .roomodes na linha {{line}}. Verifique:\n• Indentação correta (use espaços, não tabs)\n• Aspas e colchetes correspondentes\n• Sintaxe YAML válida",
"schemaValidationError": "Formato de modos personalizados inválido em .roomodes:\n{{issues}}",
"yamlParseError": "YAML inválido no arquivo .rooagents na linha {{line}}. Verifique:\n• Indentação correta (use espaços, não tabs)\n• Aspas e colchetes correspondentes\n• Sintaxe YAML válida",
"schemaValidationError": "Formato de modos personalizados inválido em .rooagents:\n{{issues}}",
"invalidFormat": "Formato de modos personalizados inválido. Certifique-se de que suas configurações seguem o formato YAML correto.",
"updateFailed": "Falha ao atualizar modo personalizado: {{error}}",
"deleteFailed": "Falha ao excluir modo personalizado: {{error}}",
@ -168,7 +168,7 @@
}
},
"marketplace": {
"mode": {
"Agente": {
"rulesCleanupFailed": "O modo foi removido com sucesso, mas falhou ao excluir a pasta de regras em {{rulesFolderPath}}. Você pode precisar excluí-la manualmente."
}
},
@ -180,7 +180,7 @@
}
},
"prompts": {
"deleteMode": {
"deleteAgent": {
"title": "Excluir Modo Personalizado",
"description": "Tem certeza de que deseja excluir este modo {{scope}}? Isso também excluirá a pasta de regras associada em: {{rulesFolderPath}}",
"descriptionNoRules": "Tem certeza de que deseja excluir este modo personalizado?",

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "Modos",
"Agentes": "Modos",
"mcps": "Servidores MCP",
"match": "correspondência"
},
"item-card": {
"type-mode": "Modo",
"type-Agente": "Modo",
"type-mcp": "Servidor MCP",
"type-other": "Outro",
"by-author": "por {{author}}",
@ -23,7 +23,7 @@
"type": {
"label": "Tipo",
"all": "Todos os tipos",
"mode": "Modo",
"Agente": "Modo",
"mcpServer": "Servidor MCP"
},
"sort": {

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "Вы уверены, что хотите сбросить все состояние и секретное хранилище в расширении? Это действие нельзя отменить.",
"delete_config_profile": "Вы уверены, что хотите удалить этот профиль конфигурации?",
"delete_custom_mode_with_rules": "Вы уверены, что хотите удалить этот режим {scope}?\n\nЭто также приведет к удалению соответствующей папки правил по адресу:\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "Вы уверены, что хотите удалить этот режим {scope}?\n\nЭто также приведет к удалению соответствующей папки правил по адресу:\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "Неверный формат URI данных",
@ -69,7 +69,7 @@
"share_auth_required": "Требуется аутентификация. Войдите в систему для совместного доступа к задачам.",
"share_not_enabled": "Совместный доступ к задачам не включен для этой организации.",
"share_task_not_found": "Задача не найдена или доступ запрещен.",
"mode_import_failed": "Не удалось импортировать режим: {{error}}",
"agent_import_failed": "Не удалось импортировать режим: {{error}}",
"delete_rules_folder_failed": "Не удалось удалить папку правил: {{rulesFolderPath}}. Ошибка: {{error}}",
"command_not_found": "Команда '{{name}}' не найдена",
"open_command_file": "Не удалось открыть файл команды",
@ -109,8 +109,8 @@
"image_saved": "Изображение сохранено в {{path}}",
"organization_share_link_copied": "Ссылка для совместного доступа организации скопирована в буфер обмена!",
"public_share_link_copied": "Публичная ссылка для совместного доступа скопирована в буфер обмена!",
"mode_exported": "Режим '{{mode}}' успешно экспортирован",
"mode_imported": "Режим успешно импортирован"
"agent_exported": "Режим '{{Агент}}' успешно экспортирован",
"agent_imported": "Режим успешно импортирован"
},
"answers": {
"yes": "Да",
@ -150,10 +150,10 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": "Недопустимый YAML в файле .roomodes на строке {{line}}. Проверь:\n• Правильные отступы (используй пробелы, не табы)\n• Соответствующие кавычки и скобки\n• Допустимый синтаксис YAML",
"schemaValidationError": "Недопустимый формат пользовательских режимов в .roomodes:\n{{issues}}",
"yamlParseError": "Недопустимый YAML в файле .rooagents на строке {{line}}. Проверь:\n• Правильные отступы (используй пробелы, не табы)\n• Соответствующие кавычки и скобки\n• Допустимый синтаксис YAML",
"schemaValidationError": "Недопустимый формат пользовательских режимов в .rooagents:\n{{issues}}",
"invalidFormat": "Недопустимый формат пользовательских режимов. Убедись, что твои настройки соответствуют правильному формату YAML.",
"updateFailed": "Не удалось обновить пользовательский режим: {{error}}",
"deleteFailed": "Не удалось удалить пользовательский режим: {{error}}",
@ -168,7 +168,7 @@
}
},
"marketplace": {
"mode": {
"Агент": {
"rulesCleanupFailed": "Режим успешно удален, но не удалось удалить папку правил в {{rulesFolderPath}}. Возможно, вам придется удалить ее вручную."
}
},
@ -180,7 +180,7 @@
}
},
"prompts": {
"deleteMode": {
"deleteAgent": {
"title": "Удалить пользовательский режим",
"description": "Вы уверены, что хотите удалить этот режим {{scope}}? Это также удалит связанную папку правил по адресу: {{rulesFolderPath}}",
"descriptionNoRules": "Вы уверены, что хотите удалить этот пользовательский режим?",

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "Режимы",
"Агенты": "Режимы",
"mcps": "MCP серверы",
"match": "совпадение"
},
"item-card": {
"type-mode": "Режим",
"type-Агент": "Режим",
"type-mcp": "MCP сервер",
"type-other": "Другое",
"by-author": "от {{author}}",
@ -23,7 +23,7 @@
"type": {
"label": "Тип",
"all": "Все типы",
"mode": "Режим",
"Агент": "Режим",
"mcpServer": "MCP сервер"
},
"sort": {

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "Uzantıdaki tüm durumları ve gizli depolamayı sıfırlamak istediğinizden emin misiniz? Bu işlem geri alınamaz.",
"delete_config_profile": "Bu yapılandırma profilini silmek istediğinizden emin misiniz?",
"delete_custom_mode_with_rules": "Bu {scope} modunu silmek istediğinizden emin misiniz?\n\nBu işlem, ilişkili kurallar klasörünü de şu konumdan silecektir:\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "Bu {scope} modunu silmek istediğinizden emin misiniz?\n\nBu işlem, ilişkili kurallar klasörünü de şu konumdan silecektir:\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "Geçersiz veri URI formatı",
@ -69,7 +69,7 @@
"share_auth_required": "Kimlik doğrulama gerekli. Görevleri paylaşmak için lütfen giriş yapın.",
"share_not_enabled": "Bu kuruluş için görev paylaşımı etkinleştirilmemiş.",
"share_task_not_found": "Görev bulunamadı veya erişim reddedildi.",
"mode_import_failed": "Mod içe aktarılamadı: {{error}}",
"agent_import_failed": "Mod içe aktarılamadı: {{error}}",
"delete_rules_folder_failed": "Kurallar klasörü silinemedi: {{rulesFolderPath}}. Hata: {{error}}",
"command_not_found": "'{{name}}' komutu bulunamadı",
"open_command_file": "Komut dosyasıılamadı",
@ -109,8 +109,8 @@
"image_saved": "Resim {{path}} konumuna kaydedildi",
"organization_share_link_copied": "Kuruluş paylaşım bağlantısı panoya kopyalandı!",
"public_share_link_copied": "Herkese açık paylaşım bağlantısı panoya kopyalandı!",
"mode_exported": "'{{mode}}' modu başarıyla dışa aktarıldı",
"mode_imported": "Mod başarıyla içe aktarıldı"
"agent_exported": "'{{Ajan}}' modu başarıyla dışa aktarıldı",
"agent_imported": "Mod başarıyla içe aktarıldı"
},
"answers": {
"yes": "Evet",
@ -150,10 +150,10 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": ".roomodes dosyasının {{line}}. satırında geçersiz YAML. Kontrol et:\n• Doğru girinti (tab değil boşluk kullan)\n• Eşleşen tırnak işaretleri ve parantezler\n• Geçerli YAML sözdizimi",
"schemaValidationError": ".roomodes'ta geçersiz özel mod formatı:\n{{issues}}",
"yamlParseError": ".rooagents dosyasının {{line}}. satırında geçersiz YAML. Kontrol et:\n• Doğru girinti (tab değil boşluk kullan)\n• Eşleşen tırnak işaretleri ve parantezler\n• Geçerli YAML sözdizimi",
"schemaValidationError": ".rooagents'ta geçersiz özel mod formatı:\n{{issues}}",
"invalidFormat": "Geçersiz özel mod formatı. Ayarlarının doğru YAML formatını takip ettiğinden emin ol.",
"updateFailed": "Özel mod güncellemesi başarısız: {{error}}",
"deleteFailed": "Özel mod silme başarısız: {{error}}",
@ -168,7 +168,7 @@
}
},
"marketplace": {
"mode": {
"Ajan": {
"rulesCleanupFailed": "Mod başarıyla kaldırıldı, ancak {{rulesFolderPath}} konumundaki kurallar klasörü silinemedi. Manuel olarak silmeniz gerekebilir."
}
},
@ -180,7 +180,7 @@
}
},
"prompts": {
"deleteMode": {
"deleteAgent": {
"title": "Özel Modu Sil",
"description": "Bu {{scope}} modunu silmek istediğinizden emin misiniz? Bu, {{rulesFolderPath}} adresindeki ilişkili kurallar klasörünü de silecektir",
"descriptionNoRules": "Bu özel modu silmek istediğinizden emin misiniz?",

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "Modlar",
"Ajanlar": "Modlar",
"mcps": "MCP Sunucuları",
"match": "eşleşme"
},
"item-card": {
"type-mode": "Mod",
"type-Ajan": "Mod",
"type-mcp": "MCP Sunucusu",
"type-other": "Diğer",
"by-author": "{{author}} tarafından",
@ -23,7 +23,7 @@
"type": {
"label": "Tür",
"all": "Tüm Türler",
"mode": "Mod",
"Ajan": "Mod",
"mcpServer": "MCP Sunucusu"
},
"sort": {

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "Bạn có chắc chắn muốn đặt lại tất cả trạng thái và lưu trữ bí mật trong tiện ích mở rộng không? Hành động này không thể hoàn tác.",
"delete_config_profile": "Bạn có chắc chắn muốn xóa hồ sơ cấu hình này không?",
"delete_custom_mode_with_rules": "Bạn có chắc chắn muốn xóa chế độ {scope} này không?\n\nThao tác này cũng sẽ xóa thư mục quy tắc liên quan tại:\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "Bạn có chắc chắn muốn xóa chế độ {scope} này không?\n\nThao tác này cũng sẽ xóa thư mục quy tắc liên quan tại:\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "Định dạng URI dữ liệu không hợp lệ",
@ -69,7 +69,7 @@
"share_auth_required": "Cần xác thực. Vui lòng đăng nhập để chia sẻ nhiệm vụ.",
"share_not_enabled": "Chia sẻ nhiệm vụ không được bật cho tổ chức này.",
"share_task_not_found": "Không tìm thấy nhiệm vụ hoặc truy cập bị từ chối.",
"mode_import_failed": "Nhập chế độ thất bại: {{error}}",
"agent_import_failed": "Nhập chế độ thất bại: {{error}}",
"delete_rules_folder_failed": "Không thể xóa thư mục quy tắc: {{rulesFolderPath}}. Lỗi: {{error}}",
"command_not_found": "Không tìm thấy lệnh '{{name}}'",
"open_command_file": "Không thể mở tệp lệnh",
@ -109,8 +109,8 @@
"image_saved": "Hình ảnh đã được lưu vào {{path}}",
"organization_share_link_copied": "Liên kết chia sẻ tổ chức đã được sao chép vào clipboard!",
"public_share_link_copied": "Liên kết chia sẻ công khai đã được sao chép vào clipboard!",
"mode_exported": "Chế độ '{{mode}}' đã được xuất thành công",
"mode_imported": "Chế độ đã được nhập thành công"
"agent_exported": "Chế độ '{{Đại lý}}' đã được xuất thành công",
"agent_imported": "Chế độ đã được nhập thành công"
},
"answers": {
"yes": "Có",
@ -150,10 +150,10 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": "YAML không hợp lệ trong tệp .roomodes tại dòng {{line}}. Vui lòng kiểm tra:\n• Thụt lề đúng (dùng dấu cách, không dùng tab)\n• Dấu ngoặc kép và ngoặc đơn khớp nhau\n• Cú pháp YAML hợp lệ",
"schemaValidationError": "Định dạng chế độ tùy chỉnh không hợp lệ trong .roomodes:\n{{issues}}",
"yamlParseError": "YAML không hợp lệ trong tệp .rooagents tại dòng {{line}}. Vui lòng kiểm tra:\n• Thụt lề đúng (dùng dấu cách, không dùng tab)\n• Dấu ngoặc kép và ngoặc đơn khớp nhau\n• Cú pháp YAML hợp lệ",
"schemaValidationError": "Định dạng chế độ tùy chỉnh không hợp lệ trong .rooagents:\n{{issues}}",
"invalidFormat": "Định dạng chế độ tùy chỉnh không hợp lệ. Vui lòng đảm bảo cài đặt của bạn tuân theo định dạng YAML đúng.",
"updateFailed": "Cập nhật chế độ tùy chỉnh thất bại: {{error}}",
"deleteFailed": "Xóa chế độ tùy chỉnh thất bại: {{error}}",
@ -168,7 +168,7 @@
}
},
"marketplace": {
"mode": {
"Đại lý": {
"rulesCleanupFailed": "Đã xóa chế độ thành công, nhưng không thể xóa thư mục quy tắc tại {{rulesFolderPath}}. Bạn có thể cần xóa thủ công."
}
},
@ -180,7 +180,7 @@
}
},
"prompts": {
"deleteMode": {
"deleteAgent": {
"title": "Xóa chế độ tùy chỉnh",
"description": "Bạn có chắc chắn muốn xóa chế độ {{scope}} này không? Thao tác này cũng θα xóa thư mục quy tắc liên quan tại {{rulesFolderPath}}",
"translations": {

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "Chế độ",
"Đại lý": "Chế độ",
"mcps": "Máy chủ MCP",
"match": "khớp"
},
"item-card": {
"type-mode": "Chế độ",
"type-Đại lý": "Chế độ",
"type-mcp": "Máy chủ MCP",
"type-other": "Khác",
"by-author": "bởi {{author}}",
@ -23,7 +23,7 @@
"type": {
"label": "Loại",
"all": "Tất cả loại",
"mode": "Chế độ",
"Đại lý": "Chế độ",
"mcpServer": "Máy chủ MCP"
},
"sort": {

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "您确定要重置扩展中的所有状态和密钥存储吗?此操作无法撤消。",
"delete_config_profile": "您确定要删除此配置文件吗?",
"delete_custom_mode_with_rules": "您确定要删除此 {scope} 模式吗?\n\n这也将删除位于以下位置的关联规则文件夹\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "您确定要删除此 {scope} 代理吗?\n\n这也将删除位于以下位置的关联规则文件夹\n{rulesFolderPath}"
},
"errors": {
"invalid_mcp_config": "项目MCP配置格式无效",
@ -48,7 +48,7 @@
"list_api_config": "获取API配置列表失败",
"update_server_timeout": "更新服务器超时设置失败",
"hmr_not_running": "本地开发服务器未运行HMR将不起作用。请在启动扩展前运行'npm run dev'以启用HMR。",
"retrieve_current_mode": "从状态中检索当前模式失败。",
"retrieve_current_agent": "从状态中检索当前代理失败。",
"failed_delete_repo": "删除关联的影子仓库或分支失败:{{error}}",
"failed_remove_directory": "删除任务目录失败:{{error}}",
"custom_storage_path_unusable": "自定义存储路径 \"{{path}}\" 不可用,将使用默认路径",
@ -74,7 +74,7 @@
"share_auth_required": "需要身份验证。请登录以分享任务。",
"share_not_enabled": "此组织未启用任务分享功能。",
"share_task_not_found": "未找到任务或访问被拒绝。",
"mode_import_failed": "导入模式失败:{{error}}",
"agent_import_failed": "导入代理失败:{{error}}",
"delete_rules_folder_failed": "删除规则文件夹失败:{{rulesFolderPath}}。错误:{{error}}",
"command_not_found": "未找到命令 '{{name}}'",
"open_command_file": "打开命令文件失败",
@ -114,8 +114,8 @@
"image_saved": "图片已保存到 {{path}}",
"organization_share_link_copied": "组织分享链接已复制到剪贴板!",
"public_share_link_copied": "公开分享链接已复制到剪贴板!",
"mode_exported": "模式 '{{mode}}' 已成功导出",
"mode_imported": "模式已成功导入"
"agent_exported": "代理 '{{agent}}' 已成功导出",
"agent_imported": "代理已成功导入"
},
"answers": {
"yes": "是",
@ -155,17 +155,17 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": ".roomodes 文件第 {{line}} 行 YAML 格式无效。请检查:\n• 正确的缩进(使用空格,不要使用制表符)\n• 匹配的引号和括号\n• 有效的 YAML 语法",
"schemaValidationError": ".roomodes 中自定义模式格式无效:\n{{issues}}",
"invalidFormat": "自定义模式格式无效。请确保你的设置遵循正确的 YAML 格式。",
"updateFailed": "更新自定义模式失败:{{error}}",
"deleteFailed": "删除自定义模式失败:{{error}}",
"resetFailed": "重置自定义模式失败:{{error}}",
"modeNotFound": "写入错误:未找到模式",
"noWorkspaceForProject": "未找到项目特定模式的工作区文件夹",
"rulesCleanupFailed": "模式删除成功,但无法删除位于 {{rulesFolderPath}} 的规则文件夹。您可能需要手动删除。"
"yamlParseError": ".rooagents 文件第 {{line}} 行 YAML 格式无效。请检查:\n• 正确的缩进(使用空格,不要使用制表符)\n• 匹配的引号和括号\n• 有效的 YAML 语法",
"schemaValidationError": ".rooagents 中自定义代理格式无效:\n{{issues}}",
"invalidFormat": "自定义代理格式无效。请确保你的设置遵循正确的 YAML 格式。",
"updateFailed": "更新自定义代理失败:{{error}}",
"deleteFailed": "删除自定义代理失败:{{error}}",
"resetFailed": "重置自定义代理失败:{{error}}",
"agentNotFound": "写入错误:未找到代理",
"noWorkspaceForProject": "未找到项目特定代理的工作区文件夹",
"rulesCleanupFailed": "代理删除成功,但无法删除位于 {{rulesFolderPath}} 的规则文件夹。您可能需要手动删除。"
},
"scope": {
"project": "项目",
@ -173,8 +173,8 @@
}
},
"marketplace": {
"mode": {
"rulesCleanupFailed": "模式已成功移除,但无法删除位于 {{rulesFolderPath}} 的规则文件夹。您可能需要手动删除。"
"agent": {
"rulesCleanupFailed": "代理已成功移除,但无法删除位于 {{rulesFolderPath}} 的规则文件夹。您可能需要手动删除。"
}
},
"mdm": {
@ -185,10 +185,10 @@
}
},
"prompts": {
"deleteMode": {
"title": "删除自定义模式",
"description": "您确定要删除此 {{scope}} 模式吗?这也将删除位于 {{rulesFolderPath}} 的关联规则文件夹",
"descriptionNoRules": "您确定要删除此自定义模式吗?",
"deleteAgent": {
"title": "删除自定义代理",
"description": "您确定要删除此 {{scope}} 代理吗?这也将删除位于 {{rulesFolderPath}} 的关联规则文件夹",
"descriptionNoRules": "您确定要删除此自定义代理吗?",
"confirm": "删除"
}
},

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "模式",
"agents": "代理",
"mcps": "MCP 服务",
"match": "匹配"
},
"item-card": {
"type-mode": "模式",
"type-agent": "代理",
"type-mcp": "MCP 服务",
"type-other": "其他",
"by-author": "作者:{{author}}",

View file

@ -17,7 +17,7 @@
"confirmation": {
"reset_state": "您確定要重設擴充套件中的所有狀態和金鑰儲存嗎?此操作無法復原。",
"delete_config_profile": "您確定要刪除此設定檔案嗎?",
"delete_custom_mode_with_rules": "您確定要刪除此 {scope} 模式嗎?\n\n這也將刪除位於以下位置的關聯規則資料夾\n{rulesFolderPath}"
"delete_custom_agent_with_rules": "您確定要刪除此 {scope} 模式嗎?\n\n這也將刪除位於以下位置的關聯規則資料夾\n{rulesFolderPath}"
},
"errors": {
"invalid_data_uri": "資料 URI 格式無效",
@ -89,7 +89,7 @@
"generate_complete_prompt": "Gemini 完成錯誤:{{error}}",
"sources": "來源:"
},
"mode_import_failed": "匯入模式失敗:{{error}}"
"agent_import_failed": "匯入模式失敗:{{error}}"
},
"warnings": {
"no_terminal_content": "沒有選擇終端機內容",
@ -109,8 +109,8 @@
"image_saved": "圖片已儲存至 {{path}}",
"organization_share_link_copied": "組織分享連結已複製到剪貼簿!",
"public_share_link_copied": "公開分享連結已複製到剪貼簿!",
"mode_exported": "模式 '{{mode}}' 已成功匯出",
"mode_imported": "模式已成功匯入"
"agent_exported": "模式 '{{代理}}' 已成功匯出",
"agent_imported": "模式已成功匯入"
},
"answers": {
"yes": "是",
@ -150,10 +150,10 @@
}
}
},
"customModes": {
"customAgents": {
"errors": {
"yamlParseError": ".roomodes 檔案第 {{line}} 行 YAML 格式無效。請檢查:\n• 正確的縮排(使用空格,不要使用定位字元)\n• 匹配的引號和括號\n• 有效的 YAML 語法",
"schemaValidationError": ".roomodes 中自訂模式格式無效:\n{{issues}}",
"yamlParseError": ".rooagents 檔案第 {{line}} 行 YAML 格式無效。請檢查:\n• 正確的縮排(使用空格,不要使用定位字元)\n• 匹配的引號和括號\n• 有效的 YAML 語法",
"schemaValidationError": ".rooagents 中自訂模式格式無效:\n{{issues}}",
"invalidFormat": "自訂模式格式無效。請確保你的設定遵循正確的 YAML 格式。",
"updateFailed": "更新自訂模式失敗:{{error}}",
"deleteFailed": "刪除自訂模式失敗:{{error}}",
@ -168,7 +168,7 @@
}
},
"marketplace": {
"mode": {
"代理": {
"rulesCleanupFailed": "模式已成功移除,但無法刪除位於 {{rulesFolderPath}} 的規則資料夾。您可能需要手動刪除。"
}
},
@ -180,7 +180,7 @@
}
},
"prompts": {
"deleteMode": {
"deleteAgent": {
"title": "刪除自訂模式",
"description": "您確定要刪除此 {{scope}} 模式嗎?這也將刪除位於 {{rulesFolderPath}} 的關聯規則資料夾",
"descriptionNoRules": "您確定要刪除此自訂模式嗎?",

View file

@ -1,11 +1,11 @@
{
"type-group": {
"modes": "模式",
"代理": "模式",
"mcps": "MCP 伺服器",
"match": "符合"
},
"item-card": {
"type-mode": "模式",
"type-代理": "模式",
"type-mcp": "MCP 伺服器",
"type-other": "其他",
"by-author": "作者:{{author}}",
@ -23,7 +23,7 @@
"type": {
"label": "類型",
"all": "所有類型",
"mode": "模式",
"代理": "模式",
"mcpServer": "MCP 伺服器"
},
"sort": {

View file

@ -9,6 +9,7 @@ import { GlobalFileNames } from "../../shared/globalFileNames"
import { ensureSettingsDirectoryExists } from "../../utils/globalContext"
import { t } from "../../i18n"
import { TelemetryService } from "@roo-code/telemetry"
import type { CustomAgentsManager } from "../../core/config/CustomAgentsManager"
import type { CustomModesManager } from "../../core/config/CustomModesManager"
export class MarketplaceManager {
@ -17,10 +18,10 @@ export class MarketplaceManager {
constructor(
private readonly context: vscode.ExtensionContext,
private readonly customModesManager?: CustomModesManager,
private readonly customAgentsManager?: CustomAgentsManager | CustomModesManager,
) {
this.configLoader = new RemoteConfigLoader()
this.installer = new SimpleInstaller(context, customModesManager)
this.installer = new SimpleInstaller(context, customAgentsManager)
}
async getMarketplaceItems(): Promise<{ items: MarketplaceItem[]; errors?: string[] }> {
@ -201,22 +202,40 @@ export class MarketplaceManager {
return // No workspace, no project installations
}
// Check modes in .roomodes
// Check agents/modes in .rooagents (preferred) or .roomodes (backward compatibility)
const projectAgentsPath = path.join(workspaceFolder.uri.fsPath, ".rooagents")
const projectModesPath = path.join(workspaceFolder.uri.fsPath, ".roomodes")
// Try .rooagents first
try {
const content = await fs.readFile(projectModesPath, "utf-8")
const content = await fs.readFile(projectAgentsPath, "utf-8")
const data = yaml.parse(content)
if (data?.customModes && Array.isArray(data.customModes)) {
for (const mode of data.customModes) {
if (mode.slug) {
metadata[mode.slug] = {
type: "mode",
if (data?.customAgents && Array.isArray(data.customAgents)) {
for (const agent of data.customAgents) {
if (agent.slug) {
metadata[agent.slug] = {
type: "mode", // Keep as "mode" for marketplace compatibility
}
}
}
}
} catch (error) {
// File doesn't exist or can't be read, skip
// .rooagents doesn't exist, try .roomodes for backward compatibility
try {
const content = await fs.readFile(projectModesPath, "utf-8")
const data = yaml.parse(content)
if (data?.customModes && Array.isArray(data.customModes)) {
for (const mode of data.customModes) {
if (mode.slug) {
metadata[mode.slug] = {
type: "mode",
}
}
}
}
} catch (error) {
// Neither file exists or can't be read, skip
}
}
// Check MCPs in .roo/mcp.json

View file

@ -5,6 +5,7 @@ import * as yaml from "yaml"
import type { MarketplaceItem, MarketplaceItemType, InstallMarketplaceItemOptions, McpParameter } from "@roo-code/types"
import { GlobalFileNames } from "../../shared/globalFileNames"
import { ensureSettingsDirectoryExists } from "../../utils/globalContext"
import type { CustomAgentsManager } from "../../core/config/CustomAgentsManager"
import type { CustomModesManager } from "../../core/config/CustomModesManager"
export interface InstallOptions extends InstallMarketplaceItemOptions {
@ -15,7 +16,7 @@ export interface InstallOptions extends InstallMarketplaceItemOptions {
export class SimpleInstaller {
constructor(
private readonly context: vscode.ExtensionContext,
private readonly customModesManager?: CustomModesManager,
private readonly customAgentsManager?: CustomAgentsManager | CustomModesManager,
) {}
async installItem(item: MarketplaceItem, options: InstallOptions): Promise<{ filePath: string; line?: number }> {
@ -44,16 +45,16 @@ export class SimpleInstaller {
throw new Error("Mode content should not be an array")
}
// If CustomModesManager is available, use importModeWithRules
if (this.customModesManager) {
// If CustomAgentsManager is available, use importModeWithRules
if (this.customAgentsManager) {
// Transform marketplace content to import format (wrap in customModes array)
const importData = {
customModes: [yaml.parse(item.content)],
}
const importYaml = yaml.stringify(importData)
// Call customModesManager.importModeWithRules
const result = await this.customModesManager.importModeWithRules(importYaml, target)
// Call customAgentsManager.importModeWithRules (backward compatible method)
const result = await this.customAgentsManager.importModeWithRules(importYaml, target)
if (!result.success) {
throw new Error(result.error || "Failed to import mode")
@ -294,7 +295,7 @@ export class SimpleInstaller {
}
private async removeMode(item: MarketplaceItem, target: "project" | "global"): Promise<void> {
if (!this.customModesManager) {
if (!this.customAgentsManager) {
throw new Error("CustomModesManager is not available")
}
@ -320,12 +321,12 @@ export class SimpleInstaller {
}
// Get the current modes to determine the source
const modes = await this.customModesManager.getCustomModes()
const modes = await this.customAgentsManager.getCustomModes()
const mode = modes.find((m) => m.slug === modeSlug)
// Use CustomModesManager to delete the mode configuration
// Use CustomAgentsManager to delete the mode configuration
// This also handles rules folder deletion
await this.customModesManager.deleteCustomMode(modeSlug, true)
await this.customAgentsManager.deleteCustomMode(modeSlug, true)
}
private async removeMcp(item: MarketplaceItem, target: "project" | "global"): Promise<void> {
@ -362,7 +363,18 @@ export class SimpleInstaller {
if (!workspaceFolder) {
throw new Error("No workspace folder found")
}
return path.join(workspaceFolder.uri.fsPath, ".roomodes")
// Check if .rooagents exists, otherwise use .roomodes for backward compatibility
const rooagentsPath = path.join(workspaceFolder.uri.fsPath, ".rooagents")
const roomodesPath = path.join(workspaceFolder.uri.fsPath, ".roomodes")
try {
await fs.access(rooagentsPath)
return rooagentsPath
} catch {
// .rooagents doesn't exist, use .roomodes for backward compatibility
return roomodesPath
}
} else {
const globalSettingsPath = await ensureSettingsDirectoryExists(this.context)
return path.join(globalSettingsPath, GlobalFileNames.customModes)

View file

@ -4,6 +4,9 @@ import type {
ProviderSettings,
HistoryItem,
ModeConfig,
AgentConfig,
CustomModePrompts,
CustomAgentPrompts,
TelemetrySetting,
Experiments,
ClineMessage,
@ -83,8 +86,12 @@ export interface ExtensionMessage {
| "autoApprovalEnabled"
| "updateCustomMode"
| "deleteCustomMode"
| "updateCustomAgent"
| "deleteCustomAgent"
| "exportModeResult"
| "importModeResult"
| "exportAgentResult"
| "importAgentResult"
| "checkRulesDirectoryResult"
| "deleteCustomModeCheck"
| "currentCheckpointUpdated"
@ -170,6 +177,7 @@ export interface ExtensionMessage {
listApiConfig?: ProviderSettingsEntry[]
mode?: Mode
customMode?: ModeConfig
customAgent?: AgentConfig
slug?: string
success?: boolean
values?: Record<string, any>
@ -295,6 +303,7 @@ export type ExtensionState = Pick<
mode: Mode
customModes: ModeConfig[]
customAgents?: AgentConfig[] // Optional for backward compatibility
toolRequirements?: Record<string, boolean> // Map of tool names to their requirements (e.g. {"apply_diff": true} if diffEnabled)
cwd?: string // Current working directory

View file

@ -4,6 +4,7 @@ import type {
ProviderSettings,
PromptComponent,
ModeConfig,
AgentConfig,
InstallMarketplaceItemOptions,
MarketplaceItem,
ShareVisibility,
@ -144,8 +145,11 @@ export interface WebviewMessage {
| "autoApprovalEnabled"
| "updateCustomMode"
| "deleteCustomMode"
| "updateCustomAgent"
| "deleteCustomAgent"
| "setopenAiCustomModelInfo"
| "openCustomModesSettings"
| "openCustomAgentsSettings"
| "checkpointDiff"
| "checkpointRestore"
| "deleteMcpServer"
@ -199,6 +203,10 @@ export interface WebviewMessage {
| "exportModeResult"
| "importMode"
| "importModeResult"
| "exportAgent"
| "exportAgentResult"
| "importAgent"
| "importAgentResult"
| "checkRulesDirectory"
| "checkRulesDirectoryResult"
| "saveCodeIndexSettingsAtomic"
@ -210,7 +218,7 @@ export interface WebviewMessage {
| "insertTextIntoTextarea"
text?: string
editedMessageContent?: string
tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "account"
tab?: "settings" | "history" | "mcp" | "modes" | "agents" | "chat" | "marketplace" | "account"
disabled?: boolean
context?: string
dataUri?: string
@ -234,6 +242,7 @@ export interface WebviewMessage {
setting?: string
slug?: string
modeConfig?: ModeConfig
agentConfig?: AgentConfig
timeout?: number
payload?: WebViewMessagePayload
source?: "global" | "project"

View file

@ -3,11 +3,14 @@ import * as vscode from "vscode"
import {
type GroupOptions,
type GroupEntry,
type AgentConfig,
type ModeConfig,
type CustomAgentPrompts,
type CustomModePrompts,
type ExperimentId,
type ToolGroup,
type PromptComponent,
DEFAULT_AGENTS,
DEFAULT_MODES,
} from "@roo-code/types"
@ -16,7 +19,8 @@ import { addCustomInstructions } from "../core/prompts/sections/custom-instructi
import { EXPERIMENT_IDS } from "./experiments"
import { TOOL_GROUPS, ALWAYS_AVAILABLE_TOOLS } from "./tools"
export type Mode = string
export type Agent = string
export type Mode = Agent // Backward compatibility alias
// Helper to extract group name regardless of format
export function getGroupName(group: GroupEntry): ToolGroup {
@ -60,94 +64,136 @@ export function getToolsForMode(groups: readonly GroupEntry[]): string[] {
return Array.from(tools)
}
// Main modes configuration as an ordered array
// Main agents configuration as an ordered array
export const agents = DEFAULT_AGENTS
// Main modes configuration as an ordered array (backward compatibility)
export const modes = DEFAULT_MODES
// Export the default mode slug
export const defaultModeSlug = modes[0].slug
// Export the default agent slug
export const defaultAgentSlug = agents[0].slug
// Helper functions
export function getModeBySlug(slug: string, customModes?: ModeConfig[]): ModeConfig | undefined {
// Check custom modes first
const customMode = customModes?.find((mode) => mode.slug === slug)
if (customMode) {
return customMode
// Export the default mode slug (backward compatibility)
export const defaultModeSlug = defaultAgentSlug
// Helper functions for agents
export function getAgentBySlug(slug: string, customAgents?: AgentConfig[]): AgentConfig | undefined {
// Check custom agents first
const customAgent = customAgents?.find((agent) => agent.slug === slug)
if (customAgent) {
return customAgent
}
// Then check built-in modes
return modes.find((mode) => mode.slug === slug)
// Then check built-in agents
return agents.find((agent) => agent.slug === slug)
}
export function getModeConfig(slug: string, customModes?: ModeConfig[]): ModeConfig {
const mode = getModeBySlug(slug, customModes)
if (!mode) {
throw new Error(`No mode found for slug: ${slug}`)
export function getAgentConfig(slug: string, customAgents?: AgentConfig[]): AgentConfig {
const agent = getAgentBySlug(slug, customAgents)
if (!agent) {
throw new Error(`No agent found for slug: ${slug}`)
}
return mode
return agent
}
// Get all available modes, with custom modes overriding built-in modes
export function getAllModes(customModes?: ModeConfig[]): ModeConfig[] {
if (!customModes?.length) {
return [...modes]
// Get all available agents, with custom agents overriding built-in agents
export function getAllAgents(customAgents?: AgentConfig[]): AgentConfig[] {
if (!customAgents?.length) {
return [...agents]
}
// Start with built-in modes
const allModes = [...modes]
// Start with built-in agents
const allAgents = [...agents]
// Process custom modes
customModes.forEach((customMode) => {
const index = allModes.findIndex((mode) => mode.slug === customMode.slug)
// Process custom agents
customAgents.forEach((customAgent) => {
const index = allAgents.findIndex((agent) => agent.slug === customAgent.slug)
if (index !== -1) {
// Override existing mode
allModes[index] = customMode
// Override existing agent
allAgents[index] = customAgent
} else {
// Add new mode
allModes.push(customMode)
// Add new agent
allAgents.push(customAgent)
}
})
return allModes
return allAgents
}
// Check if a mode is custom or an override
// Check if an agent is custom or an override
export function isCustomAgent(slug: string, customAgents?: AgentConfig[]): boolean {
return !!customAgents?.some((agent) => agent.slug === slug)
}
// Helper functions for modes (backward compatibility)
export function getModeBySlug(slug: string, customModes?: ModeConfig[]): ModeConfig | undefined {
return getAgentBySlug(slug, customModes)
}
export function getModeConfig(slug: string, customModes?: ModeConfig[]): ModeConfig {
return getAgentConfig(slug, customModes)
}
// Get all available modes, with custom modes overriding built-in modes (backward compatibility)
export function getAllModes(customModes?: ModeConfig[]): ModeConfig[] {
return getAllAgents(customModes)
}
// Check if a mode is custom or an override (backward compatibility)
export function isCustomMode(slug: string, customModes?: ModeConfig[]): boolean {
return !!customModes?.some((mode) => mode.slug === slug)
return isCustomAgent(slug, customModes)
}
/**
* Find a mode by its slug, don't fall back to built-in modes
* Find an agent by its slug, don't fall back to built-in agents
*/
export function findAgentBySlug(slug: string, agents: readonly AgentConfig[] | undefined): AgentConfig | undefined {
return agents?.find((agent) => agent.slug === slug)
}
/**
* Get the agent selection based on the provided agent slug, prompt component, and custom agents.
* If a custom agent is found, it takes precedence over the built-in agents.
* If no custom agent is found, the built-in agent is used with partial merging from promptComponent.
* If neither is found, the default agent is used.
*/
export function getAgentSelection(agent: string, promptComponent?: PromptComponent, customAgents?: AgentConfig[]) {
const customAgent = findAgentBySlug(agent, customAgents)
const builtInAgent = findAgentBySlug(agent, agents)
// If we have a custom agent, use it entirely
if (customAgent) {
return {
roleDefinition: customAgent.roleDefinition || "",
baseInstructions: customAgent.customInstructions || "",
description: customAgent.description || "",
}
}
// Otherwise, use built-in agent as base and merge with promptComponent
const baseAgent = builtInAgent || agents[0] // fallback to default agent
return {
roleDefinition: promptComponent?.roleDefinition || baseAgent.roleDefinition || "",
baseInstructions: promptComponent?.customInstructions || baseAgent.customInstructions || "",
description: baseAgent.description || "",
}
}
/**
* Find a mode by its slug, don't fall back to built-in modes (backward compatibility)
*/
export function findModeBySlug(slug: string, modes: readonly ModeConfig[] | undefined): ModeConfig | undefined {
return modes?.find((mode) => mode.slug === slug)
return findAgentBySlug(slug, modes)
}
/**
* Get the mode selection based on the provided mode slug, prompt component, and custom modes.
* Get the mode selection based on the provided mode slug, prompt component, and custom modes (backward compatibility).
* If a custom mode is found, it takes precedence over the built-in modes.
* If no custom mode is found, the built-in mode is used with partial merging from promptComponent.
* If neither is found, the default mode is used.
*/
export function getModeSelection(mode: string, promptComponent?: PromptComponent, customModes?: ModeConfig[]) {
const customMode = findModeBySlug(mode, customModes)
const builtInMode = findModeBySlug(mode, modes)
// If we have a custom mode, use it entirely
if (customMode) {
return {
roleDefinition: customMode.roleDefinition || "",
baseInstructions: customMode.customInstructions || "",
description: customMode.description || "",
}
}
// Otherwise, use built-in mode as base and merge with promptComponent
const baseMode = builtInMode || modes[0] // fallback to default mode
return {
roleDefinition: promptComponent?.roleDefinition || baseMode.roleDefinition || "",
baseInstructions: promptComponent?.customInstructions || baseMode.customInstructions || "",
description: baseMode.description || "",
}
return getAgentSelection(mode, promptComponent, customModes)
}
// Edit operation parameters that indicate an actual edit operation
@ -164,10 +210,10 @@ export class FileRestrictionError extends Error {
}
}
export function isToolAllowedForMode(
export function isToolAllowedForAgent(
tool: string,
modeSlug: string,
customModes: ModeConfig[],
agentSlug: string,
customAgents: AgentConfig[],
toolRequirements?: Record<string, boolean>,
toolParams?: Record<string, any>, // All tool parameters
experiments?: Record<string, boolean>,
@ -192,13 +238,13 @@ export function isToolAllowedForMode(
return false
}
const mode = getModeBySlug(modeSlug, customModes)
if (!mode) {
const agent = getAgentBySlug(agentSlug, customAgents)
if (!agent) {
return false
}
// Check if tool is in any of the mode's groups and respects any group options
for (const group of mode.groups) {
// Check if tool is in any of the agent's groups and respects any group options
for (const group of agent.groups) {
const groupName = getGroupName(group)
const options = getGroupOptions(group)
@ -222,7 +268,7 @@ export function isToolAllowedForMode(
// Handle single file path validation
if (filePath && isEditOperation && !doesFileMatchRegex(filePath, options.fileRegex)) {
throw new FileRestrictionError(mode.name, options.fileRegex, options.description, filePath, tool)
throw new FileRestrictionError(agent.name, options.fileRegex, options.description, filePath, tool)
}
// Handle XML args parameter (used by MULTI_FILE_APPLY_DIFF experiment)
@ -240,7 +286,7 @@ export function isToolAllowedForMode(
if (extractedPath && !extractedPath.includes("<") && !extractedPath.includes(">")) {
if (!doesFileMatchRegex(extractedPath, options.fileRegex)) {
throw new FileRestrictionError(
mode.name,
agent.name,
options.fileRegex,
options.description,
extractedPath,
@ -268,37 +314,147 @@ export function isToolAllowedForMode(
return false
}
// Create the mode-specific default prompts
export const defaultPrompts: Readonly<CustomModePrompts> = Object.freeze(
// Backward compatibility function for modes
export function isToolAllowedForMode(
tool: string,
modeSlug: string,
customModes: ModeConfig[],
toolRequirements?: Record<string, boolean>,
toolParams?: Record<string, any>, // All tool parameters
experiments?: Record<string, boolean>,
): boolean {
return isToolAllowedForAgent(tool, modeSlug, customModes, toolRequirements, toolParams, experiments)
}
// Create the agent-specific default prompts
export const defaultAgentPrompts: Readonly<CustomAgentPrompts> = Object.freeze(
Object.fromEntries(
modes.map((mode) => [
mode.slug,
agents.map((agent) => [
agent.slug,
{
roleDefinition: mode.roleDefinition,
whenToUse: mode.whenToUse,
customInstructions: mode.customInstructions,
description: mode.description,
roleDefinition: agent.roleDefinition,
whenToUse: agent.whenToUse,
customInstructions: agent.customInstructions,
description: agent.description,
},
]),
),
)
// Helper function to get all modes with their prompt overrides from extension state
export async function getAllModesWithPrompts(context: vscode.ExtensionContext): Promise<ModeConfig[]> {
const customModes = (await context.globalState.get<ModeConfig[]>("customModes")) || []
const customModePrompts = (await context.globalState.get<CustomModePrompts>("customModePrompts")) || {}
// Create the mode-specific default prompts (backward compatibility)
export const defaultPrompts: Readonly<CustomModePrompts> = defaultAgentPrompts
const allModes = getAllModes(customModes)
return allModes.map((mode) => ({
...mode,
roleDefinition: customModePrompts[mode.slug]?.roleDefinition ?? mode.roleDefinition,
whenToUse: customModePrompts[mode.slug]?.whenToUse ?? mode.whenToUse,
customInstructions: customModePrompts[mode.slug]?.customInstructions ?? mode.customInstructions,
// description is not overridable via customModePrompts, so we keep the original
// Helper function to get all agents with their prompt overrides from extension state
export async function getAllAgentsWithPrompts(context: vscode.ExtensionContext): Promise<AgentConfig[]> {
const customAgents =
(await context.globalState.get<AgentConfig[]>("customAgents")) ||
(await context.globalState.get<ModeConfig[]>("customModes")) ||
[] // Fallback for backward compatibility
const customAgentPrompts =
(await context.globalState.get<CustomAgentPrompts>("customAgentPrompts")) ||
(await context.globalState.get<CustomModePrompts>("customModePrompts")) ||
{} // Fallback for backward compatibility
const allAgents = getAllAgents(customAgents)
return allAgents.map((agent) => ({
...agent,
roleDefinition: customAgentPrompts[agent.slug]?.roleDefinition ?? agent.roleDefinition,
whenToUse: customAgentPrompts[agent.slug]?.whenToUse ?? agent.whenToUse,
customInstructions: customAgentPrompts[agent.slug]?.customInstructions ?? agent.customInstructions,
// description is not overridable via customAgentPrompts, so we keep the original
}))
}
// Helper function to get complete mode details with all overrides
// Helper function to get complete agent details with all overrides
export async function getFullAgentDetails(
agentSlug: string,
customAgents?: AgentConfig[],
customAgentPrompts?: CustomAgentPrompts,
options?: {
cwd?: string
globalCustomInstructions?: string
language?: string
},
): Promise<AgentConfig> {
// First get the base agent config from custom agents or built-in agents
const baseAgent = getAgentBySlug(agentSlug, customAgents) || agents.find((a) => a.slug === agentSlug) || agents[0]
// Check for any prompt component overrides
const promptComponent = customAgentPrompts?.[agentSlug]
// Get the base custom instructions
const baseCustomInstructions = promptComponent?.customInstructions || baseAgent.customInstructions || ""
const baseWhenToUse = promptComponent?.whenToUse || baseAgent.whenToUse || ""
const baseDescription = promptComponent?.description || baseAgent.description || ""
// If we have cwd, load and combine all custom instructions
let fullCustomInstructions = baseCustomInstructions
if (options?.cwd) {
fullCustomInstructions = await addCustomInstructions(
baseCustomInstructions,
options.globalCustomInstructions || "",
options.cwd,
agentSlug,
{ language: options.language },
)
}
// Return agent with any overrides applied
return {
...baseAgent,
roleDefinition: promptComponent?.roleDefinition || baseAgent.roleDefinition,
whenToUse: baseWhenToUse,
description: baseDescription,
customInstructions: fullCustomInstructions,
}
}
// Helper function to safely get agent role definition
export function getAgentRoleDefinition(agentSlug: string, customAgents?: AgentConfig[]): string {
const agent = getAgentBySlug(agentSlug, customAgents)
if (!agent) {
console.warn(`No agent found for slug: ${agentSlug}`)
return ""
}
return agent.roleDefinition
}
// Helper function to safely get agent description
export function getAgentDescription(agentSlug: string, customAgents?: AgentConfig[]): string {
const agent = getAgentBySlug(agentSlug, customAgents)
if (!agent) {
console.warn(`No agent found for slug: ${agentSlug}`)
return ""
}
return agent.description ?? ""
}
// Helper function to safely get agent whenToUse
export function getAgentWhenToUse(agentSlug: string, customAgents?: AgentConfig[]): string {
const agent = getAgentBySlug(agentSlug, customAgents)
if (!agent) {
console.warn(`No agent found for slug: ${agentSlug}`)
return ""
}
return agent.whenToUse ?? ""
}
// Helper function to safely get agent custom instructions
export function getAgentCustomInstructions(agentSlug: string, customAgents?: AgentConfig[]): string {
const agent = getAgentBySlug(agentSlug, customAgents)
if (!agent) {
console.warn(`No agent found for slug: ${agentSlug}`)
return ""
}
return agent.customInstructions ?? ""
}
// Helper function to get all modes with their prompt overrides from extension state (backward compatibility)
export async function getAllModesWithPrompts(context: vscode.ExtensionContext): Promise<ModeConfig[]> {
return getAllAgentsWithPrompts(context)
}
// Helper function to get complete mode details with all overrides (backward compatibility)
export async function getFullModeDetails(
modeSlug: string,
customModes?: ModeConfig[],
@ -309,75 +465,25 @@ export async function getFullModeDetails(
language?: string
},
): Promise<ModeConfig> {
// First get the base mode config from custom modes or built-in modes
const baseMode = getModeBySlug(modeSlug, customModes) || modes.find((m) => m.slug === modeSlug) || modes[0]
// Check for any prompt component overrides
const promptComponent = customModePrompts?.[modeSlug]
// Get the base custom instructions
const baseCustomInstructions = promptComponent?.customInstructions || baseMode.customInstructions || ""
const baseWhenToUse = promptComponent?.whenToUse || baseMode.whenToUse || ""
const baseDescription = promptComponent?.description || baseMode.description || ""
// If we have cwd, load and combine all custom instructions
let fullCustomInstructions = baseCustomInstructions
if (options?.cwd) {
fullCustomInstructions = await addCustomInstructions(
baseCustomInstructions,
options.globalCustomInstructions || "",
options.cwd,
modeSlug,
{ language: options.language },
)
}
// Return mode with any overrides applied
return {
...baseMode,
roleDefinition: promptComponent?.roleDefinition || baseMode.roleDefinition,
whenToUse: baseWhenToUse,
description: baseDescription,
customInstructions: fullCustomInstructions,
}
return getFullAgentDetails(modeSlug, customModes, customModePrompts, options)
}
// Helper function to safely get role definition
// Helper function to safely get role definition (backward compatibility)
export function getRoleDefinition(modeSlug: string, customModes?: ModeConfig[]): string {
const mode = getModeBySlug(modeSlug, customModes)
if (!mode) {
console.warn(`No mode found for slug: ${modeSlug}`)
return ""
}
return mode.roleDefinition
return getAgentRoleDefinition(modeSlug, customModes)
}
// Helper function to safely get description
// Helper function to safely get description (backward compatibility)
export function getDescription(modeSlug: string, customModes?: ModeConfig[]): string {
const mode = getModeBySlug(modeSlug, customModes)
if (!mode) {
console.warn(`No mode found for slug: ${modeSlug}`)
return ""
}
return mode.description ?? ""
return getAgentDescription(modeSlug, customModes)
}
// Helper function to safely get whenToUse
// Helper function to safely get whenToUse (backward compatibility)
export function getWhenToUse(modeSlug: string, customModes?: ModeConfig[]): string {
const mode = getModeBySlug(modeSlug, customModes)
if (!mode) {
console.warn(`No mode found for slug: ${modeSlug}`)
return ""
}
return mode.whenToUse ?? ""
return getAgentWhenToUse(modeSlug, customModes)
}
// Helper function to safely get custom instructions
// Helper function to safely get custom instructions (backward compatibility)
export function getCustomInstructions(modeSlug: string, customModes?: ModeConfig[]): string {
const mode = getModeBySlug(modeSlug, customModes)
if (!mode) {
console.warn(`No mode found for slug: ${modeSlug}`)
return ""
}
return mode.customInstructions ?? ""
return getAgentCustomInstructions(modeSlug, customModes)
}

View file

@ -17,7 +17,7 @@ import SettingsView, { SettingsViewRef } from "./components/settings/SettingsVie
import WelcomeView from "./components/welcome/WelcomeView"
import McpView from "./components/mcp/McpView"
import { MarketplaceView } from "./components/marketplace/MarketplaceView"
import ModesView from "./components/modes/ModesView"
import AgentsView from "./components/agents/AgentsView"
import { HumanRelayDialog } from "./components/human-relay/HumanRelayDialog"
import { DeleteMessageDialog, EditMessageDialog } from "./components/chat/MessageModificationConfirmationDialog"
import ErrorBoundary from "./components/ErrorBoundary"
@ -26,7 +26,7 @@ import { useAddNonInteractiveClickListener } from "./components/ui/hooks/useNonI
import { TooltipProvider } from "./components/ui/tooltip"
import { STANDARD_TOOLTIP_DELAY } from "./components/ui/standard-tooltip"
type Tab = "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "account"
type Tab = "settings" | "history" | "mcp" | "agents" | "chat" | "marketplace" | "account"
interface HumanRelayDialogState {
isOpen: boolean
@ -54,7 +54,7 @@ const MemoizedHumanRelayDialog = React.memo(HumanRelayDialog)
const tabsByMessageAction: Partial<Record<NonNullable<ExtensionMessage["action"]>, Tab>> = {
chatButtonClicked: "chat",
settingsButtonClicked: "settings",
promptsButtonClicked: "modes",
promptsButtonClicked: "agents",
mcpButtonClicked: "mcp",
historyButtonClicked: "history",
marketplaceButtonClicked: "marketplace",
@ -233,7 +233,7 @@ const App = () => {
<WelcomeView />
) : (
<>
{tab === "modes" && <ModesView onDone={() => switchTab("chat")} />}
{tab === "agents" && <AgentsView onDone={() => switchTab("chat")} />}
{tab === "mcp" && <McpView onDone={() => switchTab("chat")} />}
{tab === "history" && <HistoryView onDone={() => switchTab("chat")} />}
{tab === "settings" && (

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,61 @@
import React from "react"
import { useAppTranslation } from "@src/i18n/TranslationContext"
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@src/components/ui"
interface DeleteAgentDialogProps {
open: boolean
onOpenChange: (open: boolean) => void
modeToDelete: {
slug: string
name: string
source?: string
rulesFolderPath?: string
} | null
onConfirm: () => void
}
export const DeleteAgentDialog: React.FC<DeleteAgentDialogProps> = ({
open,
onOpenChange,
modeToDelete,
onConfirm,
}) => {
const { t } = useAppTranslation()
return (
<AlertDialog open={open} onOpenChange={onOpenChange}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{t("prompts:deleteAgent.title")}</AlertDialogTitle>
<AlertDialogDescription>
{modeToDelete && (
<>
{t("prompts:deleteAgent.message", { modeName: modeToDelete.name })}
{modeToDelete.rulesFolderPath && (
<div className="mt-2">
{t("prompts:deleteAgent.rulesFolder", {
folderPath: modeToDelete.rulesFolderPath,
})}
</div>
)}
</>
)}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>{t("prompts:deleteAgent.cancel")}</AlertDialogCancel>
<AlertDialogAction onClick={onConfirm}>{t("prompts:deleteAgent.confirm")}</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)
}

View file

@ -0,0 +1,267 @@
// npx vitest src/components/modes/__tests__/AgentsView.spec.tsx
import { render, screen, fireEvent, waitFor } from "@/utils/test-utils"
import AgentsView from "../AgentsView"
import { ExtensionStateContext } from "@src/context/ExtensionStateContext"
import { vscode } from "@src/utils/vscode"
// Mock vscode API
vitest.mock("@src/utils/vscode", () => ({
vscode: {
postMessage: vitest.fn(),
},
}))
const mockExtensionState = {
customModePrompts: {},
listApiConfigMeta: [
{ id: "config1", name: "Config 1" },
{ id: "config2", name: "Config 2" },
],
enhancementApiConfigId: "",
setEnhancementApiConfigId: vitest.fn(),
mode: "code",
customModes: [],
customSupportPrompts: [],
currentApiConfigName: "",
customInstructions: "Initial instructions",
setCustomInstructions: vitest.fn(),
}
const renderPromptsView = (props = {}) => {
const mockOnDone = vitest.fn()
return render(
<ExtensionStateContext.Provider value={{ ...mockExtensionState, ...props } as any}>
<AgentsView onDone={mockOnDone} />
</ExtensionStateContext.Provider>,
)
}
Element.prototype.scrollIntoView = vitest.fn()
describe("PromptsView", () => {
beforeEach(() => {
vitest.clearAllMocks()
})
it("displays the current mode name in the select trigger", () => {
renderPromptsView({ mode: "code" })
const selectTrigger = screen.getByTestId("agent-select-trigger")
expect(selectTrigger).toHaveTextContent("Code")
})
it("opens the mode selection popover when the trigger is clicked", async () => {
renderPromptsView()
const selectTrigger = screen.getByTestId("agent-select-trigger")
fireEvent.click(selectTrigger)
await waitFor(() => {
expect(selectTrigger).toHaveAttribute("aria-expanded", "true")
})
})
it("filters mode options based on search input", async () => {
renderPromptsView()
const selectTrigger = screen.getByTestId("agent-select-trigger")
fireEvent.click(selectTrigger)
const searchInput = screen.getByTestId("agent-search-input")
fireEvent.change(searchInput, { target: { value: "ask" } })
await waitFor(() => {
expect(screen.getByTestId("agent-option-ask")).toBeInTheDocument()
expect(screen.queryByTestId("agent-option-code")).not.toBeInTheDocument()
expect(screen.queryByTestId("agent-option-architect")).not.toBeInTheDocument()
})
})
it("selects a mode from the dropdown and sends update message", async () => {
renderPromptsView()
const selectTrigger = screen.getByTestId("agent-select-trigger")
fireEvent.click(selectTrigger)
const askOption = await waitFor(() => screen.getByTestId("agent-option-ask"))
fireEvent.click(askOption)
expect(mockExtensionState.setEnhancementApiConfigId).not.toHaveBeenCalled() // Ensure this is not called by mode switch
expect(vscode.postMessage).toHaveBeenCalledWith({
type: "mode",
text: "ask",
})
await waitFor(() => {
expect(selectTrigger).toHaveAttribute("aria-expanded", "false")
})
})
it("handles prompt changes correctly", async () => {
renderPromptsView()
// Get the textarea
const textarea = await waitFor(() => screen.getByTestId("code-prompt-textarea"))
// Simulate VSCode TextArea change event
const changeEvent = new CustomEvent("change", {
detail: {
target: {
value: "New prompt value",
},
},
})
fireEvent(textarea, changeEvent)
expect(vscode.postMessage).toHaveBeenCalledWith({
type: "updatePrompt",
promptMode: "code",
customPrompt: { roleDefinition: "New prompt value" },
})
})
it("resets role definition only for built-in modes", async () => {
const customMode = {
slug: "custom-mode",
name: "Custom Mode",
roleDefinition: "Custom role",
groups: [],
}
// Test with built-in mode (code)
const { unmount } = render(
<ExtensionStateContext.Provider
value={{ ...mockExtensionState, mode: "code", customModes: [customMode] } as any}>
<AgentsView onDone={vitest.fn()} />
</ExtensionStateContext.Provider>,
)
// Find and click the role definition reset button
const resetButton = screen.getByTestId("role-definition-reset")
expect(resetButton).toBeInTheDocument()
await fireEvent.click(resetButton)
// Verify it only resets role definition
// When resetting a built-in mode's role definition, the field should be removed entirely
// from the customPrompt object, not set to undefined.
// This allows the default role definition from the built-in mode to be used instead.
expect(vscode.postMessage).toHaveBeenCalledWith({
type: "updatePrompt",
promptMode: "code",
customPrompt: {}, // Empty object because the role definition field is removed entirely
})
// Cleanup before testing custom mode
unmount()
// Test with custom mode
render(
<ExtensionStateContext.Provider
value={{ ...mockExtensionState, mode: "custom-mode", customModes: [customMode] } as any}>
<AgentsView onDone={vitest.fn()} />
</ExtensionStateContext.Provider>,
)
// Verify reset button is not present for custom mode
expect(screen.queryByTestId("role-definition-reset")).not.toBeInTheDocument()
})
it("description section behavior for different mode types", async () => {
const customMode = {
slug: "custom-mode",
name: "Custom Mode",
roleDefinition: "Custom role",
description: "Custom description",
groups: [],
}
// Test with built-in mode (code) - description section should be shown with reset button
const { unmount } = render(
<ExtensionStateContext.Provider
value={{ ...mockExtensionState, mode: "code", customModes: [customMode] } as any}>
<AgentsView onDone={vitest.fn()} />
</ExtensionStateContext.Provider>,
)
// Verify description reset button IS present for built-in modes
// because built-in modes can have their descriptions customized and reset
expect(screen.queryByTestId("description-reset")).toBeInTheDocument()
// Cleanup before testing custom mode
unmount()
// Test with custom mode - description section should be shown
render(
<ExtensionStateContext.Provider
value={{ ...mockExtensionState, mode: "custom-mode", customModes: [customMode] } as any}>
<AgentsView onDone={vitest.fn()} />
</ExtensionStateContext.Provider>,
)
// Verify description section is present for custom modes
// but reset button is NOT present (since custom modes manage their own descriptions)
expect(screen.queryByTestId("description-reset")).not.toBeInTheDocument()
// Verify the description text field is present for custom modes
expect(screen.getByTestId("custom-mode-description-textfield")).toBeInTheDocument()
})
it("handles clearing custom instructions correctly", async () => {
const setCustomInstructions = vitest.fn()
renderPromptsView({
...mockExtensionState,
customInstructions: "Initial instructions",
setCustomInstructions,
})
const textarea = screen.getByTestId("global-custom-instructions-textarea")
// Simulate VSCode TextArea change event with empty value
// We need to simulate both the CustomEvent format and regular event format
// since the component handles both
Object.defineProperty(textarea, "value", {
writable: true,
value: "",
})
const changeEvent = new Event("change", { bubbles: true })
fireEvent(textarea, changeEvent)
// The component calls setCustomInstructions with value || undefined
// Since empty string is falsy, it should be undefined
expect(setCustomInstructions).toHaveBeenCalledWith(undefined)
expect(vscode.postMessage).toHaveBeenCalledWith({
type: "customInstructions",
text: undefined,
})
})
it("closes the mode selection popover when ESC key is pressed", async () => {
renderPromptsView()
const selectTrigger = screen.getByTestId("agent-select-trigger")
// Open the popover
fireEvent.click(selectTrigger)
await waitFor(() => {
expect(selectTrigger).toHaveAttribute("aria-expanded", "true")
})
// Press ESC key
fireEvent.keyDown(window, { key: "Escape" })
// Verify popover is closed
await waitFor(() => {
expect(selectTrigger).toHaveAttribute("aria-expanded", "false")
})
})
it("does not close the popover when ESC is pressed while popover is closed", async () => {
renderPromptsView()
const selectTrigger = screen.getByTestId("agent-select-trigger")
// Ensure popover is closed
expect(selectTrigger).toHaveAttribute("aria-expanded", "false")
// Press ESC key
fireEvent.keyDown(window, { key: "Escape" })
// Verify popover remains closed
expect(selectTrigger).toHaveAttribute("aria-expanded", "false")
})
})

View file

@ -0,0 +1,304 @@
import React from "react"
import { ChevronUp, Check, X } from "lucide-react"
import { cn } from "@/lib/utils"
import { useRooPortal } from "@/components/ui/hooks/useRooPortal"
import { Popover, PopoverContent, PopoverTrigger, StandardTooltip } from "@/components/ui"
import { IconButton } from "./IconButton"
import { vscode } from "@/utils/vscode"
import { useExtensionState } from "@/context/ExtensionStateContext"
import { useAppTranslation } from "@/i18n/TranslationContext"
import { Mode, getAllModes } from "@roo/modes"
import { ModeConfig, CustomModePrompts } from "@roo-code/types"
import { telemetryClient } from "@/utils/TelemetryClient"
import { TelemetryEventName } from "@roo-code/types"
import { Fzf } from "fzf"
// Minimum number of modes required to show search functionality
const SEARCH_THRESHOLD = 6
interface AgentSelectorProps {
value: Mode
onChange: (value: Mode) => void
disabled?: boolean
title?: string
triggerClassName?: string
modeShortcutText: string
customModes?: ModeConfig[]
customModePrompts?: CustomModePrompts
disableSearch?: boolean
}
export const AgentSelector = ({
value,
onChange,
disabled = false,
title = "",
triggerClassName = "",
modeShortcutText,
customModes,
customModePrompts,
disableSearch = false,
}: AgentSelectorProps) => {
const [open, setOpen] = React.useState(false)
const [searchValue, setSearchValue] = React.useState("")
const searchInputRef = React.useRef<HTMLInputElement>(null)
const portalContainer = useRooPortal("roo-portal")
const { hasOpenedModeSelector, setHasOpenedModeSelector } = useExtensionState()
const { t } = useAppTranslation()
const trackAgentSelectorOpened = React.useCallback(() => {
// Track telemetry every time the agent selector is opened
telemetryClient.capture(TelemetryEventName.MODE_SELECTOR_OPENED)
// Track first-time usage for UI purposes
if (!hasOpenedModeSelector) {
setHasOpenedModeSelector(true)
vscode.postMessage({ type: "hasOpenedModeSelector", bool: true })
}
}, [hasOpenedModeSelector, setHasOpenedModeSelector])
// Get all modes including custom modes and merge custom prompt descriptions
const modes = React.useMemo(() => {
const allModes = getAllModes(customModes)
return allModes.map((mode) => ({
...mode,
description: customModePrompts?.[mode.slug]?.description ?? mode.description,
}))
}, [customModes, customModePrompts])
// Find the selected mode
const selectedMode = React.useMemo(() => modes.find((mode) => mode.slug === value), [modes, value])
// Memoize searchable items for fuzzy search with separate name and description search
const nameSearchItems = React.useMemo(() => {
return modes.map((mode) => ({
original: mode,
searchStr: [mode.name, mode.slug].filter(Boolean).join(" "),
}))
}, [modes])
const descriptionSearchItems = React.useMemo(() => {
return modes.map((mode) => ({
original: mode,
searchStr: mode.description || "",
}))
}, [modes])
// Create memoized Fzf instances for name and description searches
const nameFzfInstance = React.useMemo(() => {
return new Fzf(nameSearchItems, {
selector: (item) => item.searchStr,
})
}, [nameSearchItems])
const descriptionFzfInstance = React.useMemo(() => {
return new Fzf(descriptionSearchItems, {
selector: (item) => item.searchStr,
})
}, [descriptionSearchItems])
// Filter modes based on search value using fuzzy search with priority
const filteredModes = React.useMemo(() => {
if (!searchValue) return modes
// First search in names/slugs
const nameMatches = nameFzfInstance.find(searchValue)
const nameMatchedModes = new Set(nameMatches.map((result) => result.item.original.slug))
// Then search in descriptions
const descriptionMatches = descriptionFzfInstance.find(searchValue)
// Combine results: name matches first, then description matches
const combinedResults = [
...nameMatches.map((result) => result.item.original),
...descriptionMatches
.filter((result) => !nameMatchedModes.has(result.item.original.slug))
.map((result) => result.item.original),
]
return combinedResults
}, [modes, searchValue, nameFzfInstance, descriptionFzfInstance])
const onClearSearch = React.useCallback(() => {
setSearchValue("")
searchInputRef.current?.focus()
}, [])
const handleSelect = React.useCallback(
(modeSlug: string) => {
onChange(modeSlug as Mode)
setOpen(false)
// Clear search after selection
setSearchValue("")
},
[onChange],
)
const onOpenChange = React.useCallback(
(isOpen: boolean) => {
if (isOpen) trackAgentSelectorOpened()
setOpen(isOpen)
// Clear search when closing
if (!isOpen) {
setSearchValue("")
}
},
[trackAgentSelectorOpened],
)
// Auto-focus search input when popover opens
React.useEffect(() => {
if (open && searchInputRef.current) {
searchInputRef.current.focus()
}
}, [open])
// Determine if search should be shown
const showSearch = !disableSearch && modes.length > SEARCH_THRESHOLD
// Combine instruction text for tooltip
const instructionText = `${t("chat:modeSelector.description")} ${modeShortcutText}`
const trigger = (
<PopoverTrigger
disabled={disabled}
data-testid="agent-selector-trigger"
className={cn(
"inline-flex items-center gap-1.5 relative whitespace-nowrap px-1.5 py-1 text-xs",
"bg-transparent border border-[rgba(255,255,255,0.08)] rounded-md text-vscode-foreground",
"transition-all duration-150 focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder focus-visible:ring-inset",
disabled
? "opacity-50 cursor-not-allowed"
: "opacity-90 hover:opacity-100 hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)] cursor-pointer",
triggerClassName,
!disabled && !hasOpenedModeSelector
? "bg-primary opacity-90 hover:bg-primary-hover text-vscode-button-foreground"
: null,
)}>
<ChevronUp className="pointer-events-none opacity-80 flex-shrink-0 size-3" />
<span className="truncate">{selectedMode?.name || ""}</span>
</PopoverTrigger>
)
return (
<Popover open={open} onOpenChange={onOpenChange} data-testid="agent-selector-root">
{title ? <StandardTooltip content={title}>{trigger}</StandardTooltip> : trigger}
<PopoverContent
align="start"
sideOffset={4}
container={portalContainer}
className="p-0 overflow-hidden min-w-80 max-w-9/10">
<div className="flex flex-col w-full">
{/* Show search bar only when there are more than SEARCH_THRESHOLD items, otherwise show info blurb */}
{showSearch ? (
<div className="relative p-2 border-b border-vscode-dropdown-border">
<input
aria-label="Search modes"
ref={searchInputRef}
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
placeholder={t("chat:modeSelector.searchPlaceholder")}
className="w-full h-8 px-2 py-1 text-xs bg-vscode-input-background text-vscode-input-foreground border border-vscode-input-border rounded focus:outline-0"
data-testid="agent-search-input"
/>
{searchValue.length > 0 && (
<div className="absolute right-4 top-0 bottom-0 flex items-center justify-center">
<X
className="text-vscode-input-foreground opacity-50 hover:opacity-100 size-4 p-0.5 cursor-pointer"
onClick={onClearSearch}
/>
</div>
)}
</div>
) : (
<div className="p-3 border-b border-vscode-dropdown-border">
<p className="m-0 text-xs text-vscode-descriptionForeground">{instructionText}</p>
</div>
)}
{/* Mode List */}
<div className="max-h-[300px] overflow-y-auto">
{filteredModes.length === 0 && searchValue ? (
<div className="py-2 px-3 text-sm text-vscode-foreground/70">
{t("chat:modeSelector.noResults")}
</div>
) : (
<div className="py-1">
{filteredModes.map((mode) => (
<div
key={mode.slug}
onClick={() => handleSelect(mode.slug)}
className={cn(
"px-3 py-1.5 text-sm cursor-pointer flex items-center",
"hover:bg-vscode-list-hoverBackground",
mode.slug === value
? "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground"
: "",
)}
data-testid="agent-selector-item">
<div className="flex-1 min-w-0">
<div className="font-bold truncate">{mode.name}</div>
{mode.description && (
<div className="text-xs text-vscode-descriptionForeground truncate">
{mode.description}
</div>
)}
</div>
{mode.slug === value && <Check className="ml-auto size-4 p-0.5" />}
</div>
))}
</div>
)}
</div>
{/* Bottom bar with buttons on left and title on right */}
<div className="flex flex-row items-center justify-between px-2 py-2 border-t border-vscode-dropdown-border">
<div className="flex flex-row gap-1">
<IconButton
iconClass="codicon-extensions"
title={t("chat:modeSelector.marketplace")}
onClick={() => {
window.postMessage(
{
type: "action",
action: "marketplaceButtonClicked",
values: { marketplaceTab: "mode" },
},
"*",
)
setOpen(false)
}}
/>
<IconButton
iconClass="codicon-settings-gear"
title={t("chat:modeSelector.settings")}
onClick={() => {
vscode.postMessage({
type: "switchTab",
tab: "agents",
})
setOpen(false)
}}
/>
</div>
{/* Info icon and title on the right - only show info icon when search bar is visible */}
<div className="flex items-center gap-1 pr-1">
{showSearch && (
<StandardTooltip content={instructionText}>
<span className="codicon codicon-info text-xs text-vscode-descriptionForeground opacity-70 hover:opacity-100 cursor-help" />
</StandardTooltip>
)}
<h4 className="m-0 font-medium text-sm text-vscode-descriptionForeground">
{t("chat:modeSelector.title")}
</h4>
</div>
</div>
</div>
</PopoverContent>
</Popover>
)
}
export default AgentSelector

View file

@ -22,7 +22,7 @@ import { convertToMentionPath } from "@/utils/path-mentions"
import { StandardTooltip } from "@/components/ui"
import Thumbnails from "../common/Thumbnails"
import ModeSelector from "./ModeSelector"
import AgentSelector from "./AgentSelector"
import { ApiConfigSelector } from "./ApiConfigSelector"
import { MAX_IMAGES_PER_MESSAGE } from "./ChatView"
import ContextMenu from "./ContextMenu"
@ -31,7 +31,7 @@ import { IndexingStatusBadge } from "./IndexingStatusBadge"
import { SlashCommandsPopover } from "./SlashCommandsPopover"
import { cn } from "@/lib/utils"
import { usePromptHistory } from "./hooks/usePromptHistory"
import { EditModeControls } from "./EditModeControls"
import { EditAgentControls } from "./EditAgentControls"
interface ChatTextAreaProps {
inputValue: string
@ -897,9 +897,9 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
[setMode],
)
// Helper function to render mode selector
const renderModeSelector = () => (
<ModeSelector
// Helper function to render agent selector
const renderAgentSelector = () => (
<AgentSelector
value={mode}
title={t("chat:selectMode")}
onChange={handleModeChange}
@ -915,11 +915,11 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
vscode.postMessage({ type: "loadApiConfigurationById", text: value })
}, [])
// Helper function to render non-edit mode controls
const renderNonEditModeControls = () => (
// Helper function to render non-edit agent controls
const renderNonEditAgentControls = () => (
<div className={cn("flex", "justify-between", "items-center", "mt-auto")}>
<div className={cn("flex", "items-center", "gap-1", "min-w-0")}>
<div className="shrink-0">{renderModeSelector()}</div>
<div className="shrink-0">{renderAgentSelector()}</div>
<div className={cn("flex-1", "min-w-0", "overflow-hidden")}>
<ApiConfigSelector
@ -1226,7 +1226,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
</div>
{isEditMode && (
<EditModeControls
<EditAgentControls
mode={mode}
onModeChange={handleModeChange}
modeShortcutText={modeShortcutText}
@ -1253,7 +1253,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
/>
)}
{!isEditMode && renderNonEditModeControls()}
{!isEditMode && renderNonEditAgentControls()}
</div>
)
},

View file

@ -0,0 +1,115 @@
import React from "react"
import { Mode } from "@roo/modes"
import { Button, StandardTooltip } from "@/components/ui"
import { Image, SendHorizontal } from "lucide-react"
import { cn } from "@/lib/utils"
import AgentSelector from "./AgentSelector"
import { useAppTranslation } from "@/i18n/TranslationContext"
interface EditAgentControlsProps {
mode: Mode
onModeChange: (value: Mode) => void
modeShortcutText: string
customModes: any
customModePrompts: any
onCancel?: () => void
onSend: () => void
onSelectImages: () => void
sendingDisabled: boolean
shouldDisableImages: boolean
}
export const EditAgentControls: React.FC<EditAgentControlsProps> = ({
mode,
onModeChange,
modeShortcutText,
customModes,
customModePrompts,
onCancel,
onSend,
onSelectImages,
sendingDisabled,
shouldDisableImages,
}) => {
const { t } = useAppTranslation()
return (
<div
className={cn(
"flex",
"items-center",
"justify-between",
"absolute",
"bottom-2",
"left-2",
"right-2",
"z-30",
)}>
<div className={cn("flex", "items-center", "gap-1", "flex-1", "min-w-0")}>
<div className="shrink-0">
<AgentSelector
value={mode}
title={t("chat:selectMode")}
onChange={onModeChange}
triggerClassName="w-full"
modeShortcutText={modeShortcutText}
customModes={customModes}
customModePrompts={customModePrompts}
/>
</div>
</div>
<div className={cn("flex", "items-center", "gap-0.5", "shrink-0", "ml-2")}>
<Button
variant="secondary"
size="sm"
onClick={onCancel}
disabled={sendingDisabled}
className="text-xs bg-vscode-toolbar-hoverBackground hover:bg-vscode-button-secondaryBackground text-vscode-button-secondaryForeground">
Cancel
</Button>
<StandardTooltip content={t("chat:addImages")}>
<button
aria-label={t("chat:addImages")}
disabled={shouldDisableImages}
onClick={!shouldDisableImages ? onSelectImages : undefined}
className={cn(
"relative inline-flex items-center justify-center",
"bg-transparent border-none p-1.5",
"rounded-md min-w-[28px] min-h-[28px]",
"opacity-60 hover:opacity-100 text-vscode-descriptionForeground hover:text-vscode-foreground",
"transition-all duration-150",
"hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)]",
"focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder",
"active:bg-[rgba(255,255,255,0.1)]",
!shouldDisableImages && "cursor-pointer",
shouldDisableImages &&
"opacity-40 cursor-not-allowed grayscale-[30%] hover:bg-transparent hover:border-[rgba(255,255,255,0.08)] active:bg-transparent",
)}>
<Image className="w-4 h-4" />
</button>
</StandardTooltip>
<StandardTooltip content={t("chat:save.tooltip")}>
<button
aria-label={t("chat:save.tooltip")}
disabled={sendingDisabled}
onClick={!sendingDisabled ? onSend : undefined}
className={cn(
"relative inline-flex items-center justify-center",
"bg-transparent border-none p-1.5",
"rounded-md min-w-[28px] min-h-[28px]",
"opacity-60 hover:opacity-100 text-vscode-descriptionForeground hover:text-vscode-foreground",
"transition-all duration-150",
"hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)]",
"focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder",
"active:bg-[rgba(255,255,255,0.1)]",
!sendingDisabled && "cursor-pointer",
sendingDisabled &&
"opacity-40 cursor-not-allowed grayscale-[30%] hover:bg-transparent hover:border-[rgba(255,255,255,0.08)] active:bg-transparent",
)}>
<SendHorizontal className="w-4 h-4" />
</button>
</StandardTooltip>
</div>
</div>
)
}

View file

@ -1,7 +1,7 @@
import React from "react"
import { render, screen, fireEvent } from "@/utils/test-utils"
import { describe, test, expect, vi } from "vitest"
import ModeSelector from "../ModeSelector"
import AgentSelector from "../AgentSelector"
import { Mode } from "@roo/modes"
import { ModeConfig } from "@roo-code/types"
@ -14,8 +14,8 @@ vi.mock("@/utils/vscode", () => ({
vi.mock("@/context/ExtensionStateContext", () => ({
useExtensionState: () => ({
hasOpenedModeSelector: false,
setHasOpenedModeSelector: vi.fn(),
hasOpenedAgentSelector: false,
setHasOpenedAgentSelector: vi.fn(),
}),
}))
@ -46,7 +46,7 @@ vi.mock("@roo/modes", async () => {
}
})
describe("ModeSelector", () => {
describe("AgentSelector", () => {
test("shows custom description from customModePrompts", () => {
const customModePrompts = {
code: {
@ -55,7 +55,7 @@ describe("ModeSelector", () => {
}
render(
<ModeSelector
<AgentSelector
value={"code" as Mode}
onChange={vi.fn()}
modeShortcutText="Ctrl+M"
@ -64,14 +64,14 @@ describe("ModeSelector", () => {
)
// The component should be rendered
expect(screen.getByTestId("mode-selector-trigger")).toBeInTheDocument()
expect(screen.getByTestId("agent-selector-trigger")).toBeInTheDocument()
})
test("falls back to default description when no custom prompt", () => {
render(<ModeSelector value={"code" as Mode} onChange={vi.fn()} modeShortcutText="Ctrl+M" />)
render(<AgentSelector value={"code" as Mode} onChange={vi.fn()} modeShortcutText="Ctrl+M" />)
// The component should be rendered
expect(screen.getByTestId("mode-selector-trigger")).toBeInTheDocument()
expect(screen.getByTestId("agent-selector-trigger")).toBeInTheDocument()
})
test("shows search bar when there are more than 6 modes", () => {
@ -84,13 +84,13 @@ describe("ModeSelector", () => {
groups: ["read", "edit"],
}))
render(<ModeSelector value={"mode-0" as Mode} onChange={vi.fn()} modeShortcutText="Ctrl+M" />)
render(<AgentSelector value={"mode-0" as Mode} onChange={vi.fn()} modeShortcutText="Ctrl+M" />)
// Click to open the popover
fireEvent.click(screen.getByTestId("mode-selector-trigger"))
fireEvent.click(screen.getByTestId("agent-selector-trigger"))
// Search input should be visible
expect(screen.getByTestId("mode-search-input")).toBeInTheDocument()
expect(screen.getByTestId("agent-search-input")).toBeInTheDocument()
// Info icon should be visible
expect(screen.getByText("chat:modeSelector.title")).toBeInTheDocument()
@ -108,13 +108,13 @@ describe("ModeSelector", () => {
groups: ["read", "edit"],
}))
render(<ModeSelector value={"mode-0" as Mode} onChange={vi.fn()} modeShortcutText="Ctrl+M" />)
render(<AgentSelector value={"mode-0" as Mode} onChange={vi.fn()} modeShortcutText="Ctrl+M" />)
// Click to open the popover
fireEvent.click(screen.getByTestId("mode-selector-trigger"))
fireEvent.click(screen.getByTestId("agent-selector-trigger"))
// Search input should NOT be visible
expect(screen.queryByTestId("mode-search-input")).not.toBeInTheDocument()
expect(screen.queryByTestId("agent-search-input")).not.toBeInTheDocument()
// Info blurb should be visible
expect(screen.getByText(/chat:modeSelector.description/)).toBeInTheDocument()
@ -134,17 +134,17 @@ describe("ModeSelector", () => {
groups: ["read", "edit"],
}))
render(<ModeSelector value={"mode-0" as Mode} onChange={vi.fn()} modeShortcutText="Ctrl+M" />)
render(<AgentSelector value={"mode-0" as Mode} onChange={vi.fn()} modeShortcutText="Ctrl+M" />)
// Click to open the popover
fireEvent.click(screen.getByTestId("mode-selector-trigger"))
fireEvent.click(screen.getByTestId("agent-selector-trigger"))
// Type in search
const searchInput = screen.getByTestId("mode-search-input")
const searchInput = screen.getByTestId("agent-search-input")
fireEvent.change(searchInput, { target: { value: "Mode 3" } })
// Should show filtered results
const modeItems = screen.getAllByTestId("mode-selector-item")
const modeItems = screen.getAllByTestId("agent-selector-item")
expect(modeItems.length).toBeLessThan(7) // Should have filtered some out
})
@ -159,14 +159,19 @@ describe("ModeSelector", () => {
}))
render(
<ModeSelector value={"mode-0" as Mode} onChange={vi.fn()} modeShortcutText="Ctrl+M" disableSearch={true} />,
<AgentSelector
value={"mode-0" as Mode}
onChange={vi.fn()}
modeShortcutText="Ctrl+M"
disableSearch={true}
/>,
)
// Click to open the popover
fireEvent.click(screen.getByTestId("mode-selector-trigger"))
fireEvent.click(screen.getByTestId("agent-selector-trigger"))
// Search input should NOT be visible even with 10 modes
expect(screen.queryByTestId("mode-search-input")).not.toBeInTheDocument()
expect(screen.queryByTestId("agent-search-input")).not.toBeInTheDocument()
// Info blurb should be visible instead
expect(screen.getByText(/chat:modeSelector.description/)).toBeInTheDocument()
@ -187,13 +192,13 @@ describe("ModeSelector", () => {
}))
// Don't pass disableSearch prop (should default to false)
render(<ModeSelector value={"mode-0" as Mode} onChange={vi.fn()} modeShortcutText="Ctrl+M" />)
render(<AgentSelector value={"mode-0" as Mode} onChange={vi.fn()} modeShortcutText="Ctrl+M" />)
// Click to open the popover
fireEvent.click(screen.getByTestId("mode-selector-trigger"))
fireEvent.click(screen.getByTestId("agent-selector-trigger"))
// Search input should be visible
expect(screen.getByTestId("mode-search-input")).toBeInTheDocument()
expect(screen.getByTestId("agent-search-input")).toBeInTheDocument()
// Info icon should be visible
const infoIcon = document.querySelector(".codicon-info")

View file

@ -1,7 +1,7 @@
import React from "react"
import { render, screen, fireEvent } from "@testing-library/react"
import { describe, it, expect, vi, beforeEach } from "vitest"
import { EditModeControls } from "../EditModeControls"
import { EditAgentControls } from "../EditAgentControls"
import { Mode } from "@roo/modes"
// Mock the translation hook
@ -31,7 +31,7 @@ vi.mock("../ModeSelector", () => ({
),
}))
describe("EditModeControls", () => {
describe("EditAgentControls", () => {
const defaultProps = {
mode: "code" as Mode,
onModeChange: vi.fn(),
@ -50,7 +50,7 @@ describe("EditModeControls", () => {
})
it("renders all controls correctly", () => {
render(<EditModeControls {...defaultProps} />)
render(<EditAgentControls {...defaultProps} />)
// Check for mode selector
expect(screen.getByTitle("chat:selectMode")).toBeInTheDocument()
@ -66,7 +66,7 @@ describe("EditModeControls", () => {
})
it("calls onCancel when Cancel button is clicked", () => {
render(<EditModeControls {...defaultProps} />)
render(<EditAgentControls {...defaultProps} />)
const cancelButton = screen.getByText("Cancel")
fireEvent.click(cancelButton)
@ -75,7 +75,7 @@ describe("EditModeControls", () => {
})
it("calls onSend when send button is clicked", () => {
render(<EditModeControls {...defaultProps} />)
render(<EditAgentControls {...defaultProps} />)
const sendButton = screen.getByLabelText("chat:save.tooltip")
fireEvent.click(sendButton)
@ -84,7 +84,7 @@ describe("EditModeControls", () => {
})
it("calls onSelectImages when image button is clicked", () => {
render(<EditModeControls {...defaultProps} />)
render(<EditAgentControls {...defaultProps} />)
const imageButton = screen.getByLabelText("chat:addImages")
fireEvent.click(imageButton)
@ -93,7 +93,7 @@ describe("EditModeControls", () => {
})
it("disables buttons when sendingDisabled is true", () => {
render(<EditModeControls {...defaultProps} sendingDisabled={true} />)
render(<EditAgentControls {...defaultProps} sendingDisabled={true} />)
const cancelButton = screen.getByText("Cancel")
const sendButton = screen.getByLabelText("chat:save.tooltip")
@ -103,14 +103,14 @@ describe("EditModeControls", () => {
})
it("disables image button when shouldDisableImages is true", () => {
render(<EditModeControls {...defaultProps} shouldDisableImages={true} />)
render(<EditAgentControls {...defaultProps} shouldDisableImages={true} />)
const imageButton = screen.getByLabelText("chat:addImages")
expect(imageButton).toBeDisabled()
})
it("does not call onSelectImages when image button is disabled", () => {
render(<EditModeControls {...defaultProps} shouldDisableImages={true} />)
render(<EditAgentControls {...defaultProps} shouldDisableImages={true} />)
const imageButton = screen.getByLabelText("chat:addImages")
fireEvent.click(imageButton)
@ -119,7 +119,7 @@ describe("EditModeControls", () => {
})
it("does not call onSend when send button is disabled", () => {
render(<EditModeControls {...defaultProps} sendingDisabled={true} />)
render(<EditAgentControls {...defaultProps} sendingDisabled={true} />)
const sendButton = screen.getByLabelText("chat:save.tooltip")
fireEvent.click(sendButton)
@ -128,7 +128,7 @@ describe("EditModeControls", () => {
})
it("calls onModeChange when mode is changed", () => {
render(<EditModeControls {...defaultProps} />)
render(<EditAgentControls {...defaultProps} />)
const modeSelector = screen.getByTitle("chat:selectMode")
fireEvent.change(modeSelector, { target: { value: "architect" } })

View file

@ -194,7 +194,7 @@ export const MarketplaceInstallModal: React.FC<MarketplaceInstallModalProps> = (
setValidationError(null)
}
const handlePostInstallAction = (tab: "mcp" | "modes") => {
const handlePostInstallAction = (tab: "mcp" | "agents") => {
if (tab === "mcp") {
// Navigate to MCP tab
window.postMessage(
@ -376,7 +376,7 @@ export const MarketplaceInstallModal: React.FC<MarketplaceInstallModalProps> = (
<Button variant="outline" onClick={onClose}>
{t("marketplace:install.done")}
</Button>
<Button onClick={() => handlePostInstallAction(item.type === "mcp" ? "mcp" : "modes")}>
<Button onClick={() => handlePostInstallAction(item.type === "mcp" ? "mcp" : "agents")}>
{item.type === "mcp"
? t("marketplace:install.goToMcp")
: t("marketplace:install.goToModes")}

View file

@ -4,7 +4,9 @@ import {
type ProviderSettings,
type ProviderSettingsEntry,
type CustomModePrompts,
type CustomAgentPrompts,
type ModeConfig,
type AgentConfig,
type ExperimentId,
type OrganizationAllowList,
ORGANIZATION_ALLOW_ALL,
@ -111,6 +113,9 @@ export interface ExtensionStateContextType extends ExtensionState {
setAutoApprovalEnabled: (value: boolean) => void
customModes: ModeConfig[]
setCustomModes: (value: ModeConfig[]) => void
// New agent-specific properties with backward compatibility
customAgents: AgentConfig[]
setCustomAgents: (value: AgentConfig[]) => void
setMaxOpenTabsContext: (value: number) => void
maxWorkspaceFiles: number
setMaxWorkspaceFiles: (value: number) => void
@ -205,6 +210,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
hasOpenedModeSelector: false, // Default to false (not opened yet)
autoApprovalEnabled: false,
customModes: [],
customAgents: [], // Initialize empty agents array
maxOpenTabsContext: 20,
maxWorkspaceFiles: 200,
cwd: "",
@ -453,6 +459,14 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
setState((prevState) => ({ ...prevState, enhancementApiConfigId: value })),
setAutoApprovalEnabled: (value) => setState((prevState) => ({ ...prevState, autoApprovalEnabled: value })),
setCustomModes: (value) => setState((prevState) => ({ ...prevState, customModes: value })),
// Agent-specific setters with backward compatibility
customAgents: state.customAgents || state.customModes || [], // Fall back to customModes if customAgents not set
setCustomAgents: (value) =>
setState((prevState) => ({
...prevState,
customAgents: value,
customModes: value, // Keep customModes in sync for backward compatibility
})),
setMaxOpenTabsContext: (value) => setState((prevState) => ({ ...prevState, maxOpenTabsContext: value })),
setMaxWorkspaceFiles: (value) => setState((prevState) => ({ ...prevState, maxWorkspaceFiles: value })),
setBrowserToolEnabled: (value) => setState((prevState) => ({ ...prevState, browserToolEnabled: value })),