UI top down homescreen (#2951)

* isotrUpdate welcome screen UI components and fix unused variable

* Save collapsibility.

* Add persistence, locales.

* Top layout, expanded tips.

* Minimal 'tasks' language.

* Adjust announcement positioning/dimensions.

* Fix tests, defaults.

* Fix translations.

* Compromise-compromise.

* Final tweaks.

* More tweaks.

* More tweaks.

* Issues fix.

* Update translations, remove debug.

* Fix transparency issue.

---------

Co-authored-by: hannesrudolph <hrudolph@gmail.com>
This commit is contained in:
Sacha Sayan 2025-04-25 22:39:11 -04:00 committed by GitHub
parent de22566ea2
commit 83133c6e6d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
50 changed files with 633 additions and 302 deletions

View file

@ -53,6 +53,7 @@ export class ContextProxy {
public async initialize() {
for (const key of GLOBAL_STATE_KEYS) {
try {
// Revert to original assignment
this.stateCache[key] = this.originalContext.globalState.get(key)
} catch (error) {
logger.error(`Error loading global ${key}: ${error instanceof Error ? error.message : String(error)}`)

View file

@ -1213,6 +1213,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
language,
maxReadFileLine,
terminalCompressProgressBar,
historyPreviewCollapsed,
} = await this.getState()
const telemetryKey = process.env.POSTHOG_API_KEY
@ -1298,6 +1299,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
settingsImportedAt: this.settingsImportedAt,
terminalCompressProgressBar: terminalCompressProgressBar ?? true,
hasSystemPromptOverride,
historyPreviewCollapsed: historyPreviewCollapsed ?? false,
}
}
@ -1386,6 +1388,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
telemetrySetting: stateValues.telemetrySetting || "unset",
showRooIgnoredFiles: stateValues.showRooIgnoredFiles ?? true,
maxReadFileLine: stateValues.maxReadFileLine ?? 500,
historyPreviewCollapsed: stateValues.historyPreviewCollapsed ?? false,
}
}

View file

@ -843,6 +843,10 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
await updateGlobalState("maxReadFileLine", message.value)
await provider.postStateToWebview()
break
case "setHistoryPreviewCollapsed": // Add the new case handler
await updateGlobalState("historyPreviewCollapsed", message.bool ?? false)
// No need to call postStateToWebview here as the UI already updated optimistically
break
case "toggleApiConfigPin":
if (message.text) {
const currentPinned = getGlobalState("pinnedApiConfigs") ?? {}

View file

@ -287,6 +287,7 @@ type GlobalSettings = {
}
| undefined
enhancementApiConfigId?: string | undefined
historyPreviewCollapsed?: boolean | undefined
}
type ClineMessage = {

View file

@ -290,6 +290,7 @@ type GlobalSettings = {
}
| undefined
enhancementApiConfigId?: string | undefined
historyPreviewCollapsed?: boolean | undefined
}
export type { GlobalSettings }

View file

@ -573,6 +573,7 @@ export const globalSettingsSchema = z.object({
customModePrompts: customModePromptsSchema.optional(),
customSupportPrompts: customSupportPromptsSchema.optional(),
enhancementApiConfigId: z.string().optional(),
historyPreviewCollapsed: z.boolean().optional(),
})
export type GlobalSettings = z.infer<typeof globalSettingsSchema>
@ -650,6 +651,7 @@ const globalSettingsRecord: GlobalSettingsRecord = {
customSupportPrompts: undefined,
enhancementApiConfigId: undefined,
cachedChromeHostUrl: undefined,
historyPreviewCollapsed: undefined,
}
export const GLOBAL_SETTINGS_KEYS = Object.keys(globalSettingsRecord) as Keys<GlobalSettings>[]

View file

@ -66,6 +66,7 @@ export interface ExtensionMessage {
| "fileSearchResults"
| "toggleApiConfigPin"
| "acceptInput"
| "setHistoryPreviewCollapsed"
text?: string
action?:
| "chatButtonClicked"
@ -197,6 +198,7 @@ export type ExtensionState = Pick<
renderContext: "sidebar" | "editor"
settingsImportedAt?: number
historyPreviewCollapsed?: boolean
}
export type { ClineMessage, ClineAsk, ClineSay }

View file

