@introspection-ai/recipes 0.13.0 → 0.14.1

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.
Files changed (222) hide show
  1. package/README.md +46 -57
  2. package/dist/{agent-tool.d.ts → agents.d.ts} +4 -1
  3. package/dist/agents.d.ts.map +1 -0
  4. package/dist/{agent-tool.js → agents.js} +1 -1
  5. package/dist/agents.js.map +1 -0
  6. package/dist/api/extensions.d.ts +3 -0
  7. package/dist/api/extensions.d.ts.map +1 -0
  8. package/dist/api/extensions.js +2 -0
  9. package/dist/api/extensions.js.map +1 -0
  10. package/dist/api/mcp.d.ts +4 -0
  11. package/dist/api/mcp.d.ts.map +1 -0
  12. package/dist/api/mcp.js +2 -0
  13. package/dist/api/mcp.js.map +1 -0
  14. package/dist/api/session.d.ts +3 -0
  15. package/dist/api/session.d.ts.map +1 -0
  16. package/dist/api/session.js +2 -0
  17. package/dist/api/session.js.map +1 -0
  18. package/dist/child-agent.d.ts +5 -4
  19. package/dist/child-agent.d.ts.map +1 -1
  20. package/dist/child-agent.js +26 -117
  21. package/dist/child-agent.js.map +1 -1
  22. package/dist/child-session.d.ts +23 -0
  23. package/dist/child-session.d.ts.map +1 -0
  24. package/dist/child-session.js +48 -0
  25. package/dist/child-session.js.map +1 -0
  26. package/dist/extensions.d.ts +29 -0
  27. package/dist/extensions.d.ts.map +1 -0
  28. package/dist/extensions.js +119 -0
  29. package/dist/extensions.js.map +1 -0
  30. package/dist/index.d.ts +4 -13
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +2 -13
  33. package/dist/index.js.map +1 -1
  34. package/dist/inspect.d.ts +38 -5
  35. package/dist/inspect.d.ts.map +1 -1
  36. package/dist/inspect.js +92 -41
  37. package/dist/inspect.js.map +1 -1
  38. package/dist/interactions.d.ts +18 -2
  39. package/dist/interactions.d.ts.map +1 -1
  40. package/dist/interactions.js +41 -10
  41. package/dist/interactions.js.map +1 -1
  42. package/dist/mcp-catalog.d.ts +1 -0
  43. package/dist/mcp-catalog.d.ts.map +1 -1
  44. package/dist/mcp-catalog.js +14 -6
  45. package/dist/mcp-catalog.js.map +1 -1
  46. package/dist/mcp-chunks/auth-command-ZLGYIEUY.js +273 -0
  47. package/dist/mcp-chunks/call-arguments-LU3W6D3K.js +13 -0
  48. package/dist/mcp-chunks/call-command-LKTKSYTH.js +612 -0
  49. package/dist/mcp-chunks/chunk-2U4BSDC4.js +3951 -0
  50. package/dist/mcp-chunks/chunk-2XL7MG7R.js +272 -0
  51. package/dist/mcp-chunks/chunk-3BJA27PY.js +2321 -0
  52. package/dist/mcp-chunks/chunk-4SQKWYFF.js +15 -0
  53. package/dist/mcp-chunks/chunk-5QOSCSQB.js +290 -0
  54. package/dist/mcp-chunks/chunk-6W5QFASN.js +77 -0
  55. package/dist/mcp-chunks/chunk-6XCZGU3G.js +1004 -0
  56. package/dist/mcp-chunks/chunk-7FHEBT5G.js +149 -0
  57. package/dist/mcp-chunks/chunk-7KA2VJVZ.js +114 -0
  58. package/dist/mcp-chunks/chunk-7UDVSOOF.js +138 -0
  59. package/dist/mcp-chunks/chunk-BNV3TPE4.js +66 -0
  60. package/dist/mcp-chunks/chunk-BTLAWHTA.js +129 -0
  61. package/dist/mcp-chunks/chunk-BV56DXPW.js +13 -0
  62. package/dist/mcp-chunks/chunk-BWHIA4PC.js +90 -0
  63. package/dist/mcp-chunks/chunk-BZIQOWE6.js +267 -0
  64. package/dist/mcp-chunks/chunk-D3MRAZ6H.js +16140 -0
  65. package/dist/mcp-chunks/chunk-DHBE7UBH.js +750 -0
  66. package/dist/mcp-chunks/chunk-E22DYOW5.js +251 -0
  67. package/dist/mcp-chunks/chunk-ECIVB7P4.js +139 -0
  68. package/dist/mcp-chunks/chunk-HKRJ6O36.js +1076 -0
  69. package/dist/mcp-chunks/chunk-IABRYROW.js +44 -0
  70. package/dist/mcp-chunks/chunk-J6LYIZXN.js +45 -0
  71. package/dist/mcp-chunks/chunk-L7NTQVYN.js +161 -0
  72. package/dist/mcp-chunks/chunk-LEZSACDE.js +141 -0
  73. package/dist/mcp-chunks/chunk-LKIBAYKU.js +208 -0
  74. package/dist/mcp-chunks/chunk-LNH5LAJD.js +152 -0
  75. package/dist/mcp-chunks/chunk-LQQEYD76.js +124 -0
  76. package/dist/mcp-chunks/chunk-LRKZP7DJ.js +47 -0
  77. package/dist/mcp-chunks/chunk-LS7PMWSR.js +109 -0
  78. package/dist/mcp-chunks/chunk-M3TPODXI.js +95 -0
  79. package/dist/mcp-chunks/chunk-MZ2NARG7.js +400 -0
  80. package/dist/mcp-chunks/chunk-N46NEFAF.js +45 -0
  81. package/dist/mcp-chunks/chunk-NNOEGEUZ.js +17273 -0
  82. package/dist/mcp-chunks/chunk-NRAJX5E4.js +69 -0
  83. package/dist/mcp-chunks/chunk-P3PSC54P.js +869 -0
  84. package/dist/mcp-chunks/chunk-PIIYJR44.js +6341 -0
  85. package/dist/mcp-chunks/chunk-PWYFKGKG.js +385 -0
  86. package/dist/mcp-chunks/chunk-SJCCBNZ4.js +45 -0
  87. package/dist/mcp-chunks/chunk-TATVT5IT.js +194 -0
  88. package/dist/mcp-chunks/chunk-TEUKFFQL.js +29 -0
  89. package/dist/mcp-chunks/chunk-UKYNQGNE.js +150 -0
  90. package/dist/mcp-chunks/chunk-UNKB4SBV.js +37 -0
  91. package/dist/mcp-chunks/chunk-WD6BOD24.js +138 -0
  92. package/dist/mcp-chunks/chunk-WQJZMCJN.js +73 -0
  93. package/dist/mcp-chunks/chunk-XANPGTLI.js +364 -0
  94. package/dist/mcp-chunks/chunk-XQK2JSW4.js +35 -0
  95. package/dist/mcp-chunks/chunk-YHQUTU6L.js +571 -0
  96. package/dist/mcp-chunks/chunk-YVZKMV5H.js +57 -0
  97. package/dist/mcp-chunks/cli-UV4QJZZM.js +929 -0
  98. package/dist/mcp-chunks/client-S7RQUG5U.js +13 -0
  99. package/dist/mcp-chunks/config-command-NLAGKID5.js +1101 -0
  100. package/dist/mcp-chunks/daemon-command-U242Z6VY.js +26 -0
  101. package/dist/mcp-chunks/dist-LK3SHAMX.js +6478 -0
  102. package/dist/mcp-chunks/emit-ts-command-VBXVXO6V.js +386 -0
  103. package/dist/mcp-chunks/generate-cli-runner-6CAZZA3P.js +1426 -0
  104. package/dist/mcp-chunks/inspect-cli-command-3ZORTOR7.js +111 -0
  105. package/dist/mcp-chunks/launch-YKRXHXJI.js +10 -0
  106. package/dist/mcp-chunks/lifecycle-XVKRHPH3.js +16 -0
  107. package/dist/mcp-chunks/list-command-2MEGGNFQ.js +4190 -0
  108. package/dist/mcp-chunks/output-utils-NKESLAJ6.js +12 -0
  109. package/dist/mcp-chunks/prompt-B1Yc1NPt-VGOTWJMN.js +918 -0
  110. package/dist/mcp-chunks/record-command-YXHTTTT5.js +17 -0
  111. package/dist/mcp-chunks/replay-command-25HJ6AQU.js +85 -0
  112. package/dist/mcp-chunks/resource-command-OO4NYF5C.js +97 -0
  113. package/dist/mcp-chunks/result-utils-MOHHLNM7.js +15 -0
  114. package/dist/mcp-chunks/runtime-5WJ3G25Y.js +33 -0
  115. package/dist/mcp-chunks/runtime-wrapper-RPWDIDBF.js +10 -0
  116. package/dist/mcp-chunks/serve-command-DHXJZMMN.js +3302 -0
  117. package/dist/mcp-chunks/timeouts-W2XWCCXR.js +18 -0
  118. package/dist/mcp-chunks/vault-command-PIYIUEZL.js +154 -0
  119. package/dist/mcp-daemon-client.d.ts +6 -1
  120. package/dist/mcp-daemon-client.d.ts.map +1 -1
  121. package/dist/mcp-daemon-client.js +119 -2
  122. package/dist/mcp-daemon-client.js.map +1 -1
  123. package/dist/mcp-daemon-protocol.d.ts +18 -1
  124. package/dist/mcp-daemon-protocol.d.ts.map +1 -1
  125. package/dist/mcp-daemon-protocol.js +31 -0
  126. package/dist/mcp-daemon-protocol.js.map +1 -1
  127. package/dist/mcp-daemon.js +169 -76602
  128. package/dist/mcp-daemon.js.map +1 -1
  129. package/dist/mcp-policy.d.ts +11 -0
  130. package/dist/mcp-policy.d.ts.map +1 -0
  131. package/dist/mcp-policy.js +27 -0
  132. package/dist/mcp-policy.js.map +1 -0
  133. package/dist/mcp-run-worker.js +38 -76540
  134. package/dist/mcp-tools.d.ts +39 -0
  135. package/dist/mcp-tools.d.ts.map +1 -0
  136. package/dist/mcp-tools.js +493 -0
  137. package/dist/mcp-tools.js.map +1 -0
  138. package/dist/mcp.d.ts +21 -9
  139. package/dist/mcp.d.ts.map +1 -1
  140. package/dist/mcp.js +101 -31
  141. package/dist/mcp.js.map +1 -1
  142. package/dist/model-binding.d.ts +39 -0
  143. package/dist/model-binding.d.ts.map +1 -0
  144. package/dist/model-binding.js +103 -0
  145. package/dist/model-binding.js.map +1 -0
  146. package/dist/pi-extension.d.ts +2 -22
  147. package/dist/pi-extension.d.ts.map +1 -1
  148. package/dist/pi-extension.js +296 -71
  149. package/dist/pi-extension.js.map +1 -1
  150. package/dist/recipe/resolve.d.ts +43 -20
  151. package/dist/recipe/resolve.d.ts.map +1 -1
  152. package/dist/recipe/resolve.js +215 -70
  153. package/dist/recipe/resolve.js.map +1 -1
  154. package/dist/recipe-agent.d.ts +24 -27
  155. package/dist/recipe-agent.d.ts.map +1 -1
  156. package/dist/recipe-agent.js +278 -230
  157. package/dist/recipe-agent.js.map +1 -1
  158. package/dist/recipe-check.d.ts +18 -0
  159. package/dist/recipe-check.d.ts.map +1 -0
  160. package/dist/recipe-check.js +261 -0
  161. package/dist/recipe-check.js.map +1 -0
  162. package/dist/recipe-extensions.d.ts.map +1 -1
  163. package/dist/recipe-extensions.js +0 -3
  164. package/dist/recipe-extensions.js.map +1 -1
  165. package/dist/recipe-model.d.ts +3 -1
  166. package/dist/recipe-model.d.ts.map +1 -1
  167. package/dist/recipe-model.js +15 -12
  168. package/dist/recipe-model.js.map +1 -1
  169. package/dist/recipe-package.d.ts +6 -28
  170. package/dist/recipe-package.d.ts.map +1 -1
  171. package/dist/recipe-package.js +248 -191
  172. package/dist/recipe-package.js.map +1 -1
  173. package/dist/recipe-skills.d.ts.map +1 -1
  174. package/dist/recipe-skills.js +42 -29
  175. package/dist/recipe-skills.js.map +1 -1
  176. package/dist/run-controller.d.ts +10 -9
  177. package/dist/run-controller.d.ts.map +1 -1
  178. package/dist/run-controller.js +28 -21
  179. package/dist/run-controller.js.map +1 -1
  180. package/dist/session.d.ts +40 -53
  181. package/dist/session.d.ts.map +1 -1
  182. package/dist/session.js +312 -173
  183. package/dist/session.js.map +1 -1
  184. package/dist/test-utils.d.ts +7 -7
  185. package/dist/test-utils.d.ts.map +1 -1
  186. package/dist/test-utils.js +32 -15
  187. package/dist/test-utils.js.map +1 -1
  188. package/docs/agent-composition.md +41 -35
  189. package/docs/host-api.md +201 -0
  190. package/docs/index.md +9 -14
  191. package/docs/interactions.md +12 -11
  192. package/docs/mcp-auth.md +6 -6
  193. package/docs/mcp-configuration.md +73 -25
  194. package/docs/pi-extension.md +39 -11
  195. package/docs/recipe-flow.md +9 -9
  196. package/docs/recipe-format.md +106 -41
  197. package/docs/recipe-judges.md +24 -36
  198. package/package.json +23 -17
  199. package/vendor/mcp-client/darwin-arm64/mcp-client +0 -0
  200. package/vendor/mcp-client/darwin-x64/mcp-client +0 -0
  201. package/vendor/mcp-client/linux-arm64/mcp-client +0 -0
  202. package/vendor/recipe-check/darwin-arm64/recipe-check +0 -0
  203. package/vendor/recipe-check/darwin-x64/recipe-check +0 -0
  204. package/vendor/recipe-check/linux-arm64/recipe-check +0 -0
  205. package/vendor/recipe-check/linux-x64/recipe-check +0 -0
  206. package/vendor/recipe-check/linux-x64-musl/recipe-check +0 -0
  207. package/vendor/recipe-check/win32-x64/recipe-check.exe +0 -0
  208. package/dist/agent-tool.d.ts.map +0 -1
  209. package/dist/agent-tool.js.map +0 -1
  210. package/dist/run.d.ts +0 -28
  211. package/dist/run.d.ts.map +0 -1
  212. package/dist/run.js +0 -84
  213. package/dist/run.js.map +0 -1
  214. package/dist/testing.d.ts +0 -25
  215. package/dist/testing.d.ts.map +0 -1
  216. package/dist/testing.js +0 -96
  217. package/dist/testing.js.map +0 -1
  218. package/docs/deployment-configuration.md +0 -65
  219. package/docs/migration.md +0 -70
  220. package/docs/python-bindings-release.md +0 -47
  221. package/docs/recipe-evals.md +0 -70
  222. package/docs/runtime-library.md +0 -171
