openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
544 lines (543 loc) • 27.1 kB
JavaScript
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-1VuiLaaR.mjs";
import "./src-CdRlGRnW.mjs";
import { t as expectDefined } from "./expect-lbe3Hgrh.mjs";
import { i as stripAnsi } from "./ansi-BeFJ0Uu7.mjs";
import { n as isRich, r as theme } from "./theme-DzaUZY4q.mjs";
import { n as stylePromptMessage, r as stylePromptTitle } from "./prompt-style-zarsDmI2.mjs";
import { n as noteToStream } from "./note-Byxgt4MB.mjs";
import { n as WizardCancelledError, r as WizardNavigationError } from "./prompts-DLsO8MlU.mjs";
import { n as createProgressSpinner, t as createCliProgress } from "./progress-UTM8yfZa.mjs";
import { t as styleSelectParams } from "./prompt-select-styled-params-DiyhlGNl.mjs";
import { styleText } from "node:util";
import { CANCEL_SYMBOL, S_BAR, S_BAR_END, S_CHECKBOX_ACTIVE, S_CHECKBOX_INACTIVE, S_CHECKBOX_SELECTED, S_PASSWORD_MASK, S_RADIO_ACTIVE, S_RADIO_INACTIVE, autocomplete, autocompleteMultiselect, cancel, confirm, intro, limitOptions, multiselect, outro, password, select, settings, symbol, symbolBar, text } from "@clack/prompts";
import { AutocompletePrompt, ConfirmPrompt, MultiSelectPrompt, PasswordPrompt, SelectPrompt, TextPrompt, settings as settings$1, wrapTextWithPrefix } from "@clack/core";
//#region src/wizard/clack-navigation-prompts.ts
function getOptionLabel(option) {
return option.label ?? String(option.value ?? "");
}
function computeLabel(label, format) {
return label.split("\n").map(format).join("\n");
}
function getFilteredOption(searchText, option) {
if (!searchText) return true;
const term = searchText.toLowerCase();
return getOptionLabel(option).toLowerCase().includes(term) || (option.hint ?? "").toLowerCase().includes(term) || String(option.value).toLowerCase().includes(term);
}
function formatNavigationFooter(navigation) {
if (!navigation || !navigation.canGoBack && !navigation.canGoForward) return "";
return [navigation.canGoBack ? styleText("dim", "← back") : void 0, navigation.canGoForward ? styleText("dim", "→ next") : void 0].filter(Boolean).join(" ");
}
function navigationFooterLines(guideVisible, barStyle, navigation, extraHints = []) {
const footer = formatNavigationFooter(navigation);
if (!footer) return [];
const hintLine = [footer, ...extraHints].join(" ");
return [`${guideVisible ? `${styleText(barStyle, S_BAR)} ` : ""}${hintLine}`];
}
function hasGuide(opts) {
return opts.withGuide ?? settings$1.withGuide;
}
function selectOptionRenderer(option, state) {
const label = getOptionLabel(option);
switch (state) {
case "disabled": return `${styleText("gray", S_RADIO_INACTIVE)} ${computeLabel(label, (text) => styleText("gray", text))}${option.hint ? ` ${styleText("dim", `(${option.hint})`)}` : ""}`;
case "selected": return computeLabel(label, (text) => styleText("dim", text));
case "active": return `${styleText("green", S_RADIO_ACTIVE)} ${label}${option.hint ? ` ${styleText("dim", `(${option.hint})`)}` : ""}`;
case "cancelled": return computeLabel(label, (text) => styleText(["strikethrough", "dim"], text));
default: return `${styleText("dim", S_RADIO_INACTIVE)} ${computeLabel(label, (text) => styleText("dim", text))}`;
}
}
function selectWithNavigationFooter(opts) {
return new SelectPrompt({
options: opts.options,
signal: opts.signal,
input: opts.input,
output: opts.output,
initialValue: opts.initialValue,
render() {
const showGuide = hasGuide(opts);
const titlePrefix = `${symbol(this.state)} `;
const titlePrefixBar = `${symbolBar(this.state)} `;
const messageLines = wrapTextWithPrefix(opts.output, opts.message, titlePrefixBar, titlePrefix);
const title = `${showGuide ? `${styleText("gray", S_BAR)}\n` : ""}${messageLines}\n`;
switch (this.state) {
case "submit":
case "cancel": {
const cancelled = this.state === "cancel";
const prefix = showGuide ? `${styleText("gray", S_BAR)} ` : "";
return `${title}${wrapTextWithPrefix(opts.output, selectOptionRenderer(expectDefined(this.options[this.cursor], "options entry at this.cursor"), cancelled ? "cancelled" : "selected"), prefix)}${cancelled && showGuide ? `\n${styleText("gray", S_BAR)}` : ""}`;
}
default: {
const prefix = showGuide ? `${styleText("cyan", S_BAR)} ` : "";
const footerLines = [...navigationFooterLines(showGuide, "cyan", opts.navigation, [styleText("dim", "↑/↓ option")]), showGuide ? styleText("cyan", S_BAR_END) : ""];
const titleLineCount = title.split("\n").length;
const footerLineCount = footerLines.length + 1;
return `${title}${prefix}${limitOptions({
output: opts.output,
cursor: this.cursor,
options: this.options,
maxItems: opts.maxItems,
columnPadding: prefix.length,
rowPadding: titleLineCount + footerLineCount,
style: (item, active) => selectOptionRenderer(item, item.disabled ? "disabled" : active ? "active" : "inactive")
}).join(`\n${prefix}`)}\n${footerLines.join("\n")}\n`;
}
}
}
}).prompt();
}
function renderAutocompleteOption(prompt, option, active) {
const label = getOptionLabel(option);
const hint = option.hint && option.value === prompt.focusedValue && (!prompt.multiple || prompt.focusedValue !== void 0) ? styleText("dim", ` (${option.hint})`) : "";
const inactiveSymbol = prompt.multiple ? S_CHECKBOX_INACTIVE : S_RADIO_INACTIVE;
if (option.disabled) return `${styleText("gray", inactiveSymbol)} ${styleText(["strikethrough", "gray"], label)}`;
return `${prompt.multiple && prompt.selectedValues.includes(option.value) ? styleText("green", S_CHECKBOX_SELECTED) : active && !prompt.multiple ? styleText("green", S_RADIO_ACTIVE) : styleText("dim", inactiveSymbol)} ${active ? `${label}${hint}` : styleText("dim", label)}`;
}
function renderAutocomplete(prompt, opts) {
const showGuide = hasGuide(opts);
const headings = [...showGuide ? [styleText("gray", S_BAR)] : [], `${symbol(prompt.state)} ${opts.message}`];
const title = `${headings.join("\n")}\n`;
const userInput = prompt.userInput;
if (prompt.state === "submit") {
if (prompt.multiple) return `${title}${showGuide ? `${styleText("gray", S_BAR)} ` : ""}${styleText("dim", `${prompt.selectedValues.length} items selected`)}`;
const selected = prompt.options.filter((option) => prompt.selectedValues.includes(option.value));
const label = selected.length > 0 ? ` ${styleText("dim", selected.map(getOptionLabel).join(", "))}` : "";
return `${title}${showGuide ? styleText("gray", S_BAR) : ""}${label}`;
}
if (prompt.state === "cancel") {
if (prompt.multiple) return `${title}${showGuide ? `${styleText("gray", S_BAR)} ` : ""}${styleText(["strikethrough", "dim"], userInput)}`;
const input = userInput ? ` ${styleText(["strikethrough", "dim"], userInput)}` : "";
return `${title}${showGuide ? styleText("gray", S_BAR) : ""}${input}`;
}
const barStyle = prompt.state === "error" ? "yellow" : "cyan";
const guidePrefix = showGuide ? `${styleText(barStyle, S_BAR)} ` : "";
const showPlaceholder = userInput === "" && opts.placeholder !== void 0;
const searchText = prompt.isNavigating || showPlaceholder ? styleText("dim", showPlaceholder ? opts.placeholder ?? "" : userInput) : prompt.userInputWithCursor;
if (showGuide || prompt.multiple) headings.push(showGuide ? styleText(barStyle, S_BAR) : "");
const searchSuffix = prompt.multiple || !(prompt.isNavigating || showPlaceholder) || opts.placeholder || userInput ? ` ${searchText}` : "";
const matches = prompt.filteredOptions.length !== prompt.options.length ? styleText("dim", ` (${prompt.filteredOptions.length} match${prompt.filteredOptions.length === 1 ? "" : "es"})`) : "";
headings.push(`${guidePrefix}${styleText("dim", "Search:")}${searchSuffix}${matches}`);
if (prompt.filteredOptions.length === 0 && userInput) headings.push(`${guidePrefix}${styleText("yellow", "No matches found")}`);
if (prompt.state === "error") headings.push(`${guidePrefix}${styleText("yellow", prompt.error)}`);
const footers = [
`${guidePrefix}${[
`${styleText("dim", "↑/↓")} to ${prompt.multiple ? "navigate" : "select"}`,
...prompt.multiple ? [`${styleText("dim", prompt.isNavigating ? "Space/Tab:" : "Tab:")} select`] : [],
`${styleText("dim", "Enter:")} confirm`,
`${styleText("dim", "Type:")} to search`
].join(" • ")}`,
...navigationFooterLines(showGuide, barStyle, opts.navigation),
showGuide ? styleText(barStyle, S_BAR_END) : ""
];
const displayOptions = !prompt.multiple && prompt.filteredOptions.length === 0 ? [] : limitOptions({
cursor: prompt.cursor,
options: prompt.filteredOptions,
...!prompt.multiple ? { columnPadding: showGuide ? 3 : 0 } : {},
rowPadding: headings.length + footers.length,
style: (option, active) => renderAutocompleteOption(prompt, option, active),
maxItems: opts.maxItems,
output: opts.output
});
return [
...headings,
...displayOptions.map((option) => `${guidePrefix}${option}`),
...footers
].join("\n");
}
function autocompleteWithNavigationFooter(opts) {
return new AutocompletePrompt({
options: opts.options,
initialValue: opts.initialValue === void 0 ? void 0 : [opts.initialValue],
initialUserInput: opts.initialUserInput,
placeholder: opts.placeholder,
filter: opts.filter ?? getFilteredOption,
signal: opts.signal,
input: opts.input,
output: opts.output,
validate: opts.validate,
render() {
return renderAutocomplete(this, opts);
}
}).prompt();
}
function textWithNavigationFooter(opts) {
return new TextPrompt({
validate: opts.validate,
placeholder: opts.placeholder,
defaultValue: opts.defaultValue,
initialValue: opts.initialValue,
output: opts.output,
signal: opts.signal,
input: opts.input,
render() {
const showGuide = hasGuide(opts);
const title = `${`${showGuide ? `${styleText("gray", S_BAR)}\n` : ""}${symbol(this.state)} `}${opts.message}\n`;
const placeholder = opts.placeholder ? styleText("inverse", opts.placeholder[0] ?? "") + styleText("dim", opts.placeholder.slice(1)) : styleText(["inverse", "hidden"], "_");
const userInput = !this.userInput ? placeholder : this.userInputWithCursor;
const value = this.value ?? "";
switch (this.state) {
case "error": {
const errorText = this.error ? ` ${styleText("yellow", this.error)}` : "";
const errorPrefix = showGuide ? `${styleText("yellow", S_BAR)} ` : "";
const errorPrefixEnd = showGuide ? styleText("yellow", S_BAR_END) : "";
const footerLines = navigationFooterLines(showGuide, "yellow", opts.navigation);
return `${title.trim()}\n${errorPrefix}${userInput}\n${footerLines.length ? `${footerLines.join("\n")}\n` : ""}${errorPrefixEnd}${errorText}\n`;
}
case "submit": {
const valueText = value ? ` ${styleText("dim", value)}` : "";
return `${title}${showGuide ? styleText("gray", S_BAR) : ""}${valueText}`;
}
case "cancel": {
const valueText = value ? ` ${styleText(["strikethrough", "dim"], value)}` : "";
const cancelPrefix = showGuide ? styleText("gray", S_BAR) : "";
return `${title}${cancelPrefix}${valueText}${value.trim() ? `\n${cancelPrefix}` : ""}`;
}
default: {
const defaultPrefix = showGuide ? `${styleText("cyan", S_BAR)} ` : "";
const defaultPrefixEnd = showGuide ? styleText("cyan", S_BAR_END) : "";
const footerLines = navigationFooterLines(showGuide, "cyan", opts.navigation);
return `${title}${defaultPrefix}${userInput}\n${footerLines.length ? `${footerLines.join("\n")}\n` : ""}${defaultPrefixEnd}\n`;
}
}
}
}).prompt();
}
function passwordWithNavigationFooter(opts) {
return new PasswordPrompt({
validate: opts.validate,
mask: opts.mask ?? S_PASSWORD_MASK,
signal: opts.signal,
input: opts.input,
output: opts.output,
render() {
const showGuide = hasGuide(opts);
const title = `${showGuide ? `${styleText("gray", S_BAR)}\n` : ""}${symbol(this.state)} ${opts.message}\n`;
const userInput = this.userInputWithCursor;
const masked = this.masked;
switch (this.state) {
case "error": {
const errorPrefix = showGuide ? `${styleText("yellow", S_BAR)} ` : "";
const errorPrefixEnd = showGuide ? `${styleText("yellow", S_BAR_END)} ` : "";
const maskedText = masked ?? "";
if (opts.clearOnError) this.clear();
const footerLines = navigationFooterLines(showGuide, "yellow", opts.navigation);
return `${title.trim()}\n${errorPrefix}${maskedText}\n${footerLines.length ? `${footerLines.join("\n")}\n` : ""}${errorPrefixEnd}${styleText("yellow", this.error)}\n`;
}
case "submit": return `${title}${showGuide ? `${styleText("gray", S_BAR)} ` : ""}${masked ? styleText("dim", masked) : ""}`;
case "cancel": return `${title}${showGuide ? `${styleText("gray", S_BAR)} ` : ""}${masked ? styleText(["strikethrough", "dim"], masked) : ""}${masked && showGuide ? `\n${styleText("gray", S_BAR)}` : ""}`;
default: {
const defaultPrefix = showGuide ? `${styleText("cyan", S_BAR)} ` : "";
const defaultPrefixEnd = showGuide ? styleText("cyan", S_BAR_END) : "";
const footerLines = navigationFooterLines(showGuide, "cyan", opts.navigation);
return `${title}${defaultPrefix}${userInput}\n${footerLines.length ? `${footerLines.join("\n")}\n` : ""}${defaultPrefixEnd}\n`;
}
}
}
}).prompt();
}
function multiselectOptionRenderer(option, state) {
const label = getOptionLabel(option);
if (state === "disabled") return `${styleText("gray", S_CHECKBOX_INACTIVE)} ${computeLabel(label, (str) => styleText(["strikethrough", "gray"], str))}${option.hint ? ` ${styleText("dim", `(${option.hint})`)}` : ""}`;
if (state === "active") return `${styleText("cyan", S_CHECKBOX_ACTIVE)} ${label}${option.hint ? ` ${styleText("dim", `(${option.hint})`)}` : ""}`;
if (state === "selected") return `${styleText("green", S_CHECKBOX_SELECTED)} ${computeLabel(label, (text) => styleText("dim", text))}${option.hint ? ` ${styleText("dim", `(${option.hint})`)}` : ""}`;
if (state === "cancelled") return computeLabel(label, (text) => styleText(["strikethrough", "dim"], text));
if (state === "active-selected") return `${styleText("green", S_CHECKBOX_SELECTED)} ${label}${option.hint ? ` ${styleText("dim", `(${option.hint})`)}` : ""}`;
if (state === "submitted") return computeLabel(label, (text) => styleText("dim", text));
return `${styleText("dim", S_CHECKBOX_INACTIVE)} ${computeLabel(label, (text) => styleText("dim", text))}`;
}
function multiselectWithNavigationFooter(opts) {
const required = opts.required ?? true;
return new MultiSelectPrompt({
options: opts.options,
signal: opts.signal,
input: opts.input,
output: opts.output,
initialValues: opts.initialValues,
cursorAt: opts.cursorAt,
validate(selected) {
if (required && (selected === void 0 || selected.length === 0)) return `Please select at least one option.\n${styleText("reset", styleText("dim", `Press ${styleText([
"gray",
"bgWhite",
"inverse"
], " space ")} to select, ${styleText("gray", styleText("bgWhite", styleText("inverse", " enter ")))} to submit`))}`;
},
render() {
const showGuide = hasGuide(opts);
const wrappedMessage = wrapTextWithPrefix(opts.output, opts.message, showGuide ? `${symbolBar(this.state)} ` : "", `${symbol(this.state)} `);
const title = `${showGuide ? `${styleText("gray", S_BAR)}\n` : ""}${wrappedMessage}\n`;
const value = this.value ?? [];
const styleOption = (option, active) => {
if (option.disabled) return multiselectOptionRenderer(option, "disabled");
const selected = value.includes(option.value);
if (active && selected) return multiselectOptionRenderer(option, "active-selected");
if (selected) return multiselectOptionRenderer(option, "selected");
return multiselectOptionRenderer(option, active ? "active" : "inactive");
};
switch (this.state) {
case "submit": {
const submitText = this.options.filter(({ value: optionValue }) => value.includes(optionValue)).map((option) => multiselectOptionRenderer(option, "submitted")).join(styleText("dim", ", ")) || styleText("dim", "none");
return `${title}${wrapTextWithPrefix(opts.output, submitText, showGuide ? `${styleText("gray", S_BAR)} ` : "")}`;
}
case "cancel": {
const label = this.options.filter(({ value: optionValue }) => value.includes(optionValue)).map((option) => multiselectOptionRenderer(option, "cancelled")).join(styleText("dim", ", "));
if (label.trim() === "") return `${title}${styleText("gray", S_BAR)}`;
return `${title}${wrapTextWithPrefix(opts.output, label, showGuide ? `${styleText("gray", S_BAR)} ` : "")}${showGuide ? `\n${styleText("gray", S_BAR)}` : ""}`;
}
default: {
const barStyle = this.state === "error" ? "yellow" : "cyan";
const prefix = showGuide ? `${styleText(barStyle, S_BAR)} ` : "";
const footerLines = this.state === "error" ? this.error.split("\n").map((line, index) => index === 0 ? `${showGuide ? `${styleText("yellow", S_BAR_END)} ` : ""}${styleText("yellow", line)}` : ` ${line}`) : [...navigationFooterLines(showGuide, "cyan", opts.navigation, [styleText("dim", "↑/↓ option"), styleText("dim", "space select")]), showGuide ? styleText("cyan", S_BAR_END) : ""];
const titleLineCount = title.split("\n").length;
const footerLineCount = footerLines.length + 1;
return `${title}${prefix}${limitOptions({
output: opts.output,
options: this.options,
cursor: this.cursor,
maxItems: opts.maxItems,
columnPadding: prefix.length,
rowPadding: titleLineCount + footerLineCount,
style: styleOption
}).join(`\n${prefix}`)}\n${footerLines.join("\n")}\n`;
}
}
}
}).prompt();
}
function autocompleteMultiselectWithNavigationFooter(opts) {
const prompt = new AutocompletePrompt({
options: opts.options,
multiple: true,
placeholder: opts.placeholder,
filter: opts.filter ?? getFilteredOption,
validate: () => {
if (opts.required && prompt.selectedValues.length === 0) return "Please select at least one item";
},
initialValue: opts.initialValues,
signal: opts.signal,
input: opts.input,
output: opts.output,
render() {
return renderAutocomplete(this, opts);
}
});
return prompt.prompt();
}
function confirmWithNavigationFooter(opts) {
const active = opts.active ?? "Yes";
const inactive = opts.inactive ?? "No";
return new ConfirmPrompt({
active,
inactive,
signal: opts.signal,
input: opts.input,
output: opts.output,
initialValue: opts.initialValue ?? true,
render() {
const showGuide = hasGuide(opts);
const titlePrefix = `${symbol(this.state)} `;
const titlePrefixBar = showGuide ? `${styleText("gray", S_BAR)} ` : "";
const messageLines = wrapTextWithPrefix(opts.output, opts.message, titlePrefixBar, titlePrefix);
const title = `${showGuide ? `${styleText("gray", S_BAR)}\n` : ""}${messageLines}\n`;
const value = this.value ? active : inactive;
switch (this.state) {
case "submit": return `${title}${showGuide ? `${styleText("gray", S_BAR)} ` : ""}${styleText("dim", value)}`;
case "cancel": return `${title}${showGuide ? `${styleText("gray", S_BAR)} ` : ""}${styleText(["strikethrough", "dim"], value)}${showGuide ? `\n${styleText("gray", S_BAR)}` : ""}`;
default: {
const defaultPrefix = showGuide ? `${styleText("cyan", S_BAR)} ` : "";
const defaultPrefixEnd = showGuide ? styleText("cyan", S_BAR_END) : "";
const separator = opts.vertical ? showGuide ? `\n${styleText("cyan", S_BAR)} ` : "\n" : ` ${styleText("dim", "/")} `;
const footerLines = navigationFooterLines(showGuide, "cyan", opts.navigation, [styleText("dim", "↑/↓ option")]);
return `${title}${defaultPrefix}${this.value ? `${styleText("green", S_RADIO_ACTIVE)} ${active}` : `${styleText("dim", S_RADIO_INACTIVE)} ${styleText("dim", active)}`}${separator}${!this.value ? `${styleText("green", S_RADIO_ACTIVE)} ${inactive}` : `${styleText("dim", S_RADIO_INACTIVE)} ${styleText("dim", inactive)}`}\n${footerLines.length > 0 ? `${footerLines.join("\n")}\n` : ""}${defaultPrefixEnd}\n`;
}
}
}
}).prompt();
}
//#endregion
//#region src/wizard/clack-prompter.ts
const CLAW_SPINNER_FRAMES = [
"(\\/)",
"(||)",
"(--)",
"(||)"
];
function guardCancel(value, output, signal) {
if (value === CANCEL_SYMBOL) {
if (!signal?.aborted) cancel(stylePromptTitle("Setup cancelled.") ?? "Setup cancelled.", { output });
throw new WizardCancelledError();
}
return value;
}
function resolveNavigationDirection(navigation, key) {
if (key?.name === "left" && navigation?.canGoBack) return "back";
if (key?.name === "right" && navigation?.canGoForward) return "forward";
}
function hasPromptNavigation(navigation) {
return navigation?.canGoBack === true || navigation?.canGoForward === true;
}
async function withHorizontalCursorActionsDisabled(disabled, work) {
if (!disabled) return await work();
const hadLeft = settings.actions.has("left");
const hadRight = settings.actions.has("right");
settings.actions.delete("left");
settings.actions.delete("right");
try {
return await work();
} finally {
if (hadLeft) settings.actions.add("left");
if (hadRight) settings.actions.add("right");
}
}
async function runPromptWithNavigation(navigation, work, output, externalSignal) {
return await withHorizontalCursorActionsDisabled(hasPromptNavigation(navigation), async () => {
const controller = new AbortController();
const signal = externalSignal ? AbortSignal.any([controller.signal, externalSignal]) : controller.signal;
let navigationDirection;
let promptSettled = false;
let cancellationImmediate;
const queueCancellation = () => {
if (cancellationImmediate || signal.aborted || navigationDirection) return;
cancellationImmediate = setImmediate(() => {
cancellationImmediate = void 0;
if (!promptSettled && !signal.aborted && !navigationDirection) controller.abort();
});
};
const onKeypress = (input, key) => {
if (input === "" || key?.ctrl === true && key.name === "d") {
queueCancellation();
return;
}
const nextDirection = resolveNavigationDirection(navigation, key);
if (!nextDirection) return;
navigationDirection ??= nextDirection;
controller.abort();
};
try {
process.stdin.once("end", queueCancellation);
if (process.stdin.readableEnded) queueCancellation();
process.stdin.on("keypress", onKeypress);
const value = await work(signal).finally(() => {
promptSettled = true;
});
if (navigationDirection) throw new WizardNavigationError(navigationDirection);
return guardCancel(value, output, externalSignal);
} finally {
if (cancellationImmediate) {
clearImmediate(cancellationImmediate);
cancellationImmediate = void 0;
}
process.stdin.off("end", queueCancellation);
process.stdin.off("keypress", onKeypress);
}
});
}
function tokenizedOptionFilter(search, option) {
const tokens = normalizeLowercaseStringOrEmpty(search).split(/\s+/).filter((token) => token.length > 0);
if (tokens.length === 0) return true;
const label = stripAnsi(option.label ?? "");
const hint = stripAnsi(option.hint ?? "");
const value = String(option.value ?? "");
const haystack = normalizeLowercaseStringOrEmpty(`${label} ${hint} ${value}`);
return tokens.every((token) => haystack.includes(token));
}
function createClackPrompter(output = process.stdout, signal) {
return {
intro: async (title) => {
intro(stylePromptTitle(title) ?? title, { output });
},
outro: async (message) => {
outro(stylePromptTitle(message) ?? message, { output });
},
note: async (message, title) => {
noteToStream(message, title, output);
},
plain: async (message) => {
output.write(message.endsWith("\n") ? message : `${message}\n`);
},
select: async (params) => {
const { message, options: styledOptions } = styleSelectParams(params);
const options = styledOptions;
return await runPromptWithNavigation(params.navigation, async (promptSignal) => {
return await (params.searchable ? params.navigation ? autocompleteWithNavigationFooter : autocomplete : params.navigation ? selectWithNavigationFooter : select)({
message,
options,
initialValue: params.initialValue,
...params.searchable ? { filter: tokenizedOptionFilter } : {},
signal: promptSignal,
...params.navigation ? { navigation: params.navigation } : {},
output
});
}, output, signal);
},
multiselect: async (params) => {
const { message, options: styledOptions } = styleSelectParams(params);
const options = styledOptions;
return await runPromptWithNavigation(params.navigation, async (promptSignal) => {
return await (params.searchable ? params.navigation ? autocompleteMultiselectWithNavigationFooter : autocompleteMultiselect : params.navigation ? multiselectWithNavigationFooter : multiselect)({
message,
options,
initialValues: params.initialValues,
...params.searchable ? { filter: tokenizedOptionFilter } : {},
signal: promptSignal,
...params.navigation ? { navigation: params.navigation } : {},
output
});
}, output, signal);
},
text: async (params) => {
return await runPromptWithNavigation(params.navigation, async (promptSignal) => {
const validate = params.validate;
return await (params.sensitive ? params.navigation ? passwordWithNavigationFooter : password : params.navigation ? textWithNavigationFooter : text)({
message: stylePromptMessage(params.message),
...!params.sensitive ? {
initialValue: params.initialValue,
placeholder: params.placeholder
} : {},
validate: validate ? (value) => validate(value ?? "") : void 0,
...params.navigation ? { navigation: params.navigation } : {},
signal: promptSignal,
output
});
}, output, params.signal && signal ? AbortSignal.any([params.signal, signal]) : params.signal ?? signal);
},
confirm: async (params) => await runPromptWithNavigation(params.navigation, async (promptSignal) => {
const message = stylePromptMessage(params.message);
return await (params.navigation ? confirmWithNavigationFooter : confirm)({
message,
initialValue: params.initialValue,
vertical: params.layout === "vertical",
...params.navigation ? { navigation: params.navigation } : {},
signal: promptSignal,
output
});
}, output, signal),
progress: (label) => {
const useClawSpinner = output.isTTY && isRich() && !process.env.CI && !process.env.VITEST;
const spin = createProgressSpinner(useClawSpinner ? {
frames: CLAW_SPINNER_FRAMES,
delay: 120,
styleFrame: theme.accent,
output
} : { output }, 10);
spin.start(label);
const osc = createCliProgress({
label,
indeterminate: true,
enabled: true,
fallback: "none",
stream: output
});
return {
update: (message) => {
spin.message(message);
osc.setLabel(message);
},
stop: (message) => {
osc.done();
spin.stop(message);
}
};
}
};
}
//#endregion
export { tokenizedOptionFilter as n, createClackPrompter as t };