@workerdeck/ui 0.7.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -3
- package/build/SessionPanel-CyhygZx_.d.mts +277 -0
- package/build/SessionPanel-_U8tjX29.mjs +8409 -0
- package/build/SessionPanel-_U8tjX29.mjs.map +1 -0
- package/build/format-DqR56Y8l.mjs +162 -0
- package/build/format-DqR56Y8l.mjs.map +1 -0
- package/build/format-ljc3lKpA.d.mts +59 -0
- package/build/format.d.mts +2 -0
- package/build/format.mjs +2 -0
- package/build/index.d.mts +615 -87
- package/build/index.mjs +6 -5081
- package/build/index.mjs.map +1 -1
- package/build/workspace.d.mts +199 -0
- package/build/workspace.mjs +849 -0
- package/build/workspace.mjs.map +1 -0
- package/package.json +22 -4
- package/src/components/agent/CodeEditor.tsx +300 -0
- package/src/components/agent/Composer.tsx +522 -87
- package/src/components/agent/ContextDialog.tsx +99 -0
- package/src/components/agent/Conversation.tsx +11 -3
- package/src/components/agent/EditorTabs.tsx +165 -0
- package/src/components/agent/FileCard.tsx +26 -0
- package/src/components/agent/FileTree.tsx +287 -0
- package/src/components/agent/FileViewer.tsx +148 -0
- package/src/components/agent/HostFilesDialog.tsx +218 -0
- package/src/components/agent/Loader.tsx +120 -14
- package/src/components/agent/McpDialog.tsx +363 -0
- package/src/components/agent/Message.tsx +51 -17
- package/src/components/agent/ModelSelect.tsx +34 -6
- package/src/components/agent/PermissionModeSelect.tsx +133 -22
- package/src/components/agent/PermissionPrompt.tsx +164 -6
- package/src/components/agent/PromptTokenText.tsx +39 -0
- package/src/components/agent/QuestionPrompt.tsx +122 -0
- package/src/components/agent/Reasoning.tsx +20 -5
- package/src/components/agent/Response.tsx +128 -0
- package/src/components/agent/SessionEmptyState.tsx +65 -0
- package/src/components/agent/SessionInfoDialog.tsx +163 -0
- package/src/components/agent/SessionPanel.tsx +756 -90
- package/src/components/agent/SessionWorkspace.tsx +282 -0
- package/src/components/agent/SkillsDialog.tsx +195 -0
- package/src/components/agent/StatusBar.tsx +85 -18
- package/src/components/agent/ToolCallCard.tsx +243 -30
- package/src/components/agent/Transcript.tsx +540 -27
- package/src/components/agent/UsageDialog.tsx +168 -0
- package/src/components/agent/line-prompt.tsx +249 -0
- package/src/components/agent/transcript-variant.tsx +61 -0
- package/src/components/prompt-area/prompt-area-engine.ts +53 -0
- package/src/components/prompt-area/types.ts +15 -0
- package/src/components/prompt-area/use-prompt-area.ts +20 -0
- package/src/components/ui/CodeBlock.tsx +40 -2
- package/src/components/ui/CopyButton.tsx +28 -3
- package/src/components/ui/Dialog.tsx +92 -0
- package/src/components/ui/Menu.tsx +55 -0
- package/src/components/ui/Splitter.tsx +133 -0
- package/src/components/ui/Tooltip.tsx +22 -5
- package/src/format.ts +10 -0
- package/src/index.ts +63 -2
- package/src/lib/clipboard.ts +56 -0
- package/src/lib/format.ts +114 -0
- package/src/lib/tool-icon.ts +96 -0
- package/src/workspace.ts +28 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
//#region src/lib/format.ts
|
|
2
|
+
function formatCost(usd) {
|
|
3
|
+
if (usd === void 0 || Number.isNaN(usd)) return "—";
|
|
4
|
+
if (usd === 0) return "$0.00";
|
|
5
|
+
if (usd < .01) return "<$0.01";
|
|
6
|
+
return `$${usd.toFixed(2)}`;
|
|
7
|
+
}
|
|
8
|
+
function formatDuration(ms) {
|
|
9
|
+
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
10
|
+
const s = ms / 1e3;
|
|
11
|
+
if (s < 60) return `${s.toFixed(1)}s`;
|
|
12
|
+
return `${Math.floor(s / 60)}m ${Math.round(s % 60)}s`;
|
|
13
|
+
}
|
|
14
|
+
/** Compact token count, Claude Code-style: 850 → "850", 359_000 → "359.0k", 1_200_000 → "1.2M". */
|
|
15
|
+
function formatTokens(tokens) {
|
|
16
|
+
if (tokens >= 1e6) return `${(tokens / 1e6).toFixed(1)}M`;
|
|
17
|
+
if (tokens >= 1e3) return `${(tokens / 1e3).toFixed(1)}k`;
|
|
18
|
+
return String(Math.round(tokens));
|
|
19
|
+
}
|
|
20
|
+
function formatBytes(bytes) {
|
|
21
|
+
if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
22
|
+
if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
23
|
+
return `${bytes} B`;
|
|
24
|
+
}
|
|
25
|
+
/** Countdown to an epoch-ms deadline: "2h 18m", "12m", "<1m"; "now" once passed. */
|
|
26
|
+
function formatCountdown(untilEpochMs, now = Date.now()) {
|
|
27
|
+
const remaining = untilEpochMs - now;
|
|
28
|
+
if (remaining <= 0) return "now";
|
|
29
|
+
const minutes = Math.ceil(remaining / 6e4);
|
|
30
|
+
if (minutes < 1) return "<1m";
|
|
31
|
+
if (minutes < 60) return `${minutes}m`;
|
|
32
|
+
const days = Math.floor(minutes / 1440);
|
|
33
|
+
if (days >= 1) return `${days}d ${Math.floor(minutes % 1440 / 60)}h`;
|
|
34
|
+
return `${Math.floor(minutes / 60)}h ${minutes % 60}m`;
|
|
35
|
+
}
|
|
36
|
+
function formatRelativeTime(epochMs, now = Date.now()) {
|
|
37
|
+
if (!epochMs) return "—";
|
|
38
|
+
const diff = Math.max(0, now - epochMs);
|
|
39
|
+
const s = Math.floor(diff / 1e3);
|
|
40
|
+
if (s < 60) return "just now";
|
|
41
|
+
const m = Math.floor(s / 60);
|
|
42
|
+
if (m < 60) return `${m}m ago`;
|
|
43
|
+
const h = Math.floor(m / 60);
|
|
44
|
+
if (h < 24) return `${h}h ago`;
|
|
45
|
+
return `${Math.floor(h / 24)}d ago`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Human label for a rate-limit window key, compact: 'five_hour' → "5h",
|
|
49
|
+
* 'seven_day_opus' → "7d opus". The per-model suffix is an open set — the CLI
|
|
50
|
+
* adds buckets as plans gain them — so it is rewritten rather than enumerated.
|
|
51
|
+
*/
|
|
52
|
+
function formatRateLimitWindow(key) {
|
|
53
|
+
if (key === "five_hour") return "5h";
|
|
54
|
+
if (key === "seven_day") return "7d";
|
|
55
|
+
const spaced = key.replaceAll("_", " ");
|
|
56
|
+
return key.startsWith("seven_day_") ? `7d ${spaced.slice(10)}` : spaced;
|
|
57
|
+
}
|
|
58
|
+
/** The same key spelled out, where there is room: 'five_hour' → "5-hour
|
|
59
|
+
* session", 'seven_day_fable' → "Weekly · Fable". */
|
|
60
|
+
function formatRateLimitWindowLong(key) {
|
|
61
|
+
if (key === "five_hour") return "5-hour session";
|
|
62
|
+
if (key === "seven_day") return "Weekly";
|
|
63
|
+
if (key === "seven_day_oauth_apps") return "Weekly · apps";
|
|
64
|
+
const capitalize = (s) => s.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
65
|
+
if (!key.startsWith("seven_day_")) return capitalize(key.replaceAll("_", " "));
|
|
66
|
+
return `Weekly · ${capitalize(key.slice(10).replaceAll("_", " "))}`;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* How long a rate-limit window is, in seconds — the denominator behind the pace
|
|
70
|
+
* marker. Derived from the key rather than reported: the CLI sends a reset time
|
|
71
|
+
* and a percentage, never a duration. `undefined` for a window whose key doesn't
|
|
72
|
+
* say, and the marker is then simply not drawn rather than guessed.
|
|
73
|
+
*/
|
|
74
|
+
function rateLimitWindowSeconds(key) {
|
|
75
|
+
if (key === "five_hour") return 5 * 3600;
|
|
76
|
+
if (key.startsWith("seven_day")) return 7 * 86400;
|
|
77
|
+
}
|
|
78
|
+
/** "8 secs ago" / "3 mins ago" — a freshness line finer-grained than
|
|
79
|
+
* {@link formatRelativeTime}, because a poll that just landed should say so. */
|
|
80
|
+
function formatAgoPrecise(epochMs, now = Date.now()) {
|
|
81
|
+
const seconds = Math.max(0, Math.floor((now - epochMs) / 1e3));
|
|
82
|
+
if (seconds < 60) return `${seconds} sec${seconds === 1 ? "" : "s"} ago`;
|
|
83
|
+
if (seconds < 3600) {
|
|
84
|
+
const minutes = Math.floor(seconds / 60);
|
|
85
|
+
return `${minutes} min${minutes === 1 ? "" : "s"} ago`;
|
|
86
|
+
}
|
|
87
|
+
const hours = Math.floor(seconds / 3600);
|
|
88
|
+
return `${hours} hour${hours === 1 ? "" : "s"} ago`;
|
|
89
|
+
}
|
|
90
|
+
/** Compact one-line preview of a tool input for card headers. */
|
|
91
|
+
function toolInputPreview(input, max = 80) {
|
|
92
|
+
if (input === null || input === void 0) return "";
|
|
93
|
+
if (typeof input === "object") {
|
|
94
|
+
const o = input;
|
|
95
|
+
const primary = o.command ?? o.file_path ?? o.path ?? o.url ?? o.pattern ?? o.query ?? o.description;
|
|
96
|
+
if (typeof primary === "string") return primary.length > max ? primary.slice(0, max - 1) + "…" : primary;
|
|
97
|
+
}
|
|
98
|
+
const text = JSON.stringify(input) ?? "";
|
|
99
|
+
return text.length > max ? text.slice(0, max - 1) + "…" : text;
|
|
100
|
+
}
|
|
101
|
+
/** Families whose name isn't just a capitalised first letter, and how the
|
|
102
|
+
* vendor writes the version after it. GPT is `GPT-5.6`; everyone else spaces
|
|
103
|
+
* it. Anything unlisted is title-cased and spaced. */
|
|
104
|
+
const MODEL_FAMILIES = {
|
|
105
|
+
gpt: {
|
|
106
|
+
name: "GPT",
|
|
107
|
+
joiner: "-"
|
|
108
|
+
},
|
|
109
|
+
deepseek: { name: "DeepSeek" },
|
|
110
|
+
glm: { name: "GLM" },
|
|
111
|
+
qwen: { name: "Qwen" },
|
|
112
|
+
kimi: { name: "Kimi" },
|
|
113
|
+
llama: { name: "Llama" },
|
|
114
|
+
mistral: { name: "Mistral" },
|
|
115
|
+
grok: { name: "Grok" }
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* The name a person says, from a wire model id:
|
|
119
|
+
*
|
|
120
|
+
* - `claude-opus-5[1m]` → "Opus 5"
|
|
121
|
+
* - `claude-haiku-4-5-20251001` → "Haiku 4.5"
|
|
122
|
+
* - `gpt-5.6-luna` → "GPT-5.6 Luna"
|
|
123
|
+
* - `gemini-2.5-pro` → "Gemini 2.5 Pro"
|
|
124
|
+
* - `o3-mini` → "o3 Mini"
|
|
125
|
+
*
|
|
126
|
+
* Three kinds of token after the family, because vendors mix them freely: a
|
|
127
|
+
* **version** (`5`, `4-5`, `5.6` — joined with dots, since Anthropic splits what
|
|
128
|
+
* OpenAI writes as one token), a **code name or tier** (`luna`, `codex`, `pro`,
|
|
129
|
+
* `mini` — kept and capitalised, since it is often the only thing telling two
|
|
130
|
+
* models apart), and a **snapshot date** (`20251001` — dropped; it is a build,
|
|
131
|
+
* not a version).
|
|
132
|
+
*
|
|
133
|
+
* Anything genuinely unreadable falls back to the id: a wrong name is worse than
|
|
134
|
+
* a raw one, which is at least true.
|
|
135
|
+
*
|
|
136
|
+
* The server has a narrower version of this (`friendlyModelName` in core's
|
|
137
|
+
* `normalize.ts`) that derives Claude catalog names at authoring time. This one
|
|
138
|
+
* is the *render-time* fallback for an id with no catalog row behind it — the
|
|
139
|
+
* sidebar has only `SessionInfo.model` — so it has to cope with every vendor the
|
|
140
|
+
* provider engine can reach, not just the CLI's own.
|
|
141
|
+
*/
|
|
142
|
+
function friendlyModel(id) {
|
|
143
|
+
if (!id) return void 0;
|
|
144
|
+
const parts = (id.split("[")[0] ?? id).toLowerCase().split("-").filter(Boolean);
|
|
145
|
+
if (parts[0] === "claude") parts.shift();
|
|
146
|
+
const familyToken = parts.shift();
|
|
147
|
+
if (!familyToken) return id;
|
|
148
|
+
const family = MODEL_FAMILIES[familyToken];
|
|
149
|
+
const name = family?.name ?? (/^o\d+$/.test(familyToken) ? familyToken : `${familyToken.charAt(0).toUpperCase()}${familyToken.slice(1)}`);
|
|
150
|
+
const version = [];
|
|
151
|
+
const words = [];
|
|
152
|
+
for (const part of parts) {
|
|
153
|
+
if (/^\d{8}$/.test(part)) continue;
|
|
154
|
+
if (/^\d+(\.\d+)?$/.test(part)) version.push(part);
|
|
155
|
+
else words.push(`${part.charAt(0).toUpperCase()}${part.slice(1)}`);
|
|
156
|
+
}
|
|
157
|
+
return [version.length > 0 ? `${name}${family?.joiner ?? " "}${version.join(".")}` : name, ...words].join(" ");
|
|
158
|
+
}
|
|
159
|
+
//#endregion
|
|
160
|
+
export { formatDuration as a, formatRelativeTime as c, rateLimitWindowSeconds as d, toolInputPreview as f, formatCountdown as i, formatTokens as l, formatBytes as n, formatRateLimitWindow as o, formatCost as r, formatRateLimitWindowLong as s, formatAgoPrecise as t, friendlyModel as u };
|
|
161
|
+
|
|
162
|
+
//# sourceMappingURL=format-DqR56Y8l.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-DqR56Y8l.mjs","names":[],"sources":["../src/lib/format.ts"],"sourcesContent":["export function formatCost(usd: number | undefined): string {\n if (usd === undefined || Number.isNaN(usd)) return '—'\n if (usd === 0) return '$0.00'\n if (usd < 0.01) return '<$0.01'\n return `$${usd.toFixed(2)}`\n}\n\nexport function formatDuration(ms: number): string {\n if (ms < 1000) return `${Math.round(ms)}ms`\n const s = ms / 1000\n if (s < 60) return `${s.toFixed(1)}s`\n const m = Math.floor(s / 60)\n return `${m}m ${Math.round(s % 60)}s`\n}\n\n/** Compact token count, Claude Code-style: 850 → \"850\", 359_000 → \"359.0k\", 1_200_000 → \"1.2M\". */\nexport function formatTokens(tokens: number): string {\n if (tokens >= 1_000_000) return `${(tokens / 1_000_000).toFixed(1)}M`\n if (tokens >= 1000) return `${(tokens / 1000).toFixed(1)}k`\n return String(Math.round(tokens))\n}\n\nexport function formatBytes(bytes: number): string {\n if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${bytes} B`\n}\n\n/** Countdown to an epoch-ms deadline: \"2h 18m\", \"12m\", \"<1m\"; \"now\" once passed. */\nexport function formatCountdown(untilEpochMs: number, now = Date.now()): string {\n const remaining = untilEpochMs - now\n if (remaining <= 0) return 'now'\n const minutes = Math.ceil(remaining / 60_000)\n if (minutes < 1) return '<1m'\n if (minutes < 60) return `${minutes}m`\n const days = Math.floor(minutes / (60 * 24))\n if (days >= 1) return `${days}d ${Math.floor((minutes % (60 * 24)) / 60)}h`\n return `${Math.floor(minutes / 60)}h ${minutes % 60}m`\n}\n\nexport function formatRelativeTime(epochMs: number | undefined, now = Date.now()): string {\n if (!epochMs) return '—'\n const diff = Math.max(0, now - epochMs)\n const s = Math.floor(diff / 1000)\n if (s < 60) return 'just now'\n const m = Math.floor(s / 60)\n if (m < 60) return `${m}m ago`\n const h = Math.floor(m / 60)\n if (h < 24) return `${h}h ago`\n const d = Math.floor(h / 24)\n return `${d}d ago`\n}\n\n/**\n * Human label for a rate-limit window key, compact: 'five_hour' → \"5h\",\n * 'seven_day_opus' → \"7d opus\". The per-model suffix is an open set — the CLI\n * adds buckets as plans gain them — so it is rewritten rather than enumerated.\n */\nexport function formatRateLimitWindow(key: string): string {\n if (key === 'five_hour') return '5h'\n if (key === 'seven_day') return '7d'\n const spaced = key.replaceAll('_', ' ')\n return key.startsWith('seven_day_') ? `7d ${spaced.slice('seven day '.length)}` : spaced\n}\n\n/** The same key spelled out, where there is room: 'five_hour' → \"5-hour\n * session\", 'seven_day_fable' → \"Weekly · Fable\". */\nexport function formatRateLimitWindowLong(key: string): string {\n if (key === 'five_hour') return '5-hour session'\n if (key === 'seven_day') return 'Weekly'\n if (key === 'seven_day_oauth_apps') return 'Weekly · apps'\n const capitalize = (s: string) => s.replace(/\\b\\w/g, (c) => c.toUpperCase())\n if (!key.startsWith('seven_day_')) return capitalize(key.replaceAll('_', ' '))\n return `Weekly · ${capitalize(key.slice('seven_day_'.length).replaceAll('_', ' '))}`\n}\n\n/**\n * How long a rate-limit window is, in seconds — the denominator behind the pace\n * marker. Derived from the key rather than reported: the CLI sends a reset time\n * and a percentage, never a duration. `undefined` for a window whose key doesn't\n * say, and the marker is then simply not drawn rather than guessed.\n */\nexport function rateLimitWindowSeconds(key: string): number | undefined {\n if (key === 'five_hour') return 5 * 3600\n if (key.startsWith('seven_day')) return 7 * 86_400\n return undefined\n}\n\n/** \"8 secs ago\" / \"3 mins ago\" — a freshness line finer-grained than\n * {@link formatRelativeTime}, because a poll that just landed should say so. */\nexport function formatAgoPrecise(epochMs: number, now = Date.now()): string {\n const seconds = Math.max(0, Math.floor((now - epochMs) / 1000))\n if (seconds < 60) return `${seconds} sec${seconds === 1 ? '' : 's'} ago`\n if (seconds < 3600) {\n const minutes = Math.floor(seconds / 60)\n return `${minutes} min${minutes === 1 ? '' : 's'} ago`\n }\n const hours = Math.floor(seconds / 3600)\n return `${hours} hour${hours === 1 ? '' : 's'} ago`\n}\n\n/** Compact one-line preview of a tool input for card headers. */\nexport function toolInputPreview(input: unknown, max = 80): string {\n if (input === null || input === undefined) return ''\n if (typeof input === 'object') {\n const o = input as Record<string, unknown>\n const primary =\n o.command ?? o.file_path ?? o.path ?? o.url ?? o.pattern ?? o.query ?? o.description\n if (typeof primary === 'string') {\n return primary.length > max ? primary.slice(0, max - 1) + '…' : primary\n }\n }\n const text = JSON.stringify(input) ?? ''\n return text.length > max ? text.slice(0, max - 1) + '…' : text\n}\n\n/** Families whose name isn't just a capitalised first letter, and how the\n * vendor writes the version after it. GPT is `GPT-5.6`; everyone else spaces\n * it. Anything unlisted is title-cased and spaced. */\nconst MODEL_FAMILIES: Record<string, { name: string; joiner?: string }> = {\n gpt: { name: 'GPT', joiner: '-' },\n deepseek: { name: 'DeepSeek' },\n glm: { name: 'GLM' },\n qwen: { name: 'Qwen' },\n kimi: { name: 'Kimi' },\n llama: { name: 'Llama' },\n mistral: { name: 'Mistral' },\n grok: { name: 'Grok' },\n}\n\n/**\n * The name a person says, from a wire model id:\n *\n * - `claude-opus-5[1m]` → \"Opus 5\"\n * - `claude-haiku-4-5-20251001` → \"Haiku 4.5\"\n * - `gpt-5.6-luna` → \"GPT-5.6 Luna\"\n * - `gemini-2.5-pro` → \"Gemini 2.5 Pro\"\n * - `o3-mini` → \"o3 Mini\"\n *\n * Three kinds of token after the family, because vendors mix them freely: a\n * **version** (`5`, `4-5`, `5.6` — joined with dots, since Anthropic splits what\n * OpenAI writes as one token), a **code name or tier** (`luna`, `codex`, `pro`,\n * `mini` — kept and capitalised, since it is often the only thing telling two\n * models apart), and a **snapshot date** (`20251001` — dropped; it is a build,\n * not a version).\n *\n * Anything genuinely unreadable falls back to the id: a wrong name is worse than\n * a raw one, which is at least true.\n *\n * The server has a narrower version of this (`friendlyModelName` in core's\n * `normalize.ts`) that derives Claude catalog names at authoring time. This one\n * is the *render-time* fallback for an id with no catalog row behind it — the\n * sidebar has only `SessionInfo.model` — so it has to cope with every vendor the\n * provider engine can reach, not just the CLI's own.\n */\nexport function friendlyModel(id: string | undefined): string | undefined {\n if (!id) return undefined\n const withoutVariant = id.split('[')[0] ?? id\n const parts = withoutVariant.toLowerCase().split('-').filter(Boolean)\n if (parts[0] === 'claude') parts.shift()\n const familyToken = parts.shift()\n if (!familyToken) return id\n const family = MODEL_FAMILIES[familyToken]\n const name =\n family?.name ??\n // OpenAI's reasoning series is lower-case by its own convention ('o3-mini'),\n // and \"O3\" reads as a different product.\n (/^o\\d+$/.test(familyToken)\n ? familyToken\n : `${familyToken.charAt(0).toUpperCase()}${familyToken.slice(1)}`)\n\n const version: string[] = []\n const words: string[] = []\n for (const part of parts) {\n if (/^\\d{8}$/.test(part)) continue\n if (/^\\d+(\\.\\d+)?$/.test(part)) version.push(part)\n else words.push(`${part.charAt(0).toUpperCase()}${part.slice(1)}`)\n }\n const versioned = version.length > 0 ? `${name}${family?.joiner ?? ' '}${version.join('.')}` : name\n return [versioned, ...words].join(' ')\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
//#region src/lib/format.d.ts
|
|
2
|
+
declare function formatCost(usd: number | undefined): string;
|
|
3
|
+
declare function formatDuration(ms: number): string;
|
|
4
|
+
/** Compact token count, Claude Code-style: 850 → "850", 359_000 → "359.0k", 1_200_000 → "1.2M". */
|
|
5
|
+
declare function formatTokens(tokens: number): string;
|
|
6
|
+
declare function formatBytes(bytes: number): string;
|
|
7
|
+
/** Countdown to an epoch-ms deadline: "2h 18m", "12m", "<1m"; "now" once passed. */
|
|
8
|
+
declare function formatCountdown(untilEpochMs: number, now?: number): string;
|
|
9
|
+
declare function formatRelativeTime(epochMs: number | undefined, now?: number): string;
|
|
10
|
+
/**
|
|
11
|
+
* Human label for a rate-limit window key, compact: 'five_hour' → "5h",
|
|
12
|
+
* 'seven_day_opus' → "7d opus". The per-model suffix is an open set — the CLI
|
|
13
|
+
* adds buckets as plans gain them — so it is rewritten rather than enumerated.
|
|
14
|
+
*/
|
|
15
|
+
declare function formatRateLimitWindow(key: string): string;
|
|
16
|
+
/** The same key spelled out, where there is room: 'five_hour' → "5-hour
|
|
17
|
+
* session", 'seven_day_fable' → "Weekly · Fable". */
|
|
18
|
+
declare function formatRateLimitWindowLong(key: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* How long a rate-limit window is, in seconds — the denominator behind the pace
|
|
21
|
+
* marker. Derived from the key rather than reported: the CLI sends a reset time
|
|
22
|
+
* and a percentage, never a duration. `undefined` for a window whose key doesn't
|
|
23
|
+
* say, and the marker is then simply not drawn rather than guessed.
|
|
24
|
+
*/
|
|
25
|
+
declare function rateLimitWindowSeconds(key: string): number | undefined;
|
|
26
|
+
/** "8 secs ago" / "3 mins ago" — a freshness line finer-grained than
|
|
27
|
+
* {@link formatRelativeTime}, because a poll that just landed should say so. */
|
|
28
|
+
declare function formatAgoPrecise(epochMs: number, now?: number): string;
|
|
29
|
+
/** Compact one-line preview of a tool input for card headers. */
|
|
30
|
+
declare function toolInputPreview(input: unknown, max?: number): string;
|
|
31
|
+
/**
|
|
32
|
+
* The name a person says, from a wire model id:
|
|
33
|
+
*
|
|
34
|
+
* - `claude-opus-5[1m]` → "Opus 5"
|
|
35
|
+
* - `claude-haiku-4-5-20251001` → "Haiku 4.5"
|
|
36
|
+
* - `gpt-5.6-luna` → "GPT-5.6 Luna"
|
|
37
|
+
* - `gemini-2.5-pro` → "Gemini 2.5 Pro"
|
|
38
|
+
* - `o3-mini` → "o3 Mini"
|
|
39
|
+
*
|
|
40
|
+
* Three kinds of token after the family, because vendors mix them freely: a
|
|
41
|
+
* **version** (`5`, `4-5`, `5.6` — joined with dots, since Anthropic splits what
|
|
42
|
+
* OpenAI writes as one token), a **code name or tier** (`luna`, `codex`, `pro`,
|
|
43
|
+
* `mini` — kept and capitalised, since it is often the only thing telling two
|
|
44
|
+
* models apart), and a **snapshot date** (`20251001` — dropped; it is a build,
|
|
45
|
+
* not a version).
|
|
46
|
+
*
|
|
47
|
+
* Anything genuinely unreadable falls back to the id: a wrong name is worse than
|
|
48
|
+
* a raw one, which is at least true.
|
|
49
|
+
*
|
|
50
|
+
* The server has a narrower version of this (`friendlyModelName` in core's
|
|
51
|
+
* `normalize.ts`) that derives Claude catalog names at authoring time. This one
|
|
52
|
+
* is the *render-time* fallback for an id with no catalog row behind it — the
|
|
53
|
+
* sidebar has only `SessionInfo.model` — so it has to cope with every vendor the
|
|
54
|
+
* provider engine can reach, not just the CLI's own.
|
|
55
|
+
*/
|
|
56
|
+
declare function friendlyModel(id: string | undefined): string | undefined;
|
|
57
|
+
//#endregion
|
|
58
|
+
export { formatDuration as a, formatRelativeTime as c, rateLimitWindowSeconds as d, toolInputPreview as f, formatCountdown as i, formatTokens as l, formatBytes as n, formatRateLimitWindow as o, formatCost as r, formatRateLimitWindowLong as s, formatAgoPrecise as t, friendlyModel as u };
|
|
59
|
+
//# sourceMappingURL=format-ljc3lKpA.d.mts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as formatDuration, c as formatRelativeTime, d as rateLimitWindowSeconds, f as toolInputPreview, i as formatCountdown, l as formatTokens, n as formatBytes, o as formatRateLimitWindow, r as formatCost, s as formatRateLimitWindowLong, t as formatAgoPrecise, u as friendlyModel } from "./format-ljc3lKpA.mjs";
|
|
2
|
+
export { formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, rateLimitWindowSeconds, toolInputPreview };
|
package/build/format.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as formatDuration, c as formatRelativeTime, d as rateLimitWindowSeconds, f as toolInputPreview, i as formatCountdown, l as formatTokens, n as formatBytes, o as formatRateLimitWindow, r as formatCost, s as formatRateLimitWindowLong, t as formatAgoPrecise, u as friendlyModel } from "./format-DqR56Y8l.mjs";
|
|
2
|
+
export { formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, rateLimitWindowSeconds, toolInputPreview };
|