UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

140 lines (139 loc) 5.54 kB
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 };