@ -124,6 +124,7 @@ export interface WebviewMessage {
| "maxReadFileLine"
| "searchFiles"
| "toggleApiConfigPin"
| "setHistoryPreviewCollapsed"
text?: string
disabled?: boolean
askResponse?: ClineAskResponse
@ -150,6 +151,7 @@ export interface WebviewMessage {
requestId?: string
ids?: string[]
hasSystemPromptOverride?: boolean
historyPreviewCollapsed?: boolean
}
export const checkoutDiffPayloadSchema = z.object({

View file

@ -123,7 +123,6 @@ const App = () => {
isHidden={tab !== "chat"}
showAnnouncement={showAnnouncement}
hideAnnouncement={() => setShowAnnouncement(false)}
showHistoryView={() => switchTab("history")}
/>
<HumanRelayDialog
isOpen={humanRelayDialogState.isOpen}

View file

@ -4,13 +4,12 @@ import { useAppTranslation } from "@/i18n/TranslationContext"
import { Trans } from "react-i18next"
interface AnnouncementProps {
version: string
hideAnnouncement: () => void
}
/*
You must update the latestAnnouncementId in ClineProvider 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 }: AnnouncementProps) => {
const Announcement = ({ hideAnnouncement }: AnnouncementProps) => {
const { t } = useAppTranslation()
const discordLink = (
@ -42,69 +41,71 @@ const Announcement = ({ version, hideAnnouncement }: AnnouncementProps) => {
)
return (
<div
style={{
backgroundColor: "var(--vscode-editor-inactiveSelectionBackground)",
borderRadius: "3px",
padding: "12px 16px",
margin: "5px 15px 5px 15px",
position: "relative",
flexShrink: 0,
}}>
<VSCodeButton
appearance="icon"
onClick={hideAnnouncement}
title={t("chat:announcement.hideButton")}
style={{ position: "absolute", top: "8px", right: "8px" }}>
<span className="codicon codicon-close"></span>
</VSCodeButton>
<h2 style={{ margin: "0 0 8px" }}>{t("chat:announcement.title")}</h2>
<div className="flex flex-col justify-center absolute top-0 bottom-0 left-0 right-0 z-50 p-10 bg-black/50">
<div
style={{
backgroundColor: "var(--vscode-editor-background)",
borderRadius: "3px",
padding: "12px 16px",
margin: "5px 15px 5px 15px",
position: "relative",
flexShrink: 0,
}}>
<VSCodeButton
appearance="icon"
onClick={hideAnnouncement}
title={t("chat:announcement.hideButton")}
style={{ position: "absolute", top: "8px", right: "8px" }}>
<span className="codicon codicon-close"></span>
</VSCodeButton>
<h2 style={{ margin: "0 0 8px" }}>{t("chat:announcement.title")}</h2>
<p style={{ margin: "5px 0px" }}>{t("chat:announcement.description")}</p>
<p style={{ margin: "5px 0px" }}>{t("chat:announcement.description")}</p>
<h3 style={{ margin: "12px 0 5px", fontSize: "14px" }}>{t("chat:announcement.whatsNew")}</h3>
<ul style={{ margin: "5px 0" }}>
<li>
{" "}
<h3 style={{ margin: "12px 0 5px", fontSize: "14px" }}>{t("chat:announcement.whatsNew")}</h3>
<ul style={{ margin: "5px 0" }}>
<li>
{" "}
<Trans
i18nKey="chat:announcement.feature1"
components={{
bold: <b />,
code: <code />,
}}
/>
</li>
<li>
{" "}
<Trans
i18nKey="chat:announcement.feature2"
components={{
bold: <b />,
code: <code />,
}}
/>
</li>
<li>
{" "}
<Trans
i18nKey="chat:announcement.feature3"
components={{
bold: <b />,
code: <code />,
}}
/>
</li>
</ul>
<p style={{ margin: "10px 0px 0px" }}>
<Trans
i18nKey="chat:announcement.feature1"
i18nKey="chat:announcement.detailsDiscussLinks"
components={{
bold: <b />,
code: <code />,
discordLink: discordLink,
redditLink: redditLink,
}}
/>
</li>
<li>
{" "}
<Trans
i18nKey="chat:announcement.feature2"
components={{
bold: <b />,
code: <code />,
}}
/>
</li>
<li>
{" "}
<Trans
i18nKey="chat:announcement.feature3"
components={{
bold: <b />,
code: <code />,
}}
/>
</li>
</ul>
<p style={{ margin: "10px 0px 0px" }}>
<Trans
i18nKey="chat:announcement.detailsDiscussLinks"
components={{
discordLink: discordLink,
redditLink: redditLink,
}}
/>
</p>
</p>
</div>
</div>
)
}

View file

@ -3,7 +3,6 @@ import debounce from "debounce"
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react"
import { useDeepCompareEffect, useEvent, useMount } from "react-use"
import { Virtuoso, type VirtuosoHandle } from "react-virtuoso"
import styled from "styled-components"
import removeMd from "remove-markdown"
import { Trans } from "react-i18next"
@ -30,8 +29,8 @@ import { useAppTranslation } from "@src/i18n/TranslationContext"
import TelemetryBanner from "../common/TelemetryBanner"
import HistoryPreview from "../history/HistoryPreview"
import RooHero from "../welcome/RooHero"
import RooHero from "@src/components/welcome/RooHero"
import RooTips from "@src/components/welcome/RooTips"
import Announcement from "./Announcement"
import BrowserSessionRow from "./BrowserSessionRow"
import ChatRow from "./ChatRow"
@ -39,12 +38,12 @@ import ChatTextArea from "./ChatTextArea"
import TaskHeader from "./TaskHeader"
import AutoApproveMenu from "./AutoApproveMenu"
import SystemPromptWarning from "./SystemPromptWarning"
import { useTaskSearch } from "../history/useTaskSearch"
export interface ChatViewProps {
isHidden: boolean
showAnnouncement: boolean
hideAnnouncement: () => void
showHistoryView: () => void
}
export interface ChatViewRef {
@ -56,13 +55,12 @@ export const MAX_IMAGES_PER_MESSAGE = 20 // Anthropic limits to 20 images
const isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0
const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewProps> = (
{ isHidden, showAnnouncement, hideAnnouncement, showHistoryView },
{ isHidden, showAnnouncement, hideAnnouncement },
ref,
) => {
const { t } = useAppTranslation()
const modeShortcutText = `${isMac ? "⌘" : "Ctrl"} + . ${t("chat:forNextMode")}`
const {
version,
clineMessages: messages,
taskHistory,
apiConfiguration,
@ -84,8 +82,23 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
customModes,
telemetrySetting,
hasSystemPromptOverride,
historyPreviewCollapsed, // Added historyPreviewCollapsed
} = useExtensionState()
const { tasks } = useTaskSearch()
// Initialize expanded state based on the persisted setting (default to expanded if undefined)
const [isExpanded, setIsExpanded] = useState(
historyPreviewCollapsed === undefined ? true : !historyPreviewCollapsed,
)
const toggleExpanded = useCallback(() => {
const newState = !isExpanded
setIsExpanded(newState)
// Send message to extension to persist the new collapsed state
vscode.postMessage({ type: "setHistoryPreviewCollapsed", bool: !newState })
}, [isExpanded])
//const task = messages.length > 0 ? (messages[0].say === "task" ? messages[0] : undefined) : undefined) : undefined
const task = useMemo(() => messages.at(0), [messages]) // 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 Cline.abort)
const modifiedMessages = useMemo(() => combineApiRequests(combineCommandSequences(messages.slice(1))), [messages])
@ -1197,17 +1210,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
}))
return (
<div
style={{
position: "fixed",
top: 0,
left: 0,
right: 0,
bottom: 0,
display: isHidden ? "none" : "flex",
flexDirection: "column",
overflow: "hidden",
}}>
<div className={isHidden ? "hidden" : "fixed top-0 left-0 right-0 bottom-0 flex flex-col overflow-hidden"}>
{showAnnouncement && <Announcement hideAnnouncement={hideAnnouncement} />}
{task ? (
<>
<TaskHeader
@ -1237,20 +1241,43 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
)}
</>
) : (
<div
style={{
flex: "1 1 0", // flex-grow: 1, flex-shrink: 1, flex-basis: 0
minHeight: 0,
overflowY: "auto",
display: "flex",
flexDirection: "column",
paddingBottom: "10px",
}}>
{telemetrySetting === "unset" && <TelemetryBanner />}
{showAnnouncement && <Announcement version={version} hideAnnouncement={hideAnnouncement} />}
<RooHero />
{taskHistory.length > 0 && <HistoryPreview showHistoryView={showHistoryView} />}
<div className="flex-1 min-h-0 overflow-y-auto flex flex-col gap-4">
{/* Moved Task Bar Header Here */}
{tasks.length !== 0 && (
<div className="flex text-vscode-descriptionForeground w-full mx-auto px-5 pt-3">
<div className="flex items-center gap-1 cursor-pointer" onClick={toggleExpanded}>
{tasks.length < 10 && (
<span className={`font-medium text-xs `}>{t("history:recentTasks")}</span>
)}
<span
className={`codicon ${isExpanded ? "codicon-eye" : "codicon-eye-closed"} scale-90`}
/>
</div>
</div>
)}
<div
className={` w-full flex flex-col gap-4 m-auto ${isExpanded && tasks.length > 0 ? "mt-0" : ""} p-10 pt-5`}>
<RooHero />
{telemetrySetting === "unset" && <TelemetryBanner />}
{/* Show the task history preview if expanded and tasks exist */}
{taskHistory.length > 0 && isExpanded && <HistoryPreview />}
<p className="ext-vscode-editor-foreground leading-tight font-vscode text-center">
<Trans
i18nKey="chat:about"
components={{
DocsLink: (
<a
href="https://docs.roocode.com/getting-started/your-first-task"
target="_blank"
rel="noopener noreferrer">
the docs
</a>
),
}}
/>
</p>
<RooTips cycle={false} />
</div>
</div>
)}
@ -1270,28 +1297,20 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
// but becomes scrollable when the viewport is too small
*/}
{!task && (
<AutoApproveMenu
style={{
marginBottom: -2,
flex: "0 1 auto", // flex-grow: 0, flex-shrink: 1, flex-basis: auto
minHeight: 0,
}}
/>
<div className="mb-[-2px] flex-initial min-h-0">
<AutoApproveMenu />
</div>
)}
{task && (
<>
<div style={{ flexGrow: 1, display: "flex" }} ref={scrollContainerRef}>
<div className="grow flex" ref={scrollContainerRef}>
<Virtuoso
ref={virtuosoRef}
key={task.ts} // trick to make sure virtuoso re-renders when task changes, and we use initialTopMostItemIndex to start at the bottom
className="scrollable"
style={{
flexGrow: 1,
overflowY: "scroll", // always show scrollbar
}}
className="scrollable grow overflow-y-scroll"
components={{
Footer: () => <div style={{ height: 5 }} />, // Add empty padding at the bottom
Footer: () => <div className="h-[5px]" />, // Add empty padding at the bottom
}}
// increasing top by 3_000 to prevent jumping around when user collapses a row
increaseViewportBy={{ top: 3_000, bottom: Number.MAX_SAFE_INTEGER }} // hack to make sure the last message is always rendered to get truly perfect scroll to bottom animation when new messages are added (Number.MAX_SAFE_INTEGER is safe for arithmetic operations, which is all virtuoso uses this value for in src/sizeRangeSystem.ts)
@ -1310,40 +1329,33 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
</div>
<AutoApproveMenu />
{showScrollToBottom ? (
<div
style={{
display: "flex",
padding: "10px 15px 0px 15px",
}}>
<ScrollToBottomButton
<div className="flex px-[15px] pt-[10px]">
<div
className="bg-[color-mix(in_srgb,_var(--vscode-toolbar-hoverBackground)_55%,_transparent)] rounded-[3px] overflow-hidden cursor-pointer flex justify-center items-center flex-1 h-[25px] hover:bg-[color-mix(in_srgb,_var(--vscode-toolbar-hoverBackground)_90%,_transparent)] active:bg-[color-mix(in_srgb,_var(--vscode-toolbar-hoverBackground)_70%,_transparent)]"
onClick={() => {
scrollToBottomSmooth()
disableAutoScrollRef.current = false
}}
title={t("chat:scrollToBottom")}>
<span className="codicon codicon-chevron-down" style={{ fontSize: "18px" }}></span>
</ScrollToBottomButton>
<span className="codicon codicon-chevron-down text-[18px]"></span>
</div>
</div>
) : (
<div
style={{
opacity:
primaryButtonText || secondaryButtonText || isStreaming
? enableButtons || (isStreaming && !didClickCancel)
? 1
: 0.5
: 0,
display: "flex",
padding: `${primaryButtonText || secondaryButtonText || isStreaming ? "10" : "0"}px 15px 0px 15px`,
}}>
className={`flex ${
primaryButtonText || secondaryButtonText || isStreaming ? "px-[15px] pt-[10px]" : "p-0"
} ${
primaryButtonText || secondaryButtonText || isStreaming
? enableButtons || (isStreaming && !didClickCancel)
? "opacity-100"
: "opacity-50"
: "opacity-0"
}`}>
{primaryButtonText && !isStreaming && (
<VSCodeButton
appearance="primary"
disabled={!enableButtons}
style={{
flex: secondaryButtonText ? 1 : 2,
marginRight: secondaryButtonText ? "6px" : "0",
}}
className={secondaryButtonText ? "flex-1 mr-[6px]" : "flex-[2] mr-0"}
title={
primaryButtonText === t("chat:retry.title")
? t("chat:retry.tooltip")
@ -1372,10 +1384,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
<VSCodeButton
appearance="secondary"
disabled={!enableButtons && !(isStreaming && !didClickCancel)}
style={{
flex: isStreaming ? 2 : 1,
marginLeft: isStreaming ? 0 : "6px",
}}
className={isStreaming ? "flex-[2] ml-0" : "flex-1 ml-[6px]"}
title={
isStreaming
? t("chat:cancel.tooltip")
@ -1425,24 +1434,4 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
const ChatView = forwardRef(ChatViewComponent)
const ScrollToBottomButton = styled.div`
background-color: color-mix(in srgb, var(--vscode-toolbar-hoverBackground) 55%, transparent);
border-radius: 3px;
overflow: hidden;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
flex: 1;
height: 25px;
&:hover {
background-color: color-mix(in srgb, var(--vscode-toolbar-hoverBackground) 90%, transparent);
}
&:active {
background-color: color-mix(in srgb, var(--vscode-toolbar-hoverBackground) 70%, transparent);
}
`
export default ChatView

View file

@ -19,8 +19,8 @@ interface ContextMenuProps {
selectedType: ContextMenuOptionType | null
queryItems: ContextMenuQueryItem[]
modes?: ModeConfig[]
loading?: boolean // New loading prop
dynamicSearchResults?: SearchResult[] // New dynamic search results prop
loading?: boolean
dynamicSearchResults?: SearchResult[]
}
const ContextMenu: React.FC<ContextMenuProps> = ({

View file

@ -95,7 +95,6 @@ const defaultProps: ChatViewProps = {
isHidden: false,
showAnnouncement: false,
hideAnnouncement: () => {},
showHistoryView: () => {},
}
const renderChatView = (props: Partial<ChatViewProps> = {}) => {

View file

@ -153,7 +153,6 @@ const defaultProps: ChatViewProps = {
isHidden: false,
showAnnouncement: false,
hideAnnouncement: () => {},
showHistoryView: () => {},
}
const queryClient = new QueryClient()

View file

@ -2,115 +2,64 @@ import { memo } from "react"
import { vscode } from "@/utils/vscode"
import { formatLargeNumber, formatDate } from "@/utils/format"
import { Button } from "@/components/ui"
import { useAppTranslation } from "@src/i18n/TranslationContext"
import { CopyButton } from "./CopyButton"
import { useTaskSearch } from "./useTaskSearch"
import { Trans } from "react-i18next"
import { Coins } from "lucide-react"
type HistoryPreviewProps = {
showHistoryView: () => void
}
const HistoryPreview = ({ showHistoryView }: HistoryPreviewProps) => {
const HistoryPreview = () => {
const { tasks, showAllWorkspaces } = useTaskSearch()
const { t } = useAppTranslation()
return (
<>
<div className="flex flex-col gap-3 shrink-0 mx-5">
{!!tasks.length && (
<div className="flex items-center justify-between text-vscode-descriptionForeground">
<div className="flex items-center gap-1">
<span className="codicon codicon-comment-discussion scale-90 mr-1" />
<span className="font-medium text-xs uppercase">{t("history:recentTasks")}</span>
</div>
<Button variant="ghost" size="sm" onClick={() => showHistoryView()} className="uppercase">
{t("history:viewAll")}
</Button>
</div>
)}
{tasks.length === 0 && (
<div className="flex flex-col gap-3">
{tasks.length !== 0 && (
<>
<p className="outline rounded p-4">
<Trans
i18nKey="chat:onboarding"
components={{
DocsLink: (
<a
href="https://docs.roocode.com/getting-started/your-first-task"
target="_blank"
rel="noopener noreferrer">
the docs
</a>
),
}}
/>
</p>
<Button size="sm" onClick={() => showHistoryView()} className="mx-auto">
{t("history:viewAll")}
</Button>
{tasks.slice(0, 3).map((item) => (
<div
key={item.id}
className="bg-vscode-editor-background rounded relative overflow-hidden cursor-pointer border border-vscode-toolbar-hoverBackground/30 hover:border-vscode-toolbar-hoverBackground/60"
onClick={() => vscode.postMessage({ type: "showTaskWithId", text: item.id })}>
<div className="flex flex-col gap-2 p-3 pt-1">
<div className="flex justify-between items-center">
<span className="text-xs font-medium text-vscode-descriptionForeground uppercase">
{formatDate(item.ts)}
</span>
<CopyButton itemTask={item.task} />
</div>
<div
className="text-vscode-foreground overflow-hidden whitespace-pre-wrap"
style={{
display: "-webkit-box",
WebkitLineClamp: 2,
WebkitBoxOrient: "vertical",
wordBreak: "break-word",
overflowWrap: "anywhere",
}}>
{item.task}
</div>
<div className="flex flex-row gap-2 text-xs text-vscode-descriptionForeground">
<span> {formatLargeNumber(item.tokensIn || 0)}</span>
<span> {formatLargeNumber(item.tokensOut || 0)}</span>
{!!item.totalCost && (
<span>
<Coins className="inline-block size-[1em]" />{" "}
{"$" + item.totalCost?.toFixed(2)}
</span>
)}
</div>
{showAllWorkspaces && item.workspace && (
<div className="flex flex-row gap-1 text-vscode-descriptionForeground text-xs mt-1">
<span className="codicon codicon-folder scale-80" />
<span>{item.workspace}</span>
</div>
)}
</div>
</div>
))}
</>
)}
{tasks.slice(0, 3).map((item) => (
<div
key={item.id}
className="bg-vscode-toolbar-hoverBackground/50 hover:bg-vscode-toolbar-hoverBackground/75 rounded-xs relative overflow-hidden opacity-90 hover:opacity-100 cursor-pointer"
onClick={() => vscode.postMessage({ type: "showTaskWithId", text: item.id })}>
<div className="flex flex-col gap-2 p-3 pt-1">
<div className="flex justify-between items-center">
<span className="text-xs font-medium text-vscode-descriptionForeground uppercase">
{formatDate(item.ts)}
</span>
<CopyButton itemTask={item.task} />
</div>
<div
className="text-vscode-descriptionForeground overflow-hidden whitespace-pre-wrap"
style={{
display: "-webkit-box",
WebkitLineClamp: 3,
WebkitBoxOrient: "vertical",
wordBreak: "break-word",
overflowWrap: "anywhere",
}}>
{item.task}
</div>
<div className="text-xs text-vscode-descriptionForeground">
<span>
{t("history:tokens", {
in: formatLargeNumber(item.tokensIn || 0),
out: formatLargeNumber(item.tokensOut || 0),
})}
</span>
{!!item.cacheWrites && (
<>
{" • "}
<span>
{t("history:cache", {
writes: formatLargeNumber(item.cacheWrites || 0),
reads: formatLargeNumber(item.cacheReads || 0),
})}
</span>
</>
)}
{!!item.totalCost && (
<>
{" • "}
<span>{t("history:apiCost", { cost: item.totalCost?.toFixed(4) })}</span>
</>
)}
</div>
{showAllWorkspaces && item.workspace && (
<div className="flex flex-row gap-1 text-vscode-descriptionForeground text-xs mt-1">
<span className="codicon codicon-folder scale-80" />
<span>{item.workspace}</span>
</div>
)}
</div>
</div>
))}
</div>
</>
)

View file

@ -1,16 +1,13 @@
import { useState } from "react"
import { useAppTranslation } from "@src/i18n/TranslationContext"
const WelcomeView = () => {
const { t } = useAppTranslation()
const RooHero = () => {
const [imagesBaseUri] = useState(() => {
const w = window as any
return w.IMAGES_BASE_URI || ""
})
return (
<div style={{ padding: "10px 20px", flexShrink: 0 }} className="flex flex-col items-center mt-8 gap-2">
<div className="flex flex-col items-center justify-center pb-4">
<div
style={{
backgroundColor: "var(--vscode-foreground)",
@ -24,9 +21,8 @@ const WelcomeView = () => {
className="mx-auto">
<img src={imagesBaseUri + "/roo-logo.svg"} alt="Roo logo" className="h-8 opacity-0" />
</div>
<h2 className="">{t("chat:greeting")}</h2>
</div>
)
}
export default WelcomeView
export default RooHero

View file

@ -0,0 +1,92 @@
import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"
import { useTranslation } from "react-i18next"
import { useState, useEffect } from "react"
import clsx from "clsx"
const tips = [
{
icon: "codicon-list-tree",
href: "https://docs.roocode.com/features/boomerang-tasks",
titleKey: "rooTips.boomerangTasks.title",
descriptionKey: "rooTips.boomerangTasks.description",
},
{
icon: "codicon-pinned",
href: "https://docs.roocode.com/basic-usage/using-modes",
titleKey: "rooTips.stickyModels.title",
descriptionKey: "rooTips.stickyModels.description",
},
{
icon: "codicon-tools",
href: "https://docs.roocode.com/basic-usage/how-tools-work",
titleKey: "rooTips.tools.title",
descriptionKey: "rooTips.tools.description",
},
]
interface RooTipsProps {
cycle?: boolean
}
const RooTips = ({ cycle = false }: RooTipsProps) => {
const { t } = useTranslation("chat")
const [currentTipIndex, setCurrentTipIndex] = useState(Math.floor(Math.random() * tips.length))
const [isFading, setIsFading] = useState(false)
useEffect(() => {
if (!cycle) return
const intervalId = setInterval(() => {
setIsFading(true) // Start fade out
setTimeout(() => {
setCurrentTipIndex((prevIndex) => (prevIndex + 1) % tips.length)
setIsFading(false) // Start fade in
}, 1000) // Fade duration
}, 11000) // 10s display + 1s fade
return () => clearInterval(intervalId) // Cleanup on unmount
}, [cycle])
const currentTip = tips[currentTipIndex]
const topTwoTips = tips.slice(0, 2)
return (
<div
className={clsx(
"flex flex-col items-center justify-center px-5 py-2.5 gap-4",
cycle && "h-[5em] overflow-visible m-5",
)}>
{/* If we need real estate, we show a compressed version of the tips. Otherwise, we expand it. */}
{cycle ? (
<>
<div className="opacity-70 pb-1"> Did you know about...</div>
<div
className={clsx(
"flex items-center gap-2 text-vscode-editor-foreground font-vscode max-w-[250px] transition-opacity duration-1000 ease-in-out",
isFading ? "opacity-0" : "opacity-70",
)}>
{" "}
<span className={`codicon ${currentTip.icon}`}></span>
<span>
<VSCodeLink href={currentTip.href}>{t(currentTip.titleKey)}</VSCodeLink>:{" "}
{t(currentTip.descriptionKey)}
</span>
</div>
</>
) : (
topTwoTips.map((tip) => (
<div
key={tip.titleKey}
className="flex items-center gap-2 text-vscode-editor-foreground font-vscode max-w-[250px]">
<span className={`codicon ${tip.icon}`}></span>
<span>
<VSCodeLink href={tip.href}>{t(tip.titleKey)}</VSCodeLink>: {t(tip.descriptionKey)}
</span>
</div>
))
)}
</div>
)
}
export default RooTips

View file

@ -38,6 +38,7 @@ const WelcomeView = () => {
<Tab>
<TabContent className="flex flex-col gap-5">
<RooHero />
<h2 className="mx-auto">{t("chat:greeting")}</h2>
<div className="outline rounded p-4">
<Trans i18nKey="welcome:introduction" />

View file

@ -0,0 +1,45 @@
import React from "react"
import { render, screen } from "@testing-library/react"
import RooTips from "../RooTips"
// Mock the translation hook
jest.mock("react-i18next", () => ({
useTranslation: () => ({
t: (key: string) => key, // Simple mock that returns the key
}),
// Mock Trans component if it were used directly, but it's not here
}))
// Mock VSCodeLink
jest.mock("@vscode/webview-ui-toolkit/react", () => ({
VSCodeLink: ({ href, children }: { href: string; children: React.ReactNode }) => <a href={href}>{children}</a>,
}))
// Mock clsx if complex class logic needs specific testing (optional)
// jest.mock('clsx');
describe("RooTips Component", () => {
beforeEach(() => {
jest.useFakeTimers()
// Reset Math.random mock for consistent starting points if needed
// jest.spyOn(global.Math, 'random').mockReturnValue(0); // Example: always start with the first tip
})
afterEach(() => {
jest.runOnlyPendingTimers()
jest.useRealTimers()
// Restore Math.random if mocked
// jest.spyOn(global.Math, 'random').mockRestore();
})
describe("when cycle is false (default)", () => {
beforeEach(() => {
render(<RooTips cycle={false} />)
})
test("renders only the top two tips", () => {
// Ensure only two tips are present (check by link role)
expect(screen.getAllByRole("link")).toHaveLength(2)
})
})
})

View file

@ -13,6 +13,7 @@ import { experimentDefault, ExperimentId } from "@roo/shared/experiments"
import { TelemetrySetting } from "@roo/shared/TelemetrySetting"
export interface ExtensionStateContextType extends ExtensionState {
historyPreviewCollapsed?: boolean // Add the new state property
didHydrateState: boolean
showWelcome: boolean
theme: any
@ -89,6 +90,7 @@ export interface ExtensionStateContextType extends ExtensionState {
togglePinnedApiConfig: (configName: string) => void
terminalCompressProgressBar?: boolean
setTerminalCompressProgressBar: (value: boolean) => void
setHistoryPreviewCollapsed: (value: boolean) => void
}
export const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)
@ -166,6 +168,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
terminalZshP10k: false, // Default Powerlevel10k integration setting
terminalZdotdir: false, // Default ZDOTDIR handling setting
terminalCompressProgressBar: true, // Default to compress progress bar output
historyPreviewCollapsed: false, // Initialize the new state (default to expanded)
})
const [didHydrateState, setDidHydrateState] = useState(false)
@ -336,6 +339,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
return { ...prevState, pinnedApiConfigs: newPinned }
}),
setHistoryPreviewCollapsed: (value) =>
setState((prevState) => ({ ...prevState, historyPreviewCollapsed: value })), // Implement the setter
}
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>

View file

@ -65,9 +65,23 @@
"tooltip": "Cancel·la l'operació actual"
},
"scrollToBottom": "Desplaça't al final del xat",
"about": "Genera, refactoritza i depura codi amb l'ajuda de la IA.<br />Consulta la nostra <DocsLink>documentació</DocsLink> per obtenir més informació.",
"onboarding": "<strong> La vostra llista de tasques en aquest espai de treball està buida. </strong> Comença escrivint una tasca a continuació. \nNo esteu segur per on començar? \nMés informació sobre què pot fer Roo als documents.",
"rooTips": {
"boomerangTasks": {
"title": "Tasques Boomerang",
"description": "Divideix les tasques en parts més petites i manejables."
},
"stickyModels": {
"title": "Modes persistents",
"description": "Cada mode recorda el vostre darrer model utilitzat"
},
"tools": {
"title": "Eines",
"description": "Permet que la IA resolgui problemes navegant per la web, executant ordres i molt més."
}
},
"selectMode": "Selecciona el mode d'interacció",
"selectApiConfig": "Selecciona la configuració de l'API",
"enhancePrompt": "Millora la sol·licitud amb context addicional",
"addImages": "Afegeix imatges al missatge",
"sendMessage": "Envia el missatge",
@ -217,5 +231,6 @@
"close": "Tancar navegador"
}
},
"systemPromptWarning": "ADVERTÈNCIA: S'ha activat una substitució personalitzada d'instruccions del sistema. Això pot trencar greument la funcionalitat i causar un comportament impredictible."
"systemPromptWarning": "ADVERTÈNCIA: S'ha activat una substitució personalitzada d'instruccions del sistema. Això pot trencar greument la funcionalitat i causar un comportament impredictible.",
"selectApiConfig": "Seleccioneu la configuració de l'API"
}

View file

@ -1,5 +1,5 @@
{
"recentTasks": "Tasques recents",
"recentTasks": "Tasques",
"viewAll": "Veure tot",
"tokens": "Tokens: ↑{{in}} ↓{{out}}",
"cache": "Cau: +{{writes}} → {{reads}}",

View file

@ -65,9 +65,23 @@
"tooltip": "Aktuelle Operation abbrechen"
},
"scrollToBottom": "Zum Chat-Ende scrollen",
"about": "Generiere, überarbeite und debugge Code mit KI-Unterstützung.<br />Weitere Informationen findest du in unserer <DocsLink>Dokumentation</DocsLink>.",
"onboarding": "<strong>Deine Aufgabenliste in diesem Arbeitsbereich ist leer.</strong> Beginne mit der Eingabe einer Aufgabe unten. Du bist dir nicht sicher, wie du anfangen sollst? Lies mehr darüber, was Roo für dich tun kann, in <DocsLink>den Dokumenten</DocsLink>.",
"rooTips": {
"boomerangTasks": {
"title": "Bumerang-Aufgaben",
"description": "Teile Aufgaben in kleinere, überschaubare Teile auf."
},
"stickyModels": {
"title": "Sticky Modi",
"description": "Jeder Modus merkt sich dein zuletzt verwendetes Modell"
},
"tools": {
"title": "Tools",
"description": "Erlaube der KI, Probleme durch Surfen im Web, Ausführen von Befehlen und mehr zu lösen."
}
},
"selectMode": "Interaktionsmodus auswählen",
"selectApiConfig": "API-Konfiguration auswählen",
"enhancePrompt": "Prompt mit zusätzlichem Kontext verbessern",
"addImages": "Bilder zur Nachricht hinzufügen",
"sendMessage": "Nachricht senden",
@ -217,5 +231,6 @@
"close": "Browser schließen"
}
},
"systemPromptWarning": "WARNUNG: Benutzerdefinierte Systemaufforderung aktiv. Dies kann die Funktionalität erheblich beeinträchtigen und zu unvorhersehbarem Verhalten führen."
"systemPromptWarning": "WARNUNG: Benutzerdefinierte Systemaufforderung aktiv. Dies kann die Funktionalität erheblich beeinträchtigen und zu unvorhersehbarem Verhalten führen.",
"selectApiConfig": "API-Konfiguration auswählen"
}

View file

@ -1,5 +1,5 @@
{
"recentTasks": "Jüngste Aufgaben",
"recentTasks": "Aufgaben",
"viewAll": "Alle anzeigen",
"tokens": "Tokens: ↑{{in}} ↓{{out}}",
"cache": "Cache: +{{writes}} → {{reads}}",

View file

@ -65,7 +65,22 @@
"tooltip": "Cancel the current operation"
},
"scrollToBottom": "Scroll to bottom of chat",
"onboarding": "<strong>Your task list in this workspace is empty.</strong> Start by typing in a task below. Not sure how to begin? Read more about what Roo can do for you in <DocsLink>the docs</DocsLink>.",
"about": "Generate, refactor, and debug code with AI assistance.<br />Check out our <DocsLink>documentation</DocsLink> to learn more.",
"onboarding": "Your task list in this workspace is empty.",
"rooTips": {
"boomerangTasks": {
"title": "Boomerang Tasks",
"description": "Split tasks into smaller, manageable parts."
},
"stickyModels": {
"title": "Sticky Modes",
"description": "Each mode remembers your last used model"
},
"tools": {
"title": "Tools",
"description": "Allow the AI to solve problems by browsing the web, running commands, and more."
}
},
"selectMode": "Select mode for interaction",
"selectApiConfig": "Select API configuration",
"enhancePrompt": "Enhance prompt with additional context",

View file

@ -1,5 +1,5 @@
{
"recentTasks": "Recent Tasks",
"recentTasks": "Tasks",
"viewAll": "View All Tasks",
"tokens": "Tokens: ↑{{in}} ↓{{out}}",
"cache": "Cache: +{{writes}} → {{reads}}",

View file

@ -65,9 +65,23 @@
"tooltip": "Cancelar la operación actual"
},
"scrollToBottom": "Desplazarse al final del chat",
"about": "Genera, refactoriza y depura código con asistencia de IA.<br />Consulta nuestra <DocsLink>documentación</DocsLink> para obtener más información.",
"onboarding": "<strong>Tu lista de tareas en este espacio de trabajo está vacía.</strong> Comienza escribiendo una tarea abajo. ¿No estás seguro cómo empezar? Lee más sobre lo que Roo puede hacer por ti en <DocsLink>la documentación</DocsLink>.",
"rooTips": {
"boomerangTasks": {
"title": "Tareas Boomerang",
"description": "Divide las tareas en partes más pequeñas y manejables."
},
"stickyModels": {
"title": "Modos persistentes",
"description": "Cada modo recuerda tu último modelo utilizado"
},
"tools": {
"title": "Herramientas",
"description": "Permite que la IA resuelva problemas navegando por la web, ejecutando comandos y mucho más."
}
},
"selectMode": "Seleccionar modo de interacción",
"selectApiConfig": "Seleccionar configuración de API",
"enhancePrompt": "Mejorar el mensaje con contexto adicional",
"addImages": "Agregar imágenes al mensaje",
"sendMessage": "Enviar mensaje",
@ -217,5 +231,6 @@
"close": "Cerrar navegador"
}
},
"systemPromptWarning": "ADVERTENCIA: Anulación de instrucciones del sistema personalizada activa. Esto puede romper gravemente la funcionalidad y causar un comportamiento impredecible."
"systemPromptWarning": "ADVERTENCIA: Anulación de instrucciones del sistema personalizada activa. Esto puede romper gravemente la funcionalidad y causar un comportamiento impredecible.",
"selectApiConfig": "Seleccionar configuración de API"
}

View file

@ -1,5 +1,5 @@
{
"recentTasks": "Tareas recientes",
"recentTasks": "Tareas",
"viewAll": "Ver todas",
"tokens": "Tokens: ↑{{in}} ↓{{out}}",
"cache": "Caché: +{{writes}} → {{reads}}",

View file

@ -65,9 +65,23 @@
"tooltip": "Annuler l'opération actuelle"
},
"scrollToBottom": "Défiler jusqu'au bas du chat",
"about": "Générer, refactoriser et déboguer du code avec l'assistance de l'IA.<br />Consultez notre <DocsLink>documentation</DocsLink> pour en savoir plus.",
"onboarding": "Grâce aux dernières avancées en matière de capacités de codage agent, je peux gérer des tâches complexes de développement logiciel étape par étape. Avec des outils qui me permettent de créer et d'éditer des fichiers, d'explorer des projets complexes, d'utiliser le navigateur et d'exécuter des commandes de terminal (après votre autorisation), je peux vous aider de manières qui vont au-delà de la complétion de code ou du support technique. Je peux même utiliser MCP pour créer de nouveaux outils et étendre mes propres capacités.",
"rooTips": {
"boomerangTasks": {
"title": "Tâches Boomerang",
"description": "Divisez les tâches en parties plus petites et gérables."
},
"stickyModels": {
"title": "Modes persistants",
"description": "Chaque mode se souvient de votre dernier modèle utilisé"
},
"tools": {
"title": "Outils",
"description": "Permettez à l'IA de résoudre des problèmes en naviguant sur le Web, en exécutant des commandes, et plus encore."
}
},
"selectMode": "Sélectionner le mode d'interaction",
"selectApiConfig": "Sélectionner la configuration API",
"enhancePrompt": "Améliorer la requête avec un contexte supplémentaire",
"addImages": "Ajouter des images au message",
"sendMessage": "Envoyer le message",
@ -217,5 +231,6 @@
"close": "Fermer le navigateur"
}
},
"systemPromptWarning": "AVERTISSEMENT : Remplacement d'instructions système personnalisées actif. Cela peut gravement perturber la fonctionnalité et provoquer un comportement imprévisible."
"systemPromptWarning": "AVERTISSEMENT : Remplacement d'instructions système personnalisées actif. Cela peut gravement perturber la fonctionnalité et provoquer un comportement imprévisible.",
"selectApiConfig": "Sélectionner la configuration de lAPI"
}

View file

@ -1,5 +1,5 @@
{
"recentTasks": "Tâches récentes",
"recentTasks": "Tâches",
"viewAll": "Voir tout",
"tokens": "Tokens: ↑{{in}} ↓{{out}}",
"cache": "Cache: +{{writes}} → {{reads}}",

View file

@ -65,9 +65,23 @@
"tooltip": "वर्तमान ऑपरेशन रद्द करें"
},
"scrollToBottom": "चैट के निचले हिस्से तक स्क्रॉल करें",
"about": "एआई सहायता से कोड जेनरेट करें, रिफैक्टर करें और डिबग करें। अधिक जानने के लिए हमारे <DocsLink>दस्तावेज़</DocsLink> देखें।",
"onboarding": "एजेंटिक कोडिंग क्षमताओं में नवीनतम प्रगति के कारण, मैं जटिल सॉफ्टवेयर विकास कार्यों को चरण-दर-चरण संभाल सकता हूं। ऐसे उपकरणों के साथ जो मुझे फ़ाइलें बनाने और संपादित करने, जटिल प्रोजेक्ट का अन्वेषण करने, ब्राउज़र का उपयोग करने और टर्मिनल कमांड (आपकी अनुमति के बाद) निष्पादित करने की अनुमति देते हैं, मैं आपकी मदद कोड पूर्णता या तकनीकी समर्थन से परे तरीकों से कर सकता हूं। मैं अपनी क्षमताओं का विस्तार करने और नए उपकरण बनाने के लिए MCP का भी उपयोग कर सकता हूं।",
"rooTips": {
"boomerangTasks": {
"title": "बूमरैंग कार्य",
"description": "कार्यों को छोटे, प्रबंधनीय भागों में विभाजित करें।"
},
"stickyModels": {
"title": "स्टिकी मोड",
"description": "प्रत्येक मोड आपके अंतिम उपयोग किए गए मॉडल को याद रखता है"
},
"tools": {
"title": "उपकरण",
"description": "एआई को वेब ब्राउज़ करके, कमांड चलाकर और अधिक समस्याओं को हल करने की अनुमति दें।"
}
},
"selectMode": "इंटरैक्शन मोड चुनें",
"selectApiConfig": "API कॉन्फ़िगरेशन चुनें",
"enhancePrompt": "अतिरिक्त संदर्भ के साथ प्रॉम्प्ट बढ़ाएँ",
"addImages": "संदेश में चित्र जोड़ें",
"sendMessage": "संदेश भेजें",
@ -217,5 +231,6 @@
"close": "ब्राउज़र बंद करें"
}
},
"systemPromptWarning": "चेतावनी: कस्टम सिस्टम प्रॉम्प्ट ओवरराइड सक्रिय है। यह कार्यक्षमता को गंभीर रूप से बाधित कर सकता है और अनियमित व्यवहार का कारण बन सकता है।"
"systemPromptWarning": "चेतावनी: कस्टम सिस्टम प्रॉम्प्ट ओवरराइड सक्रिय है। यह कार्यक्षमता को गंभीर रूप से बाधित कर सकता है और अनियमित व्यवहार का कारण बन सकता है.",
"selectApiConfig": "एपीआई कॉन्फ़िगरेशन का चयन करें"
}

