chore: merge dev into v2 (#39290)
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com> Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com> Co-authored-by: Aarav Sareen <96787824+arvsrn@users.noreply.github.com> Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com> Co-authored-by: opencode <opencode@sst.dev> Co-authored-by: Jay <53023+jayair@users.noreply.github.com> Co-authored-by: David Hill <1879069+iamdavidhill@users.noreply.github.com> Co-authored-by: BB84 <110078428+BB-84C@users.noreply.github.com> Co-authored-by: Aiden Cline <aidenpcline@gmail.com> Co-authored-by: Dax <mail@thdxr.com> Co-authored-by: Brendan Allan <git@brendonovich.dev> Co-authored-by: Jay V <air@live.ca> Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com> Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Co-authored-by: Dustin Deus <deusdustin@gmail.com> Co-authored-by: Frank <frank@anoma.ly> Co-authored-by: usrnk1 <7547651+usrnk1@users.noreply.github.com> Co-authored-by: Jack <jack@anoma.ly> Co-authored-by: Sebastian <hasta84@gmail.com> Co-authored-by: Jérôme Benoit <jerome.benoit@sap.com> Co-authored-by: Test User <test@test.com> Co-authored-by: Simon Klee <hello@simonklee.dk> Co-authored-by: Rahul A Mistry <149420892+ProdigyRahul@users.noreply.github.com> Co-authored-by: Qiping Li <liqiping1991@gmail.com> Co-authored-by: liqiping <liqiping@msh.team> Co-authored-by: OpeOginni <107570612+OpeOginni@users.noreply.github.com> Co-authored-by: Matthias Reso <13337103+mreso@users.noreply.github.com> Co-authored-by: tobwen <1864057+tobwen@users.noreply.github.com> Co-authored-by: Daniel Polito <danielbpolito@gmail.com> Co-authored-by: opencode <noreply@opencode.ai> Co-authored-by: Devin R Leopold <devin.leopold@gmail.com> Co-authored-by: Zach Bruggeman <mail@bruggie.com> Co-authored-by: Zach Bruggeman <zbruggeman@ramp.com> Co-authored-by: Kit Langton <kit.langton@gmail.com> Co-authored-by: David Siewert <david1gruppenplan@gmail.com> Co-authored-by: Andrei Dziahel <develop7@develop7.info> Co-authored-by: adityachaudhary99 <adityaachaudhary2003@gmail.com> Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com> Co-authored-by: Matt Carey <mcarey@cloudflare.com>
This commit is contained in:
parent
7211c9934a
commit
302e9b45ab
263 changed files with 12516 additions and 4822 deletions
|
|
@ -21,7 +21,7 @@ describe("message-file", () => {
|
|||
expect(attached(file())).toBe(false)
|
||||
})
|
||||
|
||||
test("treats only non-attachment source ranges as inline references", () => {
|
||||
test("keeps data-backed file mentions inline", () => {
|
||||
expect(
|
||||
inline(
|
||||
file({
|
||||
|
|
@ -34,18 +34,16 @@ describe("message-file", () => {
|
|||
),
|
||||
).toBe(true)
|
||||
|
||||
expect(
|
||||
inline(
|
||||
file({
|
||||
url: "data:text/plain;base64,SGVsbG8=",
|
||||
source: {
|
||||
type: "file",
|
||||
path: "/repo/README.txt",
|
||||
text: { value: "@README.txt", start: 0, end: 11 },
|
||||
},
|
||||
}),
|
||||
),
|
||||
).toBe(false)
|
||||
const mentioned = file({
|
||||
url: "data:text/plain;base64,SGVsbG8=",
|
||||
source: {
|
||||
type: "file",
|
||||
path: "/repo/README.txt",
|
||||
text: { value: "@README.txt", start: 0, end: 11 },
|
||||
},
|
||||
})
|
||||
expect(inline(mentioned)).toBe(true)
|
||||
expect(attached(mentioned)).toBe(false)
|
||||
})
|
||||
|
||||
test("separates image and file attachment kinds", () => {
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@ import { getFilename } from "@opencode-ai/core/util/path"
|
|||
import type { FilePart } from "@opencode-ai/sdk/v2"
|
||||
|
||||
export function attached(part: FilePart) {
|
||||
return part.url.startsWith("data:")
|
||||
return part.url.startsWith("data:") && !inline(part)
|
||||
}
|
||||
|
||||
export function inline(part: FilePart) {
|
||||
if (attached(part)) return false
|
||||
return part.source?.text?.start !== undefined && part.source?.text?.end !== undefined
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -598,6 +598,27 @@
|
|||
}
|
||||
}
|
||||
|
||||
[data-component="todos"] {
|
||||
padding: 10px 0 24px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
[data-component="checkbox"] {
|
||||
--checkbox-align: flex-start;
|
||||
--checkbox-offset: 0.5px;
|
||||
}
|
||||
|
||||
[data-slot="message-part-todo-content"] {
|
||||
line-height: var(--line-height-normal);
|
||||
|
||||
&[data-completed="completed"] {
|
||||
text-decoration: line-through;
|
||||
color: var(--v2-text-text-faint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[data-component="context-tool-group-trigger"] {
|
||||
width: 100%;
|
||||
min-height: 24px;
|
||||
|
|
@ -681,6 +702,7 @@
|
|||
[data-component="bash-output"],
|
||||
[data-component="edit-content"],
|
||||
[data-component="write-content"],
|
||||
[data-component="todos"],
|
||||
[data-component="diagnostics"],
|
||||
.error-card {
|
||||
-webkit-user-select: text;
|
||||
|
|
@ -1438,6 +1460,10 @@ body:not([data-new-layout]) {
|
|||
color: var(--text-interactive-base);
|
||||
}
|
||||
|
||||
[data-slot="message-part-todo-content"][data-completed="completed"] {
|
||||
color: var(--text-weaker);
|
||||
}
|
||||
|
||||
[data-component="diagnostics"] {
|
||||
background-color: var(--surface-critical-weak);
|
||||
border-top: 1px solid var(--border-critical-base);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import {
|
|||
TextPart,
|
||||
ToolPart,
|
||||
UserMessage,
|
||||
Todo,
|
||||
QuestionAnswer,
|
||||
QuestionInfo,
|
||||
} from "@opencode-ai/sdk/v2"
|
||||
|
|
@ -41,6 +42,7 @@ import { Collapsible } from "@opencode-ai/ui/collapsible"
|
|||
import { FileIcon } from "@opencode-ai/ui/file-icon"
|
||||
import { Icon } from "@opencode-ai/ui/icon"
|
||||
import { ToolErrorCard } from "./tool-error-card"
|
||||
import { Checkbox } from "@opencode-ai/ui/checkbox"
|
||||
import { DiffChanges } from "@opencode-ai/ui/diff-changes"
|
||||
import { Markdown } from "./markdown"
|
||||
import { ImagePreview } from "@opencode-ai/ui/image-preview"
|
||||
|
|
@ -519,6 +521,7 @@ export function getToolInfo(
|
|||
}
|
||||
}
|
||||
case "bash":
|
||||
case "shell":
|
||||
return {
|
||||
icon: "console",
|
||||
title: i18n.t("ui.tool.shell"),
|
||||
|
|
@ -545,6 +548,11 @@ export function getToolInfo(
|
|||
? `${input.files.length} ${i18n.t(input.files.length > 1 ? "ui.common.file.other" : "ui.common.file.one")}`
|
||||
: undefined,
|
||||
}
|
||||
case "todowrite":
|
||||
return {
|
||||
icon: "checklist",
|
||||
title: i18n.t("ui.tool.todos"),
|
||||
}
|
||||
case "question":
|
||||
return {
|
||||
icon: "bubble-5",
|
||||
|
|
@ -608,6 +616,8 @@ function taskSession(
|
|||
}
|
||||
|
||||
const CONTEXT_GROUP_TOOLS = new Set(["read", "glob", "grep", "list"])
|
||||
const HIDDEN_TOOLS = new Set(["todowrite"])
|
||||
|
||||
function list<T>(value: T[] | undefined | null, fallback: T[]) {
|
||||
if (Array.isArray(value)) return value
|
||||
return fallback
|
||||
|
|
@ -711,6 +721,7 @@ function index<T extends { id: string }>(items: readonly T[]) {
|
|||
|
||||
export function renderable(part: PartType, showReasoningSummaries = true) {
|
||||
if (part.type === "tool") {
|
||||
if (HIDDEN_TOOLS.has(part.tool)) return false
|
||||
if (part.tool === "question") return part.state.status !== "pending" && part.state.status !== "running"
|
||||
return true
|
||||
}
|
||||
|
|
@ -720,7 +731,7 @@ export function renderable(part: PartType, showReasoningSummaries = true) {
|
|||
}
|
||||
|
||||
function toolDefaultOpen(tool: string, shell = false, edit = false) {
|
||||
if (tool === "bash") return shell
|
||||
if (tool === "bash" || tool === "shell") return shell
|
||||
if (tool === "edit" || tool === "write" || tool === "patch" || tool === "apply_patch") return edit
|
||||
}
|
||||
|
||||
|
|
@ -1081,11 +1092,7 @@ export function ContextToolGroup(props: {
|
|||
<div data-component="context-tool-group-trigger">
|
||||
<span
|
||||
data-slot="context-tool-group-title"
|
||||
class="min-w-0 flex items-center gap-2 text-14-medium"
|
||||
classList={{
|
||||
"text-text-strong": pending(),
|
||||
"text-text-weak": !pending(),
|
||||
}}
|
||||
class="min-w-0 flex items-center gap-2 text-14-medium text-text-strong"
|
||||
>
|
||||
<span data-slot="context-tool-group-label" class="shrink-0">
|
||||
<ToolStatusTitle
|
||||
|
|
@ -1097,11 +1104,7 @@ export function ContextToolGroup(props: {
|
|||
</span>
|
||||
<span
|
||||
data-slot="context-tool-group-summary"
|
||||
class="min-w-0 overflow-hidden text-ellipsis whitespace-nowrap font-normal"
|
||||
classList={{
|
||||
"text-text-base": pending(),
|
||||
"text-text-weak": !pending(),
|
||||
}}
|
||||
class="min-w-0 overflow-hidden text-ellipsis whitespace-nowrap font-normal text-text-base"
|
||||
>
|
||||
<AnimatedCountList
|
||||
items={[
|
||||
|
|
@ -1505,7 +1508,7 @@ export function registerTool(input: { name: string; render?: ToolComponent }) {
|
|||
}
|
||||
|
||||
export function getTool(name: string) {
|
||||
return state[name === "apply_patch" ? "patch" : name]?.render
|
||||
return state[name === "apply_patch" ? "patch" : name === "bash" ? "shell" : name]?.render
|
||||
}
|
||||
|
||||
export const ToolRegistry = {
|
||||
|
|
@ -1553,6 +1556,8 @@ PART_MAPPING["tool"] = function ToolPartDisplay(props) {
|
|||
const data = useData()
|
||||
const i18n = useI18n()
|
||||
const part = () => props.part as ToolPart
|
||||
if (part().tool === "todowrite") return null
|
||||
|
||||
const hideQuestion = createMemo(
|
||||
() => part().tool === "question" && (part().state.status === "pending" || part().state.status === "running"),
|
||||
)
|
||||
|
|
@ -2098,7 +2103,7 @@ ToolRegistry.register({
|
|||
})
|
||||
|
||||
ToolRegistry.register({
|
||||
name: "bash",
|
||||
name: "shell",
|
||||
render(props) {
|
||||
const i18n = useI18n()
|
||||
const pending = () => props.status === "pending" || props.status === "running"
|
||||
|
|
@ -2537,6 +2542,57 @@ ToolRegistry.register({
|
|||
},
|
||||
})
|
||||
|
||||
ToolRegistry.register({
|
||||
name: "todowrite",
|
||||
render(props) {
|
||||
const i18n = useI18n()
|
||||
const todos = createMemo(() => {
|
||||
const meta = props.metadata?.todos
|
||||
if (Array.isArray(meta)) return meta
|
||||
|
||||
const input = props.input.todos
|
||||
if (Array.isArray(input)) return input
|
||||
|
||||
return []
|
||||
})
|
||||
|
||||
const subtitle = createMemo(() => {
|
||||
const list = todos()
|
||||
if (list.length === 0) return ""
|
||||
return `${list.filter((t: Todo) => t.status === "completed").length}/${list.length}`
|
||||
})
|
||||
|
||||
return (
|
||||
<BasicTool
|
||||
{...props}
|
||||
defaultOpen
|
||||
icon="checklist"
|
||||
trigger={{
|
||||
title: i18n.t("ui.tool.todos"),
|
||||
subtitle: subtitle(),
|
||||
}}
|
||||
>
|
||||
<Show when={todos().length}>
|
||||
<div data-component="todos">
|
||||
<For each={todos()}>
|
||||
{(todo: Todo) => (
|
||||
<Checkbox readOnly checked={todo.status === "completed"}>
|
||||
<span
|
||||
data-slot="message-part-todo-content"
|
||||
data-completed={todo.status === "completed" ? "completed" : undefined}
|
||||
>
|
||||
{todo.content}
|
||||
</span>
|
||||
</Checkbox>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</Show>
|
||||
</BasicTool>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
ToolRegistry.register({
|
||||
name: "question",
|
||||
render(props) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { parseDiffFromFile, parsePatchFiles, type FileDiffMetadata } from "@pierre/diffs"
|
||||
import { parsePatch } from "diff"
|
||||
import type { SnapshotFileDiff, VcsFileDiff } from "@opencode-ai/sdk/v2"
|
||||
import type { FileDiffInfo } from "@opencode-ai/client/promise"
|
||||
|
||||
type LegacyDiff = {
|
||||
file: string
|
||||
|
|
@ -12,7 +13,8 @@ type LegacyDiff = {
|
|||
status?: "added" | "deleted" | "modified"
|
||||
}
|
||||
|
||||
type ReviewDiff = (SnapshotFileDiff | VcsFileDiff | LegacyDiff) & { file: string }
|
||||
type SnapshotDiff = SnapshotFileDiff & { file: string }
|
||||
type ReviewDiff = SnapshotDiff | FileDiffInfo | VcsFileDiff | LegacyDiff
|
||||
export type DiffSource = Pick<LegacyDiff, "file" | "patch" | "before" | "after">
|
||||
|
||||
export type ViewDiff = {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { checksum } from "@opencode-ai/core/util/encode"
|
|||
import { createEffect, createMemo, For, Match, onCleanup, Show, Switch, untrack, type JSX } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { type FileContent, type SnapshotFileDiff, type VcsFileDiff } from "@opencode-ai/sdk/v2"
|
||||
import type { FileDiffInfo } from "@opencode-ai/client/promise"
|
||||
import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr"
|
||||
import { type SelectedLineRange } from "@pierre/diffs"
|
||||
import { Dynamic } from "solid-js/web"
|
||||
|
|
@ -62,14 +63,14 @@ export type SessionReviewCommentActions = {
|
|||
|
||||
export type SessionReviewFocus = { file: string; id: string }
|
||||
|
||||
type RawReviewDiff = (SnapshotFileDiff | VcsFileDiff) & {
|
||||
file: string
|
||||
type RawReviewDiff = (SnapshotFileDiff | FileDiffInfo | VcsFileDiff) & {
|
||||
preloaded?: PreloadMultiFileDiffResult<any>
|
||||
}
|
||||
type ReviewDiff = (SnapshotFileDiff | VcsFileDiff) & {
|
||||
file: string
|
||||
type ReviewDiff = ((SnapshotFileDiff & { file: string }) | FileDiffInfo | VcsFileDiff) & {
|
||||
preloaded?: PreloadMultiFileDiffResult<any>
|
||||
}
|
||||
type Item = ViewDiff & { preloaded?: PreloadMultiFileDiffResult<any> }
|
||||
|
||||
function diff(value: unknown): value is ReviewDiff {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) return false
|
||||
if (!("file" in value) || typeof value.file !== "string") return false
|
||||
|
|
@ -185,7 +186,7 @@ export const SessionReview = (props: SessionReviewProps) => {
|
|||
const itemsMap = createMemo(() =>
|
||||
Object.fromEntries(list(props.diffs).map((diff) => [diff.file, { ...normalize(diff), preloaded: diff.preloaded }])),
|
||||
)
|
||||
const files = createMemo(() => props.diffs.map((diff) => diff.file))
|
||||
const files = createMemo(() => props.diffs.map((diff) => diff.file!))
|
||||
const grouped = createMemo(() => {
|
||||
const next = new Map<string, SessionReviewComment[]>()
|
||||
for (const comment of props.comments ?? []) {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import {
|
|||
type SnapshotFileDiff,
|
||||
Message as MessageType,
|
||||
Part as PartType,
|
||||
type UserMessage,
|
||||
} from "@opencode-ai/sdk/v2/client"
|
||||
import type { FileDiffInfo } from "@opencode-ai/client/promise"
|
||||
import type { SessionStatus } from "@opencode-ai/sdk/v2"
|
||||
import { useData } from "../context"
|
||||
import { useFileComponent } from "@opencode-ai/ui/context/file"
|
||||
|
|
@ -91,21 +91,17 @@ function list<T>(value: T[] | undefined | null, fallback: T[]) {
|
|||
return fallback
|
||||
}
|
||||
|
||||
type SummaryDiffInput = NonNullable<NonNullable<UserMessage["summary"]>["diffs"]>[number]
|
||||
type SummaryDiff = SnapshotFileDiff & { file: string; patch: string }
|
||||
type SummaryDiff = (SnapshotFileDiff & { file: string }) | FileDiffInfo
|
||||
|
||||
function summaryDiff(value: SummaryDiffInput): value is SummaryDiff {
|
||||
return (
|
||||
typeof value.file === "string" &&
|
||||
typeof value.patch === "string" &&
|
||||
typeof value.additions === "number" &&
|
||||
typeof value.deletions === "number" &&
|
||||
value.status !== undefined
|
||||
)
|
||||
function summaryDiff(value: SnapshotFileDiff): value is SummaryDiff {
|
||||
return typeof value.file === "string"
|
||||
}
|
||||
|
||||
const hidden = new Set(["todowrite"])
|
||||
|
||||
function partState(part: PartType, showReasoningSummaries: boolean) {
|
||||
if (part.type === "tool") {
|
||||
if (hidden.has(part.tool)) return
|
||||
if (part.tool === "question" && (part.state.status === "pending" || part.state.status === "running")) return
|
||||
return "visible" as const
|
||||
}
|
||||
|
|
|
|||
|
|
@ -427,6 +427,25 @@ const TOOL_SAMPLES = {
|
|||
title: "playwriter",
|
||||
metadata: {},
|
||||
},
|
||||
todowrite: {
|
||||
tool: "todowrite",
|
||||
input: {
|
||||
todos: [
|
||||
{ content: "Create data generators", status: "completed", priority: "high" },
|
||||
{ content: "Build UI controls", status: "in_progress", priority: "high" },
|
||||
{ content: "Add CSS export", status: "pending", priority: "medium" },
|
||||
],
|
||||
},
|
||||
output: "",
|
||||
title: "Todos",
|
||||
metadata: {
|
||||
todos: [
|
||||
{ content: "Create data generators", status: "completed", priority: "high" },
|
||||
{ content: "Build UI controls", status: "in_progress", priority: "high" },
|
||||
{ content: "Add CSS export", status: "pending", priority: "medium" },
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ const docs = `### Overview
|
|||
Tool call failure summary styled like a tool trigger.
|
||||
|
||||
### API
|
||||
- Required: \`tool\` (tool id, e.g. patch, bash)
|
||||
- Required: \`tool\` (tool id, e.g. apply_patch, bash)
|
||||
- Required: \`error\` (error string)
|
||||
|
||||
### Behavior
|
||||
|
|
@ -14,9 +14,9 @@ Tool call failure summary styled like a tool trigger.
|
|||
|
||||
const samples = [
|
||||
{
|
||||
tool: "patch",
|
||||
tool: "apply_patch",
|
||||
error:
|
||||
"patch verification failed: Failed to find expected lines in /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/session-turn.tsx",
|
||||
"apply_patch verification failed: Failed to find expected lines in /Users/davidhill/Documents/Local/opencode/packages/ui/src/components/session-turn.tsx",
|
||||
},
|
||||
{
|
||||
tool: "bash",
|
||||
|
|
@ -62,13 +62,13 @@ export default {
|
|||
},
|
||||
},
|
||||
args: {
|
||||
tool: "patch",
|
||||
tool: "apply_patch",
|
||||
error: samples[0].error,
|
||||
},
|
||||
argTypes: {
|
||||
tool: {
|
||||
control: "select",
|
||||
options: ["patch", "bash", "read", "glob", "grep", "webfetch", "websearch", "question"],
|
||||
options: ["apply_patch", "bash", "read", "glob", "grep", "webfetch", "websearch", "question"],
|
||||
},
|
||||
error: {
|
||||
control: "text",
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ export function ToolErrorCard(props: ToolErrorCardProps) {
|
|||
webfetch: "ui.tool.webfetch",
|
||||
websearch: "ui.tool.websearch",
|
||||
bash: "ui.tool.shell",
|
||||
shell: "ui.tool.shell",
|
||||
patch: "ui.tool.patch",
|
||||
apply_patch: "ui.tool.patch",
|
||||
question: "ui.tool.questions",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type { Message, Part, Provider, Session, SessionStatus, SnapshotFileDiff } from "@opencode-ai/sdk/v2"
|
||||
import type { Message, Session, Part, SnapshotFileDiff, SessionStatus, Provider } from "@opencode-ai/sdk/v2"
|
||||
import type { FileDiffInfo } from "@opencode-ai/client/promise"
|
||||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||
import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr"
|
||||
|
||||
|
|
@ -21,7 +22,7 @@ type Data = {
|
|||
[sessionID: string]: SessionStatus
|
||||
}
|
||||
session_diff: {
|
||||
[sessionID: string]: SnapshotFileDiff[]
|
||||
[sessionID: string]: (SnapshotFileDiff | FileDiffInfo)[]
|
||||
}
|
||||
session_diff_preload?: {
|
||||
[sessionID: string]: PreloadMultiFileDiffResult<any>[]
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { useI18n } from "@opencode-ai/ui/context/i18n"
|
|||
import { mediaKindFromPath } from "../../pierre/media"
|
||||
import { cloneSelectedLineRange, previewSelectedLines } from "../../pierre/selection-bridge"
|
||||
import type { FileContent, SnapshotFileDiff, VcsFileDiff } from "@opencode-ai/sdk/v2"
|
||||
import type { FileDiffInfo } from "@opencode-ai/client/promise"
|
||||
import { createEffect, createMemo, onCleanup, Show, untrack } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { Dynamic } from "solid-js/web"
|
||||
|
|
@ -27,7 +28,7 @@ import { LineCommentV2OverflowIcon } from "@opencode-ai/ui/v2/line-comment-v2"
|
|||
import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2"
|
||||
import "./session-review-v2.css"
|
||||
|
||||
type ReviewDiff = (SnapshotFileDiff | VcsFileDiff) & { file: string }
|
||||
type ReviewDiff = (SnapshotFileDiff & { file: string }) | FileDiffInfo | VcsFileDiff
|
||||
|
||||
export type SessionReviewFilePreviewV2Props = {
|
||||
file: string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue