Add path resolution and slopo config rendering
Every path the plugin owns is under $DSH_HOME. Only two directories in the container this runs in are persistent volumes ($DSH_HOME and the workspace root); $HOME/.local -- where 'uv tool install' puts slopo and its CPython by default -- is on the container's writable layer and dies on recreation, not merely on restart. renderSlopoConfig writes from a closed allow-list because slopo treats an unknown config key as a hard error, and quotes every scalar because a path can contain a colon or a leading dash. Verified against slopo 0.8.0 itself: it reads the generated file back with no complaint and round-trips all 19 keys. The embedding API key is deliberately absent -- slopo reads SLOPO_EMBEDDING_API_KEY from the environment ahead of the YAML value, so the secret never lands on disk.
This commit is contained in:
1 parent
3490e5aba0
commit
844f12faa3
2 files changed
+281
No files matched your search
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Where this plugin keeps things on disk.
|
||||
*
|
||||
* Every path here is deliberately under `$DSH_HOME`, because `$DSH_HOME` is the
|
||||
* one directory that survives the container this harness usually runs in. The
|
||||
* uv-managed slopo install and the CPython it needs would otherwise live in
|
||||
* `~/.local`, which is on the container's writable layer and is lost whenever
|
||||
* the container is recreated rather than merely restarted.
|
||||
*
|
||||
* Relative paths are never used: slopo resolves every relative path against the
|
||||
* *process working directory*, not against the config file that named it, so a
|
||||
* relative path in a config invoked as `--config /elsewhere/x.yaml` still lands
|
||||
* in whatever directory the caller happened to be in.
|
||||
*/
|
||||
|
||||
import { createHash } from 'node:crypto'
|
||||
import { homedir } from 'node:os'
|
||||
import { basename, join, resolve } from 'node:path'
|
||||
|
||||
/** Plugin name, used for the `$DSH_HOME/plugin-data/<name>` directory. */
|
||||
export const PLUGIN_NAME = 'dsh-slopo'
|
||||
|
||||
/** The dsh home directory: `$DSH_HOME`, else `~/.dsh`. */
|
||||
export function resolveDshHome(env = process.env) {
|
||||
const configured = typeof env.DSH_HOME === 'string' ? env.DSH_HOME.trim() : ''
|
||||
return configured === '' ? join(homedir(), '.dsh') : resolve(configured)
|
||||
}
|
||||
|
||||
/**
|
||||
* A stable, filesystem-safe key for one workspace.
|
||||
*
|
||||
* The basename is for a human reading the directory listing; the hash is what
|
||||
* actually identifies it, so two checkouts both named `app` cannot collide.
|
||||
*/
|
||||
export function workspaceKey(cwd) {
|
||||
const absolute = resolve(cwd)
|
||||
const name =
|
||||
basename(absolute)
|
||||
.replace(/[^A-Za-z0-9._-]+/g, '-')
|
||||
.replace(/^[-.]+|-+$/g, '') || 'workspace'
|
||||
const hash = createHash('sha256').update(absolute).digest('hex').slice(0, 8)
|
||||
return `${name}-${hash}`
|
||||
}
|
||||
|
||||
/** Per-workspace state: the slopo config, index database, ignore file and log. */
|
||||
export function workspaceStateDir(dshHome, cwd) {
|
||||
return join(dshHome, 'plugin-data', PLUGIN_NAME, 'workspaces', workspaceKey(cwd))
|
||||
}
|
||||
|
||||
/** Root of this plugin's own data, independent of any workspace. */
|
||||
export function pluginDataDir(dshHome) {
|
||||
return join(dshHome, 'plugin-data', PLUGIN_NAME)
|
||||
}
|
||||
|
||||
/**
|
||||
* The directory `uv tool install` writes the slopo venv and shim into.
|
||||
*
|
||||
* Redirected here from its `~/.local/share/uv/tools` default for the durability
|
||||
* reason in the file header.
|
||||
*/
|
||||
export function managedToolDir(dshHome) {
|
||||
return join(pluginDataDir(dshHome), 'uv-tools')
|
||||
}
|
||||
|
||||
/** The directory uv keeps its downloaded CPython builds in. */
|
||||
export function managedPythonDir(dshHome) {
|
||||
return join(pluginDataDir(dshHome), 'uv-python')
|
||||
}
|
||||
|
||||
/** The slopo executable inside {@link managedToolDir}. */
|
||||
export function managedSlopoPath(dshHome) {
|
||||
return join(managedToolDir(dshHome), 'bin', process.platform === 'win32' ? 'slopo.exe' : 'slopo')
|
||||
}
|
||||
|
||||
/** Slopo's own default install location, for machines that already have one. */
|
||||
export function userLocalSlopoPath(env = process.env) {
|
||||
const home = typeof env.HOME === 'string' && env.HOME !== '' ? env.HOME : homedir()
|
||||
return join(home, '.local', 'bin', process.platform === 'win32' ? 'slopo.exe' : 'slopo')
|
||||
}
|
||||
Reference in new issue
Block a user