View file

@ -1,5 +1,5 @@
{
"recentTasks": "हाल के कार्य",
"recentTasks": "कार्य",
"viewAll": "सभी देखें",
"tokens": "Tokens: ↑{{in}} ↓{{out}}",
"cache": "कैश: +{{writes}} → {{reads}}",

View file

@ -65,9 +65,23 @@
"tooltip": "Annulla l'operazione corrente"
},
"scrollToBottom": "Scorri fino alla fine della chat",
"about": "Genera, refactor e debug del codice con l'assistenza dell'IA.<br />Consulta la nostra <DocsLink>documentazione</DocsLink> per saperne di più.",
"onboarding": "Grazie alle più recenti innovazioni nelle capacità di codifica agentica, posso gestire complesse attività di sviluppo software passo dopo passo. Con strumenti che mi permettono di creare e modificare file, esplorare progetti complessi, utilizzare il browser ed eseguire comandi da terminale (dopo la tua autorizzazione), posso aiutarti in modi che vanno oltre il completamento del codice o il supporto tecnico. Posso persino usare MCP per creare nuovi strumenti ed estendere le mie capacità.",
"rooTips": {
"boomerangTasks": {
"title": "Attività Boomerang",
"description": "Dividi le attività in parti più piccole e gestibili."
},
"stickyModels": {
"title": "Modalità persistenti",
"description": "Ogni modalità ricorda il tuo ultimo modello utilizzato"
},
"tools": {
"title": "Strumenti",
"description": "Consenti all'IA di risolvere i problemi navigando sul Web, eseguendo comandi e altro ancora."
}
},
"selectMode": "Seleziona modalità di interazione",
"selectApiConfig": "Seleziona configurazione API",
"enhancePrompt": "Migliora prompt con contesto aggiuntivo",
"addImages": "Aggiungi immagini al messaggio",
"sendMessage": "Invia messaggio",
@ -217,5 +231,6 @@
"close": "Chiudi browser"
}
},
"systemPromptWarning": "ATTENZIONE: Sovrascrittura personalizzata delle istruzioni di sistema attiva. Questo può compromettere gravemente le funzionalità e causare comportamenti imprevedibili."
"systemPromptWarning": "ATTENZIONE: Sovrascrittura personalizzata delle istruzioni di sistema attiva. Questo può compromettere gravemente le funzionalità e causare comportamenti imprevedibili.",
"selectApiConfig": "Seleziona la configurazione API"
}

