/** * Wrapper Scripts Installation * * Installs command wrappers that route operations through the broker. * Supports dynamic wrapper management based on policy configuration. */ import type { UserConfig } from '@agenshield/ipc'; /** * Wrapper definition interface */ export interface WrapperDefinition { description: string; /** Whether this wrapper requires seatbelt profile */ usesSeatbelt?: boolean; /** Whether this wrapper uses Node.js interceptor */ usesInterceptor?: boolean; /** The content generator function */ generate: (config: WrapperConfig) => string; } /** * Configuration for wrapper generation */ export interface WrapperConfig { /** Agent home directory */ agentHome: string; /** Agent username */ agentUsername: string; /** Socket path */ socketPath: string; /** HTTP fallback port */ httpPort: number; /** Path to interceptor module */ interceptorPath: string; /** NODE_OPTIONS flag: '--require' for CJS or '--import' for ESM */ interceptorFlag: string; /** Path to seatbelt profiles */ seatbeltDir: string; /** Path to Python executable */ pythonPath: string; /** Path to Node.js executable */ nodePath: string; /** Path to npm executable */ npmPath: string; /** Path to brew executable */ brewPath: string; /** Path to NVM node version directory (e.g. ~/.nvm/versions/node/v24.13.0) */ nvmNodeDir: string; } /** * Default wrapper configuration */ export declare function getDefaultWrapperConfig(userConfig?: UserConfig): WrapperConfig; /** * Wrapper definitions with dynamic content generation */ export declare const WRAPPER_DEFINITIONS: Record; /** * Legacy static WRAPPERS export for backward compatibility */ export declare const WRAPPERS: Record; export interface WrapperResult { success: boolean; name: string; path: string; message: string; error?: Error; } /** * Generate wrapper content from definition */ export declare function generateWrapperContent(name: string, config?: WrapperConfig): string | null; /** * Install a single wrapper */ export declare function installWrapper(name: string, content: string, targetDir: string): Promise; /** * Install a wrapper with sudo (for system directories) */ export declare function installWrapperWithSudo(name: string, content: string, targetDir: string, owner?: string, group?: string): Promise; /** * Install all wrappers */ export declare function installWrappers(targetDir?: string, config?: WrapperConfig): Promise; /** * Install specific wrappers by name */ export declare function installSpecificWrappers(names: string[], targetDir: string, config?: WrapperConfig): Promise; /** * Uninstall a wrapper */ export declare function uninstallWrapper(name: string, targetDir: string): Promise; /** * Uninstall all wrappers */ export declare function uninstallWrappers(targetDir?: string): Promise; /** * Verify wrapper installation */ export declare function verifyWrappers(targetDir?: string): Promise<{ valid: boolean; installed: string[]; missing: string[]; }>; /** * Install all wrappers using UserConfig * * @param userConfig - UserConfig with user information * @param directories - Directories configuration */ export declare function installAllWrappers(userConfig: UserConfig, directories: { binDir: string; wrappersDir: string; }): Promise<{ success: boolean; error?: string; installed?: string[]; }>; /** * Verbose logging options */ export interface VerboseOptions { verbose?: boolean; } /** * Install guarded shell using the hardened zsh guarded-shell content */ export declare function installGuardedShell(userConfig?: UserConfig, options?: VerboseOptions): Promise; /** * Install the shield-exec Node.js command proxy and create symlinks. * * Writes shield-exec to /opt/agenshield/bin/shield-exec (root-owned, mode 755), * then creates symlinks in the agent's bin directory for all proxied commands. * node/python are kept as separate bash wrappers (they need NODE_OPTIONS/seatbelt). */ export declare function installShieldExec(userConfig: UserConfig, binDir: string): Promise<{ success: boolean; error?: string; installed?: string[]; }>; /** * Get list of available wrapper names */ export declare function getAvailableWrappers(): string[]; /** * Get wrapper definition by name */ export declare function getWrapperDefinition(name: string): WrapperDefinition | null; /** * Check if a wrapper uses seatbelt */ export declare function wrapperUsesSeatbelt(name: string): boolean; /** * Check if a wrapper uses interceptor */ export declare function wrapperUsesInterceptor(name: string): boolean; /** * Dynamic wrapper management - add a new wrapper at runtime */ export declare function addDynamicWrapper(name: string, content: string, targetDir: string, useSudo?: boolean, owner?: string, group?: string): Promise; /** * Dynamic wrapper management - remove a wrapper at runtime */ export declare function removeDynamicWrapper(name: string, targetDir: string, useSudo?: boolean): Promise; /** * Update an existing wrapper with new content */ export declare function updateWrapper(name: string, targetDir: string, config?: WrapperConfig, useSudo?: boolean): Promise; /** * Deploy the interceptor CJS bundle to the sandbox. * * Copies `@agenshield/interceptor/register` (CJS despite the package.json * "type":"module") to `/opt/agenshield/lib/interceptor/register.cjs` * so that node wrappers can use `--require` to load it. */ export declare function deployInterceptor(userConfig?: UserConfig): Promise; /** * Copy the broker binary to /opt/agenshield/bin/ * The broker is the privileged daemon that handles socket communication. */ export declare function copyBrokerBinary(userConfig?: UserConfig): Promise; /** * Copy the shield-client binary to /opt/agenshield/bin/ * Shield-client is the CLI used by wrapper scripts (curl, git, etc.) to route * operations through the broker. * * IMPORTANT: The shebang is rewritten from #!/usr/bin/env node to * #!/opt/agenshield/bin/node-bin so that shield-client runs WITHOUT the * interceptor. Otherwise there's an infinite recursion: * interceptor → curl wrapper → shield-client → node+interceptor → … */ export declare function copyShieldClient(userConfig?: UserConfig): Promise; /** * Copy the current Node.js binary to the sandbox so the node wrapper * can exec a known-good binary without relying on system PATH. */ export declare function copyNodeBinary(userConfig?: UserConfig, sourcePath?: string): Promise; /** * Result of NVM + Node.js installation for the agent user */ export interface NvmInstallResult { success: boolean; nvmDir: string; nodeVersion: string; nodeBinaryPath: string; message: string; error?: Error; } /** * Install NVM and a specific Node.js version for the agent user. * * Runs as the agent user via `sudo -u` with `/bin/bash` (not guarded-shell). * The NVM directory is created under the agent's home so versions can be * managed independently of the host system. * * The installed node binary is then copied to /opt/agenshield/bin/node-bin * by the caller via copyNodeBinary(userConfig, nodeBinaryPath). */ export declare function installAgentNvm(options: { agentHome: string; agentUsername: string; socketGroupName: string; nodeVersion?: string; verbose?: boolean; onLog?: (msg: string) => void; }): Promise; /** * Execute a command with real-time progress logging via spawn. * * Unlike execAsync which buffers all output, this streams stdout/stderr * line-by-line through the `log()` callback so the UI can show download * progress for long-running operations (NVM install, Node download, npm install). */ export declare function execWithProgress(command: string, log: (msg: string) => void, opts?: { timeout?: number; cwd?: string; env?: Record; }): Promise<{ stdout: string; stderr: string; }>; /** * Patch the NVM-installed node binary in-place with an interceptor wrapper. * * After NVM installs node, the real binary has already been copied to * `/opt/agenshield/bin/node-bin`. This function replaces the NVM binary * (e.g. `~/.nvm/versions/node/v24.13.0/bin/node`) with a bash wrapper * that loads the interceptor and execs `node-bin`. * * This ensures ALL node invocations go through the interceptor — whether * called from `~/bin/node`, NVM's PATH, or directly — closing the NVM * PATH-order bypass. */ export declare function patchNvmNode(options: { nodeBinaryPath: string; agentUsername: string; socketGroupName: string; interceptorPath: string; socketPath: string; httpPort: number; verbose?: boolean; onLog?: (msg: string) => void; }): Promise; export interface PresetInstallResult { success: boolean; installedWrappers: string[]; errors: string[]; seatbeltInstalled: boolean; } /** * Basic system commands that should be available via symlinks (no interception needed) */ export declare const BASIC_SYSTEM_COMMANDS: string[]; /** * Install symlinks for basic system commands that don't need interception */ export declare function installBasicCommands(binDir: string, options?: { verbose?: boolean; }): Promise<{ success: boolean; installed: string[]; errors: string[]; }>; /** * Install binaries for a preset: node binary, interceptor, wrappers, seatbelt, ownership lockdown. */ export declare function installPresetBinaries(options: { requiredBins: string[]; userConfig: UserConfig; binDir: string; socketGroupName: string; nodeVersion?: string; verbose?: boolean; /** Pre-installed NVM result from install-nvm step — skips duplicate installAgentNvm() */ nvmResult?: NvmInstallResult; }): Promise; //# sourceMappingURL=wrappers.d.ts.map