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

66 lines (65 loc) • 3.27 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/. /** * Opt-in, non-blocking rebuild lock for `akm index` (#956). * * #872 removed the blocking index-rebuild lease: the index is a regenerable * cache, so a concurrent rebuild only wastes work rather than corrupts * anything, and a live-but-wedged holder passed a PID-liveness check forever * — only an age-based clock could ever free it, which is exactly the hazard * #872 deleted. This module does not reinstate that lock. It adds a * PID-liveness-only sentinel an explicit `akm index` run acquires and * releases on exit purely so a *scheduled or opportunistic* run * (`--skip-if-locked`) can step aside instead of piling up behind a rebuild * already in progress. A human-typed `akm index` with no flag is never * gated: it warns and proceeds exactly as it did before this lock existed. * * Built on the shared PID-liveness mechanics in `core/run-lock.ts` (the same * ones `akm improve`'s whole-run lock uses) — see that module's doc for the * no-stale-age-window rationale. */ import { releaseLock } from "../core/file-lock.js"; import { getIndexRebuildLockPath } from "../core/paths.js"; import { formatLockHolderPid, tryAcquireRunLock } from "../core/run-lock.js"; import { warn, warnVerbose } from "../core/warn.js"; export function indexRebuildLockPath() { return getIndexRebuildLockPath(); } /** * Acquire the rebuild lock for the duration of one `akm index` run. * * - Free: always returns `"acquired"`. * - Held, `skipIfLocked`: warns once (naming the holder) and returns * `"skipped"` — the caller must not run `akmIndex()` at all. * - Held, no flag: warns once and returns `"contended"` — the caller runs * `akmIndex()` unlocked, exactly as every `akm index` did before #956. * * A dead holder's lease is reclaimed silently (verbose-only log line, never * a user-facing warning) — the operator did nothing wrong and nothing here * requires their attention. */ export function tryAcquireIndexRebuildLock(skipIfLocked) { const lockPath = indexRebuildLockPath(); const acquire = () => tryAcquireRunLock(lockPath, { label: "index rebuild", onReclaimed: (info) => { warnVerbose(`[index] reclaimed a rebuild lock left by pid ${info.holderPid ?? "unknown"} ` + `(${info.reason}); that process is no longer running.`); }, }); const result = acquire(); if (result.state === "acquired") return result; if (skipIfLocked) { warn(`[index] another index run holds the lock (PID ${formatLockHolderPid(result.holder)}, started ${result.holder.startedAt}); ` + "skipping (--skip-if-locked)"); return { state: "skipped", holder: result.holder }; } warn(`[index] another index run is active (pid ${formatLockHolderPid(result.holder)}, started ${result.holder.startedAt}); ` + "this run will contend with it — pass --skip-if-locked for scheduled runs"); return { state: "contended", holder: result.holder }; } export function releaseIndexRebuildLock(ownership) { releaseLock(ownership); }