View file

@ -1,5 +1,5 @@
{
"recentTasks": "Compiti recenti",
"recentTasks": "Compiti",
"viewAll": "Vedi tutto",
"tokens": "Tokens: ↑{{in}} ↓{{out}}",
"cache": "Cache: +{{writes}} → {{reads}}",

View file

@ -65,9 +65,23 @@
"tooltip": "現在の操作をキャンセル"
},
"scrollToBottom": "チャットの最下部にスクロール",
"about": "AI支援でコードを生成、リファクタリング、デバッグします。詳細については、<DocsLink>ドキュメント</DocsLink>をご覧ください。",
"onboarding": "最新のエージェント型コーディング能力の進歩により、複雑なソフトウェア開発タスクをステップバイステップで処理できます。ファイルの作成や編集、複雑なプロジェクトの探索、ブラウザの使用、ターミナルコマンドの実行許可後を可能にするツールにより、コード補完や技術サポート以上の方法であなたをサポートできます。MCPを使用して新しいツールを作成し、自分の能力を拡張することもできます。",
"rooTips": {
"boomerangTasks": {
"title": "ブーメランタスク",
"description": "タスクをより小さく、管理しやすい部分に分割します。"
},
"stickyModels": {
"title": "スティッキーモード",
"description": "各モードは、最後に使用したモデルを記憶しています"
},
"tools": {
"title": "ツール",
"description": "AIがWebの閲覧、コマンドの実行などによって問題を解決できるようにします。"
}
},
"selectMode": "対話モードを選択",
"selectApiConfig": "API設定を選択",
"enhancePrompt": "追加コンテキストでプロンプトを強化",
"addImages": "メッセージに画像を追加",
"sendMessage": "メッセージを送信",
@ -217,5 +231,6 @@
"close": "ブラウザを閉じる"
}
},
"systemPromptWarning": "警告:カスタムシステムプロンプトの上書きが有効です。これにより機能が深刻に損なわれ、予測不可能な動作が発生する可能性があります。"
"systemPromptWarning": "警告:カスタムシステムプロンプトの上書きが有効です。これにより機能が深刻に損なわれ、予測不可能な動作が発生する可能性があります。",
"selectApiConfig": "API構成を選択"
}

