refactor: move setup scripts out of src/ to reduce build token count

Setup scripts are standalone CLI tools run via tsx with no runtime
imports from the main app. Moving them out of src/ excludes them from
the tsc build output and reduces the compiled bundle size.

- git mv src/setup/ setup/
- Fix imports to use ../src/logger.js and ../src/config.js
- Update package.json, vitest.config.ts, SKILL.md references
- Fix platform tests to be cross-platform (macOS + Linux)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-02-22 18:43:22 +02:00
parent c1a2491e77
commit 92d14405c5
18 changed files with 39 additions and 39 deletions

103
setup/mounts.ts Normal file
View File

@@ -0,0 +1,103 @@
/**
* Step: mounts — Write mount allowlist config file.
* Replaces 07-configure-mounts.sh
*/
import fs from 'fs';
import path from 'path';
import os from 'os';
import { logger } from '../src/logger.js';
import { isRoot } from './platform.js';
import { emitStatus } from './status.js';
function parseArgs(args: string[]): { empty: boolean; json: string } {
let empty = false;
let json = '';
for (let i = 0; i < args.length; i++) {
if (args[i] === '--empty') empty = true;
if (args[i] === '--json' && args[i + 1]) { json = args[i + 1]; i++; }
}
return { empty, json };
}
export async function run(args: string[]): Promise<void> {
const { empty, json } = parseArgs(args);
const homeDir = os.homedir();
const configDir = path.join(homeDir, '.config', 'nanoclaw');
const configFile = path.join(configDir, 'mount-allowlist.json');
if (isRoot()) {
logger.warn('Running as root — mount allowlist will be written to root home directory');
}
fs.mkdirSync(configDir, { recursive: true });
let allowedRoots = 0;
let nonMainReadOnly = 'true';
if (empty) {
logger.info('Writing empty mount allowlist');
const emptyConfig = {
allowedRoots: [],
blockedPatterns: [],
nonMainReadOnly: true,
};
fs.writeFileSync(configFile, JSON.stringify(emptyConfig, null, 2) + '\n');
} else if (json) {
// Validate JSON with JSON.parse (not piped through shell)
let parsed: { allowedRoots?: unknown[]; nonMainReadOnly?: boolean };
try {
parsed = JSON.parse(json);
} catch {
logger.error('Invalid JSON input');
emitStatus('CONFIGURE_MOUNTS', {
PATH: configFile,
ALLOWED_ROOTS: 0,
NON_MAIN_READ_ONLY: 'unknown',
STATUS: 'failed',
ERROR: 'invalid_json',
LOG: 'logs/setup.log',
});
process.exit(4);
return; // unreachable but satisfies TS
}
fs.writeFileSync(configFile, JSON.stringify(parsed, null, 2) + '\n');
allowedRoots = Array.isArray(parsed.allowedRoots) ? parsed.allowedRoots.length : 0;
nonMainReadOnly = parsed.nonMainReadOnly === false ? 'false' : 'true';
} else {
// Read from stdin
logger.info('Reading mount allowlist from stdin');
const input = fs.readFileSync(0, 'utf-8');
let parsed: { allowedRoots?: unknown[]; nonMainReadOnly?: boolean };
try {
parsed = JSON.parse(input);
} catch {
logger.error('Invalid JSON from stdin');
emitStatus('CONFIGURE_MOUNTS', {
PATH: configFile,
ALLOWED_ROOTS: 0,
NON_MAIN_READ_ONLY: 'unknown',
STATUS: 'failed',
ERROR: 'invalid_json',
LOG: 'logs/setup.log',
});
process.exit(4);
return;
}
fs.writeFileSync(configFile, JSON.stringify(parsed, null, 2) + '\n');
allowedRoots = Array.isArray(parsed.allowedRoots) ? parsed.allowedRoots.length : 0;
nonMainReadOnly = parsed.nonMainReadOnly === false ? 'false' : 'true';
}
logger.info({ configFile, allowedRoots, nonMainReadOnly }, 'Allowlist configured');
emitStatus('CONFIGURE_MOUNTS', {
PATH: configFile,
ALLOWED_ROOTS: allowedRoots,
NON_MAIN_READ_ONLY: nonMainReadOnly,
STATUS: 'success',
LOG: 'logs/setup.log',
});
}