@prometheus-ai/utils 0.5.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.
Files changed (61) hide show
  1. package/dist/types/abortable.d.ts +27 -0
  2. package/dist/types/async.d.ts +6 -0
  3. package/dist/types/cli.d.ts +117 -0
  4. package/dist/types/color.d.ts +102 -0
  5. package/dist/types/dirs.d.ts +171 -0
  6. package/dist/types/env.d.ts +55 -0
  7. package/dist/types/fetch-retry.d.ts +80 -0
  8. package/dist/types/format.d.ts +37 -0
  9. package/dist/types/frontmatter.d.ts +25 -0
  10. package/dist/types/fs-error.d.ts +31 -0
  11. package/dist/types/glob.d.ts +28 -0
  12. package/dist/types/hook-fetch.d.ts +16 -0
  13. package/dist/types/index.d.ts +29 -0
  14. package/dist/types/json.d.ts +4 -0
  15. package/dist/types/logger.d.ts +66 -0
  16. package/dist/types/mermaid-ascii.d.ts +11 -0
  17. package/dist/types/mime.d.ts +29 -0
  18. package/dist/types/peek-file.d.ts +29 -0
  19. package/dist/types/postmortem.d.ts +29 -0
  20. package/dist/types/procmgr.d.ts +25 -0
  21. package/dist/types/prompt.d.ts +18 -0
  22. package/dist/types/ptree.d.ts +108 -0
  23. package/dist/types/ring.d.ts +93 -0
  24. package/dist/types/sanitize-text.d.ts +14 -0
  25. package/dist/types/snowflake.d.ts +25 -0
  26. package/dist/types/stream.d.ts +68 -0
  27. package/dist/types/tab-spacing.d.ts +9 -0
  28. package/dist/types/temp.d.ts +14 -0
  29. package/dist/types/type-guards.d.ts +3 -0
  30. package/dist/types/which.d.ts +37 -0
  31. package/package.json +61 -0
  32. package/src/abortable.ts +73 -0
  33. package/src/async.ts +50 -0
  34. package/src/cli.ts +432 -0
  35. package/src/color.ts +302 -0
  36. package/src/dirs.ts +584 -0
  37. package/src/env.ts +172 -0
  38. package/src/fetch-retry.ts +325 -0
  39. package/src/format.ts +113 -0
  40. package/src/frontmatter.ts +128 -0
  41. package/src/fs-error.ts +56 -0
  42. package/src/glob.ts +189 -0
  43. package/src/hook-fetch.ts +30 -0
  44. package/src/index.ts +49 -0
  45. package/src/json.ts +10 -0
  46. package/src/logger.ts +417 -0
  47. package/src/mermaid-ascii.ts +31 -0
  48. package/src/mime.ts +159 -0
  49. package/src/peek-file.ts +188 -0
  50. package/src/postmortem.ts +196 -0
  51. package/src/procmgr.ts +195 -0
  52. package/src/prompt.ts +471 -0
  53. package/src/ptree.ts +390 -0
  54. package/src/ring.ts +169 -0
  55. package/src/sanitize-text.ts +38 -0
  56. package/src/snowflake.ts +136 -0
  57. package/src/stream.ts +403 -0
  58. package/src/tab-spacing.ts +342 -0
  59. package/src/temp.ts +77 -0
  60. package/src/type-guards.ts +11 -0
  61. package/src/which.ts +232 -0