View file

@ -65,9 +65,23 @@
"tooltip": "현재 작업 취소"
},
"scrollToBottom": "채팅 하단으로 스크롤",
"about": "AI 지원으로 코드를 생성, 리팩터링 및 디버깅합니다. 자세한 내용은 <DocsLink>문서</DocsLink>를 확인하세요.",
"onboarding": "<strong>이 작업 공간의 작업 목록이 비어 있습니다.</strong> 아래에 작업을 입력하여 시작하세요. 어떻게 시작해야 할지 모르겠나요? Roo가 무엇을 할 수 있는지 <DocsLink>문서</DocsLink>에서 자세히 알아보세요.",
"rooTips": {
"boomerangTasks": {
"title": "부메랑 작업",
"description": "작업을 더 작고 관리하기 쉬운 부분으로 나눕니다."
},
"stickyModels": {
"title": "스티키 모드",
"description": "각 모드는 마지막으로 사용한 모델을 기억합니다."
},
"tools": {
"title": "도구",
"description": "AI가 웹 탐색, 명령 실행 등으로 문제를 해결하도록 허용합니다."
}
},
"selectMode": "상호작용 모드 선택",
"selectApiConfig": "API 구성 선택",
"enhancePrompt": "추가 컨텍스트로 프롬프트 향상",
"addImages": "메시지에 이미지 추가",
"sendMessage": "메시지 보내기",
@ -217,5 +231,6 @@
"close": "브라우저 닫기"
}
},
"systemPromptWarning": "경고: 사용자 정의 시스템 프롬프트 재정의가 활성화되었습니다. 이로 인해 기능이 심각하게 손상되고 예측할 수 없는 동작이 발생할 수 있습니다."
"systemPromptWarning": "경고: 사용자 정의 시스템 프롬프트 재정의가 활성화되었습니다. 이로 인해 기능이 심각하게 손상되고 예측할 수 없는 동작이 발생할 수 있습니다.",
"selectApiConfig": "API 구성 선택"
}

