diff options
| author | Adam <[email protected]> | 2025-11-25 16:02:27 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2025-11-25 16:02:31 -0600 |
| commit | 447713244820e875e192a5815c4d8bc76c03b40f (patch) | |
| tree | a3df06b1df0585a8387c37826ea516ce08169289 /packages/enterprise | |
| parent | eaeea45ace01e20405d49d1a659030a4d131dc83 (diff) | |
| download | opencode-447713244820e875e192a5815c4d8bc76c03b40f.tar.gz opencode-447713244820e875e192a5815c4d8bc76c03b40f.zip | |
fix: sanitize absolute paths
Diffstat (limited to 'packages/enterprise')
| -rw-r--r-- | packages/enterprise/src/routes/share/[shareID].tsx | 403 |
1 files changed, 205 insertions, 198 deletions
diff --git a/packages/enterprise/src/routes/share/[shareID].tsx b/packages/enterprise/src/routes/share/[shareID].tsx index 292038094..42dd7e957 100644 --- a/packages/enterprise/src/routes/share/[shareID].tsx +++ b/packages/enterprise/src/routes/share/[shareID].tsx @@ -141,219 +141,226 @@ export default function () { }} > <Show when={data()}> - {(data) => ( - <DataProvider data={data()}> - {iife(() => { - const [store, setStore] = createStore({ - messageId: undefined as string | undefined, - }) - const match = createMemo(() => Binary.search(data().session, data().sessionID, (s) => s.id)) - if (!match().found) throw new Error(`Session ${data().sessionID} not found`) - const info = createMemo(() => data().session[match().index]) - const messages = createMemo(() => - data().sessionID - ? (data().message[data().sessionID]?.filter((m) => m.role === "user") ?? []).sort( - (a, b) => b.time.created - a.time.created, - ) - : [], - ) - const firstUserMessage = createMemo(() => messages().at(0)) - const activeMessage = createMemo( - () => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(), - ) - function setActiveMessage(message: UserMessage | undefined) { - if (message) { - setStore("messageId", message.id) - } else { - setStore("messageId", undefined) + {(data) => { + const match = createMemo(() => Binary.search(data().session, data().sessionID, (s) => s.id)) + if (!match().found) throw new Error(`Session ${data().sessionID} not found`) + const info = createMemo(() => data().session[match().index]) + + return ( + <DataProvider data={data()} directory={info().directory}> + {iife(() => { + const [store, setStore] = createStore({ + messageId: undefined as string | undefined, + }) + const messages = createMemo(() => + data().sessionID + ? (data().message[data().sessionID]?.filter((m) => m.role === "user") ?? []).sort( + (a, b) => b.time.created - a.time.created, + ) + : [], + ) + const firstUserMessage = createMemo(() => messages().at(0)) + const activeMessage = createMemo( + () => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(), + ) + function setActiveMessage(message: UserMessage | undefined) { + if (message) { + setStore("messageId", message.id) + } else { + setStore("messageId", undefined) + } } - } - const provider = createMemo(() => activeMessage()?.model?.providerID) - const modelID = createMemo(() => activeMessage()?.model?.modelID) - const model = createMemo(() => data().model[data().sessionID]?.find((m) => m.id === modelID())) - const diffs = createMemo(() => { - const diffs = data().session_diff[data().sessionID] ?? [] - const preloaded = data().session_diff_preload[data().sessionID] ?? [] - return diffs.map((diff) => ({ - ...diff, - preloaded: preloaded.find((d) => d.newFile.name === diff.file), - })) - }) + const provider = createMemo(() => activeMessage()?.model?.providerID) + const modelID = createMemo(() => activeMessage()?.model?.modelID) + const model = createMemo(() => data().model[data().sessionID]?.find((m) => m.id === modelID())) + const diffs = createMemo(() => { + const diffs = data().session_diff[data().sessionID] ?? [] + const preloaded = data().session_diff_preload[data().sessionID] ?? [] + return diffs.map((diff) => ({ + ...diff, + preloaded: preloaded.find((d) => d.newFile.name === diff.file), + })) + }) - const title = () => ( - <div class="flex flex-col gap-4 shrink-0"> - <div class="h-8 flex gap-4 items-center justify-start self-stretch"> - <div class="pl-[2.5px] pr-2 flex items-center gap-1.75 bg-surface-strong shadow-xs-border-base"> - <Mark class="shrink-0 w-3 my-0.5" /> - <div class="text-12-mono text-text-base">v{info().version}</div> - </div> - <div class="flex gap-2 items-center"> - <img src={`https://models.dev/logos/${provider()}.svg`} class="size-3.5 shrink-0 dark:invert" /> - <div class="text-12-regular text-text-base">{model()?.name ?? modelID()}</div> - </div> - <div class="text-12-regular text-text-weaker"> - {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")} + const title = () => ( + <div class="flex flex-col gap-4 shrink-0"> + <div class="h-8 flex gap-4 items-center justify-start self-stretch"> + <div class="pl-[2.5px] pr-2 flex items-center gap-1.75 bg-surface-strong shadow-xs-border-base"> + <Mark class="shrink-0 w-3 my-0.5" /> + <div class="text-12-mono text-text-base">v{info().version}</div> + </div> + <div class="flex gap-2 items-center"> + <img src={`https://models.dev/logos/${provider()}.svg`} class="size-3.5 shrink-0 dark:invert" /> + <div class="text-12-regular text-text-base">{model()?.name ?? modelID()}</div> + </div> + <div class="text-12-regular text-text-weaker"> + {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")} + </div> </div> + <div class="text-left text-16-medium text-text-strong">{info().title}</div> </div> - <div class="text-left text-16-medium text-text-strong">{info().title}</div> - </div> - ) + ) - const turns = () => ( - <div class="relative mt-2 pt-6 pb-8 px-4 min-w-0 w-full h-full overflow-y-auto no-scrollbar"> - {title()} - <div class="flex flex-col gap-15 items-start justify-start mt-4"> - <For each={messages()}> - {(message) => ( - <SessionTurn - sessionID={data().sessionID} - messageID={message.id} - classes={{ - root: "min-w-0 w-full relative", - content: - "flex flex-col justify-between !overflow-visible [&_[data-slot=session-turn-message-header]]:top-[-32px]", - }} - /> - )} - </For> - </div> - <div class="flex items-center justify-center pt-20 pb-8 shrink-0"> - <Logo class="w-58.5 opacity-12" /> + const turns = () => ( + <div class="relative mt-2 pt-6 pb-8 px-4 min-w-0 w-full h-full overflow-y-auto no-scrollbar"> + {title()} + <div class="flex flex-col gap-15 items-start justify-start mt-4"> + <For each={messages()}> + {(message) => ( + <SessionTurn + sessionID={data().sessionID} + messageID={message.id} + classes={{ + root: "min-w-0 w-full relative", + content: + "flex flex-col justify-between !overflow-visible [&_[data-slot=session-turn-message-header]]:top-[-32px]", + }} + /> + )} + </For> + </div> + <div class="flex items-center justify-center pt-20 pb-8 shrink-0"> + <Logo class="w-58.5 opacity-12" /> + </div> </div> - </div> - ) + ) - const wide = createMemo(() => diffs().length === 0) + const wide = createMemo(() => diffs().length === 0) - return ( - <div class="relative bg-background-stronger w-screen h-screen overflow-hidden flex flex-col"> - <header class="h-12 px-6 py-2 flex items-center justify-between self-stretch bg-background-base border-b border-border-weak-base"> - <div class=""> - <a href="https://opencode.ai"> - <Mark /> - </a> - </div> - <div class="flex gap-3 items-center"> - <IconButton - as={"a"} - href="https://github.com/sst/opencode" - target="_blank" - icon="github" - variant="ghost" - /> - <IconButton - as={"a"} - href="https://opencode.ai/discord" - target="_blank" - icon="discord" - variant="ghost" - /> - </div> - </header> - <div class="select-text flex flex-col flex-1 min-h-0"> - <div class="hidden md:flex w-full flex-1 min-h-0"> - <div - classList={{ - "@container relative shrink-0 pt-14 flex flex-col gap-10 min-h-0 w-full mx-auto": true, - "px-21 @4xl:px-6 max-w-2xl": !wide(), - "px-6 max-w-2xl": wide(), - }} - > - {title()} - <div class="flex items-start justify-start h-full min-h-0"> - <Show when={messages().length > 1}> - <> - <div class="md:hidden absolute right-full"> - <MessageNav - class="mt-2 mr-3" - messages={messages()} - current={activeMessage()} - onMessageSelect={setActiveMessage} - size="compact" - /> - </div> - <div - classList={{ - "hidden md:block": true, - "absolute right-[90%]": !wide(), - "absolute right-full": wide(), - }} - > - <MessageNav + return ( + <div class="relative bg-background-stronger w-screen h-screen overflow-hidden flex flex-col"> + <header class="h-12 px-6 py-2 flex items-center justify-between self-stretch bg-background-base border-b border-border-weak-base"> + <div class=""> + <a href="https://opencode.ai"> + <Mark /> + </a> + </div> + <div class="flex gap-3 items-center"> + <IconButton + as={"a"} + href="https://github.com/sst/opencode" + target="_blank" + icon="github" + variant="ghost" + /> + <IconButton + as={"a"} + href="https://opencode.ai/discord" + target="_blank" + icon="discord" + variant="ghost" + /> + </div> + </header> + <div class="select-text flex flex-col flex-1 min-h-0"> + <div class="hidden md:flex w-full flex-1 min-h-0"> + <div + classList={{ + "@container relative shrink-0 pt-14 flex flex-col gap-10 min-h-0 w-full mx-auto": true, + "px-21 @4xl:px-6 max-w-2xl": !wide(), + "px-6 max-w-2xl": wide(), + }} + > + {title()} + <div class="flex items-start justify-start h-full min-h-0"> + <Show when={messages().length > 1}> + <> + <div class="md:hidden absolute right-full"> + <MessageNav + class="mt-2 mr-3" + messages={messages()} + current={activeMessage()} + onMessageSelect={setActiveMessage} + size="compact" + /> + </div> + <div classList={{ - "mt-2.5 mr-3": !wide(), - "mt-0.5 mr-8": wide(), + "hidden md:block": true, + "absolute right-[90%]": !wide(), + "absolute right-full": wide(), }} - messages={messages()} - current={activeMessage()} - onMessageSelect={setActiveMessage} - size={wide() ? "normal" : "compact"} - /> + > + <MessageNav + classList={{ + "mt-2.5 mr-3": !wide(), + "mt-0.5 mr-8": wide(), + }} + messages={messages()} + current={activeMessage()} + onMessageSelect={setActiveMessage} + size={wide() ? "normal" : "compact"} + /> + </div> + </> + </Show> + <SessionTurn + sessionID={data().sessionID} + messageID={store.messageId ?? firstUserMessage()!.id!} + classes={{ root: "grow", content: "flex flex-col justify-between", container: "pb-20" }} + > + <div class="flex items-center justify-center pb-8 shrink-0"> + <Logo class="w-58.5 opacity-12" /> </div> - </> - </Show> - <SessionTurn - sessionID={data().sessionID} - messageID={store.messageId ?? firstUserMessage()!.id!} - classes={{ root: "grow", content: "flex flex-col justify-between", container: "pb-20" }} - > - <div class="flex items-center justify-center pb-8 shrink-0"> - <Logo class="w-58.5 opacity-12" /> - </div> - </SessionTurn> + </SessionTurn> + </div> </div> + <Show when={diffs().length > 0}> + <div class="relative grow pt-14 flex-1 min-h-0 border-l border-border-weak-base"> + <SessionReview + diffs={diffs()} + classes={{ + root: "pb-20", + header: "px-6", + container: "px-6", + }} + /> + </div> + </Show> </div> - <Show when={diffs().length > 0}> - <div class="relative grow pt-14 flex-1 min-h-0 border-l border-border-weak-base"> - <SessionReview - diffs={diffs()} - classes={{ - root: "pb-20", - header: "px-6", - container: "px-6", - }} - /> - </div> - </Show> + <Switch> + <Match when={diffs().length > 0}> + <Tabs class="md:hidden"> + <Tabs.List> + <Tabs.Trigger value="session" class="w-1/2" classes={{ button: "w-full" }}> + Session + </Tabs.Trigger> + <Tabs.Trigger value="review" class="w-1/2 !border-r-0" classes={{ button: "w-full" }}> + 5 Files Changed + </Tabs.Trigger> + </Tabs.List> + <Tabs.Content value="session" class="!overflow-hidden"> + {turns()} + </Tabs.Content> + <Tabs.Content + forceMount + value="review" + class="!overflow-hidden hidden data-[selected]:block" + > + <div class="relative h-full pt-8 overflow-y-auto no-scrollbar"> + <SessionReview + diffs={diffs()} + classes={{ + root: "pb-20", + header: "px-4", + container: "px-4", + }} + /> + </div> + </Tabs.Content> + </Tabs> + </Match> + <Match when={true}> + <div class="md:hidden !overflow-hidden">{turns()}</div> + </Match> + </Switch> </div> - <Switch> - <Match when={diffs().length > 0}> - <Tabs class="md:hidden"> - <Tabs.List> - <Tabs.Trigger value="session" class="w-1/2" classes={{ button: "w-full" }}> - Session - </Tabs.Trigger> - <Tabs.Trigger value="review" class="w-1/2 !border-r-0" classes={{ button: "w-full" }}> - 5 Files Changed - </Tabs.Trigger> - </Tabs.List> - <Tabs.Content value="session" class="!overflow-hidden"> - {turns()} - </Tabs.Content> - <Tabs.Content forceMount value="review" class="!overflow-hidden hidden data-[selected]:block"> - <div class="relative h-full pt-8 overflow-y-auto no-scrollbar"> - <SessionReview - diffs={diffs()} - classes={{ - root: "pb-20", - header: "px-4", - container: "px-4", - }} - /> - </div> - </Tabs.Content> - </Tabs> - </Match> - <Match when={true}> - <div class="md:hidden !overflow-hidden">{turns()}</div> - </Match> - </Switch> </div> - </div> - ) - })} - </DataProvider> - )} + ) + })} + </DataProvider> + ) + }} </Show> </ErrorBoundary> ) |
