mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 12:21:13 -05:00
Refactor Kodu links
This commit is contained in:
@@ -1,23 +1,11 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import axios from "axios"
|
||||
import { ApiHandler, withoutImageData } from "."
|
||||
import { ApiHandlerOptions, koduDefaultModelId, KoduModelId, koduModels, ModelInfo } from "../shared/api"
|
||||
import axios from "axios"
|
||||
import * as vscode from "vscode"
|
||||
|
||||
const KODU_BASE_URL = "https://claude-dev.com"
|
||||
|
||||
export function didClickKoduSignIn() {
|
||||
const loginUrl = `${KODU_BASE_URL}/auth/login?redirectTo=${vscode.env.uriScheme}://saoudrizwan.claude-dev&ext=1`
|
||||
vscode.env.openExternal(vscode.Uri.parse(loginUrl))
|
||||
}
|
||||
|
||||
export function didClickKoduAddCredits() {
|
||||
const addCreditsUrl = `${KODU_BASE_URL}/user/addCredits?redirectTo=${vscode.env.uriScheme}://saoudrizwan.claude-dev&ext=1`
|
||||
vscode.env.openExternal(vscode.Uri.parse(addCreditsUrl))
|
||||
}
|
||||
import { getKoduCreditsUrl, getKoduInferenceUrl } from "../shared/kodu"
|
||||
|
||||
export async function fetchKoduCredits({ apiKey }: { apiKey: string }) {
|
||||
const response = await axios.get(`${KODU_BASE_URL}/api/credits`, {
|
||||
const response = await axios.get(getKoduCreditsUrl(), {
|
||||
headers: {
|
||||
"x-api-key": apiKey,
|
||||
},
|
||||
@@ -89,7 +77,7 @@ export class KoduHandler implements ApiHandler {
|
||||
tool_choice: { type: "auto" },
|
||||
}
|
||||
}
|
||||
const response = await axios.post(`${KODU_BASE_URL}/api/inference`, requestBody, {
|
||||
const response = await axios.post(getKoduInferenceUrl(), requestBody, {
|
||||
headers: {
|
||||
"x-api-key": this.options.koduApiKey,
|
||||
},
|
||||
|
||||
@@ -8,7 +8,7 @@ import { downloadTask, getNonce, getUri, selectImages } from "../utils"
|
||||
import * as path from "path"
|
||||
import fs from "fs/promises"
|
||||
import { HistoryItem } from "../shared/HistoryItem"
|
||||
import { didClickKoduAddCredits, didClickKoduSignIn, fetchKoduCredits } from "../api/kodu"
|
||||
import { fetchKoduCredits } from "../api/kodu"
|
||||
|
||||
/*
|
||||
https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts
|
||||
@@ -358,15 +358,9 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
|
||||
case "exportTaskWithId":
|
||||
this.exportTaskWithId(message.text!)
|
||||
break
|
||||
case "didClickKoduSignIn":
|
||||
didClickKoduSignIn()
|
||||
break
|
||||
case "didClickKoduSignOut":
|
||||
await this.signOutKodu()
|
||||
break
|
||||
case "didClickKoduAddCredits":
|
||||
didClickKoduAddCredits()
|
||||
break
|
||||
case "fetchKoduCredits":
|
||||
const koduApiKey = await this.getSecret("koduApiKey")
|
||||
if (koduApiKey) {
|
||||
@@ -515,6 +509,7 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
|
||||
customInstructions,
|
||||
alwaysAllowReadOnly,
|
||||
themeName: vscode.workspace.getConfiguration("workbench").get<string>("colorTheme"),
|
||||
uriScheme: vscode.env.uriScheme,
|
||||
claudeMessages: this.claudeDev?.claudeMessages || [],
|
||||
taskHistory: (taskHistory || []).filter((item) => item.ts && item.task).sort((a, b) => b.ts - a.ts),
|
||||
shouldShowAnnouncement: lastShownAnnouncementId !== this.latestAnnouncementId,
|
||||
|
||||
@@ -25,6 +25,7 @@ export interface ExtensionState {
|
||||
customInstructions?: string
|
||||
alwaysAllowReadOnly?: boolean
|
||||
themeName?: string
|
||||
uriScheme?: string
|
||||
claudeMessages: ClaudeMessage[]
|
||||
taskHistory: HistoryItem[]
|
||||
shouldShowAnnouncement: boolean
|
||||
|
||||
@@ -16,9 +16,7 @@ export interface WebviewMessage {
|
||||
| "showTaskWithId"
|
||||
| "deleteTaskWithId"
|
||||
| "exportTaskWithId"
|
||||
| "didClickKoduSignIn"
|
||||
| "didClickKoduSignOut"
|
||||
| "didClickKoduAddCredits"
|
||||
| "fetchKoduCredits"
|
||||
text?: string
|
||||
askResponse?: ClaudeAskResponse
|
||||
|
||||
17
src/shared/kodu.ts
Normal file
17
src/shared/kodu.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
const KODU_BASE_URL = "https://claude-dev.com"
|
||||
|
||||
export function getKoduSignInUrl(uriScheme?: string) {
|
||||
return `${KODU_BASE_URL}/auth/login?redirectTo=${uriScheme}://saoudrizwan.claude-dev&ext=1`
|
||||
}
|
||||
|
||||
export function getKoduAddCreditsUrl(uriScheme?: string) {
|
||||
return `${KODU_BASE_URL}/user/addCredits?redirectTo=${uriScheme}://saoudrizwan.claude-dev&ext=1`
|
||||
}
|
||||
|
||||
export function getKoduCreditsUrl() {
|
||||
return `${KODU_BASE_URL}/api/credits`
|
||||
}
|
||||
|
||||
export function getKoduInferenceUrl() {
|
||||
return `${KODU_BASE_URL}/api/inference`
|
||||
}
|
||||
@@ -28,6 +28,7 @@ const App: React.FC = () => {
|
||||
const [customInstructions, setCustomInstructions] = useState<string>("")
|
||||
const [alwaysAllowReadOnly, setAlwaysAllowReadOnly] = useState<boolean>(false)
|
||||
const [vscodeThemeName, setVscodeThemeName] = useState<string | undefined>(undefined)
|
||||
const [vscodeUriScheme, setVscodeUriScheme] = useState<string | undefined>(undefined)
|
||||
const [claudeMessages, setClaudeMessages] = useState<ClaudeMessage[]>([])
|
||||
const [taskHistory, setTaskHistory] = useState<HistoryItem[]>([])
|
||||
const [showAnnouncement, setShowAnnouncement] = useState(false)
|
||||
@@ -62,6 +63,7 @@ const App: React.FC = () => {
|
||||
setCustomInstructions(message.state!.customInstructions || "")
|
||||
setAlwaysAllowReadOnly(message.state!.alwaysAllowReadOnly || false)
|
||||
setVscodeThemeName(message.state!.themeName)
|
||||
setVscodeUriScheme(message.state!.uriScheme)
|
||||
setClaudeMessages(message.state!.claudeMessages)
|
||||
setTaskHistory(message.state!.taskHistory)
|
||||
setKoduCredits(message.state!.koduCredits)
|
||||
@@ -121,7 +123,11 @@ const App: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
{showWelcome ? (
|
||||
<WelcomeView apiConfiguration={apiConfiguration} setApiConfiguration={setApiConfiguration} />
|
||||
<WelcomeView
|
||||
apiConfiguration={apiConfiguration}
|
||||
setApiConfiguration={setApiConfiguration}
|
||||
vscodeUriScheme={vscodeUriScheme}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{showSettings && (
|
||||
@@ -137,6 +143,7 @@ const App: React.FC = () => {
|
||||
alwaysAllowReadOnly={alwaysAllowReadOnly}
|
||||
setAlwaysAllowReadOnly={setAlwaysAllowReadOnly}
|
||||
onDone={() => setShowSettings(false)}
|
||||
vscodeUriScheme={vscodeUriScheme}
|
||||
/>
|
||||
)}
|
||||
{showHistory && <HistoryView taskHistory={taskHistory} onDone={() => setShowHistory(false)} />}
|
||||
@@ -159,6 +166,7 @@ const App: React.FC = () => {
|
||||
setShowAnnouncement(false)
|
||||
}}
|
||||
apiConfiguration={apiConfiguration}
|
||||
vscodeUriScheme={vscodeUriScheme}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
||||
import { vscode } from "../utils/vscode"
|
||||
import { ApiConfiguration } from "../../../src/shared/api"
|
||||
import { getKoduSignInUrl } from "../../../src/shared/kodu"
|
||||
import VSCodeButtonLink from "./VSCodeButtonLink"
|
||||
|
||||
interface AnnouncementProps {
|
||||
version: string
|
||||
hideAnnouncement: () => void
|
||||
apiConfiguration?: ApiConfiguration
|
||||
vscodeUriScheme?: string
|
||||
}
|
||||
/*
|
||||
You must update the latestAnnouncementId in ClaudeDevProvider for new announcements to show to users. This new id will be compared with whats in state for the 'last announcement shown', and if it's different then the announcement will render. As soon as an announcement is shown, the id will be updated in state. This ensures that announcements are not shown more than once, even if the user doesn't close it themselves.
|
||||
*/
|
||||
const Announcement = ({ version, hideAnnouncement, apiConfiguration }: AnnouncementProps) => {
|
||||
const Announcement = ({ version, hideAnnouncement, apiConfiguration, vscodeUriScheme }: AnnouncementProps) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
@@ -33,23 +35,23 @@ const Announcement = ({ version, hideAnnouncement, apiConfiguration }: Announcem
|
||||
<ul style={{ margin: "0 0 8px", paddingLeft: "20px" }}>
|
||||
<li>
|
||||
Excited to announce that{" "}
|
||||
<VSCodeLink href="https://claude-dev.com" style={{ display: "inline" }}>
|
||||
<VSCodeLink href={getKoduSignInUrl(vscodeUriScheme)} style={{ display: "inline" }}>
|
||||
Kodu
|
||||
</VSCodeLink>{" "}
|
||||
is offering $10 free credits to help new users get the most out of Claude Dev with high rate limits
|
||||
and prompt caching! Stay tuned for some exciting updates like easier billing and deploying live
|
||||
websites.
|
||||
{apiConfiguration?.koduApiKey === undefined && (
|
||||
<VSCodeButton
|
||||
<VSCodeButtonLink
|
||||
appearance="secondary"
|
||||
onClick={() => vscode.postMessage({ type: "didClickKoduSignIn" })}
|
||||
href={getKoduSignInUrl(vscodeUriScheme)}
|
||||
style={{
|
||||
transform: "scale(0.8)",
|
||||
transformOrigin: "left center",
|
||||
margin: "4px 0 2px 0",
|
||||
}}>
|
||||
Claim $10 Free Credits
|
||||
</VSCodeButton>
|
||||
</VSCodeButtonLink>
|
||||
)}
|
||||
</li>
|
||||
<li>
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import {
|
||||
VSCodeButton,
|
||||
VSCodeDropdown,
|
||||
VSCodeLink,
|
||||
VSCodeOption,
|
||||
VSCodeTextField,
|
||||
} from "@vscode/webview-ui-toolkit/react"
|
||||
import { VSCodeDropdown, VSCodeLink, VSCodeOption, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react"
|
||||
import { useEvent } from "react-use"
|
||||
import {
|
||||
ApiConfiguration,
|
||||
ApiModelId,
|
||||
@@ -19,9 +14,10 @@ import {
|
||||
openRouterDefaultModelId,
|
||||
openRouterModels,
|
||||
} from "../../../src/shared/api"
|
||||
import { vscode } from "../utils/vscode"
|
||||
import { useEvent } from "react-use"
|
||||
import { ExtensionMessage } from "../../../src/shared/ExtensionMessage"
|
||||
import { getKoduAddCreditsUrl, getKoduSignInUrl } from "../../../src/shared/kodu"
|
||||
import { vscode } from "../utils/vscode"
|
||||
import VSCodeButtonLink from "./VSCodeButtonLink"
|
||||
|
||||
interface ApiOptionsProps {
|
||||
showModelOptions: boolean
|
||||
@@ -29,6 +25,7 @@ interface ApiOptionsProps {
|
||||
setApiConfiguration: React.Dispatch<React.SetStateAction<ApiConfiguration | undefined>>
|
||||
koduCredits?: number
|
||||
apiErrorMessage?: string
|
||||
vscodeUriScheme?: string
|
||||
}
|
||||
|
||||
const ApiOptions: React.FC<ApiOptionsProps> = ({
|
||||
@@ -37,6 +34,7 @@ const ApiOptions: React.FC<ApiOptionsProps> = ({
|
||||
setApiConfiguration,
|
||||
koduCredits,
|
||||
apiErrorMessage,
|
||||
vscodeUriScheme,
|
||||
}) => {
|
||||
const [didFetchKoduCredits, setDidFetchKoduCredits] = useState(false)
|
||||
const handleInputChange = (field: keyof ApiConfiguration) => (event: any) => {
|
||||
@@ -184,22 +182,19 @@ const ApiOptions: React.FC<ApiOptionsProps> = ({
|
||||
{formatPrice(koduCredits || 0)}
|
||||
</span>
|
||||
</div>
|
||||
<VSCodeButton
|
||||
appearance="primary"
|
||||
onClick={() => vscode.postMessage({ type: "didClickKoduAddCredits" })}
|
||||
<VSCodeButtonLink
|
||||
href={getKoduAddCreditsUrl(vscodeUriScheme)}
|
||||
style={{
|
||||
width: "fit-content",
|
||||
}}>
|
||||
Add Credits
|
||||
</VSCodeButton>
|
||||
</VSCodeButtonLink>
|
||||
</>
|
||||
) : (
|
||||
<div style={{ margin: "4px 0px" }}>
|
||||
<VSCodeButton
|
||||
appearance="primary"
|
||||
onClick={() => vscode.postMessage({ type: "didClickKoduSignIn" })}>
|
||||
<VSCodeButtonLink href={getKoduSignInUrl(vscodeUriScheme)}>
|
||||
Sign in to Kodu
|
||||
</VSCodeButton>
|
||||
</VSCodeButtonLink>
|
||||
</div>
|
||||
)}
|
||||
<p
|
||||
@@ -210,7 +205,7 @@ const ApiOptions: React.FC<ApiOptionsProps> = ({
|
||||
}}>
|
||||
Kodu is recommended for its high rate limits and access to the latest features like prompt
|
||||
caching.
|
||||
<VSCodeLink href="https://claude-dev.com" style={{ display: "inline", fontSize: "12px" }}>
|
||||
<VSCodeLink href="https://kodu.ai" style={{ display: "inline", fontSize: "12px" }}>
|
||||
Learn more about Kodu here.
|
||||
</VSCodeLink>
|
||||
</p>
|
||||
|
||||
@@ -30,6 +30,7 @@ interface ChatViewProps {
|
||||
hideAnnouncement: () => void
|
||||
showHistoryView: () => void
|
||||
apiConfiguration?: ApiConfiguration
|
||||
vscodeUriScheme?: string
|
||||
}
|
||||
|
||||
const MAX_IMAGES_PER_MESSAGE = 20 // Anthropic limits to 20 images
|
||||
@@ -46,6 +47,7 @@ const ChatView = ({
|
||||
hideAnnouncement,
|
||||
showHistoryView,
|
||||
apiConfiguration,
|
||||
vscodeUriScheme,
|
||||
}: ChatViewProps) => {
|
||||
//const task = messages.length > 0 ? (messages[0].say === "task" ? messages[0] : undefined) : undefined) : undefined
|
||||
const task = messages.length > 0 ? messages[0] : undefined // leaving this less safe version here since if the first message is not a task, then the extension is in a bad state and needs to be debugged (see ClaudeDev.abort)
|
||||
@@ -490,6 +492,7 @@ const ChatView = ({
|
||||
version={version}
|
||||
hideAnnouncement={hideAnnouncement}
|
||||
apiConfiguration={apiConfiguration}
|
||||
vscodeUriScheme={vscodeUriScheme}
|
||||
/>
|
||||
)}
|
||||
<div style={{ padding: "0 20px", flexGrow: taskHistory.length > 0 ? undefined : 1 }}>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { ApiConfiguration } from "../../../src/shared/api"
|
||||
import { validateApiConfiguration, validateMaxRequestsPerTask } from "../utils/validate"
|
||||
import { vscode } from "../utils/vscode"
|
||||
import ApiOptions from "./ApiOptions"
|
||||
import { getKoduSignInUrl } from "../../../src/shared/kodu"
|
||||
|
||||
type SettingsViewProps = {
|
||||
version: string
|
||||
@@ -23,6 +24,7 @@ type SettingsViewProps = {
|
||||
onDone: () => void
|
||||
alwaysAllowReadOnly: boolean
|
||||
setAlwaysAllowReadOnly: React.Dispatch<React.SetStateAction<boolean>>
|
||||
vscodeUriScheme?: string
|
||||
}
|
||||
|
||||
const SettingsView = ({
|
||||
@@ -37,6 +39,7 @@ const SettingsView = ({
|
||||
onDone,
|
||||
alwaysAllowReadOnly,
|
||||
setAlwaysAllowReadOnly,
|
||||
vscodeUriScheme,
|
||||
}: SettingsViewProps) => {
|
||||
const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
|
||||
const [maxRequestsErrorMessage, setMaxRequestsErrorMessage] = useState<string | undefined>(undefined)
|
||||
@@ -104,27 +107,34 @@ const SettingsView = ({
|
||||
<div
|
||||
style={{ flexGrow: 1, overflowY: "scroll", paddingRight: 8, display: "flex", flexDirection: "column" }}>
|
||||
{apiConfiguration?.koduApiKey === undefined && (
|
||||
<div
|
||||
<a
|
||||
href={getKoduSignInUrl(vscodeUriScheme)}
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
backgroundColor: "var(--vscode-editor-inactiveSelectionBackground)",
|
||||
color: "var(--vscode-textLink-foreground)",
|
||||
padding: "6px 8px",
|
||||
borderRadius: "3px",
|
||||
margin: "0 0 8px 0px",
|
||||
fontSize: "12px",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={() => vscode.postMessage({ type: "didClickKoduSignIn" })}>
|
||||
<i
|
||||
className="codicon codicon-info"
|
||||
textDecoration: "none",
|
||||
color: "inherit",
|
||||
outline: "none",
|
||||
}}>
|
||||
<div
|
||||
style={{
|
||||
marginRight: 6,
|
||||
fontSize: 16,
|
||||
}}></i>
|
||||
<span>Claim $10 free credits from Kodu</span>
|
||||
</div>
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
backgroundColor: "var(--vscode-editor-inactiveSelectionBackground)",
|
||||
color: "var(--vscode-textLink-foreground)",
|
||||
padding: "6px 8px",
|
||||
borderRadius: "3px",
|
||||
margin: "0 0 8px 0px",
|
||||
fontSize: "12px",
|
||||
cursor: "pointer",
|
||||
}}>
|
||||
<i
|
||||
className="codicon codicon-info"
|
||||
style={{
|
||||
marginRight: 6,
|
||||
fontSize: 16,
|
||||
}}></i>
|
||||
<span>Claim $10 free credits from Kodu</span>
|
||||
</div>
|
||||
</a>
|
||||
)}
|
||||
<div style={{ marginBottom: 5 }}>
|
||||
<ApiOptions
|
||||
@@ -133,6 +143,7 @@ const SettingsView = ({
|
||||
showModelOptions={true}
|
||||
koduCredits={koduCredits}
|
||||
apiErrorMessage={apiErrorMessage}
|
||||
vscodeUriScheme={vscodeUriScheme}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
23
webview-ui/src/components/VSCodeButtonLink.tsx
Normal file
23
webview-ui/src/components/VSCodeButtonLink.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import React from "react"
|
||||
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
interface VSCodeButtonLinkProps {
|
||||
href: string
|
||||
children: React.ReactNode
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
const VSCodeButtonLink: React.FC<VSCodeButtonLinkProps> = ({ href, children, ...props }) => {
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
style={{
|
||||
textDecoration: "none",
|
||||
color: "inherit",
|
||||
}}>
|
||||
<VSCodeButton {...props}>{children}</VSCodeButton>
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
export default VSCodeButtonLink
|
||||
@@ -4,13 +4,15 @@ import { ApiConfiguration } from "../../../src/shared/api"
|
||||
import { validateApiConfiguration } from "../utils/validate"
|
||||
import { vscode } from "../utils/vscode"
|
||||
import ApiOptions from "./ApiOptions"
|
||||
import { getKoduSignInUrl } from "../../../src/shared/kodu"
|
||||
|
||||
interface WelcomeViewProps {
|
||||
apiConfiguration?: ApiConfiguration
|
||||
setApiConfiguration: React.Dispatch<React.SetStateAction<ApiConfiguration | undefined>>
|
||||
vscodeUriScheme?: string
|
||||
}
|
||||
|
||||
const WelcomeView: React.FC<WelcomeViewProps> = ({ apiConfiguration, setApiConfiguration }) => {
|
||||
const WelcomeView: React.FC<WelcomeViewProps> = ({ apiConfiguration, setApiConfiguration, vscodeUriScheme }) => {
|
||||
const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
|
||||
|
||||
const disableLetsGoButton = apiErrorMessage != null
|
||||
@@ -59,7 +61,7 @@ const WelcomeView: React.FC<WelcomeViewProps> = ({ apiConfiguration, setApiConfi
|
||||
}}></i>
|
||||
<span>
|
||||
Explore Claude's capabilities with $10 free credits from{" "}
|
||||
<VSCodeLink href="https://claude-dev.com" style={{ display: "inline" }}>
|
||||
<VSCodeLink href={getKoduSignInUrl(vscodeUriScheme)} style={{ display: "inline" }}>
|
||||
Kodu
|
||||
</VSCodeLink>
|
||||
</span>
|
||||
@@ -70,6 +72,7 @@ const WelcomeView: React.FC<WelcomeViewProps> = ({ apiConfiguration, setApiConfi
|
||||
apiConfiguration={apiConfiguration}
|
||||
setApiConfiguration={setApiConfiguration}
|
||||
showModelOptions={false}
|
||||
vscodeUriScheme={vscodeUriScheme}
|
||||
/>
|
||||
{apiConfiguration?.apiProvider !== "kodu" && (
|
||||
<VSCodeButton onClick={handleSubmit} disabled={disableLetsGoButton} style={{ marginTop: "3px" }}>
|
||||
|
||||
Reference in New Issue
Block a user