View file

@ -1,5 +1,5 @@
{
"recentTasks": "최근 작업",
"recentTasks": "작업",
"viewAll": "모두 보기",
"tokens": "Tokens: ↑{{in}} ↓{{out}}",
"cache": "캐시: +{{writes}} → {{reads}}",

View file

@ -65,9 +65,23 @@
"tooltip": "Anuluj bieżącą operację"
},
"scrollToBottom": "Przewiń do dołu czatu",
"about": "Generuj, refaktoryzuj i debuguj kod z pomocą sztucznej inteligencji.<br />Sprawdź naszą <DocsLink>dokumentację</DocsLink>, aby dowiedzieć się więcej.",
"onboarding": "<strong>Twoja lista zadań w tym obszarze roboczym jest pusta.</strong> Zacznij od wpisania zadania poniżej. Nie wiesz, jak zacząć? Przeczytaj więcej o tym, co Roo może dla Ciebie zrobić w <DocsLink>dokumentacji</DocsLink>.",
"rooTips": {
"boomerangTasks": {
"title": "Zadania bumerangowe",
"description": "Podziel zadania na mniejsze, łatwiejsze do zarządzania części."
},
"stickyModels": {
"title": "Tryby trwałe",
"description": "Każdy tryb zapamiętuje ostatnio używany model"
},
"tools": {
"title": "Narzędzia",
"description": "Pozwól sztucznej inteligencji rozwiązywać problemy, przeglądając sieć, uruchamiając polecenia i nie tylko."
}
},
"selectMode": "Wybierz tryb interakcji",
"selectApiConfig": "Wybierz konfigurację API",
"enhancePrompt": "Ulepsz podpowiedź dodatkowym kontekstem",
"addImages": "Dodaj obrazy do wiadomości",
"sendMessage": "Wyślij wiadomość",
@ -217,5 +231,6 @@
"close": "Zamknij przeglądarkę"
}
},
"systemPromptWarning": "OSTRZEŻENIE: Aktywne niestandardowe zastąpienie instrukcji systemowych. Może to poważnie zakłócić funkcjonalność i powodować nieprzewidywalne zachowanie."
"systemPromptWarning": "OSTRZEŻENIE: Aktywne niestandardowe zastąpienie instrukcji systemowych. Może to poważnie zakłócić funkcjonalność i powodować nieprzewidywalne zachowanie.",
"selectApiConfig": "Wybierz konfigurację API"
}

