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

67 lines (66 loc) • 2.92 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/. /** * Serialize `fn` behind every task previously enqueued under `key`: an * in-process keyed promise chain (Bun is single-threaded, so this is a * sufficient — and free — admission control for per-key mutual exclusion). * * `chains` is the caller's own module-state map, so independent subsystems * (the unit-writer's per-database write queue, the worktree module's per-repo * git lock) never share chains. A failed task rejects its OWN caller but * never wedges the chain, and a drained tail deletes its map entry so a * long-lived process does not retain one settled promise per key it ever * touched. */ export function serializeByKey(chains, key, fn) { const tail = chains.get(key) ?? Promise.resolve(); const run = tail.then(() => fn()); // Keep the chain alive regardless of individual outcomes. const settled = run.then(() => undefined, () => undefined); chains.set(key, settled); // If another task was enqueued in the meantime the map now holds ITS tail, // and this check leaves it alone. void settled.then(() => { if (chains.get(key) === settled) chains.delete(key); }); return run; } /** * Maps over items concurrently with a pool size limit. * Uses Promise.allSettled semantics — one failure does not cancel others. * * Cooperative cancellation (P0.5 seam for the workflow scheduler): when * `opts.signal` aborts, workers stop CLAIMING new items — in-flight `fn` * calls run to completion (pass the same signal into `fn`'s own work to * preempt those too). Unclaimed items stay `undefined` in the result, * indistinguishable from individual failures by design: callers already * treat `undefined` as "no result". * * A thrown `fn` is SWALLOWED (its slot stays `undefined`) — a caller that * must report failure detail, or distinguish "threw" from "never claimed", * catches inside `fn` and returns an explicit outcome value instead. This is * the OPPOSITE of {@link serializeByKey} above, whose failures reject their * own caller. */ export async function concurrentMap(items, fn, concurrency = 1, opts) { const results = new Array(items.length).fill(undefined); let nextIndex = 0; async function worker() { while (nextIndex < items.length) { if (opts?.signal?.aborted) return; const i = nextIndex++; try { results[i] = await fn(items[i], i); } catch { // individual failure: leave undefined, caller checks } } } const workers = Array.from({ length: Math.min(concurrency, items.length) }, worker); await Promise.all(workers); return results; }