@prometheus-ai/utils 0.5.3 → 0.5.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 +14 -0
- package/README.md +36 -0
- package/dist/types/abortable.d.ts +5 -0
- package/dist/types/dirs.d.ts +4 -0
- package/dist/types/env.d.ts +4 -0
- package/dist/types/fetch-retry.d.ts +8 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/logger.d.ts +22 -5
- package/dist/types/loop-phase.d.ts +10 -0
- package/dist/types/module-timer.d.ts +1 -0
- package/dist/types/path-tree.d.ts +76 -0
- package/dist/types/procmgr.d.ts +4 -0
- package/dist/types/runtime-install.d.ts +68 -0
- package/dist/types/tab-spacing.d.ts +16 -0
- package/dist/types/timing-buffer.d.ts +22 -0
- package/package.json +4 -2
- package/src/abortable.ts +86 -1
- package/src/dirs.ts +10 -0
- package/src/env.ts +17 -0
- package/src/fetch-retry.ts +8 -0
- package/src/index.ts +3 -0
- package/src/logger.ts +320 -73
- package/src/loop-phase.ts +49 -0
- package/src/module-timer.ts +148 -0
- package/src/path-tree.ts +147 -0
- package/src/procmgr.ts +1 -1
- package/src/runtime-install.ts +372 -0
- package/src/tab-spacing.ts +51 -0
- package/src/temp.ts +57 -4
- package/src/timing-buffer.ts +47 -0
package/src/tab-spacing.ts
CHANGED
|
@@ -340,3 +340,54 @@ export function getIndentation(file?: string | null, projectDir?: string | null)
|
|
|
340
340
|
indentationCache.set(absKey, clamped);
|
|
341
341
|
return clamped;
|
|
342
342
|
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* `.editorconfig`-derived formatting options for an LSP `textDocument/formatting` request.
|
|
346
|
+
*
|
|
347
|
+
* Both fields are absent when the resolved `.editorconfig` chain does not pin them, so callers
|
|
348
|
+
* can layer their own fallbacks underneath.
|
|
349
|
+
*/
|
|
350
|
+
export interface EditorConfigFormatting {
|
|
351
|
+
/** Effective indent width in columns, from `indent_size` or `tab_width`. */
|
|
352
|
+
tabSize?: number;
|
|
353
|
+
/** `true` for `indent_style = space`, `false` for `indent_style = tab` or `indent_size = tab`. */
|
|
354
|
+
insertSpaces?: boolean;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Resolve `.editorconfig` formatting hints for `file` without falling back to any default.
|
|
359
|
+
*/
|
|
360
|
+
export function getEditorConfigFormatting(file?: string | null, projectDir?: string | null): EditorConfigFormatting {
|
|
361
|
+
if (file === undefined || file === null || file === "") {
|
|
362
|
+
return {};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const cwd = projectDir ?? process.cwd();
|
|
366
|
+
const absoluteFile = resolveFilePath(cwd, file);
|
|
367
|
+
if (hasOverlongPathComponent(absoluteFile)) {
|
|
368
|
+
return {};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const match = resolveEditorConfigMatch(absoluteFile);
|
|
372
|
+
if (match === undefined) {
|
|
373
|
+
return {};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const result: EditorConfigFormatting = {};
|
|
377
|
+
|
|
378
|
+
if (match.indentSize?.kind === "spaces") {
|
|
379
|
+
result.tabSize = clampTabWidth(match.indentSize.n);
|
|
380
|
+
} else if (match.tabWidth !== undefined) {
|
|
381
|
+
result.tabSize = clampTabWidth(match.tabWidth);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (match.indentStyle === IndentStyle.Space) {
|
|
385
|
+
result.insertSpaces = true;
|
|
386
|
+
} else if (match.indentStyle === IndentStyle.Tab || match.indentSize?.kind === "tab") {
|
|
387
|
+
result.insertSpaces = false;
|
|
388
|
+
} else if (match.indentSize?.kind === "spaces") {
|
|
389
|
+
result.insertSpaces = true;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return result;
|
|
393
|
+
}
|
package/src/temp.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
+
import * as fsPromises from "node:fs/promises";
|
|
2
3
|
import * as os from "node:os";
|
|
3
4
|
import * as path from "node:path";
|
|
4
5
|
|
|
@@ -13,7 +14,7 @@ export class TempDir {
|
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
static async create(prefix?: string): Promise<TempDir> {
|
|
16
|
-
return new TempDir(await
|
|
17
|
+
return new TempDir(await fsPromises.mkdtemp(normalizePrefix(prefix)));
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
#removePromise: Promise<void> | null = null;
|
|
@@ -30,13 +31,13 @@ export class TempDir {
|
|
|
30
31
|
if (this.#removePromise) {
|
|
31
32
|
return this.#removePromise;
|
|
32
33
|
}
|
|
33
|
-
const removePromise =
|
|
34
|
+
const removePromise = removeWithRetries(this.#path);
|
|
34
35
|
this.#removePromise = removePromise;
|
|
35
36
|
return removePromise;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
removeSync(): void {
|
|
39
|
-
|
|
40
|
+
removeSyncWithRetries(this.#path);
|
|
40
41
|
this.#removePromise = Promise.resolve();
|
|
41
42
|
}
|
|
42
43
|
|
|
@@ -69,9 +70,61 @@ const kTempDir = os.tmpdir();
|
|
|
69
70
|
|
|
70
71
|
function normalizePrefix(prefix?: string): string {
|
|
71
72
|
if (!prefix) {
|
|
72
|
-
return `${kTempDir}${path.sep}
|
|
73
|
+
return `${kTempDir}${path.sep}prometheus-temp-`;
|
|
73
74
|
} else if (prefix.startsWith("@")) {
|
|
74
75
|
return path.join(kTempDir, prefix.slice(1));
|
|
75
76
|
}
|
|
76
77
|
return prefix;
|
|
77
78
|
}
|
|
79
|
+
|
|
80
|
+
const kRemoveOptions = { recursive: true, force: true } as const;
|
|
81
|
+
const kRemoveRetries = 4;
|
|
82
|
+
const kRemoveRetryDelayMs = 10;
|
|
83
|
+
const kRetryableRemoveErrorCodes = new Set(["EBUSY", "EPERM", "ENOTEMPTY"]);
|
|
84
|
+
const kSleepBuffer = new Int32Array(new SharedArrayBuffer(4));
|
|
85
|
+
|
|
86
|
+
async function removeWithRetries(target: string): Promise<void> {
|
|
87
|
+
for (let attempt = 0; ; attempt++) {
|
|
88
|
+
try {
|
|
89
|
+
await fsPromises.rm(target, kRemoveOptions);
|
|
90
|
+
return;
|
|
91
|
+
} catch (err) {
|
|
92
|
+
if (!shouldRetryRemove(err, attempt)) throw err;
|
|
93
|
+
await Bun.sleep(kRemoveRetryDelayMs);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function removeSyncWithRetries(target: string): void {
|
|
99
|
+
for (let attempt = 0; ; attempt++) {
|
|
100
|
+
try {
|
|
101
|
+
fs.rmSync(target, kRemoveOptions);
|
|
102
|
+
return;
|
|
103
|
+
} catch (err) {
|
|
104
|
+
if (!shouldRetryRemove(err, attempt)) throw err;
|
|
105
|
+
sleepSync(kRemoveRetryDelayMs);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function shouldRetryRemove(err: unknown, attempt: number): boolean {
|
|
111
|
+
return attempt < kRemoveRetries && process.platform === "win32" && isRetryableRemoveError(err);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function isRetryableRemoveError(err: unknown): boolean {
|
|
115
|
+
return (
|
|
116
|
+
typeof err === "object" &&
|
|
117
|
+
err !== null &&
|
|
118
|
+
"code" in err &&
|
|
119
|
+
typeof err.code === "string" &&
|
|
120
|
+
kRetryableRemoveErrorCodes.has(err.code)
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function sleepSync(ms: number): void {
|
|
125
|
+
if ("sleepSync" in Bun && typeof Bun.sleepSync === "function") {
|
|
126
|
+
Bun.sleepSync(ms);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
Atomics.wait(kSleepBuffer, 0, 0, ms);
|
|
130
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared contract between the {@link module-timer} preload and {@link logger}'s
|
|
3
|
+
* timing tree. Kept in its own dependency-free module so the preload can import
|
|
4
|
+
* it without pulling in winston (via logger) and the logger can drain the buffer
|
|
5
|
+
* without importing the Bun-plugin preload.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface ModuleLoadEvent {
|
|
9
|
+
/** Absolute or Bun-resolved module path. */
|
|
10
|
+
path: string;
|
|
11
|
+
/** `performance.now()` timestamp captured at Bun `onLoad` entry. */
|
|
12
|
+
start: number;
|
|
13
|
+
/** Inclusive module window: `onLoad` entry → appended final marker. */
|
|
14
|
+
durationMs: number;
|
|
15
|
+
/** Own top-level body / TLA time: prepended body marker → appended final marker. */
|
|
16
|
+
bodyMs?: number;
|
|
17
|
+
/** Resolved static children imported by this module. */
|
|
18
|
+
imports: string[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Registry-global key under which the preload accumulates module-load events.
|
|
23
|
+
* `Symbol.for` so both modules resolve the same symbol independently.
|
|
24
|
+
*/
|
|
25
|
+
const KEY: symbol = Symbol.for("prometheus.moduleLoadBuffer");
|
|
26
|
+
|
|
27
|
+
type Store = Record<symbol, ModuleLoadEvent[] | undefined>;
|
|
28
|
+
|
|
29
|
+
/** The append-only buffer the preload pushes into (created on first access). */
|
|
30
|
+
export function moduleLoadBuffer(): ModuleLoadEvent[] {
|
|
31
|
+
const store = globalThis as unknown as Store;
|
|
32
|
+
let buffer = store[KEY];
|
|
33
|
+
if (!buffer) {
|
|
34
|
+
buffer = [];
|
|
35
|
+
store[KEY] = buffer;
|
|
36
|
+
}
|
|
37
|
+
return buffer;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Drain and return all buffered events, leaving the buffer empty. */
|
|
41
|
+
export function drainModuleLoadEvents(): ModuleLoadEvent[] {
|
|
42
|
+
const store = globalThis as unknown as Store;
|
|
43
|
+
const buffer = store[KEY];
|
|
44
|
+
if (!buffer || buffer.length === 0) return [];
|
|
45
|
+
store[KEY] = [];
|
|
46
|
+
return buffer;
|
|
47
|
+
}
|