@every-env/cctime
Version:
Claude Code Transcript Time Analyzer - Analyze response times from claude.ai transcripts
2,370 lines (2,362 loc) • 147 kB
JavaScript
#!/usr/bin/env node
import { createRequire } from "node:module";
var __create = Object.create;
var __getProtoOf = Object.getPrototypeOf;
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __toESM = (mod, isNodeMode, target) => {
target = mod != null ? __create(__getProtoOf(mod)) : {};
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
for (let key of __getOwnPropNames(mod))
if (!__hasOwnProp.call(to, key))
__defProp(to, key, {
get: () => mod[key],
enumerable: true
});
return to;
};
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
var __require = /* @__PURE__ */ createRequire(import.meta.url);
// node_modules/cli-spinners/spinners.json
var require_spinners = __commonJS((exports, module) => {
module.exports = {
dots: {
interval: 80,
frames: [
"⠋",
"⠙",
"⠹",
"⠸",
"⠼",
"⠴",
"⠦",
"⠧",
"⠇",
"⠏"
]
},
dots2: {
interval: 80,
frames: [
"⣾",
"⣽",
"⣻",
"⢿",
"⡿",
"⣟",
"⣯",
"⣷"
]
},
dots3: {
interval: 80,
frames: [
"⠋",
"⠙",
"⠚",
"⠞",
"⠖",
"⠦",
"⠴",
"⠲",
"⠳",
"⠓"
]
},
dots4: {
interval: 80,
frames: [
"⠄",
"⠆",
"⠇",
"⠋",
"⠙",
"⠸",
"⠰",
"⠠",
"⠰",
"⠸",
"⠙",
"⠋",
"⠇",
"⠆"
]
},
dots5: {
interval: 80,
frames: [
"⠋",
"⠙",
"⠚",
"⠒",
"⠂",
"⠂",
"⠒",
"⠲",
"⠴",
"⠦",
"⠖",
"⠒",
"⠐",
"⠐",
"⠒",
"⠓",
"⠋"
]
},
dots6: {
interval: 80,
frames: [
"⠁",
"⠉",
"⠙",
"⠚",
"⠒",
"⠂",
"⠂",
"⠒",
"⠲",
"⠴",
"⠤",
"⠄",
"⠄",
"⠤",
"⠴",
"⠲",
"⠒",
"⠂",
"⠂",
"⠒",
"⠚",
"⠙",
"⠉",
"⠁"
]
},
dots7: {
interval: 80,
frames: [
"⠈",
"⠉",
"⠋",
"⠓",
"⠒",
"⠐",
"⠐",
"⠒",
"⠖",
"⠦",
"⠤",
"⠠",
"⠠",
"⠤",
"⠦",
"⠖",
"⠒",
"⠐",
"⠐",
"⠒",
"⠓",
"⠋",
"⠉",
"⠈"
]
},
dots8: {
interval: 80,
frames: [
"⠁",
"⠁",
"⠉",
"⠙",
"⠚",
"⠒",
"⠂",
"⠂",
"⠒",
"⠲",
"⠴",
"⠤",
"⠄",
"⠄",
"⠤",
"⠠",
"⠠",
"⠤",
"⠦",
"⠖",
"⠒",
"⠐",
"⠐",
"⠒",
"⠓",
"⠋",
"⠉",
"⠈",
"⠈"
]
},
dots9: {
interval: 80,
frames: [
"⢹",
"⢺",
"⢼",
"⣸",
"⣇",
"⡧",
"⡗",
"⡏"
]
},
dots10: {
interval: 80,
frames: [
"⢄",
"⢂",
"⢁",
"⡁",
"⡈",
"⡐",
"⡠"
]
},
dots11: {
interval: 100,
frames: [
"⠁",
"⠂",
"⠄",
"⡀",
"⢀",
"⠠",
"⠐",
"⠈"
]
},
dots12: {
interval: 80,
frames: [
"⢀⠀",
"⡀⠀",
"⠄⠀",
"⢂⠀",
"⡂⠀",
"⠅⠀",
"⢃⠀",
"⡃⠀",
"⠍⠀",
"⢋⠀",
"⡋⠀",
"⠍⠁",
"⢋⠁",
"⡋⠁",
"⠍⠉",
"⠋⠉",
"⠋⠉",
"⠉⠙",
"⠉⠙",
"⠉⠩",
"⠈⢙",
"⠈⡙",
"⢈⠩",
"⡀⢙",
"⠄⡙",
"⢂⠩",
"⡂⢘",
"⠅⡘",
"⢃⠨",
"⡃⢐",
"⠍⡐",
"⢋⠠",
"⡋⢀",
"⠍⡁",
"⢋⠁",
"⡋⠁",
"⠍⠉",
"⠋⠉",
"⠋⠉",
"⠉⠙",
"⠉⠙",
"⠉⠩",
"⠈⢙",
"⠈⡙",
"⠈⠩",
"⠀⢙",
"⠀⡙",
"⠀⠩",
"⠀⢘",
"⠀⡘",
"⠀⠨",
"⠀⢐",
"⠀⡐",
"⠀⠠",
"⠀⢀",
"⠀⡀"
]
},
dots13: {
interval: 80,
frames: [
"⣼",
"⣹",
"⢻",
"⠿",
"⡟",
"⣏",
"⣧",
"⣶"
]
},
dots8Bit: {
interval: 80,
frames: [
"⠀",
"⠁",
"⠂",
"⠃",
"⠄",
"⠅",
"⠆",
"⠇",
"⡀",
"⡁",
"⡂",
"⡃",
"⡄",
"⡅",
"⡆",
"⡇",
"⠈",
"⠉",
"⠊",
"⠋",
"⠌",
"⠍",
"⠎",
"⠏",
"⡈",
"⡉",
"⡊",
"⡋",
"⡌",
"⡍",
"⡎",
"⡏",
"⠐",
"⠑",
"⠒",
"⠓",
"⠔",
"⠕",
"⠖",
"⠗",
"⡐",
"⡑",
"⡒",
"⡓",
"⡔",
"⡕",
"⡖",
"⡗",
"⠘",
"⠙",
"⠚",
"⠛",
"⠜",
"⠝",
"⠞",
"⠟",
"⡘",
"⡙",
"⡚",
"⡛",
"⡜",
"⡝",
"⡞",
"⡟",
"⠠",
"⠡",
"⠢",
"⠣",
"⠤",
"⠥",
"⠦",
"⠧",
"⡠",
"⡡",
"⡢",
"⡣",
"⡤",
"⡥",
"⡦",
"⡧",
"⠨",
"⠩",
"⠪",
"⠫",
"⠬",
"⠭",
"⠮",
"⠯",
"⡨",
"⡩",
"⡪",
"⡫",
"⡬",
"⡭",
"⡮",
"⡯",
"⠰",
"⠱",
"⠲",
"⠳",
"⠴",
"⠵",
"⠶",
"⠷",
"⡰",
"⡱",
"⡲",
"⡳",
"⡴",
"⡵",
"⡶",
"⡷",
"⠸",
"⠹",
"⠺",
"⠻",
"⠼",
"⠽",
"⠾",
"⠿",
"⡸",
"⡹",
"⡺",
"⡻",
"⡼",
"⡽",
"⡾",
"⡿",
"⢀",
"⢁",
"⢂",
"⢃",
"⢄",
"⢅",
"⢆",
"⢇",
"⣀",
"⣁",
"⣂",
"⣃",
"⣄",
"⣅",
"⣆",
"⣇",
"⢈",
"⢉",
"⢊",
"⢋",
"⢌",
"⢍",
"⢎",
"⢏",
"⣈",
"⣉",
"⣊",
"⣋",
"⣌",
"⣍",
"⣎",
"⣏",
"⢐",
"⢑",
"⢒",
"⢓",
"⢔",
"⢕",
"⢖",
"⢗",
"⣐",
"⣑",
"⣒",
"⣓",
"⣔",
"⣕",
"⣖",
"⣗",
"⢘",
"⢙",
"⢚",
"⢛",
"⢜",
"⢝",
"⢞",
"⢟",
"⣘",
"⣙",
"⣚",
"⣛",
"⣜",
"⣝",
"⣞",
"⣟",
"⢠",
"⢡",
"⢢",
"⢣",
"⢤",
"⢥",
"⢦",
"⢧",
"⣠",
"⣡",
"⣢",
"⣣",
"⣤",
"⣥",
"⣦",
"⣧",
"⢨",
"⢩",
"⢪",
"⢫",
"⢬",
"⢭",
"⢮",
"⢯",
"⣨",
"⣩",
"⣪",
"⣫",
"⣬",
"⣭",
"⣮",
"⣯",
"⢰",
"⢱",
"⢲",
"⢳",
"⢴",
"⢵",
"⢶",
"⢷",
"⣰",
"⣱",
"⣲",
"⣳",
"⣴",
"⣵",
"⣶",
"⣷",
"⢸",
"⢹",
"⢺",
"⢻",
"⢼",
"⢽",
"⢾",
"⢿",
"⣸",
"⣹",
"⣺",
"⣻",
"⣼",
"⣽",
"⣾",
"⣿"
]
},
sand: {
interval: 80,
frames: [
"⠁",
"⠂",
"⠄",
"⡀",
"⡈",
"⡐",
"⡠",
"⣀",
"⣁",
"⣂",
"⣄",
"⣌",
"⣔",
"⣤",
"⣥",
"⣦",
"⣮",
"⣶",
"⣷",
"⣿",
"⡿",
"⠿",
"⢟",
"⠟",
"⡛",
"⠛",
"⠫",
"⢋",
"⠋",
"⠍",
"⡉",
"⠉",
"⠑",
"⠡",
"⢁"
]
},
line: {
interval: 130,
frames: [
"-",
"\\",
"|",
"/"
]
},
line2: {
interval: 100,
frames: [
"⠂",
"-",
"–",
"—",
"–",
"-"
]
},
pipe: {
interval: 100,
frames: [
"┤",
"┘",
"┴",
"└",
"├",
"┌",
"┬",
"┐"
]
},
simpleDots: {
interval: 400,
frames: [
". ",
".. ",
"...",
" "
]
},
simpleDotsScrolling: {
interval: 200,
frames: [
". ",
".. ",
"...",
" ..",
" .",
" "
]
},
star: {
interval: 70,
frames: [
"✶",
"✸",
"✹",
"✺",
"✹",
"✷"
]
},
star2: {
interval: 80,
frames: [
"+",
"x",
"*"
]
},
flip: {
interval: 70,
frames: [
"_",
"_",
"_",
"-",
"`",
"`",
"'",
"´",
"-",
"_",
"_",
"_"
]
},
hamburger: {
interval: 100,
frames: [
"☱",
"☲",
"☴"
]
},
growVertical: {
interval: 120,
frames: [
"▁",
"▃",
"▄",
"▅",
"▆",
"▇",
"▆",
"▅",
"▄",
"▃"
]
},
growHorizontal: {
interval: 120,
frames: [
"▏",
"▎",
"▍",
"▌",
"▋",
"▊",
"▉",
"▊",
"▋",
"▌",
"▍",
"▎"
]
},
balloon: {
interval: 140,
frames: [
" ",
".",
"o",
"O",
"@",
"*",
" "
]
},
balloon2: {
interval: 120,
frames: [
".",
"o",
"O",
"°",
"O",
"o",
"."
]
},
noise: {
interval: 100,
frames: [
"▓",
"▒",
"░"
]
},
bounce: {
interval: 120,
frames: [
"⠁",
"⠂",
"⠄",
"⠂"
]
},
boxBounce: {
interval: 120,
frames: [
"▖",
"▘",
"▝",
"▗"
]
},
boxBounce2: {
interval: 100,
frames: [
"▌",
"▀",
"▐",
"▄"
]
},
triangle: {
interval: 50,
frames: [
"◢",
"◣",
"◤",
"◥"
]
},
binary: {
interval: 80,
frames: [
"010010",
"001100",
"100101",
"111010",
"111101",
"010111",
"101011",
"111000",
"110011",
"110101"
]
},
arc: {
interval: 100,
frames: [
"◜",
"◠",
"◝",
"◞",
"◡",
"◟"
]
},
circle: {
interval: 120,
frames: [
"◡",
"⊙",
"◠"
]
},
squareCorners: {
interval: 180,
frames: [
"◰",
"◳",
"◲",
"◱"
]
},
circleQuarters: {
interval: 120,
frames: [
"◴",
"◷",
"◶",
"◵"
]
},
circleHalves: {
interval: 50,
frames: [
"◐",
"◓",
"◑",
"◒"
]
},
squish: {
interval: 100,
frames: [
"╫",
"╪"
]
},
toggle: {
interval: 250,
frames: [
"⊶",
"⊷"
]
},
toggle2: {
interval: 80,
frames: [
"▫",
"▪"
]
},
toggle3: {
interval: 120,
frames: [
"□",
"■"
]
},
toggle4: {
interval: 100,
frames: [
"■",
"□",
"▪",
"▫"
]
},
toggle5: {
interval: 100,
frames: [
"▮",
"▯"
]
},
toggle6: {
interval: 300,
frames: [
"ဝ",
"၀"
]
},
toggle7: {
interval: 80,
frames: [
"⦾",
"⦿"
]
},
toggle8: {
interval: 100,
frames: [
"◍",
"◌"
]
},
toggle9: {
interval: 100,
frames: [
"◉",
"◎"
]
},
toggle10: {
interval: 100,
frames: [
"㊂",
"㊀",
"㊁"
]
},
toggle11: {
interval: 50,
frames: [
"⧇",
"⧆"
]
},
toggle12: {
interval: 120,
frames: [
"☗",
"☖"
]
},
toggle13: {
interval: 80,
frames: [
"=",
"*",
"-"
]
},
arrow: {
interval: 100,
frames: [
"←",
"↖",
"↑",
"↗",
"→",
"↘",
"↓",
"↙"
]
},
arrow2: {
interval: 80,
frames: [
"⬆️ ",
"↗️ ",
"➡️ ",
"↘️ ",
"⬇️ ",
"↙️ ",
"⬅️ ",
"↖️ "
]
},
arrow3: {
interval: 120,
frames: [
"▹▹▹▹▹",
"▸▹▹▹▹",
"▹▸▹▹▹",
"▹▹▸▹▹",
"▹▹▹▸▹",
"▹▹▹▹▸"
]
},
bouncingBar: {
interval: 80,
frames: [
"[ ]",
"[= ]",
"[== ]",
"[=== ]",
"[====]",
"[ ===]",
"[ ==]",
"[ =]",
"[ ]",
"[ =]",
"[ ==]",
"[ ===]",
"[====]",
"[=== ]",
"[== ]",
"[= ]"
]
},
bouncingBall: {
interval: 80,
frames: [
"( ● )",
"( ● )",
"( ● )",
"( ● )",
"( ●)",
"( ● )",
"( ● )",
"( ● )",
"( ● )",
"(● )"
]
},
smiley: {
interval: 200,
frames: [
"\uD83D\uDE04 ",
"\uD83D\uDE1D "
]
},
monkey: {
interval: 300,
frames: [
"\uD83D\uDE48 ",
"\uD83D\uDE48 ",
"\uD83D\uDE49 ",
"\uD83D\uDE4A "
]
},
hearts: {
interval: 100,
frames: [
"\uD83D\uDC9B ",
"\uD83D\uDC99 ",
"\uD83D\uDC9C ",
"\uD83D\uDC9A ",
"❤️ "
]
},
clock: {
interval: 100,
frames: [
"\uD83D\uDD5B ",
"\uD83D\uDD50 ",
"\uD83D\uDD51 ",
"\uD83D\uDD52 ",
"\uD83D\uDD53 ",
"\uD83D\uDD54 ",
"\uD83D\uDD55 ",
"\uD83D\uDD56 ",
"\uD83D\uDD57 ",
"\uD83D\uDD58 ",
"\uD83D\uDD59 ",
"\uD83D\uDD5A "
]
},
earth: {
interval: 180,
frames: [
"\uD83C\uDF0D ",
"\uD83C\uDF0E ",
"\uD83C\uDF0F "
]
},
material: {
interval: 17,
frames: [
"█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
"███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
"████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
"██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
"██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
"███████▁▁▁▁▁▁▁▁▁▁▁▁▁",
"████████▁▁▁▁▁▁▁▁▁▁▁▁",
"█████████▁▁▁▁▁▁▁▁▁▁▁",
"█████████▁▁▁▁▁▁▁▁▁▁▁",
"██████████▁▁▁▁▁▁▁▁▁▁",
"███████████▁▁▁▁▁▁▁▁▁",
"█████████████▁▁▁▁▁▁▁",
"██████████████▁▁▁▁▁▁",
"██████████████▁▁▁▁▁▁",
"▁██████████████▁▁▁▁▁",
"▁██████████████▁▁▁▁▁",
"▁██████████████▁▁▁▁▁",
"▁▁██████████████▁▁▁▁",
"▁▁▁██████████████▁▁▁",
"▁▁▁▁█████████████▁▁▁",
"▁▁▁▁██████████████▁▁",
"▁▁▁▁██████████████▁▁",
"▁▁▁▁▁██████████████▁",
"▁▁▁▁▁██████████████▁",
"▁▁▁▁▁██████████████▁",
"▁▁▁▁▁▁██████████████",
"▁▁▁▁▁▁██████████████",
"▁▁▁▁▁▁▁█████████████",
"▁▁▁▁▁▁▁█████████████",
"▁▁▁▁▁▁▁▁████████████",
"▁▁▁▁▁▁▁▁████████████",
"▁▁▁▁▁▁▁▁▁███████████",
"▁▁▁▁▁▁▁▁▁███████████",
"▁▁▁▁▁▁▁▁▁▁██████████",
"▁▁▁▁▁▁▁▁▁▁██████████",
"▁▁▁▁▁▁▁▁▁▁▁▁████████",
"▁▁▁▁▁▁▁▁▁▁▁▁▁███████",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁██████",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████",
"█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████",
"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███",
"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███",
"███▁▁▁▁▁▁▁▁▁▁▁▁▁▁███",
"████▁▁▁▁▁▁▁▁▁▁▁▁▁▁██",
"█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█",
"█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█",
"██████▁▁▁▁▁▁▁▁▁▁▁▁▁█",
"████████▁▁▁▁▁▁▁▁▁▁▁▁",
"█████████▁▁▁▁▁▁▁▁▁▁▁",
"█████████▁▁▁▁▁▁▁▁▁▁▁",
"█████████▁▁▁▁▁▁▁▁▁▁▁",
"█████████▁▁▁▁▁▁▁▁▁▁▁",
"███████████▁▁▁▁▁▁▁▁▁",
"████████████▁▁▁▁▁▁▁▁",
"████████████▁▁▁▁▁▁▁▁",
"██████████████▁▁▁▁▁▁",
"██████████████▁▁▁▁▁▁",
"▁██████████████▁▁▁▁▁",
"▁██████████████▁▁▁▁▁",
"▁▁▁█████████████▁▁▁▁",
"▁▁▁▁▁████████████▁▁▁",
"▁▁▁▁▁████████████▁▁▁",
"▁▁▁▁▁▁███████████▁▁▁",
"▁▁▁▁▁▁▁▁█████████▁▁▁",
"▁▁▁▁▁▁▁▁█████████▁▁▁",
"▁▁▁▁▁▁▁▁▁█████████▁▁",
"▁▁▁▁▁▁▁▁▁█████████▁▁",
"▁▁▁▁▁▁▁▁▁▁█████████▁",
"▁▁▁▁▁▁▁▁▁▁▁████████▁",
"▁▁▁▁▁▁▁▁▁▁▁████████▁",
"▁▁▁▁▁▁▁▁▁▁▁▁███████▁",
"▁▁▁▁▁▁▁▁▁▁▁▁███████▁",
"▁▁▁▁▁▁▁▁▁▁▁▁▁███████",
"▁▁▁▁▁▁▁▁▁▁▁▁▁███████",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁"
]
},
moon: {
interval: 80,
frames: [
"\uD83C\uDF11 ",
"\uD83C\uDF12 ",
"\uD83C\uDF13 ",
"\uD83C\uDF14 ",
"\uD83C\uDF15 ",
"\uD83C\uDF16 ",
"\uD83C\uDF17 ",
"\uD83C\uDF18 "
]
},
runner: {
interval: 140,
frames: [
"\uD83D\uDEB6 ",
"\uD83C\uDFC3 "
]
},
pong: {
interval: 80,
frames: [
"▐⠂ ▌",
"▐⠈ ▌",
"▐ ⠂ ▌",
"▐ ⠠ ▌",
"▐ ⡀ ▌",
"▐ ⠠ ▌",
"▐ ⠂ ▌",
"▐ ⠈ ▌",
"▐ ⠂ ▌",
"▐ ⠠ ▌",
"▐ ⡀ ▌",
"▐ ⠠ ▌",
"▐ ⠂ ▌",
"▐ ⠈ ▌",
"▐ ⠂▌",
"▐ ⠠▌",
"▐ ⡀▌",
"▐ ⠠ ▌",
"▐ ⠂ ▌",
"▐ ⠈ ▌",
"▐ ⠂ ▌",
"▐ ⠠ ▌",
"▐ ⡀ ▌",
"▐ ⠠ ▌",
"▐ ⠂ ▌",
"▐ ⠈ ▌",
"▐ ⠂ ▌",
"▐ ⠠ ▌",
"▐ ⡀ ▌",
"▐⠠ ▌"
]
},
shark: {
interval: 120,
frames: [
"▐|\\____________▌",
"▐_|\\___________▌",
"▐__|\\__________▌",
"▐___|\\_________▌",
"▐____|\\________▌",
"▐_____|\\_______▌",
"▐______|\\______▌",
"▐_______|\\_____▌",
"▐________|\\____▌",
"▐_________|\\___▌",
"▐__________|\\__▌",
"▐___________|\\_▌",
"▐____________|\\▌",
"▐____________/|▌",
"▐___________/|_▌",
"▐__________/|__▌",
"▐_________/|___▌",
"▐________/|____▌",
"▐_______/|_____▌",
"▐______/|______▌",
"▐_____/|_______▌",
"▐____/|________▌",
"▐___/|_________▌",
"▐__/|__________▌",
"▐_/|___________▌",
"▐/|____________▌"
]
},
dqpb: {
interval: 100,
frames: [
"d",
"q",
"p",
"b"
]
},
weather: {
interval: 100,
frames: [
"☀️ ",
"☀️ ",
"☀️ ",
"\uD83C\uDF24 ",
"⛅️ ",
"\uD83C\uDF25 ",
"☁️ ",
"\uD83C\uDF27 ",
"\uD83C\uDF28 ",
"\uD83C\uDF27 ",
"\uD83C\uDF28 ",
"\uD83C\uDF27 ",
"\uD83C\uDF28 ",
"⛈ ",
"\uD83C\uDF28 ",
"\uD83C\uDF27 ",
"\uD83C\uDF28 ",
"☁️ ",
"\uD83C\uDF25 ",
"⛅️ ",
"\uD83C\uDF24 ",
"☀️ ",
"☀️ "
]
},
christmas: {
interval: 400,
frames: [
"\uD83C\uDF32",
"\uD83C\uDF84"
]
},
grenade: {
interval: 80,
frames: [
"، ",
"′ ",
" ´ ",
" ‾ ",
" ⸌",
" ⸊",
" |",
" ⁎",
" ⁕",
" ෴ ",
" ⁓",
" ",
" ",
" "
]
},
point: {
interval: 125,
frames: [
"∙∙∙",
"●∙∙",
"∙●∙",
"∙∙●",
"∙∙∙"
]
},
layer: {
interval: 150,
frames: [
"-",
"=",
"≡"
]
},
betaWave: {
interval: 80,
frames: [
"ρββββββ",
"βρβββββ",
"ββρββββ",
"βββρβββ",
"ββββρββ",
"βββββρβ",
"ββββββρ"
]
},
fingerDance: {
interval: 160,
frames: [
"\uD83E\uDD18 ",
"\uD83E\uDD1F ",
"\uD83D\uDD96 ",
"✋ ",
"\uD83E\uDD1A ",
"\uD83D\uDC46 "
]
},
fistBump: {
interval: 80,
frames: [
"\uD83E\uDD1C \uD83E\uDD1B ",
"\uD83E\uDD1C \uD83E\uDD1B ",
"\uD83E\uDD1C \uD83E\uDD1B ",
" \uD83E\uDD1C \uD83E\uDD1B ",
" \uD83E\uDD1C\uD83E\uDD1B ",
" \uD83E\uDD1C✨\uD83E\uDD1B ",
"\uD83E\uDD1C ✨ \uD83E\uDD1B "
]
},
soccerHeader: {
interval: 80,
frames: [
" \uD83E\uDDD1⚽️ \uD83E\uDDD1 ",
"\uD83E\uDDD1 ⚽️ \uD83E\uDDD1 ",
"\uD83E\uDDD1 ⚽️ \uD83E\uDDD1 ",
"\uD83E\uDDD1 ⚽️ \uD83E\uDDD1 ",
"\uD83E\uDDD1 ⚽️ \uD83E\uDDD1 ",
"\uD83E\uDDD1 ⚽️ \uD83E\uDDD1 ",
"\uD83E\uDDD1 ⚽️\uD83E\uDDD1 ",
"\uD83E\uDDD1 ⚽️ \uD83E\uDDD1 ",
"\uD83E\uDDD1 ⚽️ \uD83E\uDDD1 ",
"\uD83E\uDDD1 ⚽️ \uD83E\uDDD1 ",
"\uD83E\uDDD1 ⚽️ \uD83E\uDDD1 ",
"\uD83E\uDDD1 ⚽️ \uD83E\uDDD1 "
]
},
mindblown: {
interval: 160,
frames: [
"\uD83D\uDE10 ",
"\uD83D\uDE10 ",
"\uD83D\uDE2E ",
"\uD83D\uDE2E ",
"\uD83D\uDE26 ",
"\uD83D\uDE26 ",
"\uD83D\uDE27 ",
"\uD83D\uDE27 ",
"\uD83E\uDD2F ",
"\uD83D\uDCA5 ",
"✨ ",
" ",
" ",
" "
]
},
speaker: {
interval: 160,
frames: [
"\uD83D\uDD08 ",
"\uD83D\uDD09 ",
"\uD83D\uDD0A ",
"\uD83D\uDD09 "
]
},
orangePulse: {
interval: 100,
frames: [
"\uD83D\uDD38 ",
"\uD83D\uDD36 ",
"\uD83D\uDFE0 ",
"\uD83D\uDFE0 ",
"\uD83D\uDD36 "
]
},
bluePulse: {
interval: 100,
frames: [
"\uD83D\uDD39 ",
"\uD83D\uDD37 ",
"\uD83D\uDD35 ",
"\uD83D\uDD35 ",
"\uD83D\uDD37 "
]
},
orangeBluePulse: {
interval: 100,
frames: [
"\uD83D\uDD38 ",
"\uD83D\uDD36 ",
"\uD83D\uDFE0 ",
"\uD83D\uDFE0 ",
"\uD83D\uDD36 ",
"\uD83D\uDD39 ",
"\uD83D\uDD37 ",
"\uD83D\uDD35 ",
"\uD83D\uDD35 ",
"\uD83D\uDD37 "
]
},
timeTravel: {
interval: 100,
frames: [
"\uD83D\uDD5B ",
"\uD83D\uDD5A ",
"\uD83D\uDD59 ",
"\uD83D\uDD58 ",
"\uD83D\uDD57 ",
"\uD83D\uDD56 ",
"\uD83D\uDD55 ",
"\uD83D\uDD54 ",
"\uD83D\uDD53 ",
"\uD83D\uDD52 ",
"\uD83D\uDD51 ",
"\uD83D\uDD50 "
]
},
aesthetic: {
interval: 80,
frames: [
"▰▱▱▱▱▱▱",
"▰▰▱▱▱▱▱",
"▰▰▰▱▱▱▱",
"▰▰▰▰▱▱▱",
"▰▰▰▰▰▱▱",
"▰▰▰▰▰▰▱",
"▰▰▰▰▰▰▰",
"▰▱▱▱▱▱▱"
]
},
dwarfFortress: {
interval: 80,
frames: [
" ██████£££ ",
"☺██████£££ ",
"☺██████£££ ",
"☺▓█████£££ ",
"☺▓█████£££ ",
"☺▒█████£££ ",
"☺▒█████£££ ",
"☺░█████£££ ",
"☺░█████£££ ",
"☺ █████£££ ",
" ☺█████£££ ",
" ☺█████£££ ",
" ☺▓████£££ ",
" ☺▓████£££ ",
" ☺▒████£££ ",
" ☺▒████£££ ",
" ☺░████£££ ",
" ☺░████£££ ",
" ☺ ████£££ ",
" ☺████£££ ",
" ☺████£££ ",
" ☺▓███£££ ",
" ☺▓███£££ ",
" ☺▒███£££ ",
" ☺▒███£££ ",
" ☺░███£££ ",
" ☺░███£££ ",
" ☺ ███£££ ",
" ☺███£££ ",
" ☺███£££ ",
" ☺▓██£££ ",
" ☺▓██£££ ",
" ☺▒██£££ ",
" ☺▒██£££ ",
" ☺░██£££ ",
" ☺░██£££ ",
" ☺ ██£££ ",
" ☺██£££ ",
" ☺██£££ ",
" ☺▓█£££ ",
" ☺▓█£££ ",
" ☺▒█£££ ",
" ☺▒█£££ ",
" ☺░█£££ ",
" ☺░█£££ ",
" ☺ █£££ ",
" ☺█£££ ",
" ☺█£££ ",
" ☺▓£££ ",
" ☺▓£££ ",
" ☺▒£££ ",
" ☺▒£££ ",
" ☺░£££ ",
" ☺░£££ ",
" ☺ £££ ",
" ☺£££ ",
" ☺£££ ",
" ☺▓££ ",
" ☺▓££ ",
" ☺▒££ ",
" ☺▒££ ",
" ☺░££ ",
" ☺░££ ",
" ☺ ££ ",
" ☺££ ",
" ☺££ ",
" ☺▓£ ",
" ☺▓£ ",
" ☺▒£ ",
" ☺▒£ ",
" ☺░£ ",
" ☺░£ ",
" ☺ £ ",
" ☺£ ",
" ☺£ ",
" ☺▓ ",
" ☺▓ ",
" ☺▒ ",
" ☺▒ ",
" ☺░ ",
" ☺░ ",
" ☺ ",
" ☺ &",
" ☺ ☼&",
" ☺ ☼ &",
" ☺☼ &",
" ☺☼ & ",
" ‼ & ",
" ☺ & ",
" ‼ & ",
" ☺ & ",
" ‼ & ",
" ☺ & ",
"‼ & ",
" & ",
" & ",
" & ░ ",
" & ▒ ",
" & ▓ ",
" & £ ",
" & ░£ ",
" & ▒£ ",
" & ▓£ ",
" & ££ ",
" & ░££ ",
" & ▒££ ",
"& ▓££ ",
"& £££ ",
" ░£££ ",
" ▒£££ ",
" ▓£££ ",
" █£££ ",
" ░█£££ ",
" ▒█£££ ",
" ▓█£££ ",
" ██£££ ",
" ░██£££ ",
" ▒██£££ ",
" ▓██£££ ",
" ███£££ ",
" ░███£££ ",
" ▒███£££ ",
" ▓███£££ ",
" ████£££ ",
" ░████£££ ",
" ▒████£££ ",
" ▓████£££ ",
" █████£££ ",
" ░█████£££ ",
" ▒█████£££ ",
" ▓█████£££ ",
" ██████£££ ",
" ██████£££ "
]
}
};
});
// node_modules/cli-spinners/index.js
var require_cli_spinners = __commonJS((exports, module) => {
var spinners = Object.assign({}, require_spinners());
var spinnersList = Object.keys(spinners);
Object.defineProperty(spinners, "random", {
get() {
const randomIndex = Math.floor(Math.random() * spinnersList.length);
const spinnerName = spinnersList[randomIndex];
return spinners[spinnerName];
}
});
module.exports = spinners;
});
// src/cli.tsx
import { Command } from "commander";
import { render } from "ink";
import React16 from "react";
// src/app-main.tsx
import React15, { useEffect as useEffect8 } from "react";
import { Text as Text13, Box as Box11, useInput as useInput5, useApp as useApp4 } from "ink";
// node_modules/ink-spinner/build/index.js
var import_cli_spinners = __toESM(require_cli_spinners(), 1);
import React, { useState, useEffect } from "react";
import { Text } from "ink";
function Spinner({ type = "dots" }) {
const [frame, setFrame] = useState(0);
const spinner = import_cli_spinners.default[type];
useEffect(() => {
const timer = setInterval(() => {
setFrame((previousFrame) => {
const isLastFrame = previousFrame === spinner.frames.length - 1;
return isLastFrame ? 0 : previousFrame + 1;
});
}, spinner.interval);
return () => {
clearInterval(timer);
};
}, [spinner]);
return React.createElement(Text, null, spinner.frames[frame]);
}
var build_default = Spinner;
// src/state/store.tsx
import React2, { createContext, useReducer } from "react";
var initialUIState = {
view: "dashboard",
selectedDate: null,
selectedIndex: 0,
sortBy: "date",
sortOrder: "desc",
dateRange: {
from: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
to: new Date
}
};
var initialSettings = {
watchMode: false,
refreshInterval: 5000,
showPercentiles: true,
exportPath: process.cwd()
};
var initialState = {
data: null,
ui: initialUIState,
settings: initialSettings,
loading: false,
error: null
};
function appReducer(state, action) {
switch (action.type) {
case "SET_DATA":
return {
...state,
data: action.payload,
loading: false,
error: null
};
case "SET_LOADING":
return {
...state,
loading: action.payload
};
case "SET_ERROR":
return {
...state,
error: action.payload,
loading: false
};
case "SET_VIEW":
return {
...state,
ui: {
...state.ui,
view: action.payload
}
};
case "SELECT_DATE":
return {
...state,
ui: {
...state.ui,
selectedDate: action.payload,
view: "details"
}
};
case "SET_SORT":
return {
...state,
ui: {
...state.ui,
sortBy: action.payload.sortBy,
sortOrder: action.payload.sortOrder
}
};
case "UPDATE_SETTINGS":
return {
...state,
settings: {
...state.settings,
...action.payload
}
};
case "SET_SELECTED_INDEX":
return {
...state,
ui: {
...state.ui,
selectedIndex: action.payload
}
};
case "UPDATE_DATE_RANGE":
return {
...state,
ui: {
...state.ui,
dateRange: action.payload
}
};
default:
return state;
}
}
var AppContext = createContext(undefined);
function AppProvider({ children, initialData }) {
const [state, dispatch] = useReducer(appReducer, {
...initialState,
data: initialData || null
});
return /* @__PURE__ */ React2.createElement(AppContext.Provider, {
value: { state, dispatch }
}, children);
}
function useAppContext() {
const context = React2.useContext(AppContext);
if (!context) {
throw new Error("useAppContext must be used within AppProvider");
}
return context;
}
var actions = {
setData: (data) => ({
type: "SET_DATA",
payload: data
}),
setLoading: (loading) => ({
type: "SET_LOADING",
payload: loading
}),
setError: (error) => ({
type: "SET_ERROR",
payload: error
}),
setView: (view) => ({
type: "SET_VIEW",
payload: view
}),
selectDate: (date) => ({
type: "SELECT_DATE",
payload: date
}),
setSort: (sortBy, sortOrder) => ({
type: "SET_SORT",
payload: { sortBy, sortOrder }
}),
updateSettings: (settings) => ({
type: "UPDATE_SETTINGS",
payload: settings
}),
setSelectedIndex: (index) => ({
type: "SET_SELECTED_INDEX",
payload: index
}),
updateDateRange: (from, to) => ({
type: "UPDATE_DATE_RANGE",
payload: { from, to }
})
};
// src/state/hooks.ts
import { useEffect as useEffect2, useCallback, useState as useState2, useRef } from "react";
import { useInput } from "ink";
function useAppState() {
const { state } = useAppContext();
return state;
}
function useAppDispatch() {
const { dispatch } = useAppContext();
return dispatch;
}
function useKeyboardNavigation(options) {
const [lastKey, setLastKey] = useState2(null);
useInput((input, key) => {
setLastKey(input || "special");
if (key.upArrow && options?.onUp) {
options.onUp();
} else if (key.downArrow && options?.onDown) {
options.onDown();
} else if (key.leftArrow && options?.onLeft) {
options.onLeft();
} else if (key.rightArrow && options?.onRight) {
options.onRight();
}
if (key.return && options?.onEnter) {
options.onEnter();
} else if (key.escape && options?.onEscape) {
options.onEscape();
} else if (key.tab && !key.shift && options?.onTab) {
options.onTab();
} else if (key.tab && key.shift && options?.onShiftTab) {
options.onShiftTab();
}
if (input && options?.customHandlers?.[input]) {
options.customHandlers[input]();
}
});
return { lastKey };
}
function useDataLoader(options) {
const { dispatch } = useAppContext();
const [isLoading, setIsLoading] = useState2(false);
const [error, setError] = useState2(null);
const loadingRef = useRef(false);
const loadData = useCallback(async () => {
if (loadingRef.current)
return;
loadingRef.current = true;
setIsLoading(true);
setError(null);
dispatch(actions.setLoading(true));
try {
const mockData = {
daily: new Map,
sessions: new Map,
summary: {
totalResponseTimeMs: 0,
totalResponses: 0,
averageResponseTimeMs: 0,
uniqueSessions: 0,
dateRange: {
from: new Date().toISOString(),
to: new Date().toISOString()
}
}
};
await new Promise((resolve) => setTimeout(resolve, 1000));
dispatch(actions.setData(mockData));
} catch (err) {
const errorMessage = err instanceof Error ? err.message : "Unknown error";
setError(err instanceof Error ? err : new Error(errorMessage));
dispatch(actions.setError(errorMessage));
} finally {
setIsLoading(false);
dispatch(actions.setLoading(false));
loadingRef.current = false;
}
}, [dispatch, options]);
useEffect2(() => {
loadData();
}, [loadData]);
return {
isLoading,
error,
reload: loadData
};
}
function useSelection(items, initialIndex = 0) {
const [selectedIndex, setSelectedIndex] = useState2(initialIndex);
const selectNext = useCallback(() => {
setSelectedIndex((prev) => Math.min(items.length - 1, prev + 1));
}, [items.length]);
const selectPrevious = useCallback(() => {
setSelectedIndex((prev) => Math.max(0, prev - 1));
}, []);
const selectFirst = useCallback(() => {
setSelectedIndex(0);
}, []);
const selectLast = useCallback(() => {
setSelectedIndex(items.length - 1);
}, [items.length]);
const selectIndex = useCallback((index) => {
setSelectedIndex(Math.max(0, Math.min(items.length - 1, index)));
}, [items.length]);
useEffect2(() => {
if (selectedIndex >= items.length) {
setSelectedIndex(Math.max(0, items.length - 1));
}
}, [items.length, selectedIndex]);
return {
selectedIndex,
selectedItem: items[selectedIndex],
selectNext,
selectPrevious,
selectFirst,
selectLast,
selectIndex
};
}
function useSorting(items, initialSortBy, initialOrder = "asc") {
const [sortBy, setSortBy] = useState2(initialSortBy);
const [sortOrder, setSortOrder] = useState2(initialOrder);
const sortedItems = [...items].sort((a, b) => {
const aValue = a[sortBy];
const bValue = b[sortBy];
if (aValue === bValue)
return 0;
const comparison = aValue < bValue ? -1 : 1;
return sortOrder === "asc" ? comparison : -comparison;
});
const toggleSortOrder = useCallback(() => {
setSortOrder((prev) => prev === "asc" ? "desc" : "asc");
}, []);
const changeSortBy = useCallback((field) => {
if (field === sortBy) {
toggleSortOrder();
} else {
setSortBy(field);
setSortOrder("asc");
}
}, [sortBy, toggleSortOrder]);
return {
sortedItems,
sortBy,
sortOrder,
changeSortBy,
toggleSortOrder
};
}
function usePagination(items, pageSize = 10) {
const [currentPage, setCurrentPage] = useState2(0);
const totalPages = Math.ceil(items.length / pageSize);
const paginatedItems = items.slice(currentPage * pageSize, (currentPage + 1) * pageSize);
const nextPage = useCallback(() => {
setCurrentPage((prev) => Math.min(totalPages - 1, prev + 1));
}, [totalPages]);
const previousPage = useCallback(() => {
setCurrentPage((prev) => Math.max(0, prev - 1));
}, []);
const goToPage = useCallback((page) => {
setCurrentPage(Math.max(0, Math.min(totalPages - 1, page)));
}, [totalPages]);
const goToFirst = useCallback(() => {
setCurrentPage(0);
}, []);
const goToLast = useCallback(() => {
setCurrentPage(totalPages - 1);
}, [totalPages]);
useEffect2(() => {
if (currentPage >= totalPages && totalPages > 0) {
setCurrentPage(totalPages - 1);
}
}, [currentPage, totalPages]);
return {
paginatedItems,
currentPage,
totalPages,
nextPage,
previousPage,
goToPage,
goToFirst,
goToLast,
hasNextPage: currentPage < totalPages - 1,
hasPreviousPage: currentPage > 0
};
}
function useAutoRefresh(callback, interval, enabled = true) {
const callbackRef = useRef(callback);
useEffect2(() => {
callbackRef.current = callback;
}, [callback]);
useEffect2(() => {
if (!enabled || interval <= 0)
return;
const timer = setInterval(() => {
callbackRef.current();
}, interval);
return () => clearInterval(timer);
}, [interval, enabled]);
}
// src/navigation.ts
import { useInput as useInput2, useApp } from "ink";
import { useCallback as useCallback2, useRef as useRef2 } from "react";
var KEYBOARD_SHORTCUTS = {
TAB: "tab",
SHIFT_TAB: "shift+tab",
ENTER: "return",
ESCAPE: "escape",
UP: "up",
DOWN: "down",
LEFT: "left",
RIGHT: "right",
PAGE_UP: "pageUp",
PAGE_DOWN: "pageDown",
HOME: "home",
END: "end",
DASHBOARD: "d",
DETAILS: "v",
EXPORT: "e",
SETTINGS: "s",
QUIT: "q",
REFRESH: "r",
SORT: "o",
TOGGLE_SORT_ORDER: "O",
HELP: "?",
EXPORT_JSON: "j",
EXPORT_CSV: "c",
EXPORT_MARKDOWN: "m"
};
function useNavigationController() {
const { state, dispatch } = useAppContext();
const { exit } = useApp();
const focusIndex = useRef2(0);
const maxFocusIndex = useRef2(0);
const handleViewChange = useCallback2((view) => {
dispatch(actions.setView(view));
focusIndex.current = 0;
}, [dispatch]);
const handleNavigation = useCallback2((input, key) => {
if (input === KEYBOARD_SHORTCUTS.QUIT) {
exit();
return;
}
if (input === KEYBOARD_SHORTCUTS.DASHBOARD) {
handleViewChange("dashboard");
return;
}
if (input === KEYBOARD_SHORTCUTS.EXPORT) {
handleViewChange("export");
return;
}
if (input === KEYBOARD_SHORTCUTS.SETTINGS) {
handleViewChange("settings");
return;
}
if (key.escape) {
handleViewChange("dashboard");
return;
}
switch (state.ui.view) {
case "dashboard":
handleDashboardNavigation(input, key);
break;
case "details":
handleDetailsNavigation(input, key);
break;
case "export":
handleExportNavigation(input, key);
break;
case "settings":
handleSettingsNavigation(input, key);
break;
}
}, [state.ui.view, exit, handleViewChange]);
const handleDashboardNavigation = useCallback2((input, key) => {
if (key.upArrow || key.downArrow) {
const dailyData = state.data?.daily ? Array.from(state.data.daily.values()) : [];
const maxIndex = dailyData.length - 1;
let newIndex = state.ui.selectedIndex;
if (key.upArrow) {
newIndex = Math.max(0, newIndex - 1);
} else {
newIndex = Math.min(maxIndex, newIndex + 1);
}
dispatch(actions.setSelectedIndex(newIndex));
}
if (key.return && state.data) {
const dailyData = Array.from(state.data.daily.values());
const selectedEntry = dailyData[state.ui.selectedIndex];
if (selectedEntry) {
dispatch(actions.selectDate(selectedEntry.date));
}
}
if (input === KEYBOARD_SHORTCUTS.SORT) {
const sortOptions = ["date", "totalTime", "avgTime", "count"];
const currentIndex = sortOptions.indexOf(state.ui.sortBy);
const nextIndex = (currentIndex + 1) % sortOptions.length;
dispatch(actions.setSort(sortOptions[nextIndex], state.ui.sortOrder));
}
if (input === KEYBOARD_SHORTCUTS.TOGGLE_SORT_ORDER) {
const newOrder = state.ui.sortOrder === "asc" ? "desc" : "asc";
dispatch(actions.setSort(state.ui.sortBy, newOrder));
}
}, [state, dispatch]);
const handleDetailsNavigation = useCallback2((input, key) => {
if (key.escape || input === "b") {
handleViewChange("dashboard");
}
if (key.upArrow || key.downArrow) {
}
}, [handleViewChange]);
const handleExportNavigation = useCallback2((input, key) => {
if (key.escape) {
handleViewChange("dashboard");
}
}, [handleViewChange]);
const handleSettingsNavigation = useCallback2((input, key) => {
if (key.tab) {
focusIndex.current = (focusIndex.current + 1) % (maxFocusIndex.current + 1);
} else if (key.shift && key.tab) {
focusIndex.current = focusIndex.current === 0 ? maxFocusIndex.current : focusIndex.current - 1;
}
if (input === " ") {
}
if (key.escape) {
handleViewChange("dashboard");
}
}, [handleViewChange]);
useInput2(handleNavigation);
return {
focusIndex: focusIndex.current,
setMaxFocusIndex: (max) => {
maxFocusIndex.current = max;
},
handleViewChange
};
}
// src/components/views/Dashboard.tsx
import React9, { useState as useState6, useMemo } from "react";
import { Box as Box7, Text as Text8 } from "ink";
// src/components/base/Table.tsx
import React3 from "react";
import { Box, Text as Text2 } from "ink";
var BaseTable = ({
columns,
rows,
showBorder = false,
headerColor = "white",
selectedRowColor = "blue"
}) => {
if (!rows || rows.length === 0) {
return /* @__PURE__ */ React3.createElement(Box, {
flexDirection: "column"
}, /* @__PURE__ */ React3.createElement(Text2, {
dimColor: true
}, "No data available"));
}
return /* @__PURE__ */ React3.createElement(Box, {
flexDirection: "column"
}, /* @__PURE__ */ React3.createElement(Box, null, columns.map((col) => /* @__PURE__ */ React3.createElement(Box, {
key: col.key,
width: col.width,
paddingRight: 1
}, /* @__PURE__ */ React3.createElement(Text2, {
bold: true,
underline: true,
color: headerColor
}, col.header)))), rows.map((row, rowIndex) => {
const isSelected = row.isSelected || false;
return /* @__PURE__ */ React3.createElement(Box, {
key: rowIndex
}, columns.map((col) => /* @__PURE__ */ React3.createElement(Box, {
key: col.key,
width: col.width,
paddingRight: 1
}, /* @__PURE__ */ React3.createElement(Text2, {
color: isSelected ? selectedRowColor : undefined,
backgroundColor: isSelected ? "gray" : undefined,
bold: isSelected
}, row[col.key]))));
}));
};
// src/components/base/Chart.tsx
import React4 from "react";
import { Box as Box2, Text as Text3 } from "ink";
import * as asciichart from "asciichart";
var BaseChart = ({
data,
height = 10,
title,
showLabels = true,
color = "green"
}) => {
if (!data || data.length === 0) {
return /* @__PURE__ */ React4.createElement(Box2, {
flexDirection: "column",
borderStyle: "single",
padding: 1
}, title && /* @__PURE__ */ React4.createElement(Text3, {
bold: true
}, title), /* @__PURE__ */ React4.createElement(Text3, {
dimColor: true
}, "No data to display"));
}
const values = data.map((d) => d.value);
const minValue = Math.min(...values);
const maxValue = Math.max(...values);
const chartOptions = {
height,
padding: " ",
format: (x, i) => {
if (x < 1000)
return x.toFixed(0).padStart(6);
return (x / 1000).toFixed(1).padStart(5) + "k";
}
};
const chart = asciichart.plot(values, chartOptions);
const formatDateLabel = (dateStr) => {
const date = new Date(dateStr);
return date.toLocaleDateString("en-US", { month: "short", day: "numeric" });
};
const xAxisLabels = () => {
if (!showLabels || data.length < 2)
return null;
const startLabel = formatDateLabel(data[0].date);
const endLabel = formatDateLabel(data[data.length - 1].date);
const chartWidth = chart.split(`
`)[0].length - 7;
const padding = Math.max(0, chartWidth - startLabel.length - endLabel.length);
return startLabel + " ".repeat(padding) + endLabel;
};
const stats = {
min: minValue,
max: maxValue,
avg: values.reduce((a, b) => a + b, 0) / values.length,
current: values[values.length - 1]
};
return /* @__PURE__ */ React4.createElement(Box2, {
flexDirection: "column",
borderStyle: "single",
padding: 1
}, title && /* @__PURE__ */ React4.createElement(Box2, {
marginBottom: 1
}, /* @__PURE__ */ React4.createElement(Text3, {
bold: true
}, title)), /* @__PURE__ */ React4.createElement(Box2, {
flexDirection: "column"
}, /* @__PURE__ */ React4.createElement(Text3, {
color
}, chart), showLabels && xAxisLabels() && /* @__PURE__ */ React4.createElement(Box2, {
marginTop: 1
}, /* @__PURE__ */ React4.createElement(Text3, {
dimColor: true
}, " ", xAxisLabels())), /* @__PURE__ */ React4.createElement(Box2, {
marginTop: 1,
gap: 2
}, /* @__PURE__ */ React4.createElement(Text3, {
dimColor: true
}, "Min: ", /* @__PURE__ */ React4.createElement(Text3, {
color: "red"
}, stats.min.toFixed(0), "ms")), /* @__PURE__ */ React4.createElement(Text3, {
dimColor: true
}, "Max: ", /* @__PURE__ */ React4.createElement(Text3, {
color: "green"
}, stats.max.toFixed(0), "ms")), /* @__PURE__ */ React4.createElement(Text3, {
dimColor: true
}, "Avg: ", /* @__PURE__ */ React4.createElement(Text3, {
color: "yellow"
}, stats.avg.toFixed(0), "ms")), /* @__PURE__ */ React4.createElement(Text3, {
dimColor: true
}, "Current: ", /* @__PURE__ */ React4.createElement(Text3, {
color: "cyan"
}, stats.current.toFixed(0), "ms")))));
};
// src/components/base/ProgressBar.tsx
import React5, { useState as useState3, useEffect as useEffect3 } from "react";
import { Box as Box3, Text as Text4 } from "ink";
var BaseProgressBar = ({
progress,
label = "Processing",
currentFile,
showPercentage = true,
width = 30,
character = "█",
color = "green"
}) => {
const [indeterminatePosition, setIndeterminatePosition] = useState3(0);
const [animationFrame, setAnimationFrame] = useState3(0);
useEffect3(() => {
if (progress === undefined) {
const timer = setInterval(() => {
setAnimationFrame((prev) => prev + 1);
setIndeterminatePosition((prev) => (prev + 1) % (width + 10));
}, 100);
return () => clearInterval(timer);
}
}, [progress, width]);
const renderDeterminateBar = () => {
const clampedProgress = Math.max(0, Math.min(100, progress || 0));
const filled = Math.floor(clampedProgress / 100 * width);
const empty = width - filled;
return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(Text4, {
color
}, character.repeat(filled)), /* @__PURE__ */ React5.createElement(Text4, {
dimColor: true
}, "░".repeat(empty)));
};
const renderIndeterminateBar = () => {
const spinnerChars = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
const currentSpinner = spinnerChars[animationFrame % spinnerChars.length];
const barArray = Array(width).fill("░");
const indicatorWidth = 5;
const startPos = Math.max(0, Math.min(width - indicatorWidth, indeterminatePosition - 5));
for (let i = 0;i < indicatorWidth && startPos + i < width; i++) {
barArray[startPos + i] = character;
}
return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(Text4, {
color
}, currentSpinner, " "), /* @__PURE__ */ React5.createElement(Text4, null, barArray.map((char, i) => /* @__PURE__ */ React5.createElement(Text4, {
key: i,
color: char === character ? color : undefined,