@vibe-agent-toolkit/utils 0.2.0-rc.11 → 0.2.0-rc.12

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 (322) hide show
  1. package/README.md +111 -9
  2. package/dist/archive/archive.d.ts +129 -0
  3. package/dist/archive/archive.d.ts.map +1 -0
  4. package/dist/archive/archive.js +223 -0
  5. package/dist/archive/archive.js.map +1 -0
  6. package/dist/archive/entries.d.ts +132 -0
  7. package/dist/archive/entries.d.ts.map +1 -0
  8. package/dist/archive/entries.js +223 -0
  9. package/dist/archive/entries.js.map +1 -0
  10. package/dist/archive/limits.d.ts +39 -0
  11. package/dist/archive/limits.d.ts.map +1 -0
  12. package/dist/archive/limits.js +59 -0
  13. package/dist/archive/limits.js.map +1 -0
  14. package/dist/archive/records.d.ts +14 -0
  15. package/dist/archive/records.d.ts.map +1 -0
  16. package/dist/archive/records.js +3 -0
  17. package/dist/archive/records.js.map +1 -0
  18. package/dist/archive/tar-reader.d.ts +18 -0
  19. package/dist/archive/tar-reader.d.ts.map +1 -0
  20. package/dist/archive/tar-reader.js +173 -0
  21. package/dist/archive/tar-reader.js.map +1 -0
  22. package/dist/archive/zip-reader.d.ts +76 -0
  23. package/dist/archive/zip-reader.d.ts.map +1 -0
  24. package/dist/archive/zip-reader.js +376 -0
  25. package/dist/archive/zip-reader.js.map +1 -0
  26. package/dist/archive.d.ts +14 -0
  27. package/dist/archive.d.ts.map +1 -0
  28. package/dist/archive.js +12 -0
  29. package/dist/archive.js.map +1 -0
  30. package/dist/asset-reference.d.ts +17 -1
  31. package/dist/asset-reference.d.ts.map +1 -1
  32. package/dist/asset-reference.js +31 -7
  33. package/dist/asset-reference.js.map +1 -1
  34. package/dist/dirent-kind.d.ts +13 -40
  35. package/dist/dirent-kind.d.ts.map +1 -1
  36. package/dist/dirent-kind.js +21 -69
  37. package/dist/dirent-kind.js.map +1 -1
  38. package/dist/entrypoint.d.ts +2 -2
  39. package/dist/entrypoint.d.ts.map +1 -1
  40. package/dist/entrypoint.js +4 -3
  41. package/dist/entrypoint.js.map +1 -1
  42. package/dist/env-flag.d.ts +2 -0
  43. package/dist/env-flag.d.ts.map +1 -1
  44. package/dist/env-flag.js +2 -0
  45. package/dist/env-flag.js.map +1 -1
  46. package/dist/errors/confirmed-absent.d.ts +41 -0
  47. package/dist/errors/confirmed-absent.d.ts.map +1 -0
  48. package/dist/errors/confirmed-absent.js +43 -0
  49. package/dist/errors/confirmed-absent.js.map +1 -0
  50. package/dist/errors/errno-table.d.ts +177 -0
  51. package/dist/errors/errno-table.d.ts.map +1 -0
  52. package/dist/errors/errno-table.js +343 -0
  53. package/dist/errors/errno-table.js.map +1 -0
  54. package/dist/errors/fs-boundary.d.ts +36 -0
  55. package/dist/errors/fs-boundary.d.ts.map +1 -0
  56. package/dist/errors/fs-boundary.js +121 -0
  57. package/dist/errors/fs-boundary.js.map +1 -0
  58. package/dist/errors/fs-fault.d.ts +176 -0
  59. package/dist/errors/fs-fault.d.ts.map +1 -0
  60. package/dist/errors/fs-fault.js +215 -0
  61. package/dist/errors/fs-fault.js.map +1 -0
  62. package/dist/errors/git-errno.d.ts +13 -0
  63. package/dist/errors/git-errno.d.ts.map +1 -0
  64. package/dist/errors/git-errno.js +45 -0
  65. package/dist/errors/git-errno.js.map +1 -0
  66. package/dist/errors/path-present.d.ts +72 -0
  67. package/dist/errors/path-present.d.ts.map +1 -0
  68. package/dist/errors/path-present.js +110 -0
  69. package/dist/errors/path-present.js.map +1 -0
  70. package/dist/errors/rag-index-empty.d.ts +16 -0
  71. package/dist/errors/rag-index-empty.d.ts.map +1 -0
  72. package/dist/errors/rag-index-empty.js +16 -0
  73. package/dist/errors/rag-index-empty.js.map +1 -0
  74. package/dist/errors/suppressed-faults.d.ts +34 -0
  75. package/dist/errors/suppressed-faults.d.ts.map +1 -0
  76. package/dist/errors/suppressed-faults.js +66 -0
  77. package/dist/errors/suppressed-faults.js.map +1 -0
  78. package/dist/file-crawler.d.ts +13 -18
  79. package/dist/file-crawler.d.ts.map +1 -1
  80. package/dist/file-crawler.js +140 -24
  81. package/dist/file-crawler.js.map +1 -1
  82. package/dist/fs-utils.d.ts +75 -50
  83. package/dist/fs-utils.d.ts.map +1 -1
  84. package/dist/fs-utils.js +148 -158
  85. package/dist/fs-utils.js.map +1 -1
  86. package/dist/fs.d.ts +4 -4
  87. package/dist/fs.d.ts.map +1 -1
  88. package/dist/fs.js +4 -4
  89. package/dist/fs.js.map +1 -1
  90. package/dist/git-snapshot.d.ts +25 -17
  91. package/dist/git-snapshot.d.ts.map +1 -1
  92. package/dist/git-snapshot.js +65 -11
  93. package/dist/git-snapshot.js.map +1 -1
  94. package/dist/git-tracker.d.ts +11 -3
  95. package/dist/git-tracker.d.ts.map +1 -1
  96. package/dist/git-tracker.js +29 -6
  97. package/dist/git-tracker.js.map +1 -1
  98. package/dist/git-utils.d.ts.map +1 -1
  99. package/dist/git-utils.js +7 -35
  100. package/dist/git-utils.js.map +1 -1
  101. package/dist/git.d.ts +1 -1
  102. package/dist/git.d.ts.map +1 -1
  103. package/dist/git.js +1 -1
  104. package/dist/git.js.map +1 -1
  105. package/dist/gitignore-checker.d.ts.map +1 -1
  106. package/dist/gitignore-checker.js +5 -4
  107. package/dist/gitignore-checker.js.map +1 -1
  108. package/dist/in-order.d.ts +93 -0
  109. package/dist/in-order.d.ts.map +1 -0
  110. package/dist/in-order.js +165 -0
  111. package/dist/in-order.js.map +1 -0
  112. package/dist/index.d.ts +20 -4
  113. package/dist/index.d.ts.map +1 -1
  114. package/dist/index.js +30 -4
  115. package/dist/index.js.map +1 -1
  116. package/dist/kill-process-tree.d.ts +43 -0
  117. package/dist/kill-process-tree.d.ts.map +1 -0
  118. package/dist/kill-process-tree.js +48 -0
  119. package/dist/kill-process-tree.js.map +1 -0
  120. package/dist/link-following.d.ts +115 -0
  121. package/dist/link-following.d.ts.map +1 -0
  122. package/dist/link-following.js +283 -0
  123. package/dist/link-following.js.map +1 -0
  124. package/dist/listing-refusal.d.ts +44 -0
  125. package/dist/listing-refusal.d.ts.map +1 -1
  126. package/dist/listing-refusal.js +79 -2
  127. package/dist/listing-refusal.js.map +1 -1
  128. package/dist/name-fold.d.ts +25 -0
  129. package/dist/name-fold.d.ts.map +1 -0
  130. package/dist/name-fold.js +40 -0
  131. package/dist/name-fold.js.map +1 -0
  132. package/dist/path-containment.d.ts +3 -1
  133. package/dist/path-containment.d.ts.map +1 -1
  134. package/dist/path-containment.js +13 -7
  135. package/dist/path-containment.js.map +1 -1
  136. package/dist/path-utils.d.ts +14 -17
  137. package/dist/path-utils.d.ts.map +1 -1
  138. package/dist/path-utils.js +37 -55
  139. package/dist/path-utils.js.map +1 -1
  140. package/dist/process.d.ts +2 -0
  141. package/dist/process.d.ts.map +1 -1
  142. package/dist/process.js +2 -0
  143. package/dist/process.js.map +1 -1
  144. package/dist/project-utils.d.ts.map +1 -1
  145. package/dist/project-utils.js +8 -9
  146. package/dist/project-utils.js.map +1 -1
  147. package/dist/safe-exec.d.ts +6 -2
  148. package/dist/safe-exec.d.ts.map +1 -1
  149. package/dist/safe-exec.js +1 -1
  150. package/dist/safe-exec.js.map +1 -1
  151. package/dist/skill-targets.d.ts.map +1 -1
  152. package/dist/skill-targets.js +3 -1
  153. package/dist/skill-targets.js.map +1 -1
  154. package/dist/skill-test/spawn-claude.d.ts +0 -15
  155. package/dist/skill-test/spawn-claude.d.ts.map +1 -1
  156. package/dist/skill-test/spawn-claude.js +11 -50
  157. package/dist/skill-test/spawn-claude.js.map +1 -1
  158. package/dist/special-file.d.ts +18 -0
  159. package/dist/special-file.d.ts.map +1 -0
  160. package/dist/special-file.js +21 -0
  161. package/dist/special-file.js.map +1 -0
  162. package/dist/terminating-signals.d.ts +129 -0
  163. package/dist/terminating-signals.d.ts.map +1 -0
  164. package/dist/terminating-signals.js +210 -0
  165. package/dist/terminating-signals.js.map +1 -0
  166. package/dist/test-helpers.d.ts +9 -5
  167. package/dist/test-helpers.d.ts.map +1 -1
  168. package/dist/test-helpers.js +18 -21
  169. package/dist/test-helpers.js.map +1 -1
  170. package/dist/test-scratch-guard.d.ts +34 -0
  171. package/dist/test-scratch-guard.d.ts.map +1 -0
  172. package/dist/test-scratch-guard.js +45 -0
  173. package/dist/test-scratch-guard.js.map +1 -0
  174. package/dist/testing/archive-fixtures.d.ts +147 -0
  175. package/dist/testing/archive-fixtures.d.ts.map +1 -0
  176. package/dist/testing/archive-fixtures.js +449 -0
  177. package/dist/testing/archive-fixtures.js.map +1 -0
  178. package/dist/testing/executables.d.ts +6 -0
  179. package/dist/testing/executables.d.ts.map +1 -1
  180. package/dist/testing/executables.js +20 -9
  181. package/dist/testing/executables.js.map +1 -1
  182. package/dist/testing/fault-fs-preload.d.ts +16 -0
  183. package/dist/testing/fault-fs-preload.d.ts.map +1 -0
  184. package/dist/testing/fault-fs-preload.js +22 -0
  185. package/dist/testing/fault-fs-preload.js.map +1 -0
  186. package/dist/testing/fault-fs.d.ts +115 -0
  187. package/dist/testing/fault-fs.d.ts.map +1 -0
  188. package/dist/testing/fault-fs.js +411 -0
  189. package/dist/testing/fault-fs.js.map +1 -0
  190. package/dist/testing/fault-spec.d.ts +83 -0
  191. package/dist/testing/fault-spec.d.ts.map +1 -0
  192. package/dist/testing/fault-spec.js +132 -0
  193. package/dist/testing/fault-spec.js.map +1 -0
  194. package/dist/testing/hostile-tree.d.ts.map +1 -1
  195. package/dist/testing/hostile-tree.js +3 -4
  196. package/dist/testing/hostile-tree.js.map +1 -1
  197. package/dist/testing/platform-gates.d.ts +8 -0
  198. package/dist/testing/platform-gates.d.ts.map +1 -1
  199. package/dist/testing/platform-gates.js +24 -0
  200. package/dist/testing/platform-gates.js.map +1 -1
  201. package/dist/testing/temp-dir.d.ts +31 -0
  202. package/dist/testing/temp-dir.d.ts.map +1 -1
  203. package/dist/testing/temp-dir.js +63 -0
  204. package/dist/testing/temp-dir.js.map +1 -1
  205. package/dist/testing/tier-timeout.d.ts +34 -0
  206. package/dist/testing/tier-timeout.d.ts.map +1 -0
  207. package/dist/testing/tier-timeout.js +45 -0
  208. package/dist/testing/tier-timeout.js.map +1 -0
  209. package/dist/testing/tree-snapshot.d.ts +71 -0
  210. package/dist/testing/tree-snapshot.d.ts.map +1 -0
  211. package/dist/testing/tree-snapshot.js +163 -0
  212. package/dist/testing/tree-snapshot.js.map +1 -0
  213. package/dist/testing.d.ts +6 -0
  214. package/dist/testing.d.ts.map +1 -1
  215. package/dist/testing.js +8 -1
  216. package/dist/testing.js.map +1 -1
  217. package/dist/text-file.d.ts +14 -1
  218. package/dist/text-file.d.ts.map +1 -1
  219. package/dist/text-file.js +41 -8
  220. package/dist/text-file.js.map +1 -1
  221. package/dist/timing-dump.d.ts.map +1 -1
  222. package/dist/timing-dump.js +2 -10
  223. package/dist/timing-dump.js.map +1 -1
  224. package/dist/tree-change/apply-decisions.d.ts +101 -0
  225. package/dist/tree-change/apply-decisions.d.ts.map +1 -0
  226. package/dist/tree-change/apply-decisions.js +139 -0
  227. package/dist/tree-change/apply-decisions.js.map +1 -0
  228. package/dist/tree-change/apply.d.ts +98 -0
  229. package/dist/tree-change/apply.d.ts.map +1 -0
  230. package/dist/tree-change/apply.js +364 -0
  231. package/dist/tree-change/apply.js.map +1 -0
  232. package/dist/tree-change/copy-decisions.d.ts +58 -0
  233. package/dist/tree-change/copy-decisions.d.ts.map +1 -0
  234. package/dist/tree-change/copy-decisions.js +66 -0
  235. package/dist/tree-change/copy-decisions.js.map +1 -0
  236. package/dist/tree-change/copy-tree.d.ts +125 -0
  237. package/dist/tree-change/copy-tree.d.ts.map +1 -0
  238. package/dist/tree-change/copy-tree.js +279 -0
  239. package/dist/tree-change/copy-tree.js.map +1 -0
  240. package/dist/tree-change/files.d.ts +167 -0
  241. package/dist/tree-change/files.d.ts.map +1 -0
  242. package/dist/tree-change/files.js +423 -0
  243. package/dist/tree-change/files.js.map +1 -0
  244. package/dist/tree-change/followed-walk.d.ts +54 -0
  245. package/dist/tree-change/followed-walk.d.ts.map +1 -0
  246. package/dist/tree-change/followed-walk.js +81 -0
  247. package/dist/tree-change/followed-walk.js.map +1 -0
  248. package/dist/tree-change/host-chain.d.ts +48 -0
  249. package/dist/tree-change/host-chain.d.ts.map +1 -0
  250. package/dist/tree-change/host-chain.js +85 -0
  251. package/dist/tree-change/host-chain.js.map +1 -0
  252. package/dist/tree-change/identity-compare.d.ts +61 -0
  253. package/dist/tree-change/identity-compare.d.ts.map +1 -0
  254. package/dist/tree-change/identity-compare.js +115 -0
  255. package/dist/tree-change/identity-compare.js.map +1 -0
  256. package/dist/tree-change/identity.d.ts +62 -0
  257. package/dist/tree-change/identity.d.ts.map +1 -0
  258. package/dist/tree-change/identity.js +152 -0
  259. package/dist/tree-change/identity.js.map +1 -0
  260. package/dist/tree-change/index.d.ts +24 -0
  261. package/dist/tree-change/index.d.ts.map +1 -0
  262. package/dist/tree-change/index.js +14 -0
  263. package/dist/tree-change/index.js.map +1 -0
  264. package/dist/tree-change/link-chain.d.ts +180 -0
  265. package/dist/tree-change/link-chain.d.ts.map +1 -0
  266. package/dist/tree-change/link-chain.js +377 -0
  267. package/dist/tree-change/link-chain.js.map +1 -0
  268. package/dist/tree-change/link-containment.d.ts +105 -0
  269. package/dist/tree-change/link-containment.d.ts.map +1 -0
  270. package/dist/tree-change/link-containment.js +196 -0
  271. package/dist/tree-change/link-containment.js.map +1 -0
  272. package/dist/tree-change/link-walk.d.ts +49 -0
  273. package/dist/tree-change/link-walk.d.ts.map +1 -0
  274. package/dist/tree-change/link-walk.js +69 -0
  275. package/dist/tree-change/link-walk.js.map +1 -0
  276. package/dist/tree-change/plan.d.ts +206 -0
  277. package/dist/tree-change/plan.d.ts.map +1 -0
  278. package/dist/tree-change/plan.js +320 -0
  279. package/dist/tree-change/plan.js.map +1 -0
  280. package/dist/tree-change/readable-tree.d.ts +44 -0
  281. package/dist/tree-change/readable-tree.d.ts.map +1 -0
  282. package/dist/tree-change/readable-tree.js +52 -0
  283. package/dist/tree-change/readable-tree.js.map +1 -0
  284. package/dist/tree-change/rollback-error.d.ts +29 -0
  285. package/dist/tree-change/rollback-error.d.ts.map +1 -0
  286. package/dist/tree-change/rollback-error.js +31 -0
  287. package/dist/tree-change/rollback-error.js.map +1 -0
  288. package/dist/tree-change/staging-names.d.ts +27 -0
  289. package/dist/tree-change/staging-names.d.ts.map +1 -0
  290. package/dist/tree-change/staging-names.js +40 -0
  291. package/dist/tree-change/staging-names.js.map +1 -0
  292. package/dist/tree-change/tree-walk.d.ts +81 -0
  293. package/dist/tree-change/tree-walk.d.ts.map +1 -0
  294. package/dist/tree-change/tree-walk.js +212 -0
  295. package/dist/tree-change/tree-walk.js.map +1 -0
  296. package/dist/win32-namespace.d.ts +24 -0
  297. package/dist/win32-namespace.d.ts.map +1 -0
  298. package/dist/win32-namespace.js +31 -0
  299. package/dist/win32-namespace.js.map +1 -0
  300. package/dist/yaml/surgical-yaml.d.ts +12 -3
  301. package/dist/yaml/surgical-yaml.d.ts.map +1 -1
  302. package/dist/yaml/surgical-yaml.js +16 -6
  303. package/dist/yaml/surgical-yaml.js.map +1 -1
  304. package/eslint/README.md +12 -4
  305. package/eslint/rules/fs-binding-scan.cjs +278 -0
  306. package/eslint/rules/no-adhoc-errno.cjs +364 -0
  307. package/eslint/rules/no-bare-symlink-in-tests.cjs +2 -3
  308. package/eslint/rules/no-blind-catch.cjs +1 -1
  309. package/eslint/rules/no-destructive-fs.cjs +359 -0
  310. package/eslint/rules/no-existssync.cjs +70 -0
  311. package/eslint/rules/no-fragile-entrypoint-guard.cjs +3 -2
  312. package/eslint/rules/no-link-following-fs.cjs +68 -0
  313. package/eslint/rules/no-literal-process-exit.cjs +3 -16
  314. package/eslint/rules/no-literal-test-timeout.cjs +214 -0
  315. package/eslint/rules/no-raw-signal-listener.cjs +224 -0
  316. package/eslint/rules/no-stdout-outside-writer.cjs +135 -0
  317. package/package.json +10 -2
  318. package/dist/errors/errno.d.ts +0 -51
  319. package/dist/errors/errno.d.ts.map +0 -1
  320. package/dist/errors/errno.js +0 -112
  321. package/dist/errors/errno.js.map +0 -1
  322. package/eslint/rules/no-fs-promises-cp.cjs +0 -43
