@oh-my-pi/pi-utils 15.9.0 → 15.9.3

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.
@@ -95,6 +95,12 @@ export declare function getGpuCachePath(): string;
95
95
  * cache file without touching the rest of the config root.
96
96
  */
97
97
  export declare function getGithubCacheDbPath(): string;
98
+ /**
99
+ * Get the encrypted auth-broker snapshot cache path (~/.omp/cache/auth-broker-snapshot.enc).
100
+ * Honors the `OMP_AUTH_BROKER_SNAPSHOT_CACHE` env var when set so tests and
101
+ * operators can isolate or relocate the cache file.
102
+ */
103
+ export declare function getAuthBrokerSnapshotCachePath(): string;
98
104
  /** Get the local FastEmbed model cache directory (~/.omp/cache/fastembed). */
99
105
  export declare function getFastembedCacheDir(): string;
100
106
  /** Get the natives directory (~/.omp/natives). */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-utils",
4
- "version": "15.9.0",
4
+ "version": "15.9.3",
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": "15.9.0",
34
+ "@oh-my-pi/pi-natives": "15.9.3",
35
35
  "beautiful-mermaid": "^1.1.3",
36
36
  "handlebars": "^4.7.9",
37
37
  "winston": "^3.19.0",
package/src/dirs.ts CHANGED
@@ -343,6 +343,17 @@ export function getGithubCacheDbPath(): string {
343
343
  return dirs.rootSubdir(path.join("cache", "github-cache.db"), "cache");
344
344
  }
345
345
 
346
+ /**
347
+ * Get the encrypted auth-broker snapshot cache path (~/.omp/cache/auth-broker-snapshot.enc).
348
+ * Honors the `OMP_AUTH_BROKER_SNAPSHOT_CACHE` env var when set so tests and
349
+ * operators can isolate or relocate the cache file.
350
+ */
351
+ export function getAuthBrokerSnapshotCachePath(): string {
352
+ const override = process.env.OMP_AUTH_BROKER_SNAPSHOT_CACHE;
353
+ if (override) return override;
354
+ return dirs.rootSubdir(path.join("cache", "auth-broker-snapshot.enc"), "cache");
355
+ }
356
+
346
357
  /** Get the local FastEmbed model cache directory (~/.omp/cache/fastembed). */
347
358
  export function getFastembedCacheDir(): string {
348
359
  return dirs.rootSubdir(path.join("cache", "fastembed"), "cache");
@@ -4,17 +4,25 @@
4
4
  */
5
5
  import * as fs from "node:fs";
6
6
  import * as path from "node:path";
7
- import { isEnoent } from "./fs-error";
7
+ import { isFsError } from "./fs-error";
8
8
 
9
9
  export const MIN_TAB_WIDTH = 1;
10
10
  export const MAX_TAB_WIDTH = 16;
11
11
  export const DEFAULT_TAB_WIDTH = 3;
12
12
 
13
+ /**
14
+ * Per-component path length cap on common filesystems (`NAME_MAX = 255` on
15
+ * Linux ext4 / macOS APFS / Windows NTFS). Paths with components longer than
16
+ * this cannot be opened at all, so editorconfig discovery short-circuits to
17
+ * the default instead of running into `ENAMETOOLONG` from `readFileSync`.
18
+ */
19
+ const NAME_MAX_BYTES = 255;
20
+
13
21
  const EDITORCONFIG_NAME = ".editorconfig";
14
22
 
15
23
  let defaultTabWidth = DEFAULT_TAB_WIDTH;
16
24
 
17
- const editorConfigCache = new Map<string, ParsedEditorConfig>();
25
+ const editorConfigCache = new Map<string, ParsedEditorConfig | null>();
18
26
  const editorConfigChainCache = new Map<string, ChainEntry[]>();
19
27
  const indentationCache = new Map<string, number>();
20
28
 
@@ -145,14 +153,18 @@ function parseCachedEditorConfig(configPath: string): ParsedEditorConfig | undef
145
153
  const key = path.resolve(configPath);
146
154
  const hit = editorConfigCache.get(key);
147
155
  if (hit !== undefined) {
148
- return hit;
156
+ return hit ?? undefined;
149
157
  }
150
158
 
151
159
  let content: string;
152
160
  try {
153
161
  content = fs.readFileSync(key, "utf8");
154
162
  } catch (err) {
155
- if (isEnoent(err)) return undefined;
163
+ // editorconfig discovery is best-effort. Any filesystem error
164
+ // (`ENOENT`, `ENAMETOOLONG`, `ENOTDIR`, `EACCES`, `ELOOP`, `EINVAL`,
165
+ // …) means "no usable config at this path" — never a fatal condition
166
+ // for callers like the edit renderer that hand us arbitrary strings.
167
+ if (isFsError(err)) return undefined;
156
168
  throw err;
157
169
  }
158
170
  const parsed = parseEditorConfigFile(content);
@@ -279,6 +291,15 @@ function resolveEditorConfigTabWidth(match: EditorConfigMatch | undefined, fallb
279
291
  return undefined;
280
292
  }
281
293
 
294
+ function hasOverlongPathComponent(filePath: string): boolean {
295
+ for (const part of filePath.split(/[\\/]/)) {
296
+ if (part.length > 0 && Buffer.byteLength(part) > NAME_MAX_BYTES) {
297
+ return true;
298
+ }
299
+ }
300
+ return false;
301
+ }
302
+
282
303
  export function getDefaultTabWidth(): number {
283
304
  return defaultTabWidth;
284
305
  }
@@ -298,6 +319,15 @@ export function getIndentation(file?: string | null, projectDir?: string | null)
298
319
 
299
320
  const cwd = projectDir ?? process.cwd();
300
321
  const absoluteFile = resolveFilePath(cwd, file);
322
+
323
+ // Renderers can hand us arbitrary strings (e.g. a malformed edit tool
324
+ // call whose `file_path` is gibberish). Reject paths whose normalized
325
+ // absolute form still has any component longer than `NAME_MAX_BYTES` —
326
+ // the editorconfig chain would only trip `ENAMETOOLONG` from
327
+ // `readFileSync` and escape.
328
+ if (hasOverlongPathComponent(absoluteFile)) {
329
+ return fallback;
330
+ }
301
331
  const absKey = absoluteFile;
302
332
  const cached = indentationCache.get(absKey);
303
333
  if (cached !== undefined) {