clawdie-ai/setup/llama-cpp.ts
Clawdie AI cdf2c8f296 Enable Tailscale jail auto-join (Sam & Codex)
Add a setup helper to enable tailscale inside jails when FEATURE_TAILSCALE

and an auth key are present, prefetch tailscale packages, and document

the installer shortcut.

---

Build: FAIL — not run

Tests: FAIL — not run
2026-04-04 15:40:47 +00:00

138 lines
4.2 KiB
TypeScript

/**
* setup/llama-cpp.ts — Provision the llama-cpp jail for local inference.
*
* Creates the jail if missing, installs llama-cpp, and prepares
* directories for models. Does not start llama-server by default.
*/
import { execSync, spawnSync } from 'child_process';
import {
AGENT_INTERNAL_DOMAIN,
AGENT_NAME,
FEATURE_LLAMA_CPP,
LOCAL_LLM_PROVIDER,
LLAMA_CPP_JAIL_IP,
SUBNET_BASE,
} from '../src/config.js';
import { logger } from '../src/logger.js';
import { loadPackageList, mountPkgCacheInJail } from './packages.js';
import { getPlatform } from './platform.js';
import { emitStatus } from './status.js';
import { maybeEnableTailscaleInJail } from './tailscale.js';
const LOG = 'logs/setup.log';
const MODELS_DIR = '/var/db/llm-models';
function bastille(...args: string[]): { ok: boolean; output: string } {
const result = spawnSync('bastille', args, {
encoding: 'utf-8',
env: process.env,
});
const output = [result.stdout || '', result.stderr || '']
.filter(Boolean)
.join('\n')
.trim();
return { ok: (result.status ?? 1) === 0, output };
}
function jailExists(name: string): boolean {
const { output } = bastille('list');
return output.split('\n').some((line) => {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('JID')) return false;
const cols = trimmed.split(/\s+/u);
return cols.length > 1 && cols[1] === name;
});
}
function detectFreeBSDRelease(): string {
const output = execSync('freebsd-version -u', { encoding: 'utf-8' }).trim();
const match = output.match(/^(\d+\.\d+-\w+)/);
return match?.[1] ?? output;
}
export async function run(_args: string[]): Promise<void> {
const explicitJailName = (process.env.LLAMA_CPP_JAIL_NAME || '').trim();
const hostname = `llama-cpp.${AGENT_INTERNAL_DOMAIN}`;
const runBastille = (args: string[]) => bastille(...args);
if (!FEATURE_LLAMA_CPP && LOCAL_LLM_PROVIDER !== 'llama_cpp') {
emitStatus('SETUP_LLAMA_CPP', {
STATUS: 'skipped',
REASON: 'feature_disabled',
LOG,
});
logger.info('llama-cpp skipped — FEATURE_LLAMA_CPP disabled and provider not llama_cpp');
return;
}
if (getPlatform() !== 'freebsd') {
emitStatus('SETUP_LLAMA_CPP', {
STATUS: 'failed',
ERROR: 'unsupported_platform',
LOG,
});
process.exit(1);
}
try {
const preferredJailName = `${AGENT_NAME}-llamacpp`;
const legacyJailName = 'llamacpp';
let jailName = explicitJailName || preferredJailName;
if (!explicitJailName) {
if (jailExists(legacyJailName) && !jailExists(preferredJailName)) {
jailName = legacyJailName;
}
}
const exists = jailExists(jailName);
if (!exists) {
const release = detectFreeBSDRelease();
const gateway = process.env.WARDEN_GATEWAY || `${SUBNET_BASE}.1`;
const bridge = process.env.WARDEN_BRIDGE || 'warden0';
logger.info({ jailName, ip: LLAMA_CPP_JAIL_IP, release }, 'Creating llama-cpp jail');
const create = bastille(
'create', '-T', '-B',
'-g', gateway,
jailName, release, `${LLAMA_CPP_JAIL_IP}/24`, bridge,
);
if (!create.ok) {
throw new Error(`bastille create failed: ${create.output}`);
}
bastille('config', jailName, 'set', 'host.hostname', hostname);
bastille('restart', jailName);
} else {
logger.info({ jailName }, 'llama-cpp jail already exists, skipping creation');
}
mountPkgCacheInJail(jailName);
const packages = loadPackageList('llama-cpp-jail.txt');
const pkg = bastille('pkg', jailName, 'install', '-y', ...packages);
if (!pkg.ok) {
logger.warn({ output: pkg.output }, 'llama-cpp package install had warnings');
}
maybeEnableTailscaleInJail(runBastille, jailName, jailName);
bastille('cmd', jailName, 'install', '-d', '-m', '755', MODELS_DIR);
emitStatus('SETUP_LLAMA_CPP', {
STATUS: 'success',
JAIL_NAME: jailName,
JAIL_IP: LLAMA_CPP_JAIL_IP,
MODELS_DIR,
NOTE: 'models_required',
LOG,
});
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
emitStatus('SETUP_LLAMA_CPP', {
STATUS: 'failed',
ERROR: message,
LOG,
});
throw error;
}
}