Add CLI setup and QQ webhook integration
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import readline from "node:readline/promises";
|
||||
import { stdin as input, stdout as output } from "node:process";
|
||||
|
||||
export interface PromptSession {
|
||||
ask(question: string, defaultValue?: string): Promise<string>;
|
||||
askBoolean(question: string, defaultValue?: boolean): Promise<boolean>;
|
||||
askList(question: string, defaultValues?: string[]): Promise<string[]>;
|
||||
choose<T>(question: string, choices: Choice<T>[], defaultIndex?: number): Promise<T>;
|
||||
close(): void;
|
||||
}
|
||||
|
||||
export interface Choice<T> {
|
||||
label: string;
|
||||
value: T;
|
||||
hint?: string;
|
||||
}
|
||||
|
||||
export function createPromptSession(): PromptSession {
|
||||
const rl = readline.createInterface({ input, output });
|
||||
return {
|
||||
ask: (question, defaultValue) => ask(rl, question, defaultValue),
|
||||
askBoolean: (question, defaultValue) => askBoolean(rl, question, defaultValue),
|
||||
askList: (question, defaultValues) => askList(rl, question, defaultValues),
|
||||
choose: (question, choices, defaultIndex) => choose(rl, question, choices, defaultIndex),
|
||||
close: () => rl.close()
|
||||
};
|
||||
}
|
||||
|
||||
export async function ask(rl: readline.Interface, question: string, defaultValue?: string): Promise<string> {
|
||||
const suffix = defaultValue !== undefined && defaultValue !== "" ? ` [${defaultValue}]` : "";
|
||||
const answer = (await rl.question(`${question}${suffix}: `)).trim();
|
||||
return answer || defaultValue || "";
|
||||
}
|
||||
|
||||
export async function askBoolean(rl: readline.Interface, question: string, defaultValue = false): Promise<boolean> {
|
||||
const suffix = defaultValue ? " [Y/n]" : " [y/N]";
|
||||
for (;;) {
|
||||
const answer = (await rl.question(`${question}${suffix}: `)).trim().toLowerCase();
|
||||
if (!answer) return defaultValue;
|
||||
if (["y", "yes"].includes(answer)) return true;
|
||||
if (["n", "no"].includes(answer)) return false;
|
||||
console.log("Please answer yes or no.");
|
||||
}
|
||||
}
|
||||
|
||||
export async function askList(rl: readline.Interface, question: string, defaultValues: string[] = []): Promise<string[]> {
|
||||
const answer = await ask(rl, question, defaultValues.join(","));
|
||||
return answer.split(",").map((value) => value.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
export async function choose<T>(
|
||||
rl: readline.Interface,
|
||||
question: string,
|
||||
choices: Choice<T>[],
|
||||
defaultIndex = 0
|
||||
): Promise<T> {
|
||||
if (choices.length === 0) throw new Error("No choices available");
|
||||
|
||||
console.log(question);
|
||||
choices.forEach((choice, index) => {
|
||||
const marker = index === defaultIndex ? "*" : " ";
|
||||
const hint = choice.hint ? ` - ${choice.hint}` : "";
|
||||
console.log(` ${marker} ${index + 1}) ${choice.label}${hint}`);
|
||||
});
|
||||
|
||||
for (;;) {
|
||||
const answer = (await rl.question(`Choose 1-${choices.length} [${defaultIndex + 1}]: `)).trim();
|
||||
if (!answer) return choices[defaultIndex]?.value ?? choices[0].value;
|
||||
const index = Number(answer) - 1;
|
||||
if (Number.isInteger(index) && choices[index]) return choices[index].value;
|
||||
console.log(`Please enter a number from 1 to ${choices.length}.`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user