@oh-my-pi/pi-utils 18.14.0 → 18.14.2

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/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.14.2] - 2026-10-31
6
+
7
+ ### Added
8
+
9
+ - Added `oklabDistance`, the perceptual distance between two hex colors ([#17520](https://github.com/can1357/oh-my-pi/pull/17520))
10
+
11
+ ## [18.14.1] - 2026-10-31
12
+
13
+ ### Added
14
+
15
+ - Added `isFileLockHeld`, which reports whether a file lock is held without acquiring it ([#17428](https://github.com/can1357/oh-my-pi/pull/17428) by [@andrebrait](https://github.com/andrebrait))
16
+
5
17
  ## [18.14.0] - 2026-10-29
6
18
 
7
19
  ### Added
@@ -99,6 +99,8 @@ export interface OKLCH {
99
99
  * hues, so carrying them between colors preserves the palette's "weight".
100
100
  */
101
101
  export declare function hexToOklch(hex: string): OKLCH;
102
+ /** Perceptual distance between two hex colors: Euclidean OKLab, 0 when identical, 1 from black to white. */
103
+ export declare function oklabDistance(a: string, b: string): number;
102
104
  /**
103
105
  * The sRGB gamut cusp for an OKLCH hue: the lightness/chroma point where the
104
106
  * hue reaches its maximum chroma inside sRGB.
@@ -16,6 +16,12 @@ declare function getLockPath(filePath: string): string;
16
16
  declare function tryAcquireLock(lockPath: string): NativeFileLock | null;
17
17
  /** Acquire an exclusive lease without waiting; `null` while another holder owns it. */
18
18
  export declare function tryAcquireFileLock(filePath: string): FileLockHandle | null;
19
+ /**
20
+ * Whether any holder, including this process, owns the lease, observed without
21
+ * taking it, so a concurrent `tryAcquireFileLock` never meets the probe.
22
+ * Throws when the lock cannot be probed.
23
+ */
24
+ export declare function isFileLockHeld(filePath: string): boolean;
19
25
  /** Acquire an exclusive lease; callers must release it when their operation ends. */
20
26
  export declare function acquireFileLock(filePath: string, options?: FileLockOptions): Promise<FileLockHandle>;
21
27
  /** Run `fn` while holding an OS-backed exclusive lock for `filePath`. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-utils",
3
- "version": "18.14.0",
3
+ "version": "18.14.2",
4
4
  "description": "Shared utilities for pi packages",
5
5
  "keywords": [
6
6
  "cli",
@@ -56,7 +56,7 @@
56
56
  "fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
57
57
  },
58
58
  "dependencies": {
59
- "@oh-my-pi/pi-natives": "18.14.0"
59
+ "@oh-my-pi/pi-natives": "18.14.2"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@types/bun": "^1.3.14"
package/src/color.ts CHANGED
@@ -311,6 +311,12 @@ function oklabToLinearRgb(L: number, a: number, b: number): { r: number; g: numb
311
311
  };
312
312
  }
313
313
 
314
+ /** Convert a hex color to OKLab. */
315
+ function hexToOklab(hex: string): { L: number; a: number; b: number } {
316
+ const rgb = hexToRgb(hex);
317
+ return linearRgbToOklab(linearizeChannel(rgb.r), linearizeChannel(rgb.g), linearizeChannel(rgb.b));
318
+ }
319
+
314
320
  /**
315
321
  * Convert a hex color to OKLCH (perceptual lightness/chroma/hue).
316
322
  *
@@ -318,14 +324,20 @@ function oklabToLinearRgb(L: number, a: number, b: number): { r: number; g: numb
318
324
  * hues, so carrying them between colors preserves the palette's "weight".
319
325
  */
320
326
  export function hexToOklch(hex: string): OKLCH {
321
- const rgb = hexToRgb(hex);
322
- const lab = linearRgbToOklab(linearizeChannel(rgb.r), linearizeChannel(rgb.g), linearizeChannel(rgb.b));
327
+ const lab = hexToOklab(hex);
323
328
  const c = Math.hypot(lab.a, lab.b);
324
329
  let h = (Math.atan2(lab.b, lab.a) * 180) / Math.PI;
325
330
  if (h < 0) h += 360;
326
331
  return { l: lab.L, c, h };
327
332
  }
328
333
 
334
+ /** Perceptual distance between two hex colors: Euclidean OKLab, 0 when identical, 1 from black to white. */
335
+ export function oklabDistance(a: string, b: string): number {
336
+ const x = hexToOklab(a);
337
+ const y = hexToOklab(b);
338
+ return Math.hypot(x.L - y.L, x.a - y.a, x.b - y.b);
339
+ }
340
+
329
341
  /**
330
342
  * Max OKLab saturation (C/L) that stays inside sRGB for the hue direction
331
343
  * `(a, b)`, via Björn Ottosson's polynomial fit plus one Halley refinement.
package/src/file-lock.ts CHANGED
@@ -44,6 +44,15 @@ export function tryAcquireFileLock(filePath: string): FileLockHandle | null {
44
44
  return tryAcquireLock(getLockPath(filePath));
45
45
  }
46
46
 
47
+ /**
48
+ * Whether any holder, including this process, owns the lease, observed without
49
+ * taking it, so a concurrent `tryAcquireFileLock` never meets the probe.
50
+ * Throws when the lock cannot be probed.
51
+ */
52
+ export function isFileLockHeld(filePath: string): boolean {
53
+ return NativeFileLock.isHeld(getLockPath(filePath));
54
+ }
55
+
47
56
  /** Acquire an exclusive lease; callers must release it when their operation ends. */
48
57
  export async function acquireFileLock(filePath: string, options: FileLockOptions = {}): Promise<FileLockHandle> {
49
58
  const opts = { ...DEFAULT_OPTIONS, ...options };