@@ -2,18 +2,9 @@ import { randomBytes } from 'node:crypto';
2
2
  import nodeFs, { rmSync, symlinkSync } from 'node:fs';
3
3
  import fs from 'node:fs/promises';
4
4
  import { syncBuiltinESMExports } from 'node:module';
5
- import { isFilesystemAccessError } from './errors/errno.js';
5
+ import { fsFaultOf, isSymlinkUnsupportedError } from './errors/errno-table.js';
6
6
  import { normalizedTmpdir, safePath, toForwardSlash } from './path-utils.js';
7
7
  let cachedCapability;
8
- /**
9
- * The errnos that mean "this host cannot create symlinks": Windows without
10
- * Developer Mode or `SeCreateSymbolicLinkPrivilege` (`EPERM`), and a
11
- * filesystem that has no symlinks to offer (`ENOTSUP` / `EOPNOTSUPP`).
12
- */
13
- const SYMLINK_UNSUPPORTED_ERRNOS = new Set(['EPERM', 'ENOTSUP', 'EOPNOTSUPP']);
14
- function isSymlinkUnsupported(error) {
15
- return error instanceof Error && 'code' in error && typeof error.code === 'string' && SYMLINK_UNSUPPORTED_ERRNOS.has(error.code);
16
- }
17
8
  /**
18
9
  * Whether this PROCESS can create symlinks — probed once and memoized.
19
10
  *
@@ -28,7 +19,7 @@ function isSymlinkUnsupported(error) {
28
19
  *
29
20
  * Because the answer is memoized for the whole process, what reads as "no"
30
21
  * matters more than usual: a `null` here silently `skip()`s every symlink test
31
- * for the rest of the run. So ONLY {@link SYMLINK_UNSUPPORTED_ERRNOS} is a
22
+ * for the rest of the run. So ONLY {@link isSymlinkUnsupportedError} is a
32
23
  * no. A tmpdir that is unwritable or missing, or a bug, is not an answer about
33
24
  * symlinks at all and stays loud rather than becoming a process-wide skip for
34
25
  * a reason nothing reported.
@@ -45,11 +36,11 @@ export function symlinkCapability() {
45
36
  if (cachedCapability === undefined) {
46
37
  const probe = safePath.join(normalizedTmpdir(), `.vat-symlink-probe-${randomBytes(4).toString('hex')}`);
47
38
  try {
48
- symlinkSync('.', probe);
39
+ symlinkSync('.', probe, 'dir');
49
40
  cachedCapability = {};
50
41
  }
51
42
  catch (error) {
52
- if (!isSymlinkUnsupported(error))
43
+ if (!isSymlinkUnsupportedError(error))
53
44
  throw error;
54
45
  cachedCapability = null;
55
46
  }
@@ -63,7 +54,7 @@ export function symlinkCapability() {
63
54
  rmSync(probe, { force: true });
64
55
  }
65
56
  catch (error) {
66
- if (!isFilesystemAccessError(error))
57
+ if (fsFaultOf(error) === undefined)
67
58
  throw error;
68
59
  }
69
60
  }
@@ -174,10 +165,11 @@ export function detachGitEnv() {
174
165
  }
175
166
  /**
176
167
  * The errno-shaped error a refused `fs` call throws: a message, the `code`,
177
- * and the `syscall`, exactly as Node shapes one.
168
+ * the `syscall` and the `path`, exactly as Node shapes one — a caller that names
169
+ * the refused file from `path` (a tree probe naming the nested file) reads it.
178
170
  */
