@brianlovin/notion-skills
Version:
Sync agent skills from a Notion database to Claude Code, Codex, OpenCode, Cursor, Gemini CLI.
65 lines • 2.44 kB
JavaScript
import chalk from "chalk";
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
const SPINNER_INTERVAL_MS = 80;
export function startTask(label) {
const tty = !!process.stdout.isTTY;
let interval;
if (tty) {
let frame = 0;
process.stdout.write(` ${chalk.cyan(SPINNER_FRAMES[0])} ${label}`);
interval = setInterval(() => {
frame = (frame + 1) % SPINNER_FRAMES.length;
process.stdout.write(`\r ${chalk.cyan(SPINNER_FRAMES[frame])} ${label}`);
}, SPINNER_INTERVAL_MS);
// Don't keep the event loop alive just for the spinner.
interval.unref();
}
const stop = () => {
if (interval) {
clearInterval(interval);
interval = undefined;
}
};
return {
done(note) {
stop();
const tail = note ? ` ${chalk.dim(note)}` : "";
const line = ` ${chalk.green("✓")} ${label}${tail}\n`;
process.stdout.write(tty ? `\r\x1b[2K${line}` : line);
},
fail(reason) {
stop();
const tail = reason ? ` ${chalk.dim(`(${reason})`)}` : "";
const line = ` ${chalk.red("✗")} ${label}${tail}\n`;
process.stdout.write(tty ? `\r\x1b[2K${line}` : line);
},
};
}
/**
* Wrap an async operation in a spinner. Resolves to the operation's
* return value; on failure, marks the spinner failed and rethrows so
* the caller (or top-level error handler) can decide what to do.
*
* Optional `noteFor` callback derives a one-line note shown after
* the ✓ on success — useful for "✓ Querying Skills (17 pages)"
* style outputs without forcing callers to drop down to startTask.
*
* Use this instead of static `chalk.dim("Doing thing…")` lines for
* any user-visible wait > ~500ms — Notion API calls, GitHub fetches,
* schema reconciliation. The braille spinner makes it obvious the
* tool is alive vs hung.
*/
export async function withSpinner(label, fn, options = {}) {
const task = startTask(label);
try {
const result = await fn();
task.done(options.noteFor ? options.noteFor(result) : undefined);
return result;
}
catch (err) {
const reason = err instanceof Error ? err.message.split("\n")[0] : String(err);
task.fail(reason);
throw err;
}
}
//# sourceMappingURL=_progress.js.map