chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:39:12 +08:00
commit d8dcd5f6d1
8604 changed files with 2479390 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
import React from "react";
import { Box, Text } from "ink";
export function CodeBlock({ code = "", language }) {
return (
<Box flexDirection="column" borderStyle="single" borderColor="gray" paddingX={1}>
{language && (
<Text dimColor bold>
{language}
</Text>
)}
<Text>{code}</Text>
</Box>
);
}
+40
View File
@@ -0,0 +1,40 @@
import React, { useState } from "react";
import { Box, Text, useInput } from "ink";
export function ConfirmDialog({ message, onConfirm, onCancel }) {
const [selected, setSelected] = useState(1); // 0=yes, 1=no (default no)
useInput((input, key) => {
if (key.leftArrow || input === "y") setSelected(0);
if (key.rightArrow || input === "n") setSelected(1);
if (key.return) {
if (selected === 0) onConfirm?.();
else onCancel?.();
}
if (key.escape) onCancel?.();
});
return (
<Box flexDirection="column" borderStyle="round" borderColor="yellow" padding={1}>
<Text bold color="yellow">
{message}
</Text>
<Box marginTop={1} gap={2}>
<Text
bold={selected === 0}
color={selected === 0 ? "green" : undefined}
inverse={selected === 0}
>
Yes
</Text>
<Text
bold={selected === 1}
color={selected === 1 ? "red" : undefined}
inverse={selected === 1}
>
No
</Text>
</Box>
</Box>
);
}
+50
View File
@@ -0,0 +1,50 @@
import React, { useState } from "react";
import { Box, Text, useInput } from "ink";
import { theme } from "./theme.jsx";
function formatCell(v, col) {
if (v == null) return "-";
if (col.formatter) return col.formatter(v);
return String(v);
}
export function DataTable({ rows = [], schema = [], selectable = false, onSelect }) {
const [selectedIdx, setSelectedIdx] = useState(0);
useInput((input, key) => {
if (!selectable || rows.length === 0) return;
if (key.upArrow) setSelectedIdx((i) => Math.max(0, i - 1));
if (key.downArrow) setSelectedIdx((i) => Math.min(rows.length - 1, i + 1));
if (key.return && onSelect) onSelect(rows[selectedIdx]);
});
if (rows.length === 0) {
return <Text dimColor>No data.</Text>;
}
return (
<Box flexDirection="column">
<Box>
{schema.map((col) => (
<Box key={col.key} width={col.width ?? 16} marginRight={1}>
<Text bold color={theme.header}>
{col.header}
</Text>
</Box>
))}
</Box>
{rows.map((row, idx) => (
<Box
key={idx}
backgroundColor={selectable && idx === selectedIdx ? theme.selected : undefined}
>
{schema.map((col) => (
<Box key={col.key} width={col.width ?? 16} marginRight={1}>
<Text>{formatCell(row[col.key], col)}</Text>
</Box>
))}
</Box>
))}
</Box>
);
}
+25
View File
@@ -0,0 +1,25 @@
import React, { useEffect, useState } from "react";
import { Text } from "ink";
export function HeaderSwr({ fetcher, interval = 5000, render, initial = null }) {
const [data, setData] = useState(initial);
useEffect(() => {
let cancelled = false;
async function tick() {
try {
const next = await fetcher();
if (!cancelled) setData(next);
} catch {}
}
tick();
const id = setInterval(tick, interval);
return () => {
cancelled = true;
clearInterval(id);
};
}, [fetcher, interval]);
if (!data) return <Text dimColor>Loading</Text>;
return render(data);
}
@@ -0,0 +1,12 @@
import React from "react";
import { Text } from "ink";
export function KeyMaskedDisplay({ apiKey, revealed = false }) {
if (!apiKey) return <Text dimColor>(none)</Text>;
const display = revealed
? apiKey
: apiKey.length <= 8
? "***"
: `${apiKey.slice(0, 6)}***${apiKey.slice(-4)}`;
return <Text>{display}</Text>;
}
+13
View File
@@ -0,0 +1,13 @@
import React from "react";
import { Text } from "ink";
export function MarkdownView({ content = "" }) {
// Render markdown as plain text with basic bold/italic stripping.
// For rich rendering, use marked-terminal externally before passing content.
const clean = content
.replace(/\*\*(.+?)\*\*/g, "$1")
.replace(/\*(.+?)\*/g, "$1")
.replace(/`(.+?)`/g, "$1")
.replace(/^#+\s+/gm, "");
return <Text>{clean}</Text>;
}
+38
View File
@@ -0,0 +1,38 @@
import React, { useState } from "react";
import { Box, Text, useInput } from "ink";
export function MenuSelect({ items = [], onSelect, initial = 0 }) {
const [idx, setIdx] = useState(Math.min(initial, Math.max(0, items.length - 1)));
useInput((input, key) => {
if (items.length === 0) return;
if (key.upArrow) setIdx((i) => (i - 1 + items.length) % items.length);
if (key.downArrow) setIdx((i) => (i + 1) % items.length);
if (key.return && onSelect) onSelect(items[idx]);
const n = parseInt(input, 10);
if (!isNaN(n) && n >= 1 && n <= items.length) {
const newIdx = n - 1;
setIdx(newIdx);
if (onSelect) onSelect(items[newIdx]);
}
});
return (
<Box flexDirection="column">
{items.map((item, i) => (
<Box key={i}>
<Text bold={i === idx} color={i === idx ? "yellow" : undefined} dimColor={item.disabled}>
{i === idx ? "▶ " : " "}
{item.label}
</Text>
{item.hint && (
<Text dimColor>
{" "}
{item.hint}
</Text>
)}
</Box>
))}
</Box>
);
}
+18
View File
@@ -0,0 +1,18 @@
import React from "react";
import { Box, Text } from "ink";
import TextInput from "ink-text-input";
export function MultilineInput({ label, value, onChange, placeholder }) {
return (
<Box flexDirection="column">
{label && (
<Text bold dimColor>
{label}
</Text>
)}
<Box borderStyle="single" borderColor="gray" paddingX={1}>
<TextInput value={value} onChange={onChange} placeholder={placeholder} />
</Box>
</Box>
);
}
+15
View File
@@ -0,0 +1,15 @@
import React from "react";
import { Box, Text } from "ink";
export function ProgressBar({ value = 0, max = 100, width = 20, color = "green" }) {
const pct = Math.min(1, Math.max(0, value / max));
const filled = Math.round(pct * width);
const empty = width - filled;
return (
<Box>
<Text color={color}>{"█".repeat(filled)}</Text>
<Text dimColor>{"░".repeat(empty)}</Text>
<Text> {Math.round(pct * 100)}%</Text>
</Box>
);
}
+15
View File
@@ -0,0 +1,15 @@
import React from "react";
import { Text } from "ink";
const BARS = ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"];
export function Sparkline({ data = [], color = "cyan", width = 10 }) {
const slice = data.slice(-width);
if (slice.length === 0) return <Text dimColor>{"─".repeat(width)}</Text>;
const max = Math.max(...slice, 1);
const chars = slice.map((v) => {
const idx = Math.round((v / max) * (BARS.length - 1));
return BARS[Math.min(Math.max(idx, 0), BARS.length - 1)];
});
return <Text color={color}>{chars.join("")}</Text>;
}
+17
View File
@@ -0,0 +1,17 @@
import React from "react";
import { Text } from "ink";
const STATUS_MAP = {
running: { label: "● running", color: "green" },
stopped: { label: "● stopped", color: "red" },
starting: { label: "◌ starting", color: "yellow" },
error: { label: "✗ error", color: "red" },
unknown: { label: "? unknown", color: "gray" },
ok: { label: "✓ ok", color: "green" },
warn: { label: "⚠ warn", color: "yellow" },
};
export function StatusBadge({ status = "unknown" }) {
const s = STATUS_MAP[status] ?? { label: status, color: "gray" };
return <Text color={s.color}>{s.label}</Text>;
}
+18
View File
@@ -0,0 +1,18 @@
import React from "react";
import { Box, Text } from "ink";
export function TokenCounter({ tokensIn = 0, tokensOut = 0, costUsd = 0, model }) {
return (
<Box flexDirection="column">
<Box>
<Text bold>In: </Text>
<Text>{tokensIn.toLocaleString()}</Text>
<Text bold> Out: </Text>
<Text>{tokensOut.toLocaleString()}</Text>
<Text bold> Cost: </Text>
<Text color="yellow">${costUsd.toFixed(4)}</Text>
</Box>
{model && <Text dimColor>Model: {model}</Text>}
</Box>
);
}
+11
View File
@@ -0,0 +1,11 @@
export const theme = {
primary: "cyan",
secondary: "yellow",
success: "green",
error: "red",
warning: "yellow",
muted: "gray",
header: "cyan",
selected: "blue",
border: "cyan",
};