mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-11 22:51:26 +00:00
Turn on marketplace (#4788)
This commit is contained in:
parent
3e2aec2ca7
commit
7b5a1d987d
10 changed files with 43 additions and 202 deletions
|
|
@ -6,7 +6,7 @@ import type { Keys, Equals, AssertEqual } from "./type-fu.js"
|
|||
* ExperimentId
|
||||
*/
|
||||
|
||||
export const experimentIds = ["powerSteering", "disableCompletionCommand", "marketplace", "multiFileApplyDiff"] as const
|
||||
export const experimentIds = ["powerSteering", "disableCompletionCommand", "multiFileApplyDiff"] as const
|
||||
|
||||
export const experimentIdsSchema = z.enum(experimentIds)
|
||||
|
||||
|
|
@ -19,7 +19,6 @@ export type ExperimentId = z.infer<typeof experimentIdsSchema>
|
|||
export const experimentsSchema = z.object({
|
||||
powerSteering: z.boolean().optional(),
|
||||
disableCompletionCommand: z.boolean().optional(),
|
||||
marketplace: z.boolean().optional(),
|
||||
multiFileApplyDiff: z.boolean().optional(),
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -502,9 +502,6 @@ export class ClineProvider
|
|||
// If the extension is starting a new session, clear previous task state.
|
||||
await this.removeClineFromStack()
|
||||
|
||||
// Set initial VSCode context for experiments
|
||||
await this.updateVSCodeContext()
|
||||
|
||||
this.log("Webview view resolved")
|
||||
}
|
||||
|
||||
|
|
@ -1245,29 +1242,12 @@ export class ClineProvider
|
|||
const state = await this.getStateToPostToWebview()
|
||||
this.postMessageToWebview({ type: "state", state })
|
||||
|
||||
// Update VSCode context for experiments
|
||||
await this.updateVSCodeContext()
|
||||
|
||||
// Check MDM compliance and send user to account tab if not compliant
|
||||
if (!this.checkMdmCompliance()) {
|
||||
await this.postMessageToWebview({ type: "action", action: "accountButtonClicked" })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates VSCode context variables for experiments so they can be used in when clauses
|
||||
*/
|
||||
private async updateVSCodeContext() {
|
||||
const { experiments } = await this.getState()
|
||||
|
||||
// Set context for marketplace experiment
|
||||
await vscode.commands.executeCommand(
|
||||
"setContext",
|
||||
`${Package.name}.marketplaceEnabled`,
|
||||
experiments.marketplace ?? false,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is a file-based system prompt override for the given mode
|
||||
*/
|
||||
|
|
@ -1356,14 +1336,12 @@ export class ClineProvider
|
|||
const allowedCommands = vscode.workspace.getConfiguration(Package.name).get<string[]>("allowedCommands") || []
|
||||
const cwd = this.cwd
|
||||
|
||||
// Only fetch marketplace data if the feature is enabled
|
||||
// Fetch marketplace data
|
||||
let marketplaceItems: any[] = []
|
||||
let marketplaceInstalledMetadata: any = { project: {}, global: {} }
|
||||
|
||||
if (experiments.marketplace) {
|
||||
marketplaceItems = (await this.marketplaceManager.getCurrentItems()) || []
|
||||
marketplaceInstalledMetadata = await this.marketplaceManager.getInstallationMetadata()
|
||||
}
|
||||
marketplaceItems = (await this.marketplaceManager.getCurrentItems()) || []
|
||||
marketplaceInstalledMetadata = await this.marketplaceManager.getInstallationMetadata()
|
||||
|
||||
// Check if there's a system prompt override for the current mode
|
||||
const currentMode = mode ?? defaultModeSlug
|
||||
|
|
|
|||
|
|
@ -1465,13 +1465,6 @@ export const webviewMessageHandler = async (
|
|||
break
|
||||
}
|
||||
case "filterMarketplaceItems": {
|
||||
// Check if marketplace is enabled before making API calls
|
||||
const { experiments } = await provider.getState()
|
||||
if (!experiments.marketplace) {
|
||||
console.log("Marketplace: Feature disabled, skipping API call")
|
||||
break
|
||||
}
|
||||
|
||||
if (marketplaceManager && message.filters) {
|
||||
try {
|
||||
await marketplaceManager.updateWithFilteredItems({
|
||||
|
|
@ -1489,13 +1482,6 @@ export const webviewMessageHandler = async (
|
|||
}
|
||||
|
||||
case "installMarketplaceItem": {
|
||||
// Check if marketplace is enabled before installing
|
||||
const { experiments } = await provider.getState()
|
||||
if (!experiments.marketplace) {
|
||||
console.log("Marketplace: Feature disabled, skipping installation")
|
||||
break
|
||||
}
|
||||
|
||||
if (marketplaceManager && message.mpItem && message.mpInstallOptions) {
|
||||
try {
|
||||
const configFilePath = await marketplaceManager.installMarketplaceItem(
|
||||
|
|
@ -1525,13 +1511,6 @@ export const webviewMessageHandler = async (
|
|||
}
|
||||
|
||||
case "removeInstalledMarketplaceItem": {
|
||||
// Check if marketplace is enabled before removing
|
||||
const { experiments } = await provider.getState()
|
||||
if (!experiments.marketplace) {
|
||||
console.log("Marketplace: Feature disabled, skipping removal")
|
||||
break
|
||||
}
|
||||
|
||||
if (marketplaceManager && message.mpItem && message.mpInstallOptions) {
|
||||
try {
|
||||
await marketplaceManager.removeInstalledMarketplaceItem(message.mpItem, message.mpInstallOptions)
|
||||
|
|
@ -1544,13 +1523,6 @@ export const webviewMessageHandler = async (
|
|||
}
|
||||
|
||||
case "installMarketplaceItemWithParameters": {
|
||||
// Check if marketplace is enabled before installing with parameters
|
||||
const { experiments } = await provider.getState()
|
||||
if (!experiments.marketplace) {
|
||||
console.log("Marketplace: Feature disabled, skipping installation with parameters")
|
||||
break
|
||||
}
|
||||
|
||||
if (marketplaceManager && message.payload && "item" in message.payload && "parameters" in message.payload) {
|
||||
try {
|
||||
const configFilePath = await marketplaceManager.installMarketplaceItem(message.payload.item, {
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@
|
|||
{
|
||||
"command": "roo-cline.marketplaceButtonClicked",
|
||||
"group": "navigation@4",
|
||||
"when": "view == roo-cline.SidebarProvider && roo-cline.marketplaceEnabled"
|
||||
"when": "view == roo-cline.SidebarProvider"
|
||||
},
|
||||
{
|
||||
"command": "roo-cline.historyButtonClicked",
|
||||
|
|
@ -274,7 +274,7 @@
|
|||
{
|
||||
"command": "roo-cline.marketplaceButtonClicked",
|
||||
"group": "navigation@4",
|
||||
"when": "activeWebviewPanelId == roo-cline.TabPanelProvider && roo-cline.marketplaceEnabled"
|
||||
"when": "activeWebviewPanelId == roo-cline.TabPanelProvider"
|
||||
},
|
||||
{
|
||||
"command": "roo-cline.historyButtonClicked",
|
||||
|
|
|
|||
|
|
@ -6,21 +6,22 @@ import { webviewMessageHandler } from "../../../core/webview/webviewMessageHandl
|
|||
const mockProvider = {
|
||||
getState: vi.fn(),
|
||||
postStateToWebview: vi.fn(),
|
||||
postMessageToWebview: vi.fn(),
|
||||
} as any
|
||||
|
||||
const mockMarketplaceManager = {
|
||||
updateWithFilteredItems: vi.fn(),
|
||||
} as any
|
||||
|
||||
describe("Marketplace Setting Check", () => {
|
||||
describe("Marketplace General Availability", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it("should skip API calls when marketplace is disabled", async () => {
|
||||
// Mock experiments with marketplace disabled
|
||||
it("should allow marketplace API calls (marketplace is generally available)", async () => {
|
||||
// Mock state without marketplace experiment (since it's now generally available)
|
||||
mockProvider.getState.mockResolvedValue({
|
||||
experiments: { marketplace: false },
|
||||
experiments: {},
|
||||
})
|
||||
|
||||
const message = {
|
||||
|
|
@ -30,25 +31,7 @@ describe("Marketplace Setting Check", () => {
|
|||
|
||||
await webviewMessageHandler(mockProvider, message, mockMarketplaceManager)
|
||||
|
||||
// Should not call marketplace manager methods
|
||||
expect(mockMarketplaceManager.updateWithFilteredItems).not.toHaveBeenCalled()
|
||||
expect(mockProvider.postStateToWebview).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("should allow API calls when marketplace is enabled", async () => {
|
||||
// Mock experiments with marketplace enabled
|
||||
mockProvider.getState.mockResolvedValue({
|
||||
experiments: { marketplace: true },
|
||||
})
|
||||
|
||||
const message = {
|
||||
type: "filterMarketplaceItems" as const,
|
||||
filters: { type: "mcp", search: "", tags: [] },
|
||||
}
|
||||
|
||||
await webviewMessageHandler(mockProvider, message, mockMarketplaceManager)
|
||||
|
||||
// Should call marketplace manager methods
|
||||
// Should call marketplace manager methods since marketplace is generally available
|
||||
expect(mockMarketplaceManager.updateWithFilteredItems).toHaveBeenCalledWith({
|
||||
type: "mcp",
|
||||
search: "",
|
||||
|
|
@ -57,13 +40,13 @@ describe("Marketplace Setting Check", () => {
|
|||
expect(mockProvider.postStateToWebview).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("should skip installation when marketplace is disabled", async () => {
|
||||
// Mock experiments with marketplace disabled
|
||||
it("should allow marketplace installation (marketplace is generally available)", async () => {
|
||||
// Mock state without marketplace experiment (since it's now generally available)
|
||||
mockProvider.getState.mockResolvedValue({
|
||||
experiments: { marketplace: false },
|
||||
experiments: {},
|
||||
})
|
||||
|
||||
const mockInstallMarketplaceItem = vi.fn()
|
||||
const mockInstallMarketplaceItem = vi.fn().mockResolvedValue(undefined)
|
||||
const mockMarketplaceManagerWithInstall = {
|
||||
installMarketplaceItem: mockInstallMarketplaceItem,
|
||||
}
|
||||
|
|
@ -83,7 +66,7 @@ describe("Marketplace Setting Check", () => {
|
|||
|
||||
await webviewMessageHandler(mockProvider, message, mockMarketplaceManagerWithInstall as any)
|
||||
|
||||
// Should not call install method
|
||||
expect(mockInstallMarketplaceItem).not.toHaveBeenCalled()
|
||||
// Should call install method since marketplace is generally available
|
||||
expect(mockInstallMarketplaceItem).toHaveBeenCalledWith(message.mpItem, message.mpInstallOptions)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ describe("experiments", () => {
|
|||
it("returns false when POWER_STEERING experiment is not enabled", () => {
|
||||
const experiments: Record<ExperimentId, boolean> = {
|
||||
powerSteering: false,
|
||||
marketplace: false,
|
||||
disableCompletionCommand: false,
|
||||
multiFileApplyDiff: false,
|
||||
}
|
||||
|
|
@ -37,7 +36,6 @@ describe("experiments", () => {
|
|||
it("returns true when experiment POWER_STEERING is enabled", () => {
|
||||
const experiments: Record<ExperimentId, boolean> = {
|
||||
powerSteering: true,
|
||||
marketplace: false,
|
||||
disableCompletionCommand: false,
|
||||
multiFileApplyDiff: false,
|
||||
}
|
||||
|
|
@ -47,49 +45,10 @@ describe("experiments", () => {
|
|||
it("returns false when experiment is not present", () => {
|
||||
const experiments: Record<ExperimentId, boolean> = {
|
||||
powerSteering: false,
|
||||
marketplace: false,
|
||||
disableCompletionCommand: false,
|
||||
multiFileApplyDiff: false,
|
||||
}
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false)
|
||||
})
|
||||
})
|
||||
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,
|
||||
marketplace: false,
|
||||
disableCompletionCommand: false,
|
||||
multiFileApplyDiff: 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,
|
||||
marketplace: true,
|
||||
disableCompletionCommand: false,
|
||||
multiFileApplyDiff: false,
|
||||
}
|
||||
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,
|
||||
// marketplace missing
|
||||
} as any
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.MARKETPLACE)).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { AssertEqual, Equals, Keys, Values, ExperimentId, Experiments } from "@roo-code/types"
|
||||
|
||||
export const EXPERIMENT_IDS = {
|
||||
MARKETPLACE: "marketplace",
|
||||
MULTI_FILE_APPLY_DIFF: "multiFileApplyDiff",
|
||||
DISABLE_COMPLETION_COMMAND: "disableCompletionCommand",
|
||||
POWER_STEERING: "powerSteering",
|
||||
|
|
@ -16,7 +15,6 @@ interface ExperimentConfig {
|
|||
}
|
||||
|
||||
export const experimentConfigsMap: Record<ExperimentKey, ExperimentConfig> = {
|
||||
MARKETPLACE: { enabled: false },
|
||||
MULTI_FILE_APPLY_DIFF: { enabled: false },
|
||||
DISABLE_COMPLETION_COMMAND: { enabled: false },
|
||||
POWER_STEERING: { enabled: false },
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ const App = () => {
|
|||
telemetrySetting,
|
||||
telemetryKey,
|
||||
machineId,
|
||||
experiments,
|
||||
cloudUserInfo,
|
||||
cloudIsAuthenticated,
|
||||
mdmCompliant,
|
||||
|
|
@ -93,10 +92,6 @@ const App = () => {
|
|||
// Handle switchTab action with tab parameter
|
||||
if (message.action === "switchTab" && message.tab) {
|
||||
const targetTab = message.tab as Tab
|
||||
// Don't switch to marketplace tab if the experiment is disabled
|
||||
if (targetTab === "marketplace" && !experiments.marketplace) {
|
||||
return
|
||||
}
|
||||
switchTab(targetTab)
|
||||
setCurrentSection(undefined)
|
||||
} else {
|
||||
|
|
@ -105,10 +100,6 @@ const App = () => {
|
|||
const section = message.values?.section as string | undefined
|
||||
|
||||
if (newTab) {
|
||||
// Don't switch to marketplace tab if the experiment is disabled
|
||||
if (newTab === "marketplace" && !experiments.marketplace) {
|
||||
return
|
||||
}
|
||||
switchTab(newTab)
|
||||
setCurrentSection(section)
|
||||
}
|
||||
|
|
@ -124,7 +115,7 @@ const App = () => {
|
|||
chatViewRef.current?.acceptInput()
|
||||
}
|
||||
},
|
||||
[switchTab, experiments],
|
||||
[switchTab],
|
||||
)
|
||||
|
||||
useEvent("message", onMessage)
|
||||
|
|
@ -147,10 +138,10 @@ const App = () => {
|
|||
|
||||
// Track marketplace tab views
|
||||
useEffect(() => {
|
||||
if (tab === "marketplace" && experiments.marketplace) {
|
||||
if (tab === "marketplace") {
|
||||
telemetryClient.capture(TelemetryEventName.MARKETPLACE_TAB_VIEWED)
|
||||
}
|
||||
}, [tab, experiments.marketplace])
|
||||
}, [tab])
|
||||
|
||||
if (!didHydrateState) {
|
||||
return null
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ describe("App", () => {
|
|||
didHydrateState: true,
|
||||
showWelcome: false,
|
||||
shouldShowAnnouncement: false,
|
||||
experiments: { marketplace: false },
|
||||
experiments: {},
|
||||
language: "en",
|
||||
})
|
||||
})
|
||||
|
|
@ -224,74 +224,35 @@ describe("App", () => {
|
|||
expect(screen.queryByTestId(`${view}-view`)).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
describe("marketplace experiment", () => {
|
||||
it("does not switch to marketplace tab when experiment is disabled", async () => {
|
||||
mockUseExtensionState.mockReturnValue({
|
||||
didHydrateState: true,
|
||||
showWelcome: false,
|
||||
shouldShowAnnouncement: false,
|
||||
experiments: { marketplace: false },
|
||||
language: "en",
|
||||
})
|
||||
it("switches to marketplace view when receiving marketplaceButtonClicked action", async () => {
|
||||
render(<AppWithProviders />)
|
||||
|
||||
render(<AppWithProviders />)
|
||||
|
||||
act(() => {
|
||||
triggerMessage("marketplaceButtonClicked")
|
||||
})
|
||||
|
||||
// Should remain on chat view
|
||||
const chatView = screen.getByTestId("chat-view")
|
||||
expect(chatView.getAttribute("data-hidden")).toBe("false")
|
||||
expect(screen.queryByTestId("marketplace-view")).not.toBeInTheDocument()
|
||||
act(() => {
|
||||
triggerMessage("marketplaceButtonClicked")
|
||||
})
|
||||
|
||||
it("switches to marketplace tab when experiment is enabled", async () => {
|
||||
mockUseExtensionState.mockReturnValue({
|
||||
didHydrateState: true,
|
||||
showWelcome: false,
|
||||
shouldShowAnnouncement: false,
|
||||
experiments: { marketplace: true },
|
||||
language: "en",
|
||||
})
|
||||
const marketplaceView = await screen.findByTestId("marketplace-view")
|
||||
expect(marketplaceView).toBeInTheDocument()
|
||||
|
||||
render(<AppWithProviders />)
|
||||
const chatView = screen.getByTestId("chat-view")
|
||||
expect(chatView.getAttribute("data-hidden")).toBe("true")
|
||||
})
|
||||
|
||||
act(() => {
|
||||
triggerMessage("marketplaceButtonClicked")
|
||||
})
|
||||
it("returns to chat view when clicking done in marketplace view", async () => {
|
||||
render(<AppWithProviders />)
|
||||
|
||||
const marketplaceView = await screen.findByTestId("marketplace-view")
|
||||
expect(marketplaceView).toBeInTheDocument()
|
||||
|
||||
const chatView = screen.getByTestId("chat-view")
|
||||
expect(chatView.getAttribute("data-hidden")).toBe("true")
|
||||
act(() => {
|
||||
triggerMessage("marketplaceButtonClicked")
|
||||
})
|
||||
|
||||
it("returns to chat view when clicking done in marketplace view", async () => {
|
||||
mockUseExtensionState.mockReturnValue({
|
||||
didHydrateState: true,
|
||||
showWelcome: false,
|
||||
shouldShowAnnouncement: false,
|
||||
experiments: { marketplace: true },
|
||||
language: "en",
|
||||
})
|
||||
const marketplaceView = await screen.findByTestId("marketplace-view")
|
||||
|
||||
render(<AppWithProviders />)
|
||||
|
||||
act(() => {
|
||||
triggerMessage("marketplaceButtonClicked")
|
||||
})
|
||||
|
||||
const marketplaceView = await screen.findByTestId("marketplace-view")
|
||||
|
||||
act(() => {
|
||||
marketplaceView.click()
|
||||
})
|
||||
|
||||
const chatView = screen.getByTestId("chat-view")
|
||||
expect(chatView.getAttribute("data-hidden")).toBe("false")
|
||||
expect(screen.queryByTestId("marketplace-view")).not.toBeInTheDocument()
|
||||
act(() => {
|
||||
marketplaceView.click()
|
||||
})
|
||||
|
||||
const chatView = screen.getByTestId("chat-view")
|
||||
expect(chatView.getAttribute("data-hidden")).toBe("false")
|
||||
expect(screen.queryByTestId("marketplace-view")).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export const ExperimentalSettings = ({
|
|||
|
||||
<Section>
|
||||
{Object.entries(experimentConfigsMap)
|
||||
.filter((config) => config[0] !== "DIFF_STRATEGY" && config[0] !== "MULTI_SEARCH_AND_REPLACE")
|
||||
.filter(([key]) => key in EXPERIMENT_IDS)
|
||||
.map((config) => {
|
||||
if (config[0] === "MULTI_FILE_APPLY_DIFF") {
|
||||
return (
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue