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
42 lines (41 loc) • 1.63 kB
JavaScript
// 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/.
const UNSAFE_KEYS = new Set(["__proto__", "constructor", "prototype"]);
export function isPlainObject(value) {
if (value === null || typeof value !== "object" || Array.isArray(value))
return false;
const prototype = Object.getPrototypeOf(value);
return prototype === Object.prototype || prototype === null;
}
function copyConfigValue(value) {
if (Array.isArray(value))
return value.map(copyConfigValue);
if (!isPlainObject(value))
return value;
const copy = {};
for (const key of Object.keys(value)) {
if (UNSAFE_KEYS.has(key))
throw new TypeError(`Unsafe configuration key: ${key}`);
copy[key] = copyConfigValue(value[key]);
}
return copy;
}
/**
* Merge configuration values without mutating either input. Plain objects merge
* recursively; arrays and scalar values replace the less-specific value.
*/
export function deepMergeConfig(base, override) {
const result = copyConfigValue(base);
for (const key of Object.keys(override)) {
if (UNSAFE_KEYS.has(key))
throw new TypeError(`Unsafe configuration key: ${key}`);
const next = override[key];
if (next === undefined)
continue;
const current = result[key];
result[key] =
isPlainObject(current) && isPlainObject(next) ? deepMergeConfig(current, next) : copyConfigValue(next);
}
return result;
}