179
171
  export function errnoError(code, syscall, target) {
180
- return Object.assign(new Error(`${code}: refused, ${syscall} '${target}'`), { code, syscall });
172
+ return Object.assign(new Error(`${code}: refused, ${syscall} '${target}'`), { code, syscall, path: target });
181
173
  }
182
174
  /**
183
175
  * Assign `fn` over `module[method]` and republish the builtin's ESM bindings.
@@ -220,13 +212,18 @@ export function refuseSyncFs(method, targetPath, code) {
220
212
  /**
221
213
  * `fs/promises[method]` rejects with `code` for exactly `targetPath` until the
222
214
  * returned restore is called; every other path, and every other method, is real.
215
+ * `beforeRefusing`, when given, runs first on each refused call — a write that
216
+ * fails partway (a full disk) leaves a truncated file behind, and a test of the
217
+ * cleanup needs that file to exist.
223
218
  */
224
- export function refuseAsyncFs(method, targetPath, code) {
219
+ export function refuseAsyncFs(method, targetPath, code, beforeRefusing) {
225
220
  const original = fs[method].bind(fs);
226
221
  const refused = toForwardSlash(targetPath);
227
- republish(fs, method, async (target, ...rest) => {
228
- if (toForwardSlash(String(target)) === refused)
229
- throw errnoError(code, method, String(target));
222
+ republish(fs, method, (target, ...rest) => {
223
+ if (toForwardSlash(String(target)) === refused) {
224
+ beforeRefusing?.();
225
+ return Promise.reject(errnoError(code, method, String(target)));
226
+ }
230
227
  return original(target, ...rest);
231
228
  });
232
229
  return () => republish(fs, method, original);
@@ -254,7 +251,7 @@ export async function withSyncFsRefused(method, targetPath, code, body) {
254
251
  * @param body - Runs while the refusal is in force; may be async
255
252
  * @returns Whatever `body` returned
256
253
  */
257
- export async function withReaddirSyncRefused(directory, code, body) {
254
+ export function withReaddirSyncRefused(directory, code, body) {
258
255
  return withSyncFsRefused('readdirSync', directory, code, body);
259
256
  }
260
257
  //# sourceMappingURL=test-helpers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../src/test-helpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../src/test-helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The fail-closed guard for user state in a TEST process.
3
+ *
4
+ * VAT keeps state under the user's home: the Claude directory (`CLAUDE_CONFIG_DIR`, else
5
+ * `$HOME/.claude`), every other target's user-scope skills directory (`~/.codex/skills`, …), the
6
+ * session store. A test that reaches one of them without redirecting it writes a developer's real
7
+ * configuration, exit 0, with nothing in its output to say so — it has happened, twice, to a live
8
+ * Claude config. So each place that resolves such a root passes it through
9
+ * {@link requireTestScratch}, which throws when the test harness has named the one tree user state
10
+ * may be in and the root is outside it.
11
+ *
12
+ * No user sets the variable: unset, the guard does nothing and costs one environment read.
13
+ */
14
+ /**
15
+ * The variable a test process sets to the tree its user state may be in: the OS temp directory, in
16
+ * each spelling it has (`path.delimiter`-separated — on macOS `/var/…` and the `/private/var/…` it
17
+ * links to). The repo's shared vitest setup arms it in every tier, and every `vat` child a test
18
+ * spawns inherits it.
19
+ */
20
+ export declare const TEST_USER_STATE_UNDER = "VAT_TEST_USER_STATE_UNDER";
21
+ /**
22
+ * `root` — a directory of user state VAT is about to hand out — unless a test process named the tree
23
+ * it must be in and it is outside that tree.
24
+ *
25
+ * Judged by spelling alone, with no filesystem call: the guard must not itself be a read the OS can
26
+ * refuse (a fault-injection run would fail the guard instead of the verb under test).
27
+ *
28
+ * @param root - The resolved directory, absolute
29
+ * @param what - What it is, for the message: `The Claude directory`
30
+ * @returns `root`, unchanged
31
+ * @throws Error naming the directory and the tree, when the variable is set and `root` is outside it
32
+ */
33
+ export declare function requireTestScratch(root: string, what: string): string;
34
+ //# sourceMappingURL=test-scratch-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-scratch-guard.d.ts","sourceRoot":"","sources":["../src/test-scratch-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,8BAA8B,CAAC;AAEjE;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CASrE"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The fail-closed guard for user state in a TEST process.
3
+ *
4
+ * VAT keeps state under the user's home: the Claude directory (`CLAUDE_CONFIG_DIR`, else
5
+ * `$HOME/.claude`), every other target's user-scope skills directory (`~/.codex/skills`, …), the
6
+ * session store. A test that reaches one of them without redirecting it writes a developer's real
7
+ * configuration, exit 0, with nothing in its output to say so — it has happened, twice, to a live
8
+ * Claude config. So each place that resolves such a root passes it through
9
+ * {@link requireTestScratch}, which throws when the test harness has named the one tree user state
10
+ * may be in and the root is outside it.
11
+ *
12
+ * No user sets the variable: unset, the guard does nothing and costs one environment read.
13
+ */
14
+ import { delimiter } from 'node:path';
15
+ import { relativeEscapesRoot, safePath } from './path-core.js';
16
+ /**
17
+ * The variable a test process sets to the tree its user state may be in: the OS temp directory, in
18
+ * each spelling it has (`path.delimiter`-separated — on macOS `/var/…` and the `/private/var/…` it
19
+ * links to). The repo's shared vitest setup arms it in every tier, and every `vat` child a test
20
+ * spawns inherits it.
21
+ */
22
+ export const TEST_USER_STATE_UNDER = 'VAT_TEST_USER_STATE_UNDER';
23
+ /**
24
+ * `root` — a directory of user state VAT is about to hand out — unless a test process named the tree
25
+ * it must be in and it is outside that tree.
26
+ *
27
+ * Judged by spelling alone, with no filesystem call: the guard must not itself be a read the OS can
28
+ * refuse (a fault-injection run would fail the guard instead of the verb under test).
29
+ *
30
+ * @param root - The resolved directory, absolute
31
+ * @param what - What it is, for the message: `The Claude directory`
32
+ * @returns `root`, unchanged
33
+ * @throws Error naming the directory and the tree, when the variable is set and `root` is outside it
34
+ */
35
+ export function requireTestScratch(root, what) {
36
+ const under = process.env[TEST_USER_STATE_UNDER]?.trim();
37
+ if (under === undefined || under.length === 0)
38
+ return root;
39
+ const trees = under.split(delimiter).filter((tree) => tree.length > 0);
40
+ if (trees.some((tree) => !relativeEscapesRoot(safePath.relative(tree, root))))
41
+ return root;
42
+ throw new Error(`${what} resolves to ${root}, outside ${under}: refusing to resolve it in a test process `
43
+ + `(${TEST_USER_STATE_UNDER} is set). Point the test at a temp directory first — HOME (and CLAUDE_CONFIG_DIR, blank or under it).`);
44
+ }
45
+ //# sourceMappingURL=test-scratch-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-scratch-guard.js","sourceRoot":"","sources":["../src/test-scratch-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,2BAA2B,CAAC;AAEjE;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,IAAY;IAC3D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,EAAE,IAAI,EAAE,CAAC;IACzD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3D,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvE,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,mBAAmB,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3F,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,gBAAgB,IAAI,aAAa,KAAK,6CAA6C;UACtF,IAAI,qBAAqB,uGAAuG,CACrI,CAAC;AACJ,CAAC"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Archives for tests, written byte by byte — the ONE place a suite builds a tarball or a ZIP.
3
+ *
4
+ * Hand-written on purpose. An archive library writes only what it considers an archive: it
5
+ * strips a leading `/`, folds `..` away, refuses a name listed twice and will not mark an entry
6
+ * a link or a device. Those are exactly the archives an extractor must refuse, so a fixture
7
+ * built with the library under test cannot express them. Nothing here imports `tar` or
8
+ * `adm-zip` — only `packages/utils/src/archive/` does.
9
+ */
10
+ /** One entry of a fixture archive, exactly as the archive will spell it. */
11
+ export interface ArchiveFixtureEntry {
12
+ /** The entry name, verbatim: `../x`, `/abs`, `C:\\x` and a name already listed are all written as given. */
13
+ readonly name: string;
14
+ /** What the entry is; `file` when omitted. `device` is a character device. */
15
+ readonly kind?: 'file' | 'directory' | 'link' | 'hardlink' | 'device' | 'fifo';
16
+ /** A file's bytes. */
17
+ readonly data?: string | Uint8Array;
18
+ /** Where a `link` or `hardlink` points, verbatim. */
19
+ readonly target?: string;
20
+ /** Permission bits (setuid, setgid and sticky included); `0o644`, or `0o755` for a directory, when omitted. */
21
+ readonly mode?: number;
22
+ /** The size the entry's header DECLARES, when it should differ from the data's own length. */
23
+ readonly declaredSize?: number;
24
+ /** When a ZIP entry says it was last modified (local time, two-second resolution); the DOS epoch when omitted. */
25
+ readonly modified?: Date;
26
+ /**
27
+ * Tar only: the header's type byte, verbatim, in place of the one `kind` gives — `x` (a PAX
28
+ * header whose `data` overrides the next entry), `L` (a GNU long name), `S` (sparse), `D` (a GNU
29
+ * dump directory), or a byte no tar defines.
30
+ */
31
+ readonly tarType?: string;
32
+ }
33
+ /**
34
+ * One PAX extended-header record, `<length> <key>=<value>\n`, the length counting itself: the
35
+ * `data` of a `tarType: 'x'` entry, which overrides that field of the entry after it.
36
+ *
37
+ * @param key - The field: `path`, `linkpath`, `size`
38
+ * @param value - Its value, verbatim
39
+ */
40
+ export declare function paxRecord(key: string, value: string): string;
41
+ /**
42
+ * A tar archive of `entries`, in order, gzipped unless `options.gzip` is `false`.
43
+ *
44
+ * @param entries - The entries, written exactly as given
45
+ * @param options - `gzip: false` for a plain tar
46
+ * @returns The archive's bytes
47
+ */
48
+ export declare function tarFixture(entries: readonly ArchiveFixtureEntry[], options?: {
49
+ readonly gzip?: boolean;
50
+ }): Buffer;
51
+ /**
52
+ * A ZIP archive of `entries`, in order, each as a ZIP made on Unix records it (so a link, a
53
+ * device and an executable bit are all expressible).
54
+ *
55
+ * @param entries - The entries, written exactly as given; a `hardlink` throws (a ZIP has none)
56
+ * @param options - `compress: false` to store every entry instead of deflating it
57
+ * @returns The archive's bytes
58
+ */
59
+ export declare function zipFixture(entries: readonly ArchiveFixtureEntry[], options?: {
60
+ readonly compress?: boolean;
61
+ }): Buffer;
62
+ /**
63
+ * A directory tree as fixture entries, in listing order: each directory, then what it holds; a
64
+ * file with its bytes and permission bits; a symbolic link as a link entry with its target
65
+ * verbatim (never followed). What a test that used to `tar` or `zip` a directory hands
66
+ * {@link tarFixture} or {@link zipFixture}.
67
+ *
68
+ * @param dir - The directory to read
69
+ * @param prefix - What each entry name begins with: `''`, or a directory name ending in `/` (`package/`)
70
+ * @returns The entries of `dir`, `dir` itself not among them
71
+ */
72
+ export declare function archiveEntriesOfDirectory(dir: string, prefix?: string): ArchiveFixtureEntry[];
73
+ /**
74
+ * An archive of `format` holding `entries` — {@link tarFixture} (gzipped) or {@link zipFixture}
75
+ * (deflated) — for a suite that runs the same rows through both formats.
76
+ */
77
+ export declare function archiveFixture(format: 'tar' | 'zip', entries: readonly ArchiveFixtureEntry[]): Buffer;
78
+ /** One archive an extractor must refuse: what makes it hostile, and the entries that do. */
79
+ export interface HostileArchiveRow {
80
+ /** What the archive holds, for a test's title. */
81
+ readonly what: string;
82
+ /** The formats that can express it (a ZIP has no hard link). */
83
+ readonly formats: ReadonlyArray<'tar' | 'zip'>;
84
+ /** The `ArchiveRefusedError` reason the archive module gives. */
85
+ readonly reason: 'link' | 'hardlink' | 'special' | 'unsafe-name' | 'name-clash' | 'unreadable' | 'unsupported' | 'too-many-entries' | 'too-large';
86
+ /**
87
+ * The offending entries, to add to an otherwise sound archive.
88
+ *
89
+ * @param prefix - Where inside the archive they go: `''`, or a directory name ending in `/`
90
+ */
91
+ readonly entries: (prefix: string) => ArchiveFixtureEntry[];
92
+ /**
93
+ * For a row that is hostile in its FRAMING rather than its entries: what to do to the built
94
+ * archive's bytes. A suite hands every archive it builds for a row through {@link hostileArchive}.
95
+ */
96
+ readonly mangle?: (archive: Buffer) => Buffer;
97
+ }
98
+ /**
99
+ * The archive a row stands for: `built` — the suite's sound archive with the row's entries — as
100
+ * the row frames it. Every suite that runs {@link hostileArchiveRows} passes its bytes through here.
101
+ *
102
+ * @param row - The row
103
+ * @param built - The archive the suite built from the row's entries
104
+ */
105
+ export declare function hostileArchive(row: HostileArchiveRow, built: Buffer): Buffer;
106
+ /**
107
+ * `archive` (a {@link zipFixture}) with `stub` before its first local header: a self-extracting
108
+ * ZIP. `adjusted` moves every offset its central directory and end record hold by the stub's
109
+ * length, as `zip -A` and an SFX builder do, so the directory still names each local header.
110
+ *
111
+ * @param archive - The ZIP
112
+ * @param stub - The bytes to put before it
113
+ * @param adjusted - Whether the offsets are moved to match
114
+ */
115
+ export declare function withZipStub(archive: Buffer, stub: Buffer, adjusted: boolean): Buffer;
116
+ /**
117
+ * `archive` (a {@link zipFixture}) carrying `entry` as a local header and its data after its last
118
+ * listed entry, before a central directory that does not list it: an entry only a reader that
119
+ * walks local headers from the front sees. Every offset still agrees, so a reader that holds the
120
+ * directory to its own reading takes the archive.
121
+ *
122
+ * @param archive - The ZIP
123
+ * @param entry - The entry its local headers hold and its directory does not
124
+ */
125
+ export declare function withUnlistedLocalEntry(archive: Buffer, entry: ArchiveFixtureEntry): Buffer;
126
+ /**
127
+ * A ZIP member that holds more than its directory declares: the archive parses and its entry list
128
+ * passes the policy, and the member is refused only when it is READ — `ArchiveEntryReadError`,
129
+ * `ARCHIVE_ENTRY_UNREADABLE`, never an `ArchiveRefusedError`, so it is no row of
130
+ * {@link hostileArchiveRows} (whose rows each name an `ArchiveRefusedError` reason). Each lane that
131
+ * reads a ZIP's members runs it beside that table, so the CLI's mapping of the code to
132
+ * `INPUT_UNREADABLE` is held by every lane that can raise it.
133
+ *
134
+ * @param prefix - Where inside the archive it goes: `''`, or a directory name ending in `/`
135
+ */
136
+ export declare function entryHoldingMoreThanDeclared(prefix: string): ArchiveFixtureEntry[];
137
+ /**
138
+ * Every shape of archive VAT refuses to extract, as rows a suite runs through each lane that
139
+ * extracts one: the same table for the archive module's own tests and for every verb's.
140
+ *
141
+ * @param limits - The bounds the lane under test holds an archive to; the last two rows are built just past them
142
+ */
143
+ export declare function hostileArchiveRows(limits: {
144
+ readonly maxEntries: number;
145
+ readonly maxBytes: number;
146
+ }): HostileArchiveRow[];
147
+ //# sourceMappingURL=archive-fixtures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive-fixtures.d.ts","sourceRoot":"","sources":["../../src/testing/archive-fixtures.ts"],"names":[],"mappings":"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"}