mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
chore(marketplace): finishing touches (#14)
* fix(marketplace): done should redirect to browse * test(marketplace): update outdated tests * refactor(marketplace): handle opening in non-workspace * feat(marketplace): put behind a feature flag * fix(marketplace): missing translations * fix: solve lint errors, make build-able * fix: use `cwd` instead of `filePaths` for ws detection * fix(marketplace): should dedupe items with same id from multiple registries * fix: tab cycle should not reach hidden content * fix: `mcp` filter --------- Co-authored-by: NamesMT <dangquoctrung123@gmail.com>
This commit is contained in:
parent
325b34db3d
commit
b0d1895753
50 changed files with 319 additions and 118 deletions
3
src/exports/roo-code.d.ts
vendored
3
src/exports/roo-code.d.ts
vendored
|
|
@ -104,6 +104,7 @@ type GlobalSettings = {
|
|||
| {
|
||||
autoCondenseContext: boolean
|
||||
powerSteering: boolean
|
||||
marketplace: boolean
|
||||
}
|
||||
| undefined
|
||||
language?:
|
||||
|
|
@ -843,6 +844,7 @@ type IpcMessage =
|
|||
| {
|
||||
autoCondenseContext: boolean
|
||||
powerSteering: boolean
|
||||
marketplace: boolean
|
||||
}
|
||||
| undefined
|
||||
language?:
|
||||
|
|
@ -1325,6 +1327,7 @@ type TaskCommand =
|
|||
| {
|
||||
autoCondenseContext: boolean
|
||||
powerSteering: boolean
|
||||
marketplace: boolean
|
||||
}
|
||||
| undefined
|
||||
language?:
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ type GlobalSettings = {
|
|||
| {
|
||||
autoCondenseContext: boolean
|
||||
powerSteering: boolean
|
||||
marketplace: boolean
|
||||
}
|
||||
| undefined
|
||||
language?:
|
||||
|
|
@ -857,6 +858,7 @@ type IpcMessage =
|
|||
| {
|
||||
autoCondenseContext: boolean
|
||||
powerSteering: boolean
|
||||
marketplace: boolean
|
||||
}
|
||||
| undefined
|
||||
language?:
|
||||
|
|
@ -1341,6 +1343,7 @@ type TaskCommand =
|
|||
| {
|
||||
autoCondenseContext: boolean
|
||||
powerSteering: boolean
|
||||
marketplace: boolean
|
||||
}
|
||||
| undefined
|
||||
language?:
|
||||
|
|
|
|||
|
|
@ -387,7 +387,7 @@ export type CommandExecutionStatus = z.infer<typeof commandExecutionStatusSchema
|
|||
* ExperimentId
|
||||
*/
|
||||
|
||||
export const experimentIds = ["autoCondenseContext", "powerSteering"] as const
|
||||
export const experimentIds = ["autoCondenseContext", "powerSteering", "marketplace"] as const
|
||||
|
||||
export const experimentIdsSchema = z.enum(experimentIds)
|
||||
|
||||
|
|
@ -400,6 +400,7 @@ export type ExperimentId = z.infer<typeof experimentIdsSchema>
|
|||
const experimentsSchema = z.object({
|
||||
autoCondenseContext: z.boolean(),
|
||||
powerSteering: z.boolean(),
|
||||
marketplace: z.boolean(),
|
||||
})
|
||||
|
||||
export type Experiments = z.infer<typeof experimentsSchema>
|
||||
|
|
|
|||
|
|
@ -82,9 +82,19 @@ export class MarketplaceManager {
|
|||
async getMarketplaceItems(
|
||||
enabledSources: MarketplaceSource[],
|
||||
): Promise<{ items: MarketplaceItem[]; errors?: string[] }> {
|
||||
const items: MarketplaceItem[] = []
|
||||
const dedupedItems: Record<string, MarketplaceItem> = {}
|
||||
const errors: string[] = []
|
||||
|
||||
function _dedupeAndAddItem(item: MarketplaceItem) {
|
||||
const id = item.id
|
||||
const existingItem = dedupedItems[id]
|
||||
if (existingItem) {
|
||||
if (existingItem.version >= item.version) return
|
||||
}
|
||||
|
||||
dedupedItems[id] = item
|
||||
}
|
||||
|
||||
// Process sources sequentially with locking
|
||||
for (const source of enabledSources) {
|
||||
if (this.isSourceLocked(source.url)) {
|
||||
|
|
@ -105,7 +115,7 @@ export class MarketplaceManager {
|
|||
sourceName: source.name || this.getRepoNameFromUrl(source.url),
|
||||
sourceUrl: source.url,
|
||||
}))
|
||||
items.push(...itemsWithSource)
|
||||
itemsWithSource.forEach(_dedupeAndAddItem)
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
|
|
@ -118,13 +128,13 @@ export class MarketplaceManager {
|
|||
}
|
||||
|
||||
// Store the current items
|
||||
this.currentItems = items
|
||||
this.currentItems = Object.values(dedupedItems)
|
||||
// Preserve original unfiltered items
|
||||
this.originalItems = items
|
||||
this.originalItems = this.currentItems
|
||||
|
||||
// Return both items and errors
|
||||
const result = {
|
||||
items,
|
||||
items: this.originalItems,
|
||||
...(errors.length > 0 && { errors }),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ describe("experiments", () => {
|
|||
const experiments: Record<ExperimentId, boolean> = {
|
||||
powerSteering: false,
|
||||
autoCondenseContext: false,
|
||||
marketplace: false,
|
||||
}
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false)
|
||||
})
|
||||
|
|
@ -32,6 +33,7 @@ describe("experiments", () => {
|
|||
const experiments: Record<ExperimentId, boolean> = {
|
||||
powerSteering: true,
|
||||
autoCondenseContext: false,
|
||||
marketplace: false,
|
||||
}
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(true)
|
||||
})
|
||||
|
|
@ -40,6 +42,7 @@ describe("experiments", () => {
|
|||
const experiments: Record<ExperimentId, boolean> = {
|
||||
powerSteering: false,
|
||||
autoCondenseContext: false,
|
||||
marketplace: false,
|
||||
}
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false)
|
||||
})
|
||||
|
|
@ -48,6 +51,7 @@ describe("experiments", () => {
|
|||
const experiments: Record<ExperimentId, boolean> = {
|
||||
powerSteering: false,
|
||||
autoCondenseContext: false,
|
||||
marketplace: false,
|
||||
}
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.AUTO_CONDENSE_CONTEXT)).toBe(false)
|
||||
})
|
||||
|
|
@ -56,8 +60,46 @@ describe("experiments", () => {
|
|||
const experiments: Record<ExperimentId, boolean> = {
|
||||
powerSteering: false,
|
||||
autoCondenseContext: true,
|
||||
marketplace: false,
|
||||
}
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.AUTO_CONDENSE_CONTEXT)).toBe(true)
|
||||
})
|
||||
})
|
||||
describe("MARKETPLACE", () => {
|
||||
it("is configured correctly", () => {
|
||||
expect(EXPERIMENT_IDS.MARKETPLACE).toBe("marketplace")
|
||||
expect(experimentConfigsMap.MARKETPLACE).toMatchObject({
|
||||
enabled: false,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("isEnabled for MARKETPLACE", () => {
|
||||
it("returns false when MARKETPLACE experiment is not enabled", () => {
|
||||
const experiments: Record<ExperimentId, boolean> = {
|
||||
powerSteering: false,
|
||||
autoCondenseContext: false,
|
||||
marketplace: false,
|
||||
}
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.MARKETPLACE)).toBe(false)
|
||||
})
|
||||
|
||||
it("returns true when MARKETPLACE experiment is enabled", () => {
|
||||
const experiments: Record<ExperimentId, boolean> = {
|
||||
powerSteering: false,
|
||||
autoCondenseContext: false,
|
||||
marketplace: true,
|
||||
}
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.MARKETPLACE)).toBe(true)
|
||||
})
|
||||
|
||||
it("returns false when MARKETPLACE experiment is not present", () => {
|
||||
const experiments: Record<ExperimentId, boolean> = {
|
||||
powerSteering: false,
|
||||
autoCondenseContext: false,
|
||||
// marketplace missing
|
||||
} as any
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.MARKETPLACE)).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ export type { ExperimentId }
|
|||
|
||||
export const EXPERIMENT_IDS = {
|
||||
POWER_STEERING: "powerSteering",
|
||||
MARKETPLACE: "marketplace",
|
||||
AUTO_CONDENSE_CONTEXT: "autoCondenseContext",
|
||||
} as const satisfies Record<string, ExperimentId>
|
||||
|
||||
|
|
@ -18,6 +19,7 @@ interface ExperimentConfig {
|
|||
|
||||
export const experimentConfigsMap: Record<ExperimentKey, ExperimentConfig> = {
|
||||
POWER_STEERING: { enabled: false },
|
||||
MARKETPLACE: { enabled: false },
|
||||
AUTO_CONDENSE_CONTEXT: { enabled: false }, // Keep this last, there is a slider below it in the UI
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { useEvent } from "react-use"
|
|||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
|
||||
|
||||
import { ExtensionMessage } from "@roo/shared/ExtensionMessage"
|
||||
import TranslationProvider from "./i18n/TranslationContext"
|
||||
import TranslationProvider, { useAppTranslation } from "./i18n/TranslationContext"
|
||||
import { MarketplaceViewStateManager } from "./components/marketplace/MarketplaceViewStateManager"
|
||||
|
||||
import { vscode } from "./utils/vscode"
|
||||
|
|
@ -30,8 +30,16 @@ const tabsByMessageAction: Partial<Record<NonNullable<ExtensionMessage["action"]
|
|||
}
|
||||
|
||||
const App = () => {
|
||||
const { didHydrateState, showWelcome, shouldShowAnnouncement, telemetrySetting, telemetryKey, machineId } =
|
||||
useExtensionState()
|
||||
const {
|
||||
didHydrateState,
|
||||
showWelcome,
|
||||
shouldShowAnnouncement,
|
||||
telemetrySetting,
|
||||
telemetryKey,
|
||||
machineId,
|
||||
experiments,
|
||||
} = useExtensionState()
|
||||
const { t } = useAppTranslation()
|
||||
|
||||
// Create a persistent state manager
|
||||
const marketplaceStateManager = useMemo(() => new MarketplaceViewStateManager(), [])
|
||||
|
|
@ -124,9 +132,17 @@ const App = () => {
|
|||
{tab === "settings" && (
|
||||
<SettingsView ref={settingsRef} onDone={() => setTab("chat")} targetSection={currentSection} />
|
||||
)}
|
||||
{tab === "marketplace" && (
|
||||
<MarketplaceView stateManager={marketplaceStateManager} onDone={() => switchTab("chat")} />
|
||||
)}
|
||||
{tab === "marketplace" &&
|
||||
(experiments.marketplace ? (
|
||||
<MarketplaceView stateManager={marketplaceStateManager} onDone={() => switchTab("chat")} />
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center h-full p-8 text-center">
|
||||
<div className="text-lg font-semibold mb-2">{t("settings:experimental.MARKETPLACE.name")}</div>
|
||||
<div className="text-vscode-descriptionForeground mb-4">
|
||||
{t("settings:experimental.MARKETPLACE.warning")}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<ChatView
|
||||
ref={chatViewRef}
|
||||
isHidden={tab !== "chat"}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ export function MarketplaceListView({
|
|||
{t("marketplace:filters.type.mode")}
|
||||
</span>
|
||||
</SelectItem>
|
||||
<SelectItem value="mcp server">
|
||||
<SelectItem value="mcp">
|
||||
<span className="flex items-center gap-2">
|
||||
<Server className="h-4 w-4" />
|
||||
{t("marketplace:filters.type.mcp server")}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,15 @@ export function MarketplaceView({ stateManager, onDone }: MarketplaceViewProps)
|
|||
<RefreshCw className={cn("size-4", { "animate-spin": state.isFetching })} />
|
||||
{t("marketplace:refresh")}
|
||||
</Button>
|
||||
<Button variant="default" onClick={onDone}>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={() => {
|
||||
if (state.activeTab === "browse" || state.activeTab === "installed") {
|
||||
onDone?.()
|
||||
} else {
|
||||
manager.transition({ type: "SET_ACTIVE_TAB", payload: { tab: "browse" } })
|
||||
}
|
||||
}}>
|
||||
{t("marketplace:done")}
|
||||
</Button>
|
||||
</div>
|
||||
|
|
@ -145,8 +153,8 @@ export function MarketplaceView({ stateManager, onDone }: MarketplaceViewProps)
|
|||
<div
|
||||
className={cn("absolute w-full transition-all duration-300 ease-in-out", {
|
||||
"translate-x-0 opacity-100 z-10": state.activeTab === "browse",
|
||||
"translate-x-[-100%] opacity-0 z-0": state.activeTab === "installed",
|
||||
"translate-x-[-200%] opacity-0 z-0": state.activeTab === "settings",
|
||||
"translate-x-[-100%] opacity-0 invisible z-0": state.activeTab === "installed",
|
||||
"translate-x-[-200%] opacity-0 invisible z-0": state.activeTab === "settings",
|
||||
})}>
|
||||
<MarketplaceListView
|
||||
stateManager={stateManager}
|
||||
|
|
@ -157,9 +165,9 @@ export function MarketplaceView({ stateManager, onDone }: MarketplaceViewProps)
|
|||
|
||||
<div
|
||||
className={cn("absolute w-full transition-all duration-300 ease-in-out", {
|
||||
"translate-x-[100%] opacity-0 z-0": state.activeTab === "browse",
|
||||
"translate-x-[100%] opacity-0 invisible z-0": state.activeTab === "browse",
|
||||
"translate-x-0 opacity-100 z-10": state.activeTab === "installed",
|
||||
"translate-x-[-100%] opacity-0 z-0": state.activeTab === "settings",
|
||||
"translate-x-[-100%] opacity-0 invisible z-0": state.activeTab === "settings",
|
||||
})}>
|
||||
<MarketplaceListView
|
||||
stateManager={stateManager}
|
||||
|
|
@ -171,8 +179,8 @@ export function MarketplaceView({ stateManager, onDone }: MarketplaceViewProps)
|
|||
|
||||
<div
|
||||
className={cn("absolute w-full transition-all duration-300 ease-in-out", {
|
||||
"translate-x-[200%] opacity-0 z-0": state.activeTab === "browse",
|
||||
"translate-x-[100%] opacity-0 z-0": state.activeTab === "installed",
|
||||
"translate-x-[200%] opacity-0 invisible z-0": state.activeTab === "browse",
|
||||
"translate-x-[100%] opacity-0 invisible z-0": state.activeTab === "installed",
|
||||
"translate-x-0 opacity-100 z-10": state.activeTab === "settings",
|
||||
})}>
|
||||
<MarketplaceSourcesConfig stateManager={stateManager} />
|
||||
|
|
|
|||
|
|
@ -260,15 +260,17 @@ export class MarketplaceViewStateManager {
|
|||
}
|
||||
|
||||
case "FETCH_ERROR": {
|
||||
// Preserve current filters and sources
|
||||
const { filters, sources, activeTab } = this.state
|
||||
// Preserve current filters, sources, and items
|
||||
const { filters, sources, activeTab, allItems, displayItems } = this.state
|
||||
|
||||
// Reset state but preserve filters and sources
|
||||
// Reset state but preserve filters, sources, and items
|
||||
this.state = {
|
||||
...this.getDefaultState(),
|
||||
filters,
|
||||
sources,
|
||||
activeTab,
|
||||
allItems,
|
||||
displayItems,
|
||||
isFetching: false,
|
||||
}
|
||||
this.notifyStateChange()
|
||||
|
|
|
|||
|
|
@ -5,14 +5,12 @@ import { ViewState } from "../MarketplaceViewStateManager"
|
|||
import userEvent from "@testing-library/user-event"
|
||||
import { TooltipProvider } from "@/components/ui/tooltip"
|
||||
|
||||
// Mock translation hook
|
||||
jest.mock("@/i18n/TranslationContext", () => ({
|
||||
useAppTranslation: () => ({
|
||||
t: (key: string) => key, // Return the key as-is for easy testing
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}))
|
||||
|
||||
// Mock ResizeObserver
|
||||
class MockResizeObserver {
|
||||
observe() {}
|
||||
unobserve() {}
|
||||
|
|
@ -21,7 +19,6 @@ class MockResizeObserver {
|
|||
|
||||
global.ResizeObserver = MockResizeObserver
|
||||
|
||||
// Mock state manager with initial state
|
||||
const mockTransition = jest.fn()
|
||||
const mockState: ViewState = {
|
||||
allItems: [],
|
||||
|
|
@ -45,12 +42,10 @@ const mockState: ViewState = {
|
|||
},
|
||||
}
|
||||
|
||||
// Mock useStateManager hook
|
||||
jest.mock("../useStateManager", () => ({
|
||||
useStateManager: () => [mockState, { transition: mockTransition }],
|
||||
}))
|
||||
|
||||
// Mock all lucide-react icons
|
||||
jest.mock("lucide-react", () => {
|
||||
return new Proxy(
|
||||
{},
|
||||
|
|
|
|||
|
|
@ -3,14 +3,12 @@ import { MarketplaceSourcesConfig } from "../MarketplaceSourcesConfigView"
|
|||
import { MarketplaceViewStateManager } from "../MarketplaceViewStateManager"
|
||||
import { validateSource, ValidationError } from "@roo/shared/MarketplaceValidation"
|
||||
|
||||
// Mock the translation hook
|
||||
jest.mock("@/i18n/TranslationContext", () => ({
|
||||
useAppTranslation: () => ({
|
||||
t: (key: string) => key, // Return the key as-is for testing
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}))
|
||||
|
||||
// Mock the validateSource function
|
||||
jest.mock("@roo/shared/MarketplaceValidation", () => ({
|
||||
validateSource: jest.fn(),
|
||||
}))
|
||||
|
|
@ -20,13 +18,11 @@ describe("MarketplaceSourcesConfig", () => {
|
|||
|
||||
beforeEach(() => {
|
||||
stateManager = new MarketplaceViewStateManager()
|
||||
// Reset state manager to have no sources
|
||||
stateManager.transition({
|
||||
type: "UPDATE_SOURCES",
|
||||
payload: { sources: [] },
|
||||
})
|
||||
jest.clearAllMocks()
|
||||
// Default mock implementation for validateSource
|
||||
;(validateSource as jest.Mock).mockReturnValue([])
|
||||
})
|
||||
|
||||
|
|
@ -83,7 +79,6 @@ describe("MarketplaceSourcesConfig", () => {
|
|||
fireEvent.change(urlInput, { target: { value: "" } }) // Set URL to empty
|
||||
fireEvent.blur(urlInput) // Trigger blur to activate client-side validation
|
||||
|
||||
// This error is displayed as a field-specific error message
|
||||
const errorMessage = await screen.findByText("marketplace:sources.errors.emptyUrl", {
|
||||
selector: "p.text-xs.text-red-500",
|
||||
})
|
||||
|
|
@ -112,7 +107,6 @@ describe("MarketplaceSourcesConfig", () => {
|
|||
})
|
||||
|
||||
it("shows error when max sources reached", async () => {
|
||||
// Add max number of sources with unique URLs
|
||||
const maxSources = Array(10)
|
||||
.fill(null)
|
||||
.map((_, i) => ({
|
||||
|
|
@ -233,7 +227,6 @@ describe("MarketplaceSourcesConfig", () => {
|
|||
const longName = "This is a very long source name that exceeds limit"
|
||||
fireEvent.change(nameInput, { target: { value: longName } })
|
||||
|
||||
// The component should truncate to 20 chars
|
||||
expect(nameInput).toHaveValue(longName.slice(0, 20))
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -7,25 +7,22 @@ import { TooltipProvider } from "@/components/ui/tooltip"
|
|||
import type { RocketConfig } from "config-rocket"
|
||||
import { ExtensionStateContext } from "@/context/ExtensionStateContext"
|
||||
|
||||
// Mock vscode API - IMPORTANT: This mock must be at the very top of the file
|
||||
const mockPostMessage = jest.fn()
|
||||
jest.mock("@src/utils/vscode", () => ({
|
||||
vscode: {
|
||||
postMessage: mockPostMessage,
|
||||
getState: jest.fn(() => ({})), // Mock getState as well if it's used
|
||||
getState: jest.fn(() => ({})),
|
||||
setState: jest.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
// Mock translation hook
|
||||
jest.mock("@/i18n/TranslationContext", () => ({
|
||||
useAppTranslation: () => ({
|
||||
t: (key: string) => key, // Return the key as-is for easy testing
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}))
|
||||
|
||||
// Mock useEvent from react-use
|
||||
let mockUseEventHandler: ((event: MessageEvent) => void) | undefined // Declare outside mock
|
||||
let mockUseEventHandler: ((event: MessageEvent) => void) | undefined
|
||||
jest.mock("react-use", () => ({
|
||||
useEvent: jest.fn((eventName, handler) => {
|
||||
if (eventName === "message") {
|
||||
|
|
@ -34,7 +31,6 @@ jest.mock("react-use", () => ({
|
|||
}),
|
||||
}))
|
||||
|
||||
// Mock ResizeObserver
|
||||
class MockResizeObserver {
|
||||
observe() {}
|
||||
unobserve() {}
|
||||
|
|
@ -237,6 +233,7 @@ describe("MarketplaceView", () => {
|
|||
experiments: {
|
||||
autoCondenseContext: false,
|
||||
powerSteering: false,
|
||||
marketplace: true,
|
||||
},
|
||||
marketplaceSources: [],
|
||||
}}>
|
||||
|
|
@ -254,7 +251,7 @@ describe("MarketplaceView", () => {
|
|||
expect(screen.getByText("marketplace:done")).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("calls onDone when Done button is clicked", async () => {
|
||||
it("calls onDone when Done button is clicked and active tab is browse or installed", async () => {
|
||||
const user = userEvent.setup()
|
||||
const onDoneMock = jest.fn()
|
||||
renderWithProviders({ onDone: onDoneMock })
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ describe("MarketplaceViewStateManager", () => {
|
|||
})
|
||||
|
||||
describe("Initial State", () => {
|
||||
it.skip("should initialize with default state", () => {
|
||||
it("should initialize with default state", () => {
|
||||
const state = manager.getState()
|
||||
expect(state).toEqual({
|
||||
allItems: [],
|
||||
|
|
@ -55,6 +55,10 @@ describe("MarketplaceViewStateManager", () => {
|
|||
activeTab: "browse",
|
||||
refreshingUrls: [],
|
||||
sources: [DEFAULT_MARKETPLACE_SOURCE],
|
||||
installedMetadata: {
|
||||
project: {},
|
||||
global: {},
|
||||
},
|
||||
filters: {
|
||||
type: "",
|
||||
search: "",
|
||||
|
|
@ -103,13 +107,12 @@ describe("MarketplaceViewStateManager", () => {
|
|||
})
|
||||
|
||||
describe("Fetch Transitions", () => {
|
||||
it.skip("should handle FETCH_ITEMS transition", async () => {
|
||||
it("should handle FETCH_ITEMS transition", async () => {
|
||||
jest.clearAllMocks() // Clear mock to ignore initialize() call
|
||||
await manager.transition({ type: "FETCH_ITEMS" })
|
||||
|
||||
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||
type: "fetchMarketplaceItems",
|
||||
bool: true,
|
||||
})
|
||||
|
||||
const state = manager.getState()
|
||||
|
|
@ -398,11 +401,12 @@ describe("MarketplaceViewStateManager", () => {
|
|||
})
|
||||
|
||||
describe("Error Handling", () => {
|
||||
it.skip("should handle fetch timeout", async () => {
|
||||
it("should handle fetch timeout", async () => {
|
||||
await manager.transition({ type: "FETCH_ITEMS" })
|
||||
|
||||
// Fast-forward past the timeout
|
||||
// Fast-forward past the timeout and simulate error message
|
||||
jest.advanceTimersByTime(30000)
|
||||
manager.handleMessage({ type: "marketplaceButtonClicked", text: "error" })
|
||||
|
||||
const state = manager.getState()
|
||||
expect(state.isFetching).toBe(false)
|
||||
|
|
@ -583,7 +587,7 @@ describe("MarketplaceViewStateManager", () => {
|
|||
expect(state.isFetching).toBe(false)
|
||||
})
|
||||
|
||||
it.skip("should handle marketplace button click for refresh", () => {
|
||||
it("should handle marketplace button click for refresh", () => {
|
||||
manager.handleMessage({
|
||||
type: "marketplaceButtonClicked",
|
||||
})
|
||||
|
|
@ -592,7 +596,6 @@ describe("MarketplaceViewStateManager", () => {
|
|||
expect(state.isFetching).toBe(true)
|
||||
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||
type: "fetchMarketplaceItems",
|
||||
bool: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -608,7 +611,7 @@ describe("MarketplaceViewStateManager", () => {
|
|||
expect(state.activeTab).toBe("settings")
|
||||
})
|
||||
|
||||
it.skip("should trigger initial fetch when switching to browse with no items", async () => {
|
||||
it("should trigger initial fetch when switching to browse with no items", async () => {
|
||||
jest.clearAllMocks() // Clear mock to ignore initialize() call
|
||||
|
||||
// Start in settings tab
|
||||
|
|
@ -625,7 +628,6 @@ describe("MarketplaceViewStateManager", () => {
|
|||
|
||||
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||
type: "fetchMarketplaceItems",
|
||||
bool: true,
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -656,7 +658,7 @@ describe("MarketplaceViewStateManager", () => {
|
|||
})
|
||||
})
|
||||
|
||||
it.skip("should automatically fetch when sources are modified and viewing browse tab", async () => {
|
||||
it("should automatically fetch when sources are modified and viewing browse tab", async () => {
|
||||
jest.clearAllMocks() // Clear mock to ignore initialize() call
|
||||
|
||||
// Add some items first
|
||||
|
|
@ -680,7 +682,6 @@ describe("MarketplaceViewStateManager", () => {
|
|||
// Should trigger fetch due to source modification
|
||||
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||
type: "fetchMarketplaceItems",
|
||||
bool: true,
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -698,11 +699,12 @@ describe("MarketplaceViewStateManager", () => {
|
|||
})
|
||||
|
||||
describe("Fetch Timeout Handling", () => {
|
||||
it.skip("should handle fetch timeout", async () => {
|
||||
it("should handle fetch timeout", async () => {
|
||||
await manager.transition({ type: "FETCH_ITEMS" })
|
||||
|
||||
// Fast-forward past the timeout
|
||||
// Fast-forward past the timeout and simulate error message
|
||||
jest.advanceTimersByTime(30000)
|
||||
manager.handleMessage({ type: "marketplaceButtonClicked", text: "error" })
|
||||
|
||||
const state = manager.getState()
|
||||
expect(state.isFetching).toBe(false)
|
||||
|
|
@ -756,7 +758,7 @@ describe("MarketplaceViewStateManager", () => {
|
|||
expect(state.activeTab).toBe("settings")
|
||||
})
|
||||
|
||||
it.skip("should make minimal state updates when timeout occurs in browse tab", async () => {
|
||||
it("should make minimal state updates when timeout occurs in browse tab", async () => {
|
||||
// First ensure we're in browse tab
|
||||
await manager.transition({
|
||||
type: "SET_ACTIVE_TAB",
|
||||
|
|
@ -770,26 +772,24 @@ describe("MarketplaceViewStateManager", () => {
|
|||
payload: { items: testItems },
|
||||
})
|
||||
|
||||
// Start a new fetch
|
||||
await manager.transition({ type: "FETCH_ITEMS" })
|
||||
|
||||
// Track state changes
|
||||
let stateChangeCount = 0
|
||||
const unsubscribe = manager.onStateChange(() => {
|
||||
stateChangeCount++
|
||||
})
|
||||
|
||||
// Reset the counter since we've already had state changes
|
||||
stateChangeCount = 0
|
||||
// Start a new fetch
|
||||
await manager.transition({ type: "FETCH_ITEMS" })
|
||||
|
||||
// Fast-forward past the timeout
|
||||
// Fast-forward past the timeout and simulate error message
|
||||
jest.advanceTimersByTime(30000)
|
||||
manager.handleMessage({ type: "marketplaceButtonClicked", text: "error" })
|
||||
|
||||
// Clean up the handler
|
||||
unsubscribe()
|
||||
|
||||
// Verify we got a state update
|
||||
expect(stateChangeCount).toBe(1)
|
||||
// Verify we got a state update (one for FETCH_ITEMS, one for FETCH_ERROR)
|
||||
expect(stateChangeCount).toBe(2)
|
||||
|
||||
// Verify the items were preserved
|
||||
const state = manager.getState()
|
||||
|
|
@ -825,7 +825,7 @@ describe("MarketplaceViewStateManager", () => {
|
|||
jest.useRealTimers()
|
||||
})
|
||||
|
||||
it.skip("should trigger fetch for remaining source after source deletion when in browse tab", async () => {
|
||||
it("should trigger fetch for remaining source after source deletion when in browse tab", async () => {
|
||||
// Start with two sources
|
||||
const sources = [
|
||||
{ url: "https://github.com/test/repo1", enabled: true },
|
||||
|
|
@ -855,7 +855,6 @@ describe("MarketplaceViewStateManager", () => {
|
|||
// Verify that a fetch was triggered for the remaining source
|
||||
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||
type: "fetchMarketplaceItems",
|
||||
bool: true,
|
||||
})
|
||||
|
||||
// Verify state has the remaining source
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { cn } from "@/lib/utils"
|
|||
import { Button } from "@/components/ui/button"
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
|
||||
import { Rocket, Server, Package, Sparkles, ChevronDown } from "lucide-react"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
|
||||
interface MarketplaceItemCardProps {
|
||||
item: MarketplaceItem
|
||||
|
|
@ -42,6 +43,7 @@ export const MarketplaceItemCard: React.FC<MarketplaceItemCardProps> = ({
|
|||
setActiveTab,
|
||||
}) => {
|
||||
const { t } = useAppTranslation()
|
||||
const { cwd } = useExtensionState()
|
||||
|
||||
const typeLabel = useMemo(() => {
|
||||
const labels: Partial<Record<MarketplaceItem["type"], string>> = {
|
||||
|
|
@ -137,28 +139,35 @@ export const MarketplaceItemCard: React.FC<MarketplaceItemCardProps> = ({
|
|||
<div className="flex items-center">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="default"
|
||||
className="text-xs h-5 rounded-r-none py-0 px-2"
|
||||
onClick={() =>
|
||||
vscode.postMessage({
|
||||
type: installed.project
|
||||
? "removeInstalledMarketplaceItem"
|
||||
: "installMarketplaceItem",
|
||||
mpItem: item,
|
||||
mpInstallOptions: { target: "project" },
|
||||
})
|
||||
}>
|
||||
{installed.project
|
||||
? t("marketplace:items.card.removeProject")
|
||||
: t("marketplace:items.card.installProject")}
|
||||
</Button>
|
||||
<span className="inline-block">
|
||||
<Button
|
||||
size="sm"
|
||||
variant={installed.project ? "secondary" : "default"}
|
||||
className="text-xs h-5 rounded-r-none py-0 px-2"
|
||||
disabled={!cwd}
|
||||
onClick={() => {
|
||||
if (cwd) {
|
||||
vscode.postMessage({
|
||||
type: installed.project
|
||||
? "removeInstalledMarketplaceItem"
|
||||
: "installMarketplaceItem",
|
||||
mpItem: item,
|
||||
mpInstallOptions: { target: "project" },
|
||||
})
|
||||
}
|
||||
}}>
|
||||
{installed.project
|
||||
? t("marketplace:items.card.removeProject")
|
||||
: t("marketplace:items.card.installProject")}
|
||||
</Button>
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{installed.project
|
||||
? t("marketplace:items.card.removeProject")
|
||||
: t("marketplace:items.card.installProject")}
|
||||
{!cwd
|
||||
? t("marketplace:items.card.noWorkspaceTooltip")
|
||||
: installed.project
|
||||
? t("marketplace:items.card.removeProject")
|
||||
: t("marketplace:items.card.installProject")}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<MarketplaceItemActionsMenu
|
||||
|
|
@ -167,7 +176,7 @@ export const MarketplaceItemCard: React.FC<MarketplaceItemCardProps> = ({
|
|||
triggerNode={
|
||||
<Button
|
||||
size="sm"
|
||||
variant="default"
|
||||
variant={installed.project ? "secondary" : "default"}
|
||||
className="h-5 px-1 py-0 rounded-l-none border-l border-l-white/10">
|
||||
<ChevronDown className="size-3" />
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -310,6 +310,25 @@ describe("MarketplaceItemCard", () => {
|
|||
})
|
||||
})
|
||||
|
||||
it("disables install button and shows tooltip when no workspace is open", async () => {
|
||||
// Mock useExtensionState to simulate no workspace
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
jest.spyOn(require("@/context/ExtensionStateContext"), "useExtensionState").mockReturnValue({
|
||||
filePaths: [],
|
||||
} as any)
|
||||
|
||||
const user = userEvent.setup()
|
||||
renderWithProviders(<MarketplaceItemCard {...defaultProps} />)
|
||||
|
||||
const installButton = screen.getByRole("button", { name: "Install Project" })
|
||||
expect(installButton).toBeDisabled()
|
||||
|
||||
// Hover to trigger tooltip
|
||||
await user.hover(installButton)
|
||||
const tooltip = await screen.findByText("Open a workspace to install marketplace items")
|
||||
expect(tooltip).toBeInTheDocument()
|
||||
})
|
||||
|
||||
describe("MarketplaceItemCard expandable section badge", () => {
|
||||
it("shows badge count for matched sub-items", () => {
|
||||
const packageItem: MarketplaceItem = {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "Eliminar",
|
||||
"removeGlobal": "Eliminar (Global)",
|
||||
"viewSource": "Veure",
|
||||
"viewOnSource": "Veure a {{source}}"
|
||||
"viewOnSource": "Veure a {{source}}",
|
||||
"noWorkspaceTooltip": "Obre un espai de treball per instal·lar elements del marketplace"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "Instal·lació del projecte",
|
||||
|
|
|
|||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "Utilitzar eina diff de blocs múltiples experimental",
|
||||
"description": "Quan està activat, Roo utilitzarà l'eina diff de blocs múltiples. Això intentarà actualitzar múltiples blocs de codi a l'arxiu en una sola petició."
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Habilitar Marketplace a Roo Code",
|
||||
"description": "Quan està habilitat, Roo podrà instal·lar i gestionar elements del Marketplace.",
|
||||
"warning": "El Marketplace encara no està habilitat. Si voleu ser un dels primers a adoptar-lo, activeu-lo a la configuració experimental."
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "Entfernen",
|
||||
"removeGlobal": "Entfernen (Global)",
|
||||
"viewSource": "Ansehen",
|
||||
"viewOnSource": "Auf {{source}} ansehen"
|
||||
"viewOnSource": "Auf {{source}} ansehen",
|
||||
"noWorkspaceTooltip": "Öffne einen Arbeitsbereich, um Marketplace-Elemente zu installieren"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "Projektinstallation",
|
||||
|
|
|
|||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "Experimentelles Multi-Block-Diff-Werkzeug verwenden",
|
||||
"description": "Wenn aktiviert, verwendet Roo das Multi-Block-Diff-Werkzeug. Dies versucht, mehrere Codeblöcke in der Datei in einer Anfrage zu aktualisieren."
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Marktplatz in Roo Code aktivieren",
|
||||
"description": "Wenn aktiviert, kann Roo Elemente vom Marktplatz installieren und verwalten.",
|
||||
"warning": "Der Marktplatz ist noch nicht aktiviert. Wenn du ein Early Adopter sein möchtest, aktiviere ihn bitte in den Experimentellen Einstellungen."
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,8 @@
|
|||
"removeProject": "Remove",
|
||||
"removeGlobal": "Remove (Global)",
|
||||
"viewSource": "View",
|
||||
"viewOnSource": "View on {{source}}"
|
||||
"viewOnSource": "View on {{source}}",
|
||||
"noWorkspaceTooltip": "Open a workspace to install marketplace items"
|
||||
}
|
||||
},
|
||||
"sources": {
|
||||
|
|
|
|||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "Use experimental multi block diff tool",
|
||||
"description": "When enabled, Roo will use multi block diff tool. This will try to update multiple code blocks in the file in one request."
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Enable Marketplace in Roo Code",
|
||||
"description": "When enabled, Roo will be able to install and manage items from the Marketplace.",
|
||||
"warning": "The Marketplace is not yet enabled. If you want to be an early adopter, please enable it in the Experimental Settings."
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "Eliminar",
|
||||
"removeGlobal": "Eliminar (Global)",
|
||||
"viewSource": "Ver",
|
||||
"viewOnSource": "Ver en {{source}}"
|
||||
"viewOnSource": "Ver en {{source}}",
|
||||
"noWorkspaceTooltip": "Abre un espacio de trabajo para instalar elementos del marketplace"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "Instalación del proyecto",
|
||||
|
|
|
|||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "Usar herramienta experimental de diff de bloques múltiples",
|
||||
"description": "Cuando está habilitado, Roo usará la herramienta de diff de bloques múltiples. Esto intentará actualizar múltiples bloques de código en el archivo en una sola solicitud."
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Habilitar Marketplace en Roo Code",
|
||||
"description": "Cuando está habilitado, Roo podrá instalar y administrar elementos del Marketplace.",
|
||||
"warning": "El Marketplace aún no está habilitado. Si desea ser un adoptador temprano, habilítelo en la Configuración experimental."
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "Supprimer",
|
||||
"removeGlobal": "Supprimer (Global)",
|
||||
"viewSource": "Voir",
|
||||
"viewOnSource": "Voir sur {{source}}"
|
||||
"viewOnSource": "Voir sur {{source}}",
|
||||
"noWorkspaceTooltip": "Ouvrez un espace de travail pour installer les éléments du marketplace"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "Installation du projet",
|
||||
|
|
|
|||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "Utiliser l'outil diff multi-blocs expérimental",
|
||||
"description": "Lorsqu'il est activé, Roo utilisera l'outil diff multi-blocs. Cela tentera de mettre à jour plusieurs blocs de code dans le fichier en une seule requête."
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Activer le Marketplace dans Roo Code",
|
||||
"description": "Lorsqu'il est activé, Roo pourra installer et gérer des éléments du Marketplace.",
|
||||
"warning": "Le Marketplace n'est pas encore activé. Si vous souhaitez être un adopteur précoce, veuillez l'activer dans les paramètres expérimentaux."
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "हटाएं",
|
||||
"removeGlobal": "हटाएं (ग्लोबल)",
|
||||
"viewSource": "देखें",
|
||||
"viewOnSource": "{{source}} पर देखें"
|
||||
"viewOnSource": "{{source}} पर देखें",
|
||||
"noWorkspaceTooltip": "मार्केटप्लेस आइटम इंस्टॉल करने के लिए एक कार्यक्षेत्र खोलें"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "परियोजना स्थापना",
|
||||
|
|
|
|||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "प्रायोगिक मल्टी ब्लॉक diff उपकरण का उपयोग करें",
|
||||
"description": "जब सक्षम किया जाता है, तो Roo मल्टी ब्लॉक diff उपकरण का उपयोग करेगा। यह एक अनुरोध में फ़ाइल में कई कोड ब्लॉक अपडेट करने का प्रयास करेगा।"
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Roo Code में मार्केटप्लेस सक्षम करें",
|
||||
"description": "जब सक्षम होता है, तो Roo मार्केटप्लेस से आइटम स्थापित और प्रबंधित करने में सक्षम होगा।",
|
||||
"warning": "मार्केटप्लेस अभी तक सक्षम नहीं है। यदि आप शुरुआती अपनाने वाले बनना चाहते हैं, तो कृपया इसे प्रायोगिक सेटिंग्स में सक्षम करें।"
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "Rimuovi",
|
||||
"removeGlobal": "Rimuovi (Globale)",
|
||||
"viewSource": "Visualizza",
|
||||
"viewOnSource": "Visualizza su {{source}}"
|
||||
"viewOnSource": "Visualizza su {{source}}",
|
||||
"noWorkspaceTooltip": "Apri un'area di lavoro per installare gli elementi del marketplace"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "Installazione del progetto",
|
||||
|
|
|
|||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "Usa strumento diff multi-blocco sperimentale",
|
||||
"description": "Quando abilitato, Roo utilizzerà lo strumento diff multi-blocco. Questo tenterà di aggiornare più blocchi di codice nel file in una singola richiesta."
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Abilita Marketplace in Roo Code",
|
||||
"description": "Quando abilitato, Roo sarà in grado di installare e gestire elementi dal Marketplace.",
|
||||
"warning": "Il Marketplace non è ancora abilitato. Se vuoi essere un early adopter, abilitalo nelle Impostazioni sperimentali."
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "削除",
|
||||
"removeGlobal": "削除 (グローバル)",
|
||||
"viewSource": "表示",
|
||||
"viewOnSource": "{{source}}で表示"
|
||||
"viewOnSource": "{{source}}で表示",
|
||||
"noWorkspaceTooltip": "マーケットプレイスアイテムをインストールするには、ワークスペースを開いてください"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "プロジェクトのインストール",
|
||||
|
|
|
|||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "実験的なマルチブロックdiffツールを使用する",
|
||||
"description": "有効にすると、Rooはマルチブロックdiffツールを使用します。これにより、1つのリクエストでファイル内の複数のコードブロックを更新しようとします。"
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Roo Codeでマーケットプレイスを有効にする",
|
||||
"description": "有効にすると、Rooはマーケットプレイスからアイテムをインストールおよび管理できるようになります。",
|
||||
"warning": "マーケットプレイスはまだ有効になっていません。早期導入者になりたい場合は、実験的設定で有効にしてください。"
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "제거",
|
||||
"removeGlobal": "제거 (글로벌)",
|
||||
"viewSource": "보기",
|
||||
"viewOnSource": "{{source}}에서 보기"
|
||||
"viewOnSource": "{{source}}에서 보기",
|
||||
"noWorkspaceTooltip": "마켓플레이스 항목을 설치하려면 작업 영역을 여세요"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "프로젝트 설치",
|
||||
|
|
|
|||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "실험적 다중 블록 diff 도구 사용",
|
||||
"description": "활성화하면 Roo가 다중 블록 diff 도구를 사용합니다. 이것은 하나의 요청에서 파일의 여러 코드 블록을 업데이트하려고 시도합니다."
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Roo Code에서 마켓플레이스 활성화",
|
||||
"description": "활성화하면 Roo는 마켓플레이스에서 항목을 설치하고 관리할 수 있습니다.",
|
||||
"warning": "마켓플레이스는 아직 활성화되지 않았습니다. 얼리 어답터가 되려면 실험적 설정에서 활성화하세요."
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "Verwijderen",
|
||||
"removeGlobal": "Verwijderen (Globaal)",
|
||||
"viewSource": "Bekijken",
|
||||
"viewOnSource": "Bekijken op {{source}}"
|
||||
"viewOnSource": "Bekijken op {{source}}",
|
||||
"noWorkspaceTooltip": "Open een werkruimte om marketplace-items te installeren"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "Projectinstallatie",
|
||||
|
|
|
|||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "Experimentele multi-block diff-tool gebruiken",
|
||||
"description": "Indien ingeschakeld, gebruikt Roo de multi-block diff-tool. Hiermee wordt geprobeerd meerdere codeblokken in het bestand in één verzoek bij te werken."
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Marktplaats in Roo Code inschakelen",
|
||||
"description": "Indien ingeschakeld, kan Roo items van de Marktplaats installeren en beheren.",
|
||||
"warning": "De Marktplaats is nog niet ingeschakeld. Als je een vroege gebruiker wilt zijn, schakel deze dan in de Experimentele instellingen in."
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "Usuń",
|
||||
"removeGlobal": "Usuń (Globalny)",
|
||||
"viewSource": "Zobacz",
|
||||
"viewOnSource": "Zobacz na {{source}}"
|
||||
"viewOnSource": "Zobacz na {{source}}",
|
||||
"noWorkspaceTooltip": "Otwórz obszar roboczy, aby zainstalować elementy Marketplace"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "Instalacja projektu",
|
||||
|
|
|
|||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "Użyj eksperymentalnego narzędzia diff wieloblokowego",
|
||||
"description": "Po włączeniu, Roo użyje narzędzia diff wieloblokowego. Spróbuje to zaktualizować wiele bloków kodu w pliku w jednym żądaniu."
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Włącz Marketplace w Roo Code",
|
||||
"description": "Po włączeniu, Roo będzie w stanie instalować i zarządzać elementami z Marketplace.",
|
||||
"warning": "Marketplace nie jest jeszcze włączony. Jeśli chcesz być wczesnym użytkownikiem, włącz go w Ustawieniach eksperymentalnych."
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "Remover",
|
||||
"removeGlobal": "Remover (Global)",
|
||||
"viewSource": "Ver",
|
||||
"viewOnSource": "Ver no {{source}}"
|
||||
"viewOnSource": "Ver no {{source}}",
|
||||
"noWorkspaceTooltip": "Abra um espaço de trabalho para instalar itens do marketplace"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "Instalação do projeto",
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
"terminal": "Terminal",
|
||||
"experimental": "Experimental",
|
||||
"language": "Idioma",
|
||||
"about": "Sobre"
|
||||
"about": "Sobre Roo Code"
|
||||
},
|
||||
"autoApprove": {
|
||||
"description": "Permitir que o Roo realize operações automaticamente sem exigir aprovação. Ative essas configurações apenas se confiar totalmente na IA e compreender os riscos de segurança associados.",
|
||||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "Usar ferramenta diff de múltiplos blocos experimental",
|
||||
"description": "Quando ativado, o Roo usará a ferramenta diff de múltiplos blocos. Isso tentará atualizar vários blocos de código no arquivo em uma única solicitação."
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Ativar Marketplace no Roo Code",
|
||||
"description": "Quando ativado, o Roo poderá instalar e gerenciar itens do Marketplace.",
|
||||
"warning": "O Marketplace ainda não está ativado. Se você quiser ser um adotante inicial, ative-o nas Configurações experimentais."
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "Удалить",
|
||||
"removeGlobal": "Удалить (Глобально)",
|
||||
"viewSource": "Просмотреть",
|
||||
"viewOnSource": "Просмотреть на {{source}}"
|
||||
"viewOnSource": "Просмотреть на {{source}}",
|
||||
"noWorkspaceTooltip": "Откройте рабочую область для установки элементов marketplace"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "Установка проекта",
|
||||
|
|
|
|||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "Использовать экспериментальный мультиблочный инструмент диффа",
|
||||
"description": "Если включено, Roo будет использовать мультиблочный инструмент диффа, пытаясь обновить несколько блоков кода за один запрос."
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Включить Marketplace в Roo Code",
|
||||
"description": "Если включено, Roo сможет устанавливать элементы из Marketplace и управлять ими.",
|
||||
"warning": "Marketplace ещё не включён. Если вы хотите стать ранним пользователем, включите его в экспериментальных настройках."
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "Kaldır",
|
||||
"removeGlobal": "Kaldır (Global)",
|
||||
"viewSource": "Görüntüle",
|
||||
"viewOnSource": "{{source}} üzerinde görüntüle"
|
||||
"viewOnSource": "{{source}} üzerinde görüntüle",
|
||||
"noWorkspaceTooltip": "Marketplace öğelerini yüklemek için bir çalışma alanı açın"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "Proje kurulumu",
|
||||
|
|
|
|||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "Deneysel çoklu blok diff aracını kullan",
|
||||
"description": "Etkinleştirildiğinde, Roo çoklu blok diff aracını kullanacaktır. Bu, tek bir istekte dosyadaki birden fazla kod bloğunu güncellemeye çalışacaktır."
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Roo Code'da Pazaryeri'ni etkinleştir",
|
||||
"description": "Etkinleştirildiğinde, Roo Pazaryeri'nden öğeleri yükleyebilir ve yönetebilir.",
|
||||
"warning": "Pazaryeri henüz etkinleştirilmedi. Erken benimseyen olmak istiyorsanız, lütfen Deneysel Ayarlar'da etkinleştirin."
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "Gỡ cài đặt",
|
||||
"removeGlobal": "Gỡ cài đặt (Toàn cục)",
|
||||
"viewSource": "Xem",
|
||||
"viewOnSource": "Xem trên {{source}}"
|
||||
"viewOnSource": "Xem trên {{source}}",
|
||||
"noWorkspaceTooltip": "Mở một không gian làm việc để cài đặt các mục marketplace"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "Cài đặt dự án",
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
"terminal": "Terminal",
|
||||
"experimental": "Thử nghiệm",
|
||||
"language": "Ngôn ngữ",
|
||||
"about": "Giới thiệu"
|
||||
"about": "Giới thiệu Roo Code"
|
||||
},
|
||||
"autoApprove": {
|
||||
"description": "Cho phép Roo tự động thực hiện các hoạt động mà không cần phê duyệt. Chỉ bật những cài đặt này nếu bạn hoàn toàn tin tưởng AI và hiểu rõ các rủi ro bảo mật liên quan.",
|
||||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "Sử dụng công cụ diff đa khối thử nghiệm",
|
||||
"description": "Khi được bật, Roo sẽ sử dụng công cụ diff đa khối. Điều này sẽ cố gắng cập nhật nhiều khối mã trong tệp trong một yêu cầu."
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "Bật Marketplace trong Roo Code",
|
||||
"description": "Khi được bật, Roo sẽ có thể cài đặt và quản lý các mục từ Marketplace.",
|
||||
"warning": "Marketplace chưa được bật. Nếu bạn muốn trở thành người dùng sớm, vui lòng bật nó trong Cài đặt thử nghiệm."
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "移除(项目)",
|
||||
"removeGlobal": "移除(全局)",
|
||||
"viewSource": "查看",
|
||||
"viewOnSource": "在 {{source}} 上查看"
|
||||
"viewOnSource": "在 {{source}} 上查看",
|
||||
"noWorkspaceTooltip": "打开工作区以安装市场项目"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "项目安装",
|
||||
|
|
|
|||
|
|
@ -412,24 +412,29 @@
|
|||
"description": "智能上下文压缩使用 LLM 调用来总结过去的对话,在任务上下文窗口达到预设阈值时进行,而不是在上下文填满时丢弃旧消息。"
|
||||
},
|
||||
"DIFF_STRATEGY_UNIFIED": {
|
||||
"name": "启用diff更新工具",
|
||||
"description": "可减少因模型错误导致的重复尝试,但可能引发意外操作。启用前请确保理解风险并会仔细检查所有修改。"
|
||||
"name": "使用实验性统一差异更新策略",
|
||||
"description": "启用实验性统一差异更新策略。此策略可能会减少因模型错误导致的重试次数,但可能导致意外行为或不正确的编辑。仅在您理解风险并愿意仔细审查所有更改时才启用。"
|
||||
},
|
||||
"SEARCH_AND_REPLACE": {
|
||||
"name": "启用搜索和替换工具",
|
||||
"name": "使用实验性搜索和替换工具",
|
||||
"description": "启用实验性搜索和替换工具,允许 Roo 在一个请求中替换搜索词的多个实例。"
|
||||
},
|
||||
"INSERT_BLOCK": {
|
||||
"name": "启用插入内容工具",
|
||||
"description": "允许 Roo 在特定行号插入内容,无需处理差异。"
|
||||
"name": "使用实验性插入内容工具",
|
||||
"description": "启用实验性插入内容工具,允许 Roo 在特定行号插入内容,无需创建差异。"
|
||||
},
|
||||
"POWER_STEERING": {
|
||||
"name": "启用增强导向模式",
|
||||
"description": "开启后,Roo 将更频繁地向模型推送当前模式定义的详细信息,从而强化对角色设定和自定义指令的遵循力度。注意:此模式会提升每条消息的 token 消耗量。"
|
||||
"name": "使用实验性“增强导向”模式",
|
||||
"description": "启用后,Roo 将更频繁地提醒模型其当前模式定义的详细信息。这将导致更严格地遵守角色定义和自定义指令,但每条消息将使用更多 Token。"
|
||||
},
|
||||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "允许批量搜索和替换",
|
||||
"description": "启用后,Roo 将尝试在一个请求中进行批量搜索和替换。"
|
||||
"name": "使用实验性多块差异工具",
|
||||
"description": "启用后,Roo 将使用多块差异工具。这将尝试在一个请求中更新文件中的多个代码块。"
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "在 Roo Code 中启用应用商店",
|
||||
"description": "启用后,Roo 将能够从应用商店安装和管理项目。",
|
||||
"warning": "应用商店尚未启用。如果您想成为早期采用者,请在实验性设置中启用它。"
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
"removeProject": "移除",
|
||||
"removeGlobal": "移除 (全域)",
|
||||
"viewSource": "檢視",
|
||||
"viewOnSource": "在 {{source}} 上檢視"
|
||||
"viewOnSource": "在 {{source}} 上檢視",
|
||||
"noWorkspaceTooltip": "開啟工作區以安裝市集項目"
|
||||
}
|
||||
},
|
||||
"installProjectTooltip": "專案安裝",
|
||||
|
|
|
|||
|
|
@ -430,6 +430,11 @@
|
|||
"MULTI_SEARCH_AND_REPLACE": {
|
||||
"name": "使用實驗性多區塊差異比對工具",
|
||||
"description": "啟用後,Roo 將使用多區塊差異比對工具,嘗試在單一請求中更新檔案內的多個程式碼區塊。"
|
||||
},
|
||||
"MARKETPLACE": {
|
||||
"name": "在 Roo Code 中啟用 Marketplace",
|
||||
"description": "啟用後,Roo 將能夠從 Marketplace 安裝和管理項目。",
|
||||
"warning": "Marketplace 尚未啟用。如果您想成為早期採用者,請在實驗性設定中啟用它。"
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue