diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx index e3a2e3f721b..c616d9dc936 100644 --- a/packages/app/src/components/settings-general.tsx +++ b/packages/app/src/components/settings-general.tsx @@ -418,7 +418,7 @@ export const SettingsGeneral: Component = () => { return (
-
+

{language.t("settings.tab.general")}

diff --git a/packages/app/src/components/settings-keybinds.tsx b/packages/app/src/components/settings-keybinds.tsx index bcc731af99f..94bc76d76a0 100644 --- a/packages/app/src/components/settings-keybinds.tsx +++ b/packages/app/src/components/settings-keybinds.tsx @@ -370,7 +370,7 @@ export const SettingsKeybinds: Component = () => { return (
-
+

{language.t("settings.shortcuts.title")}

diff --git a/packages/app/src/components/settings-models.tsx b/packages/app/src/components/settings-models.tsx index 3a0b7a4fb1b..07f6d30e184 100644 --- a/packages/app/src/components/settings-models.tsx +++ b/packages/app/src/components/settings-models.tsx @@ -59,7 +59,7 @@ export const SettingsModels: Component = () => { return (
-
+

{language.t("settings.models.title")}

diff --git a/packages/app/src/components/settings-permissions.tsx b/packages/app/src/components/settings-permissions.tsx index 348854491ab..5c922ba44a4 100644 --- a/packages/app/src/components/settings-permissions.tsx +++ b/packages/app/src/components/settings-permissions.tsx @@ -177,7 +177,7 @@ export const SettingsPermissions: Component = () => { return (
-
+

{language.t("settings.permissions.title")}

{language.t("settings.permissions.description")}

diff --git a/packages/app/src/components/settings-providers.tsx b/packages/app/src/components/settings-providers.tsx index a3375c9c608..d1837ee607d 100644 --- a/packages/app/src/components/settings-providers.tsx +++ b/packages/app/src/components/settings-providers.tsx @@ -132,7 +132,7 @@ export const SettingsProviders: Component = () => { return (
-
+

{language.t("settings.providers.title")}

diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/history.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/history.tsx index d5a44decd7b..739b6c1992c 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/history.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/history.tsx @@ -2,8 +2,7 @@ import path from "path" import { Global } from "@/global" import { Filesystem } from "@/util/filesystem" import { onMount } from "solid-js" -import { createStore, produce } from "solid-js/store" -import { clone } from "remeda" +import { createStore, produce, unwrap } from "solid-js/store" import { createSimpleContext } from "../../context/helper" import { appendFile, writeFile } from "fs/promises" import type { AgentPart, FilePart, TextPart } from "@kilocode/sdk/v2" @@ -83,7 +82,7 @@ export const { use: usePromptHistory, provider: PromptHistoryProvider } = create return store.history.at(store.index) }, append(item: PromptInfo) { - const entry = clone(item) + const entry = structuredClone(unwrap(item)) let trimmed = false setStore( produce((draft) => { diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/stash.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/stash.tsx index d4dc138d893..ef3eb329a99 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/stash.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/stash.tsx @@ -2,8 +2,7 @@ import path from "path" import { Global } from "@/global" import { Filesystem } from "@/util/filesystem" import { onMount } from "solid-js" -import { createStore, produce } from "solid-js/store" -import { clone } from "remeda" +import { createStore, produce, unwrap } from "solid-js/store" import { createSimpleContext } from "../../context/helper" import { appendFile, writeFile } from "fs/promises" import type { PromptInfo } from "./history" @@ -53,7 +52,7 @@ export const { use: usePromptStash, provider: PromptStashProvider } = createSimp return store.entries }, push(entry: Omit) { - const stash = clone({ ...entry, timestamp: Date.now() }) + const stash = structuredClone(unwrap({ ...entry, timestamp: Date.now() })) let trimmed = false setStore( produce((draft) => { diff --git a/packages/opencode/src/session/llm.ts b/packages/opencode/src/session/llm.ts index 59a20e017ae..02b9c760f36 100644 --- a/packages/opencode/src/session/llm.ts +++ b/packages/opencode/src/session/llm.ts @@ -11,7 +11,7 @@ import { tool, jsonSchema, } from "ai" -import { clone, mergeDeep, pipe } from "remeda" +import { mergeDeep, pipe } from "remeda" import { ProviderTransform } from "@/provider/transform" import { Config } from "@/config/config" import { Instance } from "@/project/instance" @@ -90,15 +90,11 @@ export namespace LLM { ) const header = system[0] - const original = clone(system) await Plugin.trigger( "experimental.chat.system.transform", { sessionID: input.sessionID, model: input.model }, { system }, ) - if (system.length === 0) { - system.push(...original) - } // rejoin to maintain 2-part structure for caching if header unchanged if (system.length > 2 && system[0] === header) { const rest = system.slice(1) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 28dcabea9d6..4ab9fb911ab 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -22,7 +22,6 @@ import PROMPT_PLAN from "../session/prompt/plan.txt" import CODE_SWITCH from "../session/prompt/code-switch.txt" import MAX_STEPS from "../session/prompt/max-steps.txt" import { defer } from "../util/defer" -import { clone } from "remeda" import { ToolRegistry } from "../tool/registry" import { MCP } from "../mcp" import { LSP } from "../lsp" @@ -659,11 +658,9 @@ export namespace SessionPrompt { }) } - const sessionMessages = clone(msgs) - // Ephemerally wrap queued user messages with a reminder to stay on track if (step > 1 && lastFinished) { - for (const msg of sessionMessages) { + for (const msg of msgs) { if (msg.info.role !== "user" || msg.info.id <= lastFinished.id) continue for (const part of msg.parts) { if (part.type !== "text" || part.ignored || part.synthetic) continue @@ -680,7 +677,7 @@ export namespace SessionPrompt { } } - await Plugin.trigger("experimental.chat.messages.transform", {}, { messages: sessionMessages }) + await Plugin.trigger("experimental.chat.messages.transform", {}, { messages: msgs }) // Build system prompt, adding structured output instruction if needed const system = [ @@ -699,7 +696,7 @@ export namespace SessionPrompt { sessionID, system, messages: [ - ...MessageV2.toModelMessages(sessionMessages, model), + ...MessageV2.toModelMessages(msgs, model), ...(isLastStep ? [ { @@ -953,7 +950,12 @@ export namespace SessionPrompt { title: "", metadata, output: truncated.content, - attachments, + attachments: attachments.map((attachment) => ({ + ...attachment, + id: Identifier.ascending("part"), + sessionID: ctx.sessionID, + messageID: input.processor.message.id, + })), content: result.content, // directly return content to preserve ordering when outputting to model } } diff --git a/packages/ui/src/components/collapsible.css b/packages/ui/src/components/collapsible.css index c96d5e64bbf..bab2c4f9269 100644 --- a/packages/ui/src/components/collapsible.css +++ b/packages/ui/src/components/collapsible.css @@ -26,13 +26,16 @@ [data-slot="collapsible-arrow"] { opacity: 0; transition: opacity 0.15s ease; + will-change: opacity; + transform: translateZ(0); } [data-slot="collapsible-arrow-icon"] { display: inline-flex; color: var(--icon-weaker); - transform: rotate(-90deg); + transform: translateZ(0) rotate(-90deg); transition: transform 0.15s ease; + will-change: transform; } &:hover [data-slot="collapsible-arrow"] { @@ -74,7 +77,7 @@ } [data-slot="collapsible-arrow-icon"] { - transform: rotate(0deg); + transform: translateZ(0) rotate(0deg); } } diff --git a/packages/ui/src/components/message-part.css b/packages/ui/src/components/message-part.css index e17aeec12fd..2249a865a13 100644 --- a/packages/ui/src/components/message-part.css +++ b/packages/ui/src/components/message-part.css @@ -180,6 +180,7 @@ [data-component="text-part"] { width: 100%; + margin-top: 24px; [data-slot="text-part-body"] { margin-top: 0; @@ -228,13 +229,18 @@ [data-component="reasoning-part"] { width: 100%; color: var(--text-base); - font-size: var(--font-size-small); - line-height: var(--line-height-large); + line-height: var(--line-height-normal); [data-component="markdown"] { margin-top: 24px; font-style: normal; font-size: inherit; + color: var(--text-weak); + + strong, + b { + color: var(--text-weak); + } p:has(strong) { margin-top: 24px; diff --git a/packages/ui/src/components/session-turn.css b/packages/ui/src/components/session-turn.css index 81fee2a6172..bf1258d2e5a 100644 --- a/packages/ui/src/components/session-turn.css +++ b/packages/ui/src/components/session-turn.css @@ -129,6 +129,11 @@ gap: 8px; flex-shrink: 0; + [data-slot="collapsible-arrow"] { + margin-left: -6px; + transform: translateY(2px); + } + [data-component="diff-changes"][data-variant="bars"] { transform: translateY(1px); } diff --git a/packages/ui/src/styles/theme.css b/packages/ui/src/styles/theme.css index 6bcc7485204..832b43ec74f 100644 --- a/packages/ui/src/styles/theme.css +++ b/packages/ui/src/styles/theme.css @@ -117,6 +117,7 @@ --surface-weak: var(--smoke-light-alpha-3); --surface-weaker: var(--smoke-light-alpha-4); --surface-strong: #ffffff; + --surface-stronger-non-alpha: var(--surface-raised-stronger-non-alpha); --surface-raised-stronger-non-alpha: var(--white); --surface-brand-base: var(--yuzu-light-9); --surface-brand-hover: var(--yuzu-light-10); @@ -375,6 +376,7 @@ --surface-weak: var(--smoke-dark-alpha-4); --surface-weaker: var(--smoke-dark-alpha-5); --surface-strong: var(--smoke-dark-alpha-7); + --surface-stronger-non-alpha: var(--surface-raised-stronger-non-alpha); --surface-raised-stronger-non-alpha: var(--smoke-dark-3); --surface-brand-base: var(--yuzu-light-9); --surface-brand-hover: var(--yuzu-light-10);