summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--STATS.md1
-rw-r--r--bun.lock7
-rw-r--r--package.json6
-rw-r--r--packages/desktop/package.json3
-rw-r--r--packages/desktop/src/components/assistant-message.tsx362
-rw-r--r--packages/desktop/src/components/diff-changes.tsx20
-rw-r--r--packages/desktop/src/components/diff.tsx25
-rw-r--r--packages/desktop/src/context/local.tsx8
-rw-r--r--packages/desktop/src/pages/index.tsx180
-rw-r--r--packages/opencode/src/auth/github-copilot.ts147
-rw-r--r--packages/opencode/src/provider/transform.ts4
-rw-r--r--packages/opencode/src/session/compaction.ts1
-rw-r--r--packages/opencode/src/session/index.ts9
-rw-r--r--packages/opencode/src/session/prompt.ts22
-rw-r--r--packages/opencode/src/tool/tool.ts3
-rw-r--r--packages/opencode/test/session/session.test.ts71
-rw-r--r--packages/sdk/js/src/gen/types.gen.ts8
-rw-r--r--packages/ui/package.json2
-rw-r--r--packages/ui/script/colors.txt438
-rw-r--r--packages/ui/src/components/collapsible.css46
-rw-r--r--packages/ui/src/components/collapsible.tsx14
-rw-r--r--packages/ui/src/components/icon.tsx10
-rw-r--r--packages/ui/src/styles/tailwind/colors.css16
-rw-r--r--packages/ui/src/styles/theme.css50
24 files changed, 975 insertions, 478 deletions
diff --git a/STATS.md b/STATS.md
index fd1a15446..cd00e57e0 100644
--- a/STATS.md
+++ b/STATS.md
@@ -120,3 +120,4 @@
| 2025-10-24 | 572,692 (+7,976) | 506,905 (+8,169) | 1,079,597 (+16,145) |
| 2025-10-25 | 578,927 (+6,235) | 516,129 (+9,224) | 1,095,056 (+15,459) |
| 2025-10-26 | 584,409 (+5,482) | 521,179 (+5,050) | 1,105,588 (+10,532) |
+| 2025-10-27 | 589,999 (+5,590) | 526,001 (+4,822) | 1,116,000 (+10,412) |
diff --git a/bun.lock b/bun.lock
index 8dcbb2b27..42d088109 100644
--- a/bun.lock
+++ b/bun.lock
@@ -141,6 +141,7 @@
"@types/luxon": "3.7.1",
"@types/node": "catalog:",
"@typescript/native-preview": "catalog:",
+ "opencode": "workspace:*",
"typescript": "catalog:",
"vite": "catalog:",
"vite-plugin-icons-spritesheet": "3.0.1",
@@ -276,7 +277,7 @@
"version": "0.15.18",
"dependencies": {
"@kobalte/core": "catalog:",
- "@pierre/precision-diffs": "0.0.2-alpha.1-1",
+ "@pierre/precision-diffs": "catalog:",
"@solidjs/meta": "catalog:",
"fuzzysort": "catalog:",
"luxon": "catalog:",
@@ -343,7 +344,7 @@
"@hono/zod-validator": "0.4.2",
"@kobalte/core": "0.13.11",
"@openauthjs/openauth": "0.0.0-20250322224806",
- "@pierre/precision-diffs": "0.0.2-alpha.1-1",
+ "@pierre/precision-diffs": "0.3.2",
"@solidjs/meta": "0.29.4",
"@tailwindcss/vite": "4.1.11",
"@tsconfig/bun": "1.0.9",
@@ -937,7 +938,7 @@
"@petamoriken/float16": ["@petamoriken/[email protected]", "", {}, "sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog=="],
- "@pierre/precision-diffs": ["@pierre/[email protected]", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/transformers": "3.13.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.13.0" } }, "sha512-T43cwB7gMnbM+tp9p73NptUm4uUOfmrP5ihMOAHWQPpzBa/oeTjqZlmEmSQLpT8WKKnWG0lbKZPtlw7l0gW0Vw=="],
+ "@pierre/precision-diffs": ["@pierre/[email protected]", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/transformers": "3.13.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.13.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-HE+wFB0TV+wmjur/J+qI5PsRQl5RN6tCEFTusW0S5FDfZJUIpkxJCacqUxyEI0DriXMKhgGQ+oCQShfaFELdrQ=="],
"@pkgjs/parseargs": ["@pkgjs/[email protected]", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
diff --git a/package.json b/package.json
index 48afdc7c0..a5e521797 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,7 @@
"@tsconfig/bun": "1.0.9",
"@cloudflare/workers-types": "4.20251008.0",
"@openauthjs/openauth": "0.0.0-20250322224806",
- "@pierre/precision-diffs": "0.0.2-alpha.1-1",
+ "@pierre/precision-diffs": "0.3.2",
"@solidjs/meta": "0.29.4",
"@tailwindcss/vite": "4.1.11",
"diff": "8.0.2",
@@ -53,8 +53,8 @@
"turbo": "2.5.6"
},
"dependencies": {
- "@opencode-ai/sdk": "workspace:*",
- "@opencode-ai/script": "workspace:*"
+ "@opencode-ai/script": "workspace:*",
+ "@opencode-ai/sdk": "workspace:*"
},
"repository": {
"type": "git",
diff --git a/packages/desktop/package.json b/packages/desktop/package.json
index 135ee9bb1..c4af384f4 100644
--- a/packages/desktop/package.json
+++ b/packages/desktop/package.json
@@ -12,12 +12,13 @@
},
"license": "MIT",
"devDependencies": {
+ "opencode": "workspace:*",
"@tailwindcss/vite": "catalog:",
"@tsconfig/bun": "1.0.9",
"@types/luxon": "3.7.1",
"@types/node": "catalog:",
- "typescript": "catalog:",
"@typescript/native-preview": "catalog:",
+ "typescript": "catalog:",
"vite": "catalog:",
"vite-plugin-icons-spritesheet": "3.0.1",
"vite-plugin-solid": "catalog:"
diff --git a/packages/desktop/src/components/assistant-message.tsx b/packages/desktop/src/components/assistant-message.tsx
new file mode 100644
index 000000000..38c06bbe5
--- /dev/null
+++ b/packages/desktop/src/components/assistant-message.tsx
@@ -0,0 +1,362 @@
+import type { Part, AssistantMessage, ReasoningPart, TextPart, ToolPart } from "@opencode-ai/sdk"
+import type { Tool } from "opencode/tool/tool"
+import type { ReadTool } from "opencode/tool/read"
+import { children, Component, createMemo, For, Match, Show, Switch, type JSX } from "solid-js"
+import { Dynamic } from "solid-js/web"
+import { Markdown } from "./markdown"
+import { Collapsible, Icon, IconProps } from "@opencode-ai/ui"
+import { getDirectory, getFilename } from "@/utils"
+import type { ListTool } from "opencode/tool/ls"
+import type { GlobTool } from "opencode/tool/glob"
+import type { GrepTool } from "opencode/tool/grep"
+import type { WebFetchTool } from "opencode/tool/webfetch"
+import type { TaskTool } from "opencode/tool/task"
+import type { BashTool } from "opencode/tool/bash"
+import type { EditTool } from "opencode/tool/edit"
+import type { WriteTool } from "opencode/tool/write"
+import { DiffChanges } from "./diff-changes"
+
+export function AssistantMessage(props: { message: AssistantMessage; parts: Part[] }) {
+ return (
+ <div class="w-full flex flex-col items-start gap-4">
+ <For each={props.parts}>
+ {(part) => {
+ const component = createMemo(() => PART_MAPPING[part.type as keyof typeof PART_MAPPING])
+ return (
+ <Show when={component()}>
+ <Dynamic component={component()} part={part as any} message={props.message} />
+ </Show>
+ )
+ }}
+ </For>
+ </div>
+ )
+}
+
+const PART_MAPPING = {
+ text: TextPart,
+ tool: ToolPart,
+ reasoning: ReasoningPart,
+}
+
+function ReasoningPart(props: { part: ReasoningPart; message: AssistantMessage }) {
+ return null
+ // return (
+ // <Show when={props.part.text.trim()}>
+ // <div>{props.part.text}</div>
+ // </Show>
+ // )
+}
+
+function TextPart(props: { part: TextPart; message: AssistantMessage }) {
+ return (
+ <Show when={props.part.text.trim()}>
+ <Markdown text={props.part.text.trim()} />
+ </Show>
+ )
+}
+
+function ToolPart(props: { part: ToolPart; message: AssistantMessage }) {
+ // const sync = useSync()
+
+ const component = createMemo(() => {
+ const render = ToolRegistry.render(props.part.tool) ?? GenericTool
+
+ const metadata = props.part.state.status === "pending" ? {} : (props.part.state.metadata ?? {})
+ const input = props.part.state.status === "completed" ? props.part.state.input : {}
+ // const permissions = sync.data.permission[props.message.sessionID] ?? []
+ // const permissionIndex = permissions.findIndex((x) => x.callID === props.part.callID)
+ // const permission = permissions[permissionIndex]
+
+ return (
+ <>
+ <Dynamic
+ component={render}
+ input={input}
+ tool={props.part.tool}
+ metadata={metadata}
+ // permission={permission?.metadata ?? {}}
+ output={props.part.state.status === "completed" ? props.part.state.output : undefined}
+ />
+ {/* <Show when={props.part.state.status === "error"}>{props.part.state.error.replace("Error: ", "")}</Show> */}
+ </>
+ )
+ })
+
+ return <Show when={component()}>{component()}</Show>
+}
+
+type TriggerTitle = {
+ title: string
+ subtitle?: string
+ args?: string[]
+ action?: JSX.Element
+}
+
+const isTriggerTitle = (val: any): val is TriggerTitle => {
+ return typeof val === "object" && val !== null && "title" in val && !(val instanceof Node)
+}
+
+function BasicTool(props: { icon: IconProps["name"]; trigger: TriggerTitle | JSX.Element; children?: JSX.Element }) {
+ const resolved = children(() => props.children)
+
+ return (
+ <Collapsible>
+ <Collapsible.Trigger>
+ <div class="w-full flex items-center self-stretch gap-5 justify-between">
+ <div class="w-full flex items-center self-stretch gap-5">
+ <Icon name={props.icon} size="small" />
+ <Switch>
+ <Match when={isTriggerTitle(props.trigger)}>
+ <div class="w-full flex items-center gap-2 justify-between">
+ <div class="flex items-center gap-2">
+ <span class="text-12-medium text-text-base capitalize">
+ {(props.trigger as TriggerTitle).title}
+ </span>
+ <Show when={(props.trigger as TriggerTitle).subtitle}>
+ <span class="text-12-medium text-text-weak">{(props.trigger as TriggerTitle).subtitle}</span>
+ </Show>
+ <Show when={(props.trigger as TriggerTitle).args?.length}>
+ <For each={(props.trigger as TriggerTitle).args}>
+ {(arg) => <span class="text-12-regular text-text-weaker">{arg}</span>}
+ </For>
+ </Show>
+ </div>
+ <Show when={(props.trigger as TriggerTitle).action}>{(props.trigger as TriggerTitle).action}</Show>
+ </div>
+ </Match>
+ <Match when={true}>{props.trigger as JSX.Element}</Match>
+ </Switch>
+ </div>
+ <Show when={resolved()}>
+ <Collapsible.Arrow />
+ </Show>
+ </div>
+ </Collapsible.Trigger>
+ <Show when={props.children}>
+ <Collapsible.Content>{props.children}</Collapsible.Content>
+ </Show>
+ </Collapsible>
+ )
+}
+
+function GenericTool(props: ToolProps<any>) {
+ return <BasicTool icon="mcp" trigger={{ title: props.tool }} />
+}
+
+type ToolProps<T extends Tool.Info> = {
+ input: Partial<Tool.InferParameters<T>>
+ metadata: Partial<Tool.InferMetadata<T>>
+ // permission: Record<string, any>
+ tool: string
+ output?: string
+}
+
+const ToolRegistry = (() => {
+ const state: Record<
+ string,
+ {
+ name: string
+ render?: Component<ToolProps<any>>
+ }
+ > = {}
+ function register<T extends Tool.Info>(input: { name: string; render?: Component<ToolProps<T>> }) {
+ state[input.name] = input
+ return input
+ }
+ return {
+ register,
+ render(name: string) {
+ return state[name]?.render
+ },
+ }
+})()
+
+ToolRegistry.register<typeof ReadTool>({
+ name: "read",
+ render(props) {
+ return (
+ <BasicTool
+ icon="glasses"
+ trigger={{ title: props.tool, subtitle: props.input.filePath ? getFilename(props.input.filePath) : "" }}
+ />
+ )
+ },
+})
+
+ToolRegistry.register<typeof ListTool>({
+ name: "list",
+ render(props) {
+ return (
+ <BasicTool icon="bullet-list" trigger={{ title: props.tool, subtitle: props.input.path || "/" }}>
+ <Show when={false && props.output}>
+ <div class="whitespace-pre">{props.output}</div>
+ </Show>
+ </BasicTool>
+ )
+ },
+})
+
+ToolRegistry.register<typeof GlobTool>({
+ name: "glob",
+ render(props) {
+ return (
+ <BasicTool
+ icon="magnifying-glass-menu"
+ trigger={{
+ title: props.tool,
+ subtitle: props.input.path || "/",
+ args: props.input.pattern ? ["pattern=" + props.input.pattern] : [],
+ }}
+ >
+ <Show when={false && props.output}>
+ <div class="whitespace-pre">{props.output}</div>
+ </Show>
+ </BasicTool>
+ )
+ },
+})
+
+ToolRegistry.register<typeof GrepTool>({
+ name: "grep",
+ render(props) {
+ const args = []
+ if (props.input.pattern) args.push("pattern=" + props.input.pattern)
+ if (props.input.include) args.push("include=" + props.input.include)
+ return (
+ <BasicTool
+ icon="magnifying-glass-menu"
+ trigger={{
+ title: props.tool,
+ subtitle: props.input.path || "/",
+ args,
+ }}
+ >
+ <Show when={false && props.output}>
+ <div class="whitespace-pre">{props.output}</div>
+ </Show>
+ </BasicTool>
+ )
+ },
+})
+
+ToolRegistry.register<typeof WebFetchTool>({
+ name: "webfetch",
+ render(props) {
+ return (
+ <BasicTool
+ icon="window-cursor"
+ trigger={{
+ title: props.tool,
+ subtitle: props.input.url || "",
+ args: props.input.format ? ["format=" + props.input.format] : [],
+ action: (
+ <div class="size-6 flex items-center justify-center">
+ <Icon name="square-arrow-top-right" size="small" />
+ </div>
+ ),
+ }}
+ >
+ <Show when={false && props.output}>
+ <div class="whitespace-pre">{props.output}</div>
+ </Show>
+ </BasicTool>
+ )
+ },
+})
+
+ToolRegistry.register<typeof TaskTool>({
+ name: "task",
+ render(props) {
+ return (
+ <BasicTool
+ icon="task"
+ trigger={{
+ title: `${props.input.subagent_type || props.tool} Agent`,
+ subtitle: props.input.description,
+ }}
+ >
+ <Show when={false && props.output}>
+ <div class="whitespace-pre">{props.output}</div>
+ </Show>
+ </BasicTool>
+ )
+ },
+})
+
+ToolRegistry.register<typeof BashTool>({
+ name: "bash",
+ render(props) {
+ return (
+ <BasicTool
+ icon="console"
+ trigger={{
+ title: "Shell",
+ subtitle: "Ran " + props.input.command,
+ }}
+ >
+ <Show when={false && props.output}>
+ <div class="whitespace-pre">{props.output}</div>
+ </Show>
+ </BasicTool>
+ )
+ },
+})
+
+ToolRegistry.register<typeof EditTool>({
+ name: "edit",
+ render(props) {
+ return (
+ <BasicTool
+ icon="code-lines"
+ trigger={
+ <div class="flex items-center justify-between w-full">
+ <div class="flex items-center gap-5">
+ <div class="text-12-medium text-text-base capitalize">Edit</div>
+ <div class="flex">
+ <Show when={props.input.filePath?.includes("/")}>
+ <span class="text-text-weak">{getDirectory(props.input.filePath!)}/</span>
+ </Show>
+ <span class="text-text-strong">{getFilename(props.input.filePath ?? "")}</span>
+ </div>
+ </div>
+ <div class="flex gap-4 items-center justify-end">{/* <DiffChanges diff={diff} /> */}</div>
+ </div>
+ }
+ >
+ <Show when={false && props.output}>
+ <div class="whitespace-pre">{props.output}</div>
+ </Show>
+ </BasicTool>
+ )
+ },
+})
+
+ToolRegistry.register<typeof WriteTool>({
+ name: "write",
+ render(props) {
+ return (
+ <BasicTool
+ icon="code-lines"
+ trigger={
+ <div class="flex items-center justify-between w-full">
+ <div class="flex items-center gap-5">
+ <div class="text-12-medium text-text-base capitalize">Write</div>
+ <div class="flex">
+ <Show when={props.input.filePath?.includes("/")}>
+ <span class="text-text-weak">{getDirectory(props.input.filePath!)}/</span>
+ </Show>
+ <span class="text-text-strong">{getFilename(props.input.filePath ?? "")}</span>
+ </div>
+ </div>
+ <div class="flex gap-4 items-center justify-end">{/* <DiffChanges diff={diff} /> */}</div>
+ </div>
+ }
+ >
+ <Show when={false && props.output}>
+ <div class="whitespace-pre">{props.output}</div>
+ </Show>
+ </BasicTool>
+ )
+ },
+})
diff --git a/packages/desktop/src/components/diff-changes.tsx b/packages/desktop/src/components/diff-changes.tsx
new file mode 100644
index 000000000..3b633f70f
--- /dev/null
+++ b/packages/desktop/src/components/diff-changes.tsx
@@ -0,0 +1,20 @@
+import { FileDiff } from "@opencode-ai/sdk"
+import { createMemo, Show } from "solid-js"
+
+export function DiffChanges(props: { diff: FileDiff | FileDiff[] }) {
+ const additions = createMemo(() =>
+ Array.isArray(props.diff) ? props.diff.reduce((acc, diff) => acc + (diff.additions ?? 0), 0) : props.diff.additions,
+ )
+ const deletions = createMemo(() =>
+ Array.isArray(props.diff) ? props.diff.reduce((acc, diff) => acc + (diff.deletions ?? 0), 0) : props.diff.deletions,
+ )
+ const total = createMemo(() => additions() + deletions())
+ return (
+ <Show when={total() > 0}>
+ <div class="flex gap-2 justify-end items-center">
+ <span class="text-12-mono text-right text-text-diff-add-base">{`+${additions()}`}</span>
+ <span class="text-12-mono text-right text-text-diff-delete-base">{`-${deletions()}`}</span>
+ </div>
+ </Show>
+ )
+}
diff --git a/packages/desktop/src/components/diff.tsx b/packages/desktop/src/components/diff.tsx
index d8457b528..c39ad852e 100644
--- a/packages/desktop/src/components/diff.tsx
+++ b/packages/desktop/src/components/diff.tsx
@@ -2,8 +2,9 @@ import {
type FileContents,
FileDiff,
type DiffLineAnnotation,
+ type HunkData,
DiffFileRendererOptions,
- registerCustomTheme,
+ // registerCustomTheme,
} from "@pierre/precision-diffs"
import { ComponentProps, createEffect, splitProps } from "solid-js"
@@ -15,8 +16,7 @@ export type DiffProps<T = {}> = Omit<DiffFileRendererOptions<T>, "themes"> & {
classList?: ComponentProps<"div">["classList"]
}
-// @ts-expect-error
-registerCustomTheme("opencode", () => import("./theme.json"))
+// registerCustomTheme("opencode", () => import("./theme.json"))
// interface ThreadMetadata {
// threadId: string
@@ -49,7 +49,7 @@ export function Diff<T>(props: DiffProps<T>) {
// annotations and a container element to hold the diff
createEffect(() => {
const instance = new FileDiff<T>({
- theme: "opencode",
+ theme: "pierre-light",
// Or can also provide a 'themes' prop, which allows the code to adapt
// to your OS light or dark theme
// themes: { dark: 'pierre-night', light: 'pierre-light' },
@@ -98,6 +98,23 @@ export function Diff<T>(props: DiffProps<T>) {
// 'simple':
// Just a subtle bar separator between each hunk
hunkSeparators: "line-info",
+ // hunkSeparators(hunkData: HunkData) {
+ // const fragment = document.createDocumentFragment()
+ // const numCol = document.createElement("div")
+ // numCol.textContent = `${hunkData.lines}`
+ // numCol.style.position = "sticky"
+ // numCol.style.left = "0"
+ // numCol.style.backgroundColor = "var(--pjs-bg)"
+ // numCol.style.zIndex = "2"
+ // fragment.appendChild(numCol)
+ // const contentCol = document.createElement("div")
+ // contentCol.textContent = "unmodified lines"
+ // contentCol.style.position = "sticky"
+ // contentCol.style.width = "var(--pjs-column-content-width)"
+ // contentCol.style.left = "var(--pjs-column-number-width)"
+ // fragment.appendChild(contentCol)
+ // return fragment
+ // },
// On lines that have both additions and deletions, we can run a
// separate diff check to mark parts of the lines that change.
// 'none':
diff --git a/packages/desktop/src/context/local.tsx b/packages/desktop/src/context/local.tsx
index 6ed8ec17b..978dbfbc6 100644
--- a/packages/desktop/src/context/local.tsx
+++ b/packages/desktop/src/context/local.tsx
@@ -460,13 +460,6 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
return sync.data.message[store.active]?.find((m) => m.id === store.activeMessage)
})
- const activeAssistantMessages = createMemo(() => {
- if (!store.active || !activeMessage()) return []
- return sync.data.message[store.active]?.filter(
- (m) => m.role === "assistant" && m.parentID == activeMessage()?.id,
- )
- })
-
const model = createMemo(() => {
if (!last()) return
const model = sync.data.provider.find((x) => x.id === last().providerID)?.models[last().modelID]
@@ -504,7 +497,6 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
return {
active,
activeMessage,
- activeAssistantMessages,
lastUserMessage,
cost,
last,
diff --git a/packages/desktop/src/pages/index.tsx b/packages/desktop/src/pages/index.tsx
index 6702284b2..15da87bd6 100644
--- a/packages/desktop/src/pages/index.tsx
+++ b/packages/desktop/src/pages/index.tsx
@@ -22,6 +22,10 @@ import { Code } from "@/components/code"
import { useSync } from "@/context/sync"
import { useSDK } from "@/context/sdk"
import { Diff } from "@/components/diff"
+import { ProgressCircle } from "@/components/progress-circle"
+import { AssistantMessage } from "@/components/assistant-message"
+import { type AssistantMessage as AssistantMessageType } from "@opencode-ai/sdk"
+import { DiffChanges } from "@/components/diff-changes"
export default function Page() {
const local = useLocal()
@@ -92,7 +96,7 @@ export default function Page() {
}
}
- if (event.key.length === 1 && event.key !== "Unidentified") {
+ if (event.key.length === 1 && event.key !== "Unidentified" && !(event.ctrlKey || event.metaKey)) {
inputRef?.focus()
}
}
@@ -392,9 +396,6 @@ export default function Page() {
{(session) => {
const diffs = createMemo(() => session.summary?.diffs ?? [])
const filesChanged = createMemo(() => diffs().length)
- const additions = createMemo(() => diffs().reduce((acc, diff) => (acc ?? 0) + (diff.additions ?? 0), 0))
- const deletions = createMemo(() => diffs().reduce((acc, diff) => (acc ?? 0) + (diff.deletions ?? 0), 0))
-
return (
<Tooltip placement="right" value={session.title}>
<div>
@@ -408,12 +409,7 @@ export default function Page() {
</div>
<div class="flex justify-between items-center self-stretch">
<span class="text-12-regular text-text-weak">{`${filesChanged() || "No"} file${filesChanged() !== 1 ? "s" : ""} changed`}</span>
- <Show when={additions() || deletions()}>
- <div class="flex gap-2 justify-end items-center">
- <span class="text-12-mono text-right text-text-diff-add-base">{`+${additions()}`}</span>
- <span class="text-12-mono text-right text-text-diff-delete-base">{`-${deletions()}`}</span>
- </div>
- </Show>
+ <DiffChanges diff={diffs()} />
</div>
</div>
</Tooltip>
@@ -434,13 +430,12 @@ export default function Page() {
<Tabs onChange={handleTabChange}>
<div class="sticky top-0 shrink-0 flex">
<Tabs.List>
- <Tabs.Trigger value="chat" class="flex gap-x-1.5 items-center">
+ <Tabs.Trigger value="chat" class="flex gap-x-4 items-center">
<div>Chat</div>
- <Show when={local.session.active()}>
- <div class="flex flex-col h-4 px-2 -mr-2 justify-center items-center rounded-full bg-surface-base text-12-medium text-text-strong">
- {local.session.context()}%
- </div>
- </Show>
+ <Tooltip value={`${local.session.tokens() ?? 0} Tokens`} class="flex items-center gap-1.5">
+ <ProgressCircle percentage={local.session.context() ?? 0} />
+ <div class="text-14-regular text-text-weak text-right">{local.session.context() ?? 0}%</div>
+ </Tooltip>
</Tabs.Trigger>
{/* <Tabs.Trigger value="review">Review</Tabs.Trigger> */}
<SortableProvider ids={local.file.opened().map((file) => file.path)}>
@@ -548,33 +543,114 @@ export default function Page() {
<Show when={local.session.userMessages().length > 1}>
<ul role="list" class="w-60 shrink-0 flex flex-col items-start gap-1">
<For each={local.session.userMessages()}>
- {(message) => (
- <li
- class="group/li flex items-center gap-x-2 py-1 self-stretch cursor-default"
- onClick={() => local.session.setActiveMessage(message.id)}
- >
- <div class="w-[18px] shrink-0">
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 12" fill="none">
- <g>
- <rect x="0" width="2" height="12" rx="1" fill="#CFCECD" />
- <rect x="4" width="2" height="12" rx="1" fill="#CFCECD" />
- <rect x="8" width="2" height="12" rx="1" fill="#CFCECD" />
- <rect x="12" width="2" height="12" rx="1" fill="#CFCECD" />
- <rect x="16" width="2" height="12" rx="1" fill="#CFCECD" />
- </g>
- </svg>
- </div>
- <div
- data-active={local.session.activeMessage()?.id === message.id}
- classList={{
- "text-14-regular text-text-weak whitespace-nowrap truncate min-w-0": true,
- "text-text-weak data-[active=true]:text-text-strong group-hover/li:text-text-base": true,
- }}
+ {(message) => {
+ const countLines = (text: string) => {
+ if (!text) return 0
+ return text.split("\n").length
+ }
+
+ const additions = createMemo(
+ () =>
+ message.summary?.diffs.reduce((acc, diff) => acc + (diff.additions ?? 0), 0) ?? 0,
+ )
+
+ const deletions = createMemo(
+ () =>
+ message.summary?.diffs.reduce((acc, diff) => acc + (diff.deletions ?? 0), 0) ?? 0,
+ )
+
+ const totalBeforeLines = createMemo(
+ () =>
+ message.summary?.diffs.reduce((acc, diff) => acc + countLines(diff.before), 0) ??
+ 0,
+ )
+
+ const blockCounts = createMemo(() => {
+ const TOTAL_BLOCKS = 5
+
+ const adds = additions()
+ const dels = deletions()
+ const unchanged = Math.max(0, totalBeforeLines() - dels)
+
+ const totalActivity = unchanged + adds + dels
+
+ if (totalActivity === 0) {
+ return { added: 0, deleted: 0, neutral: TOTAL_BLOCKS }
+ }
+
+ const percentAdded = adds / totalActivity
+ const percentDeleted = dels / totalActivity
+ const added_raw = percentAdded * TOTAL_BLOCKS
+ const deleted_raw = percentDeleted * TOTAL_BLOCKS
+
+ let added = adds > 0 ? Math.ceil(added_raw) : 0
+ let deleted = dels > 0 ? Math.ceil(deleted_raw) : 0
+
+ let total_allocated = added + deleted
+ if (total_allocated > TOTAL_BLOCKS) {
+ if (added_raw < deleted_raw) {
+ added = Math.floor(added_raw)
+ } else {
+ deleted = Math.floor(deleted_raw)
+ }
+
+ total_allocated = added + deleted
+ if (total_allocated > TOTAL_BLOCKS) {
+ if (added_raw < deleted_raw) {
+ deleted = Math.floor(deleted_raw)
+ } else {
+ added = Math.floor(added_raw)
+ }
+ }
+ }
+
+ const neutral = Math.max(0, TOTAL_BLOCKS - added - deleted)
+
+ return { added, deleted, neutral }
+ })
+
+ const ADD_COLOR = "var(--icon-diff-add-base)"
+ const DELETE_COLOR = "var(--icon-diff-delete-base)"
+ const NEUTRAL_COLOR = "var(--icon-weak-base)"
+
+ const visibleBlocks = createMemo(() => {
+ const counts = blockCounts()
+ const blocks = [
+ ...Array(counts.added).fill(ADD_COLOR),
+ ...Array(counts.deleted).fill(DELETE_COLOR),
+ ...Array(counts.neutral).fill(NEUTRAL_COLOR),
+ ]
+ return blocks.slice(0, 5)
+ })
+
+ return (
+ <li
+ class="group/li flex items-center gap-x-2 py-1 self-stretch cursor-default"
+ onClick={() => local.session.setActiveMessage(message.id)}
>
- {message.summary?.title ?? local.session.getMessageText(message)}
- </div>
- </li>
- )}
+ <div class="w-[18px] shrink-0">
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 12" fill="none">
+ <g>
+ <For each={visibleBlocks()}>
+ {(color, i) => (
+ <rect x={i() * 4} width="2" height="12" rx="1" fill={color} />
+ )}
+ </For>
+ </g>
+ </svg>
+ </div>
+ <div
+ data-active={local.session.activeMessage()?.id === message.id}
+ classList={{
+ "text-14-regular text-text-weak whitespace-nowrap truncate min-w-0": true,
+ "text-text-weak data-[active=true]:text-text-strong group-hover/li:text-text-base": true,
+ }}
+ >
+ {message.summary?.title ?? local.session.getMessageText(message)}
+ </div>
+ </li>
+ )
+ }}
</For>
</ul>
</Show>
@@ -585,6 +661,11 @@ export default function Page() {
const title = createMemo(() => message.summary?.title)
const prompt = createMemo(() => local.session.getMessageText(message))
const summary = createMemo(() => message.summary?.body)
+ const assistantMessages = createMemo(() => {
+ return sync.data.message[activeSession().id]?.filter(
+ (m) => m.role === "assistant" && m.parentID == message.id,
+ ) as AssistantMessageType[]
+ })
return (
<div
@@ -633,10 +714,7 @@ export default function Page() {
</div>
</div>
<div class="flex gap-4 items-center justify-end">
- <div class="flex gap-2 justify-end items-center">
- <span class="text-12-mono text-right text-text-diff-add-base">{`+${diff.additions}`}</span>
- <span class="text-12-mono text-right text-text-diff-delete-base">{`-${diff.deletions}`}</span>
- </div>
+ <DiffChanges diff={diff} />
<Icon name="chevron-grabber-vertical" size="small" />
</div>
</div>
@@ -661,10 +739,18 @@ export default function Page() {
</Show>
</div>
{/* Response */}
- <div data-todo="Response (Timeline)">
+ <div data-todo="Response" class="w-full">
<div class="flex flex-col items-start gap-1 self-stretch">
<h2 class="text-12-medium text-text-weak">Response</h2>
</div>
+ <div class="w-full flex flex-col items-start self-stretch gap-8">
+ <For each={assistantMessages()}>
+ {(assistantMessage) => {
+ const parts = createMemo(() => sync.data.part[assistantMessage.id])
+ return <AssistantMessage message={assistantMessage} parts={parts()} />
+ }}
+ </For>
+ </div>
</div>
</div>
)
diff --git a/packages/opencode/src/auth/github-copilot.ts b/packages/opencode/src/auth/github-copilot.ts
deleted file mode 100644
index bd5740c9b..000000000
--- a/packages/opencode/src/auth/github-copilot.ts
+++ /dev/null
@@ -1,147 +0,0 @@
-import z from "zod"
-import { Auth } from "./index"
-import { NamedError } from "../util/error"
-
-export namespace AuthGithubCopilot {
- const CLIENT_ID = "Iv1.b507a08c87ecfe98"
- const DEVICE_CODE_URL = "https://github.com/login/device/code"
- const ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token"
- const COPILOT_API_KEY_URL = "https://api.github.com/copilot_internal/v2/token"
-
- interface DeviceCodeResponse {
- device_code: string
- user_code: string
- verification_uri: string
- expires_in: number
- interval: number
- }
-
- interface AccessTokenResponse {
- access_token?: string
- error?: string
- error_description?: string
- }
-
- interface CopilotTokenResponse {
- token: string
- expires_at: number
- refresh_in: number
- endpoints: {
- api: string
- }
- }
-
- export async function authorize() {
- const deviceResponse = await fetch(DEVICE_CODE_URL, {
- method: "POST",
- headers: {
- Accept: "application/json",
- "Content-Type": "application/json",
- "User-Agent": "GitHubCopilotChat/0.26.7",
- },
- body: JSON.stringify({
- client_id: CLIENT_ID,
- scope: "read:user",
- }),
- })
- const deviceData: DeviceCodeResponse = await deviceResponse.json()
- return {
- device: deviceData.device_code,
- user: deviceData.user_code,
- verification: deviceData.verification_uri,
- interval: deviceData.interval || 5,
- expiry: deviceData.expires_in,
- }
- }
-
- export async function poll(device_code: string) {
- const response = await fetch(ACCESS_TOKEN_URL, {
- method: "POST",
- headers: {
- Accept: "application/json",
- "Content-Type": "application/json",
- "User-Agent": "GitHubCopilotChat/0.26.7",
- },
- body: JSON.stringify({
- client_id: CLIENT_ID,
- device_code,
- grant_type: "urn:ietf:params:oauth:grant-type:device_code",
- }),
- })
-
- if (!response.ok) return "failed"
-
- const data: AccessTokenResponse = await response.json()
-
- if (data.access_token) {
- // Store the GitHub OAuth token
- await Auth.set("github-copilot", {
- type: "oauth",
- refresh: data.access_token,
- access: "",
- expires: 0,
- })
- return "complete"
- }
-
- if (data.error === "authorization_pending") return "pending"
-
- if (data.error) return "failed"
-
- return "pending"
- }
-
- export async function access() {
- const info = await Auth.get("github-copilot")
- if (!info || info.type !== "oauth") return
- if (info.access && info.expires > Date.now()) return info.access
-
- // Get new Copilot API token
- const response = await fetch(COPILOT_API_KEY_URL, {
- headers: {
- Accept: "application/json",
- Authorization: `Bearer ${info.refresh}`,
- "User-Agent": "GitHubCopilotChat/0.26.7",
- "Editor-Version": "vscode/1.99.3",
- "Editor-Plugin-Version": "copilot-chat/0.26.7",
- },
- })
-
- if (!response.ok) return
-
- const tokenData: CopilotTokenResponse = await response.json()
-
- // Store the Copilot API token
- await Auth.set("github-copilot", {
- type: "oauth",
- refresh: info.refresh,
- access: tokenData.token,
- expires: tokenData.expires_at * 1000,
- })
-
- return tokenData.token
- }
-
- export const DeviceCodeError = NamedError.create("DeviceCodeError", z.object({}))
-
- export const TokenExchangeError = NamedError.create(
- "TokenExchangeError",
- z.object({
- message: z.string(),
- }),
- )
-
- export const AuthenticationError = NamedError.create(
- "AuthenticationError",
- z.object({
- message: z.string(),
- }),
- )
-
- export const CopilotTokenError = NamedError.create(
- "CopilotTokenError",
- z.object({
- message: z.string(),
- }),
- )
-}
diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts
index 73ff442ab..dda02cc4e 100644
--- a/packages/opencode/src/provider/transform.ts
+++ b/packages/opencode/src/provider/transform.ts
@@ -92,7 +92,9 @@ export namespace ProviderTransform {
}
if (modelID.includes("gpt-5") && !modelID.includes("gpt-5-chat")) {
- if (!modelID.includes("codex")) result["reasoningEffort"] = "medium"
+ if (!modelID.includes("codex") && !modelID.includes("gpt-5-pro")) {
+ result["reasoningEffort"] = "medium"
+ }
if (providerID !== "azure") {
result["textVerbosity"] = modelID.includes("codex") ? "medium" : "low"
diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts
index d9ead5791..76313453f 100644
--- a/packages/opencode/src/session/compaction.ts
+++ b/packages/opencode/src/session/compaction.ts
@@ -155,6 +155,7 @@ export namespace SessionCompaction {
error,
})
},
+ tools: model.info.tool_call ? {} : undefined,
messages: [
...system.map(
(x): ModelMessage => ({
diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts
index ee4cc704f..ff9f436e2 100644
--- a/packages/opencode/src/session/index.ts
+++ b/packages/opencode/src/session/index.ts
@@ -78,6 +78,12 @@ export namespace Session {
export type ShareInfo = z.output<typeof ShareInfo>
export const Event = {
+ Created: Bus.event(
+ "session.created",
+ z.object({
+ info: Info,
+ }),
+ ),
Updated: Bus.event(
"session.updated",
z.object({
@@ -167,6 +173,9 @@ export namespace Session {
}
log.info("created", result)
await Storage.write(["session", Instance.project.id, result.id], result)
+ Bus.publish(Event.Created, {
+ info: result,
+ })
const cfg = await Config.get()
if (!result.parentID && (Flag.OPENCODE_AUTO_SHARE || cfg.share === "auto"))
share(result.id)
diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts
index 7018978e2..26a04cb8e 100644
--- a/packages/opencode/src/session/prompt.ts
+++ b/packages/opencode/src/session/prompt.ts
@@ -191,28 +191,6 @@ export namespace SessionPrompt {
processor,
})
- // const permUnsub = (() => {
- // const handled = new Set<string>()
- // const options = [
- // { optionId: "allow_once", kind: "allow_once", name: "Allow once" },
- // { optionId: "allow_always", kind: "allow_always", name: "Always allow" },
- // { optionId: "reject_once", kind: "reject_once", name: "Reject" },
- // ]
- // return Bus.subscribe(Permission.Event.Updated, async (event) => {
- // const info = event.properties
- // if (info.sessionID !== input.sessionID) return
- // if (handled.has(info.id)) return
- // handled.add(info.id)
- // const toolCallId = info.callID ?? info.id
- // const metadata = info.metadata ?? {}
- // // TODO: emit permission event to bus for ACP to handle
- // Permission.respond({ sessionID: info.sessionID, permissionID: info.id, response: "reject" })
- // })
- // })()
- // await using _permSub = defer(() => {
- // permUnsub?.()
- // })
-
const params = await Plugin.trigger(
"chat.params",
{
diff --git a/packages/opencode/src/tool/tool.ts b/packages/opencode/src/tool/tool.ts
index 978c9c072..c7a28c516 100644
--- a/packages/opencode/src/tool/tool.ts
+++ b/packages/opencode/src/tool/tool.ts
@@ -32,6 +32,9 @@ export namespace Tool {
}>
}
+ export type InferParameters<T extends Info> = T extends Info<infer P> ? z.infer<P> : never
+ export type InferMetadata<T extends Info> = T extends Info<any, infer M> ? M : never
+
export function define<Parameters extends z.ZodType, Result extends Metadata>(
id: string,
init: Info<Parameters, Result>["init"] | Awaited<ReturnType<Info<Parameters, Result>["init"]>>,
diff --git a/packages/opencode/test/session/session.test.ts b/packages/opencode/test/session/session.test.ts
new file mode 100644
index 000000000..219cef127
--- /dev/null
+++ b/packages/opencode/test/session/session.test.ts
@@ -0,0 +1,71 @@
+import { describe, expect, test } from "bun:test"
+import path from "path"
+import { Session } from "../../src/session"
+import { Bus } from "../../src/bus"
+import { Log } from "../../src/util/log"
+import { Instance } from "../../src/project/instance"
+
+const projectRoot = path.join(__dirname, "../..")
+Log.init({ print: false })
+
+describe("session.started event", () => {
+ test("should emit session.started event when session is created", async () => {
+ await Instance.provide({
+ directory: projectRoot,
+ fn: async () => {
+ let eventReceived = false
+ let receivedInfo: Session.Info | undefined
+
+ const unsub = Bus.subscribe(Session.Event.Created, (event) => {
+ eventReceived = true
+ receivedInfo = event.properties.info as Session.Info
+ })
+
+ const session = await Session.create({})
+
+ await new Promise((resolve) => setTimeout(resolve, 100))
+
+ unsub()
+
+ expect(eventReceived).toBe(true)
+ expect(receivedInfo).toBeDefined()
+ expect(receivedInfo?.id).toBe(session.id)
+ expect(receivedInfo?.projectID).toBe(session.projectID)
+ expect(receivedInfo?.directory).toBe(session.directory)
+ expect(receivedInfo?.title).toBe(session.title)
+
+ await Session.remove(session.id)
+ },
+ })
+ })
+
+ test("session.started event should be emitted before session.updated", async () => {
+ await Instance.provide({
+ directory: projectRoot,
+ fn: async () => {
+ const events: string[] = []
+
+ const unsubStarted = Bus.subscribe(Session.Event.Created, () => {
+ events.push("started")
+ })
+
+ const unsubUpdated = Bus.subscribe(Session.Event.Updated, () => {
+ events.push("updated")
+ })
+
+ const session = await Session.create({})
+
+ await new Promise((resolve) => setTimeout(resolve, 100))
+
+ unsubStarted()
+ unsubUpdated()
+
+ expect(events).toContain("started")
+ expect(events).toContain("updated")
+ expect(events.indexOf("started")).toBeLessThan(events.indexOf("updated"))
+
+ await Session.remove(session.id)
+ },
+ })
+ })
+})
diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts
index 47bb20972..0b55cc5b4 100644
--- a/packages/sdk/js/src/gen/types.gen.ts
+++ b/packages/sdk/js/src/gen/types.gen.ts
@@ -1197,6 +1197,13 @@ export type EventSessionIdle = {
}
}
+export type EventSessionCreated = {
+ type: "session.created"
+ properties: {
+ info: Session
+ }
+}
+
export type EventSessionUpdated = {
type: "session.updated"
properties: {
@@ -1247,6 +1254,7 @@ export type Event =
| EventFileWatcherUpdated
| EventTodoUpdated
| EventSessionIdle
+ | EventSessionCreated
| EventSessionUpdated
| EventSessionDeleted
| EventSessionError
diff --git a/packages/ui/package.json b/packages/ui/package.json
index bf75293aa..cdb9eee1c 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -24,7 +24,7 @@
},
"dependencies": {
"@kobalte/core": "catalog:",
- "@pierre/precision-diffs": "0.0.2-alpha.1-1",
+ "@pierre/precision-diffs": "catalog:",
"@solidjs/meta": "catalog:",
"fuzzysort": "catalog:",
"luxon": "catalog:",
diff --git a/packages/ui/script/colors.txt b/packages/ui/script/colors.txt
index 15f8bb3d1..b022e8a11 100644
--- a/packages/ui/script/colors.txt
+++ b/packages/ui/script/colors.txt
@@ -1,214 +1,224 @@
- --background-base: #f8f7f7;
- --background-weak: var(--smoke-light-3);
- --background-strong: var(--smoke-light-1);
- --background-stronger: #fcfcfc;
- --base: var(--smoke-light-alpha-2);
- --surface-base: var(--smoke-light-alpha-2);
- --base2: var(--smoke-light-alpha-2);
- --base3: var(--smoke-light-alpha-2);
- --surface-inset-base: var(--smoke-light-alpha-3);
- --surface-inset-base-hover: var(--smoke-light-alpha-3);
- --surface-inset-strong: #1f000017;
- --surface-inset-strong-hover: #1f000017;
- --surface-raised-base: var(--smoke-light-alpha-1);
- --surface-float-base: var(--smoke-dark-1);
- --surface-float-base-hover: var(--smoke-dark-2);
- --surface-raised-base-hover: var(--smoke-light-alpha-2);
- --surface-raised-strong: var(--smoke-light-1);
- --surface-raised-strong-hover: var(--white);
- --surface-raised-stronger: var(--white);
- --surface-raised-stronger-hover: var(--white);
- --surface-weak: var(--smoke-light-alpha-3);
- --surface-weaker: var(--smoke-light-alpha-4);
- --surface-strong: #ffffff;
- --surface-raised-stronger-non-alpha: var(--white);
- --surface-brand-base: var(--yuzu-light-9);
- --surface-brand-hover: var(--yuzu-light-10);
- --surface-interactive-base: var(--cobalt-light-3);
- --surface-interactive-hover: var(--cobalt-light-4);
- --surface-interactive-weak: var(--cobalt-light-2);
- --surface-interactive-weak-hover: var(--cobalt-light-3);
- --surface-success-base: var(--apple-light-3);
- --surface-success-weak: var(--apple-light-2);
- --surface-success-strong: var(--apple-light-9);
- --surface-warning-base: var(--solaris-light-3);
- --surface-warning-weak: var(--solaris-light-2);
- --surface-warning-strong: var(--solaris-light-9);
- --surface-critical-base: var(--ember-light-3);
- --surface-critical-weak: var(--ember-light-2);
- --surface-critical-strong: var(--ember-light-9);
- --surface-info-base: var(--lilac-light-3);
- --surface-info-weak: var(--lilac-light-2);
- --surface-info-strong: var(--lilac-light-9);
- --surface-diff-skip-base: var(--smoke-light-3);
- --surface-diff-unchanged-base: #ffffff00;
- --surface-diff-hidden-base: var(--blue-light-3);
- --surface-diff-hidden-weak: var(--blue-light-2);
- --surface-diff-hidden-weaker: var(--blue-light-1);
- --surface-diff-hidden-strong: var(--blue-light-5);
- --surface-diff-hidden-stronger: var(--blue-light-9);
- --surface-diff-add-base: var(--mint-light-3);
- --surface-diff-add-weak: var(--mint-light-2);
- --surface-diff-add-weaker: var(--mint-light-1);
- --surface-diff-add-strong: var(--mint-light-5);
- --surface-diff-add-stronger: var(--mint-light-9);
- --surface-diff-delete-base: var(--ember-light-3);
- --surface-diff-delete-weak: var(--ember-light-2);
- --surface-diff-delete-weaker: var(--ember-light-1);
- --surface-diff-delete-strong: var(--ember-light-6);
- --surface-diff-delete-stronger: var(--ember-light-9);
- --text-base: var(--smoke-light-11);
- --input-base: var(--smoke-light-1);
- --input-hover: var(--smoke-light-2);
- --input-active: var(--cobalt-light-1);
- --input-selected: var(--cobalt-light-4);
- --input-focus: var(--cobalt-light-1);
- --input-disabled: var(--smoke-light-4);
- --text-weak: var(--smoke-light-9);
- --text-weaker: var(--smoke-light-8);
- --text-strong: var(--smoke-light-12);
- --text-on-brand-base: var(--smoke-light-alpha-11);
- --text-on-interactive-base: var(--smoke-light-1);
- --text-on-success-base: var(--smoke-dark-alpha-11);
- --text-on-warning-base: var(--smoke-dark-alpha-11);
- --text-on-info-base: var(--smoke-dark-alpha-11);
- --text-diff-add-base: var(--mint-light-11);
- --text-diff-delete-base: var(--ember-light-11);
- --text-diff-delete-strong: var(--ember-light-12);
- --text-diff-add-strong: var(--mint-light-12);
- --text-on-info-weak: var(--smoke-dark-alpha-9);
- --text-on-info-strong: var(--smoke-dark-alpha-12);
- --text-on-warning-weak: var(--smoke-dark-alpha-9);
- --text-on-warning-strong: var(--smoke-dark-alpha-12);
- --text-on-success-weak: var(--smoke-dark-alpha-9);
- --text-on-success-strong: var(--smoke-dark-alpha-12);
- --text-on-brand-weak: var(--smoke-light-alpha-9);
- --text-on-brand-weaker: var(--smoke-light-alpha-8);
- --text-on-brand-strong: var(--smoke-light-alpha-12);
- --button-secondary-base: #fdfcfc;
- --border-base: var(--smoke-light-alpha-7);
- --border-hover: var(--smoke-light-alpha-8);
- --border-active: var(--smoke-light-alpha-9);
- --border-selected: var(--cobalt-light-alpha-9);
- --border-disabled: var(--smoke-light-alpha-8);
- --border-focus: var(--smoke-light-alpha-9);
- --border-weak-base: var(--smoke-light-alpha-5);
- --border-strong-base: var(--smoke-light-alpha-7);
- --border-strong-hover: var(--smoke-light-alpha-8);
- --border-strong-active: var(--smoke-light-alpha-7);
- --border-strong-selected: var(--cobalt-light-alpha-6);
- --border-strong-disabled: var(--smoke-light-alpha-6);
- --border-strong-focus: var(--smoke-light-alpha-7);
- --border-weak-hover: var(--smoke-light-alpha-6);
- --border-weak-active: var(--smoke-light-alpha-7);
- --border-weak-selected: var(--cobalt-light-alpha-6);
- --border-weak-disabled: var(--smoke-light-alpha-6);
- --border-weak-focus: var(--smoke-light-alpha-7);
- --border-interactive-base: var(--cobalt-light-7);
- --border-interactive-hover: var(--cobalt-light-8);
- --border-interactive-active: var(--cobalt-light-9);
- --border-interactive-selected: var(--cobalt-light-9);
- --border-interactive-disabled: var(--smoke-light-8);
- --border-interactive-focus: var(--cobalt-light-9);
- --border-success-base: var(--apple-light-6);
- --border-success-hover: var(--apple-light-7);
- --border-success-selected: var(--apple-light-9);
- --border-warning-base: var(--solaris-light-6);
- --border-warning-hover: var(--solaris-light-7);
- --border-warning-selected: var(--solaris-light-9);
- --border-critical-base: var(--ember-light-6);
- --border-critical-hover: var(--ember-light-7);
- --border-critical-selected: var(--ember-light-9);
- --border-info-base: var(--lilac-light-6);
- --border-info-hover: var(--lilac-light-7);
- --border-info-selected: var(--lilac-light-9);
- --icon-base: var(--smoke-light-9);
- --icon-hover: var(--smoke-light-11);
- --icon-active: var(--smoke-light-12);
- --icon-selected: var(--smoke-light-12);
- --icon-disabled: var(--smoke-light-8);
- --icon-focus: var(--smoke-light-12);
- --icon-weak-base: var(--smoke-light-7);
- --icon-invert-base: #ffffff;
- --icon-weak-hover: var(--smoke-light-8);
- --icon-weak-active: var(--smoke-light-9);
- --icon-weak-selected: var(--smoke-light-10);
- --icon-weak-disabled: var(--smoke-light-6);
- --icon-weak-focus: var(--smoke-light-9);
- --icon-strong-base: var(--smoke-light-12);
- --icon-strong-hover: var(--smoke-light-12);
- --icon-strong-active: var(--smoke-light-12);
- --icon-strong-selected: var(--smoke-light-12);
- --icon-strong-disabled: var(--smoke-light-8);
- --icon-strong-focus: var(--smoke-light-12);
- --icon-brand-base: var(--smoke-light-12);
- --icon-interactive-base: var(--cobalt-light-9);
- --icon-success-base: var(--apple-light-7);
- --icon-success-hover: var(--apple-light-8);
- --icon-success-active: var(--apple-light-11);
- --icon-warning-base: var(--amber-light-7);
- --icon-warning-hover: var(--amber-light-8);
- --icon-warning-active: var(--amber-light-11);
- --icon-critical-base: var(--ember-light-7);
- --icon-critical-hover: var(--ember-light-8);
- --icon-critical-active: var(--ember-light-11);
- --icon-info-base: var(--lilac-light-7);
- --icon-info-hover: var(--lilac-light-8);
- --icon-info-active: var(--lilac-light-11);
- --icon-on-brand-base: var(--smoke-light-alpha-11);
- --icon-on-brand-hover: var(--smoke-light-alpha-12);
- --icon-on-brand-selected: var(--smoke-light-alpha-12);
- --icon-on-interactive-base: var(--smoke-light-alpha-9);
- --icon-on-interactive-hover: var(--smoke-light-alpha-10);
- --icon-on-interactive-selected: var(--smoke-light-alpha-11);
- --icon-agent-plan-base: var(--purple-light-9);
- --icon-agent-docs-base: var(--amber-light-9);
- --icon-agent-ask-base: var(--cyan-light-9);
- --icon-agent-build-base: var(--blue-light-9);
- --icon-on-success-base: var(--apple-light-alpha-9);
- --icon-on-success-hover: var(--apple-light-alpha-10);
- --icon-on-success-selected: var(--apple-light-alpha-11);
- --icon-on-warning-base: var(--amber-lightalpha-9);
- --icon-on-warning-hover: var(--amber-lightalpha-10);
- --icon-on-warning-selected: var(--amber-lightalpha-11);
- --icon-on-critical-base: var(--ember-light-alpha-9);
- --icon-on-critical-hover: var(--ember-light-alpha-10);
- --icon-on-critical-selected: var(--ember-light-alpha-11);
- --icon-on-info-base: var(--lilac-light-9);
- --icon-on-info-hover: var(--lilac-light-alpha-10);
- --icon-on-info-selected: var(--lilac-light-alpha-11);
- --icon-diff-add-base: var(--mint-light-11);
- --icon-diff-add-hover: var(--mint-light-12);
- --icon-diff-add-active: var(--mint-light-12);
- --icon-diff-delete-base: var(--ember-light-9);
- --icon-diff-delete-hover: var(--ember-light-10);
- --icon-diff-delete-active: var(--ember-light-11);
- --syntax-comment: #ffffff;
- --syntax-string: #ffffff;
- --syntax-keyword: #ffffff;
- --syntax-function: #ffffff;
- --syntax-number: #ffffff;
- --syntax-operator: #ffffff;
- --syntax-variable: #ffffff;
- --syntax-type: #ffffff;
- --syntax-constant: #ffffff;
- --syntax-punctuation: #ffffff;
- --syntax-success: #ffffff;
- --syntax-warning: #ffffff;
- --syntax-critical: #ffffff;
- --syntax-info: #ffffff;
- --markdown-heading: #ffffff;
- --markdown-text: #ffffff;
- --markdown-link: #ffffff;
- --markdown-link-text: #ffffff;
- --markdown-code: #ffffff;
- --markdown-block-quote: #ffffff;
- --markdown-emph: #ffffff;
- --markdown-strong: #ffffff;
- --markdown-horizontal-rule: #ffffff;
- --markdown-list-item: #ffffff;
- --markdown-list-enumeration: #ffffff;
- --markdown-image: #ffffff;
- --markdown-image-text: #ffffff;
- --markdown-code-block: #ffffff;
- --border-color: #ffffff;
+--background-base: #F8F7F7;
+--background-weak: var(--smoke-light-3);
+--background-strong: var(--smoke-light-1);
+--background-stronger: #FCFCFC;
+--base: var(--smoke-light-alpha-2);
+--surface-base: var(--smoke-light-alpha-2);
+--surface-base-hover: #0500000F;
+--surface-base-active: var(--smoke-light-alpha-3);
+--surface-base-interactive-active: var(--cobalt-light-alpha-3);
+--base2: var(--smoke-light-alpha-2);
+--base3: var(--smoke-light-alpha-2);
+--surface-inset-base: var(--smoke-light-alpha-2);
+--surface-inset-base-hover: var(--smoke-light-alpha-3);
+--surface-inset-strong: #1F000017;
+--surface-inset-strong-hover: #1F000017;
+--surface-raised-base: var(--smoke-light-alpha-1);
+--surface-float-base: var(--smoke-dark-1);
+--surface-float-base-hover: var(--smoke-dark-2);
+--surface-raised-base-hover: var(--smoke-light-alpha-2);
+--surface-raised-strong: var(--smoke-light-1);
+--surface-raised-strong-hover: var(--white);
+--surface-raised-stronger: var(--white);
+--surface-raised-stronger-hover: var(--white);
+--surface-weak: var(--smoke-light-alpha-3);
+--surface-weaker: var(--smoke-light-alpha-4);
+--surface-strong: #FFFFFF;
+--surface-raised-stronger-non-alpha: var(--white);
+--surface-brand-base: var(--yuzu-light-9);
+--surface-brand-hover: var(--yuzu-light-10);
+--surface-interactive-base: var(--cobalt-light-3);
+--surface-interactive-hover: var(--cobalt-light-4);
+--surface-interactive-weak: var(--cobalt-light-2);
+--surface-interactive-weak-hover: var(--cobalt-light-3);
+--surface-success-base: var(--apple-light-3);
+--surface-success-weak: var(--apple-light-2);
+--surface-success-strong: var(--apple-light-9);
+--surface-warning-base: var(--solaris-light-3);
+--surface-warning-weak: var(--solaris-light-2);
+--surface-warning-strong: var(--solaris-light-9);
+--surface-critical-base: var(--ember-light-3);
+--surface-critical-weak: var(--ember-light-2);
+--surface-critical-strong: var(--ember-light-9);
+--surface-info-base: var(--lilac-light-3);
+--surface-info-weak: var(--lilac-light-2);
+--surface-info-strong: var(--lilac-light-9);
+--surface-diff-hidden-base: var(--blue-light-3);
+--surface-diff-skip-base: var(--smoke-light-2);
+--surface-diff-unchanged-base: #FFFFFF00;
+--surface-diff-hidden-weak: var(--blue-light-2);
+--surface-diff-hidden-weaker: var(--blue-light-1);
+--surface-diff-hidden-strong: var(--blue-light-5);
+--surface-diff-hidden-stronger: var(--blue-light-9);
+--surface-diff-add-base: var(--mint-light-3);
+--surface-diff-add-weak: var(--mint-light-2);
+--surface-diff-add-weaker: var(--mint-light-1);
+--surface-diff-add-strong: var(--mint-light-5);
+--surface-diff-add-stronger: var(--mint-light-9);
+--surface-diff-delete-base: var(--ember-light-3);
+--surface-diff-delete-weak: var(--ember-light-2);
+--surface-diff-delete-weaker: var(--ember-light-1);
+--surface-diff-delete-strong: var(--ember-light-6);
+--surface-diff-delete-stronger: var(--ember-light-9);
+--text-base: var(--smoke-light-11);
+--input-base: var(--smoke-light-1);
+--input-hover: var(--smoke-light-2);
+--input-active: var(--cobalt-light-1);
+--input-selected: var(--cobalt-light-4);
+--input-focus: var(--cobalt-light-1);
+--input-disabled: var(--smoke-light-4);
+--text-weak: var(--smoke-light-9);
+--text-weaker: var(--smoke-light-8);
+--text-strong: var(--smoke-light-12);
+--text-interactive-base: var(--cobalt-light-9);
+--text-on-brand-base: var(--smoke-light-alpha-11);
+--text-on-interactive-base: var(--smoke-light-1);
+--text-on-interactive-weak: var(--smoke-dark-alpha-11);
+--text-on-success-base: var(--smoke-dark-alpha-11);
+--text-on-warning-base: var(--smoke-dark-alpha-11);
+--text-on-info-base: var(--smoke-dark-alpha-11);
+--text-diff-add-base: var(--mint-light-11);
+--text-diff-delete-base: var(--ember-light-11);
+--text-diff-delete-strong: var(--ember-light-12);
+--text-diff-add-strong: var(--mint-light-12);
+--text-on-info-weak: var(--smoke-dark-alpha-9);
+--text-on-info-strong: var(--smoke-dark-alpha-12);
+--text-on-warning-weak: var(--smoke-dark-alpha-9);
+--text-on-warning-strong: var(--smoke-dark-alpha-12);
+--text-on-success-weak: var(--smoke-dark-alpha-9);
+--text-on-success-strong: var(--smoke-dark-alpha-12);
+--text-on-brand-weak: var(--smoke-light-alpha-9);
+--text-on-brand-weaker: var(--smoke-light-alpha-8);
+--text-on-brand-strong: var(--smoke-light-alpha-12);
+--button-secondary-base: #FDFCFC;
+--button-secondary-base-hover: #FAF9F9;
+--border-base: var(--smoke-light-alpha-7);
+--border-hover: var(--smoke-light-alpha-8);
+--border-active: var(--smoke-light-alpha-9);
+--border-selected: var(--cobalt-light-alpha-9);
+--border-disabled: var(--smoke-light-alpha-8);
+--border-focus: var(--smoke-light-alpha-9);
+--border-weak-base: var(--smoke-light-alpha-5);
+--border-strong-base: var(--smoke-light-alpha-7);
+--border-strong-hover: var(--smoke-light-alpha-8);
+--border-strong-active: var(--smoke-light-alpha-7);
+--border-strong-selected: var(--cobalt-light-alpha-6);
+--border-strong-disabled: var(--smoke-light-alpha-6);
+--border-strong-focus: var(--smoke-light-alpha-7);
+--border-weak-hover: var(--smoke-light-alpha-6);
+--border-weak-active: var(--smoke-light-alpha-7);
+--border-weak-selected: var(--cobalt-light-alpha-5);
+--border-weak-disabled: var(--smoke-light-alpha-6);
+--border-weak-focus: var(--smoke-light-alpha-7);
+--border-interactive-base: var(--cobalt-light-7);
+--border-interactive-hover: var(--cobalt-light-8);
+--border-interactive-active: var(--cobalt-light-9);
+--border-interactive-selected: var(--cobalt-light-9);
+--border-interactive-disabled: var(--smoke-light-8);
+--border-interactive-focus: var(--cobalt-light-9);
+--border-success-base: var(--apple-light-6);
+--border-success-hover: var(--apple-light-7);
+--border-success-selected: var(--apple-light-9);
+--border-warning-base: var(--solaris-light-6);
+--border-warning-hover: var(--solaris-light-7);
+--border-warning-selected: var(--solaris-light-9);
+--border-critical-base: var(--ember-light-6);
+--border-critical-hover: var(--ember-light-7);
+--border-critical-selected: var(--ember-light-9);
+--border-info-base: var(--lilac-light-6);
+--border-info-hover: var(--lilac-light-7);
+--border-info-selected: var(--lilac-light-9);
+--icon-base: var(--smoke-light-9);
+--icon-hover: var(--smoke-light-11);
+--icon-active: var(--smoke-light-12);
+--icon-selected: var(--smoke-light-12);
+--icon-disabled: var(--smoke-light-8);
+--icon-focus: var(--smoke-light-12);
+--icon-weak-base: var(--smoke-light-7);
+--icon-invert-base: #FFFFFF;
+--icon-weak-hover: var(--smoke-light-8);
+--icon-weak-active: var(--smoke-light-9);
+--icon-weak-selected: var(--smoke-light-10);
+--icon-weak-disabled: var(--smoke-light-6);
+--icon-weak-focus: var(--smoke-light-9);
+--icon-strong-base: var(--smoke-light-12);
+--icon-strong-hover: var(--smoke-light-12);
+--icon-strong-active: var(--smoke-light-12);
+--icon-strong-selected: var(--smoke-light-12);
+--icon-strong-disabled: var(--smoke-light-8);
+--icon-strong-focus: var(--smoke-light-12);
+--icon-brand-base: var(--smoke-light-12);
+--icon-interactive-base: var(--cobalt-light-9);
+--icon-success-base: var(--apple-light-7);
+--icon-success-hover: var(--apple-light-8);
+--icon-success-active: var(--apple-light-11);
+--icon-warning-base: var(--amber-light-7);
+--icon-warning-hover: var(--amber-light-8);
+--icon-warning-active: var(--amber-light-11);
+--icon-critical-base: var(--ember-light-7);
+--icon-critical-hover: var(--ember-light-8);
+--icon-critical-active: var(--ember-light-11);
+--icon-info-base: var(--lilac-light-7);
+--icon-info-hover: var(--lilac-light-8);
+--icon-info-active: var(--lilac-light-11);
+--icon-on-brand-base: var(--smoke-light-alpha-11);
+--icon-on-brand-hover: var(--smoke-light-alpha-12);
+--icon-on-brand-selected: var(--smoke-light-alpha-12);
+--icon-on-interactive-base: var(--smoke-light-1);
+--icon-agent-plan-base: var(--purple-light-9);
+--icon-agent-docs-base: var(--amber-light-9);
+--icon-agent-ask-base: var(--cyan-light-9);
+--icon-agent-build-base: var(--cobalt-light-9);
+--icon-on-success-base: var(--apple-light-alpha-9);
+--icon-on-success-hover: var(--apple-light-alpha-10);
+--icon-on-success-selected: var(--apple-light-alpha-11);
+--icon-on-warning-base: var(--amber-lightalpha-9);
+--icon-on-warning-hover: var(--amber-lightalpha-10);
+--icon-on-warning-selected: var(--amber-lightalpha-11);
+--icon-on-critical-base: var(--ember-light-alpha-9);
+--icon-on-critical-hover: var(--ember-light-alpha-10);
+--icon-on-critical-selected: var(--ember-light-alpha-11);
+--icon-on-info-base: var(--lilac-light-9);
+--icon-on-info-hover: var(--lilac-light-alpha-10);
+--icon-on-info-selected: var(--lilac-light-alpha-11);
+--icon-diff-add-base: var(--mint-light-11);
+--icon-diff-add-hover: var(--mint-light-12);
+--icon-diff-add-active: var(--mint-light-12);
+--icon-diff-delete-base: var(--ember-light-9);
+--icon-diff-delete-hover: var(--ember-light-10);
+--icon-diff-delete-active: var(--ember-light-11);
+--syntax-comment: #8A8A8A;
+--syntax-string: #D68C27;
+--syntax-keyword: #3B7DD8;
+--syntax-function: #D1383D;
+--syntax-number: #3D9A57;
+--syntax-operator: #D68C27;
+--syntax-variable: #B0851F;
+--syntax-type: #318795;
+--syntax-constant: #953170;
+--syntax-punctuation: #1A1A1A;
+--syntax-success: var(--apple-dark-10);
+--syntax-warning: var(--amber-light-10);
+--syntax-critical: var(--ember-dark-9);
+--syntax-info: var(--lilac-dark-11);
+--markdown-heading: #D68C27;
+--markdown-text: #1A1A1A;
+--markdown-link: #3B7DD8;
+--markdown-link-text: #318795;
+--markdown-code: #3D9A57;
+--markdown-block-quote: #B0851F;
+--markdown-emph: #B0851F;
+--markdown-strong: #D68C27;
+--markdown-horizontal-rule: #8A8A8A;
+--markdown-list-item: #3B7DD8;
+--markdown-list-enumeration: #318795;
+--markdown-image: #3B7DD8;
+--markdown-image-text: #318795;
+--markdown-code-block: #1A1A1A;
+--border-color: #FFFFFF;
+--border-weaker-base: var(--smoke-light-alpha-3);
+--border-weaker-hover: var(--smoke-light-alpha-4);
+--border-weaker-active: var(--smoke-light-alpha-6);
+--border-weaker-selected: var(--cobalt-light-alpha-4);
+--border-weaker-disabled: var(--smoke-light-alpha-2);
+--border-weaker-focus: var(--smoke-light-alpha-6);
diff --git a/packages/ui/src/components/collapsible.css b/packages/ui/src/components/collapsible.css
index 441d0083f..34699fc20 100644
--- a/packages/ui/src/components/collapsible.css
+++ b/packages/ui/src/components/collapsible.css
@@ -1,23 +1,55 @@
[data-component="collapsible"] {
+ width: 100%;
display: flex;
flex-direction: column;
+ background-color: var(--surface-inset-base);
+ border: 1px solid var(--border-weaker-base);
+ transition: background-color 0.15s ease;
+ border-radius: 8px;
+ overflow: clip;
- [data-slot="trigger"] {
- cursor: pointer;
+ [data-slot="collapsible-trigger"] {
+ width: 100%;
+ display: flex;
+ height: 40px;
+ padding: 6px 8px 6px 12px;
+ align-items: center;
+ align-self: stretch;
+ cursor: default;
user-select: none;
+ color: var(--text-base);
+ /* text-12-medium */
+ font-family: var(--font-family-sans);
+ font-size: var(--font-size-small);
+ font-style: normal;
+ font-weight: var(--font-weight-medium);
+ line-height: var(--line-height-large); /* 166.667% */
+ letter-spacing: var(--letter-spacing-normal);
+
+ /* &:hover { */
+ /* background-color: var(--surface-base); */
+ /* } */
&:focus-visible {
- outline: 2px solid var(--border-focus);
- outline-offset: 2px;
+ outline: none;
}
-
&[data-disabled] {
cursor: not-allowed;
- opacity: 0.5;
+ }
+
+ [data-slot="collapsible-arrow"] {
+ width: 24px;
+ height: 24px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ /* [data-slot="collapsible-arrow-icon"] { */
+ /* } */
}
}
- [data-slot="content"] {
+ [data-slot="collapsible-content"] {
overflow: hidden;
/* animation: slideUp 250ms ease-out; */
diff --git a/packages/ui/src/components/collapsible.tsx b/packages/ui/src/components/collapsible.tsx
index f926192e8..d2e4a139b 100644
--- a/packages/ui/src/components/collapsible.tsx
+++ b/packages/ui/src/components/collapsible.tsx
@@ -1,5 +1,6 @@
import { Collapsible as Kobalte, CollapsibleRootProps } from "@kobalte/core/collapsible"
import { ComponentProps, ParentProps, splitProps } from "solid-js"
+import { Icon } from "./icon"
export interface CollapsibleProps extends ParentProps<CollapsibleRootProps> {
class?: string
@@ -21,14 +22,23 @@ function CollapsibleRoot(props: CollapsibleProps) {
}
function CollapsibleTrigger(props: ComponentProps<typeof Kobalte.Trigger>) {
- return <Kobalte.Trigger data-slot="trigger" {...props} />
+ return <Kobalte.Trigger data-slot="collapsible-trigger" {...props} />
}
function CollapsibleContent(props: ComponentProps<typeof Kobalte.Content>) {
- return <Kobalte.Content data-slot="content" {...props} />
+ return <Kobalte.Content data-slot="collapsible-content" {...props} />
+}
+
+function CollapsibleArrow(props?: ComponentProps<"div">) {
+ return (
+ <div data-slot="collapsible-arrow" {...(props || {})}>
+ <Icon data-slot="collapsible-arrow-icon" name="chevron-grabber-vertical" size="small" />
+ </div>
+ )
}
export const Collapsible = Object.assign(CollapsibleRoot, {
+ Arrow: CollapsibleArrow,
Trigger: CollapsibleTrigger,
Content: CollapsibleContent,
})
diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx
index 0011a9676..5736146e5 100644
--- a/packages/ui/src/components/icon.tsx
+++ b/packages/ui/src/components/icon.tsx
@@ -139,6 +139,16 @@ const newIcons = {
folder: `<path d="M2.08301 2.91675V16.2501H17.9163V5.41675H9.99967L8.33301 2.91675H2.08301Z" stroke="currentColor" stroke-linecap="round"/>`,
"pencil-line": `<path d="M9.58301 17.9166H17.9163M17.9163 5.83325L14.1663 2.08325L2.08301 14.1666V17.9166H5.83301L17.9163 5.83325Z" stroke="currentColor" stroke-linecap="square"/>`,
"chevron-grabber-vertical": `<path d="M6.66675 12.4998L10.0001 15.8332L13.3334 12.4998M6.66675 7.49984L10.0001 4.1665L13.3334 7.49984" stroke="currentColor" stroke-linecap="square"/>`,
+ mcp: `<g><path d="M0.972656 9.37176L9.5214 1.60019C10.7018 0.527151 12.6155 0.527151 13.7957 1.60019C14.9761 2.67321 14.9761 4.41295 13.7957 5.48599L7.3397 11.3552" stroke="currentColor" stroke-linecap="round"/><path d="M7.42871 11.2747L13.7957 5.48643C14.9761 4.41338 16.8898 4.41338 18.0702 5.48643L18.1147 5.52688C19.2951 6.59993 19.2951 8.33966 18.1147 9.4127L10.3831 16.4414C9.98966 16.7991 9.98966 17.379 10.3831 17.7366L11.9707 19.1799" stroke="currentColor" stroke-linecap="round"/><path d="M11.6587 3.54346L5.33619 9.29119C4.15584 10.3642 4.15584 12.1039 5.33619 13.177C6.51649 14.25 8.43019 14.25 9.61054 13.177L15.9331 7.42923" stroke="currentColor" stroke-linecap="round"/></g>`,
+ glasses: `<path d="M0.416626 7.91667H1.66663M19.5833 7.91667H18.3333M11.866 7.57987C11.3165 7.26398 10.6793 7.08333 9.99996 7.08333C9.32061 7.08333 8.68344 7.26398 8.13389 7.57987M8.74996 10C8.74996 12.0711 7.07103 13.75 4.99996 13.75C2.92889 13.75 1.24996 12.0711 1.24996 10C1.24996 7.92893 2.92889 6.25 4.99996 6.25C7.07103 6.25 8.74996 7.92893 8.74996 10ZM18.75 10C18.75 12.0711 17.071 13.75 15 13.75C12.9289 13.75 11.25 12.0711 11.25 10C11.25 7.92893 12.9289 6.25 15 6.25C17.071 6.25 18.75 7.92893 18.75 10Z" stroke="currentColor" stroke-linecap="square"/>`,
+ "bullet-list": `<path d="M9.58329 13.7497H17.0833M9.58329 6.24967H17.0833M6.24996 6.24967C6.24996 7.17015 5.50377 7.91634 4.58329 7.91634C3.66282 7.91634 2.91663 7.17015 2.91663 6.24967C2.91663 5.3292 3.66282 4.58301 4.58329 4.58301C5.50377 4.58301 6.24996 5.3292 6.24996 6.24967ZM6.24996 13.7497C6.24996 14.6701 5.50377 15.4163 4.58329 15.4163C3.66282 15.4163 2.91663 14.6701 2.91663 13.7497C2.91663 12.8292 3.66282 12.083 4.58329 12.083C5.50377 12.083 6.24996 12.8292 6.24996 13.7497Z" stroke="currentColor" stroke-linecap="square"/>`,
+ "magnifying-glass-menu": `<path d="M2.08325 10.0002H4.58325M2.08325 5.41683H5.41659M2.08325 14.5835H5.41659M16.4583 13.9585L18.7499 16.2502M17.9166 10.0002C17.9166 12.9917 15.4915 15.4168 12.4999 15.4168C9.50838 15.4168 7.08325 12.9917 7.08325 10.0002C7.08325 7.00862 9.50838 4.5835 12.4999 4.5835C15.4915 4.5835 17.9166 7.00862 17.9166 10.0002Z" stroke="currentColor" stroke-linecap="square"/>`,
+ "window-cursor": `<path d="M17.9166 10.4167V3.75H2.08325V17.0833H10.4166M17.9166 13.5897L11.6666 11.6667L13.5897 17.9167L15.032 15.0321L17.9166 13.5897Z" stroke="currentColor" stroke-width="1.07143" stroke-linecap="square"/><path d="M5.00024 6.125C5.29925 6.12518 5.54126 6.36795 5.54126 6.66699C5.54108 6.96589 5.29914 7.20783 5.00024 7.20801C4.7012 7.20801 4.45843 6.966 4.45825 6.66699C4.45825 6.36784 4.70109 6.125 5.00024 6.125ZM7.91626 6.125C8.21541 6.125 8.45825 6.36784 8.45825 6.66699C8.45808 6.966 8.21531 7.20801 7.91626 7.20801C7.61736 7.20783 7.37542 6.96589 7.37524 6.66699C7.37524 6.36795 7.61726 6.12518 7.91626 6.125ZM10.8333 6.125C11.1324 6.125 11.3752 6.36784 11.3752 6.66699C11.3751 6.966 11.1323 7.20801 10.8333 7.20801C10.5342 7.20801 10.2914 6.966 10.2913 6.66699C10.2913 6.36784 10.5341 6.125 10.8333 6.125Z" fill="currentColor" stroke="currentColor" stroke-width="0.25" stroke-linecap="square"/>`,
+ task: `<path d="M9.99992 2.0835V17.9168M7.08325 3.75016H2.08325V16.2502H7.08325M12.9166 16.2502H17.9166V3.75016H12.9166" stroke="currentColor" stroke-linecap="square"/>`,
+ checklist: `<path d="M9.58342 13.7498H17.0834M9.58342 6.24984H17.0834M2.91675 6.6665L4.58341 7.9165L7.08341 4.1665M2.91675 14.1665L4.58341 15.4165L7.08341 11.6665" stroke="currentColor" stroke-linecap="square"/>`,
+ console: `<path d="M3.75 5.4165L8.33333 9.99984L3.75 14.5832M10.4167 14.5832H16.25" stroke="currentColor" stroke-linecap="square"/>`,
+ "code-lines": `<path d="M2.08325 3.75H11.2499M14.5833 3.75H17.9166M2.08325 10L7.08325 10M10.4166 10L17.9166 10M2.08325 16.25L8.74992 16.25M12.0833 16.25L17.9166 16.25" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round"/>`,
+ "square-arrow-top-right": `<path d="M7.91675 2.9165H2.91675V17.0832H17.0834V12.0832M12.0834 2.9165H17.0834V7.9165M9.58342 10.4165L16.6667 3.33317" stroke="currentColor" stroke-linecap="square"/>`,
}
export interface IconProps extends ComponentProps<"svg"> {
diff --git a/packages/ui/src/styles/tailwind/colors.css b/packages/ui/src/styles/tailwind/colors.css
index 2bf3fd772..e2f6788ab 100644
--- a/packages/ui/src/styles/tailwind/colors.css
+++ b/packages/ui/src/styles/tailwind/colors.css
@@ -9,6 +9,9 @@
--color-background-stronger: var(--background-stronger);
--color-base: var(--base);
--color-surface-base: var(--surface-base);
+ --color-surface-base-hover: var(--surface-base-hover);
+ --color-surface-base-active: var(--surface-base-active);
+ --color-surface-base-interactive-active: var(--surface-base-interactive-active);
--color-base2: var(--base2);
--color-base3: var(--base3);
--color-surface-inset-base: var(--surface-inset-base);
@@ -45,9 +48,9 @@
--color-surface-info-base: var(--surface-info-base);
--color-surface-info-weak: var(--surface-info-weak);
--color-surface-info-strong: var(--surface-info-strong);
+ --color-surface-diff-hidden-base: var(--surface-diff-hidden-base);
--color-surface-diff-skip-base: var(--surface-diff-skip-base);
--color-surface-diff-unchanged-base: var(--surface-diff-unchanged-base);
- --color-surface-diff-hidden-base: var(--surface-diff-hidden-base);
--color-surface-diff-hidden-weak: var(--surface-diff-hidden-weak);
--color-surface-diff-hidden-weaker: var(--surface-diff-hidden-weaker);
--color-surface-diff-hidden-strong: var(--surface-diff-hidden-strong);
@@ -72,8 +75,10 @@
--color-text-weak: var(--text-weak);
--color-text-weaker: var(--text-weaker);
--color-text-strong: var(--text-strong);
+ --color-text-interactive-base: var(--text-interactive-base);
--color-text-on-brand-base: var(--text-on-brand-base);
--color-text-on-interactive-base: var(--text-on-interactive-base);
+ --color-text-on-interactive-weak: var(--text-on-interactive-weak);
--color-text-on-success-base: var(--text-on-success-base);
--color-text-on-warning-base: var(--text-on-warning-base);
--color-text-on-info-base: var(--text-on-info-base);
@@ -91,6 +96,7 @@
--color-text-on-brand-weaker: var(--text-on-brand-weaker);
--color-text-on-brand-strong: var(--text-on-brand-strong);
--color-button-secondary-base: var(--button-secondary-base);
+ --color-button-secondary-base-hover: var(--button-secondary-base-hover);
--color-border-base: var(--border-base);
--color-border-hover: var(--border-hover);
--color-border-active: var(--border-active);
@@ -164,8 +170,6 @@
--color-icon-on-brand-hover: var(--icon-on-brand-hover);
--color-icon-on-brand-selected: var(--icon-on-brand-selected);
--color-icon-on-interactive-base: var(--icon-on-interactive-base);
- --color-icon-on-interactive-hover: var(--icon-on-interactive-hover);
- --color-icon-on-interactive-selected: var(--icon-on-interactive-selected);
--color-icon-agent-plan-base: var(--icon-agent-plan-base);
--color-icon-agent-docs-base: var(--icon-agent-docs-base);
--color-icon-agent-ask-base: var(--icon-agent-ask-base);
@@ -217,4 +221,10 @@
--color-markdown-image-text: var(--markdown-image-text);
--color-markdown-code-block: var(--markdown-code-block);
--color-border-color: var(--border-color);
+ --color-border-weaker-base: var(--border-weaker-base);
+ --color-border-weaker-hover: var(--border-weaker-hover);
+ --color-border-weaker-active: var(--border-weaker-active);
+ --color-border-weaker-selected: var(--border-weaker-selected);
+ --color-border-weaker-disabled: var(--border-weaker-disabled);
+ --color-border-weaker-focus: var(--border-weaker-focus);
} \ No newline at end of file
diff --git a/packages/ui/src/styles/theme.css b/packages/ui/src/styles/theme.css
index 5358f380d..0c22bae5a 100644
--- a/packages/ui/src/styles/theme.css
+++ b/packages/ui/src/styles/theme.css
@@ -66,11 +66,14 @@
--background-weak: var(--smoke-light-3);
--background-strong: var(--smoke-light-1);
--background-stronger: #fcfcfc;
- --surface-base: var(--smoke-light-alpha-2);
--base: var(--smoke-light-alpha-2);
+ --surface-base: var(--smoke-light-alpha-2);
+ --surface-base-hover: #0500000f;
+ --surface-base-active: var(--smoke-light-alpha-3);
+ --surface-base-interactive-active: var(--cobalt-light-alpha-3);
--base2: var(--smoke-light-alpha-2);
--base3: var(--smoke-light-alpha-2);
- --surface-inset-base: var(--smoke-light-alpha-3);
+ --surface-inset-base: var(--smoke-light-alpha-2);
--surface-inset-base-hover: var(--smoke-light-alpha-3);
--surface-inset-strong: #1f000017;
--surface-inset-strong-hover: #1f000017;
@@ -105,7 +108,7 @@
--surface-info-weak: var(--lilac-light-2);
--surface-info-strong: var(--lilac-light-9);
--surface-diff-hidden-base: var(--blue-light-3);
- --surface-diff-skip-base: var(--smoke-light-3);
+ --surface-diff-skip-base: var(--smoke-light-2);
--surface-diff-unchanged-base: #ffffff00;
--surface-diff-hidden-weak: var(--blue-light-2);
--surface-diff-hidden-weaker: var(--blue-light-1);
@@ -131,6 +134,7 @@
--text-weak: var(--smoke-light-9);
--text-weaker: var(--smoke-light-8);
--text-strong: var(--smoke-light-12);
+ --text-interactive-base: var(--cobalt-light-9);
--text-on-brand-base: var(--smoke-light-alpha-11);
--text-on-interactive-base: var(--smoke-light-1);
--text-on-interactive-weak: var(--smoke-dark-alpha-11);
@@ -151,7 +155,7 @@
--text-on-brand-weaker: var(--smoke-light-alpha-8);
--text-on-brand-strong: var(--smoke-light-alpha-12);
--button-secondary-base: #fdfcfc;
- --button-secondary-base-hover: var(--smoke-light-2);
+ --button-secondary-base-hover: #faf9f9;
--border-base: var(--smoke-light-alpha-7);
--border-hover: var(--smoke-light-alpha-8);
--border-active: var(--smoke-light-alpha-9);
@@ -167,7 +171,7 @@
--border-strong-focus: var(--smoke-light-alpha-7);
--border-weak-hover: var(--smoke-light-alpha-6);
--border-weak-active: var(--smoke-light-alpha-7);
- --border-weak-selected: var(--cobalt-light-alpha-4);
+ --border-weak-selected: var(--cobalt-light-alpha-5);
--border-weak-disabled: var(--smoke-light-alpha-6);
--border-weak-focus: var(--smoke-light-alpha-7);
--border-interactive-base: var(--cobalt-light-7);
@@ -228,7 +232,7 @@
--icon-agent-plan-base: var(--purple-light-9);
--icon-agent-docs-base: var(--amber-light-9);
--icon-agent-ask-base: var(--cyan-light-9);
- --icon-agent-build-base: var(--blue-light-9);
+ --icon-agent-build-base: var(--cobalt-light-9);
--icon-on-success-base: var(--apple-light-alpha-9);
--icon-on-success-hover: var(--apple-light-alpha-10);
--icon-on-success-selected: var(--apple-light-alpha-11);
@@ -276,6 +280,12 @@
--markdown-image-text: #318795;
--markdown-code-block: #1a1a1a;
--border-color: #ffffff;
+ --border-weaker-base: var(--smoke-light-alpha-3);
+ --border-weaker-hover: var(--smoke-light-alpha-4);
+ --border-weaker-active: var(--smoke-light-alpha-6);
+ --border-weaker-selected: var(--cobalt-light-alpha-4);
+ --border-weaker-disabled: var(--smoke-light-alpha-2);
+ --border-weaker-focus: var(--smoke-light-alpha-6);
@media (prefers-color-scheme: dark) {
/* OC-1-Dark */
@@ -284,8 +294,11 @@
--background-weak: #201d1d;
--background-strong: #151313;
--background-stronger: #201c1c;
- --surface-base: var(--smoke-dark-alpha-3);
--base: var(--smoke-dark-alpha-2);
+ --surface-base: var(--smoke-dark-alpha-2);
+ --surface-base-hover: #e0b7b716;
+ --surface-base-active: var(--smoke-dark-alpha-3);
+ --surface-base-interactive-active: var(--cobalt-dark-alpha-2);
--base2: var(--smoke-dark-alpha-2);
--base3: var(--smoke-dark-alpha-2);
--surface-inset-base: #0e0b0b7f;
@@ -300,8 +313,8 @@
--surface-raised-strong-hover: var(--smoke-dark-alpha-6);
--surface-raised-stronger: var(--smoke-dark-alpha-6);
--surface-raised-stronger-hover: var(--smoke-dark-alpha-7);
- --surface-weak: var(--smoke-dark-alpha-5);
- --surface-weaker: var(--smoke-dark-alpha-6);
+ --surface-weak: var(--smoke-dark-alpha-4);
+ --surface-weaker: var(--smoke-dark-alpha-5);
--surface-strong: var(--smoke-dark-alpha-7);
--surface-raised-stronger-non-alpha: var(--smoke-dark-4);
--surface-brand-base: var(--yuzu-light-9);
@@ -323,7 +336,7 @@
--surface-info-weak: var(--lilac-light-2);
--surface-info-strong: var(--lilac-light-9);
--surface-diff-hidden-base: var(--blue-dark-2);
- --surface-diff-skip-base: var(--smoke-dark-alpha-2);
+ --surface-diff-skip-base: var(--smoke-dark-alpha-1);
--surface-diff-unchanged-base: var(--smoke-dark-1);
--surface-diff-hidden-weak: var(--blue-dark-1);
--surface-diff-hidden-weaker: var(--blue-dark-3);
@@ -349,6 +362,7 @@
--text-weak: var(--smoke-dark-alpha-9);
--text-weaker: var(--smoke-dark-alpha-8);
--text-strong: var(--smoke-dark-alpha-12);
+ --text-interactive-base: var(--cobalt-dark-11);
--text-on-brand-base: var(--smoke-dark-alpha-11);
--text-on-interactive-base: var(--smoke-dark-12);
--text-on-interactive-weak: var(--smoke-dark-alpha-11);
@@ -368,12 +382,12 @@
--text-on-brand-weak: var(--smoke-dark-alpha-9);
--text-on-brand-weaker: var(--smoke-dark-alpha-8);
--text-on-brand-strong: var(--smoke-dark-alpha-12);
- --button-secondary-base: var(--smoke-dark-6);
- --button-secondary-base-hover: var(--smoke-dark-5);
+ --button-secondary-base: var(--smoke-dark-4);
+ --button-secondary-base-hover: #2a2727;
--border-base: var(--smoke-dark-alpha-7);
--border-hover: var(--smoke-dark-alpha-8);
--border-active: var(--smoke-dark-alpha-9);
- --border-selected: var(--cobalt-dark-alpha-9);
+ --border-selected: var(--cobalt-dark-alpha-11);
--border-disabled: var(--smoke-dark-alpha-8);
--border-focus: var(--smoke-dark-alpha-9);
--border-weak-base: var(--smoke-dark-alpha-6);
@@ -385,7 +399,7 @@
--border-strong-focus: var(--smoke-dark-alpha-8);
--border-weak-hover: var(--smoke-dark-alpha-7);
--border-weak-active: var(--smoke-dark-alpha-8);
- --border-weak-selected: var(--cobalt-dark-alpha-3);
+ --border-weak-selected: var(--cobalt-dark-alpha-6);
--border-weak-disabled: var(--smoke-dark-alpha-6);
--border-weak-focus: var(--smoke-dark-alpha-8);
--border-interactive-base: var(--cobalt-light-7);
@@ -446,7 +460,7 @@
--icon-agent-plan-base: var(--purple-dark-9);
--icon-agent-docs-base: var(--amber-dark-9);
--icon-agent-ask-base: var(--cyan-dark-9);
- --icon-agent-build-base: var(--blue-dark-9);
+ --icon-agent-build-base: var(--cobalt-dark-11);
--icon-on-success-base: var(--apple-dark-alpha-9);
--icon-on-success-hover: var(--apple-dark-alpha-10);
--icon-on-success-selected: var(--apple-dark-alpha-11);
@@ -494,5 +508,11 @@
--markdown-image-text: #56b6c2;
--markdown-code-block: #eeeeee;
--border-color: #ffffff;
+ --border-weaker-base: var(--smoke-dark-alpha-3);
+ --border-weaker-hover: var(--smoke-dark-alpha-4);
+ --border-weaker-active: var(--smoke-dark-alpha-6);
+ --border-weaker-selected: var(--cobalt-dark-alpha-3);
+ --border-weaker-disabled: var(--smoke-dark-alpha-2);
+ --border-weaker-focus: var(--smoke-dark-alpha-6);
}
}