From a044ee702b149d76190e60d41a4850ef8c55fb94 Mon Sep 17 00:00:00 2001 From: code-crusher Date: Thu, 12 Feb 2026 16:10:15 +0530 Subject: [PATCH 01/12] pro model info --- src/package.json | 2 +- .../kilocode/chat/ModelSelector.tsx | 57 ++++++++++++++++--- .../kilocode/hooks/useProviderModels.ts | 19 +++---- .../kilocode/settings/providers/KiloCode.tsx | 22 +++---- .../src/components/settings/ModelPicker.tsx | 51 ++++++++++++++++- webview-ui/src/utils/customIcons.tsx | 30 ++++++++++ 6 files changed, 147 insertions(+), 34 deletions(-) diff --git a/src/package.json b/src/package.json index 7eb5dbb6d2..95a03fef31 100644 --- a/src/package.json +++ b/src/package.json @@ -3,7 +3,7 @@ "displayName": "%extension.displayName%", "description": "%extension.description%", "publisher": "matterai", - "version": "5.4.0", + "version": "5.4.1", "icon": "assets/icons/matterai-ic.png", "galleryBanner": { "color": "#FFFFFF", diff --git a/webview-ui/src/components/kilocode/chat/ModelSelector.tsx b/webview-ui/src/components/kilocode/chat/ModelSelector.tsx index e9db7171ca..6b1b922f03 100644 --- a/webview-ui/src/components/kilocode/chat/ModelSelector.tsx +++ b/webview-ui/src/components/kilocode/chat/ModelSelector.tsx @@ -1,13 +1,14 @@ -import { useMemo } from "react" -import { SelectDropdown, DropdownOptionType } from "@/components/ui" +import { DropdownOption, DropdownOptionType, SelectDropdown, StandardTooltip } from "@/components/ui" +import { usePreferredModels } from "@/components/ui/hooks/kilocode/usePreferredModels" +import { Alert02Icon } from "@/utils/customIcons" import { OPENROUTER_DEFAULT_PROVIDER_NAME, type ProviderSettings } from "@roo-code/types" -import { vscode } from "@src/utils/vscode" import { useAppTranslation } from "@src/i18n/TranslationContext" import { cn } from "@src/lib/utils" -import { prettyModelName, getModelCredits } from "../../../utils/prettyModelName" +import { vscode } from "@src/utils/vscode" +import { useMemo } from "react" +import { getModelCredits, prettyModelName } from "../../../utils/prettyModelName" import { useProviderModels } from "../hooks/useProviderModels" import { getModelIdKey, getSelectedModelId } from "../hooks/useSelectedModel" -import { usePreferredModels } from "@/components/ui/hooks/kilocode/usePreferredModels" interface ModelSelectorProps { currentApiConfigName?: string @@ -17,7 +18,8 @@ interface ModelSelectorProps { export const ModelSelector = ({ currentApiConfigName, apiConfiguration, fallbackText }: ModelSelectorProps) => { const { t } = useAppTranslation() - const { provider, providerModels, providerDefaultModel, isLoading, isError } = useProviderModels(apiConfiguration) + const { provider, providerModels, providerDefaultModel, isLoading, isError, proModelIds, proModelsEnabled } = + useProviderModels(apiConfiguration) const selectedModelId = getSelectedModelId({ provider, apiConfiguration, @@ -32,13 +34,20 @@ export const ModelSelector = ({ currentApiConfigName, apiConfiguration, fallback const baseLabel = providerModels[modelId]?.displayName ?? prettyModelName(modelId) const credits = getModelCredits(modelId) const label = credits ? `${baseLabel} ${credits}` : baseLabel + + // kilocode_change: Check if this is a pro model that's disabled + const isProModel = proModelIds?.includes(modelId) + const isProModelDisabled = isProModel && !proModelsEnabled + return { value: modelId, label, type: DropdownOptionType.ITEM, + disabled: isProModelDisabled, + isProModelDisabled, } }) - }, [modelsIds, providerModels, selectedModelId]) + }, [modelsIds, providerModels, selectedModelId, proModelIds, proModelsEnabled]) const disabled = isLoading || isError @@ -61,6 +70,39 @@ export const ModelSelector = ({ currentApiConfigName, apiConfiguration, fallback }) } + const renderItem = (option: DropdownOption & { isProModelDisabled?: boolean }) => { + return ( +
+
+
{option.label}
+
+ {option.isProModelDisabled && ( + + Pro models are only available on the Paid Plan + +
+ }> + + + + + )} + + ) + } + if (isLoading) { return null } @@ -83,6 +125,7 @@ export const ModelSelector = ({ currentApiConfigName, apiConfiguration, fallback )} triggerIcon={true} itemClassName="group" + renderItem={renderItem} /> ) } diff --git a/webview-ui/src/components/kilocode/hooks/useProviderModels.ts b/webview-ui/src/components/kilocode/hooks/useProviderModels.ts index 082edfee20..88e2381f09 100644 --- a/webview-ui/src/components/kilocode/hooks/useProviderModels.ts +++ b/webview-ui/src/components/kilocode/hooks/useProviderModels.ts @@ -1,4 +1,3 @@ -import { useMemo } from "react" import { type ProviderName, type ProviderSettings, @@ -323,22 +322,20 @@ export const useProviderModels = (apiConfiguration?: ProviderSettings) => { }) : FALLBACK_MODELS - // kilocode_change start: Filter out axon-code-2-pro if beta models are not enabled - const filteredModels = useMemo(() => { - if (!betaModelsEnabled) { - // Filter out axon-code-2-pro when beta models are not enabled - const { "axon-code-2-pro": _, ...rest } = models as ModelRecord - return rest - } - return models - }, [models, betaModelsEnabled]) + // kilocode_change start: Always show all models including axon-code-2-pro + // Pro models are marked as disabled if betaModelsEnabled is false + const proModelIds = ["axon-code-2-pro"] + const proModelsEnabled = betaModelsEnabled // kilocode_change end return { provider, - providerModels: filteredModels as ModelRecord, + providerModels: models as ModelRecord, providerDefaultModel: defaultModel, isLoading: routerModels.isLoading, isError: routerModels.isError, + // kilocode_change: pro models support + proModelIds, + proModelsEnabled, } } diff --git a/webview-ui/src/components/kilocode/settings/providers/KiloCode.tsx b/webview-ui/src/components/kilocode/settings/providers/KiloCode.tsx index fa74c65c4d..465b5880db 100644 --- a/webview-ui/src/components/kilocode/settings/providers/KiloCode.tsx +++ b/webview-ui/src/components/kilocode/settings/providers/KiloCode.tsx @@ -9,8 +9,6 @@ import { ModelPicker } from "../../../settings/ModelPicker" import { OrganizationSelector } from "../../common/OrganizationSelector" import { getKiloCodeBackendSignInUrl } from "../../helpers" import { useExtensionState } from "@/context/ExtensionStateContext" -import { useMemo } from "react" -import type { ModelRecord } from "@roo/api" type KiloCodeProps = { apiConfiguration: ProviderSettings @@ -40,16 +38,12 @@ export const KiloCode = ({ const { t } = useAppTranslation() const { betaModelsEnabled } = useExtensionState() - // Filter out axon-code-2-pro if beta models are not enabled - const filteredModels = useMemo(() => { - const models = routerModels?.["kilocode-openrouter"] ?? {} - if (!betaModelsEnabled) { - // Filter out axon-code-2-pro when beta models are not enabled - const { "axon-code-2-pro": _, ...rest } = models as ModelRecord - return rest - } - return models - }, [routerModels, betaModelsEnabled]) + // Always show all models including axon-code-2-pro + // The model will be marked as disabled if betaModelsEnabled is false + const models = routerModels?.["kilocode-openrouter"] ?? {} + + // List of pro model IDs that require paid plan + const proModelIds = ["axon-code-2-pro"] // const handleInputChange = useCallback( // ( @@ -126,11 +120,13 @@ export const KiloCode = ({ apiConfiguration={apiConfiguration} setApiConfigurationField={setApiConfigurationField} defaultModelId={kilocodeDefaultModel} - models={filteredModels} + models={models} modelIdKey="kilocodeModel" serviceName="Axon Code" serviceUrl={getAppUrl()} organizationAllowList={organizationAllowList} + proModelIds={proModelIds} + proModelsEnabled={betaModelsEnabled} /> ) diff --git a/webview-ui/src/components/settings/ModelPicker.tsx b/webview-ui/src/components/settings/ModelPicker.tsx index 2d3d755b46..a615bd0943 100644 --- a/webview-ui/src/components/settings/ModelPicker.tsx +++ b/webview-ui/src/components/settings/ModelPicker.tsx @@ -19,11 +19,14 @@ import { PopoverContent, PopoverTrigger, SelectSeparator, // kilocode_change + StandardTooltip, // kilocode_change } from "@src/components/ui" import { useEscapeKey } from "@src/hooks/useEscapeKey" import { cn } from "@src/lib/utils" +import { vscode } from "@src/utils/vscode" // kilocode_change import { ApiErrorMessage } from "./ApiErrorMessage" +import { Alert02Icon } from "@/utils/customIcons" type ModelIdKey = keyof Pick< ProviderSettings, @@ -57,6 +60,9 @@ interface ModelPickerProps { ) => void organizationAllowList: OrganizationAllowList errorMessage?: string + // kilocode_change: pro models support + proModelIds?: string[] + proModelsEnabled?: boolean } export const ModelPicker = ({ @@ -69,6 +75,9 @@ export const ModelPicker = ({ setApiConfigurationField, // organizationAllowList, // kilocode_change: unused errorMessage, + // kilocode_change: pro models support + proModelIds = [], + proModelsEnabled = true, }: ModelPickerProps) => { const { t } = useAppTranslation() @@ -94,6 +103,12 @@ export const ModelPicker = ({ return } + // kilocode_change: prevent selection of pro models when not enabled + const isProModel = proModelIds.includes(modelId) + if (isProModel && !proModelsEnabled) { + return + } + setOpen(false) setApiConfigurationField(modelIdKey, modelId) @@ -105,7 +120,7 @@ export const ModelPicker = ({ // Delay to ensure the popover is closed before setting the search value. selectTimeoutRef.current = setTimeout(() => setSearchValue(""), 100) }, - [modelIdKey, setApiConfigurationField], + [modelIdKey, setApiConfigurationField, proModelIds, proModelsEnabled], ) const onOpenChange = useCallback((open: boolean) => { @@ -203,6 +218,10 @@ export const ModelPicker = ({ const previousModelWasPreferred = Number.isInteger( models?.[modelIds[i - 1]]?.preferredIndex, ) + // kilocode_change: check if this is a pro model that's disabled + const isProModel = proModelIds.includes(model) + const isProModelDisabled = isProModel && !proModelsEnabled + return ( {!isPreferred && previousModelWasPreferred ? : null} @@ -210,10 +229,38 @@ export const ModelPicker = ({ value={model} onSelect={onSelect} data-testid={`model-option-${model}`} - className={cn(isPreferred ? "font-semibold" : "")}> + className={cn( + isPreferred ? "font-semibold" : "", + isProModelDisabled ? "opacity-60 cursor-not-allowed" : "", + )}> {model} + {isProModelDisabled && ( + + + Pro models are only available on the Paid Plan + + + + }> + + + + + )} ) => ( /> ) + +export const Alert02Icon = (props: React.SVGProps) => ( + + + + + +) From 9c21cc068b294a35e1cf0398146319f20f337a0c Mon Sep 17 00:00:00 2001 From: code-crusher Date: Thu, 12 Feb 2026 16:33:27 +0530 Subject: [PATCH 02/12] updated profile page with data --- .../kilocode/settings/providers/KiloCode.tsx | 156 +++++++++++++++--- .../src/components/settings/ModelPicker.tsx | 2 +- 2 files changed, 136 insertions(+), 22 deletions(-) diff --git a/webview-ui/src/components/kilocode/settings/providers/KiloCode.tsx b/webview-ui/src/components/kilocode/settings/providers/KiloCode.tsx index 465b5880db..dad01bebf9 100644 --- a/webview-ui/src/components/kilocode/settings/providers/KiloCode.tsx +++ b/webview-ui/src/components/kilocode/settings/providers/KiloCode.tsx @@ -9,6 +9,8 @@ import { ModelPicker } from "../../../settings/ModelPicker" import { OrganizationSelector } from "../../common/OrganizationSelector" import { getKiloCodeBackendSignInUrl } from "../../helpers" import { useExtensionState } from "@/context/ExtensionStateContext" +import { ProfileData, WebviewMessage } from "@roo/WebviewMessage" +import { useEffect, useRef, useState } from "react" type KiloCodeProps = { apiConfiguration: ProviderSettings @@ -36,13 +38,76 @@ export const KiloCode = ({ kilocodeDefaultModel, }: KiloCodeProps) => { const { t } = useAppTranslation() - const { betaModelsEnabled } = useExtensionState() + const { betaModelsEnabled, clineMessages } = useExtensionState() + + // Profile data state for usage info + const [profileData, setProfileData] = useState(null) + const previousMessagesRef = useRef("") + + // Fetch profile data on mount if token exists + useEffect(() => { + if (apiConfiguration?.kilocodeToken) { + vscode.postMessage({ type: "fetchProfileDataRequest" }) + } + }, [apiConfiguration?.kilocodeToken]) + + // Listen for profile data response + useEffect(() => { + const handleMessage = (event: MessageEvent) => { + const message = event.data + if (message.type === "profileDataResponse") { + const payload = message.payload as any + if (payload?.success && payload.data) { + setProfileData(payload.data) + } + } + } + + window.addEventListener("message", handleMessage) + return () => { + window.removeEventListener("message", handleMessage) + } + }, []) + + // Watch for new assistant responses and fetch updated profile data + useEffect(() => { + if (!apiConfiguration?.kilocodeToken || !clineMessages) return + + const currentMessagesHash = JSON.stringify( + clineMessages.map((msg) => ({ + type: msg.type, + say: msg.say, + partial: msg.partial, + ts: msg.ts, + })), + ) + + if (previousMessagesRef.current !== currentMessagesHash) { + const hasNewAssistantResponse = clineMessages.some( + (msg) => msg.type === "say" && (msg.say === "text" || msg.say === "completion_result") && !msg.partial, + ) + + if (hasNewAssistantResponse && previousMessagesRef.current !== "") { + vscode.postMessage({ type: "fetchProfileDataRequest" }) + } + + previousMessagesRef.current = currentMessagesHash + } + }, [clineMessages, apiConfiguration?.kilocodeToken]) + + // Calculate usage percentage from profile data + const usagePercentage = + profileData?.usagePercentage !== undefined + ? profileData.usagePercentage + : profileData?.usedCredits !== undefined && profileData?.totalCredits !== undefined + ? (profileData.usedCredits / profileData.totalCredits) * 100 + : null // Always show all models including axon-code-2-pro // The model will be marked as disabled if betaModelsEnabled is false const models = routerModels?.["kilocode-openrouter"] ?? {} - // List of pro model IDs that require paid plan + // List of pro model IDs which require paid plan const proModelIds = ["axon-code-2-pro"] // const handleInputChange = useCallback( @@ -72,28 +137,54 @@ export const KiloCode = ({ return ( <>
- +
{!hideKiloCodeButton && (apiConfiguration.kilocodeToken ? ( -
- +
+ {/* Usage info */} + {profileData && ( +
+
+
+ Current Plan +
+
+ {profileData.plan?.toLocaleUpperCase()} +
+
+
+
+ Monthly Credits +
+
+ ${(profileData.remainingCredits || 0).toFixed(1)} / $ + {(profileData.totalCredits || 0).toFixed(1)} remaining ( + {usagePercentage !== null + ? `${usagePercentage.toFixed(0)}% used` + : "loading..."} + ) +
+
+ {profileData.remainingReviews !== undefined && ( +
+
+ Monthly Reviews +
+
+ {profileData.remainingReviews.toFixed(0)} reviews remaining +
+
+ )} +
+ )} + + {/* Manage plan button */} + + Manage/Upgrade plan +
) : ( + + {!hideKiloCodeButton && apiConfiguration.kilocodeToken ? ( + + ) : ( + <> + )} ) } diff --git a/webview-ui/src/components/settings/ModelPicker.tsx b/webview-ui/src/components/settings/ModelPicker.tsx index a615bd0943..46fd2ae82c 100644 --- a/webview-ui/src/components/settings/ModelPicker.tsx +++ b/webview-ui/src/components/settings/ModelPicker.tsx @@ -170,7 +170,7 @@ export const ModelPicker = ({ return ( <>
- +
) : ( handleCopyPrompt(comment)}> - + Copy )} diff --git a/webview-ui/src/utils/customIcons.tsx b/webview-ui/src/utils/customIcons.tsx index af0b0fb9b5..34dcc6f78b 100644 --- a/webview-ui/src/utils/customIcons.tsx +++ b/webview-ui/src/utils/customIcons.tsx @@ -236,3 +236,103 @@ export const Brain01Icon = (props: React.SVGProps) => ( strokeLinejoin="round"> ) + +export const ChatSpark01Icon = (props: React.SVGProps) => ( + + + + + +) + +export const Copy01Icon = (props: React.SVGProps) => ( + + + + +) + +export const TickDouble02Icon = (props: React.SVGProps) => ( + + + + +) + +export const Tick02Icon = (props: React.SVGProps) => ( + + + +) From 3da391783a01448b9e7620d4ad7ac474beb608c9 Mon Sep 17 00:00:00 2001 From: code-crusher Date: Fri, 13 Feb 2026 17:19:01 +0530 Subject: [PATCH 06/12] sticky user messages --- webview-ui/src/components/chat/ChatRow.tsx | 12 +- webview-ui/src/components/chat/ChatView.tsx | 109 +++++++- .../components/kilocode/KiloTaskHeader.tsx | 242 +----------------- .../components/kilocode/StickyUserMessage.tsx | 126 +++++++++ webview-ui/src/index.css | 1 + 5 files changed, 255 insertions(+), 235 deletions(-) create mode 100644 webview-ui/src/components/kilocode/StickyUserMessage.tsx diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 4e430ca9bc..eed1c52824 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -59,6 +59,7 @@ import { PlayIcon } from "@/utils/customIcons" interface ChatRowProps { message: ClineMessage + messageIndex?: number // kilocode_change: for sticky message tracking lastModifiedMessage?: ClineMessage isExpanded: boolean isLast: boolean @@ -144,6 +145,7 @@ const computeDiffStats = (diff?: string | null) => { export const ChatRowContent = ({ message, + messageIndex, // kilocode_change: for sticky message tracking lastModifiedMessage, isExpanded, isLast, @@ -1463,17 +1465,17 @@ export const ChatRowContent = ({ ) case "user_feedback": return ( -
+
{/*
{t("chat:feedback.youSaid")}
*/}
@@ -1501,7 +1503,7 @@ export const ChatRowContent = ({
{ if (!isStreaming) { handleEditClick() diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index 7141a57d88..da842e4bec 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -64,6 +64,7 @@ import { ChatTextArea } from "./ChatTextArea" import { showSystemNotification } from "@/kilocode/helpers" // kilocode_change import BottomControls from "../kilocode/BottomControls" // kilocode_change import KiloTaskHeader from "../kilocode/KiloTaskHeader" // kilocode_change +import StickyUserMessage from "../kilocode/StickyUserMessage" // kilocode_change import AutoApproveMenu from "./AutoApproveMenu" import SystemPromptWarning from "./SystemPromptWarning" // import ProfileViolationWarning from "./ProfileViolationWarning" kilocode_change: unused @@ -257,6 +258,12 @@ const ChatViewComponent: React.ForwardRefRenderFunction(null) const userRespondedRef = useRef(false) const [currentFollowUpTs, setCurrentFollowUpTs] = useState(null) + // kilocode_change start: Sticky user message state + const [stickyMessageIndex, setStickyMessageIndex] = useState(null) + const stickyHeaderRef = useRef(null) + const virtuosoScrollerRef = useRef(null) + const [stickyHeaderHeight, setStickyHeaderHeight] = useState(0) + // kilocode_change end const [iconsBaseUri] = useState(() => { const w = window as any return w.ICONS_BASE_URI || "" @@ -1743,6 +1750,83 @@ const ChatViewComponent: React.ForwardRefRenderFunction { + const indices: number[] = [] + groupedMessages.forEach((msg, i) => { + if (!Array.isArray(msg) && msg.type === "say" && msg.say === "user_feedback") { + indices.push(i) + } + }) + return indices + }, [groupedMessages]) + + useEffect(() => { + const scroller = virtuosoScrollerRef.current + if (!scroller) return + + const handleScroll = () => { + if (userFeedbackIndices.length === 0) { + setStickyMessageIndex(null) + return + } + + const stickyHeight = stickyHeaderRef.current?.offsetHeight ?? 40 + const scrollerRect = scroller.getBoundingClientRect() + const threshold = scrollerRect.top + stickyHeight + + let bestIndex: number | null = null + let passedRenderedRegion = false + + for (const idx of userFeedbackIndices) { + const el = scroller.querySelector(`[data-item-index="${idx}"]`) as HTMLElement | null + + if (!el) { + if (passedRenderedRegion) { + // Past the rendered region — below viewport, stop + break + } + // Not yet in rendered region — above viewport (scrolled past) + bestIndex = idx + continue + } + + passedRenderedRegion = true + const elTop = el.getBoundingClientRect().top + if (elTop <= threshold) { + bestIndex = idx + } else { + // Below the threshold, everything after will be too + break + } + } + + setStickyMessageIndex(bestIndex) + } + + scroller.addEventListener("scroll", handleScroll, { passive: true }) + handleScroll() // Initial check + return () => scroller.removeEventListener("scroll", handleScroll) + }, [userFeedbackIndices]) + + // Track sticky header height with ResizeObserver so list items don't hide behind it + useEffect(() => { + const el = stickyHeaderRef.current + if (!el) { + setStickyHeaderHeight(0) + return + } + + const updateHeight = () => setStickyHeaderHeight(el.offsetHeight) + updateHeight() + + const observer = new ResizeObserver(updateHeight) + observer.observe(el) + return () => observer.disconnect() + }, [task?.ts]) // re-run when task mounts/changes + // kilocode_change end + // Effect to handle showing the checkpoint warning after a delay useEffect(() => { // Only show the warning when there's a task but no visible messages yet @@ -2174,7 +2258,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction - {/* kilocode_change start */} {hasSystemPromptOverride && (
@@ -2335,7 +2418,19 @@ const ChatViewComponent: React.ForwardRefRenderFunction -
+
+ {/* kilocode_change: Sticky user message - positioned outside Virtuoso for true sticky behavior */} +
+
+ +
+
, + }} atBottomStateChange={(isAtBottom: boolean) => { setIsAtBottom(isAtBottom) if (isAtBottom) { @@ -2353,6 +2452,12 @@ const ChatViewComponent: React.ForwardRefRenderFunction { + if (ref instanceof HTMLElement) { + virtuosoScrollerRef.current = ref + } + }} />
diff --git a/webview-ui/src/components/kilocode/KiloTaskHeader.tsx b/webview-ui/src/components/kilocode/KiloTaskHeader.tsx index 02549bb3cd..5d3e6213af 100644 --- a/webview-ui/src/components/kilocode/KiloTaskHeader.tsx +++ b/webview-ui/src/components/kilocode/KiloTaskHeader.tsx @@ -1,16 +1,11 @@ // kilocode_change: new file -import { memo, useRef, useState } from "react" +import { memo } from "react" import type { ClineMessage } from "@roo-code/types" -import { useSelectedModel } from "@/components/ui/hooks/useSelectedModel" -import { useExtensionState } from "@src/context/ExtensionStateContext" import { cn } from "@src/lib/utils" -import Thumbnails from "../common/Thumbnails" -import { ReadOnlyChatText } from "../chat/ReadOnlyChatText" - -import { TodoListDisplay } from "../chat/TodoListDisplay" +// import { TodoListDisplay } from "../chat/TodoListDisplay" export interface TaskHeaderProps { task: ClineMessage @@ -20,252 +15,43 @@ export interface TaskHeaderProps { cacheReads?: number totalCost: number contextTokens: number - // buttonsDisabled: boolean handleCondenseContext: (taskId: string) => void onClose: () => void groupedMessages: (ClineMessage | ClineMessage[])[] onMessageClick?: (index: number) => void isTaskActive?: boolean todos?: any[] - title?: string // kilocode_change: Task title from backend + title?: string } const KiloTaskHeader = ({ - task, - // tokensIn, - // tokensOut, - // cacheWrites, - // cacheReads, - // totalCost, - // contextTokens, - // buttonsDisabled, - // handleCondenseContext, onClose, - // groupedMessages, - // onMessageClick, - // isTaskActive = false, - todos, + // todos, title, }: TaskHeaderProps) => { - // const { t } = useTranslation() - // const { showTaskTimeline } = useExtensionState() - const { apiConfiguration } = useExtensionState() - const { info: model } = useSelectedModel(apiConfiguration) - const [isTaskExpanded, setIsTaskExpanded] = useState(false) - - const textContainerRef = useRef(null) - const textRef = useRef(null) - const contextWindow = model?.contextWindow || 1 - - // const { width: windowWidth } = useWindowSize() - - // const condenseButton = ( - // - // - // - // ) - - // const hasTodos = todos && Array.isArray(todos) && todos.length > 0 - return (
- {/* kilocode_change: Show title with X button at the top */} - {title && ( -
-
- {title} -
- -
- )} + {/* Title with close button */}
-
setIsTaskExpanded(!isTaskExpanded)}> - {/*
- -
*/} -
- {/* - {t("chat:task.title")} - {!isTaskExpanded && ":"} - */} - {!isTaskExpanded && ( -
- -
- )} -
+
+ {title || "New task"}
- {/* - - */} +
- {/* Collapsed state: Track context and cost if we have any */} - {!isTaskExpanded && contextWindow > 0 && ( -
- {/* {showTaskTimeline && ( - - )} */} - - {/*
- - {condenseButton} - - {!!totalCost && ${totalCost.toFixed(2)}} -
*/} -
- )} - {/* Expanded state: Show task text and images */} - {isTaskExpanded && ( - <> -
setIsTaskExpanded(!isTaskExpanded)} - ref={textContainerRef} - className="text-vscode-font-size overflow-y-auto break-words break-anywhere relative"> -
- -
-
- {task.images && task.images.length > 0 && } - - {/* {showTaskTimeline && ( - - )} */} - - {/*
- {isTaskExpanded && contextWindow > 0 && ( -
-
- - {t("chat:task.contextWindow")} - -
- - {condenseButton} -
- )} -
-
- {t("chat:task.tokens")} - {typeof tokensIn === "number" && tokensIn > 0 && ( - - - {formatLargeNumber(tokensIn)} - - )} - {typeof tokensOut === "number" && tokensOut > 0 && ( - - - {formatLargeNumber(tokensOut)} - - )} -
- {!totalCost && } -
- - {((typeof cacheReads === "number" && cacheReads > 0) || - (typeof cacheWrites === "number" && cacheWrites > 0)) && ( -
- {t("chat:task.cache")} - {typeof cacheWrites === "number" && cacheWrites > 0 && ( - - - {formatLargeNumber(cacheWrites)} - - )} - {typeof cacheReads === "number" && cacheReads > 0 && ( - - - {formatLargeNumber(cacheReads)} - - )} -
- )} - - {!!totalCost && ( -
-
- {t("chat:task.apiCost")} - ${totalCost?.toFixed(2)} -
- -
- )} -
*/} - - )}
- + {/* */}
) } diff --git a/webview-ui/src/components/kilocode/StickyUserMessage.tsx b/webview-ui/src/components/kilocode/StickyUserMessage.tsx new file mode 100644 index 0000000000..5e93b6f8b1 --- /dev/null +++ b/webview-ui/src/components/kilocode/StickyUserMessage.tsx @@ -0,0 +1,126 @@ +// kilocode_change: new file - Sticky user message component for chat +import { memo, useState } from "react" +import type { ClineMessage } from "@roo-code/types" +import { ReadOnlyChatText } from "../chat/ReadOnlyChatText" +import { cn } from "@src/lib/utils" + +export interface StickyUserMessageProps { + task: ClineMessage + messages: (ClineMessage | ClineMessage[])[] + stickyIndex: number | null +} + +/** + * StickyUserMessage - Displays the current "sticky" user message. + * + * This works like sticky headers on mobile UI: + * - Shows the initial prompt (task.text) by default + * - As user scrolls, it tracks which user message should be sticky + * - Uses CSS position: sticky to stay at the top of the scroll container + */ +const StickyUserMessage = ({ task, messages, stickyIndex }: StickyUserMessageProps) => { + const [isExpanded, setIsExpanded] = useState(false) + + // Get the message to display based on stickyIndex + // stickyIndex: null = task prompt, number = index in messages array (groupedMessages) + const getStickyMessage = () => { + // If stickyIndex is null, show the initial task prompt + if (stickyIndex === null) { + return { + text: task?.text, + images: task?.images, + } + } + + // Find the user_feedback message at the given index in groupedMessages + const msg = messages[stickyIndex] + + if (!msg || Array.isArray(msg)) { + return { + text: task?.text, + images: task?.images, + } + } + + if (msg.type === "say" && msg.say === "user_feedback") { + return { + text: msg.text, + images: msg.images, + } + } + + // Fallback to task prompt + return { + text: task?.text, + images: task?.images, + } + } + + const stickyMessage = getStickyMessage() + + if (!stickyMessage?.text && !stickyMessage?.images?.length) { + return null + } + + return ( +
+
setIsExpanded(!isExpanded)}> +
+ {!isExpanded ? ( +
+ +
+ ) : ( +
+ +
+ )} +
+
+ {isExpanded && stickyMessage.images && stickyMessage.images.length > 0 && ( +
+ {stickyMessage.images.slice(0, 4).map((img, i) => ( + {`Image + ))} + {stickyMessage.images.length > 4 && ( + +{stickyMessage.images.length - 4} more + )} +
+ )} +
+ ) +} + +export default memo(StickyUserMessage) diff --git a/webview-ui/src/index.css b/webview-ui/src/index.css index ba2762b4b2..78f5b0388c 100644 --- a/webview-ui/src/index.css +++ b/webview-ui/src/index.css @@ -152,6 +152,7 @@ --color-matterai-chip-blue: #8bf4f720; --color-matterai-yellow: #fff0ac; --color-matterai-blue-dark: #1a3b59; + --color-matterai-background-dark: #15181c; } @layer base { From a5116a27aa8183acf9718ebfb639c014c79a0c16 Mon Sep 17 00:00:00 2001 From: code-crusher Date: Fri, 13 Feb 2026 18:13:19 +0530 Subject: [PATCH 07/12] fix auto model naming --- packages/types/src/codebase-index.ts | 4 ++-- src/api/providers/kilocode-models.ts | 2 +- src/api/providers/openrouter.ts | 3 --- webview-ui/src/components/chat/ChatView.tsx | 2 +- .../src/components/ui/hooks/useOpenRouterModelProviders.ts | 2 +- webview-ui/src/utils/prettyModelName.ts | 2 +- 6 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/types/src/codebase-index.ts b/packages/types/src/codebase-index.ts index 636fb3f2c3..8dcb549984 100644 --- a/packages/types/src/codebase-index.ts +++ b/packages/types/src/codebase-index.ts @@ -5,8 +5,8 @@ import { z } from "zod" */ export const CODEBASE_INDEX_DEFAULTS = { MIN_SEARCH_RESULTS: 10, - MAX_SEARCH_RESULTS: 5, - DEFAULT_SEARCH_RESULTS: 5, + MAX_SEARCH_RESULTS: 2, + DEFAULT_SEARCH_RESULTS: 2, SEARCH_RESULTS_STEP: 10, MIN_SEARCH_SCORE: 0.5, MAX_SEARCH_SCORE: 1, diff --git a/src/api/providers/kilocode-models.ts b/src/api/providers/kilocode-models.ts index 80daa78b94..1bdcd73e51 100644 --- a/src/api/providers/kilocode-models.ts +++ b/src/api/providers/kilocode-models.ts @@ -27,7 +27,7 @@ export type KiloCodeModel = { } export const KILO_CODE_MODELS: Record = { - auto: { + "axon-auto": { id: "axon-auto", name: "Auto", description: "Auto is a model that automatically selects the best model for the task", diff --git a/src/api/providers/openrouter.ts b/src/api/providers/openrouter.ts index d72eaf3f30..e7dd17d0cd 100644 --- a/src/api/providers/openrouter.ts +++ b/src/api/providers/openrouter.ts @@ -228,14 +228,12 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH this.customRequestOptions(metadata), // kilocode_change ) } catch (error) { - // kilocode_change start if (this.providerName == "KiloCode" && isAnyRecognizedKiloCodeError(error)) { throw error } const err = new Error(makeOpenRouterErrorReadable(error)) as any err.status = error?.status || error?.code throw err - // kilocode_change end } let lastUsage: CompletionUsage | undefined = undefined @@ -243,7 +241,6 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH try { let fullContent = "" - let fullReasoning = "" // kilocode_change: variable kept for structural integrity if needed, but unused logs removed let isThinking = false diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index da842e4bec..b803af0ff1 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -2326,7 +2326,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction

- Setup Automated PR Reviews + Setup Agentic PR Reviews

= { - auto: { + "axon-auto": { id: "axon-auto", name: "Auto", description: "Auto is a model that automatically selects the best model for the task", diff --git a/webview-ui/src/utils/prettyModelName.ts b/webview-ui/src/utils/prettyModelName.ts index 731769ff52..09266e46c4 100644 --- a/webview-ui/src/utils/prettyModelName.ts +++ b/webview-ui/src/utils/prettyModelName.ts @@ -1,6 +1,6 @@ // Hardcoded credits information for Axon models const AXON_MODEL_CREDITS: Record = { - auto: "(0.25x)", + "axon-auto": "(0.25x)", "axon-code": "(0.5x)", "axon-code-2": "(1x)", "axon-code-2-pro": "(1.5x)", From bbbec0e70011cc1b2ed8b16923c890a4ce8614c4 Mon Sep 17 00:00:00 2001 From: code-crusher Date: Fri, 13 Feb 2026 19:08:06 +0530 Subject: [PATCH 08/12] improve codebase indexing tool UI --- webview-ui/src/components/chat/ChatRow.tsx | 1 - .../src/components/chat/CodebaseSearchResult.tsx | 13 +++++++++---- .../chat/CodebaseSearchResultsDisplay.tsx | 2 +- webview-ui/src/i18n/locales/en/chat.json | 4 ++-- webview-ui/src/index.css | 9 ++++++--- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index eed1c52824..5c023ad7d7 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -1472,7 +1472,6 @@ export const ChatRowContent = ({
*/}
= ({ filePath, score, startLine, endLine }) => { +const CodebaseSearchResult: React.FC = ({ + filePath, + // score, + startLine, + endLine, +}) => { // const { _t } = useTranslation("chat") const handleClick = () => { @@ -29,7 +34,7 @@ const CodebaseSearchResult: React.FC = ({ filePath, s //
+ className="px-2 py-1 rounded-md text-sm cursor-pointer hover:bg-[var(--color-matterai-background-dark)] hover:text-white">
{filePath.split("/").at(-1)}:{startLine === endLine ? startLine : `${startLine}-${endLine}`} @@ -37,9 +42,9 @@ const CodebaseSearchResult: React.FC = ({ filePath, s {filePath.split("/").slice(0, -1).join("/")} - + {/* {score.toFixed(3)} - + */}
//
diff --git a/webview-ui/src/components/chat/CodebaseSearchResultsDisplay.tsx b/webview-ui/src/components/chat/CodebaseSearchResultsDisplay.tsx index eb594af100..c14e8dc291 100644 --- a/webview-ui/src/components/chat/CodebaseSearchResultsDisplay.tsx +++ b/webview-ui/src/components/chat/CodebaseSearchResultsDisplay.tsx @@ -19,7 +19,7 @@ const CodebaseSearchResultsDisplay: React.FC
setCodebaseSearchResultsExpanded(!codebaseSearchResultsExpanded)} - className="cursor-pointer flex items-center justify-between px-2 py-2 border bg-[var(--vscode-editor-background)] border-[var(--vscode-editorGroup-border)] rounded-lg"> + className="cursor-pointer flex items-center justify-between px-2 py-1.5 bg-[var(--vscode-editor-background)] rounded-lg"> {{regex}}" }, "codebaseSearch": { - "wantsToSearch": "searching codebase for {{query}}", - "wantsToSearchWithPath": "searching codebase for {{query}} in {{path}}", + "wantsToSearch": "Exploring {{query}}", + "wantsToSearchWithPath": "Exploring {{query}} in {{path}}", "didSearch_one": "Found 1 result", "didSearch_other": "Found {{count}} results", "resultTooltip": "Similarity score: {{score}} (click to open file)" diff --git a/webview-ui/src/index.css b/webview-ui/src/index.css index 78f5b0388c..ebe98f9512 100644 --- a/webview-ui/src/index.css +++ b/webview-ui/src/index.css @@ -215,9 +215,12 @@ /* Code Block Styles */ pre, code { - background-color: var(--vscode-input-background) !important; - padding-left: 0.1rem; - padding-right: 0.1rem; + font-family: "Consolas", "Monaco", "Courier New", monospace; + font-size: 0.9em; + color: var(--color-matterai-green); + background-color: var(--vscode-input-background); + padding: 0.2em 0.4em; + border-radius: 3px; } /* Search result highlighting */ From 835c88f9db7b76615930078c945665f6e3bb5814 Mon Sep 17 00:00:00 2001 From: code-crusher Date: Fri, 13 Feb 2026 19:33:33 +0530 Subject: [PATCH 09/12] improve task history list --- src/shared/kilocode/getTaskHistory.ts | 2 +- webview-ui/src/components/history/HistoryView.tsx | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/shared/kilocode/getTaskHistory.ts b/src/shared/kilocode/getTaskHistory.ts index 8d05f6b73c..ce4f30817c 100644 --- a/src/shared/kilocode/getTaskHistory.ts +++ b/src/shared/kilocode/getTaskHistory.ts @@ -3,7 +3,7 @@ import { HistoryItem } from "@roo-code/types" import { highlightFzfMatch } from "../../../webview-ui/src/utils/highlight" // weird hack, but apparently it works import { TaskHistoryRequestPayload, TaskHistoryResponsePayload } from "../WebviewMessage" -const PAGE_SIZE = 10 +const PAGE_SIZE = 20 export function getTaskHistory( taskHistory: HistoryItem[], diff --git a/webview-ui/src/components/history/HistoryView.tsx b/webview-ui/src/components/history/HistoryView.tsx index fef1c8a792..d0515bfebc 100644 --- a/webview-ui/src/components/history/HistoryView.tsx +++ b/webview-ui/src/components/history/HistoryView.tsx @@ -247,7 +247,7 @@ const HistoryView = ({ onDone }: HistoryViewProps) => {
- + { isSelected={selectedTaskIds.includes(item.id)} onToggleSelection={toggleTaskSelection} onDelete={setDeleteTaskId} - className="m-2" /> )} /> From 6f0107a1e5c606667f8671f667e04b8af3d1fa7f Mon Sep 17 00:00:00 2001 From: code-crusher Date: Fri, 13 Feb 2026 21:56:13 +0530 Subject: [PATCH 10/12] Update notifications integration and related files --- .github/ISSUE_TEMPLATE/config.yml | 2 +- .../.kilocode/rules/memory-bank/tech.md | 2 +- .../docs/getting-started/installing.md | 4 +- .../docs/seats/getting-started.md | 2 +- .../current/getting-started/installing.md | 4 +- .../docusaurus-theme-classic/footer.json | 2 +- apps/kilocode-docs/src/constants.ts | 2 +- .../playwright-e2e/helpers/webview-helpers.ts | 2 +- .../tests/playwright-base-test.ts | 4 +- apps/vscode-e2e/.vscode-test.mjs | 2 +- apps/vscode-e2e/src/suite/index.ts | 2 +- benchmark/src/runExercise.ts | 2 +- cli/src/host/VSCode.ts | 2 +- scripts/reset-kilocode-state.sh | 6 +- src/core/tools/reportBugTool.ts | 2 +- src/extension.ts | 2 +- .../notifications/__tests__/index.spec.ts | 57 ++++++++++++------- src/integrations/notifications/index.ts | 51 ++++++++++++----- webview-ui/src/index.css | 9 +-- 19 files changed, 98 insertions(+), 61 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 69a9e8d249..6b527ef777 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -7,7 +7,7 @@ contact_links: url: https://github.com/MatterAIOrg/AxonCode/discussions/categories/2-design-improvements about: Suggestions for better design (where the current UI/UX is not clear). - name: Leave a Review - url: https://marketplace.visualstudio.com/items?itemName=kilocode.Kilo-Code&ssr=false#review-details + url: https://marketplace.visualstudio.com/items?itemName=matterai.axon-code&ssr=false#review-details about: Enjoying Axon Code? Leave a review here! - name: Join our Discord url: https://discord.gg/fJU5DvanU3 diff --git a/apps/kilocode-docs/.kilocode/rules/memory-bank/tech.md b/apps/kilocode-docs/.kilocode/rules/memory-bank/tech.md index c1ad17360d..c2a8bf17e0 100644 --- a/apps/kilocode-docs/.kilocode/rules/memory-bank/tech.md +++ b/apps/kilocode-docs/.kilocode/rules/memory-bank/tech.md @@ -110,7 +110,7 @@ npx docusaurus build ### VS Code Marketplace -- **Extension URL**: https://marketplace.visualstudio.com/items?itemName=kilocode.kilo-code +- **Extension URL**: https://marketplace.visualstudio.com/items?itemName=matterai.axon-code - **Open VSX**: https://open-vsx.org/extension/kilocode/kilo-code ## Deployment Architecture diff --git a/apps/kilocode-docs/docs/getting-started/installing.md b/apps/kilocode-docs/docs/getting-started/installing.md index bc52553004..11657fafa5 100644 --- a/apps/kilocode-docs/docs/getting-started/installing.md +++ b/apps/kilocode-docs/docs/getting-started/installing.md @@ -15,7 +15,7 @@ Axon Code is a VS Code extension that brings AI-powered coding assistance direct :::tip -If you already have VS Code installed: [Click here to install Axon Code](vscode:extension/kilocode.Kilo-Code) +If you already have VS Code installed: [Click here to install Axon Code](vscode:extension/matterai.axon-code) ::: @@ -36,7 +36,7 @@ After installation, find the Axon Code icon ( { const webviewFrameEl = workbox.frameLocator( - 'iframe[src*="extensionId=kilocode.kilo-code"][src*="purpose=webviewView"]', + 'iframe[src*="extensionId=matterai.axon-code"][src*="purpose=webviewView"]', ) await webviewFrameEl.locator("#active-frame") return webviewFrameEl.frameLocator("#active-frame") diff --git a/apps/playwright-e2e/tests/playwright-base-test.ts b/apps/playwright-e2e/tests/playwright-base-test.ts index 52c958ed45..cfc3498a5c 100644 --- a/apps/playwright-e2e/tests/playwright-base-test.ts +++ b/apps/playwright-e2e/tests/playwright-base-test.ts @@ -69,7 +69,7 @@ export const test = base.extend({ "--disable-crash-reporter", "--enable-logging", "--log-level=0", - "--disable-extensions-except=kilocode.kilo-code", + "--disable-extensions-except=matterai.axon-code", "--disable-extension-recommendations", "--disable-extension-update-check", "--disable-default-apps", @@ -79,7 +79,7 @@ export const test = base.extend({ `--extensionDevelopmentPath=${path.resolve(__dirname, "..", "..", "..", "src")}`, `--extensions-dir=${path.join(defaultCachePath, "extensions")}`, `--user-data-dir=${userDataDir}`, - "--enable-proposed-api=kilocode.kilo-code", + "--enable-proposed-api=matterai.axon-code", await createProject(), ], }) diff --git a/apps/vscode-e2e/.vscode-test.mjs b/apps/vscode-e2e/.vscode-test.mjs index 42149d118b..0a3d99b460 100644 --- a/apps/vscode-e2e/.vscode-test.mjs +++ b/apps/vscode-e2e/.vscode-test.mjs @@ -12,5 +12,5 @@ export default defineConfig({ ui: "tdd", timeout: 60000, }, - launchArgs: ["--enable-proposed-api=kilocode.Kilo-Code", "--disable-extensions"], + launchArgs: ["--enable-proposed-api=matterai.axon-code", "--disable-extensions"], }) diff --git a/apps/vscode-e2e/src/suite/index.ts b/apps/vscode-e2e/src/suite/index.ts index 4268de7b4a..ce131d8fbb 100644 --- a/apps/vscode-e2e/src/suite/index.ts +++ b/apps/vscode-e2e/src/suite/index.ts @@ -8,7 +8,7 @@ import type { RooCodeAPI } from "@roo-code/types" import { waitFor } from "./utils" export async function run() { - const extension = vscode.extensions.getExtension("kilocode.kilo-code") + const extension = vscode.extensions.getExtension("matterai.axon-code") if (!extension) { throw new Error("Extension not found") diff --git a/benchmark/src/runExercise.ts b/benchmark/src/runExercise.ts index cf6cdca330..350d6a717d 100644 --- a/benchmark/src/runExercise.ts +++ b/benchmark/src/runExercise.ts @@ -28,7 +28,7 @@ export async function run() { * Activate the extension. */ - const extension = vscode.extensions.getExtension("kilocode.Kilo-Code") + const extension = vscode.extensions.getExtension("matterai.axon-code") if (!extension) { throw new Error("Extension not found.") diff --git a/cli/src/host/VSCode.ts b/cli/src/host/VSCode.ts index 052eb74e77..4201b28ea2 100644 --- a/cli/src/host/VSCode.ts +++ b/cli/src/host/VSCode.ts @@ -2068,7 +2068,7 @@ export function createVSCodeAPIMock(extensionRootPath: string, workspacePath: st all: [], getExtension: (extensionId: string) => { // Mock the extension object with extensionUri for theme loading - if (extensionId === "kilocode.kilo-code") { + if (extensionId === "matterai.axon-code") { return { id: extensionId, extensionUri: context.extensionUri, diff --git a/scripts/reset-kilocode-state.sh b/scripts/reset-kilocode-state.sh index 9aeaeb69bf..f316f78af7 100755 --- a/scripts/reset-kilocode-state.sh +++ b/scripts/reset-kilocode-state.sh @@ -5,12 +5,12 @@ echo "Kilocode state is being reset. This probably doesn't work while VS Code i # Reset the secrets: sqlite3 ~/Library/Application\ Support/Code/User/globalStorage/state.vscdb \ "DELETE FROM ItemTable WHERE \ - key = 'kilocode.kilo-code' OR \ + key = 'matterai.axon-code' OR \ key LIKE 'workbench.view.extension.kilo-code%' OR \ - key LIKE 'secret://{\"extensionId\":\"kilocode.kilo-code\",%';" + key LIKE 'secret://{\"extensionId\":\"matterai.axon-code\",%';" # delete all kilocode state files: -rm -rf ~/Library/Application\ Support/Code/User/globalStorage/kilocode.kilo-code/ +rm -rf ~/Library/Application\ Support/Code/User/globalStorage/matterai.axon-code/ # clear some of the vscode cache that I've observed contains kilocode related entries: rm -f ~/Library/Application\ Support/Code/CachedProfilesData/__default__profile__/extensions.user.cache diff --git a/src/core/tools/reportBugTool.ts b/src/core/tools/reportBugTool.ts index 699c81fc0f..92aae1895e 100644 --- a/src/core/tools/reportBugTool.ts +++ b/src/core/tools/reportBugTool.ts @@ -49,7 +49,7 @@ export async function reportBugTool( // Derive system information values algorithmically const operatingSystem = os.platform() + " " + os.release() const kilocodeVersion = - vscode.extensions.getExtension("kilocode.kilo-code")?.packageJSON.version || "Unknown" + vscode.extensions.getExtension("matterai.axon-code")?.packageJSON.version || "Unknown" const systemInfo = `VSCode: ${vscode.version}, Node.js: ${process.version}, Architecture: ${os.arch()}` const providerAndModel = `${(await cline.providerRef.deref()?.contextProxy.getGlobalState("apiProvider")) as string} / ${cline.api.getModel().id}` diff --git a/src/extension.ts b/src/extension.ts index dbbc13b687..5c333993c3 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -256,7 +256,7 @@ export async function activate(context: vscode.ExtensionContext) { // https://discord.com/channels/1349288496988160052/1395865796026040470 await vscode.commands.executeCommand( "workbench.action.openWalkthrough", - "kilocode.kilo-code#kiloCodeWalkthrough", + "matterai.axon-code#kiloCodeWalkthrough", false, ) } catch (error) { diff --git a/src/integrations/notifications/__tests__/index.spec.ts b/src/integrations/notifications/__tests__/index.spec.ts index fdaa78eefa..dc6040146a 100644 --- a/src/integrations/notifications/__tests__/index.spec.ts +++ b/src/integrations/notifications/__tests__/index.spec.ts @@ -24,14 +24,23 @@ vi.mock("vscode", () => ({ fsPath: path.join(__dirname, "..", "..", "..", ...pathSegments), })), }, + env: { + appName: "Visual Studio Code", + }, + window: { + showInformationMessage: vi.fn().mockResolvedValue(undefined), + }, })) // Import after mocking import { showSystemNotification } from "../index" import * as os from "os" +import * as vscode from "vscode" const mockedExeca = vi.mocked(execa) const mockedPlatform = vi.mocked(os.platform) +const mockedGetExtension = vi.mocked(vscode.extensions.getExtension) +const mockedShowInformationMessage = vi.mocked(vscode.window.showInformationMessage) describe("showSystemNotification", () => { beforeEach(() => { @@ -66,15 +75,15 @@ describe("showSystemNotification", () => { "Tink", "-appIcon", expectedIconPath, + "-activate", + "com.microsoft.VSCode", ]) expect(mockedExeca).toHaveBeenCalledTimes(1) }) - it("should fall back to osascript when terminal-notifier fails", async () => { - // First call (terminal-notifier) fails + it("should fall back to VS Code notification when terminal-notifier fails", async () => { + // terminal-notifier fails mockedExeca.mockRejectedValueOnce(new Error("terminal-notifier not found")) - // Second call (osascript) succeeds - mockedExeca.mockResolvedValueOnce({} as any) await showSystemNotification({ title: "Test Title", @@ -83,8 +92,8 @@ describe("showSystemNotification", () => { }) const expectedIconPath = path.join(__dirname, "..", "..", "..", "assets", "icons", "matterai-ic.png") - expect(mockedExeca).toHaveBeenCalledTimes(2) - expect(mockedExeca).toHaveBeenNthCalledWith(1, "terminal-notifier", [ + expect(mockedExeca).toHaveBeenCalledTimes(1) + expect(mockedExeca).toHaveBeenCalledWith("terminal-notifier", [ "-message", "Test Message", "-title", @@ -95,11 +104,11 @@ describe("showSystemNotification", () => { "Tink", "-appIcon", expectedIconPath, + "-activate", + "com.microsoft.VSCode", ]) - expect(mockedExeca).toHaveBeenNthCalledWith(2, "osascript", [ - "-e", - 'display notification "Test Message" with title "Test Title" subtitle "Test Subtitle" sound name "Tink"', - ]) + // Should fall back to VS Code notification + expect(mockedShowInformationMessage).toHaveBeenCalledWith("Test Title: Test Subtitle: Test Message") }) it("should handle terminal-notifier with minimal options", async () => { @@ -119,6 +128,8 @@ describe("showSystemNotification", () => { "Tink", "-appIcon", expectedIconPath, + "-activate", + "com.microsoft.VSCode", ]) }) @@ -140,6 +151,8 @@ describe("showSystemNotification", () => { "Tink", "-appIcon", expectedIconPath, + "-activate", + "com.microsoft.VSCode", ]) }) @@ -164,14 +177,14 @@ describe("showSystemNotification", () => { "Tink", "-appIcon", expectedIconPath, + "-activate", + "com.microsoft.VSCode", ]) }) - it("should fall back to osascript and escape quotes properly", async () => { + it("should fall back to VS Code notification and handle quotes properly", async () => { // terminal-notifier fails mockedExeca.mockRejectedValueOnce(new Error("not found")) - // osascript succeeds - mockedExeca.mockResolvedValueOnce({} as any) await showSystemNotification({ title: 'Title with "quotes"', @@ -179,22 +192,22 @@ describe("showSystemNotification", () => { message: 'Message with "quotes"', }) - expect(mockedExeca).toHaveBeenNthCalledWith(2, "osascript", [ - "-e", - 'display notification "Message with \\"quotes\\"" with title "Title with \\"quotes\\"" subtitle "Subtitle with \\"quotes\\"" sound name "Tink"', - ]) + // Should fall back to VS Code notification with escaped quotes + expect(mockedShowInformationMessage).toHaveBeenCalledWith( + 'Title with \\"quotes\\": Subtitle with \\"quotes\\": Message with \\"quotes\\"', + ) }) - it("should throw error when both terminal-notifier and osascript fail", async () => { - // Both calls fail + it("should fall back to VS Code notification when terminal-notifier fails repeatedly", async () => { + // terminal-notifier fails mockedExeca.mockRejectedValue(new Error("Command failed")) await showSystemNotification({ message: "Test Message", }) - // Should not throw but log error to console - expect(console.error).toHaveBeenCalledWith("Could not show system notification", expect.any(Error)) + // Should fall back to VS Code notification + expect(mockedShowInformationMessage).toHaveBeenCalledWith("Axon Code: Test Message") }) }) @@ -279,6 +292,8 @@ describe("showSystemNotification", () => { "Tink", "-appIcon", expectedIconPath, + "-activate", + "com.microsoft.VSCode", ]) }) }) diff --git a/src/integrations/notifications/index.ts b/src/integrations/notifications/index.ts index 333b8328c4..a2f3ffba1b 100644 --- a/src/integrations/notifications/index.ts +++ b/src/integrations/notifications/index.ts @@ -8,6 +8,30 @@ interface NotificationOptions { message: string } +/** + * Get the bundle ID for the current VS Code-based editor + * Used to activate the correct app when clicking notifications + */ +function getEditorBundleId(): string { + const appName = vscode.env.appName.toLowerCase() + + // Map editor names to their bundle IDs + if (appName.includes("cursor")) { + return "com.todesktop.230313mzl4w4u92" + } + if (appName.includes("insiders")) { + return "com.microsoft.VSCodeInsiders" + } + if (appName.includes("vscodium")) { + return "com.visualstudio.code.oss" + } + if (appName.includes("windsurf")) { + return "com.codeium.windsurf" + } + // Default to VS Code + return "com.microsoft.VSCode" +} + async function showMacOSNotification(options: NotificationOptions): Promise { const { title, subtitle = "", message } = options @@ -23,25 +47,26 @@ async function showMacOSNotification(options: NotificationOptions): Promise { diff --git a/webview-ui/src/index.css b/webview-ui/src/index.css index ebe98f9512..78f5b0388c 100644 --- a/webview-ui/src/index.css +++ b/webview-ui/src/index.css @@ -215,12 +215,9 @@ /* Code Block Styles */ pre, code { - font-family: "Consolas", "Monaco", "Courier New", monospace; - font-size: 0.9em; - color: var(--color-matterai-green); - background-color: var(--vscode-input-background); - padding: 0.2em 0.4em; - border-radius: 3px; + background-color: var(--vscode-input-background) !important; + padding-left: 0.1rem; + padding-right: 0.1rem; } /* Search result highlighting */ From 6b9b498d061c93c7a157fca22dc056d98d6de798 Mon Sep 17 00:00:00 2001 From: code-crusher Date: Sat, 14 Feb 2026 00:59:34 +0530 Subject: [PATCH 11/12] fix: address review comments for sticky header and usage percentage - ChatView.tsx: Fix sticky header logic for virtualized list by checking first rendered index to correctly determine if missing elements are above or below viewport - KiloCode.tsx: Add division-by-zero guard for usagePercentage calculation --- webview-ui/src/components/chat/ChatView.tsx | 19 ++++++++++++------- .../kilocode/settings/providers/KiloCode.tsx | 4 +++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index b803af0ff1..1f0ba8d6d7 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -1776,23 +1776,28 @@ const ChatViewComponent: React.ForwardRefRenderFunction Above viewport + bestIndex = idx + continue + } else { + // Not in DOM and index is higher -> Below viewport break } - // Not yet in rendered region — above viewport (scrolled past) - bestIndex = idx - continue } - passedRenderedRegion = true const elTop = el.getBoundingClientRect().top if (elTop <= threshold) { bestIndex = idx diff --git a/webview-ui/src/components/kilocode/settings/providers/KiloCode.tsx b/webview-ui/src/components/kilocode/settings/providers/KiloCode.tsx index dad01bebf9..88c7fef0c4 100644 --- a/webview-ui/src/components/kilocode/settings/providers/KiloCode.tsx +++ b/webview-ui/src/components/kilocode/settings/providers/KiloCode.tsx @@ -99,7 +99,9 @@ export const KiloCode = ({ const usagePercentage = profileData?.usagePercentage !== undefined ? profileData.usagePercentage - : profileData?.usedCredits !== undefined && profileData?.totalCredits !== undefined + : profileData?.usedCredits !== undefined && + profileData?.totalCredits !== undefined && + profileData.totalCredits > 0 ? (profileData.usedCredits / profileData.totalCredits) * 100 : null From 3051a55e086ee1af9f291b1146d932513184d674 Mon Sep 17 00:00:00 2001 From: code-crusher Date: Sat, 14 Feb 2026 01:05:54 +0530 Subject: [PATCH 12/12] hide scrollbar --- webview-ui/src/components/chat/ChatView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index 1f0ba8d6d7..ff71dcc755 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -2439,7 +2439,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction