UNPKG

akm-cli

Version:

akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cur

59 lines (58 loc) • 2.57 kB
// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. /** Signal -> {exit code, reason, ack message}. */ export const SIGNAL_TABLE = { SIGTERM: { code: 143, reason: "SIGTERM", ack: true }, SIGINT: { code: 130, reason: "SIGINT", ack: true }, SIGHUP: { code: 129, reason: "SIGHUP", ack: false }, }; /** * Drive the improve-run lifecycle: register signal handlers, await `runWork`, * and on clean completion remove the handlers and resolve with the result. The * caller (improve-cli.ts) owns success-path result persistence + the final * `exit(0)`; this function returns the work result so that choreography stays * in the CLI exactly as before. * * Abnormal paths: * - A registered signal fires -> persist terminated row (watchdog-guarded) -> * optional ack -> `exit(code)`. * - `runWork` rejects -> handlers are removed and the rejection propagates so * the CLI's existing catch can persist `"exception"` and rethrow. */ export async function runImproveSession(opts, deps) { const { signalSource, exit, onTerminate, ack } = deps; const makeSignalHandler = (sig) => () => { const { code, reason, ack: shouldAck } = SIGNAL_TABLE[sig]; // Hard-exit fallback: if the synchronous persist ever hangs (e.g. a stuck // sqlite lock under contention), the watchdog still exits with the correct // code instead of leaving a zombie process. .unref() keeps the timer from // holding the loop open on the normal (fast) path. const watchdog = setTimeout(() => exit(code), 2000); if (typeof watchdog.unref === "function") watchdog.unref(); try { onTerminate(reason); } finally { clearTimeout(watchdog); } if (shouldAck) ack?.(`received ${sig}`); exit(code); }; const sigtermHandler = makeSignalHandler("SIGTERM"); const sigintHandler = makeSignalHandler("SIGINT"); const sighupHandler = makeSignalHandler("SIGHUP"); signalSource.once("SIGTERM", sigtermHandler); signalSource.once("SIGINT", sigintHandler); signalSource.once("SIGHUP", sighupHandler); try { return await opts.runWork(); } finally { signalSource.removeListener("SIGTERM", sigtermHandler); signalSource.removeListener("SIGINT", sigintHandler); signalSource.removeListener("SIGHUP", sighupHandler); } }