diff --git a/README.md b/README.md index b84b215..8c335a7 100644 --- a/README.md +++ b/README.md @@ -16,19 +16,7 @@ `lms` ships with [LM Studio](https://lmstudio.ai/) 0.2.22 and newer. -To set it up, run the built-in `bootstrap` command like so: - -- **Windows**: - - ```shell - cmd /c %USERPROFILE%/.cache/lm-studio/bin/lms.exe bootstrap - ``` - -- **Linux/macOS**: - - ```shell - ~/.cache/lm-studio/bin/lms bootstrap - ``` +If you have trouble running the command, try running `npx lmstudio install-cli` to add it to path. To check if the bootstrapping was successful, run the following in a **👉 new terminal window 👈**: diff --git a/package.json b/package.json index c252a43..b599949 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "license": "Apache-2.0", "dependencies": { "@lmstudio/lms-common": "^0.7.3", + "@lmstudio/lms-common-server": "^0.2.3", "@lmstudio/lms-es-plugin-runner": "^0.0.5", "@lmstudio/lms-isomorphic": "^0.4.2", "@lmstudio/lms-lmstudio": "^0.0.17", diff --git a/src/cliPref.ts b/src/cliPref.ts index 84cec31..f09bbd0 100644 --- a/src/cliPref.ts +++ b/src/cliPref.ts @@ -1,8 +1,7 @@ import { SimpleLogger } from "@lmstudio/lms-common"; -import os from "os"; -import path from "path"; import { z } from "zod"; import { SimpleFileData } from "./SimpleFileData.js"; +import { cliPrefPath } from "./lmstudioPaths.js"; export async function getCliPref(logger?: SimpleLogger) { const cliPrefSchema = z.object({ @@ -19,7 +18,7 @@ export async function getCliPref(logger?: SimpleLogger) { autoStartServer: undefined, }; const cliPref = new SimpleFileData( - path.join(os.homedir(), ".cache/lm-studio/.internal/cli-pref.json"), + cliPrefPath, defaultCliPref, cliPrefSchema, new SimpleLogger("CliPref", logger), diff --git a/src/createClient.ts b/src/createClient.ts index 9cab4f9..8600012 100644 --- a/src/createClient.ts +++ b/src/createClient.ts @@ -5,9 +5,7 @@ import { spawn } from "child_process"; import { option, optional, string } from "cmd-ts"; import { randomBytes } from "crypto"; import { readFile } from "fs/promises"; -import { homedir } from "os"; -import path from "path"; -import { lmsKey2Path } from "./lmstudioPaths.js"; +import { appInstallLocationFilePath, lmsKey2Path } from "./lmstudioPaths.js"; import { type LogLevelArgs } from "./logLevel.js"; import { checkHttpServer } from "./subcommands/server.js"; import { refinedNumber } from "./types/refinedNumber.js"; @@ -64,13 +62,9 @@ async function tryFindLocalAPIServer(): Promise { ); } -function getAppInstallLocationPath() { - return path.join(homedir(), ".cache/lm-studio/.internal/app-install-location.json"); -} - export async function wakeUpService(logger: SimpleLogger): Promise { logger.info("Waking up LM Studio service..."); - const appInstallLocationPath = getAppInstallLocationPath(); + const appInstallLocationPath = appInstallLocationFilePath; logger.debug(`Resolved appInstallLocationPath: ${appInstallLocationPath}`); try { const appInstallLocation = JSON.parse( diff --git a/src/lmstudioPaths.ts b/src/lmstudioPaths.ts index d445856..9caab63 100644 --- a/src/lmstudioPaths.ts +++ b/src/lmstudioPaths.ts @@ -1,5 +1,15 @@ -import { homedir } from "os"; +import { findLMStudioHome } from "@lmstudio/lms-common-server"; import { join } from "path"; -export const pluginsFolderPath = join(homedir(), ".cache", "lm-studio", "extensions", "plugins"); -export const lmsKey2Path = join(homedir(), ".cache", "lm-studio", ".internal", "lms-key-2"); +const lmstudioHome = findLMStudioHome(); +export const pluginsFolderPath = join(lmstudioHome, "extensions", "plugins"); +export const lmsKey2Path = join(lmstudioHome, ".internal", "lms-key-2"); +export const cliPrefPath = join(lmstudioHome, ".internal", "cli-pref.json"); +export const appInstallLocationFilePath = join( + lmstudioHome, + ".internal", + "app-install-location.json", +); +export const defaultModelsFolder = join(lmstudioHome, "models"); +export const serverCtlPath = join(lmstudioHome, ".internal", "http-server-ctl.json"); +export const serverConfigPath = join(lmstudioHome, ".internal", "http-server-config.json"); diff --git a/src/subcommands/importCmd.ts b/src/subcommands/importCmd.ts index 7269f60..bb9a59b 100644 --- a/src/subcommands/importCmd.ts +++ b/src/subcommands/importCmd.ts @@ -17,6 +17,7 @@ import { homedir } from "os"; import { basename, dirname, join } from "path"; import { z } from "zod"; import { getCliPref } from "../cliPref.js"; +import { defaultModelsFolder } from "../lmstudioPaths.js"; import { createLogger, logLevelArgs } from "../logLevel.js"; const userRepoType: Type = { @@ -327,7 +328,7 @@ async function locateSettingsJson(logger: SimpleLogger) { */ async function resolveModelsFolderPath(logger: SimpleLogger) { const settingsJsonPath = await locateSettingsJson(logger); - let modelsFolderPath = join(homedir(), ".cache", "lm-studio", "models"); + let modelsFolderPath = defaultModelsFolder; if (settingsJsonPath === null) { logger.warn( "Could not locate LM Studio configuration file, using default path:", diff --git a/src/subcommands/server.ts b/src/subcommands/server.ts index 134c2ac..721148f 100644 --- a/src/subcommands/server.ts +++ b/src/subcommands/server.ts @@ -1,9 +1,9 @@ import { text, type SimpleLogger } from "@lmstudio/lms-common"; import { command, flag, number, option, optional, subcommands } from "cmd-ts"; import { mkdir, readFile, writeFile } from "fs/promises"; -import os from "os"; import path from "path"; import { wakeUpService } from "../createClient.js"; +import { serverConfigPath, serverCtlPath } from "../lmstudioPaths.js"; import { createLogger, logLevelArgs } from "../logLevel.js"; type HttpServerCtl = @@ -20,19 +20,10 @@ interface HttpServerConfig { port: number; } -function getServerCtlPath() { - return path.join(os.homedir(), ".cache/lm-studio/.internal/http-server-ctl.json"); -} - -function getServerConfigPath() { - return path.join(os.homedir(), ".cache/lm-studio/.internal/http-server-config.json"); -} - /** * Write a control object to the server control file. */ async function writeToServerCtl(logger: SimpleLogger, controlObject: HttpServerCtl) { - const serverCtlPath = getServerCtlPath(); logger.debug(`Resolved serverCtlPath: ${serverCtlPath}`); const dir = path.dirname(serverCtlPath); logger.debug(`Making sure directory exists: ${dir}`); @@ -51,7 +42,7 @@ async function waitForCtlFileClear( ) { for (let i = 0; i < maxAttempts; i++) { await new Promise(resolve => setTimeout(resolve, checkIntervalMs)); - const isEmpty = (await readFile(getServerCtlPath(), "utf-8")).length === 0; + const isEmpty = (await readFile(serverCtlPath, "utf-8")).length === 0; if (isEmpty) { logger.debug(`Attempt ${i + 1}: File has been cleared`); return true; @@ -112,7 +103,7 @@ async function checkHttpServerWithRetries(logger: SimpleLogger, port: number, ma * Gets the last status of the server. */ export async function getServerConfig(logger: SimpleLogger) { - const lastStatusPath = getServerConfigPath(); + const lastStatusPath = serverConfigPath; logger.debug(`Reading last status from ${lastStatusPath}`); const lastStatus = JSON.parse(await readFile(lastStatusPath, "utf-8")) as HttpServerConfig; return lastStatus;