openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
140 lines (139 loc) • 5.54 kB
JavaScript
import { n as splitGraphemes, s as visibleWidth } from "./ansi-DrXAcdMD.js";
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-CIXf7egm.js";
import { r as stylePromptTitle } from "./prompt-style-BQVvtDcR.js";
import { AsyncLocalStorage } from "node:async_hooks";
import { note } from "@clack/prompts";
//#region packages/terminal-core/src/note.ts
const MIN_NOTE_COLUMNS = 80;
const URL_PREFIX_RE = /^(https?:\/\/|file:\/\/)/i;
const WINDOWS_DRIVE_RE = /^[a-zA-Z]:[\\/]/;
const FILE_LIKE_RE = /^[a-zA-Z0-9._-]+$/;
const suppressNotesStorage = new AsyncLocalStorage();
function isSuppressedByEnv(value) {
if (!value) return false;
const normalized = normalizeLowercaseStringOrEmpty(value);
if (!normalized) return false;
return normalized !== "0" && normalized !== "false" && normalized !== "off";
}
function splitLongWord(word, maxLen) {
if (maxLen <= 0) return [word];
const parts = [];
let current = "";
let currentWidth = 0;
for (const grapheme of splitGraphemes(word)) {
const width = visibleWidth(grapheme);
if (current && currentWidth + width > maxLen) {
parts.push(current);
current = "";
currentWidth = 0;
}
current += grapheme;
currentWidth += width;
}
if (current) parts.push(current);
return parts.length > 0 ? parts : [word];
}
function isCopySensitiveToken(word) {
if (!word) return false;
if (URL_PREFIX_RE.test(word)) return true;
if (word.startsWith("/") || word.startsWith("~/") || word.startsWith("./") || word.startsWith("../")) return true;
if (WINDOWS_DRIVE_RE.test(word) || word.startsWith("\\\\")) return true;
if (word.includes("/") || word.includes("\\")) return true;
return word.includes("_") && FILE_LIKE_RE.test(word);
}
function pushWrappedWordSegments(params) {
const parts = splitLongWord(params.word, params.available);
const first = parts.shift() ?? "";
params.lines.push(params.firstPrefix + first);
for (const part of parts) params.lines.push(params.continuationPrefix + part);
}
function wrapLine(line, maxWidth) {
if (line.trim().length === 0) return [line];
const match = line.match(/^(\s*)([-*\u2022]\s+)?(.*)$/);
const indent = match?.[1] ?? "";
const bullet = match?.[2] ?? "";
const content = match?.[3] ?? "";
const firstPrefix = `${indent}${bullet}`;
const nextPrefix = `${indent}${bullet ? " ".repeat(bullet.length) : ""}`;
const firstWidth = Math.max(10, maxWidth - visibleWidth(firstPrefix));
const nextWidth = Math.max(10, maxWidth - visibleWidth(nextPrefix));
const isPrintableAscii = /^[\u0020-\u007E]*$/.test(content);
const words = content.split(/\s+/).filter(Boolean);
const lines = [];
let current = "";
let prefix = firstPrefix;
let available = firstWidth;
for (const word of words) {
if (current) {
const candidate = `${current} ${word}`;
if ((isPrintableAscii ? candidate.length : visibleWidth(candidate)) <= available) {
current = candidate;
continue;
}
lines.push(prefix + current);
current = "";
prefix = nextPrefix;
available = nextWidth;
}
if ((isPrintableAscii ? word.length : visibleWidth(word)) > available && !isCopySensitiveToken(word)) {
pushWrappedWordSegments({
word,
available,
firstPrefix: prefix,
continuationPrefix: nextPrefix,
lines
});
prefix = nextPrefix;
available = nextWidth;
continue;
}
current = word;
}
if (current || words.length === 0) lines.push(prefix + current);
return lines;
}
function coerceNoteMessage(message) {
if (typeof message === "string") return message;
if (message == null) return "";
if (typeof message === "number" || typeof message === "boolean" || typeof message === "bigint") return String(message);
if (message instanceof Error) return message.message ? `${message.name}: ${message.message}` : message.name;
return "";
}
function wrapNoteMessage(message, options = {}) {
const text = coerceNoteMessage(message);
const columns = options.columns ?? resolveNoteColumns(process.stdout.columns);
const maxWidth = options.maxWidth ?? Math.max(40, Math.min(88, columns - 10));
return text.split("\n").flatMap((line) => wrapLine(line, maxWidth)).join("\n");
}
function resolveNoteColumns(columns) {
if (!Number.isFinite(columns) || !columns || columns < MIN_NOTE_COLUMNS) return MIN_NOTE_COLUMNS;
return columns;
}
function resolveNoteOutputColumns(message, columns) {
const widestLine = message.split("\n").reduce((max, line) => Math.max(max, visibleWidth(line)), 0);
return Math.max(columns, widestLine + 6);
}
function createNoteOutput(output, columns) {
if (output.columns === columns) return output;
const adaptedOutput = Object.create(output);
Object.defineProperty(adaptedOutput, "columns", {
value: columns,
configurable: true
});
adaptedOutput.write = output.write.bind(output);
return adaptedOutput;
}
function noteToStream(message, title, output) {
if (suppressNotesStorage.getStore() === true || isSuppressedByEnv(process.env.OPENCLAW_SUPPRESS_NOTES)) return;
const columns = resolveNoteColumns(output.columns);
const wrappedMessage = wrapNoteMessage(message, { columns });
note(wrappedMessage, stylePromptTitle(title), { output: createNoteOutput(output, resolveNoteOutputColumns(wrappedMessage, columns)) });
}
function note$1(message, title) {
noteToStream(message, title, process.stdout);
}
function withSuppressedNotes(callback) {
return suppressNotesStorage.run(true, callback);
}
//#endregion
export { withSuppressedNotes as a, resolveNoteOutputColumns as i, noteToStream as n, wrapNoteMessage as o, resolveNoteColumns as r, note$1 as t };