@openclaw/signal 2026.9.6 → 2026.9.7

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 (279) hide show
  1. package/assets/icon.png +0 -0
  2. package/dist/.setup/{accounts-BV6tDOTc.mjs → accounts-DMtj2E-4.mjs} +6 -35
  3. package/dist/.setup/api-DEB0Obj8.mjs +16 -0
  4. package/dist/.setup/{api-CGh4eWR8.mjs → api-DmCb6e7E.mjs} +10 -10
  5. package/dist/.setup/{approval-auth-BBI9BTRm.mjs → approval-auth-CszS7gwf.mjs} +7 -13
  6. package/dist/.setup/{approval-handler.runtime-C3vN5OWd.mjs → approval-handler.runtime-D9ofZcZW.mjs} +10 -29
  7. package/dist/.setup/{approval-reactions-DDQvPP_z.mjs → approval-reactions-BKkjIAoi.mjs} +25 -36
  8. package/dist/.setup/{channel-DhzTcFsK.mjs → channel-DrUxv5cf.mjs} +567 -136
  9. package/dist/.setup/{client-BseAt7F7.mjs → client-AXcDteBZ.mjs} +63 -152
  10. package/dist/.setup/client-adapter-c_O1ouxZ.mjs +30 -0
  11. package/dist/.setup/{config-schema-aQwwMGUj.mjs → config-schema-DvxZ18SD.mjs} +3 -13
  12. package/dist/.setup/{doctor-contract-api-Rbq_sRTI.mjs → doctor-contract-api-Db9V9gsY.mjs} +212 -91
  13. package/dist/.setup/{identity-YXPmgFMu.mjs → identity-B3JyPqGO.mjs} +2 -6
  14. package/dist/.setup/{install-signal-cli-BDbzFcU2.mjs → install-signal-cli-ChvjzM6X.mjs} +0 -4
  15. package/dist/.setup/legacy-transport-QIpaMNST.mjs +18 -0
  16. package/dist/.setup/{monitor-Dnz6Ygz5.mjs → monitor-BfwQr78f.mjs} +95 -124
  17. package/dist/.setup/{probe-DXT2eLnw.mjs → probe-BYLzra6D.mjs} +9 -9
  18. package/dist/.setup/{reaction-runtime-api-BnQGHcrB.mjs → reaction-runtime-api-DDi5x2wC.mjs} +3 -17
  19. package/dist/.setup/{question-reactions-C8cSEjVf.mjs → reaction-targets-CEdyjtrC.mjs} +11 -8
  20. package/dist/.setup/{rpc-context-CwwADZ1b.mjs → rpc-context-D26RxFIm.mjs} +1 -1
  21. package/dist/.setup/runtime-8sxUF217.mjs +8 -0
  22. package/dist/.setup/{send-B78M_eFp.mjs → send-DEjrbpIC.mjs} +25 -55
  23. package/dist/.setup/{channel.runtime-CG79z_Vy.mjs → setup-surface-Drt-4t3R.mjs} +4 -6
  24. package/dist/.setup/transport-detection-BVUDE42e.mjs +25 -0
  25. package/dist/.setup/{transport-policy-5VSnj5ma.mjs → transport-policy-B6C_LogW.mjs} +19 -1
  26. package/dist/.setup/transport-probes.runtime-DwXEHnXr.mjs +2 -0
  27. package/dist/api.js +10 -10
  28. package/dist/channel-config-api.js +1 -1
  29. package/dist/channel-plugin-api.js +1 -1
  30. package/dist/contract-api.js +2 -2
  31. package/dist/doctor-contract-api.js +1 -1
  32. package/dist/reaction-runtime-api.js +1 -1
  33. package/dist/runtime-api.js +2 -19
  34. package/dist/setup-entry.js +1 -1
  35. package/node_modules/@openclaw/fs-safe/CHANGELOG.md +102 -0
  36. package/node_modules/@openclaw/fs-safe/README.md +24 -6
  37. package/node_modules/@openclaw/fs-safe/dist/advanced.d.ts +6 -1
  38. package/node_modules/@openclaw/fs-safe/dist/advanced.js +3 -1
  39. package/node_modules/@openclaw/fs-safe/dist/archive-durability.js +1 -1
  40. package/node_modules/@openclaw/fs-safe/dist/archive-merge.js +1 -2
  41. package/node_modules/@openclaw/fs-safe/dist/archive-plan.d.ts +2 -7
  42. package/node_modules/@openclaw/fs-safe/dist/archive-read.js +9 -18
  43. package/node_modules/@openclaw/fs-safe/dist/archive-staging.d.ts +1 -2
  44. package/node_modules/@openclaw/fs-safe/dist/archive-staging.js +3 -3
  45. package/node_modules/@openclaw/fs-safe/dist/archive-zip-directory.js +4 -0
  46. package/node_modules/@openclaw/fs-safe/dist/archive-zip-entry.d.ts +11 -11
  47. package/node_modules/@openclaw/fs-safe/dist/archive-zip-entry.js +3 -35
  48. package/node_modules/@openclaw/fs-safe/dist/archive-zip-integrity.d.ts +2 -2
  49. package/node_modules/@openclaw/fs-safe/dist/archive-zip-integrity.js +2 -12
  50. package/node_modules/@openclaw/fs-safe/dist/archive-zip-loader.d.ts +7 -3
  51. package/node_modules/@openclaw/fs-safe/dist/archive-zip-loader.js +13 -10
  52. package/node_modules/@openclaw/fs-safe/dist/archive-zip-manifest.js +3 -1
  53. package/node_modules/@openclaw/fs-safe/dist/archive-zip-preflight.d.ts +2 -3
  54. package/node_modules/@openclaw/fs-safe/dist/archive-zip-preflight.js +16 -8
  55. package/node_modules/@openclaw/fs-safe/dist/archive.d.ts +6 -3
  56. package/node_modules/@openclaw/fs-safe/dist/archive.js +22 -19
  57. package/node_modules/@openclaw/fs-safe/dist/atomic.d.ts +1 -1
  58. package/node_modules/@openclaw/fs-safe/dist/copy-publication.d.ts +1 -3
  59. package/node_modules/@openclaw/fs-safe/dist/copy-publication.js +2 -6
  60. package/node_modules/@openclaw/fs-safe/dist/deny-mutation-match.d.ts +2 -0
  61. package/node_modules/@openclaw/fs-safe/dist/deny-mutation-match.js +71 -0
  62. package/node_modules/@openclaw/fs-safe/dist/deny-mutations.js +4 -3
  63. package/node_modules/@openclaw/fs-safe/dist/directory-guard.d.ts +0 -1
  64. package/node_modules/@openclaw/fs-safe/dist/directory-guard.js +0 -3
  65. package/node_modules/@openclaw/fs-safe/dist/directory-mode-node.d.ts +20 -2
  66. package/node_modules/@openclaw/fs-safe/dist/directory-mode-node.js +77 -1
  67. package/node_modules/@openclaw/fs-safe/dist/directory-receipt.js +5 -7
  68. package/node_modules/@openclaw/fs-safe/dist/effective-uid.js +1 -4
  69. package/node_modules/@openclaw/fs-safe/dist/errors.d.ts +3 -1
  70. package/node_modules/@openclaw/fs-safe/dist/errors.js +3 -2
  71. package/node_modules/@openclaw/fs-safe/dist/file-identity.js +10 -2
  72. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-acquisition.js +1 -1
  73. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-admission.js +5 -1
  74. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-held.d.ts +4 -11
  75. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-held.js +1 -4
  76. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-io.d.ts +3 -6
  77. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-io.js +1 -1
  78. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-options.d.ts +2 -10
  79. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root.d.ts +2 -4
  80. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync.js +2 -2
  81. package/node_modules/@openclaw/fs-safe/dist/file-store-boundary.d.ts +3 -7
  82. package/node_modules/@openclaw/fs-safe/dist/file-store-boundary.js +7 -10
  83. package/node_modules/@openclaw/fs-safe/dist/file-store-prune.js +7 -6
  84. package/node_modules/@openclaw/fs-safe/dist/file-store.d.ts +4 -7
  85. package/node_modules/@openclaw/fs-safe/dist/file-store.js +19 -21
  86. package/node_modules/@openclaw/fs-safe/dist/guest-native-python.js +23 -31
  87. package/node_modules/@openclaw/fs-safe/dist/guest.js +21 -12
  88. package/node_modules/@openclaw/fs-safe/dist/json-document-store.d.ts +4 -9
  89. package/node_modules/@openclaw/fs-safe/dist/json-durable-queue-ownership.d.ts +1 -5
  90. package/node_modules/@openclaw/fs-safe/dist/json-durable-queue.d.ts +0 -1
  91. package/node_modules/@openclaw/fs-safe/dist/json-durable-queue.js +2 -7
  92. package/node_modules/@openclaw/fs-safe/dist/local-file-access.js +2 -5
  93. package/node_modules/@openclaw/fs-safe/dist/local-file-descriptor.d.ts +2 -5
  94. package/node_modules/@openclaw/fs-safe/dist/local-roots.d.ts +2 -7
  95. package/node_modules/@openclaw/fs-safe/dist/move-path-cleanup.js +4 -4
  96. package/node_modules/@openclaw/fs-safe/dist/mutation-authority.js +5 -0
  97. package/node_modules/@openclaw/fs-safe/dist/native-binding.d.ts +51 -14
  98. package/node_modules/@openclaw/fs-safe/dist/native-pinned-write.js +8 -2
  99. package/node_modules/@openclaw/fs-safe/dist/native-staged-symlink.d.ts +13 -0
  100. package/node_modules/@openclaw/fs-safe/dist/native-staged-symlink.js +303 -0
  101. package/node_modules/@openclaw/fs-safe/dist/owner-dacl-batch-worker.d.ts +1 -0
  102. package/node_modules/@openclaw/fs-safe/dist/owner-dacl-batch-worker.js +54 -0
  103. package/node_modules/@openclaw/fs-safe/dist/owner-dacl-batch.d.ts +5 -0
  104. package/node_modules/@openclaw/fs-safe/dist/owner-dacl-batch.js +64 -0
  105. package/node_modules/@openclaw/fs-safe/dist/owner-dacl.d.ts +2 -0
  106. package/node_modules/@openclaw/fs-safe/dist/owner-dacl.js +3 -0
  107. package/node_modules/@openclaw/fs-safe/dist/path.js +17 -1
  108. package/node_modules/@openclaw/fs-safe/dist/permission-exec.d.ts +6 -0
  109. package/node_modules/@openclaw/fs-safe/dist/permission-exec.js +3 -6
  110. package/node_modules/@openclaw/fs-safe/dist/permissions-public.d.ts +3 -1
  111. package/node_modules/@openclaw/fs-safe/dist/permissions-public.js +1 -0
  112. package/node_modules/@openclaw/fs-safe/dist/permissions-windows.d.ts +3 -6
  113. package/node_modules/@openclaw/fs-safe/dist/permissions.d.ts +3 -10
  114. package/node_modules/@openclaw/fs-safe/dist/permissions.js +0 -1
  115. package/node_modules/@openclaw/fs-safe/dist/pinned-mutation-admission.d.ts +0 -1
  116. package/node_modules/@openclaw/fs-safe/dist/pinned-mutation-admission.js +4 -2
  117. package/node_modules/@openclaw/fs-safe/dist/pinned-mutation-shared-route.d.ts +2 -8
  118. package/node_modules/@openclaw/fs-safe/dist/pinned-open.d.ts +1 -1
  119. package/node_modules/@openclaw/fs-safe/dist/pinned-open.js +2 -3
  120. package/node_modules/@openclaw/fs-safe/dist/publish-copy-stage.js +4 -0
  121. package/node_modules/@openclaw/fs-safe/dist/read-opened-file.d.ts +2 -5
  122. package/node_modules/@openclaw/fs-safe/dist/regular-file.js +3 -3
  123. package/node_modules/@openclaw/fs-safe/dist/replace-directory.js +5 -17
  124. package/node_modules/@openclaw/fs-safe/dist/replace-file-buffer.d.ts +4 -0
  125. package/node_modules/@openclaw/fs-safe/dist/replace-file-buffer.js +36 -0
  126. package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-fallback.d.ts +4 -10
  127. package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-fallback.js +66 -38
  128. package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.d.ts +7 -11
  129. package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.js +10 -2
  130. package/node_modules/@openclaw/fs-safe/dist/replace-file-destination.d.ts +21 -0
  131. package/node_modules/@openclaw/fs-safe/dist/replace-file-destination.js +123 -0
  132. package/node_modules/@openclaw/fs-safe/dist/replace-file-mutation.d.ts +26 -0
  133. package/node_modules/@openclaw/fs-safe/dist/replace-file-mutation.js +47 -0
  134. package/node_modules/@openclaw/fs-safe/dist/replace-file-temp-owner.d.ts +2 -2
  135. package/node_modules/@openclaw/fs-safe/dist/replace-file-temp-owner.js +16 -4
  136. package/node_modules/@openclaw/fs-safe/dist/replace-file-types.d.ts +55 -0
  137. package/node_modules/@openclaw/fs-safe/dist/replace-file-types.js +1 -0
  138. package/node_modules/@openclaw/fs-safe/dist/replace-file.d.ts +3 -55
  139. package/node_modules/@openclaw/fs-safe/dist/replace-file.js +31 -11
  140. package/node_modules/@openclaw/fs-safe/dist/retained-directory-replacement.d.ts +1 -0
  141. package/node_modules/@openclaw/fs-safe/dist/retained-directory-replacement.js +1 -1
  142. package/node_modules/@openclaw/fs-safe/dist/retained-file-types.d.ts +50 -0
  143. package/node_modules/@openclaw/fs-safe/dist/retained-file-types.js +1 -0
  144. package/node_modules/@openclaw/fs-safe/dist/retained-file.d.ts +3 -0
  145. package/node_modules/@openclaw/fs-safe/dist/retained-file.js +121 -0
  146. package/node_modules/@openclaw/fs-safe/dist/root-context.js +3 -2
  147. package/node_modules/@openclaw/fs-safe/dist/root-directory-entry.d.ts +9 -0
  148. package/node_modules/@openclaw/fs-safe/dist/root-directory-entry.js +28 -0
  149. package/node_modules/@openclaw/fs-safe/dist/root-directory-list.d.ts +9 -1
  150. package/node_modules/@openclaw/fs-safe/dist/root-directory-list.js +88 -37
  151. package/node_modules/@openclaw/fs-safe/dist/root-file-final-admission.d.ts +1 -1
  152. package/node_modules/@openclaw/fs-safe/dist/root-file-final-admission.js +1 -6
  153. package/node_modules/@openclaw/fs-safe/dist/root-file.js +2 -5
  154. package/node_modules/@openclaw/fs-safe/dist/root-handle-context.d.ts +4 -0
  155. package/node_modules/@openclaw/fs-safe/dist/root-handle-context.js +12 -0
  156. package/node_modules/@openclaw/fs-safe/dist/root-impl.d.ts +3 -3
  157. package/node_modules/@openclaw/fs-safe/dist/root-impl.js +8 -5
  158. package/node_modules/@openclaw/fs-safe/dist/root-move-noreplace.d.ts +2 -7
  159. package/node_modules/@openclaw/fs-safe/dist/root-move-noreplace.js +3 -3
  160. package/node_modules/@openclaw/fs-safe/dist/root-observed-path.d.ts +0 -1
  161. package/node_modules/@openclaw/fs-safe/dist/root-observed-path.js +0 -3
  162. package/node_modules/@openclaw/fs-safe/dist/root-path-observation.d.ts +4 -11
  163. package/node_modules/@openclaw/fs-safe/dist/root-path.js +7 -10
  164. package/node_modules/@openclaw/fs-safe/dist/root-paths.d.ts +2 -6
  165. package/node_modules/@openclaw/fs-safe/dist/root-remove-identity.d.ts +1 -3
  166. package/node_modules/@openclaw/fs-safe/dist/root-walk.d.ts +19 -12
  167. package/node_modules/@openclaw/fs-safe/dist/root-walk.js +56 -20
  168. package/node_modules/@openclaw/fs-safe/dist/root-write-admission.js +1 -6
  169. package/node_modules/@openclaw/fs-safe/dist/root-write-complete-parent.d.ts +2 -0
  170. package/node_modules/@openclaw/fs-safe/dist/root-write-complete-parent.js +1 -1
  171. package/node_modules/@openclaw/fs-safe/dist/safe-path-segment.d.ts +1 -0
  172. package/node_modules/@openclaw/fs-safe/dist/safe-path-segment.js +8 -2
  173. package/node_modules/@openclaw/fs-safe/dist/secret-file.d.ts +6 -2
  174. package/node_modules/@openclaw/fs-safe/dist/secret-file.js +12 -16
  175. package/node_modules/@openclaw/fs-safe/dist/secret-read-policy.js +1 -1
  176. package/node_modules/@openclaw/fs-safe/dist/secure-file-windows.js +5 -14
  177. package/node_modules/@openclaw/fs-safe/dist/secure-file.js +3 -2
  178. package/node_modules/@openclaw/fs-safe/dist/secure-temp-dir.js +2 -7
  179. package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-acquire.js +4 -4
  180. package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-admission-parser.d.ts +1 -2
  181. package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-handle.d.ts +2 -8
  182. package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-policy.d.ts +2 -7
  183. package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.d.ts +2 -2
  184. package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.js +11 -12
  185. package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-stale-admission.d.ts +1 -5
  186. package/node_modules/@openclaw/fs-safe/dist/sidecar-lock.js +9 -7
  187. package/node_modules/@openclaw/fs-safe/dist/staged-symlink-types.d.ts +39 -0
  188. package/node_modules/@openclaw/fs-safe/dist/staged-symlink-types.js +1 -0
  189. package/node_modules/@openclaw/fs-safe/dist/stat-observation.js +3 -10
  190. package/node_modules/@openclaw/fs-safe/dist/strict-file-identity.d.ts +2 -0
  191. package/node_modules/@openclaw/fs-safe/dist/strict-file-identity.js +6 -6
  192. package/node_modules/@openclaw/fs-safe/dist/symlink-parents.js +58 -7
  193. package/node_modules/@openclaw/fs-safe/dist/temp-target.js +8 -10
  194. package/node_modules/@openclaw/fs-safe/dist/temp-workspace-admission.js +28 -33
  195. package/node_modules/@openclaw/fs-safe/dist/temp-workspace-child-admission.d.ts +1 -1
  196. package/node_modules/@openclaw/fs-safe/dist/temp-workspace-child-admission.js +16 -17
  197. package/node_modules/@openclaw/fs-safe/dist/temp-workspace-descriptor.js +1 -2
  198. package/node_modules/@openclaw/fs-safe/dist/temp-workspace-owner.js +4 -9
  199. package/node_modules/@openclaw/fs-safe/dist/temp-workspace-ownership.d.ts +8 -0
  200. package/node_modules/@openclaw/fs-safe/dist/temp-workspace-ownership.js +52 -0
  201. package/node_modules/@openclaw/fs-safe/dist/test-hooks.d.ts +5 -1
  202. package/node_modules/@openclaw/fs-safe/dist/text-atomic.d.ts +2 -1
  203. package/node_modules/@openclaw/fs-safe/dist/text-atomic.js +2 -0
  204. package/node_modules/@openclaw/fs-safe/dist/trash.js +27 -1
  205. package/node_modules/@openclaw/fs-safe/dist/walk.d.ts +2 -5
  206. package/node_modules/@openclaw/fs-safe/dist/watch-alias.d.ts +6 -0
  207. package/node_modules/@openclaw/fs-safe/dist/watch-alias.js +88 -0
  208. package/node_modules/@openclaw/fs-safe/dist/watch-hints.d.ts +9 -0
  209. package/node_modules/@openclaw/fs-safe/dist/watch-hints.js +93 -0
  210. package/node_modules/@openclaw/fs-safe/dist/watch-native.d.ts +36 -0
  211. package/node_modules/@openclaw/fs-safe/dist/watch-native.js +73 -0
  212. package/node_modules/@openclaw/fs-safe/dist/watch-scan.d.ts +28 -0
  213. package/node_modules/@openclaw/fs-safe/dist/watch-scan.js +300 -0
  214. package/node_modules/@openclaw/fs-safe/dist/watch-stream.d.ts +8 -0
  215. package/node_modules/@openclaw/fs-safe/dist/watch-stream.js +32 -0
  216. package/node_modules/@openclaw/fs-safe/dist/watch-types.d.ts +60 -0
  217. package/node_modules/@openclaw/fs-safe/dist/watch-types.js +1 -0
  218. package/node_modules/@openclaw/fs-safe/dist/watch.d.ts +5 -0
  219. package/node_modules/@openclaw/fs-safe/dist/watch.js +530 -0
  220. package/node_modules/@openclaw/fs-safe/dist/windows-owner.d.ts +3 -7
  221. package/node_modules/@openclaw/fs-safe/dist/windows-owner.js +0 -1
  222. package/node_modules/@openclaw/fs-safe/dist/windows-security-bridge.cs +6 -6
  223. package/node_modules/@openclaw/fs-safe/dist/windows-security-bridge.ps1 +78 -3
  224. package/node_modules/@openclaw/fs-safe/dist/windows-security-command.d.ts +8 -0
  225. package/node_modules/@openclaw/fs-safe/dist/windows-security-command.js +66 -15
  226. package/node_modules/@openclaw/fs-safe/dist/windows-security-facts.d.ts +4 -0
  227. package/node_modules/@openclaw/fs-safe/dist/windows-security-facts.js +6 -2
  228. package/node_modules/@openclaw/fs-safe/docs/advanced.md +4 -2
  229. package/node_modules/@openclaw/fs-safe/docs/archive.md +16 -0
  230. package/node_modules/@openclaw/fs-safe/docs/atomic.md +93 -3
  231. package/node_modules/@openclaw/fs-safe/docs/contributing.md +102 -4
  232. package/node_modules/@openclaw/fs-safe/docs/copy.md +2 -0
  233. package/node_modules/@openclaw/fs-safe/docs/durability.md +7 -0
  234. package/node_modules/@openclaw/fs-safe/docs/file-store.md +5 -0
  235. package/node_modules/@openclaw/fs-safe/docs/guest.md +7 -1
  236. package/node_modules/@openclaw/fs-safe/docs/index.md +1 -0
  237. package/node_modules/@openclaw/fs-safe/docs/install.md +30 -0
  238. package/node_modules/@openclaw/fs-safe/docs/native-helper.md +20 -4
  239. package/node_modules/@openclaw/fs-safe/docs/native.md +63 -1
  240. package/node_modules/@openclaw/fs-safe/docs/permissions.md +66 -0
  241. package/node_modules/@openclaw/fs-safe/docs/public-api.md +30 -3
  242. package/node_modules/@openclaw/fs-safe/docs/retained-file.md +115 -0
  243. package/node_modules/@openclaw/fs-safe/docs/root.md +35 -9
  244. package/node_modules/@openclaw/fs-safe/docs/secret-file.md +19 -0
  245. package/node_modules/@openclaw/fs-safe/docs/security-model.md +4 -1
  246. package/node_modules/@openclaw/fs-safe/docs/sidecar-lock.md +5 -1
  247. package/node_modules/@openclaw/fs-safe/docs/staged-symlink.md +124 -0
  248. package/node_modules/@openclaw/fs-safe/docs/store.md +3 -1
  249. package/node_modules/@openclaw/fs-safe/docs/temp.md +24 -4
  250. package/node_modules/@openclaw/fs-safe/docs/testing.md +210 -0
  251. package/node_modules/@openclaw/fs-safe/docs/types.md +6 -0
  252. package/node_modules/@openclaw/fs-safe/docs/walk.md +34 -1
  253. package/node_modules/@openclaw/fs-safe/docs/watch.md +251 -0
  254. package/node_modules/@openclaw/fs-safe/docs/writing.md +21 -0
  255. package/node_modules/@openclaw/fs-safe/package.json +13 -9
  256. package/node_modules/@openclaw/fs-safe-darwin-arm64/fs-safe-native.node +0 -0
  257. package/node_modules/@openclaw/fs-safe-darwin-arm64/package.json +1 -1
  258. package/node_modules/@openclaw/fs-safe-darwin-x64/fs-safe-native.node +0 -0
  259. package/node_modules/@openclaw/fs-safe-darwin-x64/package.json +1 -1
  260. package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/fs-safe-native.node +0 -0
  261. package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/package.json +1 -1
  262. package/node_modules/@openclaw/fs-safe-linux-arm64-musl/fs-safe-native.node +0 -0
  263. package/node_modules/@openclaw/fs-safe-linux-arm64-musl/package.json +1 -1
  264. package/node_modules/@openclaw/fs-safe-linux-x64-gnu/fs-safe-native.node +0 -0
  265. package/node_modules/@openclaw/fs-safe-linux-x64-gnu/package.json +1 -1
  266. package/node_modules/@openclaw/fs-safe-linux-x64-musl/fs-safe-native.node +0 -0
  267. package/node_modules/@openclaw/fs-safe-linux-x64-musl/package.json +1 -1
  268. package/node_modules/@openclaw/fs-safe-win32-x64-msvc/fs-safe-native.node +0 -0
  269. package/node_modules/@openclaw/fs-safe-win32-x64-msvc/package.json +1 -1
  270. package/package.json +5 -5
  271. package/dist/.setup/api-B9-B1L7Q.mjs +0 -17
  272. package/dist/.setup/client-adapter-dvFa47YL.mjs +0 -63
  273. package/dist/.setup/rolldown-runtime-8H4AJuhK.mjs +0 -14
  274. package/dist/.setup/send.runtime-CLnCWvrM.mjs +0 -2
  275. package/dist/.setup/transport-detection-CoiRl7Gx.mjs +0 -576
  276. package/dist/.setup/transport-detection.runtime-Tlhuv3T_.mjs +0 -2
  277. package/dist/.setup/transport-probes.runtime-WprAyBbL.mjs +0 -2
  278. package/node_modules/@openclaw/fs-safe/dist/directory-mode-owner.d.ts +0 -20
  279. package/node_modules/@openclaw/fs-safe/dist/directory-mode-owner.js +0 -78
