From 742c2d2c294094410290abdd21bfffa5b0f48638 Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Sun, 16 Nov 2025 21:36:27 +0000 Subject: [PATCH] surface lsp status in instance info --- package-lock.json | 79 +++++++++++--------------------- package.json | 2 +- src/components/instance-info.tsx | 36 ++++++++++++++- src/lib/sse-manager.ts | 12 +++-- src/stores/instances.ts | 46 ++++++++++++++++++- src/types/instance.ts | 3 +- 6 files changed, 119 insertions(+), 59 deletions(-) diff --git a/package-lock.json b/package-lock.json index 93f46eb3..a362221c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,16 @@ { - "name": "@opencode-ai/client", - "version": "0.1.0", + "name": "@shantur/codenomad", + "version": "0.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@opencode-ai/client", - "version": "0.1.0", + "name": "@shantur/codenomad", + "version": "0.1.2", "dependencies": { "@git-diff-view/solid": "^0.0.8", "@kobalte/core": "0.13.11", - "@opencode-ai/sdk": "0.15.13", + "@opencode-ai/sdk": "1.0.68", "@solidjs/router": "^0.13.0", "github-markdown-css": "^5.8.1", "ignore": "7.0.5", @@ -79,6 +79,7 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -1465,9 +1466,9 @@ } }, "node_modules/@opencode-ai/sdk": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-0.15.13.tgz", - "integrity": "sha512-SwKCaWTZvGuGm+CLRDp/Ku476SKuMREIKrPHvKqpZM5gfO3HrVct9zk2f+NwjI0MRKCHNMdtOoEcmz/ypc+pWg==" + "version": "1.0.68", + "resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.0.68.tgz", + "integrity": "sha512-QdpLZw2L/nHdPFGCz8z4du2RvlALgZTFgNeKUM+kJuZTtOWC5t425ELGg5xKIpynD0kj83Euvfn6l6uHs99g3w==" }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", @@ -2289,6 +2290,7 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2464,7 +2466,6 @@ "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "archiver-utils": "^2.1.0", "async": "^3.2.4", @@ -2484,7 +2485,6 @@ "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "glob": "^7.1.4", "graceful-fs": "^4.2.0", @@ -2507,7 +2507,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -2523,8 +2522,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/archiver-utils/node_modules/string_decoder": { "version": "1.1.1", @@ -2532,7 +2530,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -2751,7 +2748,6 @@ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -2827,6 +2823,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", @@ -3290,7 +3287,6 @@ "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "buffer-crc32": "^0.2.13", "crc32-stream": "^4.0.2", @@ -3397,7 +3393,6 @@ "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "crc32": "bin/crc32.njs" }, @@ -3411,7 +3406,6 @@ "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^3.4.0" @@ -3644,6 +3638,7 @@ "integrity": "sha512-rcJUkMfnJpfCboZoOOPf4L29TRtEieHNOeAbYPWPxlaBw/Z1RKrRA86dOI9rwaI4tQSc/RD82zTNHprfUHXsoQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "app-builder-lib": "24.13.3", "builder-util": "24.13.1", @@ -3828,7 +3823,6 @@ "integrity": "sha512-oHkV0iogWfyK+ah9ZIvMDpei1m9ZRpdXcvde1wTpra2U8AFDNNpqJdnin5z+PM1GbQ5BoaKCWas2HSjtR0HwMg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "app-builder-lib": "24.13.3", "archiver": "^5.3.1", @@ -3842,7 +3836,6 @@ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -3858,7 +3851,6 @@ "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -3872,7 +3864,6 @@ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 10.0.0" } @@ -4354,8 +4345,7 @@ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/fs-extra": { "version": "8.1.0", @@ -5074,8 +5064,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/isbinaryfile": { "version": "5.0.6", @@ -5137,6 +5126,7 @@ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, "license": "MIT", + "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -5242,7 +5232,6 @@ "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "readable-stream": "^2.0.5" }, @@ -5256,7 +5245,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -5272,8 +5260,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lazystream/node_modules/string_decoder": { "version": "1.1.1", @@ -5281,7 +5268,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -5318,40 +5304,35 @@ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lodash.difference": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lodash.flatten": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lowercase-keys": { "version": "2.0.0", @@ -6046,6 +6027,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -6194,8 +6176,7 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/progress": { "version": "2.0.3", @@ -6344,7 +6325,6 @@ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -6360,7 +6340,6 @@ "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "minimatch": "^5.1.0" } @@ -6578,8 +6557,7 @@ "url": "https://feross.org/support" } ], - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -6645,6 +6623,7 @@ "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.3.2.tgz", "integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=10" } @@ -6772,6 +6751,7 @@ "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.10.tgz", "integrity": "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", @@ -6891,7 +6871,6 @@ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -7149,7 +7128,6 @@ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -7533,6 +7511,7 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -8195,7 +8174,6 @@ "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "archiver-utils": "^3.0.4", "compress-commons": "^4.1.2", @@ -8211,7 +8189,6 @@ "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "glob": "^7.2.3", "graceful-fs": "^4.2.0", diff --git a/package.json b/package.json index 79c26df7..d5a6c1f0 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "dependencies": { "@git-diff-view/solid": "^0.0.8", "@kobalte/core": "0.13.11", - "@opencode-ai/sdk": "0.15.13", + "@opencode-ai/sdk": "1.0.68", "@solidjs/router": "^0.13.0", "github-markdown-css": "^5.8.1", "ignore": "7.0.5", diff --git a/src/components/instance-info.tsx b/src/components/instance-info.tsx index 8ba67a8e..37117376 100644 --- a/src/components/instance-info.tsx +++ b/src/components/instance-info.tsx @@ -1,6 +1,6 @@ import { Component, Show, For, createSignal, createEffect, onCleanup } from "solid-js" import type { Instance, RawMcpStatus } from "../types/instance" -import { updateInstance } from "../stores/instances" +import { fetchLspStatus, updateInstance } from "../stores/instances" interface InstanceInfoProps { instance: Instance @@ -52,6 +52,7 @@ const InstanceInfo: Component = (props) => { const status = metadata()?.mcpStatus return status ? parseMcpStatus(status) : [] } + const lspServers = () => metadata()?.lspStatus ?? [] createEffect(() => { const instance = props.instance @@ -82,9 +83,10 @@ const InstanceInfo: Component = (props) => { void (async () => { try { - const [projectResult, mcpResult] = await Promise.allSettled([ + const [projectResult, mcpResult, lspResult] = await Promise.allSettled([ client.project.current(), client.mcp.status(), + fetchLspStatus(instanceId), ]) if (cancelled) { @@ -93,11 +95,13 @@ const InstanceInfo: Component = (props) => { const project = projectResult.status === "fulfilled" ? projectResult.value.data : undefined const mcpStatus = mcpResult.status === "fulfilled" ? (mcpResult.value.data as RawMcpStatus) : undefined + const lspStatus = lspResult.status === "fulfilled" ? lspResult.value ?? [] : undefined const nextMetadata = { ...(instance.metadata ?? {}), ...(project ? { project } : {}), ...(mcpStatus ? { mcpStatus } : {}), + ...(lspStatus ? { lspStatus } : {}), } if (!nextMetadata.version) { @@ -213,6 +217,34 @@ const InstanceInfo: Component = (props) => { + 0}> +
+
+ LSP Servers +
+
+ + {(server) => ( +
+
+
+ {server.name ?? server.id} + + {server.root} + +
+
+
+ {server.status === "connected" ? "Connected" : "Error"} +
+
+
+ )} + +
+
+ + 0}>
diff --git a/src/lib/sse-manager.ts b/src/lib/sse-manager.ts index e5e92a63..103037d0 100644 --- a/src/lib/sse-manager.ts +++ b/src/lib/sse-manager.ts @@ -6,12 +6,13 @@ import { MessagePartRemovedEvent } from "../types/message" import type { - EventSessionUpdated, + EventLspUpdated, + EventPermissionReplied, + EventPermissionUpdated, EventSessionCompacted, EventSessionError, EventSessionIdle, - EventPermissionUpdated, - EventPermissionReplied + EventSessionUpdated, } from "@opencode-ai/sdk" interface SSEConnection { @@ -44,6 +45,7 @@ type SSEEvent = | EventSessionIdle | EventPermissionUpdated | EventPermissionReplied + | EventLspUpdated | TuiToastEvent | { type: string; properties?: Record } // Fallback for unknown event types @@ -148,6 +150,9 @@ class SSEManager { case "permission.replied": this.onPermissionReplied?.(instanceId, event as EventPermissionReplied) break + case "lsp.updated": + this.onLspUpdated?.(instanceId, event as EventLspUpdated) + break default: console.warn("[SSE] Unknown event type:", event.type) } @@ -217,6 +222,7 @@ class SSEManager { onSessionIdle?: (instanceId: string, event: EventSessionIdle) => void onPermissionUpdated?: (instanceId: string, event: EventPermissionUpdated) => void onPermissionReplied?: (instanceId: string, event: EventPermissionReplied) => void + onLspUpdated?: (instanceId: string, event: EventLspUpdated) => void onConnectionLost?: (instanceId: string, reason: string) => void | Promise getStatus(instanceId: string): "connecting" | "connected" | "disconnected" | "error" | null { diff --git a/src/stores/instances.ts b/src/stores/instances.ts index f2f56aa4..075dbab7 100644 --- a/src/stores/instances.ts +++ b/src/stores/instances.ts @@ -1,6 +1,6 @@ import { createSignal } from "solid-js" import type { Instance, LogEntry } from "../types/instance" -import type { Permission } from "@opencode-ai/sdk" +import type { LspStatus, Permission } from "@opencode-ai/sdk" import type { ClientPart, Message } from "../types/message" import { sdkManager } from "../lib/sdk-manager" import { sseManager } from "../lib/sse-manager" @@ -233,6 +233,26 @@ async function stopInstance(id: string) { removeInstance(id) } +async function fetchLspStatus(instanceId: string): Promise { + const instance = instances().get(instanceId) + if (!instance) { + console.warn(`[LSP] Skipping fetch; instance ${instanceId} not found`) + return undefined + } + if (!instance.client) { + console.warn(`[LSP] Skipping fetch; instance ${instanceId} client not ready`) + return undefined + } + const lsp = instance.client.lsp + if (!lsp?.status) { + console.warn(`[LSP] Skipping fetch; lsp.status API unavailable for instance ${instanceId}`) + return undefined + } + console.log(`[HTTP] GET /lsp.status for instance ${instanceId}`) + const response = await lsp.status() + return response.data ?? [] +} + function getActiveInstance(): Instance | null { const id = activeInstanceId() return id ? instances().get(id) || null : null @@ -546,6 +566,29 @@ sseManager.onConnectionLost = (instanceId, reason) => { }) } +sseManager.onLspUpdated = async (instanceId) => { + console.log(`[LSP] Received lsp.updated event for instance ${instanceId}`) + try { + const lspStatus = await fetchLspStatus(instanceId) + if (!lspStatus) { + return + } + const instance = instances().get(instanceId) + if (!instance) { + console.warn(`[LSP] Instance ${instanceId} disappeared before metadata update`) + return + } + updateInstance(instanceId, { + metadata: { + ...(instance.metadata ?? {}), + lspStatus, + }, + }) + } catch (error) { + console.error("Failed to refresh LSP status:", error) + } +} + async function acknowledgeDisconnectedInstance(): Promise { const pending = disconnectedInstance() if (!pending) { @@ -593,4 +636,5 @@ export { sendPermissionResponse, disconnectedInstance, acknowledgeDisconnectedInstance, + fetchLspStatus, } diff --git a/src/types/instance.ts b/src/types/instance.ts index a84e2151..6fa5ddf5 100644 --- a/src/types/instance.ts +++ b/src/types/instance.ts @@ -1,5 +1,5 @@ import type { OpencodeClient } from "@opencode-ai/sdk/client" -import type { Project as SDKProject } from "@opencode-ai/sdk" +import type { LspStatus, Project as SDKProject } from "@opencode-ai/sdk" export interface LogEntry { timestamp: number @@ -24,6 +24,7 @@ export type RawMcpStatus = Record