first commit

This commit is contained in:
kim
2026-07-06 12:41:15 +09:00
commit 68f2242984
47 changed files with 11348 additions and 0 deletions
+100
View File
@@ -0,0 +1,100 @@
import { Command } from "commander";
import { makeClient } from "./backend/client.js";
import { ConfigError, resolveBackendConfig, resolveModel } from "./config/config.js";
import { configFilePath, loadStoredConfig, saveStoredConfig, type StoredConfig } from "./config/store.js";
import { runInkApp } from "./ui/ink/index.js";
const program = new Command();
function addBackendOptions(cmd: Command): Command {
return cmd
.option("-b, --backend <name>", "backend to use: ollama or lmstudio")
.option("--base-url <url>", "override the backend's base URL");
}
program
.name("locode")
.description("Agentic coding CLI for local models via Ollama and LM Studio")
.version("0.1.0");
addBackendOptions(program)
.option("-m, --model <name>", "model name as known to the backend")
.option(
"--tool-mode <mode>",
"native | fallback | auto — auto defaults to native, probing only on /model and /backend",
"auto",
)
.action(async (opts) => {
try {
const { baseURL } = resolveBackendConfig(opts);
// Only an explicit --model flag skips the picker; a saved/env default is offered as a suggestion instead.
const model: string | undefined = opts.model;
const suggestedModel = model ? undefined : resolveModel(undefined);
const toolModeOverride = opts.toolMode === "native" || opts.toolMode === "fallback" ? opts.toolMode : undefined;
await runInkApp({ baseURL, model, suggestedModel, cwd: process.cwd(), toolModeOverride });
} catch (err) {
if (err instanceof ConfigError) {
console.error(err.message);
process.exit(1);
}
console.error((err as Error).message);
process.exit(1);
}
});
addBackendOptions(program.command("models"))
.description("List models available from the configured backend")
.action(async (opts) => {
try {
const { baseURL } = resolveBackendConfig(opts);
const client = makeClient({ baseURL, model: "" });
const list = await client.models.list();
for (const m of list.data) {
console.log(m.id);
}
} catch (err) {
if (err instanceof ConfigError) {
console.error(err.message);
process.exit(1);
}
console.error(`Failed to list models: ${(err as Error).message}`);
process.exit(1);
}
});
const configCmd = program.command("config").description("Manage persisted config");
configCmd
.command("get [key]")
.description("Print the whole config, or one key (backend, model, baseUrl)")
.action((key?: string) => {
const stored = loadStoredConfig();
if (!key) {
console.log(JSON.stringify(stored, null, 2));
return;
}
console.log(stored[key as keyof StoredConfig] ?? "(not set)");
});
configCmd
.command("set <key> <value>")
.description("Persist a config value (backend, model, baseUrl)")
.action((key: string, value: string) => {
if (key !== "backend" && key !== "model" && key !== "baseUrl") {
console.error(`Unknown config key "${key}". Valid keys: backend, model, baseUrl`);
process.exit(1);
}
const stored = loadStoredConfig();
stored[key] = value;
saveStoredConfig(stored);
console.log(`Set ${key} = ${value}`);
});
configCmd
.command("path")
.description("Print the path to the persisted config file")
.action(() => {
console.log(configFilePath());
});
program.parseAsync();