mirror of
https://github.com/anomalyco/opencode.git
synced 2026-02-21 00:04:22 +00:00
Compare commits
6 Commits
app/beta-b
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f07e877204 | ||
|
|
58ad4359da | ||
|
|
ce2763720e | ||
|
|
950df3de19 | ||
|
|
1d9f05e4f5 | ||
|
|
46361cf35c |
@@ -5,8 +5,16 @@ import DESCRIPTION from "./github-triage.txt"
|
||||
const TEAM = {
|
||||
desktop: ["adamdotdevin", "iamdavidhill", "Brendonovich", "nexxeln"],
|
||||
zen: ["fwang", "MrMushrooooom"],
|
||||
tui: ["thdxr", "kommander", "rekram1-node"],
|
||||
core: ["thdxr", "rekram1-node", "jlongster"],
|
||||
tui: [
|
||||
"thdxr",
|
||||
"kommander",
|
||||
// "rekram1-node" (on vacation)
|
||||
],
|
||||
core: [
|
||||
"thdxr",
|
||||
// "rekram1-node", (on vacation)
|
||||
"jlongster",
|
||||
],
|
||||
docs: ["R44VC0RP"],
|
||||
windows: ["Hona"],
|
||||
} as const
|
||||
@@ -42,10 +50,7 @@ async function githubFetch(endpoint: string, options: RequestInit = {}) {
|
||||
export default tool({
|
||||
description: DESCRIPTION,
|
||||
args: {
|
||||
assignee: tool.schema
|
||||
.enum(ASSIGNEES as [string, ...string[]])
|
||||
.describe("The username of the assignee")
|
||||
.default("rekram1-node"),
|
||||
assignee: tool.schema.enum(ASSIGNEES as [string, ...string[]]).describe("The username of the assignee"),
|
||||
labels: tool.schema
|
||||
.array(tool.schema.enum(["nix", "opentui", "perf", "web", "desktop", "zen", "docs", "windows", "core"]))
|
||||
.describe("The labels(s) to add to the issue")
|
||||
@@ -68,7 +73,8 @@ export default tool({
|
||||
results.push("Dropped label: nix (issue does not mention nix)")
|
||||
}
|
||||
|
||||
const assignee = nix ? "rekram1-node" : web ? pick(TEAM.desktop) : args.assignee
|
||||
// const assignee = nix ? "rekram1-node" : web ? pick(TEAM.desktop) : args.assignee
|
||||
const assignee = web ? pick(TEAM.desktop) : args.assignee
|
||||
|
||||
if (labels.includes("zen") && !zen) {
|
||||
throw new Error("Only add the zen label when issue title/body contains 'zen'")
|
||||
|
||||
@@ -4,3 +4,5 @@ Choose labels and assignee using the current triage policy and ownership rules.
|
||||
Pick the most fitting labels for the issue and assign one owner.
|
||||
|
||||
If unsure, choose the team/section with the most overlap with the issue and assign a member from that team at random.
|
||||
|
||||
(Note: rekram1-node is on vacation, do not assign issues to him.)
|
||||
|
||||
@@ -452,7 +452,10 @@ export function SessionHeader() {
|
||||
variant: "ghost",
|
||||
class:
|
||||
"rounded-md h-[24px] px-3 border border-border-weak-base bg-surface-panel shadow-none data-[expanded]:bg-surface-base-active",
|
||||
classList: { "rounded-r-none": share.shareUrl() !== undefined },
|
||||
classList: {
|
||||
"rounded-r-none": share.shareUrl() !== undefined,
|
||||
"border-r-0": share.shareUrl() !== undefined,
|
||||
},
|
||||
style: { scale: 1 },
|
||||
}}
|
||||
trigger={<span class="text-12-regular">{language.t("session.share.action.share")}</span>}
|
||||
|
||||
@@ -20,12 +20,17 @@ let demoSoundState = {
|
||||
|
||||
// To prevent audio from overlapping/playing very quickly when navigating the settings menus,
|
||||
// delay the playback by 100ms during quick selection changes and pause existing sounds.
|
||||
const playDemoSound = (src: string) => {
|
||||
const stopDemoSound = () => {
|
||||
if (demoSoundState.cleanup) {
|
||||
demoSoundState.cleanup()
|
||||
}
|
||||
|
||||
clearTimeout(demoSoundState.timeout)
|
||||
demoSoundState.cleanup = undefined
|
||||
}
|
||||
|
||||
const playDemoSound = (src: string | undefined) => {
|
||||
stopDemoSound()
|
||||
if (!src) return
|
||||
|
||||
demoSoundState.timeout = setTimeout(() => {
|
||||
demoSoundState.cleanup = playSound(src)
|
||||
@@ -132,11 +137,17 @@ export const SettingsGeneral: Component = () => {
|
||||
] as const
|
||||
const fontOptionsList = [...fontOptions]
|
||||
|
||||
const soundOptions = [...SOUND_OPTIONS]
|
||||
const noneSound = { id: "none", label: "sound.option.none", src: undefined } as const
|
||||
const soundOptions = [noneSound, ...SOUND_OPTIONS]
|
||||
|
||||
const soundSelectProps = (current: () => string, set: (id: string) => void) => ({
|
||||
const soundSelectProps = (
|
||||
enabled: () => boolean,
|
||||
current: () => string,
|
||||
setEnabled: (value: boolean) => void,
|
||||
set: (id: string) => void,
|
||||
) => ({
|
||||
options: soundOptions,
|
||||
current: soundOptions.find((o) => o.id === current()),
|
||||
current: enabled() ? (soundOptions.find((o) => o.id === current()) ?? noneSound) : noneSound,
|
||||
value: (o: (typeof soundOptions)[number]) => o.id,
|
||||
label: (o: (typeof soundOptions)[number]) => language.t(o.label),
|
||||
onHighlight: (option: (typeof soundOptions)[number] | undefined) => {
|
||||
@@ -145,6 +156,12 @@ export const SettingsGeneral: Component = () => {
|
||||
},
|
||||
onSelect: (option: (typeof soundOptions)[number] | undefined) => {
|
||||
if (!option) return
|
||||
if (option.id === "none") {
|
||||
setEnabled(false)
|
||||
stopDemoSound()
|
||||
return
|
||||
}
|
||||
setEnabled(true)
|
||||
set(option.id)
|
||||
playDemoSound(option.src)
|
||||
},
|
||||
@@ -319,66 +336,45 @@ export const SettingsGeneral: Component = () => {
|
||||
title={language.t("settings.general.sounds.agent.title")}
|
||||
description={language.t("settings.general.sounds.agent.description")}
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<div data-action="settings-sounds-agent-enabled">
|
||||
<Switch
|
||||
checked={settings.sounds.agentEnabled()}
|
||||
onChange={(checked) => settings.sounds.setAgentEnabled(checked)}
|
||||
/>
|
||||
</div>
|
||||
<Select
|
||||
disabled={!settings.sounds.agentEnabled()}
|
||||
data-action="settings-sounds-agent"
|
||||
{...soundSelectProps(
|
||||
() => settings.sounds.agent(),
|
||||
(id) => settings.sounds.setAgent(id),
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Select
|
||||
data-action="settings-sounds-agent"
|
||||
{...soundSelectProps(
|
||||
() => settings.sounds.agentEnabled(),
|
||||
() => settings.sounds.agent(),
|
||||
(value) => settings.sounds.setAgentEnabled(value),
|
||||
(id) => settings.sounds.setAgent(id),
|
||||
)}
|
||||
/>
|
||||
</SettingsRow>
|
||||
|
||||
<SettingsRow
|
||||
title={language.t("settings.general.sounds.permissions.title")}
|
||||
description={language.t("settings.general.sounds.permissions.description")}
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<div data-action="settings-sounds-permissions-enabled">
|
||||
<Switch
|
||||
checked={settings.sounds.permissionsEnabled()}
|
||||
onChange={(checked) => settings.sounds.setPermissionsEnabled(checked)}
|
||||
/>
|
||||
</div>
|
||||
<Select
|
||||
disabled={!settings.sounds.permissionsEnabled()}
|
||||
data-action="settings-sounds-permissions"
|
||||
{...soundSelectProps(
|
||||
() => settings.sounds.permissions(),
|
||||
(id) => settings.sounds.setPermissions(id),
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Select
|
||||
data-action="settings-sounds-permissions"
|
||||
{...soundSelectProps(
|
||||
() => settings.sounds.permissionsEnabled(),
|
||||
() => settings.sounds.permissions(),
|
||||
(value) => settings.sounds.setPermissionsEnabled(value),
|
||||
(id) => settings.sounds.setPermissions(id),
|
||||
)}
|
||||
/>
|
||||
</SettingsRow>
|
||||
|
||||
<SettingsRow
|
||||
title={language.t("settings.general.sounds.errors.title")}
|
||||
description={language.t("settings.general.sounds.errors.description")}
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<div data-action="settings-sounds-errors-enabled">
|
||||
<Switch
|
||||
checked={settings.sounds.errorsEnabled()}
|
||||
onChange={(checked) => settings.sounds.setErrorsEnabled(checked)}
|
||||
/>
|
||||
</div>
|
||||
<Select
|
||||
disabled={!settings.sounds.errorsEnabled()}
|
||||
data-action="settings-sounds-errors"
|
||||
{...soundSelectProps(
|
||||
() => settings.sounds.errors(),
|
||||
(id) => settings.sounds.setErrors(id),
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Select
|
||||
data-action="settings-sounds-errors"
|
||||
{...soundSelectProps(
|
||||
() => settings.sounds.errorsEnabled(),
|
||||
() => settings.sounds.errors(),
|
||||
(value) => settings.sounds.setErrorsEnabled(value),
|
||||
(id) => settings.sounds.setErrors(id),
|
||||
)}
|
||||
/>
|
||||
</SettingsRow>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -565,6 +565,7 @@ export const dict = {
|
||||
"font.option.sourceCodePro": "Source Code Pro",
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
"sound.option.none": "بلا",
|
||||
"sound.option.alert01": "تنبيه 01",
|
||||
"sound.option.alert02": "تنبيه 02",
|
||||
"sound.option.alert03": "تنبيه 03",
|
||||
|
||||
@@ -571,6 +571,7 @@ export const dict = {
|
||||
"font.option.sourceCodePro": "Source Code Pro",
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
"sound.option.none": "Nenhum",
|
||||
"sound.option.alert01": "Alerta 01",
|
||||
"sound.option.alert02": "Alerta 02",
|
||||
"sound.option.alert03": "Alerta 03",
|
||||
|
||||
@@ -639,6 +639,7 @@ export const dict = {
|
||||
"font.option.sourceCodePro": "Source Code Pro",
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
"sound.option.none": "Nijedan",
|
||||
"sound.option.alert01": "Upozorenje 01",
|
||||
"sound.option.alert02": "Upozorenje 02",
|
||||
"sound.option.alert03": "Upozorenje 03",
|
||||
|
||||
@@ -635,6 +635,7 @@ export const dict = {
|
||||
"font.option.sourceCodePro": "Source Code Pro",
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
"sound.option.none": "Ingen",
|
||||
"sound.option.alert01": "Alarm 01",
|
||||
"sound.option.alert02": "Alarm 02",
|
||||
"sound.option.alert03": "Alarm 03",
|
||||
|
||||
@@ -580,6 +580,7 @@ export const dict = {
|
||||
"font.option.sourceCodePro": "Source Code Pro",
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
"sound.option.none": "Keine",
|
||||
"sound.option.alert01": "Alarm 01",
|
||||
"sound.option.alert02": "Alarm 02",
|
||||
"sound.option.alert03": "Alarm 03",
|
||||
|
||||
@@ -642,6 +642,7 @@ export const dict = {
|
||||
"font.option.sourceCodePro": "Source Code Pro",
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
"sound.option.none": "None",
|
||||
"sound.option.alert01": "Alert 01",
|
||||
"sound.option.alert02": "Alert 02",
|
||||
"sound.option.alert03": "Alert 03",
|
||||
|
||||
@@ -643,6 +643,7 @@ export const dict = {
|
||||
"font.option.sourceCodePro": "Source Code Pro",
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
"sound.option.none": "Ninguno",
|
||||
"sound.option.alert01": "Alerta 01",
|
||||
"sound.option.alert02": "Alerta 02",
|
||||
"sound.option.alert03": "Alerta 03",
|
||||
|
||||
@@ -579,6 +579,7 @@ export const dict = {
|
||||
"font.option.sourceCodePro": "Source Code Pro",
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
"sound.option.none": "Aucun",
|
||||
"sound.option.alert01": "Alerte 01",
|
||||
"sound.option.alert02": "Alerte 02",
|
||||
"sound.option.alert03": "Alerte 03",
|
||||
|
||||
@@ -569,6 +569,7 @@ export const dict = {
|
||||
"font.option.sourceCodePro": "Source Code Pro",
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
"sound.option.none": "なし",
|
||||
"sound.option.alert01": "アラート 01",
|
||||
"sound.option.alert02": "アラート 02",
|
||||
"sound.option.alert03": "アラート 03",
|
||||
|
||||
@@ -570,6 +570,7 @@ export const dict = {
|
||||
"font.option.sourceCodePro": "Source Code Pro",
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
"sound.option.none": "없음",
|
||||
"sound.option.alert01": "알림 01",
|
||||
"sound.option.alert02": "알림 02",
|
||||
"sound.option.alert03": "알림 03",
|
||||
|
||||
@@ -642,6 +642,7 @@ export const dict = {
|
||||
"font.option.sourceCodePro": "Source Code Pro",
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
"sound.option.none": "Ingen",
|
||||
"sound.option.alert01": "Varsel 01",
|
||||
"sound.option.alert02": "Varsel 02",
|
||||
"sound.option.alert03": "Varsel 03",
|
||||
|
||||
@@ -570,6 +570,7 @@ export const dict = {
|
||||
"font.option.sourceCodePro": "Source Code Pro",
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
"sound.option.none": "Brak",
|
||||
"sound.option.alert01": "Alert 01",
|
||||
"sound.option.alert02": "Alert 02",
|
||||
"sound.option.alert03": "Alert 03",
|
||||
|
||||
@@ -640,6 +640,7 @@ export const dict = {
|
||||
"font.option.sourceCodePro": "Source Code Pro",
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
"sound.option.none": "Нет",
|
||||
"sound.option.alert01": "Alert 01",
|
||||
"sound.option.alert02": "Alert 02",
|
||||
"sound.option.alert03": "Alert 03",
|
||||
|
||||
@@ -634,6 +634,7 @@ export const dict = {
|
||||
"font.option.sourceCodePro": "Source Code Pro",
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
"sound.option.none": "ไม่มี",
|
||||
"sound.option.alert01": "เสียงเตือน 01",
|
||||
"sound.option.alert02": "เสียงเตือน 02",
|
||||
"sound.option.alert03": "เสียงเตือน 03",
|
||||
|
||||
@@ -633,6 +633,7 @@ export const dict = {
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
|
||||
"sound.option.none": "无",
|
||||
"sound.option.alert01": "警报 01",
|
||||
"sound.option.alert02": "警报 02",
|
||||
"sound.option.alert03": "警报 03",
|
||||
|
||||
@@ -629,6 +629,7 @@ export const dict = {
|
||||
"font.option.sourceCodePro": "Source Code Pro",
|
||||
"font.option.ubuntuMono": "Ubuntu Mono",
|
||||
"font.option.geistMono": "Geist Mono",
|
||||
"sound.option.none": "無",
|
||||
"sound.option.alert01": "警報 01",
|
||||
"sound.option.alert02": "警報 02",
|
||||
"sound.option.alert03": "警報 03",
|
||||
|
||||
@@ -25,6 +25,12 @@ if (envPath) {
|
||||
const scriptPath = fs.realpathSync(__filename)
|
||||
const scriptDir = path.dirname(scriptPath)
|
||||
|
||||
//
|
||||
const cached = path.join(scriptDir, ".opencode")
|
||||
if (fs.existsSync(cached)) {
|
||||
run(cached)
|
||||
}
|
||||
|
||||
const platformMap = {
|
||||
darwin: "darwin",
|
||||
linux: "linux",
|
||||
|
||||
@@ -109,8 +109,14 @@ async function main() {
|
||||
// On non-Windows platforms, just verify the binary package exists
|
||||
// Don't replace the wrapper script - it handles binary execution
|
||||
const { binaryPath } = findBinary()
|
||||
console.log(`Platform binary verified at: ${binaryPath}`)
|
||||
console.log("Wrapper script will handle binary execution")
|
||||
const target = path.join(__dirname, "bin", ".opencode")
|
||||
if (fs.existsSync(target)) fs.unlinkSync(target)
|
||||
try {
|
||||
fs.linkSync(binaryPath, target)
|
||||
} catch {
|
||||
fs.copyFileSync(binaryPath, target)
|
||||
}
|
||||
fs.chmodSync(target, 0o755)
|
||||
} catch (error) {
|
||||
console.error("Failed to setup opencode binary:", error.message)
|
||||
process.exit(1)
|
||||
|
||||
@@ -189,8 +189,10 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
const [opened, setOpened] = createSignal<SessionReviewFocus | null>(null)
|
||||
|
||||
const open = () => props.open ?? store.open
|
||||
const files = createMemo(() => props.diffs.map((d) => d.file))
|
||||
const diffs = createMemo(() => new Map(props.diffs.map((d) => [d.file, d] as const)))
|
||||
const diffStyle = () => props.diffStyle ?? (props.split ? "split" : "unified")
|
||||
const hasDiffs = () => props.diffs.length > 0
|
||||
const hasDiffs = () => files().length > 0
|
||||
|
||||
const handleChange = (open: string[]) => {
|
||||
props.onOpenChange?.(open)
|
||||
@@ -199,7 +201,7 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
}
|
||||
|
||||
const handleExpandOrCollapseAll = () => {
|
||||
const next = open().length > 0 ? [] : props.diffs.map((d) => d.file)
|
||||
const next = open().length > 0 ? [] : files()
|
||||
handleChange(next)
|
||||
}
|
||||
|
||||
@@ -322,51 +324,54 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
<div data-slot="session-review-container" class={props.classes?.container}>
|
||||
<Show when={hasDiffs()} fallback={props.empty}>
|
||||
<Accordion multiple value={open()} onChange={handleChange}>
|
||||
<For each={props.diffs}>
|
||||
{(diff) => {
|
||||
<For each={files()}>
|
||||
{(file) => {
|
||||
let wrapper: HTMLDivElement | undefined
|
||||
|
||||
const expanded = createMemo(() => open().includes(diff.file))
|
||||
const diff = createMemo(() => diffs().get(file))
|
||||
const item = () => diff()!
|
||||
|
||||
const expanded = createMemo(() => open().includes(file))
|
||||
const [force, setForce] = createSignal(false)
|
||||
|
||||
const comments = createMemo(() => (props.comments ?? []).filter((c) => c.file === diff.file))
|
||||
const comments = createMemo(() => (props.comments ?? []).filter((c) => c.file === file))
|
||||
const commentedLines = createMemo(() => comments().map((c) => c.selection))
|
||||
|
||||
const beforeText = () => (typeof diff.before === "string" ? diff.before : "")
|
||||
const afterText = () => (typeof diff.after === "string" ? diff.after : "")
|
||||
const changedLines = () => diff.additions + diff.deletions
|
||||
const beforeText = () => (typeof item().before === "string" ? item().before : "")
|
||||
const afterText = () => (typeof item().after === "string" ? item().after : "")
|
||||
const changedLines = () => item().additions + item().deletions
|
||||
|
||||
const tooLarge = createMemo(() => {
|
||||
if (!expanded()) return false
|
||||
if (force()) return false
|
||||
if (isImageFile(diff.file)) return false
|
||||
if (isImageFile(file)) return false
|
||||
return changedLines() > MAX_DIFF_CHANGED_LINES
|
||||
})
|
||||
|
||||
const isAdded = () => diff.status === "added" || (beforeText().length === 0 && afterText().length > 0)
|
||||
const isAdded = () => item().status === "added" || (beforeText().length === 0 && afterText().length > 0)
|
||||
const isDeleted = () =>
|
||||
diff.status === "deleted" || (afterText().length === 0 && beforeText().length > 0)
|
||||
const isImage = () => isImageFile(diff.file)
|
||||
const isAudio = () => isAudioFile(diff.file)
|
||||
item().status === "deleted" || (afterText().length === 0 && beforeText().length > 0)
|
||||
const isImage = () => isImageFile(file)
|
||||
const isAudio = () => isAudioFile(file)
|
||||
|
||||
const diffImageSrc = dataUrlFromValue(diff.after) ?? dataUrlFromValue(diff.before)
|
||||
const [imageSrc, setImageSrc] = createSignal<string | undefined>(diffImageSrc)
|
||||
const diffImageSrc = createMemo(() => dataUrlFromValue(item().after) ?? dataUrlFromValue(item().before))
|
||||
const [imageSrc, setImageSrc] = createSignal<string | undefined>(diffImageSrc())
|
||||
const [imageStatus, setImageStatus] = createSignal<"idle" | "loading" | "error">("idle")
|
||||
|
||||
const diffAudioSrc = dataUrlFromValue(diff.after) ?? dataUrlFromValue(diff.before)
|
||||
const [audioSrc, setAudioSrc] = createSignal<string | undefined>(diffAudioSrc)
|
||||
const diffAudioSrc = createMemo(() => dataUrlFromValue(item().after) ?? dataUrlFromValue(item().before))
|
||||
const [audioSrc, setAudioSrc] = createSignal<string | undefined>(diffAudioSrc())
|
||||
const [audioStatus, setAudioStatus] = createSignal<"idle" | "loading" | "error">("idle")
|
||||
const [audioMime, setAudioMime] = createSignal<string | undefined>(undefined)
|
||||
|
||||
const selectedLines = createMemo(() => {
|
||||
const current = selection()
|
||||
if (!current || current.file !== diff.file) return null
|
||||
if (!current || current.file !== file) return null
|
||||
return current.range
|
||||
})
|
||||
|
||||
const draftRange = createMemo(() => {
|
||||
const current = commenting()
|
||||
if (!current || current.file !== diff.file) return null
|
||||
if (!current || current.file !== file) return null
|
||||
return current.range
|
||||
})
|
||||
|
||||
@@ -417,6 +422,21 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
requestAnimationFrame(updateAnchors)
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
if (!isImage()) return
|
||||
const src = diffImageSrc()
|
||||
setImageSrc(src)
|
||||
setImageStatus("idle")
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (!isAudio()) return
|
||||
const src = diffAudioSrc()
|
||||
setAudioSrc(src)
|
||||
setAudioStatus("idle")
|
||||
setAudioMime(undefined)
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
comments()
|
||||
scheduleAnchors()
|
||||
@@ -430,7 +450,7 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (!open().includes(diff.file)) return
|
||||
if (!open().includes(file)) return
|
||||
if (!isImage()) return
|
||||
if (imageSrc()) return
|
||||
if (imageStatus() !== "idle") return
|
||||
@@ -440,7 +460,7 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
if (!reader) return
|
||||
|
||||
setImageStatus("loading")
|
||||
reader(diff.file)
|
||||
reader(file)
|
||||
.then((result) => {
|
||||
const src = dataUrl(result)
|
||||
if (!src) {
|
||||
@@ -456,7 +476,7 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (!open().includes(diff.file)) return
|
||||
if (!open().includes(file)) return
|
||||
if (!isAudio()) return
|
||||
if (audioSrc()) return
|
||||
if (audioStatus() !== "idle") return
|
||||
@@ -465,7 +485,7 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
if (!reader) return
|
||||
|
||||
setAudioStatus("loading")
|
||||
reader(diff.file)
|
||||
reader(file)
|
||||
.then((result) => {
|
||||
const src = dataUrl(result)
|
||||
if (!src) {
|
||||
@@ -489,7 +509,7 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
return
|
||||
}
|
||||
|
||||
setSelection({ file: diff.file, range })
|
||||
setSelection({ file, range })
|
||||
}
|
||||
|
||||
const handleLineSelectionEnd = (range: SelectedLineRange | null) => {
|
||||
@@ -500,8 +520,8 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
return
|
||||
}
|
||||
|
||||
setSelection({ file: diff.file, range })
|
||||
setCommenting({ file: diff.file, range })
|
||||
setSelection({ file, range })
|
||||
setCommenting({ file, range })
|
||||
}
|
||||
|
||||
const openComment = (comment: SessionReviewComment) => {
|
||||
@@ -517,22 +537,22 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
|
||||
return (
|
||||
<Accordion.Item
|
||||
value={diff.file}
|
||||
id={diffId(diff.file)}
|
||||
data-file={diff.file}
|
||||
value={file}
|
||||
id={diffId(file)}
|
||||
data-file={file}
|
||||
data-slot="session-review-accordion-item"
|
||||
data-selected={props.focusedFile === diff.file ? "" : undefined}
|
||||
data-selected={props.focusedFile === file ? "" : undefined}
|
||||
>
|
||||
<StickyAccordionHeader>
|
||||
<Accordion.Trigger>
|
||||
<div data-slot="session-review-trigger-content">
|
||||
<div data-slot="session-review-file-info">
|
||||
<FileIcon node={{ path: diff.file, type: "file" }} />
|
||||
<FileIcon node={{ path: file, type: "file" }} />
|
||||
<div data-slot="session-review-file-name-container">
|
||||
<Show when={diff.file.includes("/")}>
|
||||
<span data-slot="session-review-directory">{`\u202A${getDirectory(diff.file)}\u202C`}</span>
|
||||
<Show when={file.includes("/")}>
|
||||
<span data-slot="session-review-directory">{`\u202A${getDirectory(file)}\u202C`}</span>
|
||||
</Show>
|
||||
<span data-slot="session-review-filename">{getFilename(diff.file)}</span>
|
||||
<span data-slot="session-review-filename">{getFilename(file)}</span>
|
||||
<Show when={props.onViewFile}>
|
||||
<Tooltip value="Open file" placement="top" gutter={4}>
|
||||
<button
|
||||
@@ -541,7 +561,7 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
aria-label="Open file"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
props.onViewFile?.(diff.file)
|
||||
props.onViewFile?.(file)
|
||||
}}
|
||||
>
|
||||
<Icon name="open-file" size="small" />
|
||||
@@ -557,7 +577,7 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
<span data-slot="session-review-change" data-type="added">
|
||||
{i18n.t("ui.sessionReview.change.added")}
|
||||
</span>
|
||||
<DiffChanges changes={diff} />
|
||||
<DiffChanges changes={item()} />
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={isDeleted()}>
|
||||
@@ -571,7 +591,7 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
</span>
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<DiffChanges changes={diff} />
|
||||
<DiffChanges changes={item()} />
|
||||
</Match>
|
||||
</Switch>
|
||||
<span data-slot="session-review-diff-chevron">
|
||||
@@ -586,7 +606,7 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
data-slot="session-review-diff-wrapper"
|
||||
ref={(el) => {
|
||||
wrapper = el
|
||||
anchors.set(diff.file, el)
|
||||
anchors.set(file, el)
|
||||
scheduleAnchors()
|
||||
}}
|
||||
>
|
||||
@@ -594,7 +614,7 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
<Switch>
|
||||
<Match when={isImage() && imageSrc()}>
|
||||
<div data-slot="session-review-image-container">
|
||||
<img data-slot="session-review-image" src={imageSrc()} alt={diff.file} />
|
||||
<img data-slot="session-review-image" src={imageSrc()} alt={file} />
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={isImage() && isDeleted()}>
|
||||
@@ -634,7 +654,7 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
<Match when={!isImage()}>
|
||||
<Dynamic
|
||||
component={diffComponent}
|
||||
preloadedDiff={diff.preloaded}
|
||||
preloadedDiff={item().preloaded}
|
||||
diffStyle={diffStyle()}
|
||||
onRendered={() => {
|
||||
props.onDiffRendered?.()
|
||||
@@ -646,12 +666,12 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
selectedLines={selectedLines()}
|
||||
commentedLines={commentedLines()}
|
||||
before={{
|
||||
name: diff.file!,
|
||||
contents: typeof diff.before === "string" ? diff.before : "",
|
||||
name: file,
|
||||
contents: typeof item().before === "string" ? item().before : "",
|
||||
}}
|
||||
after={{
|
||||
name: diff.file!,
|
||||
contents: typeof diff.after === "string" ? diff.after : "",
|
||||
name: file,
|
||||
contents: typeof item().after === "string" ? item().after : "",
|
||||
}}
|
||||
/>
|
||||
</Match>
|
||||
@@ -689,10 +709,10 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
onCancel={() => setCommenting(null)}
|
||||
onSubmit={(comment) => {
|
||||
props.onLineComment?.({
|
||||
file: diff.file,
|
||||
file,
|
||||
selection: range(),
|
||||
comment,
|
||||
preview: selectionPreview(diff, range()),
|
||||
preview: selectionPreview(item(), range()),
|
||||
})
|
||||
setCommenting(null)
|
||||
}}
|
||||
|
||||
@@ -91,7 +91,7 @@ function partState(part: PartType, showReasoningSummaries: boolean) {
|
||||
}
|
||||
if (part.type === "text") return part.text?.trim() ? ("visible" as const) : undefined
|
||||
if (part.type === "reasoning") {
|
||||
if (showReasoningSummaries) return "visible" as const
|
||||
if (showReasoningSummaries && part.text?.trim()) return "visible" as const
|
||||
return
|
||||
}
|
||||
if (PART_MAPPING[part.type]) return "visible" as const
|
||||
|
||||
Reference in New Issue
Block a user