export declare const PID_FILE: string; export declare const LOG_FILE: string; /** Set by spawnBackground / restart helper when child stdio already is LOG_FILE. */ export declare const LOG_REDIRECTED_ENV = "AGIM_LOG_REDIRECTED"; export declare const DEFAULT_WEB_PORT = 3000; export declare const DEFAULT_ACP_PORT = 9090; export type ServiceMode = 'systemd' | 'background' | 'foreground' | 'none'; export interface ServiceState { mode: ServiceMode; pid: number | null; /** Approximate uptime in seconds — from systemd timestamp or proc start time. */ uptimeSec?: number; /** Raw `systemctl is-active` value when mode === 'systemd'. R14 — we * return mode='systemd' as soon as the unit is enabled, even when * state is `activating` / `failed` / `inactive`, so callers that * care about the difference can inspect this field. Undefined for * other modes. */ active?: string; } export interface TcpEndpoint { bind: string; port: number; } export interface TcpPortCheck extends TcpEndpoint { available: boolean; code?: string; owner?: string; } export declare const _internal: { setDetectServiceOverride(fn: (() => ServiceState) | null): void; /** Test-only: unwrap stdout/stderr mirrors installed by ensureServiceLogMirror. */ resetServiceLogMirrorForTests(): void; }; /** * Ensure ~/.agim/agim.log exists and mirror stdout/stderr into it. * * Historically only `spawnBackground` (`agim start --bg` / restart helper) * opened the file as the child's stdout/stderr. systemd and foreground * starts never created it, so Web Settings → Service log-tail and CLI * status always reported "not generated yet". * * When `AGIM_LOG_REDIRECTED=1`, stdio already points at LOG_FILE — only * touch/ensure the path; do not tee (would duplicate every line). */ export declare function ensureServiceLogMirror(): void; /** Format seconds as e.g. "2h 15m" / "3d 4h" / "45s". */ export declare function formatUptime(sec: number): string; /** Look up the running mode + pid. Order matters: systemd wins, then bg * pid-file, then a foreground pgrep match. Returns `{mode:'none', pid:null}` * when nothing is running. */ export declare function detectService(): ServiceState; /** * Spawn Agim detached with stdio redirected to ~/.agim/agim.log. * Writes the pid to PID_FILE so subsequent `status` / `stop` find it. * * Cross-platform: setsid → new session, no controlling tty, parent can exit. * On macOS where setsid isn't always reliable, fall through to a plain * detached spawn (child still gets stdio: 'ignore' / 'pipe' redirected to * the log file, which is enough to survive the parent). */ export declare function spawnBackground(executable: string, args?: string[]): { pid: number; }; /** Stop whichever instance is running. Returns the mode that was stopped * (or 'none' when there was nothing to do). */ export declare function stopService(): Promise<{ mode: ServiceMode; pid: number | null; }>; /** Get the configured web bind+port from `/config.json` — * used by `status` to print the URL. Returns null when config is * absent / unparseable. */ export declare function readWebEndpoint(): { bind: string; port: number; } | null; /** Get the configured ACP bind+port. ACP is optional for first-run Web * chat, but its default 9090 collides with common local proxy tools, so * quickstart/doctor need to make that conflict visible. */ export declare function readAcpEndpoint(): TcpEndpoint; /** Best-effort owner for a listening TCP port. Used only for human-facing * diagnostics; absence of lsof (or permission limits) simply means the * owner is omitted. */ export declare function findTcpListenOwner(port: number): string | undefined; export declare function checkTcpListenAvailable(endpoint: TcpEndpoint): Promise; /** R14 — find every Agim process running on this host. * Includes pids from background spawns AND systemd-spawned children * that may have escaped the cgroup (the failure mode that motivated * R14: a dbus-run-session wrapper detaches its children from * systemd's control group, leaving the previous agim alive after * `systemctl stop` "succeeds"). * * R15 — argv-strict matching. Pre-R15 this used `pgrep -af "agim start"` * which matched any process whose cmdline contained the substring * "agim start" anywhere — meaning a `bash -c 'echo "agim start"'` test * helper got SIGTERM'd by the reap path. Now we read /proc//cmdline * directly and require: * - argv[0] basename is a node-like interpreter (node / bun) * - argv[1] basename is an agim entry script (agim / cli.js) * - argv[2] is the literal string 'start' * This is impossible for a shell to satisfy — shells have argv[0]=bash. * * Non-Linux (darwin / windows) falls back to ps output; /proc isn't * available there, and those platforms aren't the R14 motivating case * (server-side cgroup escapes need systemd + Linux). */ export declare function findAgimProcesses(): number[]; /** R14 — SIGTERM then SIGKILL any agim process not in the excludeSet. * Used by the web restart handler to clear stray instances that * escaped systemd's cgroup before invoking `systemctl restart` (the * cgroup-kill on stop will then have nothing left to fail on, and * the new MainPID gets a clean port). * * Returns the pids actually reaped (signalled + confirmed dead). * Best-effort: a pid we can't signal (permissions, already exited) * is silently dropped — caller is interested in "what we killed", * not in surfacing failures the OS already handled. */ export declare function reapStrayAgimProcesses(opts?: { excludePids?: number[]; sigtermTimeoutMs?: number; }): Promise<{ reaped: number[]; survived: number[]; }>; //# sourceMappingURL=service.d.ts.map