Move config defaults to a shared constant in config.ts

Eliminates duplicated default values and simplifies the config
command by replacing the generic key metadata registry with
direct validation functions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Chris Wanstrath 2026-03-20 10:30:39 -07:00
parent e3e4419933
commit ea1b09dc8e
3 changed files with 25 additions and 25 deletions

View File

@ -1,41 +1,39 @@
import { die } from "../fmt.ts"
import * as config from "../config.ts"
const KEYS: Record<string, { default: string; description: string; normalize: (v: string) => string; validate: (v: string) => string | null }> = {
memory: {
default: "16G",
description: "Container memory limit (e.g. 4G, 16G, 32G, 64G)",
normalize: (v) => v.toUpperCase(),
validate: (v) => /^[1-9]\d*[GMgm]$/.test(v) ? null : "Must be a number followed by G or M (e.g. 16G)",
},
const VALID_KEYS = ["memory"] as const
type Key = (typeof VALID_KEYS)[number]
function validateMemory(v: string): string {
if (!/^[1-9]\d*[GMgm]$/.test(v)) die("Must be a number followed by G or M (e.g. 16G)")
return v.toUpperCase()
}
export async function action(args: string[]) {
if (args.length === 0) {
const cfg = await config.load()
for (const [key, meta] of Object.entries(KEYS)) {
const val = cfg[key as keyof config.Config]
const display = val ?? `${meta.default} (default)`
for (const key of VALID_KEYS) {
const val = cfg[key]
const display = val ?? `${config.DEFAULTS[key]} (default)`
console.log(`${key} = ${display}`)
console.log(` ${meta.description}`)
}
return
}
const [key, ...rest] = args
if (!(key in KEYS)) die(`Unknown config key: ${key}\nAvailable keys: ${Object.keys(KEYS).join(", ")}`)
if (!VALID_KEYS.includes(key as Key)) die(`Unknown config key: ${key}\nAvailable keys: ${VALID_KEYS.join(", ")}`)
if (rest.length === 0) {
const val = await config.get(key as keyof config.Config)
console.log(val ?? `${KEYS[key].default} (default)`)
const val = await config.get(key as Key)
console.log(val ?? `${config.DEFAULTS[key as Key]} (default)`)
return
}
if (rest.length > 1) die(`Too many arguments. Usage: sandlot config ${key} <value>`)
const meta = KEYS[key]
const error = meta.validate(rest[0])
if (error) die(error)
const normalized = meta.normalize(rest[0])
await config.set(key as keyof config.Config, normalized)
console.log(`${key} = ${normalized}`)
if (key === "memory") {
const normalized = validateMemory(rest[0])
await config.set("memory", normalized)
console.log(`memory = ${normalized}`)
}
}

View File

@ -4,6 +4,10 @@ import { dirname, join } from "path"
const CONFIG_PATH = join(homedir(), ".config", "sandlot", "config.json")
export const DEFAULTS = {
memory: "16G",
} as const
export interface Config {
memory?: string
}
@ -13,9 +17,7 @@ export async function load(): Promise<Config> {
if (!(await file.exists())) return {}
const raw = await file.json()
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return {}
const cfg: Config = {}
if (typeof raw.memory === "string") cfg.memory = raw.memory
return cfg
return raw as Config
}
export async function save(config: Config): Promise<void> {

View File

@ -4,7 +4,7 @@ import { homedir } from "os"
import { dirname, join } from "path"
import { requireApiKey } from "./env.ts"
import { info } from "./fmt.ts"
import { get as getConfig } from "./config.ts"
import { get as getConfig, DEFAULTS } from "./config.ts"
const DEBUG = !!process.env.DEBUG
const CONTAINER_NAME = "sandlot"
@ -67,7 +67,7 @@ function hostMounts(home: string): { dev: boolean; code: boolean } {
/** Pull the image and start the container in detached mode. */
async function createContainer(home: string): Promise<void> {
const mounts = hostMounts(home)
const memory = (await getConfig("memory")) ?? "16G"
const memory = (await getConfig("memory")) ?? DEFAULTS.memory
const args = ["container", "run", "-d", "--name", CONTAINER_NAME, "-m", memory]
if (mounts.dev) args.push("--mount", `type=bind,source=${home}/dev,target=/host/dev,readonly`)
if (mounts.code) args.push("--mount", `type=bind,source=${home}/code,target=/host/code,readonly`)