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

60 lines (59 loc) • 2.45 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/. /** * Terminal-glyph and color gating helpers (#486). * * Honor the [NO_COLOR](https://no-color.org/) convention — when NO_COLOR is * present in the environment (with any value, including empty), the CLI * suppresses both ANSI color codes AND decorative emoji glyphs. Emoji often * render as garbage in non-Unicode terminals or get logged as literal bytes * when output is piped to text aggregators, so we treat them as a subset of * "color" decoration. * * Detection is also automatic on non-TTY stderr (output piped or redirected * to a file), where decorative glyphs add nothing. */ /** * Returns true when decorative glyphs and color codes should be emitted. * False when NO_COLOR is set or stderr is not a TTY (unless FORCE_COLOR * overrides per the de-facto Node convention). */ export function shouldDecorate() { if (process.env.NO_COLOR !== undefined) return false; if (process.env.FORCE_COLOR !== undefined && process.env.FORCE_COLOR !== "" && process.env.FORCE_COLOR !== "0") { return true; } return process.stderr.isTTY === true; } // Map known decorative emoji to plain ASCII fallbacks. Anything not listed // is still removed by the catch-all sweep below when decoration is off. const EMOJI_FALLBACKS = [ [/\u{1F44B}\s*/gu, ""], // wave (with trailing space) [/✓/g, "[ok]"], [/✗/g, "[x]"], [/✘/g, "[x]"], [/⚠️?/g, "[!]"], [/\u{1F4DA}\s*/gu, ""], // books ]; /** * If decoration is disabled, replace known emoji with ASCII fallbacks and * strip any remaining pictograph code points. If decoration is enabled, * return the input unchanged. */ export function plainize(text) { if (shouldDecorate()) return text; let out = text; for (const [pattern, repl] of EMOJI_FALLBACKS) { out = out.replace(pattern, repl); } // Catch-all for unmapped pictographs. Future-proof when new emoji are added // to call sites without updating the explicit map. out = out.replace(/[\u{1F300}-\u{1FAFF}]/gu, ""); // Collapse runs of whitespace introduced by emoji removal, but preserve // intentional leading indentation. Only collapses interior runs. out = out.replace(/(\S)[ \t]{2,}/g, "$1 "); return out; }