agentwheel 0.20.20 → 0.21.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.
@@ -1,148 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/utils/fs.ts
4
- import { createHash } from "crypto";
5
- import {
6
- copyFile,
7
- cp,
8
- mkdir,
9
- readdir,
10
- readFile,
11
- rename,
12
- rm,
13
- stat,
14
- writeFile
15
- } from "fs/promises";
16
- import { dirname, join, relative } from "path";
17
- var IGNORED_ENTRY_NAMES = /* @__PURE__ */ new Set([".git", "node_modules", "__pycache__", ".DS_Store"]);
18
- var IGNORED_SUFFIXES = [".pyc", ".pyo"];
19
- async function pathExists(path) {
20
- try {
21
- await stat(path);
22
- return true;
23
- } catch {
24
- return false;
25
- }
26
- }
27
- async function removeOnFailure(path, run) {
28
- try {
29
- return await run();
30
- } catch (error) {
31
- await rm(path, { recursive: true, force: true });
32
- throw error;
33
- }
34
- }
35
- async function hashPath(path) {
36
- const stats = await stat(path);
37
- if (stats.isFile()) {
38
- const content = await readFile(path);
39
- return createHash("sha256").update("file\0").update(content).digest("hex");
40
- }
41
- if (!stats.isDirectory()) {
42
- throw new Error(`Unsupported path kind: ${path}`);
43
- }
44
- const hash = createHash("sha256").update("dir\0");
45
- const files = await listFiles(path);
46
- for (const file of files) {
47
- hash.update(relative(path, file).replaceAll("\\", "/")).update("\0");
48
- hash.update(await hashPath(file)).update("\0");
49
- }
50
- return hash.digest("hex");
51
- }
52
- async function listFiles(root) {
53
- const out = [];
54
- async function walk(dir) {
55
- const entries = await readdir(dir, { withFileTypes: true });
56
- for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
57
- if (isIgnoredGeneratedEntry(entry.name)) continue;
58
- const full = join(dir, entry.name);
59
- if (entry.isDirectory()) {
60
- await walk(full);
61
- } else if (entry.isFile()) {
62
- out.push(full);
63
- }
64
- }
65
- }
66
- await walk(root);
67
- return out;
68
- }
69
- function isIgnoredGeneratedEntry(name) {
70
- return IGNORED_ENTRY_NAMES.has(name) || IGNORED_SUFFIXES.some((suffix) => name.endsWith(suffix));
71
- }
72
- async function atomicCopy(source, dest, kind) {
73
- await mkdir(dirname(dest), { recursive: true });
74
- const temp = `${dest}.agentwheel-tmp-${process.pid}-${Date.now()}`;
75
- await rm(temp, { recursive: true, force: true });
76
- if (kind === "file") {
77
- await copyFile(source, temp);
78
- } else {
79
- await cp(source, temp, { recursive: true, dereference: true, filter: (path) => !isIgnoredGeneratedEntry(path.split(/[\\/]/).at(-1) ?? "") });
80
- }
81
- await rm(dest, { recursive: true, force: true });
82
- await rename(temp, dest);
83
- }
84
- async function writeJsonAtomic(path, data) {
85
- await mkdir(dirname(path), { recursive: true });
86
- const temp = `${path}.tmp-${process.pid}-${Date.now()}`;
87
- await writeFile(temp, `${JSON.stringify(data, null, 2)}
88
- `, "utf8");
89
- await rename(temp, path);
90
- }
91
- async function withFilesystemLock(lockPath, timeoutMs, fn, description = "cache") {
92
- await mkdir(dirname(lockPath), { recursive: true });
93
- const started = Date.now();
94
- while (true) {
95
- try {
96
- await mkdir(lockPath);
97
- await writeFile(join(lockPath, "owner.json"), JSON.stringify({ pid: process.pid, createdAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf8");
98
- break;
99
- } catch (error) {
100
- if (!isAlreadyExists(error)) throw error;
101
- if (await removeStaleFilesystemLock(lockPath)) continue;
102
- if (Date.now() - started > timeoutMs) {
103
- throw new Error(`Timed out waiting for ${description} lock at ${lockPath}`);
104
- }
105
- await new Promise((resolve) => setTimeout(resolve, 50));
106
- }
107
- }
108
- try {
109
- return await fn();
110
- } finally {
111
- await rm(lockPath, { recursive: true, force: true });
112
- }
113
- }
114
- async function removeStaleFilesystemLock(lockPath) {
115
- try {
116
- const owner = JSON.parse(await readFile(join(lockPath, "owner.json"), "utf8"));
117
- if (typeof owner.pid !== "number" || !Number.isSafeInteger(owner.pid) || owner.pid <= 0 || isProcessAlive(owner.pid)) return false;
118
- const stalePath = `${lockPath}.stale-${process.pid}-${Date.now()}`;
119
- await rename(lockPath, stalePath);
120
- await rm(stalePath, { recursive: true, force: true });
121
- return true;
122
- } catch {
123
- return false;
124
- }
125
- }
126
- function isProcessAlive(pid) {
127
- try {
128
- process.kill(pid, 0);
129
- return true;
130
- } catch (error) {
131
- return typeof error === "object" && error !== null && "code" in error && error.code !== "ESRCH";
132
- }
133
- }
134
- function isAlreadyExists(error) {
135
- return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
136
- }
137
-
138
- export {
139
- pathExists,
140
- removeOnFailure,
141
- hashPath,
142
- listFiles,
143
- isIgnoredGeneratedEntry,
144
- atomicCopy,
145
- writeJsonAtomic,
146
- withFilesystemLock,
147
- isAlreadyExists
148
- };