View file

@ -1,5 +1,5 @@
{
"recentTasks": "Ostatnie zadania",
"recentTasks": "Zadania",
"viewAll": "Zobacz wszystkie",
"tokens": "Tokens: ↑{{in}} ↓{{out}}",
"cache": "Pamięć podręczna: +{{writes}} → {{reads}}",

View file

@ -65,9 +65,23 @@
"tooltip": "Cancelar a operação atual"
},
"scrollToBottom": "Rolar para o final do chat",
"about": "Gere, refatore e depure código com assistência de IA.<br />Confira nossa <DocsLink>documentação</DocsLink> para saber mais.",
"onboarding": "<strong>Sua lista de tarefas neste espaço de trabalho está vazia.</strong> Comece digitando uma tarefa abaixo. Não sabe como começar? Leia mais sobre o que o Roo pode fazer por você nos <DocsLink>documentos</DocsLink>.",
"rooTips": {
"boomerangTasks": {
"title": "Tarefas Bumerangue",
"description": "Divida as tarefas em partes menores e gerenciáveis."
},
"stickyModels": {
"title": "Modos Fixos",
"description": "Cada modo lembra o seu último modelo usado"
},
"tools": {
"title": "Ferramentas",
"description": "Permita que a IA resolva problemas navegando na web, executando comandos e muito mais."
}
},
"selectMode": "Selecionar modo de interação",
"selectApiConfig": "Selecionar configuração de API",
"enhancePrompt": "Aprimorar prompt com contexto adicional",
"addImages": "Adicionar imagens à mensagem",
"sendMessage": "Enviar mensagem",
@ -217,5 +231,6 @@
"close": "Fechar navegador"
}
},
"systemPromptWarning": "AVISO: Substituição personalizada de instrução do sistema ativa. Isso pode comprometer gravemente a funcionalidade e causar comportamento imprevisível."
"systemPromptWarning": "AVISO: Substituição personalizada de instrução do sistema ativa. Isso pode comprometer gravemente a funcionalidade e causar comportamento imprevisível.",
"selectApiConfig": "Selecionar configuração da API"
}

View file

@ -1,5 +1,5 @@
{
"recentTasks": "Tarefas recentes",
"recentTasks": "Tarefas",
"viewAll": "Ver todas",
"tokens": "Tokens: ↑{{in}} ↓{{out}}",
"cache": "Cache: +{{writes}} → {{reads}}",

View file

@ -65,6 +65,21 @@
"tooltip": "Отменить текущую операцию"
},
"scrollToBottom": "Прокрутить чат вниз",
"about": "Создавайте, рефакторите и отлаживайте код с помощью ИИ.<br />Подробнее см. в нашей <DocsLink>документации</DocsLink>.",
"rooTips": {
"boomerangTasks": {
"title": "Boomerang Tasks",
"description": "Orchestrate complex workflows with subtasks"
},
"stickyModels": {
"title": "Липкие режимы",
"description": "Каждый режим запоминает вашу последнюю использованную модель"
},
"tools": {
"title": "Инструменты",
"description": "Разрешите ИИ решать проблемы, просматривая веб-страницы, выполняя команды и т. д."
}
},
"onboarding": "<strong>Ваш список задач в этом рабочем пространстве пуст.</strong> Начните с ввода задачи ниже. Не знаете, с чего начать? Подробнее о возможностях Roo читайте в <DocsLink>документации</DocsLink>.",
"selectMode": "Выберите режим взаимодействия",
"selectApiConfig": "Выберите конфигурацию API",

View file