@@ -0,0 +1,272 @@
1
+ import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
+
3
+ // node_modules/.pnpm/mcporter@0.12.3/node_modules/mcporter/dist/fs-json.js
4
+ import crypto from "node:crypto";
5
+ import { constants } from "node:fs";
6
+ import fs from "node:fs/promises";
7
+ import path from "node:path";
8
+ var DEFAULT_LOCK_TIMEOUT_MS = 3e4;
9
+ var LOCK_POLL_MS = 25;
10
+ var MALFORMED_LOCK_STALE_MS = 1e3;
11
+ var MAX_SYMLINK_DEPTH = 40;
12
+ var DEFAULT_ATOMIC_FILE_MODE = 384;
13
+ var localLockTails = /* @__PURE__ */ new Map();
14
+ async function readJsonFile(filePath) {
15
+ try {
16
+ const content = await fs.readFile(filePath, "utf8");
17
+ return JSON.parse(content);
18
+ } catch (error) {
19
+ if (error.code === "ENOENT") {
20
+ return void 0;
21
+ }
22
+ throw error;
23
+ }
24
+ }
25
+ async function writeTextFileAtomic(filePath, data) {
26
+ const target = await resolveAtomicWriteTarget(filePath);
27
+ await fs.mkdir(path.dirname(target.path), { recursive: true });
28
+ const tempPath = path.join(path.dirname(target.path), `.${path.basename(target.path)}.${process.pid}.${Date.now()}.${crypto.randomUUID()}.tmp`);
29
+ try {
30
+ if (target.mode !== void 0) {
31
+ await fs.access(target.path, constants.W_OK);
32
+ }
33
+ await fs.writeFile(tempPath, data, {
34
+ encoding: "utf8",
35
+ flag: "wx",
36
+ mode: target.mode ?? DEFAULT_ATOMIC_FILE_MODE
37
+ });
38
+ if (target.mode !== void 0) {
39
+ await fs.chmod(tempPath, target.mode);
40
+ }
41
+ await fs.rename(tempPath, target.path);
42
+ } catch (error) {
43
+ await fs.unlink(tempPath).catch(() => {
44
+ });
45
+ if (target.mode !== void 0 && isPermissionError(error)) {
46
+ await fs.writeFile(filePath, data, "utf8");
47
+ return;
48
+ }
49
+ throw error;
50
+ }
51
+ }
52
+ async function writeJsonFile(filePath, data) {
53
+ await writeTextFileAtomic(filePath, JSON.stringify(data, null, 2));
54
+ }
55
+ async function withFileLock(filePath, task, options = {}) {
56
+ const lockTargetPath = await resolvePathFollowingSymlinks(filePath);
57
+ const timeoutMs = options.timeoutMs ?? DEFAULT_LOCK_TIMEOUT_MS;
58
+ const startedAt = Date.now();
59
+ return withLocalLock(lockTargetPath, timeoutMs, async () => {
60
+ await fs.mkdir(path.dirname(lockTargetPath), { recursive: true });
61
+ let lockPath = `${lockTargetPath}.lock`;
62
+ const fallbackLockPath = lockTargetPath !== filePath ? `${filePath}.lock` : void 0;
63
+ let acquired = false;
64
+ while (!acquired) {
65
+ try {
66
+ await fs.writeFile(lockPath, `${process.pid}
67
+ ${(/* @__PURE__ */ new Date()).toISOString()}
68
+ `, {
69
+ encoding: "utf8",
70
+ flag: "wx"
71
+ });
72
+ acquired = true;
73
+ break;
74
+ } catch (error) {
75
+ if (fallbackLockPath && lockPath !== fallbackLockPath && isPermissionError(error)) {
76
+ await fs.mkdir(path.dirname(fallbackLockPath), { recursive: true });
77
+ lockPath = fallbackLockPath;
78
+ continue;
79
+ }
80
+ if (error.code !== "EEXIST") {
81
+ throw error;
82
+ }
83
+ if (await removeRecoverableLock(lockPath)) {
84
+ continue;
85
+ }
86
+ if (Date.now() - startedAt > timeoutMs) {
87
+ throw new Error(`Timed out waiting for file lock ${lockPath}`, { cause: error });
88
+ }
89
+ await sleep(LOCK_POLL_MS);
90
+ }
91
+ }
92
+ try {
93
+ return await task();
94
+ } finally {
95
+ await fs.unlink(lockPath).catch((error) => {
96
+ if (error.code !== "ENOENT") {
97
+ throw error;
98
+ }
99
+ });
100
+ }
101
+ });
102
+ }
103
+ function isPermissionError(error) {
104
+ const code = error.code;
105
+ return code === "EACCES" || code === "EPERM";
106
+ }
107
+ async function sleep(ms) {
108
+ await new Promise((resolve) => setTimeout(resolve, ms));
109
+ }
110
+ async function withLocalLock(key, timeoutMs, task) {
111
+ const previous = localLockTails.get(key) ?? Promise.resolve();
112
+ let release;
113
+ const current = new Promise((resolve) => {
114
+ release = resolve;
115
+ });
116
+ const tail = previous.then(() => current);
117
+ localLockTails.set(key, tail);
118
+ try {
119
+ await waitForLocalLock(previous, timeoutMs, key);
120
+ return await task();
121
+ } finally {
122
+ release();
123
+ void tail.then(() => {
124
+ if (localLockTails.get(key) === tail) {
125
+ localLockTails.delete(key);
126
+ }
127
+ });
128
+ }
129
+ }
130
+ async function waitForLocalLock(previous, timeoutMs, key) {
131
+ let timer;
132
+ try {
133
+ await Promise.race([
134
+ previous,
135
+ new Promise((_, reject) => {
136
+ timer = setTimeout(() => reject(new Error(`Timed out waiting for file lock ${key}.lock`)), Math.max(0, timeoutMs));
137
+ })
138
+ ]);
139
+ } finally {
140
+ if (timer) {
141
+ clearTimeout(timer);
142
+ }
143
+ }
144
+ }
145
+ async function resolveAtomicWriteTarget(filePath) {
146
+ try {
147
+ const stats = await fs.lstat(filePath);
148
+ if (stats.isSymbolicLink()) {
149
+ const targetPath = await resolvePathFollowingSymlinks(filePath);
150
+ return { path: targetPath, mode: await readMode(targetPath) };
151
+ }
152
+ return { path: filePath, mode: stats.mode & 511 };
153
+ } catch (error) {
154
+ if (error.code === "ENOENT") {
155
+ return { path: filePath };
156
+ }
157
+ throw error;
158
+ }
159
+ }
160
+ async function resolvePathFollowingSymlinks(filePath) {
161
+ let currentPath = await canonicalizeParentDirectory(filePath);
162
+ for (let depth = 0; depth < MAX_SYMLINK_DEPTH; depth += 1) {
163
+ let stats;
164
+ try {
165
+ stats = await fs.lstat(currentPath);
166
+ } catch (error) {
167
+ if (error.code === "ENOENT") {
168
+ return await canonicalizeParentDirectory(currentPath);
169
+ }
170
+ throw error;
171
+ }
172
+ if (!stats.isSymbolicLink()) {
173
+ return currentPath;
174
+ }
175
+ const link = await fs.readlink(currentPath);
176
+ currentPath = await canonicalizeParentDirectory(path.isAbsolute(link) ? link : path.resolve(path.dirname(currentPath), link));
177
+ }
178
+ throw new Error(`Too many symbolic links while resolving ${filePath}`);
179
+ }
180
+ async function canonicalizeParentDirectory(filePath) {
181
+ try {
182
+ return path.join(await fs.realpath(path.dirname(filePath)), path.basename(filePath));
183
+ } catch (error) {
184
+ if (error.code === "ENOENT") {
185
+ return filePath;
186
+ }
187
+ throw error;
188
+ }
189
+ }
190
+ async function readMode(filePath) {
191
+ try {
192
+ const stats = await fs.stat(filePath);
193
+ return stats.mode & 511;
194
+ } catch (error) {
195
+ if (error.code === "ENOENT") {
196
+ return void 0;
197
+ }
198
+ throw error;
199
+ }
200
+ }
201
+ async function removeRecoverableLock(lockPath) {
202
+ const breakerPath = `${lockPath}.break`;
203
+ try {
204
+ await fs.writeFile(breakerPath, `${process.pid}
205
+ ${(/* @__PURE__ */ new Date()).toISOString()}
206
+ `, {
207
+ encoding: "utf8",
208
+ flag: "wx"
209
+ });
210
+ } catch (error) {
211
+ if (error.code !== "EEXIST") {
212
+ return false;
213
+ }
214
+ if (!await isLockRecoverable(breakerPath)) {
215
+ return false;
216
+ }
217
+ await fs.unlink(breakerPath).catch(() => {
218
+ });
219
+ return false;
220
+ }
221
+ try {
222
+ if (!await isLockRecoverable(lockPath)) {
223
+ return false;
224
+ }
225
+ await fs.unlink(lockPath);
226
+ return true;
227
+ } catch (error) {
228
+ return error.code === "ENOENT";
229
+ } finally {
230
+ await fs.unlink(breakerPath).catch(() => {
231
+ });
232
+ }
233
+ }
234
+ async function isLockRecoverable(lockPath) {
235
+ let contents;
236
+ try {
237
+ contents = await fs.readFile(lockPath, "utf8");
238
+ } catch (error) {
239
+ return error.code === "ENOENT";
240
+ }
241
+ if (contents.length === 0) {
242
+ return await isMalformedLockStale(lockPath);
243
+ }
244
+ const pid = Number.parseInt(contents.split(/\r?\n/, 1)[0] ?? "", 10);
245
+ if (Number.isInteger(pid) && pid > 0) {
246
+ return !isProcessRunning(pid);
247
+ }
248
+ return await isMalformedLockStale(lockPath);
249
+ }
250
+ function isProcessRunning(pid) {
251
+ try {
252
+ process.kill(pid, 0);
253
+ return true;
254
+ } catch (error) {
255
+ return error.code === "EPERM";
256
+ }
257
+ }
258
+ async function isMalformedLockStale(lockPath) {
259
+ try {
260
+ const stats = await fs.stat(lockPath);
261
+ return Date.now() - stats.mtimeMs > MALFORMED_LOCK_STALE_MS;
262
+ } catch {
263
+ return false;
264
+ }
265
+ }
266
+
267
+ export {
268
+ readJsonFile,
269
+ writeTextFileAtomic,
270
+ writeJsonFile,
271
+ withFileLock
272
+ };