package/src/color.ts ADDED
@@ -0,0 +1,302 @@
1
+ /**
2
+ * Color manipulation utilities for hex colors.
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * import { hexToHsv, hsvToHex } from "@prometheus-ai/utils";
7
+ *
8
+ * // Rotate the hue by 90°
9
+ * const hsv = hexToHsv("#4ade80");
10
+ * hsv.h = (hsv.h + 90) % 360;
11
+ * const newHex = hsvToHex(hsv);
12
+ * ```
13
+ */
14
+
15
+ export interface HSV {
16
+ /** Hue in degrees (0-360) */
17
+ h: number;
18
+ /** Saturation (0-1) */
19
+ s: number;
20
+ /** Value/brightness (0-1) */
21
+ v: number;
22
+ }
23
+
24
+ export interface RGB {
25
+ /** Red (0-255) */
26
+ r: number;
27
+ /** Green (0-255) */
28
+ g: number;
29
+ /** Blue (0-255) */
30
+ b: number;
31
+ }
32
+
33
+ /**
34
+ * Parse a hex color string to RGB.
35
+ * Supports #RGB, #RRGGBB formats.
36
+ */
37
+ export function hexToRgb(hex: string): RGB {
38
+ const h = hex.startsWith("#") ? hex.slice(1) : hex;
39
+ if (h.length === 3) {
40
+ return {
41
+ r: parseInt(h[0] + h[0], 16),
42
+ g: parseInt(h[1] + h[1], 16),
43
+ b: parseInt(h[2] + h[2], 16),
44
+ };
45
+ }
46
+ return {
47
+ r: parseInt(h.slice(0, 2), 16),
48
+ g: parseInt(h.slice(2, 4), 16),
49
+ b: parseInt(h.slice(4, 6), 16),
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Convert RGB to hex color string.
55
+ */
56
+ export function rgbToHex(rgb: RGB): string {
57
+ const toHex = (n: number) =>
58
+ Math.max(0, Math.min(255, Math.round(n)))
59
+ .toString(16)
60
+ .padStart(2, "0");
61
+ return `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`;
62
+ }
63
+
64
+ /**
65
+ * Convert RGB to HSV.
66
+ */
67
+ export function rgbToHsv(rgb: RGB): HSV {
68
+ const r = rgb.r / 255;
69
+ const g = rgb.g / 255;
70
+ const b = rgb.b / 255;
71
+
72
+ const max = Math.max(r, g, b);
73
+ const min = Math.min(r, g, b);
74
+ const d = max - min;
75
+
76
+ let h = 0;
77
+ if (d !== 0) {
78
+ if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
79
+ else if (max === g) h = ((b - r) / d + 2) / 6;
80
+ else h = ((r - g) / d + 4) / 6;
81
+ }
82
+
83
+ return {
84
+ h: h * 360,
85
+ s: max === 0 ? 0 : d / max,
86
+ v: max,
87
+ };
88
+ }
89
+
90
+ /**
91
+ * Convert HSV to RGB.
92
+ */
93
+ export function hsvToRgb(hsv: HSV): RGB {
94
+ const { s, v } = hsv;
95
+ const h = ((hsv.h % 360) + 360) % 360; // Normalize to 0-360
96
+
97
+ const i = Math.floor(h / 60);
98
+ const f = h / 60 - i;
99
+ const p = v * (1 - s);
100
+ const q = v * (1 - f * s);
101
+ const t = v * (1 - (1 - f) * s);
102
+
103
+ let r: number, g: number, b: number;
104
+ switch (i % 6) {
105
+ case 0:
106
+ r = v;
107
+ g = t;
108
+ b = p;
109
+ break;
110
+ case 1:
111
+ r = q;
112
+ g = v;
113
+ b = p;
114
+ break;
115
+ case 2:
116
+ r = p;
117
+ g = v;
118
+ b = t;
119
+ break;
120
+ case 3:
121
+ r = p;
122
+ g = q;
123
+ b = v;
124
+ break;
125
+ case 4:
126
+ r = t;
127
+ g = p;
128
+ b = v;
129
+ break;
130
+ default:
131
+ r = v;
132
+ g = p;
133
+ b = q;
134
+ break;
135
+ }
136
+
137
+ return {
138
+ r: Math.round(r * 255),
139
+ g: Math.round(g * 255),
140
+ b: Math.round(b * 255),
141
+ };
142
+ }
143
+
144
+ /**
145
+ * Convert hex color to HSV.
146
+ */
147
+ export function hexToHsv(hex: string): HSV {
148
+ return rgbToHsv(hexToRgb(hex));
149
+ }
150
+
151
+ /**
152
+ * Convert HSV to hex color.
153
+ */
154
+ export function hsvToHex(hsv: HSV): string {
155
+ return rgbToHex(hsvToRgb(hsv));
156
+ }
157
+
158
+ /**
159
+ * Shift the hue of a hex color by a given number of degrees.
160
+ */
161
+ export function shiftHue(hex: string, degrees: number): string {
162
+ const hsv = hexToHsv(hex);
163
+ hsv.h = (hsv.h + degrees) % 360;
164
+ if (hsv.h < 0) hsv.h += 360;
165
+ return hsvToHex(hsv);
166
+ }
167
+ export interface HSVAdjustment {
168
+ /** Hue shift in degrees (additive) */
169
+ h?: number;
170
+ /** Saturation multiplier */
171
+ s?: number;
172
+ /** Value/brightness multiplier */
173
+ v?: number;
174
+ }
175
+
176
+ /**
177
+ * Adjust HSV components of a hex color.
178
+ *
179
+ * @param hex - Hex color string (#RGB or #RRGGBB)
180
+ * @param adj - Adjustments: h is additive degrees, s and v are multipliers
181
+ * @returns New hex color string
182
+ *
183
+ * @example
184
+ * ```ts
185
+ * // Shift hue +60°, reduce saturation to 71%
186
+ * adjustHsv("#00ff88", { h: 60, s: 0.71 }) // "#4a9eff"
187
+ * ```
188
+ */
189
+ export function adjustHsv(hex: string, adj: HSVAdjustment): string {
190
+ const hsv = hexToHsv(hex);
191
+ if (adj.h !== undefined) {
192
+ hsv.h = (hsv.h + adj.h) % 360;
193
+ if (hsv.h < 0) hsv.h += 360;
194
+ }
195
+ if (adj.s !== undefined) {
196
+ hsv.s = Math.max(0, Math.min(1, hsv.s * adj.s));
197
+ }
198
+ if (adj.v !== undefined) {
199
+ hsv.v = Math.max(0, Math.min(1, hsv.v * adj.v));
200
+ }
201
+ return hsvToHex(hsv);
202
+ }
203
+
204
+ /**
205
+ * Convert HSL (h: 0-360, s: 0-1, l: 0-1) to a CSS hex string.
206
+ */
207
+ export function hslToHex(h: number, s: number, l: number): string {
208
+ const a = s * Math.min(l, 1 - l);
209
+ const f = (n: number) => {
210
+ const k = (n + h / 30) % 12;
211
+ const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
212
+ return Math.round(255 * color)
213
+ .toString(16)
214
+ .padStart(2, "0");
215
+ };
216
+ return `#${f(0)}${f(8)}${f(4)}`;
217
+ }
218
+
219
+ // Conventional xterm RGB for the 16 base ANSI colors. Terminals may remap these,
220
+ // so they're a best-effort approximation for light/dark classification.
221
+ const ANSI_16: readonly (readonly [number, number, number])[] = [
222
+ [0, 0, 0],
223
+ [128, 0, 0],
224
+ [0, 128, 0],
225
+ [128, 128, 0],
226
+ [0, 0, 128],
227
+ [128, 0, 128],
228
+ [0, 128, 128],
229
+ [192, 192, 192],
230
+ [128, 128, 128],
231
+ [255, 0, 0],
232
+ [0, 255, 0],
233
+ [255, 255, 0],
234
+ [0, 0, 255],
235
+ [255, 0, 255],
236
+ [0, 255, 255],
237
+ [255, 255, 255],
238
+ ];
239
+ const CUBE_STEPS = [0, 95, 135, 175, 215, 255] as const;
240
+
241
+ /** Parse a 256-color palette index (0–255) to RGB (0..255). */
242
+ function paletteToRgb(index: number): RGB | undefined {
243
+ if (!Number.isInteger(index) || index < 0 || index > 255) return undefined;
244
+ if (index < 16) {
245
+ const rgb = ANSI_16[index];
246
+ return rgb ? { r: rgb[0], g: rgb[1], b: rgb[2] } : undefined;
247
+ }
248
+ if (index < 232) {
249
+ const n = index - 16;
250
+ return {
251
+ r: CUBE_STEPS[Math.floor(n / 36) % 6] ?? 0,
252
+ g: CUBE_STEPS[Math.floor(n / 6) % 6] ?? 0,
253
+ b: CUBE_STEPS[n % 6] ?? 0,
254
+ };
255
+ }
256
+ const gray = 8 + (index - 232) * 10;
257
+ return { r: gray, g: gray, b: gray };
258
+ }
259
+
260
+ /** Parse a theme color value — `#rgb`/`#rrggbb` hex or 256-color palette index — to RGB (0..255). */
261
+ function toRgb(value: string | number): RGB | undefined {
262
+ if (typeof value === "number") return paletteToRgb(value);
263
+ if (typeof value !== "string" || value[0] !== "#") return undefined;
264
+ if (value.length !== 4 && value.length !== 7) return undefined;
265
+ const rgb = hexToRgb(value);
266
+ if (Number.isNaN(rgb.r) || Number.isNaN(rgb.g) || Number.isNaN(rgb.b)) return undefined;
267
+ return rgb;
268
+ }
269
+
270
+ /** Gamma-decode a single 0..255 sRGB channel to linear 0..1. */
271
+ function linearizeChannel(channel: number): number {
272
+ const c = channel / 255;
273
+ return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
274
+ }
275
+
276
+ /**
277
+ * Perceptual luma (gamma-encoded BT.709 weights over raw sRGB), normalized to 0..1.
278
+ *
279
+ * Accepts a hex string (`#rgb` / `#rrggbb`) or a 256-color palette index; returns
280
+ * `undefined` for var refs, empty strings, or anything unparseable.
281
+ *
282
+ * Cheap and good enough for a light/dark *classification* threshold. NOT suitable
283
+ * for contrast ratios — use {@link relativeLuminance} for those.
284
+ */
285
+ export function colorLuma(value: string | number): number | undefined {
286
+ const rgb = toRgb(value);
287
+ if (!rgb) return undefined;
288
+ return (0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b) / 255;
289
+ }
290
+
291
+ /**
292
+ * WCAG 2.x relative luminance (BT.709 weights over linearized sRGB), normalized to
293
+ * 0..1. This is the value the WCAG contrast-ratio formula expects.
294
+ *
295
+ * Accepts a hex string (`#rgb` / `#rrggbb`) or a 256-color palette index; returns
296
+ * `undefined` for var refs, empty strings, or anything unparseable.
297
+ */
298
+ export function relativeLuminance(value: string | number): number | undefined {
299
+ const rgb = toRgb(value);
300
+ if (!rgb) return undefined;
301
+ return 0.2126 * linearizeChannel(rgb.r) + 0.7152 * linearizeChannel(rgb.g) + 0.0722 * linearizeChannel(rgb.b);
302
+ }