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
49 lines (48 loc) • 2.26 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 ESC = "\u001B";
const BEL = "\u0007";
/**
* Matches ANSI CSI sequences (colors, cursor movement, erase-line) and OSC
* sequences (title, hyperlink) terminated by BEL or ST. Built via the RegExp
* constructor so the control characters live in named string constants
* instead of regex-literal escapes.
*/
const ANSI_SEQUENCE = new RegExp(`${ESC}\\[[0-9;?]*[ -/]*[@-~]` + `|${ESC}\\][^${BEL}${ESC}]*(?:${BEL}|${ESC}\\\\)`, "g");
/**
* Resolve carriage-return overwrites within one physical line: a terminal
* would redraw from column 0 at each `\r`, so only the segment after the last
* `\r` survives (spinner frames like "⠋ Thinking..." disappear exactly as
* they do on screen). A trailing bare `\r` (CRLF line endings) is handled by
* splitting on `\r?\n` before this runs.
*/
function resolveCarriageReturns(line) {
const lastCr = line.lastIndexOf("\r");
return lastCr === -1 ? line : line.slice(lastCr + 1);
}
/** Strip terminal framing from raw captured stdout. See module doc, rule 1. */
export function stripTerminalFraming(raw) {
const lines = raw.split(/\r?\n/).map((line) => resolveCarriageReturns(line).replace(ANSI_SEQUENCE, ""));
// Drop Q's "> " response marker from the first non-empty line only — deeper
// occurrences may be legitimate content (markdown blockquotes).
for (let i = 0; i < lines.length; i++) {
const line = lines[i] ?? "";
if (line.trim().length === 0)
continue;
if (line.startsWith("> "))
lines[i] = line.slice(2);
break;
}
return lines.join("\n").trim();
}
/**
* Normalize a raw Amazon Q run result into `{ text, sessionId? }`.
* See the module doc for the rules.
*/
export const amazonqResultExtractor = (result) => {
const sessionId = result.sessionId;
// Rule 2: a pre-parsed whole-stdout JSON *string* is the answer itself.
const text = typeof result.parsed === "string" ? result.parsed.trim() : stripTerminalFraming(result.stdout);
return { text, ...(sessionId ? { sessionId } : {}) };
};