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
54 lines (53 loc) • 2.52 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/.
/**
* ANSI escape sequences (CSI color/cursor codes). Defensive only: the builder
* always passes `--no-pretty`, but a user profile may override that.
* Constructed from a char code so no literal control character appears in
* source (lint-friendly, same bytes).
*/
const ANSI_ESCAPE_RE = new RegExp(`${String.fromCharCode(27)}\\[[0-9;?]*[ -/]*[@-~]`, "g");
/**
* Aider's own announcement lines — banner, model/repo configuration echo,
* chat-history notices, edit/commit/usage reports. All patterns are anchored
* at line start and match documented phrasings only; anything else is treated
* as reply content.
*/
const NOISE_LINE_PATTERNS = [
/^aider v\d/, // version banner
/^(Main model|Weak model|Editor model|Model):\s/, // model announcements
/^Git repo:\s/, // repo detection
/^Repo-map:\s/, // repo-map status
/^Added .+ to the chat\.?$/, // file add notices
/^Restored previous conversation history\.?$/, // chat-history reload notice
/^Use \/help\b/, // onboarding hint line
/^Tokens: .+/, // usage/cost footer
/^Cost: .+/, // standalone cost footer
/^Applied edit to .+/, // edit application notices
/^Commit [0-9a-f]{6,}\b/, // auto-commit notices
/^You can use \/undo\b/, // undo hint after auto-commit
/^[─━-]{4,}$/, // ── / ━━ / ---- separator rules
];
function isNoiseLine(line) {
return NOISE_LINE_PATTERNS.some((pattern) => pattern.test(line));
}
/**
* Normalize a raw aider run result into `{ text, sessionId? }`.
* See the module doc for the stdout shape handled.
*/
export const aiderResultExtractor = (result) => {
const raw = result.stdout.replace(ANSI_ESCAPE_RE, "").trim();
const kept = raw
.split("\n")
.filter((line) => !isNoiseLine(line.trim()))
.join("\n")
.trim();
// Never return empty text when stdout had content: an all-noise filter
// outcome means the patterns over-matched for this capture, so fall back to
// the full trimmed stdout (downstream parsing still gets material).
const text = kept.length > 0 ? kept : raw;
// No session model (chat-history files, not ids): only a spawn-layer id
// passes through; output never supplies one.
return result.sessionId === undefined ? { text } : { text, sessionId: result.sessionId };
};