@@ -70,11 +70,6 @@ function snapshotDirectoryMetadata(stat, identity) {
70
70
  export function directoryReceiptAuthority(receipt) {
71
71
  return authorities.get(receipt) ?? snapshotDirectoryReceipt(receipt);
72
72
  }
73
- function rememberReceipt(receipt, authority) {
74
- authorities.set(receipt, authority);
75
- identities.set(receipt.identity, authority);
76
- return receipt;
77
- }
78
73
  export function ownDirectoryReceipt(receipt) {
79
74
  return receiptFromAuthority(snapshotDirectoryReceipt(receipt));
80
75
  }
@@ -83,11 +78,14 @@ export function copyRetainedDirectoryReceipt(receipt) {
83
78
  return receiptFromAuthority(authority);
84
79
  }
85
80
  function receiptFromAuthority(authority) {
86
- return rememberReceipt({
81
+ const receipt = {
87
82
  path: authority.path,
88
83
  realPath: authority.realPath,
89
84
  identity: Object.assign(Object.create(fs.Stats.prototype), authority.metadata),
90
- }, authority);
85
+ };
86
+ authorities.set(receipt, authority);
87
+ identities.set(receipt.identity, authority);
88
+ return receipt;
91
89
  }
92
90
  // The caller already admitted the exact observation and its paths.
93
91
  export function createDirectoryReceiptFromIdentity(pathname, realPath, exactStat) {
@@ -1,6 +1,3 @@
1
- function isValidUid(value) {
2
- return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
3
- }
4
1
  function unavailable(cause) {
5
2
  return new Error("Effective user identity is unavailable.", {
6
3
  ...(cause === undefined ? {} : { cause }),
@@ -18,7 +15,7 @@ export function resolveEffectiveUid() {
18
15
  catch (cause) {
19
16
  throw unavailable(cause);
20
17
  }
21
- if (!isValidUid(uid)) {
18
+ if (!(typeof uid === "number" && Number.isSafeInteger(uid) && uid >= 0)) {
22
19
  throw unavailable();
23
20
  }
24
21
  return uid;
@@ -1,6 +1,7 @@
1
- export type FsSafeErrorCode = "already-exists" | "denied-path" | "device-path" | "hardlink" | "helper-failed" | "helper-unavailable" | "invalid-path" | "insecure-permissions" | "not-empty" | "not-file" | "not-found" | "not-owned" | "not-removable" | "outside-workspace" | "path-alias" | "path-mismatch" | "permission-unverified" | "read-failed" | "secret-exists" | "store-reentrant-update" | "symlink" | "timeout" | "too-large" | "unsupported-platform";
1
+ export type FsSafeErrorCode = (typeof OPERATIONAL_CODE_VALUES)[number] | "already-exists" | "denied-path" | "device-path" | "hardlink" | "invalid-path" | "insecure-permissions" | "not-file" | "not-owned" | "outside-workspace" | "path-alias" | "path-mismatch" | "secret-exists" | "store-reentrant-update" | "symlink" | "too-large";
2
2
  export type FsSafeErrorCategory = "policy" | "operational";
3
3
  export type FsSafeErrorDetails = Readonly<Record<string, unknown>>;
4
+ declare const OPERATIONAL_CODE_VALUES: readonly ["helper-failed", "helper-unavailable", "not-empty", "not-found", "not-removable", "permission-unverified", "read-failed", "timeout", "unsupported-platform"];
4
5
  export declare function categorizeFsSafeError(code: FsSafeErrorCode): FsSafeErrorCategory;
5
6
  export declare class FsSafeError extends Error {
6
7
  readonly code: FsSafeErrorCode;
@@ -11,3 +12,4 @@ export declare class FsSafeError extends Error {
11
12
  details?: FsSafeErrorDetails;
12
13
  });
13
14
  }
15
+ export {};
@@ -1,4 +1,4 @@
1
- const OPERATIONAL_CODES = new Set([
1
+ const OPERATIONAL_CODE_VALUES = [
2
2
  "helper-failed",
3
3
  "helper-unavailable",
4
4
  "not-empty",
@@ -8,7 +8,8 @@ const OPERATIONAL_CODES = new Set([
8
8
  "read-failed",
9
9
  "timeout",
10
10
  "unsupported-platform",
11
- ]);
11
+ ];
12
+ const OPERATIONAL_CODES = new Set(OPERATIONAL_CODE_VALUES);
12
13
  export function categorizeFsSafeError(code) {
13
14
  return OPERATIONAL_CODES.has(code) ? "operational" : "policy";
14
15
  }
@@ -22,9 +22,17 @@ export function sameFileIdentity(left, right, platform = process.platform) {
22
22
  return (!isStatValueProvablyDifferent(left.dev, right.dev, platform) &&
23
23
  !isStatValueProvablyDifferent(left.ino, right.ino, platform));
24
24
  }
25
+ function sameCleanupStatValue(left, right) {
26
+ // Converting an unsafe number to bigint cannot recover an already rounded ID.
27
+ if (typeof left === "number" && !Number.isSafeInteger(left))
28
+ return false;
29
+ if (typeof right === "number" && !Number.isSafeInteger(right))
30
+ return false;
31
+ return sameStatValue(left, right);
32
+ }
25
33
  export function sameFileIdentityForCleanup(left, right, platform = process.platform) {
26
34
  if (platform !== "win32") {
27
- return sameStatValue(left.dev, right.dev) && sameStatValue(left.ino, right.ino);
35
+ return sameCleanupStatValue(left.dev, right.dev) && sameCleanupStatValue(left.ino, right.ino);
28
36
  }
29
37
  // A zero Windows device or inode is unknown, not proof that a pathname still
30
38
  // names the object we created. Cleanup must fail closed rather than delete a
@@ -44,5 +52,5 @@ export function sameFileIdentityForCleanup(left, right, platform = process.platf
44
52
  const rightIno = right.ino;
45
53
  if (isZero(rightIno))
46
54
  return false;
47
- return sameStatValue(leftDev, rightDev) && sameStatValue(leftIno, rightIno);
55
+ return sameCleanupStatValue(leftDev, rightDev) && sameCleanupStatValue(leftIno, rightIno);
48
56
  }
@@ -66,7 +66,7 @@ export class SyncLockAcquisition {
66
66
  }
67
67
  catch (waitError) {
68
68
  // Exhausted backoff must preserve the filesystem denial diagnosis.
69
- if (waitError.code === "file_lock_timeout")
69
+ if (waitError?.code === "file_lock_timeout")
70
70
  throw error;
71
71
  throw waitError;
72
72
  }
@@ -30,7 +30,11 @@ export function defaultSyncShouldReclaim(snapshot, staleMs, nowMs) {
30
30
  const createdAtMs = sidecarLockPayloadCreatedAtMs(snapshot.payload);
31
31
  if (createdAtMs !== null)
32
32
  return nowMs - createdAtMs > staleMs;
33
- return !snapshot.stat || nowMs - snapshot.stat.mtimeMs > staleMs;
33
+ if (!snapshot.stat)
34
+ return true;
35
+ const mtimeMs = "mtimeNs" in snapshot.stat
36
+ ? Number(snapshot.stat.mtimeNs) / 1e6 : snapshot.stat.mtimeMs;
37
+ return nowMs - mtimeMs > staleMs;
34
38
  }
35
39
  export function syncReclaimGuardExists(reclaimGuardPath) {
36
40
  try {
@@ -1,5 +1,6 @@
1
+ import { type SyncHeldLock } from "./file-lock-sync-admission.js";
2
+ import type { SidecarLockOptionFields } from "./sidecar-lock-types.js";
1
3
  import type { FileLockSyncHandle } from "./file-lock-sync.js";
2
- import { type SidecarLockSnapshot } from "./sidecar-lock-reclaim.js";
3
4
  import { type FileLockSyncRootAuthority, type FileLockSyncRootPath } from "./file-lock-sync-root.js";
4
5
  import { type FileLockSyncRootFileReceipt, type FileLockSyncRootSnapshot } from "./file-lock-sync-root-io.js";
5
6
  type RootSyncHeldLockReleaseState = "active" | "releasing" | "exit-cleaning" | "released";
@@ -7,22 +8,14 @@ type RootSyncHeldLockHandleDisposition = {
7
8
  held: RootSyncHeldLock;
8
9
  released: boolean;
9
10
  };
10
- export type RootSyncHeldLock = {
11
+ export type RootSyncHeldLock = SidecarLockOptionFields<SyncHeldLock & {
11
12
  deferredExitReleases?: Set<RootSyncHeldLockHandleDisposition>;
12
- fd: number | undefined;
13
- lockPath: string;
14
- normalizedTargetPath: string;
15
- parsePayload?: (raw: string) => unknown;
16
- refCount: number;
17
- reentrantOwner?: string;
18
13
  releaseState: RootSyncHeldLockReleaseState;
19
14
  revision: number;
20
15
  rootAuthority: FileLockSyncRootAuthority;
21
16
  rootPath: FileLockSyncRootPath;
22
17
  rootReceipt: FileLockSyncRootFileReceipt;
23
- snapshot: SidecarLockSnapshot;
24
- timer?: NodeJS.Timeout;
25
- };
18
+ }>;
26
19
  export declare function readRootSidecarSnapshotSync(rootPath: FileLockSyncRootPath, parsePayload?: (raw: string) => unknown, onOpenFailure?: (error: unknown) => void, expectedReceipt?: FileLockSyncRootFileReceipt): FileLockSyncRootSnapshot | null;
27
20
  export declare function getRootSyncHeldLocks(): Map<string, RootSyncHeldLock>;
28
21
  export declare function ensureRootSyncExitCleanupRegistered(): void;
@@ -53,9 +53,6 @@ export function getRootSyncHeldLocks() {
53
53
  }
54
54
  return globalWithState[ROOT_SYNC_HELD_LOCKS_KEY];
55
55
  }
56
- function existingRootSyncHeldLocks() {
57
- return globalThis[ROOT_SYNC_HELD_LOCKS_KEY];
58
- }
59
56
  function reactivateExactHeldLock(heldLocks, held, restoreConsumedReference) {
60
57
  if (heldLocks.get(held.normalizedTargetPath) !== held || held.releaseState === "released") {
61
58
  return false;
@@ -123,7 +120,7 @@ function releaseAllRootSyncHeldLocks() {
123
120
  try {
124
121
  // A newListener callback can invoke the candidate handler before
125
122
  // registration succeeds. Do not create acquisition state in that window.
126
- const heldLocks = existingRootSyncHeldLocks();
123
+ const heldLocks = globalThis[ROOT_SYNC_HELD_LOCKS_KEY];
127
124
  if (!heldLocks)
128
125
  return;
129
126
  getSyncLockAdmissions().clear();
@@ -1,4 +1,4 @@
1
- import { type BigIntStats, type Stats } from "node:fs";
1
+ import { type BigIntStats } from "node:fs";
2
2
  import type { RootDefaults } from "./root-options.js";
3
3
  import { type FileLockSyncRootPath } from "./file-lock-sync-root.js";
4
4
  export type ExactIdentity = Readonly<{
@@ -14,15 +14,12 @@ export type FileLockSyncRootFileReceipt = Readonly<{
14
14
  identity: ExactIdentity;
15
15
  parent: DirectoryReceipt;
16
16
  }>;
17
- export type FileLockSyncRootDirectoryReceipt = Readonly<{
18
- identity: ExactIdentity;
19
- parent: DirectoryReceipt;
20
- }>;
17
+ export type FileLockSyncRootDirectoryReceipt = FileLockSyncRootFileReceipt;
21
18
  export type FileLockSyncRootDiskSnapshot = {
22
19
  ownershipToken?: never;
23
20
  payload: unknown;
24
21
  raw: string;
25
- stat: Stats;
22
+ stat: BigIntStats;
26
23
  };
27
24
  export type FileLockSyncRootSnapshot = Readonly<{
28
25
  receipt: FileLockSyncRootFileReceipt;
@@ -143,7 +143,7 @@ export function readFileLockSyncRootSnapshot(pathAuthority, options = {}) {
143
143
  throw error;
144
144
  }
145
145
  assertRegularFile(after, pathAuthority.authority.hardlinks);
146
- const stat = fs.fstatSync(fd);
146
+ const stat = fs.fstatSync(fd, { bigint: true });
147
147
  if (expectedReceipt) {
148
148
  assertRetainedParentCurrent(pathAuthority, parent);
149
149
  }
@@ -1,19 +1,11 @@
1
1
  import type { FileLockSyncAcquireOptions } from "./file-lock-sync.js";
2
- import type { SidecarLockCompromisedInfo, SidecarLockRetryOptions, SidecarLockStaleRecovery } from "./sidecar-lock-types.js";
3
- type CapturedRootSyncAcquireOptions<TPayload extends Record<string, unknown>> = Readonly<{
4
- compromiseCheckIntervalMs?: number;
5
- lockPath?: string;
6
- onCompromised?: (info: SidecarLockCompromisedInfo) => void;
2
+ import type { SidecarLockRetryOptions } from "./sidecar-lock-types.js";
3
+ type CapturedRootSyncAcquireOptions<TPayload extends Record<string, unknown>> = Readonly<Pick<FileLockSyncAcquireOptions<TPayload>, "compromiseCheckIntervalMs" | "lockPath" | "onCompromised" | "parsePayload" | "payload" | "reentrantOwner" | "staleRecovery" | "timeoutMs"> & {
7
4
  optionsReceiver: FileLockSyncAcquireOptions<TPayload>;
8
- parsePayload?: (raw: string) => unknown;
9
- payload: () => TPayload;
10
- reentrantOwner?: string;
11
5
  retry: Readonly<SidecarLockRetryOptions>;
12
6
  shouldReclaim?: FileLockSyncAcquireOptions<TPayload>["shouldReclaim"];
13
7
  shouldRemoveStaleLock?: FileLockSyncAcquireOptions<TPayload>["shouldRemoveStaleLock"];
14
8
  staleMs: number;
15
- staleRecovery?: SidecarLockStaleRecovery;
16
- timeoutMs?: number;
17
9
  }>;
18
10
  export declare function captureRootSyncAcquireOptions<TPayload extends Record<string, unknown>>(options: FileLockSyncAcquireOptions<TPayload>): CapturedRootSyncAcquireOptions<TPayload>;
19
11
  export {};
@@ -1,3 +1,4 @@
1
+ import { type DenyMutationPolicy } from "./deny-mutations.js";
1
2
  import { type RootContext } from "./root-context.js";
2
3
  import type { Root } from "./root-impl.js";
3
4
  import type { RootDefaults } from "./root-options.js";
@@ -7,10 +8,7 @@ export type FileLockSyncRootAuthority = Readonly<{
7
8
  adapter: object;
8
9
  context: RootContext;
9
10
  assertBeforeMutation?: () => void;
10
- denyMutations?: Readonly<{
11
- paths?: readonly string[];
12
- prefixes?: readonly string[];
13
- }>;
11
+ denyMutations?: Readonly<DenyMutationPolicy>;
14
12
  hardlinks?: RootDefaults["hardlinks"];
15
13
  mutationPolicy: RootPathResolutionPolicy;
16
14
  readPolicy: RootPathResolutionPolicy;
@@ -240,7 +240,7 @@ export function acquireFileLockSync(targetPath, options) {
240
240
  createdSnapshot = {
241
241
  raw,
242
242
  payload,
243
- stat: fs.fstatSync(fd),
243
+ stat: fs.fstatSync(fd, { bigint: true }),
244
244
  ownershipToken,
245
245
  };
246
246
  createdHeld = {
@@ -280,7 +280,7 @@ export function acquireFileLockSync(targetPath, options) {
280
280
  const failed = createdSnapshot ?? { payload: null };
281
281
  if (!failed.stat) {
282
282
  try {
283
- failed.stat = fs.fstatSync(fd);
283
+ failed.stat = fs.fstatSync(fd, { bigint: true });
284
284
  }
285
285
  catch {
286
286
  // Missing identity leaves the sidecar in place, but must not skip close.
@@ -1,5 +1,5 @@
1
1
  import type { Readable } from "node:stream";
2
- import { type SyncStoreDirectoryReceipt } from "./file-store-sync-directory.js";
2
+ import { ensureSyncStoreDirectory, type SyncStoreDirectoryReceipt } from "./file-store-sync-directory.js";
3
3
  import { type Root } from "./root.js";
4
4
  import { prepareSecretFileWrite } from "./secret-file.js";
5
5
  export type SyncParentGuard = SyncStoreDirectoryReceipt;
@@ -23,12 +23,8 @@ export declare function ensureParentSync(params: {
23
23
  filePath: string;
24
24
  mode: number;
25
25
  }): SyncParentGuard;
26
- export declare function ensureStoreDirectorySync(params: {
27
- rootDir: string;
28
- targetDir: string;
29
- mode: number;
30
- messagePrefix: "private store" | "store";
31
- }): SyncParentGuard;
26
+ export declare function ensureStoreDirectorySync(params: Parameters<typeof ensureSyncStoreDirectory>[0]): SyncParentGuard;
27
+ export declare function literalStoreRootPath(relativePath: string): string;
32
28
  export declare function assertRelativePath(relativePath: string): string;
33
29
  export declare function resolveStorePath(rootDir: string, relativePath: string): string;
34
30
  export declare function assertFileStoreMaxBytes(size: number, limit: number | undefined): void;
@@ -7,8 +7,7 @@ import { FsSafeError } from "./errors.js";
7
7
  import { assertSyncStoreDirectoryReceipt, ensureSyncStoreDirectory, } from "./file-store-sync-directory.js";
8
8
  import { isPathInside, splitSafeRelativePath } from "./path.js";
9
9
  import { resolveOpenedFileRealPathForHandle, root } from "./root.js";
10
- import { ensureTrailingSep } from "./root-context.js";
11
- import { RootHandle } from "./root-impl.js";
10
+ import { rootFromDirectoryGuard } from "./root-impl.js";
12
11
  import { prepareSecretFileWrite } from "./secret-file.js";
13
12
  import { resolveSecureTempRoot } from "./secure-temp-dir.js";
14
13
  import { recursiveMkdirPath } from "./recursive-mkdir-path.js";
@@ -16,7 +15,7 @@ import { readRegularFile } from "./regular-file.js";
16
15
  import { errorCauseOptions } from "./root-errors.js";
17
16
  import { assertNoWindowsPathAlias } from "./windows-path-alias.js";
18
17
  export async function ensureParentInRoot(scopedRoot, relativePath, mode) {
19
- const parent = path.posix.dirname(relativePath);
18
+ const parent = literalStoreRootPath(path.posix.dirname(relativePath));
20
19
  if (parent === ".") {
21
20
  return;
22
21
  }
@@ -32,13 +31,7 @@ export async function openWritableStoreRoot(params) {
32
31
  export async function openPrivateStoreLockRoot(params) {
33
32
  const { parentGuard } = await prepareSecretFileWrite(params);
34
33
  // Bind to the admitted parent, never resolve a replacement into a fresh capability.
35
- return new RootHandle({
36
- rootDir: parentGuard.dir,
37
- rootGuard: { dir: parentGuard.realPath, realPath: parentGuard.realPath, stat: parentGuard.stat },
38
- rootReal: parentGuard.realPath,
39
- rootWithSep: ensureTrailingSep(parentGuard.realPath),
40
- rootIdentity: { dev: parentGuard.stat.dev, ino: parentGuard.stat.ino },
41
- }, { hardlinks: "reject" });
34
+ return rootFromDirectoryGuard(parentGuard, { hardlinks: "reject" });
42
35
  }
43
36
  async function chmodDirectoryInRootBestEffort(scopedRoot, relativePath, mode) {
44
37
  const dirPath = await scopedRoot.resolve(relativePath);
@@ -120,6 +113,10 @@ export function ensureStoreDirectorySync(params) {
120
113
  assertSyncStoreDirectoryReceipt(guard);
121
114
  return guard;
122
115
  }
116
+ // Store keys and directory-entry names are literal, unlike Root's home syntax.
117
+ export function literalStoreRootPath(relativePath) {
118
+ return relativePath === "~" || relativePath.startsWith("~/") ? `./${relativePath}` : relativePath;
119
+ }
123
120
  export function assertRelativePath(relativePath) {
124
121
  const raw = relativePath.trim();
125
122
  if (!raw || raw !== relativePath) {
@@ -2,6 +2,7 @@ import fsSync, {} from "node:fs";
2
2
  import fs from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { FsSafeError } from "./errors.js";
5
+ import { literalStoreRootPath } from "./file-store-boundary.js";
5
6
  import { isPathInside } from "./path.js";
6
7
  import { realpathSync } from "./realpath.js";
7
8
  import { recursiveMkdirPath } from "./recursive-mkdir-path.js";
@@ -22,10 +23,10 @@ export async function pruneExpiredStoreEntries(params) {
22
23
  const rootGuard = {
23
24
  dir: rootReal,
24
25
  realPath: rootReal,
25
- stat: fsSync.lstatSync(rootReal),
26
+ stat: fsSync.lstatSync(rootReal, { bigint: true }),
26
27
  };
27
28
  async function assertRootGuard() {
28
- const stat = fsSync.lstatSync(rootGuard.dir);
29
+ const stat = fsSync.lstatSync(rootGuard.dir, { bigint: true });
29
30
  if (stat.isSymbolicLink() ||
30
31
  !stat.isDirectory() ||
31
32
  stat.dev !== rootGuard.stat.dev ||
@@ -35,7 +36,7 @@ export async function pruneExpiredStoreEntries(params) {
35
36
  }
36
37
  }
37
38
  async function readStableDirectory(dir) {
38
- const before = observeOrNull(() => fsSync.lstatSync(dir));
39
+ const before = observeOrNull(() => fsSync.lstatSync(dir, { bigint: true }));
39
40
  if (!before || before.isSymbolicLink() || !before.isDirectory()) {
40
41
  return null;
41
42
  }
@@ -47,7 +48,7 @@ export async function pruneExpiredStoreEntries(params) {
47
48
  if (!entries) {
48
49
  return null;
49
50
  }
50
- const after = observeOrNull(() => fsSync.lstatSync(dir));
51
+ const after = observeOrNull(() => fsSync.lstatSync(dir, { bigint: true }));
51
52
  if (!after || before.dev !== after.dev || before.ino !== after.ino) {
52
53
  return null;
53
54
  }
@@ -74,13 +75,13 @@ export async function pruneExpiredStoreEntries(params) {
74
75
  await assertRootGuard();
75
76
  // Keep empty-dir pruning on the same root-bounded remove path as files;
76
77
  // the Root fallback handles empty directories without recursive delete.
77
- await scopedRoot.remove(relativePath, REMOVE_EMPTY_DIRECTORY_OPTIONS).catch(() => undefined);
78
+ await scopedRoot.remove(literalStoreRootPath(relativePath), REMOVE_EMPTY_DIRECTORY_OPTIONS).catch(() => undefined);
78
79
  }
79
80
  continue;
80
81
  }
81
82
  if (stat.isFile() && now - stat.mtimeMs > params.options.ttlMs) {
82
83
  await assertRootGuard();
83
- await scopedRoot.remove(relativePath, {
84
+ await scopedRoot.remove(literalStoreRootPath(relativePath), {
84
85
  assertBeforeMutation: () => {
85
86
  // Removal preparation can outlive the expiry observation above.
86
87
  const current = fsSync.lstatSync(fullPath);
@@ -12,14 +12,11 @@ export type FileStoreOptions = {
12
12
  mode?: number;
13
13
  maxBytes?: number;
14
14
  };
15
- export type FileStoreWriteOptions = {
15
+ export type FileStoreWriteOptions = Partial<Pick<FileStoreOptions, "dirMode" | "mode" | "maxBytes"> & {
16
16
  /** Override store durability; defaults to the store option, then true. */
17
- durable?: boolean;
18
- dirMode?: number;
19
- mode?: number;
20
- maxBytes?: number;
21
- tempPrefix?: string;
22
- };
17
+ durable: boolean;
18
+ tempPrefix: string;
19
+ }>;
23
20
  export type FileStoreReadOptions = RootReadOptions & {
24
21
  encoding?: BufferEncoding;
25
22
  };
@@ -3,7 +3,7 @@ import { normalizeMaxBytes } from "./byte-budget.js";
3
3
  import { readFileDescriptorBoundedSync } from "./bounded-read.js";
4
4
  import { FsSafeError } from "./errors.js";
5
5
  import { pruneExpiredStoreEntries } from "./file-store-prune.js";
6
- import { assertFileStoreMaxBytes, assertRelativePath, ensureParentInRoot, openPrivateStoreLockRoot, openWritableStoreRoot, readFileStoreCopySource, resolveStorePath, writeStreamToTempSource, } from "./file-store-boundary.js";
6
+ import { assertFileStoreMaxBytes, assertRelativePath, ensureParentInRoot, literalStoreRootPath, openPrivateStoreLockRoot, openWritableStoreRoot, readFileStoreCopySource, resolveStorePath, writeStreamToTempSource, } from "./file-store-boundary.js";
7
7
  import { writeFileSyncAtomic } from "./file-store-sync-write.js";
8
8
  import { createJsonStore } from "./json-document-store.js";
9
9
  import { stringifyJsonDocument } from "./json-stringify.js";
@@ -61,7 +61,7 @@ function handleSyncStoreReadOpenFailure(opened) {
61
61
  });
62
62
  }
63
63
  async function copyIntoRoot(params) {
64
- const relativePath = assertRelativePath(params.relativePath);
64
+ const relativePath = params.relativePath;
65
65
  const destination = resolveStorePath(params.rootDir, relativePath);
66
66
  assertNoWindowsPathAlias(params.sourcePath, "filesystem", "source path uses a Windows filesystem namespace alias");
67
67
  const sourceStat = syncFs.lstatSync(params.sourcePath);
@@ -75,7 +75,7 @@ async function copyIntoRoot(params) {
75
75
  maxBytes: params.maxBytes,
76
76
  });
77
77
  await ensureParentInRoot(scopedRoot, relativePath, params.dirMode);
78
- await scopedRoot.copyIn(relativePath, params.sourcePath, {
78
+ await scopedRoot.copyIn(literalStoreRootPath(relativePath), params.sourcePath, {
79
79
  durable: params.durable,
80
80
  maxBytes: params.maxBytes,
81
81
  mkdir: false,
@@ -97,8 +97,7 @@ export function fileStore(options) {
97
97
  return await root(rootDir, { hardlinks: "reject", maxBytes });
98
98
  }
99
99
  async function write(relativePath, data, writeOptions) {
100
- const safeRelativePath = assertRelativePath(relativePath);
101
- const destination = resolveStorePath(rootDir, safeRelativePath);
100
+ const destination = resolveStorePath(rootDir, relativePath);
102
101
  const content = Buffer.isBuffer(data) ? data : Buffer.from(data);
103
102
  const writeMaxBytes = normalizeMaxBytes(writeOptions?.maxBytes, { defaultValue: maxBytes });
104
103
  assertFileStoreMaxBytes(content.byteLength, writeMaxBytes);
@@ -121,8 +120,8 @@ export function fileStore(options) {
121
120
  dirMode: writeDirMode,
122
121
  maxBytes: writeMaxBytes,
123
122
  });
124
- await ensureParentInRoot(scopedRoot, safeRelativePath, writeDirMode);
125
- await scopedRoot.write(safeRelativePath, content, {
123
+ await ensureParentInRoot(scopedRoot, relativePath, writeDirMode);
124
+ await scopedRoot.write(literalStoreRootPath(relativePath), content, {
126
125
  mkdir: false,
127
126
  mode: writeMode,
128
127
  durable: writeDurable,
@@ -135,8 +134,7 @@ export function fileStore(options) {
135
134
  root: openRoot,
136
135
  write,
137
136
  writeStream: async (relativePath, stream, writeOptions) => {
138
- const safeRelativePath = assertRelativePath(relativePath);
139
- const destination = resolveStorePath(rootDir, safeRelativePath);
137
+ const destination = resolveStorePath(rootDir, relativePath);
140
138
  const configuredLimit = normalizeMaxBytes(writeOptions?.maxBytes, { defaultValue: maxBytes });
141
139
  const limit = configuredLimit ?? (privateMode ? DEFAULT_ROOT_MAX_BYTES : undefined);
142
140
  if (privateMode) {
@@ -172,7 +170,7 @@ export function fileStore(options) {
172
170
  try {
173
171
  await copyIntoRoot({
174
172
  rootDir,
175
- relativePath: safeRelativePath,
173
+ relativePath,
176
174
  sourcePath: staged.path,
177
175
  durable: writeDurable,
178
176
  maxBytes: limit,
@@ -214,17 +212,17 @@ export function fileStore(options) {
214
212
  tempPrefix: writeOptions?.tempPrefix,
215
213
  });
216
214
  },
217
- open: async (relativePath, readOptions) => await (await openRoot()).open(assertRelativePath(relativePath), readOptions),
218
- read: async (relativePath, readOptions) => await (await openRoot()).read(assertRelativePath(relativePath), readOptions),
219
- readBytes: async (relativePath, readOptions) => await (await openRoot()).readBytes(assertRelativePath(relativePath), readOptions),
215
+ open: async (relativePath, readOptions) => await (await openRoot()).open(literalStoreRootPath(assertRelativePath(relativePath)), readOptions),
216
+ read: async (relativePath, readOptions) => await (await openRoot()).read(literalStoreRootPath(assertRelativePath(relativePath)), readOptions),
217
+ readBytes: async (relativePath, readOptions) => await (await openRoot()).readBytes(literalStoreRootPath(assertRelativePath(relativePath)), readOptions),
220
218
  readText: async (relativePath, readOptions) => {
221
219
  const { encoding = "utf8", ...options } = readOptions ?? {};
222
- return (await (await openRoot()).read(assertRelativePath(relativePath), options)).buffer
220
+ return (await (await openRoot()).read(literalStoreRootPath(assertRelativePath(relativePath)), options)).buffer
223
221
  .toString(encoding);
224
222
  },
225
223
  readTextIfExists: async (relativePath, readOptions) => {
226
224
  try {
227
- return await (await openRoot()).readText(assertRelativePath(relativePath), readOptions);
225
+ return await (await openRoot()).readText(literalStoreRootPath(assertRelativePath(relativePath)), readOptions);
228
226
  }
229
227
  catch (error) {
230
228
  if (isNotFound(error)) {
@@ -235,12 +233,12 @@ export function fileStore(options) {
235
233
  },
236
234
  readJson: async (relativePath, readOptions) => {
237
235
  const { encoding = "utf8", ...options } = readOptions ?? {};
238
- return JSON.parse((await (await openRoot()).read(assertRelativePath(relativePath), options)).buffer
236
+ return JSON.parse((await (await openRoot()).read(literalStoreRootPath(assertRelativePath(relativePath)), options)).buffer
239
237
  .toString(encoding));
240
238
  },
241
239
  readJsonIfExists: async (relativePath, readOptions) => {
242
240
  try {
243
- return await (await openRoot()).readJson(assertRelativePath(relativePath), readOptions);
241
+ return await (await openRoot()).readJson(literalStoreRootPath(assertRelativePath(relativePath)), readOptions);
244
242
  }
245
243
  catch (error) {
246
244
  if (isNotFound(error)) {
@@ -250,9 +248,9 @@ export function fileStore(options) {
250
248
  }
251
249
  },
252
250
  remove: async (relativePath) => {
253
- await (await openRoot()).remove(assertRelativePath(relativePath));
251
+ await (await openRoot()).remove(literalStoreRootPath(assertRelativePath(relativePath)));
254
252
  },
255
- exists: async (relativePath) => await (await openRoot()).exists(assertRelativePath(relativePath)),
253
+ exists: async (relativePath) => await (await openRoot()).exists(literalStoreRootPath(assertRelativePath(relativePath))),
256
254
  writeText: async (relativePath, data, writeOptions) => await write(relativePath, data, writeOptions),
257
255
  writeJson: async (relativePath, data, writeOptions) => {
258
256
  const trailingNewline = writeOptions?.trailingNewline;
@@ -269,7 +267,7 @@ export function fileStore(options) {
269
267
  } : {}),
270
268
  readIfExists: async () => {
271
269
  try {
272
- return await (await openRoot()).readJson(assertRelativePath(relativePath));
270
+ return await (await openRoot()).readJson(literalStoreRootPath(relativePath));
273
271
  }
274
272
  catch (error) {
275
273
  if (isNotFound(error)) {
@@ -278,7 +276,7 @@ export function fileStore(options) {
278
276
  throw error;
279
277
  }
280
278
  },
281
- readRequired: async () => await (await openRoot()).readJson(assertRelativePath(relativePath)),
279
+ readRequired: async () => await (await openRoot()).readJson(literalStoreRootPath(relativePath)),
282
280
  write: async (value, options) => {
283
281
  const json = stringifyJsonDocument(value, null, 2);
284
282
  await write(relativePath, options?.trailingNewline === false ? json : `${json}\n`, { durable: options?.durable });
@@ -36,15 +36,6 @@ export const GUEST_FILESYSTEM_RENAME_NO_REPLACE_PYTHON = [
36
36
  " is_linux = sys.platform.startswith('linux')",
37
37
  " if is_linux:",
38
38
  " rename_fn = getattr(libc, 'renameat2', None)",
39
- " if rename_fn is None:",
40
- " os.link(",
41
- " src_basename,",
42
- " dst_basename,",
43
- " src_dir_fd=src_parent_fd,",
44
- " dst_dir_fd=dst_parent_fd,",
45
- " follow_symlinks=False,",
46
- " )",
47
- " return",
48
39
  " flags = 1 # RENAME_NOREPLACE",
49
40
  " elif sys.platform == 'darwin':",
50
41
  " rename_fn = getattr(libc, 'renameatx_np', None)",
@@ -52,32 +43,33 @@ export const GUEST_FILESYSTEM_RENAME_NO_REPLACE_PYTHON = [
52
43
  " else:",
53
44
  " rename_fn = None",
54
45
  " flags = 0",
55
- " if rename_fn is None:",
56
- " raise OSError(errno.ENOSYS, 'atomic no-replace rename is unavailable')",
57
- " rename_fn.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_uint]",
58
- " rename_fn.restype = ctypes.c_int",
59
- " result = rename_fn(",
60
- " src_parent_fd,",
61
- " os.fsencode(src_basename),",
62
- " dst_parent_fd,",
63
- " os.fsencode(dst_basename),",
64
- " flags,",
65
- " )",
66
- " if result != 0:",
46
+ " if rename_fn is not None:",
47
+ " rename_fn.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_uint]",
48
+ " rename_fn.restype = ctypes.c_int",
49
+ " result = rename_fn(",
50
+ " src_parent_fd,",
51
+ " os.fsencode(src_basename),",
52
+ " dst_parent_fd,",
53
+ " os.fsencode(dst_basename),",
54
+ " flags,",
55
+ " )",
56
+ " if result == 0:",
57
+ " return",
67
58
  " error_code = ctypes.get_errno()",
68
59
  " unsupported_codes = {errno.ENOSYS, errno.EINVAL, errno.ENOTSUP}",
69
60
  " if hasattr(errno, 'EOPNOTSUPP'):",
70
61
  " unsupported_codes.add(errno.EOPNOTSUPP)",
71
- " if is_linux and error_code in unsupported_codes:",
72
- " os.link(",
73
- " src_basename,",
74
- " dst_basename,",
75
- " src_dir_fd=src_parent_fd,",
76
- " dst_dir_fd=dst_parent_fd,",
77
- " follow_symlinks=False,",
78
- " )",
79
- " return",
80
- " raise OSError(error_code, os.strerror(error_code), dst_basename)",
62
+ " if not is_linux or error_code not in unsupported_codes:",
63
+ " raise OSError(error_code, os.strerror(error_code), dst_basename)",
64
+ " elif not is_linux:",
65
+ " raise OSError(errno.ENOSYS, 'atomic no-replace rename is unavailable')",
66
+ " os.link(",
67
+ " src_basename,",
68
+ " dst_basename,",
69
+ " src_dir_fd=src_parent_fd,",
70
+ " dst_dir_fd=dst_parent_fd,",
71
+ " follow_symlinks=False,",
72
+ " )",
81
73
  ].join("\n");
82
74
  export const GUEST_FILESYSTEM_CREATE_EXCLUSIVE_PYTHON = [
83
75
  "def create_exclusive(parent_fd, basename, stdin_buffer):",