mirror of
https://github.com/sst/opencode.git
synced 2025-08-27 08:24:06 +00:00
ssr sync
This commit is contained in:
parent
fdaa7f287c
commit
177875f624
3 changed files with 66 additions and 56 deletions
|
@ -69,7 +69,7 @@ export class SyncServer extends DurableObject<Env> {
|
||||||
return secret
|
return secret
|
||||||
}
|
}
|
||||||
|
|
||||||
public async messages() {
|
public async getData() {
|
||||||
const data = await this.ctx.storage.list()
|
const data = await this.ctx.storage.list()
|
||||||
const messages = []
|
const messages = []
|
||||||
for (const [key, content] of data.entries()) {
|
for (const [key, content] of data.entries()) {
|
||||||
|
@ -173,14 +173,29 @@ export default {
|
||||||
return stub.fetch(request)
|
return stub.fetch(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.method === "GET" && method === "share_messages") {
|
if (request.method === "GET" && method === "share_data") {
|
||||||
const id = url.searchParams.get("id")
|
const id = url.searchParams.get("id")
|
||||||
console.log("share_messages", id)
|
console.log("share_data", id)
|
||||||
if (!id)
|
if (!id)
|
||||||
return new Response("Error: Share ID is required", { status: 400 })
|
return new Response("Error: Share ID is required", { status: 400 })
|
||||||
const stub = env.SYNC_SERVER.get(env.SYNC_SERVER.idFromName(id))
|
const stub = env.SYNC_SERVER.get(env.SYNC_SERVER.idFromName(id))
|
||||||
const messages = await stub.messages()
|
const data = await stub.getData()
|
||||||
return new Response(JSON.stringify({ messages }), {
|
let info
|
||||||
|
const messages = {}
|
||||||
|
data.forEach((d) => {
|
||||||
|
const [root, type, ...splits] = d.key.split("/")
|
||||||
|
if (root !== "session") return
|
||||||
|
if (type === "info") {
|
||||||
|
info = d.content
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (type === "message") {
|
||||||
|
const [, messageID] = splits
|
||||||
|
messages[messageID] = d.content
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return new Response(JSON.stringify({ info, messages }), {
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,23 +156,23 @@ function flattenToolArgs(obj: any, prefix: string = ""): Array<[string, any]> {
|
||||||
* "ERROR [65:20] Property 'x' does not exist on type 'Y'"
|
* "ERROR [65:20] Property 'x' does not exist on type 'Y'"
|
||||||
*/
|
*/
|
||||||
export function getDiagnostics(
|
export function getDiagnostics(
|
||||||
diagnosticsByFile: Record<string, Diagnostic[]>
|
diagnosticsByFile: Record<string, Diagnostic[]>,
|
||||||
): string[] {
|
): string[] {
|
||||||
const result: string[] = [];
|
const result: string[] = []
|
||||||
|
|
||||||
for (const diags of Object.values(diagnosticsByFile)) {
|
for (const diags of Object.values(diagnosticsByFile)) {
|
||||||
for (const d of diags) {
|
for (const d of diags) {
|
||||||
// Only keep diagnostics explicitly marked as Error (severity === 1)
|
// Only keep diagnostics explicitly marked as Error (severity === 1)
|
||||||
if (d.severity !== 1) continue;
|
if (d.severity !== 1) continue
|
||||||
|
|
||||||
const line = d.range.start.line + 1; // 1-based
|
const line = d.range.start.line + 1 // 1-based
|
||||||
const column = d.range.start.character + 1; // 1-based
|
const column = d.range.start.character + 1 // 1-based
|
||||||
|
|
||||||
result.push(`ERROR [${line}:${column}] ${d.message}`);
|
result.push(`ERROR [${line}:${column}] ${d.message}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
function stripEnclosingTag(text: string): string {
|
function stripEnclosingTag(text: string): string {
|
||||||
|
@ -426,7 +426,8 @@ function ToolFooter(props: { time: number }) {
|
||||||
|
|
||||||
export default function Share(props: {
|
export default function Share(props: {
|
||||||
api: string
|
api: string
|
||||||
data: { key: string; content: SessionMessage | SessionInfo }[]
|
info: SessionInfo
|
||||||
|
messages: Record<string, SessionMessage>
|
||||||
}) {
|
}) {
|
||||||
let params = new URLSearchParams(document.location.search)
|
let params = new URLSearchParams(document.location.search)
|
||||||
const id = params.get("id")
|
const id = params.get("id")
|
||||||
|
@ -434,7 +435,7 @@ export default function Share(props: {
|
||||||
const [store, setStore] = createStore<{
|
const [store, setStore] = createStore<{
|
||||||
info?: SessionInfo
|
info?: SessionInfo
|
||||||
messages: Record<string, SessionMessage>
|
messages: Record<string, SessionMessage>
|
||||||
}>({ messages: {} })
|
}>({ info: props.info, messages: props.messages })
|
||||||
const messages = createMemo(() =>
|
const messages = createMemo(() =>
|
||||||
Object.values(store.messages).toSorted((a, b) => a.id?.localeCompare(b.id)),
|
Object.values(store.messages).toSorted((a, b) => a.id?.localeCompare(b.id)),
|
||||||
)
|
)
|
||||||
|
@ -442,19 +443,6 @@ export default function Share(props: {
|
||||||
[Status, string?]
|
[Status, string?]
|
||||||
>(["disconnected", "Disconnected"])
|
>(["disconnected", "Disconnected"])
|
||||||
|
|
||||||
const processDatum = (d: any) => {
|
|
||||||
const [root, type, ...splits] = d.key.split("/")
|
|
||||||
if (root !== "session") return
|
|
||||||
if (type === "info") {
|
|
||||||
setStore("info", reconcile(d.content))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (type === "message") {
|
|
||||||
const [, messageID] = splits
|
|
||||||
setStore("messages", messageID, reconcile(d.content))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const apiUrl = props.api
|
const apiUrl = props.api
|
||||||
|
|
||||||
|
@ -469,10 +457,6 @@ export default function Share(props: {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const datum of props.data) {
|
|
||||||
processDatum(datum)
|
|
||||||
}
|
|
||||||
|
|
||||||
let reconnectTimer: number | undefined
|
let reconnectTimer: number | undefined
|
||||||
let socket: WebSocket | null = null
|
let socket: WebSocket | null = null
|
||||||
|
|
||||||
|
@ -503,7 +487,17 @@ export default function Share(props: {
|
||||||
socket.onmessage = (event) => {
|
socket.onmessage = (event) => {
|
||||||
console.log("WebSocket message received")
|
console.log("WebSocket message received")
|
||||||
try {
|
try {
|
||||||
processDatum(JSON.parse(event.data))
|
const d = JSON.parse(event.data)
|
||||||
|
const [root, type, ...splits] = d.key.split("/")
|
||||||
|
if (root !== "session") return
|
||||||
|
if (type === "info") {
|
||||||
|
setStore("info", reconcile(d.content))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (type === "message") {
|
||||||
|
const [, messageID] = splits
|
||||||
|
setStore("messages", messageID, reconcile(d.content))
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error parsing WebSocket message:", error)
|
console.error("Error parsing WebSocket message:", error)
|
||||||
}
|
}
|
||||||
|
@ -579,7 +573,10 @@ export default function Share(props: {
|
||||||
result.tokens.output += assistant.tokens.output
|
result.tokens.output += assistant.tokens.output
|
||||||
result.tokens.reasoning += assistant.tokens.reasoning
|
result.tokens.reasoning += assistant.tokens.reasoning
|
||||||
|
|
||||||
result.models[`${assistant.providerID} ${assistant.modelID}`] = [assistant.providerID, assistant.modelID]
|
result.models[`${assistant.providerID} ${assistant.modelID}`] = [
|
||||||
|
assistant.providerID,
|
||||||
|
assistant.modelID,
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
@ -864,7 +861,7 @@ export default function Share(props: {
|
||||||
const metadata = createMemo(
|
const metadata = createMemo(
|
||||||
() =>
|
() =>
|
||||||
msg.metadata?.tool[
|
msg.metadata?.tool[
|
||||||
part().toolInvocation.toolCallId
|
part().toolInvocation.toolCallId
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
const args = part().toolInvocation.args
|
const args = part().toolInvocation.args
|
||||||
|
@ -974,7 +971,7 @@ export default function Share(props: {
|
||||||
const metadata = createMemo(
|
const metadata = createMemo(
|
||||||
() =>
|
() =>
|
||||||
msg.metadata?.tool[
|
msg.metadata?.tool[
|
||||||
part().toolInvocation.toolCallId
|
part().toolInvocation.toolCallId
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
const args = part().toolInvocation.args
|
const args = part().toolInvocation.args
|
||||||
|
@ -1069,7 +1066,7 @@ export default function Share(props: {
|
||||||
const metadata = createMemo(
|
const metadata = createMemo(
|
||||||
() =>
|
() =>
|
||||||
msg.metadata?.tool[
|
msg.metadata?.tool[
|
||||||
part().toolInvocation.toolCallId
|
part().toolInvocation.toolCallId
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
const args = part().toolInvocation.args
|
const args = part().toolInvocation.args
|
||||||
|
@ -1109,7 +1106,7 @@ export default function Share(props: {
|
||||||
<Match
|
<Match
|
||||||
when={
|
when={
|
||||||
part().toolInvocation.state ===
|
part().toolInvocation.state ===
|
||||||
"result" &&
|
"result" &&
|
||||||
part().toolInvocation.result
|
part().toolInvocation.result
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -1153,7 +1150,7 @@ export default function Share(props: {
|
||||||
const metadata = createMemo(
|
const metadata = createMemo(
|
||||||
() =>
|
() =>
|
||||||
msg.metadata?.tool[
|
msg.metadata?.tool[
|
||||||
part().toolInvocation.toolCallId
|
part().toolInvocation.toolCallId
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
const args = part().toolInvocation.args
|
const args = part().toolInvocation.args
|
||||||
|
@ -1261,7 +1258,7 @@ export default function Share(props: {
|
||||||
const metadata = createMemo(
|
const metadata = createMemo(
|
||||||
() =>
|
() =>
|
||||||
msg.metadata?.tool[
|
msg.metadata?.tool[
|
||||||
part().toolInvocation.toolCallId
|
part().toolInvocation.toolCallId
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
const args = part().toolInvocation.args
|
const args = part().toolInvocation.args
|
||||||
|
@ -1272,7 +1269,7 @@ export default function Share(props: {
|
||||||
part().toolInvocation.state === "result" &&
|
part().toolInvocation.state === "result" &&
|
||||||
part().toolInvocation.result
|
part().toolInvocation.result
|
||||||
const diagnostics = createMemo(() =>
|
const diagnostics = createMemo(() =>
|
||||||
getDiagnostics(metadata()?.diagnostics)
|
getDiagnostics(metadata()?.diagnostics),
|
||||||
)
|
)
|
||||||
|
|
||||||
const duration = createMemo(() =>
|
const duration = createMemo(() =>
|
||||||
|
@ -1358,13 +1355,13 @@ export default function Share(props: {
|
||||||
const metadata = createMemo(
|
const metadata = createMemo(
|
||||||
() =>
|
() =>
|
||||||
msg.metadata?.tool[
|
msg.metadata?.tool[
|
||||||
part().toolInvocation.toolCallId
|
part().toolInvocation.toolCallId
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
const args = part().toolInvocation.args
|
const args = part().toolInvocation.args
|
||||||
const filePath = args.filePath
|
const filePath = args.filePath
|
||||||
const diagnostics = createMemo(() =>
|
const diagnostics = createMemo(() =>
|
||||||
getDiagnostics(metadata()?.diagnostics)
|
getDiagnostics(metadata()?.diagnostics),
|
||||||
)
|
)
|
||||||
|
|
||||||
const duration = createMemo(() =>
|
const duration = createMemo(() =>
|
||||||
|
@ -1425,7 +1422,7 @@ export default function Share(props: {
|
||||||
const metadata = createMemo(
|
const metadata = createMemo(
|
||||||
() =>
|
() =>
|
||||||
msg.metadata?.tool[
|
msg.metadata?.tool[
|
||||||
part().toolInvocation.toolCallId
|
part().toolInvocation.toolCallId
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1480,7 +1477,7 @@ export default function Share(props: {
|
||||||
msg.role === "assistant" &&
|
msg.role === "assistant" &&
|
||||||
part.type === "tool-invocation" &&
|
part.type === "tool-invocation" &&
|
||||||
part.toolInvocation.toolName ===
|
part.toolInvocation.toolName ===
|
||||||
"opencode_todoread" &&
|
"opencode_todoread" &&
|
||||||
part
|
part
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -1488,7 +1485,7 @@ export default function Share(props: {
|
||||||
const metadata = createMemo(
|
const metadata = createMemo(
|
||||||
() =>
|
() =>
|
||||||
msg.metadata?.tool[
|
msg.metadata?.tool[
|
||||||
part().toolInvocation.toolCallId
|
part().toolInvocation.toolCallId
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1531,7 +1528,7 @@ export default function Share(props: {
|
||||||
msg.role === "assistant" &&
|
msg.role === "assistant" &&
|
||||||
part.type === "tool-invocation" &&
|
part.type === "tool-invocation" &&
|
||||||
part.toolInvocation.toolName ===
|
part.toolInvocation.toolName ===
|
||||||
"opencode_todowrite" &&
|
"opencode_todowrite" &&
|
||||||
part
|
part
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -1539,7 +1536,7 @@ export default function Share(props: {
|
||||||
const metadata = createMemo(
|
const metadata = createMemo(
|
||||||
() =>
|
() =>
|
||||||
msg.metadata?.tool[
|
msg.metadata?.tool[
|
||||||
part().toolInvocation.toolCallId
|
part().toolInvocation.toolCallId
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1613,7 +1610,7 @@ export default function Share(props: {
|
||||||
msg.role === "assistant" &&
|
msg.role === "assistant" &&
|
||||||
part.type === "tool-invocation" &&
|
part.type === "tool-invocation" &&
|
||||||
part.toolInvocation.toolName ===
|
part.toolInvocation.toolName ===
|
||||||
"opencode_webfetch" &&
|
"opencode_webfetch" &&
|
||||||
part
|
part
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -1621,7 +1618,7 @@ export default function Share(props: {
|
||||||
const metadata = createMemo(
|
const metadata = createMemo(
|
||||||
() =>
|
() =>
|
||||||
msg.metadata?.tool[
|
msg.metadata?.tool[
|
||||||
part().toolInvocation.toolCallId
|
part().toolInvocation.toolCallId
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
const args = part().toolInvocation.args
|
const args = part().toolInvocation.args
|
||||||
|
@ -1708,7 +1705,7 @@ export default function Share(props: {
|
||||||
const metadata = createMemo(
|
const metadata = createMemo(
|
||||||
() =>
|
() =>
|
||||||
msg.metadata?.tool[
|
msg.metadata?.tool[
|
||||||
part().toolInvocation.toolCallId
|
part().toolInvocation.toolCallId
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1760,7 +1757,7 @@ export default function Share(props: {
|
||||||
<Match
|
<Match
|
||||||
when={
|
when={
|
||||||
part().toolInvocation.state ===
|
part().toolInvocation.state ===
|
||||||
"result" &&
|
"result" &&
|
||||||
part().toolInvocation.result
|
part().toolInvocation.result
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
|
@ -8,12 +8,10 @@ import Share from "../../components/Share.tsx";
|
||||||
const apiUrl = import.meta.env.VITE_API_URL;
|
const apiUrl = import.meta.env.VITE_API_URL;
|
||||||
|
|
||||||
const id = Astro.url.searchParams.get('id')
|
const id = Astro.url.searchParams.get('id')
|
||||||
const res = await fetch(`${apiUrl}/share_messages?id=${id}`);
|
const res = await fetch(`${apiUrl}/share_data?id=${id}`);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|
||||||
console.log(data.info)
|
const title = data.info.title;
|
||||||
|
|
||||||
const title = "Share";
|
|
||||||
|
|
||||||
const encodedTitle = encodeURIComponent(
|
const encodedTitle = encodeURIComponent(
|
||||||
Base64.encode(
|
Base64.encode(
|
||||||
|
@ -58,7 +56,7 @@ const ogImageUrl = `${cardService}/opencode-share/${encodedTitle}.png?cost=${cos
|
||||||
],
|
],
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Share api={apiUrl} data={data.messages} client:only="solid" />
|
<Share api={apiUrl} info={data.info} messages={data.messages} client:only="solid" />
|
||||||
</StarlightPage>
|
</StarlightPage>
|
||||||
|
|
||||||
<style is:global>
|
<style is:global>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue