Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 36 additions & 14 deletions src/cm/lsp/serverLauncher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,13 @@ export { formatCommand } from "./installRuntime";
let cachedFilesDir: string | null = null;

/**
* Get the terminal home directory from system.getFilesDir().
* This is where axs stores port files.
* Get candidate Terminal data directories from system.getFilesDir().
* Newer Terminal builds keep shared runtime state in public. Older builds used
* alpine/home, and some installs keep it as a symlink for shell compatibility.
*/
async function getTerminalHomeDir(): Promise<string> {
async function getTerminalDataDirs(): Promise<string[]> {
if (cachedFilesDir) {
return `${cachedFilesDir}/alpine/home`;
return [`${cachedFilesDir}/public`, `${cachedFilesDir}/alpine/home`];
}

const system = (
Expand All @@ -104,7 +105,7 @@ async function getTerminalHomeDir(): Promise<string> {
system.getFilesDir(
(filesDir: string) => {
cachedFilesDir = filesDir;
resolve(`${filesDir}/alpine/home`);
resolve([`${filesDir}/public`, `${filesDir}/alpine/home`]);
},
(error: string) => reject(new Error(error)),
);
Expand All @@ -115,14 +116,16 @@ async function getTerminalHomeDir(): Promise<string> {
* Get the port file path for a given server and session.
* Port file format: ~/.axs/lsp_ports/{serverName}_{session}
*/
async function getPortFilePath(
async function getPortFilePaths(
serverName: string,
session: string,
): Promise<string> {
const homeDir = await getTerminalHomeDir();
): Promise<string[]> {
const dataDirs = await getTerminalDataDirs();
// Use just the binary name (not full path), mirroring axs behavior
const baseName = serverName.split("/").pop() || serverName;
return `file://${homeDir}/.axs/lsp_ports/${baseName}_${session}`;
return dataDirs.map(
(dataDir) => `file://${dataDir}/.axs/lsp_ports/${baseName}_${session}`,
);
}

/**
Expand Down Expand Up @@ -166,14 +169,16 @@ export async function getLspPort(
session: string,
): Promise<PortInfo | null> {
try {
const filePath = await getPortFilePath(serverName, session);
const port = await readPortFromFile(filePath);
const filePaths = await getPortFilePaths(serverName, session);

if (port === null) {
return null;
for (const filePath of filePaths) {
const port = await readPortFromFile(filePath);
if (port !== null) {
return { port, filePath, session };
}
}

return { port, filePath, session };
return null;
} catch {
return null;
}
Expand Down Expand Up @@ -1094,6 +1099,18 @@ export async function ensureServerRunning(
const key = server.id;
if (managedServers.has(key)) {
const existing = managedServers.get(key);
if (bridge && !bridge.port) {
if (existing?.port) {
return { uuid: existing.uuid, discoveredPort: existing.port };
}
const portInfo = await getLspPort(serverName, effectiveSession);
if (portInfo) {
if (existing) {
existing.port = portInfo.port;
}
return { uuid: existing?.uuid ?? null, discoveredPort: portInfo.port };
}
}
return { uuid: existing?.uuid ?? null };
}

Expand Down Expand Up @@ -1126,6 +1143,11 @@ export async function ensureServerRunning(
entry.port = discoveredPort;
}
}
if (!discoveredPort) {
throw new Error(
`Could not discover websocket bridge port for ${server.id}`,
);
}
} else if (
server.transport?.url &&
(server.transport.kind === "websocket" ||
Expand Down