Environment support for multiple hosts or ports (#278)

* Environment support for multiple hosts or ports

* Better error handling

* Minor changes

* Correct handling for local

* Add inspect command

* Address comments

* Address comments more
This commit is contained in:
rugvedS07
2025-07-29 13:36:45 -04:00
committed by GitHub
parent 5b378e826c
commit ecf151cd15
6 changed files with 393 additions and 56 deletions

View File

@ -1,15 +1,13 @@
import { apiServerPorts, type SimpleLogger, text } from "@lmstudio/lms-common";
import { LMStudioClient, type LMStudioClientConstructorOpts } from "@lmstudio/sdk";
import chalk from "chalk";
import { spawn } from "child_process";
import { option, optional, string } from "cmd-ts";
import { randomBytes } from "crypto";
import { readFile } from "fs/promises";
import { appInstallLocationFilePath, lmsKey2Path } from "./lmstudioPaths.js";
import { type LogLevelArgs } from "./logLevel.js";
import { checkHttpServer } from "./subcommands/server.js";
import { refinedNumber } from "./types/refinedNumber.js";
import { DEFAULT_LOCAL_ENVIRONMENT_NAME, EnvironmentManager } from "./EnvironmentManager.js";
import { option, optional, string } from "cmd-ts";
interface AppInstallLocation {
path: string;
argv: Array<string>;
@ -17,30 +15,20 @@ interface AppInstallLocation {
}
export const createClientArgs = {
host: option({
env: option({
type: optional(string),
long: "host",
long: "env",
description: text`
If you wish to connect to a remote LM Studio instance, specify the host here. Note that, in
If you wish to connect to a remote LM Studio instance, specify the env here. Note that, in
this case, lms will connect using client identifier "lms-cli-remote-<random chars>", which
will not be a privileged client, and will restrict usage of functionalities such as
"lms push".
`,
}),
port: option({
type: optional(refinedNumber({ integer: true, min: 0, max: 65535 })),
long: "port",
description: text`
The port where LM Studio can be reached. If not provided and the host is set to "127.0.0.1"
(default), the last used port will be used; otherwise, 1234 will be used.
"lms push". Know more about envs using lms env.
`,
}),
};
interface CreateClientArgs {
yes?: boolean;
host?: string;
port?: number;
}
async function isLocalServerAtPortLMStudioServerOrThrow(port: number) {
@ -107,20 +95,22 @@ export async function createClient(
args: CreateClientArgs & LogLevelArgs,
_opts: CreateClientOpts = {},
) {
let { host, port } = args;
let isRemote = true;
if (host === undefined) {
isRemote = false;
host = "127.0.0.1";
} else if (host.includes("://")) {
logger.error("Host should not include the protocol.");
process.exit(1);
} else if (host.includes(":")) {
logger.error(
`Host should not include the port number. Use ${chalk.yellowBright("--port")} instead.`,
);
process.exit(1);
const envManager = new EnvironmentManager(logger);
let currentEnv = await envManager.getCurrentEnvironment();
let host = currentEnv.host;
let port = currentEnv.port;
if (args.env) {
// If the user specified an environment, we will override the current environment with the specified one.
const specificedEnv = await envManager.tryGetEnvironment(args.env);
if (specificedEnv === undefined) {
logger.error(`Environment '${args.env}' not found`);
process.exit(1);
}
host = specificedEnv.host;
port = specificedEnv.port;
currentEnv = specificedEnv;
}
const isRemote = currentEnv.name !== DEFAULT_LOCAL_ENVIRONMENT_NAME;
let auth: LMStudioClientConstructorOpts;
if (isRemote) {
// If connecting to a remote server, we will use a random client identifier.
@ -146,7 +136,7 @@ export async function createClient(
};
}
}
if (port === undefined && host === "127.0.0.1") {
if (isRemote === false) {
// We will now attempt to connect to the local API server.
const localPort = await tryFindLocalAPIServer();
@ -186,11 +176,6 @@ export async function createClient(
logger.error("");
}
if (port === undefined) {
port = 1234;
}
logger.debug(`Connecting to server at ${host}:${port}`);
if (!(await checkHttpServer(logger, port, host))) {
logger.error(