Refactor config command and fix default memory limit
Move defaults and normalization into KEYS metadata, validate config file shape on load, and lower default container memory from 32G to 16G. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f7d876776b
commit
e3e4419933
14
README.md
14
README.md
|
|
@ -45,3 +45,17 @@ sandlot rm <branch> # tear down session (container, worktree, local branch)
|
||||||
```
|
```
|
||||||
|
|
||||||
Use git directly for commits, pushes, merges, etc. The worktree is a normal git checkout.
|
Use git directly for commits, pushes, merges, etc. The worktree is a normal git checkout.
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sandlot config # show all options and current values
|
||||||
|
sandlot config memory # show current memory setting
|
||||||
|
sandlot config memory 32G # set container memory limit
|
||||||
|
```
|
||||||
|
|
||||||
|
Config is stored in `~/.config/sandlot/config.json`.
|
||||||
|
|
||||||
|
| Key | Default | Description |
|
||||||
|
|-----|---------|-------------|
|
||||||
|
| `memory` | `16G` | Container memory limit (e.g. 4G, 16G, 32G, 64G) |
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,41 @@
|
||||||
import { die } from "../fmt.ts"
|
import { die } from "../fmt.ts"
|
||||||
import * as config from "../config.ts"
|
import * as config from "../config.ts"
|
||||||
|
|
||||||
const KEYS: Record<string, { description: string; validate: (v: string) => string | null }> = {
|
const KEYS: Record<string, { default: string; description: string; normalize: (v: string) => string; validate: (v: string) => string | null }> = {
|
||||||
memory: {
|
memory: {
|
||||||
|
default: "16G",
|
||||||
description: "Container memory limit (e.g. 4G, 16G, 32G, 64G)",
|
description: "Container memory limit (e.g. 4G, 16G, 32G, 64G)",
|
||||||
validate: (v) => /^\d+[GMgm]$/.test(v) ? null : "Must be a number followed by G or M (e.g. 16G)",
|
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)",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function action(args: string[]) {
|
export async function action(args: string[]) {
|
||||||
if (args.length === 0) {
|
if (args.length === 0) {
|
||||||
const cfg = await config.load()
|
const cfg = await config.load()
|
||||||
const defaults: Record<string, string> = { memory: "32G" }
|
|
||||||
for (const [key, meta] of Object.entries(KEYS)) {
|
for (const [key, meta] of Object.entries(KEYS)) {
|
||||||
const val = (cfg as any)[key]
|
const val = cfg[key as keyof config.Config]
|
||||||
const display = val ?? `${defaults[key]} (default)`
|
const display = val ?? `${meta.default} (default)`
|
||||||
console.log(`${key} = ${display}`)
|
console.log(`${key} = ${display}`)
|
||||||
|
console.log(` ${meta.description}`)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length === 1) {
|
const [key, ...rest] = args
|
||||||
const key = args[0]
|
if (!(key in KEYS)) die(`Unknown config key: ${key}\nAvailable keys: ${Object.keys(KEYS).join(", ")}`)
|
||||||
if (!(key in KEYS)) die(`Unknown config key: ${key}\nAvailable keys: ${Object.keys(KEYS).join(", ")}`)
|
|
||||||
|
if (rest.length === 0) {
|
||||||
const val = await config.get(key as keyof config.Config)
|
const val = await config.get(key as keyof config.Config)
|
||||||
const defaults: Record<string, string> = { memory: "32G" }
|
console.log(val ?? `${KEYS[key].default} (default)`)
|
||||||
console.log(val ?? `${defaults[key]} (default)`)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const [key, value] = args
|
if (rest.length > 1) die(`Too many arguments. Usage: sandlot config ${key} <value>`)
|
||||||
if (!(key in KEYS)) die(`Unknown config key: ${key}\nAvailable keys: ${Object.keys(KEYS).join(", ")}`)
|
const meta = KEYS[key]
|
||||||
const error = KEYS[key].validate(value)
|
const error = meta.validate(rest[0])
|
||||||
if (error) die(error)
|
if (error) die(error)
|
||||||
await config.set(key as keyof config.Config, value.toUpperCase())
|
const normalized = meta.normalize(rest[0])
|
||||||
console.log(`${key} = ${value.toUpperCase()}`)
|
await config.set(key as keyof config.Config, normalized)
|
||||||
|
console.log(`${key} = ${normalized}`)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { mkdir } from "fs/promises"
|
||||||
import { homedir } from "os"
|
import { homedir } from "os"
|
||||||
import { dirname, join } from "path"
|
import { dirname, join } from "path"
|
||||||
|
|
||||||
|
|
@ -8,15 +9,16 @@ export interface Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function load(): Promise<Config> {
|
export async function load(): Promise<Config> {
|
||||||
try {
|
const file = Bun.file(CONFIG_PATH)
|
||||||
return await Bun.file(CONFIG_PATH).json()
|
if (!(await file.exists())) return {}
|
||||||
} catch {
|
const raw = await file.json()
|
||||||
return {}
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return {}
|
||||||
}
|
const cfg: Config = {}
|
||||||
|
if (typeof raw.memory === "string") cfg.memory = raw.memory
|
||||||
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function save(config: Config): Promise<void> {
|
export async function save(config: Config): Promise<void> {
|
||||||
const { mkdir } = await import("fs/promises")
|
|
||||||
await mkdir(dirname(CONFIG_PATH), { recursive: true })
|
await mkdir(dirname(CONFIG_PATH), { recursive: true })
|
||||||
await Bun.write(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n")
|
await Bun.write(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ function hostMounts(home: string): { dev: boolean; code: boolean } {
|
||||||
/** Pull the image and start the container in detached mode. */
|
/** Pull the image and start the container in detached mode. */
|
||||||
async function createContainer(home: string): Promise<void> {
|
async function createContainer(home: string): Promise<void> {
|
||||||
const mounts = hostMounts(home)
|
const mounts = hostMounts(home)
|
||||||
const memory = (await getConfig("memory")) ?? "32G"
|
const memory = (await getConfig("memory")) ?? "16G"
|
||||||
const args = ["container", "run", "-d", "--name", CONTAINER_NAME, "-m", 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.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`)
|
if (mounts.code) args.push("--mount", `type=bind,source=${home}/code,target=/host/code,readonly`)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user