@oh-my-pi/pi-utils 16.2.6 → 16.2.8

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,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [16.2.7] - 2026-06-30
6
+
7
+ ### Added
8
+
9
+ - Added a utility to detect binary files based on content sniffing.
10
+
5
11
  ## [16.2.6] - 2026-06-29
6
12
 
7
13
  ### Added
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Classify an in-memory byte header as binary (non-UTF-8-text).
3
+ *
4
+ * Binary when the header contains a NUL byte (true binary, plus UTF-16/UTF-32
5
+ * text whose ASCII range is NUL-padded) or when it is not valid UTF-8. The
6
+ * decode runs in streaming mode so a multibyte sequence truncated at the header
7
+ * boundary is tolerated, while any genuinely invalid byte still fails — matching
8
+ * the strict `fatal` decode the `local://`/`ssh://` read paths already use.
9
+ */
10
+ export declare function isProbablyBinaryHeader(header: Uint8Array): boolean;
11
+ /**
12
+ * Sniff the first {@link BINARY_SNIFF_BYTES} of `filePath` and report whether it
13
+ * is binary (non-UTF-8-text). See {@link isProbablyBinaryHeader} for the rule.
14
+ */
15
+ export declare function isProbablyBinary(filePath: string, maxBytes?: number): Promise<boolean>;
16
+ /** Synchronous {@link isProbablyBinary}. */
17
+ export declare function isProbablyBinarySync(filePath: string, maxBytes?: number): boolean;
@@ -1,5 +1,6 @@
1
1
  export { once, untilAborted } from "./abortable";
2
2
  export * from "./async";
3
+ export * from "./binary";
3
4
  export * from "./color";
4
5
  export * from "./dirs";
5
6
  export * from "./env";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-utils",
4
- "version": "16.2.6",
4
+ "version": "16.2.8",
5
5
  "description": "Shared utilities for pi packages",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -31,7 +31,7 @@
31
31
  "fmt": "biome format --write ."
32
32
  },
33
33
  "dependencies": {
34
- "@oh-my-pi/pi-natives": "16.2.6",
34
+ "@oh-my-pi/pi-natives": "16.2.8",
35
35
  "handlebars": "^4.7.9",
36
36
  "winston": "^3.19.0",
37
37
  "winston-daily-rotate-file": "^5.0.0"
package/src/binary.ts ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Content-based binary/text classification for files that are about to be
3
+ * decoded as UTF-8 text and shown to a model or user.
4
+ *
5
+ * The read tool and `@file` auto-read both materialize file bytes as UTF-8
6
+ * strings. For a binary file (font, object, archive, packed blob) that decode
7
+ * is lossy: NUL bytes and invalid sequences survive as control characters and
8
+ * U+FFFD replacements, which corrupt terminal rendering and waste the context
9
+ * window with mojibake. Sniff the header first and refuse instead.
10
+ *
11
+ * @example
12
+ * if (await isProbablyBinary(path)) return "[binary file omitted]";
13
+ * const text = await Bun.file(path).text();
14
+ */
15
+ import { peekFile, peekFileSync } from "./peek-file";
16
+
17
+ /** Header window sniffed for the binary heuristic; mirrors git's 8000-byte scan. */
18
+ const BINARY_SNIFF_BYTES = 8192;
19
+
20
+ /**
21
+ * Classify an in-memory byte header as binary (non-UTF-8-text).
22
+ *
23
+ * Binary when the header contains a NUL byte (true binary, plus UTF-16/UTF-32
24
+ * text whose ASCII range is NUL-padded) or when it is not valid UTF-8. The
25
+ * decode runs in streaming mode so a multibyte sequence truncated at the header
26
+ * boundary is tolerated, while any genuinely invalid byte still fails — matching
27
+ * the strict `fatal` decode the `local://`/`ssh://` read paths already use.
28
+ */
29
+ export function isProbablyBinaryHeader(header: Uint8Array): boolean {
30
+ if (header.indexOf(0) !== -1) return true;
31
+ try {
32
+ new TextDecoder("utf-8", { fatal: true }).decode(header, { stream: true });
33
+ return false;
34
+ } catch {
35
+ return true;
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Sniff the first {@link BINARY_SNIFF_BYTES} of `filePath` and report whether it
41
+ * is binary (non-UTF-8-text). See {@link isProbablyBinaryHeader} for the rule.
42
+ */
43
+ export function isProbablyBinary(filePath: string, maxBytes = BINARY_SNIFF_BYTES): Promise<boolean> {
44
+ return peekFile(filePath, maxBytes, isProbablyBinaryHeader);
45
+ }
46
+
47
+ /** Synchronous {@link isProbablyBinary}. */
48
+ export function isProbablyBinarySync(filePath: string, maxBytes = BINARY_SNIFF_BYTES): boolean {
49
+ return peekFileSync(filePath, maxBytes, isProbablyBinaryHeader);
50
+ }
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { once, untilAborted } from "./abortable";
2
2
  export * from "./async";
3
+ export * from "./binary";
3
4
  export * from "./color";
4
5
  export * from "./dirs";
5
6
  export * from "./env";