@ -65,9 +65,23 @@
"tooltip": "Mevcut işlemi iptal et"
},
"scrollToBottom": "Sohbetin altına kaydır",
"about": "AI yardımıyla kod oluşturun, yeniden düzenleyin ve hatalarını ayıklayın.<br />Daha fazla bilgi edinmek için <DocsLink>belgelerimize</DocsLink> göz atın.",
"onboarding": "<strong>Bu çalışma alanındaki görev listeniz boş.</strong> Aşağıya bir görev yazarak başlayın. Nasıl başlayacağınızdan emin değil misiniz? Roo'nun sizin için neler yapabileceği hakkında daha fazla bilgiyi <DocsLink>belgelerde</DocsLink> okuyun.",
"rooTips": {
"boomerangTasks": {
"title": "Bumerang Görevleri",
"description": "Görevleri daha küçük, yönetilebilir parçalara ayırın."
},
"stickyModels": {
"title": "Yapışkan Modlar",
"description": "Her mod, en son kullandığınız modeli hatırlar"
},
"tools": {
"title": "Araçlar",
"description": "AI'nın web'e göz atarak, komutlar çalıştırarak ve daha fazlasını yaparak sorunları çözmesine izin verin."
}
},
"selectMode": "Etkileşim modunu seçin",
"selectApiConfig": "API yapılandırmasını seçin",
"enhancePrompt": "Ek bağlamla istemi geliştir",
"addImages": "Mesaja resim ekle",
"sendMessage": "Mesaj gönder",
@ -217,5 +231,6 @@
"close": "Tarayıcıyı kapat"
}
},
"systemPromptWarning": "UYARI: Özel sistem komut geçersiz kılma aktif. Bu işlevselliği ciddi şekilde bozabilir ve öngörülemeyen davranışlara neden olabilir."
"systemPromptWarning": "UYARI: Özel sistem komut geçersiz kılma aktif. Bu işlevselliği ciddi şekilde bozabilir ve öngörülemeyen davranışlara neden olabilir.",
"selectApiConfig": "API yapılandırmasını seçin"
}

View file

@ -1,5 +1,5 @@
{
"recentTasks": "Son Görevler",
"recentTasks": "Görevler",
"viewAll": "Tümünü Gör",
"tokens": "Tokens: ↑{{in}} ↓{{out}}",
"cache": "Önbellek: +{{writes}} → {{reads}}",

View file

@ -65,9 +65,23 @@
"tooltip": "Hủy thao tác hiện tại"
},
"scrollToBottom": "Cuộn xuống cuối cuộc trò chuyện",
"about": "Tạo, tái cấu trúc và gỡ lỗi mã bằng sự hỗ trợ của AI.<br />Kiểm tra <DocsLink>tài liệu</DocsLink> của chúng tôi để tìm hiểu thêm.",
"onboarding": "<strong>Danh sách nhiệm vụ của bạn trong không gian làm việc này trống.</strong> Bắt đầu bằng cách nhập nhiệm vụ bên dưới. Bạn không chắc chắn nên bắt đầu như thế nào? Đọc thêm về những gì Roo có thể làm cho bạn trong <DocsLink>tài liệu</DocsLink>.",
"rooTips": {
"boomerangTasks": {
"title": "Nhiệm vụ Boomerang",
"description": "Chia nhỏ các nhiệm vụ thành các phần nhỏ hơn, dễ quản lý hơn."
},
"stickyModels": {
"title": "Chế độ dính",
"description": "Mỗi chế độ ghi nhớ mô hình đã sử dụng cuối cùng của bạn"
},
"tools": {
"title": "Công cụ",
"description": "Cho phép AI giải quyết vấn đề bằng cách duyệt web, chạy lệnh, v.v."
}
},
"selectMode": "Chọn chế độ tương tác",
"selectApiConfig": "Chọn cấu hình API",
"enhancePrompt": "Nâng cao yêu cầu với ngữ cảnh bổ sung",
"addImages": "Thêm hình ảnh vào tin nhắn",
"sendMessage": "Gửi tin nhắn",
@ -217,5 +231,6 @@
"close": "Đóng trình duyệt"
}
},
"systemPromptWarning": "CẢNH BÁO: Đã kích hoạt ghi đè lệnh nhắc hệ thống tùy chỉnh. Điều này có thể phá vỡ nghiêm trọng chức năng và gây ra hành vi không thể dự đoán."
"systemPromptWarning": "CẢNH BÁO: Đã kích hoạt ghi đè lệnh nhắc hệ thống tùy chỉnh. Điều này có thể phá vỡ nghiêm trọng chức năng và gây ra hành vi không thể dự đoán.",
"selectApiConfig": "Chọn cấu hình API"
}

View file

@ -1,5 +1,5 @@
{
"recentTasks": "Nhiệm vụ gần đây",
"recentTasks": "Nhiệm vụ",
"viewAll": "Xem tất cả",
"tokens": "Token: ↑{{in}} ↓{{out}}",
"cache": "Bộ nhớ đệm: +{{writes}} → {{reads}}",

View file

@ -65,9 +65,23 @@
"tooltip": "取消当前操作"
},
"scrollToBottom": "滚动到聊天底部",
"about": "通过 AI 辅助生成、重构和调试代码。<br />查看我们的 <DocsLink>文档</DocsLink> 了解更多信息。",
"onboarding": "<strong>此工作区中的任务列表为空。</strong> 请在下方输入任务开始。 不确定如何开始? 在 <DocsLink>文档</DocsLink> 中阅读更多关于 Roo 可以为您做什么的信息。",
"rooTips": {
"boomerangTasks": {
"title": "任务拆分",
"description": "将任务拆分为更小、更易于管理的部分。"
},
"stickyModels": {
"title": "粘性模式",
"description": "每个模式 都会记住 您上次使用的模型"
},
"tools": {
"title": "工具",
"description": "允许 AI 通过浏览网络、运行命令等方式解决问题。"
}
},
"selectMode": "选择交互模式",
"selectApiConfig": "选择API配置",
"enhancePrompt": "增强提示词",
"addImages": "添加图片到消息",
"sendMessage": "发送消息",
@ -217,5 +231,6 @@
"close": "关闭浏览器"
}
},
"systemPromptWarning": "警告:自定义系统提示词覆盖已激活。这可能严重破坏功能并导致不可预测的行为。"
"systemPromptWarning": "警告:自定义系统提示词覆盖已激活。这可能严重破坏功能并导致不可预测的行为。",
"selectApiConfig": "选择 API 配置"
}

View file

@ -1,5 +1,5 @@
{
"recentTasks": "最近任务",
"recentTasks": "任务",
"viewAll": "查看全部",
"tokens": "Token用量: ↑{{in}} ↓{{out}}",
"cache": "缓存操作: +{{writes}} → {{reads}}",

View file

@ -65,9 +65,23 @@
"tooltip": "取消目前操作"
},
"scrollToBottom": "捲動至對話框底部",
"about": "透過 AI 輔助產生、重構和偵錯程式碼。<br />查看我們的 <DocsLink>說明文件</DocsLink> 以瞭解更多資訊。",
"onboarding": "<strong>您在此工作區中的工作清單是空的。</strong> 請在下方輸入工作以開始。 不確定如何開始? 在 <DocsLink>說明文件</DocsLink> 中閱讀更多關於 Roo 能為您做什麼的資訊。",
"rooTips": {
"boomerangTasks": {
"title": "任務拆分",
"description": "將任務拆分為更小、更易於管理的部分。"
},
"stickyModels": {
"title": "黏性模式",
"description": "每個模式都會記住您上次使用的模型"
},
"tools": {
"title": "工具",
"description": "允許 AI 透過瀏覽網路、執行命令等方式解決問題。"
}
},
"selectMode": "選擇互動模式",
"selectApiConfig": "選擇 API 設定",
"enhancePrompt": "使用額外內容增強提示",
"addImages": "新增圖片到訊息中",
"sendMessage": "傳送訊息",
@ -217,5 +231,6 @@
"close": "關閉瀏覽器"
}
},
"systemPromptWarning": "警告:自訂系統提示詞覆蓋已啟用。這可能嚴重破壞功能並導致不可預測的行為。"
"systemPromptWarning": "警告:自訂系統提示詞覆蓋已啟用。這可能嚴重破壞功能並導致不可預測的行為。",
"selectApiConfig": "選取 API 設定"
}

View file

@ -1,5 +1,5 @@
{
"recentTasks": "最近的工作",
"recentTasks": "工作",
"viewAll": "檢視全部",
"tokens": "Tokens: ↑{{in}} ↓{{out}}",
"cache": "快取:+{{writes}} → {{reads}}",