import { ConfigManager } from '../config/manager.js'; import type { FeatureFlagReader } from '../runtime/feature-flags/index.js'; export type ManagedServicePlatform = 'systemd' | 'launchd' | 'windows' | 'manual'; export interface ManagedServiceDefinition { readonly name: string; readonly description: string; readonly workingDirectory: string; readonly command: string; readonly args: readonly string[]; readonly env: Readonly>; readonly restartOnFailure: boolean; } export interface ManagedServiceStatus { readonly platform: ManagedServicePlatform; /** The resolved service name (`service.serviceName` config, else the built-in default), so a CLI/consumer never has to hardcode it. */ readonly serviceName: string; readonly path: string; readonly installed: boolean; readonly autostart: boolean; readonly running: boolean; readonly pid?: number | undefined; readonly logPath?: string | undefined; readonly commandPreview: string; readonly contents?: string | undefined; readonly suggestedCommands: readonly string[]; readonly lastAction?: 'install' | 'uninstall' | 'start' | 'stop' | 'restart' | 'status' | undefined; readonly actionError?: string | undefined; /** * One honest line about login lingering after an install on systemd: * verified-on means the daemon starts at boot; anything else names the * exact command the user can run once themselves. */ readonly lingerNote?: string | undefined; } export interface ManagedServiceActionResult { readonly status: number | null; readonly stdout?: string | undefined; readonly stderr?: string | undefined; } interface ManagedServicePaths { readonly workingDirectory: string; readonly homeDirectory: string; } export interface ManagedServiceManagerOptions extends ManagedServicePaths { readonly definitionOverride?: ManagedServiceDefinition | undefined; readonly actionRunner?: ((command: string, args: readonly string[]) => ManagedServiceActionResult) | undefined; readonly surfaceRoot?: string | undefined; readonly binaryBaseName?: string | undefined; readonly defaultServiceName?: string | undefined; readonly defaultServiceDescription?: string | undefined; readonly featureFlags?: FeatureFlagReader | undefined; } /** * Escalating restart delays (RestartSteps=/RestartMaxDelaySec=) landed in * systemd 254. On older systemd, or when the version cannot be read, the * unit degrades to the flat RestartSec retry, which StartLimitIntervalSec=0 * already keeps retrying forever instead of tombstoning. */ export declare function systemdSupportsRestartSteps(majorVersion: number | null): boolean; /** First line of `systemctl --version` is "systemd NNN (...)"; returns NNN or null. */ export declare function parseSystemdMajorVersion(versionOutput: string | undefined): number | null; /** * Survival contract for a restartOnFailure unit: StartLimitIntervalSec=0 * disables the start-rate limiter, so a crashing daemon keeps retrying * (spaced by the delays below) instead of landing in the permanent * "start-limit-hit" failed state that only a manual reset-failed clears. On * systemd 254+ the retry delay escalates from RestartSec up to * RestartMaxDelaySec across RestartSteps attempts; on older systemd those * two directives are omitted (they would be ignored with a warning) and the * flat RestartSec applies to every retry. */ export declare function renderSystemdUnit(definition: ManagedServiceDefinition, systemdMajorVersion?: number | null): string; export declare class PlatformServiceManager { private readonly configManager; private readonly workingDirectory; private readonly homeDirectory; private readonly definitionOverride?; private readonly actionRunner?; private readonly surfaceRoot?; private readonly binaryBaseName?; private readonly defaultServiceName?; private readonly defaultServiceDescription?; private readonly featureFlags; constructor(configManager: ConfigManager, options: ManagedServiceManagerOptions); private isEnabled; private requireEnabled; private getPaths; status(): ManagedServiceStatus; install(): ManagedServiceStatus; /** systemd major version via the injected runner, or null when unreadable. */ private detectSystemdMajorVersion; /** * A user unit with WantedBy=default.target only starts when its user logs * in. Lingering starts the user's systemd instance at boot, so the daemon * comes up on a machine nobody has logged into. `loginctl enable-linger` * can exit 0 without taking effect in some polkit setups, so the * show-user property readback is the source of truth, checked before and * after enabling. Returns exactly one honest line either way. */ private ensureLinger; uninstall(): ManagedServiceStatus; start(): ManagedServiceStatus; stop(): ManagedServiceStatus; restart(): ManagedServiceStatus; private resolveDefinition; private startManual; private stopManual; private runPlatformAction; /** * Resolves `running` (+ `pid` when known) for `status()`. Only the manual * platform's `startManual` ever writes the pid file (`start()` branches on * `platform === 'manual'` before ever calling `runPlatformAction`), so for * systemd/launchd the pid file is permanently absent and a pid-file-only * check would report `running: false` for a genuinely active unit. systemd * and launchd are queried live instead, through the same injected * `actionRunner` used by start/stop/restart (never a raw exec bypassing it, * so tests can fake the query deterministically). */ private queryRunning; private queryPlatformRunning; /** Runs a service-management query/action through the injected actionRunner when present, else a real spawnSync, the single choke point start/stop/restart/status share. */ private runQuery; private readPid; private isPidRunning; } export {}; //# sourceMappingURL=service-manager.d.ts.map