Dax Raad 9 months ago
parent
commit
e98f915fd5

+ 5 - 3
app/package.json

@@ -1,10 +1,12 @@
 {
 {
+  "$schema": "https://json.schemastore.org/package.json",
   "name": "opencontrol",
   "name": "opencontrol",
   "private": true,
   "private": true,
   "type": "module",
   "type": "module",
-  "packageManager": "bun",
-  "description": "OpenCode",
-  "scripts": {},
+  "packageManager": "[email protected]",
+  "scripts": {
+    "dev": "sst dev"
+  },
   "workspaces": [
   "workspaces": [
     "packages/*"
     "packages/*"
   ],
   ],

+ 22 - 13
app/packages/function/src/api.ts

@@ -3,7 +3,7 @@ import { randomUUID } from "node:crypto"
 import { Resource } from "sst"
 import { Resource } from "sst"
 
 
 type Bindings = {
 type Bindings = {
-  SYNC_SERVER: DurableObjectNamespace
+  SYNC_SERVER: DurableObjectNamespace<SyncServer>
 }
 }
 
 
 export class SyncServer extends DurableObject {
 export class SyncServer extends DurableObject {
@@ -17,9 +17,9 @@ export class SyncServer extends DurableObject {
 
 
     setTimeout(async () => {
     setTimeout(async () => {
       const data = await this.ctx.storage.list()
       const data = await this.ctx.storage.list()
-      data.forEach((content, key) => {
+      data.forEach((content: any, key) => {
         if (key === "shareID") return
         if (key === "shareID") return
-        server.send(JSON.stringify({ key, content }))
+        server.send(JSON.stringify({ key, content: JSON.parse(content) }))
       })
       })
     }, 0)
     }, 0)
 
 
@@ -48,7 +48,7 @@ export class SyncServer extends DurableObject {
   }
   }
 
 
   async getShareID() {
   async getShareID() {
-    return this.ctx.storage.get("shareID")
+    return this.ctx.storage.get<string>("shareID")
   }
   }
 
 
   async clear() {
   async clear() {
@@ -59,14 +59,17 @@ export class SyncServer extends DurableObject {
 export default {
 export default {
   async fetch(request: Request, env: Bindings, ctx: ExecutionContext) {
   async fetch(request: Request, env: Bindings, ctx: ExecutionContext) {
     const url = new URL(request.url)
     const url = new URL(request.url)
+    const splits = url.pathname.split("/")
+    const method = splits[1]
 
 
-    if (request.method === "GET" && url.pathname === "/") {
+    if (request.method === "GET" && method === "") {
       return new Response("Hello, world!", {
       return new Response("Hello, world!", {
         headers: { "Content-Type": "text/plain" },
         headers: { "Content-Type": "text/plain" },
       })
       })
     }
     }
-    if (request.method === "POST" && url.pathname.endsWith("/share_create")) {
-      const body = await request.json()
+
+    if (request.method === "POST" && method === "share_create") {
+      const body = await request.json<any>()
       const sessionID = body.sessionID
       const sessionID = body.sessionID
 
 
       // Get existing shareID
       // Get existing shareID
@@ -82,8 +85,9 @@ export default {
         headers: { "Content-Type": "application/json" },
         headers: { "Content-Type": "application/json" },
       })
       })
     }
     }
-    if (request.method === "POST" && url.pathname.endsWith("/share_delete")) {
-      const body = await request.json()
+
+    if (request.method === "POST" && method === "share_delete") {
+      const body = await request.json<any>()
       const sessionID = body.sessionID
       const sessionID = body.sessionID
       const shareID = body.shareID
       const shareID = body.shareID
 
 
@@ -103,8 +107,9 @@ export default {
         headers: { "Content-Type": "application/json" },
         headers: { "Content-Type": "application/json" },
       })
       })
     }
     }
-    if (request.method === "POST" && url.pathname.endsWith("/share_sync")) {
-      const body = await request.json()
+
+    if (request.method === "POST" && method === "share_sync") {
+      const body = await request.json<any>()
       const sessionID = body.sessionID
       const sessionID = body.sessionID
       const shareID = body.shareID
       const shareID = body.shareID
       const key = body.key
       const key = body.key
@@ -132,13 +137,17 @@ export default {
       await stub.publish(key, content)
       await stub.publish(key, content)
 
 
       // store message
       // store message
-      await Resource.Bucket.put(`${shareID}/${key}.json`, content)
+      await Resource.Bucket.put(
+        `${shareID}/${key}.json`,
+        JSON.stringify(content),
+      )
 
 
       return new Response(JSON.stringify({}), {
       return new Response(JSON.stringify({}), {
         headers: { "Content-Type": "application/json" },
         headers: { "Content-Type": "application/json" },
       })
       })
     }
     }
-    if (request.method === "GET" && url.pathname.endsWith("/share_poll")) {
+
+    if (request.method === "GET" && method === "share_poll") {
       // Expect to receive a WebSocket Upgrade request.
       // Expect to receive a WebSocket Upgrade request.
       // If there is one, accept the request and return a WebSocket Response.
       // If there is one, accept the request and return a WebSocket Response.
       const upgradeHeader = request.headers.get("Upgrade")
       const upgradeHeader = request.headers.get("Upgrade")

+ 41 - 525
app/packages/web/src/components/Share.tsx

@@ -1,12 +1,13 @@
-import { createSignal, onCleanup, onMount, Show, For } from "solid-js"
+import { createSignal, onCleanup, onMount, Show, For, createMemo } from "solid-js"
 import styles from "./share.module.css"
 import styles from "./share.module.css"
 import { type UIMessage } from "ai"
 import { type UIMessage } from "ai"
+import { createStore } from "solid-js/store"
 
 
 type Status = "disconnected" | "connecting" | "connected" | "error" | "reconnecting"
 type Status = "disconnected" | "connecting" | "connected" | "error" | "reconnecting"
 
 
 type Message = {
 type Message = {
   key: string
   key: string
-  content: string
+  content: any
 }
 }
 
 
 type SessionInfo = {
 type SessionInfo = {
@@ -32,11 +33,27 @@ export default function Share(props: { api: string }) {
   let params = new URLSearchParams(document.location.search)
   let params = new URLSearchParams(document.location.search)
   const sessionId = params.get("id")
   const sessionId = params.get("id")
 
 
+  const [store, setStore] = createStore<{
+    info?: SessionInfo
+    messages: Record<string, UIMessage<{
+      time: {
+        created: number;
+        completed?: number;
+      };
+      sessionID: string;
+      tool: Record<string, {
+        properties: Record<string, any>;
+        time: {
+          start: number;
+          end: number;
+        };
+      }>;
+    }>>
+  }>({
+    messages: {},
+  })
+  const messages = createMemo(() => Object.values(store.messages).toSorted((a, b) => a.id.localeCompare(b.id)))
   const [connectionStatus, setConnectionStatus] = createSignal<[Status, string?]>(["disconnected", "Disconnected"])
   const [connectionStatus, setConnectionStatus] = createSignal<[Status, string?]>(["disconnected", "Disconnected"])
-  const [sessionInfo, setSessionInfo] = createSignal<SessionInfo | null>(null)
-  const [systemMessage, setSystemMessage] = createSignal<Message | null>(null)
-  const [messages, setMessages] = createSignal<Message[]>([])
-  const [expandedSystemMessage, setExpandedSystemMessage] = createSignal(false)
 
 
   onMount(() => {
   onMount(() => {
     const apiUrl = props.api
     const apiUrl = props.api
@@ -87,37 +104,19 @@ export default function Share(props: { api: string }) {
         console.log("WebSocket message received")
         console.log("WebSocket message received")
         try {
         try {
           const data = JSON.parse(event.data) as Message
           const data = JSON.parse(event.data) as Message
+          const [root, type, ...splits] = data.key.split("/")
+          if (root !== "session") return
 
 
-          // Check if this is a session info message
-          if (data.key.startsWith("session/info/")) {
-            const infoContent = JSON.parse(data.content) as SessionInfo
-            setSessionInfo(infoContent)
-            console.log("Session info updated:", infoContent)
+          if (type === "info") {
+            setStore("info", data.content)
             return
             return
           }
           }
 
 
-          // Check if it's a system message
-          const msgContent = JSON.parse(data.content) as UIMessage
-          if (msgContent.role === "system") {
-            setSystemMessage(data)
-            console.log("System message updated:", data)
-            return
+          if (type === "message") {
+            const [, messageID] = splits
+            setStore("messages", messageID, data.content)
           }
           }
 
 
-          // Non-system messages
-          setMessages((prev) => {
-            // Check if message with this key already exists
-            const existingIndex = prev.findIndex((msg) => msg.key === data.key)
-            if (existingIndex >= 0) {
-              // Update existing message
-              const updated = [...prev]
-              updated[existingIndex] = data
-              return updated
-            } else {
-              // Add new message
-              return [...prev, data]
-            }
-          })
         } catch (error) {
         } catch (error) {
           console.error("Error parsing WebSocket message:", error)
           console.error("Error parsing WebSocket message:", error)
         }
         }
@@ -168,34 +167,26 @@ export default function Share(props: { api: string }) {
         </div>
         </div>
         <div data-section="row">
         <div data-section="row">
           <ul class={styles.stats}>
           <ul class={styles.stats}>
-            <li>
-              <span>Cost</span>
-              {sessionInfo()?.cost ?
-                <span>{sessionInfo()?.cost}</span>
-                :
-                <span data-placeholder>&mdash;</span>
-              }
-            </li>
             <li>
             <li>
               <span>Input Tokens</span>
               <span>Input Tokens</span>
-              {sessionInfo()?.tokens?.input ?
-                <span>{sessionInfo()?.tokens?.input}</span>
+              {store.info?.tokens?.input ?
+                <span>{store.info?.tokens?.input}</span>
                 :
                 :
                 <span data-placeholder>&mdash;</span>
                 <span data-placeholder>&mdash;</span>
               }
               }
             </li>
             </li>
             <li>
             <li>
               <span>Output Tokens</span>
               <span>Output Tokens</span>
-              {sessionInfo()?.tokens?.output ?
-                <span>{sessionInfo()?.tokens?.output}</span>
+              {store.info?.tokens?.output ?
+                <span>{store.info?.tokens?.output}</span>
                 :
                 :
                 <span data-placeholder>&mdash;</span>
                 <span data-placeholder>&mdash;</span>
               }
               }
             </li>
             </li>
             <li>
             <li>
               <span>Reasoning Tokens</span>
               <span>Reasoning Tokens</span>
-              {sessionInfo()?.tokens?.reasoning ?
-                <span>{sessionInfo()?.tokens?.reasoning}</span>
+              {store.info?.tokens?.reasoning ?
+                <span>{store.info?.tokens?.reasoning}</span>
                 :
                 :
                 <span data-placeholder>&mdash;</span>
                 <span data-placeholder>&mdash;</span>
               }
               }
@@ -208,506 +199,31 @@ export default function Share(props: { api: string }) {
       </div>
       </div>
 
 
       <div style={{ margin: "2rem 0" }}>
       <div style={{ margin: "2rem 0" }}>
-
-        {/* Display system message as context in the Session Information block */}
-        <Show when={systemMessage()}>
-          <div
-            style={{
-              padding: "1rem",
-              marginBottom: "1rem",
-              border: "1px solid #dee2e6",
-            }}
-          >
-            <h4 style={{ margin: "0 0 0.75rem 0" }}>Context</h4>
-            {(() => {
-              try {
-                const parsed = JSON.parse(
-                  systemMessage()?.content || "",
-                ) as UIMessage
-                if (
-                  parsed.parts &&
-                  parsed.parts.length > 0 &&
-                  parsed.parts[0].type === "text"
-                ) {
-                  const text = parsed.parts[0].text || ""
-                  const lines = text.split("\n")
-                  const visibleLines = expandedSystemMessage()
-                    ? lines
-                    : lines.slice(0, 5)
-                  const hasMoreLines = lines.length > 5
-
-                  return (
-                    <>
-                      <div
-                        style={{
-                          padding: "0.75rem",
-                          border: "1px solid #dee2e6",
-                        }}
-                      >
-                        {/* Create a modified version of the text part for the system message */}
-                        {(() => {
-                          // Create a modified part with truncated text
-                          const modifiedPart = {
-                            ...parsed.parts[0],
-                            text: visibleLines.join("\n"),
-                          }
-
-                          return (
-                            <>
-                              <pre>{modifiedPart.text}</pre>
-                              {hasMoreLines && !expandedSystemMessage() && (
-                                <div
-                                  style={{
-                                    color: "#6c757d",
-                                    fontStyle: "italic",
-                                    marginTop: "0.5rem",
-                                  }}
-                                >
-                                  {lines.length - 5} more lines...
-                                </div>
-                              )}
-                            </>
-                          )
-                        })()}
-                      </div>
-                      {hasMoreLines && (
-                        <button
-                          onClick={() =>
-                            setExpandedSystemMessage(!expandedSystemMessage())
-                          }
-                          style={{
-                            marginTop: "0.5rem",
-                            padding: "0.25rem 0.75rem",
-                            border: "1px solid #ced4da",
-                            cursor: "pointer",
-                            fontSize: "0.875rem",
-                          }}
-                        >
-                          {expandedSystemMessage() ? "Show Less" : "Show More"}
-                        </button>
-                      )}
-                    </>
-                  )
-                }
-              } catch (e) {
-                return <div>Error parsing system message</div>
-              }
-
-              return null
-            })()}
-          </div>
-        </Show>
-
         <div
         <div
           style={{
           style={{
             border: "1px solid #ccc",
             border: "1px solid #ccc",
             padding: "1rem",
             padding: "1rem",
-            maxHeight: "500px",
-            overflowY: "auto",
+            "overflow-y": "auto",
           }}
           }}
         >
         >
           <Show
           <Show
             when={messages().length > 0}
             when={messages().length > 0}
             fallback={<p>Waiting for messages...</p>}
             fallback={<p>Waiting for messages...</p>}
           >
           >
-            <ul style={{ listStyleType: "none", padding: 0 }}>
+            <ul style={{ "list-style-type": "none", padding: 0 }}>
               <For each={messages()}>
               <For each={messages()}>
                 {(msg) => (
                 {(msg) => (
                   <li
                   <li
                     style={{
                     style={{
                       padding: "0.75rem",
                       padding: "0.75rem",
                       margin: "0.75rem 0",
                       margin: "0.75rem 0",
-                      boxShadow: "0 1px 3px rgba(0,0,0,0.1)",
+                      "box-shadow": "0 1px 3px rgba(0,0,0,0.1)",
                     }}
                     }}
                   >
                   >
                     <div>
                     <div>
-                      <strong>Key:</strong> {msg.key}
+                      <strong>Key:</strong> {msg.id}
                     </div>
                     </div>
-
-                    {(() => {
-                      try {
-                        const parsed = JSON.parse(msg.content) as UIMessage
-                        const createdTime = parsed.metadata?.time?.created
-                          ? new Date(
-                            parsed.metadata.time.created,
-                          ).toLocaleString()
-                          : "Unknown time"
-
-                        return (
-                          <>
-                            <div style={{ marginTop: "0.5rem" }}>
-                              <strong>Full Content:</strong>
-                              <pre
-                                style={{
-                                  padding: "0.5rem",
-                                  overflow: "auto",
-                                  maxHeight: "150px",
-                                  whiteSpace: "pre-wrap",
-                                  wordBreak: "break-word",
-                                  fontSize: "0.85rem",
-                                }}
-                              >
-                                {JSON.stringify(parsed, null, 2)}
-                              </pre>
-                            </div>
-
-                            {parsed.parts && parsed.parts.length > 0 && (
-                              <div style={{ marginTop: "0.75rem" }}>
-                                <div
-                                  style={{
-                                    display: "flex",
-                                    justifyContent: "space-between",
-                                    alignItems: "center",
-                                    padding: "0.25rem 0.5rem",
-                                    marginBottom: "0.5rem",
-                                  }}
-                                >
-                                  <strong>
-                                    Role: {parsed.role || "Unknown"}
-                                  </strong>
-                                  <span
-                                    style={{
-                                      fontSize: "0.8rem",
-                                      color: "#6c757d",
-                                    }}
-                                  >
-                                    {createdTime}
-                                  </span>
-                                </div>
-
-                                <div
-                                  style={{
-                                    padding: "0.75rem",
-                                    border: "1px solid #dee2e6",
-                                  }}
-                                >
-                                  <For
-                                    each={parsed.parts.filter(
-                                      (part) => part.type !== "step-start",
-                                    )}
-                                  >
-                                    {(part) => {
-                                      if (part.type === "text") {
-                                        //{
-                                        //  "type": "text",
-                                        //  "text": "Hello! How can I help you today?"
-                                        //}
-                                        return (
-                                          <pre>
-                                            [{part.type}] {part.text}{" "}
-                                          </pre>
-                                        )
-                                      }
-                                      if (part.type === "reasoning") {
-                                        //{
-                                        //  "type": "reasoning",
-                                        //  "text": "The user asked for a weather forecast. I should call the 'getWeather' tool with the location 'San Francisco'.",
-                                        //  "providerMetadata": { "step_id": "reason_step_1" }
-                                        //}
-                                        return (
-                                          <pre>
-                                            [{part.type}] {part.text}
-                                          </pre>
-                                        )
-                                      }
-                                      if (part.type === "tool-invocation") {
-                                        return (
-                                          <div>
-                                            <div
-                                              style={{
-                                                display: "flex",
-                                                justifyContent: "space-between",
-                                                alignItems: "center",
-                                                marginBottom: "0.3rem",
-                                              }}
-                                            >
-                                              <span>
-                                                <pre
-                                                  style={{
-                                                    margin: 0,
-                                                    display: "inline",
-                                                  }}
-                                                >
-                                                  [{part.type}]
-                                                </pre>{" "}
-                                                Tool:{" "}
-                                                <strong>
-                                                  {part.toolInvocation.toolName}
-                                                </strong>
-                                              </span>
-                                              {parsed.metadata?.tool?.[
-                                                part.toolInvocation.toolCallId
-                                              ]?.time?.start &&
-                                                parsed.metadata?.tool?.[
-                                                  part.toolInvocation.toolCallId
-                                                ]?.time?.end && (
-                                                  <span
-                                                    style={{
-                                                      color: "#6c757d",
-                                                      fontSize: "0.8rem",
-                                                    }}
-                                                  >
-                                                    {(
-                                                      (new Date(
-                                                        parsed.metadata?.tool?.[
-                                                          part.toolInvocation.toolCallId
-                                                        ].time.end,
-                                                      ) -
-                                                        new Date(
-                                                          parsed.metadata?.tool?.[
-                                                            part.toolInvocation.toolCallId
-                                                          ].time.start,
-                                                        )) /
-                                                      1000
-                                                    ).toFixed(2)}
-                                                    s
-                                                  </span>
-                                                )}
-                                            </div>
-                                            {(() => {
-                                              if (
-                                                part.toolInvocation.state ===
-                                                "partial-call"
-                                              ) {
-                                                //{
-                                                //  "type": "tool-invocation",
-                                                //  "toolInvocation": {
-                                                //    "state": "partial-call",
-                                                //    "toolCallId": "tool_abc123",
-                                                //    "toolName": "searchWeb",
-                                                //    "argsTextDelta": "{\"query\":\"latest AI news"
-                                                //  }
-                                                //}
-                                                return (
-                                                  <>
-                                                    <pre>
-                                                      {
-                                                        part.toolInvocation
-                                                          .argsTextDelta
-                                                      }
-                                                    </pre>
-                                                    <span>...</span>
-                                                  </>
-                                                )
-                                              }
-                                              if (
-                                                part.toolInvocation.state ===
-                                                "call"
-                                              ) {
-                                                //{
-                                                //  "type": "tool-invocation",
-                                                //  "toolInvocation": {
-                                                //    "state": "call",
-                                                //    "toolCallId": "tool_abc123",
-                                                //    "toolName": "searchWeb",
-                                                //    "args": { "query": "latest AI news", "count": 3 }
-                                                //  }
-                                                //}
-                                                return (
-                                                  <pre>
-                                                    {JSON.stringify(
-                                                      part.toolInvocation.args,
-                                                      null,
-                                                      2,
-                                                    )}
-                                                  </pre>
-                                                )
-                                              }
-                                              if (
-                                                part.toolInvocation.state ===
-                                                "result"
-                                              ) {
-                                                //{
-                                                //  "type": "tool-invocation",
-                                                //  "toolInvocation": {
-                                                //    "state": "result",
-                                                //    "toolCallId": "tool_abc123",
-                                                //    "toolName": "searchWeb",
-                                                //    "args": { "query": "latest AI news", "count": 3 },
-                                                //    "result": [
-                                                //      { "title": "AI SDK v5 Announced", "url": "..." },
-                                                //      { "title": "New LLM Achieves SOTA", "url": "..." }
-                                                //    ]
-                                                //  }
-                                                //}
-                                                return (
-                                                  <>
-                                                    <pre>
-                                                      {JSON.stringify(
-                                                        part.toolInvocation
-                                                          .args,
-                                                        null,
-                                                        2,
-                                                      )}
-                                                    </pre>
-                                                    <pre>
-                                                      {JSON.stringify(
-                                                        part.toolInvocation
-                                                          .result,
-                                                        null,
-                                                        2,
-                                                      )}
-                                                    </pre>
-                                                  </>
-                                                )
-                                              }
-                                              if (
-                                                part.toolInvocation.state ===
-                                                "error"
-                                              ) {
-                                                //{
-                                                //  "type": "tool-invocation",
-                                                //  "toolInvocation": {
-                                                //    "state": "error",
-                                                //    "toolCallId": "tool_abc123",
-                                                //    "toolName": "searchWeb",
-                                                //    "args": { "query": "latest AI news", "count": 3 },
-                                                //    "errorMessage": "API limit exceeded for searchWeb tool."
-                                                //  }
-                                                //}
-                                                return (
-                                                  <>
-                                                    <pre>
-                                                      {JSON.stringify(
-                                                        part.toolInvocation
-                                                          .args,
-                                                        null,
-                                                        2,
-                                                      )}
-                                                    </pre>
-                                                    <pre>
-                                                      {
-                                                        part.toolInvocation
-                                                          .errorMessage
-                                                      }
-                                                    </pre>
-                                                  </>
-                                                )
-                                              }
-                                            })()}
-                                          </div>
-                                        )
-                                      }
-                                      if (part.type === "source") {
-                                        //{
-                                        //  "type": "source",
-                                        //  "source": {
-                                        //    "sourceType": "url",
-                                        //    "id": "doc_xyz789",
-                                        //    "url": "https://example.com/research-paper.pdf",
-                                        //    "title": "Groundbreaking AI Research Paper"
-                                        //  }
-                                        //}
-                                        return (
-                                          <div>
-                                            <div>
-                                              <span>
-                                                <pre>[{part.type}]</pre>
-                                              </span>
-                                              <span>
-                                                Source:{" "}
-                                                {part.source.title ||
-                                                  part.source.id}
-                                              </span>
-                                            </div>
-                                            {part.source.url && (
-                                              <div>
-                                                <a
-                                                  href={part.source.url}
-                                                  target="_blank"
-                                                  rel="noopener noreferrer"
-                                                  style={{ color: "#0c5460" }}
-                                                >
-                                                  {part.source.url}
-                                                </a>
-                                              </div>
-                                            )}
-                                            {part.source.sourceType && (
-                                              <div>
-                                                Type: {part.source.sourceType}
-                                              </div>
-                                            )}
-                                          </div>
-                                        )
-                                      }
-                                      if (part.type === "file") {
-                                        //{
-                                        //  "type": "file",
-                                        //  "mediaType": "image/jpeg",
-                                        //  "filename": "cat_photo.jpg",
-                                        //  "url": "https://example-files.com/cats/cat_photo.jpg"
-                                        //}
-                                        const isImage =
-                                          part.mediaType?.startsWith("image/")
-
-                                        return (
-                                          <div>
-                                            <div>
-                                              <span>
-                                                <pre>[{part.type}]</pre>
-                                              </span>
-                                              <span>File: {part.filename}</span>
-                                              <span>{part.mediaType}</span>
-                                            </div>
-
-                                            {isImage && part.url ? (
-                                              <div>
-                                                <img
-                                                  src={part.url}
-                                                  alt={
-                                                    part.filename ||
-                                                    "Attached image"
-                                                  }
-                                                />
-                                              </div>
-                                            ) : (
-                                              <div>
-                                                {part.url ? (
-                                                  <a
-                                                    href={part.url}
-                                                    target="_blank"
-                                                    rel="noopener noreferrer"
-                                                  >
-                                                    Download: {part.filename}
-                                                  </a>
-                                                ) : (
-                                                  <div>
-                                                    File attachment (no URL
-                                                    available)
-                                                  </div>
-                                                )}
-                                              </div>
-                                            )}
-                                          </div>
-                                        )
-                                      }
-                                      return null
-                                    }}
-                                  </For>
-                                </div>
-                              </div>
-                            )}
-                          </>
-                        )
-                      } catch (e) {
-                        return (
-                          <div>
-                            <strong>Content:</strong>
-                            <pre
-                              style={{
-                                padding: "0.5rem",
-                                overflow: "auto",
-                                maxHeight: "200px",
-                                whiteSpace: "pre-wrap",
-                                wordBreak: "break-word",
-                              }}
-                            >
-                              {msg.content}
-                            </pre>
-                          </div>
-                        )
-                      }
-                    })()}
+                    <pre>{JSON.stringify(msg, null, 2)}</pre>
                   </li>
                   </li>
                 )}
                 )}
               </For>
               </For>

+ 2 - 0
js/src/lsp/index.ts

@@ -102,11 +102,13 @@ export namespace LSP {
         ".ctsx",
         ".ctsx",
       ],
       ],
     },
     },
+    /*
     {
     {
       id: "golang",
       id: "golang",
       command: ["gopls"],
       command: ["gopls"],
       extensions: [".go"],
       extensions: [".go"],
     },
     },
+    */
   ];
   ];
 
 
   export namespace Diagnostic {
   export namespace Diagnostic {

+ 1 - 1
js/src/share/share.ts

@@ -52,7 +52,7 @@ export namespace Share {
     await state();
     await state();
   }
   }
 
 
-  const URL = "https://api.dev.opencode.ai";
+  const URL = process.env["OPENCODE_API"] ?? "https://api.dev.opencode.ai";
   export async function create(sessionID: string) {
   export async function create(sessionID: string) {
     return fetch(`${URL}/share_create`, {
     return fetch(`${URL}/share_create`, {
       method: "POST",
       method: "POST",