@openclaw/feishu 2026.9.8 → 2026.10.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/dist/.setup/{channel-DV4hM2Uf.mjs → channel-CX62T71S.mjs} +146 -245
  2. package/dist/.setup/{channel.runtime-CXQcH5zZ.mjs → channel.runtime-COiaq-Rv.mjs} +6 -12
  3. package/dist/.setup/{chat-D8MlFAZi.mjs → chat-BdyvImsY.mjs} +6 -9
  4. package/dist/.setup/{client-BYG-_IZl.mjs → client-BsBVWJzN.mjs} +1 -1
  5. package/dist/.setup/{doctor-contract-3XC0vbIw.mjs → doctor-contract-B1B9ogdd.mjs} +212 -27
  6. package/dist/.setup/{monitor-D_rsHBZ6.mjs → monitor-7DvwUs4Y.mjs} +5 -6
  7. package/dist/.setup/{monitor.account-DvvY7i6k.mjs → monitor.account-7xVu7XWY.mjs} +190 -393
  8. package/dist/.setup/{probe-_ViqSi0j.mjs → probe-B9o7iey6.mjs} +13 -39
  9. package/dist/.setup/{reply-delivery-result-COAjaukc.mjs → reply-delivery-result-Bt-BWBEA.mjs} +151 -297
  10. package/dist/.setup/{setup-api-C4S5I3ac.mjs → setup-api-DmzX9S01.mjs} +1 -1
  11. package/dist/.setup/{subagent-hooks-BaFoMu8W.mjs → subagent-hooks-CUXg0pC-.mjs} +5 -11
  12. package/dist/.setup/{thread-bindings-EdLXPXzw.mjs → thread-bindings-jW2x5VuN.mjs} +23 -41
  13. package/dist/api.js +234 -297
  14. package/dist/channel-plugin-api.js +1 -1
  15. package/dist/doctor-contract-api.js +2 -2
  16. package/dist/session-binding-contract-api.js +1 -1
  17. package/dist/setup-api.js +1 -1
  18. package/dist/setup-entry.js +1 -1
  19. package/dist/subagent-hooks-api.js +1 -1
  20. package/node_modules/@openclaw/fs-safe/CHANGELOG.md +95 -0
  21. package/node_modules/@openclaw/fs-safe/README.md +70 -379
  22. package/node_modules/@openclaw/fs-safe/dist/absolute-path.js +35 -51
  23. package/node_modules/@openclaw/fs-safe/dist/advanced.d.ts +2 -0
  24. package/node_modules/@openclaw/fs-safe/dist/advanced.js +1 -0
  25. package/node_modules/@openclaw/fs-safe/dist/archive-input.js +2 -0
  26. package/node_modules/@openclaw/fs-safe/dist/archive-parser.wasm +0 -0
  27. package/node_modules/@openclaw/fs-safe/dist/archive-staging.d.ts +1 -1
  28. package/node_modules/@openclaw/fs-safe/dist/archive-staging.js +9 -10
  29. package/node_modules/@openclaw/fs-safe/dist/archive.js +2 -5
  30. package/node_modules/@openclaw/fs-safe/dist/atomic-io.d.ts +51 -0
  31. package/node_modules/@openclaw/fs-safe/dist/atomic-io.js +242 -0
  32. package/node_modules/@openclaw/fs-safe/dist/config.d.ts +1 -1
  33. package/node_modules/@openclaw/fs-safe/dist/config.js +1 -1
  34. package/node_modules/@openclaw/fs-safe/dist/copy-file-input.d.ts +1 -1
  35. package/node_modules/@openclaw/fs-safe/dist/copy-file-input.js +2 -2
  36. package/node_modules/@openclaw/fs-safe/dist/copy-tree-portable.js +2 -0
  37. package/node_modules/@openclaw/fs-safe/dist/create.js +12 -5
  38. package/node_modules/@openclaw/fs-safe/dist/directory-guard.d.ts +11 -0
  39. package/node_modules/@openclaw/fs-safe/dist/directory-guard.js +4 -7
  40. package/node_modules/@openclaw/fs-safe/dist/entry-publication-types.d.ts +55 -0
  41. package/node_modules/@openclaw/fs-safe/dist/entry-publication-types.js +1 -0
  42. package/node_modules/@openclaw/fs-safe/dist/entry-publication.d.ts +8 -0
  43. package/node_modules/@openclaw/fs-safe/dist/entry-publication.js +262 -0
  44. package/node_modules/@openclaw/fs-safe/dist/exclusive-create.d.ts +3 -0
  45. package/node_modules/@openclaw/fs-safe/dist/exclusive-create.js +22 -0
  46. package/node_modules/@openclaw/fs-safe/dist/file-cleanup.d.ts +1 -6
  47. package/node_modules/@openclaw/fs-safe/dist/file-cleanup.js +3 -6
  48. package/node_modules/@openclaw/fs-safe/dist/file-identity.js +3 -6
  49. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-io.js +2 -2
  50. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-mutation.js +9 -0
  51. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root.js +4 -6
  52. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-stale-admission.js +1 -1
  53. package/node_modules/@openclaw/fs-safe/dist/file-lock-sync.js +8 -0
  54. package/node_modules/@openclaw/fs-safe/dist/file-store-boundary.js +2 -0
  55. package/node_modules/@openclaw/fs-safe/dist/file-store-sync-write.js +20 -18
  56. package/node_modules/@openclaw/fs-safe/dist/file-store.js +4 -10
  57. package/node_modules/@openclaw/fs-safe/dist/fs.d.ts +2 -10
  58. package/node_modules/@openclaw/fs-safe/dist/fs.js +2 -10
  59. package/node_modules/@openclaw/fs-safe/dist/guarded-mkdir.d.ts +3 -4
  60. package/node_modules/@openclaw/fs-safe/dist/guarded-mkdir.js +6 -18
  61. package/node_modules/@openclaw/fs-safe/dist/guest-dispatch-python.js +1 -1
  62. package/node_modules/@openclaw/fs-safe/dist/guest-native-python.js +0 -2
  63. package/node_modules/@openclaw/fs-safe/dist/guest.js +3 -9
  64. package/node_modules/@openclaw/fs-safe/dist/index.d.ts +1 -1
  65. package/node_modules/@openclaw/fs-safe/dist/index.js +1 -1
  66. package/node_modules/@openclaw/fs-safe/dist/json-durable-queue-directory.js +1 -5
  67. package/node_modules/@openclaw/fs-safe/dist/json.js +19 -37
  68. package/node_modules/@openclaw/fs-safe/dist/move-path.js +2 -0
  69. package/node_modules/@openclaw/fs-safe/dist/mutation-authority.d.ts +1 -0
  70. package/node_modules/@openclaw/fs-safe/dist/mutation-authority.js +9 -1
  71. package/node_modules/@openclaw/fs-safe/dist/native-binding.d.ts +47 -2
  72. package/node_modules/@openclaw/fs-safe/dist/native-config.d.ts +1 -9
  73. package/node_modules/@openclaw/fs-safe/dist/native-config.js +6 -40
  74. package/node_modules/@openclaw/fs-safe/dist/native-parent-admission.d.ts +2 -0
  75. package/node_modules/@openclaw/fs-safe/dist/native-parent-admission.js +5 -2
  76. package/node_modules/@openclaw/fs-safe/dist/native-pinned-write.js +11 -316
  77. package/node_modules/@openclaw/fs-safe/dist/native-policy-parent-windows.d.ts +7 -7
  78. package/node_modules/@openclaw/fs-safe/dist/native-policy-parent-windows.js +28 -175
  79. package/node_modules/@openclaw/fs-safe/dist/native-policy-parent.d.ts +15 -0
  80. package/node_modules/@openclaw/fs-safe/dist/native-policy-parent.js +418 -0
  81. package/node_modules/@openclaw/fs-safe/dist/native-rename-outcome.js +9 -4
  82. package/node_modules/@openclaw/fs-safe/dist/native-staged-file.js +17 -13
  83. package/node_modules/@openclaw/fs-safe/dist/native-staged-symlink.js +6 -24
  84. package/node_modules/@openclaw/fs-safe/dist/native.js +5 -1
  85. package/node_modules/@openclaw/fs-safe/dist/path-case.js +10 -9
  86. package/node_modules/@openclaw/fs-safe/dist/path-scope-lexical.js +4 -1
  87. package/node_modules/@openclaw/fs-safe/dist/path-segment-route.d.ts +1 -0
  88. package/node_modules/@openclaw/fs-safe/dist/path-segment-route.js +3 -0
  89. package/node_modules/@openclaw/fs-safe/dist/path.js +4 -1
  90. package/node_modules/@openclaw/fs-safe/dist/permissions-windows.d.ts +0 -1
  91. package/node_modules/@openclaw/fs-safe/dist/pinned-mutation-admission.js +1 -3
  92. package/node_modules/@openclaw/fs-safe/dist/pinned-write-staged.js +2 -0
  93. package/node_modules/@openclaw/fs-safe/dist/pinned-write.js +9 -10
  94. package/node_modules/@openclaw/fs-safe/dist/private-producer-handoff.js +3 -6
  95. package/node_modules/@openclaw/fs-safe/dist/publish-copy-stage.js +2 -2
  96. package/node_modules/@openclaw/fs-safe/dist/publish-file.js +4 -3
  97. package/node_modules/@openclaw/fs-safe/dist/replace-file-buffer.d.ts +3 -4
  98. package/node_modules/@openclaw/fs-safe/dist/replace-file-buffer.js +18 -32
  99. package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-fallback.d.ts +5 -17
  100. package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-fallback.js +92 -230
  101. package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-source.d.ts +4 -15
  102. package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-source.js +22 -63
  103. package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.d.ts +9 -34
  104. package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.js +78 -83
  105. package/node_modules/@openclaw/fs-safe/dist/replace-file-destination.d.ts +18 -20
  106. package/node_modules/@openclaw/fs-safe/dist/replace-file-destination.js +64 -98
  107. package/node_modules/@openclaw/fs-safe/dist/replace-file-temp-owner.d.ts +16 -33
  108. package/node_modules/@openclaw/fs-safe/dist/replace-file-temp-owner.js +61 -200
  109. package/node_modules/@openclaw/fs-safe/dist/replace-file-types.d.ts +1 -6
  110. package/node_modules/@openclaw/fs-safe/dist/replace-file.js +76 -216
  111. package/node_modules/@openclaw/fs-safe/dist/root-boundary.js +14 -24
  112. package/node_modules/@openclaw/fs-safe/dist/root-context.d.ts +1 -4
  113. package/node_modules/@openclaw/fs-safe/dist/root-context.js +4 -19
  114. package/node_modules/@openclaw/fs-safe/dist/root-create-native.d.ts +52 -0
  115. package/node_modules/@openclaw/fs-safe/dist/root-create-native.js +350 -0
  116. package/node_modules/@openclaw/fs-safe/dist/root-directory-list-types.d.ts +35 -0
  117. package/node_modules/@openclaw/fs-safe/dist/root-directory-list-types.js +1 -0
  118. package/node_modules/@openclaw/fs-safe/dist/root-directory-list.d.ts +2 -27
  119. package/node_modules/@openclaw/fs-safe/dist/root-directory-list.js +31 -28
  120. package/node_modules/@openclaw/fs-safe/dist/root-directory.js +1 -4
  121. package/node_modules/@openclaw/fs-safe/dist/root-errors.js +34 -0
  122. package/node_modules/@openclaw/fs-safe/dist/root-file.js +9 -21
  123. package/node_modules/@openclaw/fs-safe/dist/root-impl.js +105 -37
  124. package/node_modules/@openclaw/fs-safe/dist/root-move-noreplace.d.ts +7 -2
  125. package/node_modules/@openclaw/fs-safe/dist/root-move-noreplace.js +67 -38
  126. package/node_modules/@openclaw/fs-safe/dist/root-observed-path.d.ts +1 -1
  127. package/node_modules/@openclaw/fs-safe/dist/root-observed-path.js +0 -2
  128. package/node_modules/@openclaw/fs-safe/dist/root-options.d.ts +2 -3
  129. package/node_modules/@openclaw/fs-safe/dist/root-path-existing.js +3 -1
  130. package/node_modules/@openclaw/fs-safe/dist/root-path-stat.js +68 -85
  131. package/node_modules/@openclaw/fs-safe/dist/root-path.js +6 -1
  132. package/node_modules/@openclaw/fs-safe/dist/root-paths-lexical.d.ts +4 -0
  133. package/node_modules/@openclaw/fs-safe/dist/root-paths-lexical.js +1 -1
  134. package/node_modules/@openclaw/fs-safe/dist/root-paths.js +4 -9
  135. package/node_modules/@openclaw/fs-safe/dist/root-remove-native.d.ts +4 -0
  136. package/node_modules/@openclaw/fs-safe/dist/root-remove-native.js +311 -0
  137. package/node_modules/@openclaw/fs-safe/dist/root-remove.d.ts +11 -0
  138. package/node_modules/@openclaw/fs-safe/dist/root-remove.js +3 -1
  139. package/node_modules/@openclaw/fs-safe/dist/root-walk.d.ts +2 -2
  140. package/node_modules/@openclaw/fs-safe/dist/root-walk.js +1 -3
  141. package/node_modules/@openclaw/fs-safe/dist/root-write-admission.d.ts +3 -3
  142. package/node_modules/@openclaw/fs-safe/dist/root-write-admission.js +8 -10
  143. package/node_modules/@openclaw/fs-safe/dist/safe-path-segment.d.ts +0 -1
  144. package/node_modules/@openclaw/fs-safe/dist/safe-path-segment.js +0 -4
  145. package/node_modules/@openclaw/fs-safe/dist/secret-file.js +12 -9
  146. package/node_modules/@openclaw/fs-safe/dist/secure-temp-dir.d.ts +0 -2
  147. package/node_modules/@openclaw/fs-safe/dist/sibling-staged-file.js +2 -0
  148. package/node_modules/@openclaw/fs-safe/dist/sibling-temp.js +7 -4
  149. package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-acquire.js +13 -6
  150. package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.d.ts +0 -3
  151. package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.js +5 -23
  152. package/node_modules/@openclaw/fs-safe/dist/staged-file-settlement.d.ts +2 -1
  153. package/node_modules/@openclaw/fs-safe/dist/staged-file-settlement.js +11 -6
  154. package/node_modules/@openclaw/fs-safe/dist/temp-cleanup.js +1 -8
  155. package/node_modules/@openclaw/fs-safe/dist/temp-workspace-child-admission.d.ts +1 -1
  156. package/node_modules/@openclaw/fs-safe/dist/temp-workspace-child-admission.js +2 -9
  157. package/node_modules/@openclaw/fs-safe/dist/text-atomic.d.ts +1 -6
  158. package/node_modules/@openclaw/fs-safe/dist/trash.js +6 -2
  159. package/node_modules/@openclaw/fs-safe/dist/walk.js +100 -46
  160. package/node_modules/@openclaw/fs-safe/dist/watch-hints.d.ts +7 -0
  161. package/node_modules/@openclaw/fs-safe/dist/watch-hints.js +235 -19
  162. package/node_modules/@openclaw/fs-safe/dist/watch-native.d.ts +21 -2
  163. package/node_modules/@openclaw/fs-safe/dist/watch-native.js +21 -3
  164. package/node_modules/@openclaw/fs-safe/dist/watch-rescan.d.ts +6 -0
  165. package/node_modules/@openclaw/fs-safe/dist/watch-rescan.js +111 -0
  166. package/node_modules/@openclaw/fs-safe/dist/watch-scan.d.ts +13 -0
  167. package/node_modules/@openclaw/fs-safe/dist/watch-scan.js +27 -4
  168. package/node_modules/@openclaw/fs-safe/dist/watch-stream.js +2 -0
  169. package/node_modules/@openclaw/fs-safe/dist/watch.js +131 -40
  170. package/node_modules/@openclaw/fs-safe/dist/windows-path-alias.d.ts +8 -0
  171. package/node_modules/@openclaw/fs-safe/dist/windows-path-alias.js +24 -6
  172. package/node_modules/@openclaw/fs-safe/dist/windows-path-syntax.d.ts +13 -0
  173. package/node_modules/@openclaw/fs-safe/dist/windows-path-syntax.js +51 -0
  174. package/node_modules/@openclaw/fs-safe/docs/advanced.md +4 -0
  175. package/node_modules/@openclaw/fs-safe/docs/atomic.md +4 -1
  176. package/node_modules/@openclaw/fs-safe/docs/config.md +6 -14
  177. package/node_modules/@openclaw/fs-safe/docs/contributing.md +4 -14
  178. package/node_modules/@openclaw/fs-safe/docs/durability.md +6 -29
  179. package/node_modules/@openclaw/fs-safe/docs/entry-publication.md +146 -0
  180. package/node_modules/@openclaw/fs-safe/docs/errors.md +16 -0
  181. package/node_modules/@openclaw/fs-safe/docs/file-store.md +28 -5
  182. package/node_modules/@openclaw/fs-safe/docs/index.md +2 -31
  183. package/node_modules/@openclaw/fs-safe/docs/install.md +10 -31
  184. package/node_modules/@openclaw/fs-safe/docs/json.md +1 -1
  185. package/node_modules/@openclaw/fs-safe/docs/local-roots.md +0 -1
  186. package/node_modules/@openclaw/fs-safe/docs/migrating-to-0.5.md +12 -12
  187. package/node_modules/@openclaw/fs-safe/docs/native-helper.md +35 -96
  188. package/node_modules/@openclaw/fs-safe/docs/native.md +22 -20
  189. package/node_modules/@openclaw/fs-safe/docs/path.md +1 -1
  190. package/node_modules/@openclaw/fs-safe/docs/permissions.md +1 -2
  191. package/node_modules/@openclaw/fs-safe/docs/public-api.md +1 -2
  192. package/node_modules/@openclaw/fs-safe/docs/reading.md +1 -2
  193. package/node_modules/@openclaw/fs-safe/docs/root.md +26 -184
  194. package/node_modules/@openclaw/fs-safe/docs/secret-file.md +1 -1
  195. package/node_modules/@openclaw/fs-safe/docs/security-model.md +115 -3
  196. package/node_modules/@openclaw/fs-safe/docs/store.md +2 -2
  197. package/node_modules/@openclaw/fs-safe/docs/temp.md +29 -65
  198. package/node_modules/@openclaw/fs-safe/docs/testing.md +90 -58
  199. package/node_modules/@openclaw/fs-safe/docs/types.md +3 -16
  200. package/node_modules/@openclaw/fs-safe/docs/walk.md +33 -5
  201. package/node_modules/@openclaw/fs-safe/docs/watch.md +96 -14
  202. package/node_modules/@openclaw/fs-safe/docs/writing.md +172 -16
  203. package/node_modules/@openclaw/fs-safe/package.json +10 -10
  204. package/node_modules/@openclaw/fs-safe-darwin-arm64/fs-safe-native.node +0 -0
  205. package/node_modules/@openclaw/fs-safe-darwin-arm64/package.json +1 -1
  206. package/node_modules/@openclaw/fs-safe-darwin-x64/fs-safe-native.node +0 -0
  207. package/node_modules/@openclaw/fs-safe-darwin-x64/package.json +1 -1
  208. package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/fs-safe-native.node +0 -0
  209. package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/package.json +1 -1
  210. package/node_modules/@openclaw/fs-safe-linux-arm64-musl/fs-safe-native.node +0 -0
  211. package/node_modules/@openclaw/fs-safe-linux-arm64-musl/package.json +1 -1
  212. package/node_modules/@openclaw/fs-safe-linux-x64-gnu/fs-safe-native.node +0 -0
  213. package/node_modules/@openclaw/fs-safe-linux-x64-gnu/package.json +1 -1
  214. package/node_modules/@openclaw/fs-safe-linux-x64-musl/fs-safe-native.node +0 -0
  215. package/node_modules/@openclaw/fs-safe-linux-x64-musl/package.json +1 -1
  216. package/node_modules/@openclaw/fs-safe-win32-x64-msvc/fs-safe-native.node +0 -0
  217. package/node_modules/@openclaw/fs-safe-win32-x64-msvc/package.json +1 -1
  218. package/package.json +5 -5
  219. package/skills/feishu-wiki/SKILL.md +1 -1
  220. package/dist/.setup/accounts-wRqItHug.mjs +0 -206
  221. package/node_modules/@openclaw/fs-safe/dist/watch-alias.d.ts +0 -6
  222. package/node_modules/@openclaw/fs-safe/dist/watch-alias.js +0 -88
  223. package/node_modules/@openclaw/fs-safe/docs/mutation-policy-proof.md +0 -69
  224. package/node_modules/@openclaw/fs-safe/docs/private-file-store.md +0 -68
  225. package/node_modules/@openclaw/fs-safe/docs/test-hooks.md +0 -110
@@ -1,12 +1,4 @@
1
1
  let overrideConfig = {};
2
- let legacyWarningEmitted = false;
3
- const legacyModeEnvKeys = ["FS_SAFE_PYTHON_MODE", "OPENCLAW_FS_SAFE_PYTHON_MODE"];
4
- const legacyPathEnvKeys = [
5
- "FS_SAFE_PYTHON",
6
- "OPENCLAW_FS_SAFE_PYTHON",
7
- "OPENCLAW_PINNED_PYTHON",
8
- "OPENCLAW_PINNED_WRITE_PYTHON",
9
- ];
10
2
  function parseMode(value) {
11
3
  if (!value) {
12
4
  return undefined;
@@ -26,46 +18,20 @@ function parseMode(value) {
26
18
  export function configureFsSafeNative(config) {
27
19
  overrideConfig = { ...overrideConfig, ...config };
28
20
  }
29
- function warnLegacyPythonConfiguration(source, mappedMode) {
30
- if (legacyWarningEmitted) {
31
- return;
32
- }
33
- legacyWarningEmitted = true;
34
- process.emitWarning(`${source} is a deprecated 0.4 compatibility bridge; mapped to native mode ` +
35
- `"${mappedMode}". Use configureFsSafeNative({ mode: "${mappedMode}" }) or ` +
36
- `FS_SAFE_NATIVE_MODE=${mappedMode}. Python interpreter paths are no longer used.`, { code: "FS_SAFE_PYTHON_DEPRECATED", type: "DeprecationWarning" });
37
- }
38
- function readLegacyPythonMode() {
39
- const configuredKeys = [...legacyModeEnvKeys, ...legacyPathEnvKeys].filter((key) => process.env[key] !== undefined);
40
- if (configuredKeys.length === 0) {
41
- return undefined;
42
- }
43
- const rawMode = legacyModeEnvKeys.map((key) => process.env[key]).find((value) => value !== undefined);
44
- const mappedMode = parseMode(rawMode) ?? "auto";
45
- warnLegacyPythonConfiguration(`Legacy ${configuredKeys.join(", ")}`, mappedMode);
46
- return mappedMode;
47
- }
48
- /**
49
- * @deprecated Compatibility bridge for 0.4 upgrades. Use configureFsSafeNative.
50
- */
51
- export function configureFsSafePython(config) {
52
- const mappedMode = config.mode ?? "auto";
53
- warnLegacyPythonConfiguration("configureFsSafePython()", mappedMode);
54
- if (config.mode !== undefined) {
55
- configureFsSafeNative({ mode: config.mode });
56
- }
57
- }
58
21
  export function getFsSafeNativeConfig() {
59
- const legacyMode = readLegacyPythonMode();
60
22
  return {
61
23
  mode: overrideConfig.mode ??
62
24
  parseMode(process.env.FS_SAFE_NATIVE_MODE) ??
63
25
  parseMode(process.env.OPENCLAW_FS_SAFE_NATIVE_MODE) ??
64
- legacyMode ??
65
26
  "auto",
66
27
  };
67
28
  }
29
+ export function isFsSafeNativeRequired() {
30
+ return (overrideConfig.mode ??
31
+ parseMode(process.env.FS_SAFE_NATIVE_MODE) ??
32
+ parseMode(process.env.OPENCLAW_FS_SAFE_NATIVE_MODE) ??
33
+ "auto") === "require";
34
+ }
68
35
  export function __resetFsSafeNativeConfigForTest() {
69
36
  overrideConfig = {};
70
- legacyWarningEmitted = false;
71
37
  }
@@ -5,6 +5,7 @@ import type { NativeBinding } from "./native.js";
5
5
  import { describeStagedDirectory } from "./staged-directory.js";
6
6
  type RootIdentity = Pick<FileIdentityStat, "dev" | "ino">;
7
7
  export type NativeRootAdmission = {
8
+ directoryFlags?: number;
8
9
  exactRoot: boolean;
9
10
  reportCloseErrors?: boolean;
10
11
  operation: string;
@@ -27,6 +28,7 @@ export declare function openNativeRootAdmission(binding: NativeBinding, params:
27
28
  rootIdentity?: RootIdentity;
28
29
  operation?: string;
29
30
  reportCloseErrors?: boolean;
31
+ searchOnly?: boolean;
30
32
  }): Promise<NativeRootAdmission>;
31
33
  export declare function openNativeParentAdmission(binding: NativeBinding, rootAdmission: Omit<NativeRootAdmission, "root"> & {
32
34
  root: Pick<FileHandle, "fd">;
@@ -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 { inspectDirectoryIdentity, inspectDirectoryIdentitySync } from "./directory-guard.js";
5
+ import { nodeDirectorySearchOnlyFlags } from "./directory-mode-node.js";
5
6
  import { inspectNativeDirectoryObservation } from "./native-directory-observation.js";
6
7
  import { FsSafeError } from "./errors.js";
7
8
  import { captureNativeFdClose } from "./native-binding.js";
@@ -24,7 +25,8 @@ function assertParentAdmissionAvailable(binding) {
24
25
  }
25
26
  export async function openNativeRootAdmission(binding, params) {
26
27
  assertParentAdmissionAvailable(binding);
27
- const directoryFlags = fsSync.constants.O_RDONLY | (fsSync.constants.O_DIRECTORY ?? 0);
28
+ const directoryFlags = (params.searchOnly ? nodeDirectorySearchOnlyFlags()?.flags ?? fsSync.constants.O_RDONLY : fsSync.constants.O_RDONLY) |
29
+ (fsSync.constants.O_DIRECTORY ?? 0);
28
30
  assertNoWindowsPathAlias(params.rootPath, "filesystem", "native root uses a Windows filesystem namespace alias");
29
31
  const root = await fs.open(pathForWindowsFilesystem(params.rootPath), directoryFlags);
30
32
  try {
@@ -50,6 +52,7 @@ export async function openNativeRootAdmission(binding, params) {
50
52
  throw new FsSafeError("path-mismatch", `root path changed during ${params.operation ?? "native admission"}`);
51
53
  }
52
54
  return {
55
+ directoryFlags,
53
56
  exactRoot,
54
57
  reportCloseErrors: params.reportCloseErrors,
55
58
  operation: params.operation ?? "native admission",
@@ -73,7 +76,7 @@ export async function openNativeRootAdmission(binding, params) {
73
76
  export async function openNativeParentAdmission(binding, rootAdmission, relativeParentPath, observation) {
74
77
  assertParentAdmissionAvailable(binding);
75
78
  const closeFd = captureNativeFdClose(binding);
76
- const directoryFlags = fsSync.constants.O_RDONLY | (fsSync.constants.O_DIRECTORY ?? 0);
79
+ const directoryFlags = rootAdmission.directoryFlags ?? (fsSync.constants.O_RDONLY | (fsSync.constants.O_DIRECTORY ?? 0));
77
80
  assertNoWindowsPathAlias(relativeParentPath, "relative", "native parent uses a Windows filesystem namespace alias");
78
81
  const opened = binding.openBeneath(rootAdmission.root.fd, relativeParentPath, directoryFlags);
79
82
  if (!opened || !Number.isInteger(opened.fd) || opened.fd < 0) {
@@ -52,312 +52,13 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
52
52
  });
53
53
  import fsSync, {} from "node:fs";
54
54
  import path from "node:path";
55
- import { inspectDirectoryIdentity } from "./directory-guard.js";
56
- import { FsSafeError } from "./errors.js";
57
55
  import { runPinnedWriteWindows } from "./native-pinned-write-windows.js";
58
- import { capturePolicyAwareWindowsParent } from "./native-policy-parent-windows.js";
56
+ import { capturePolicyAwareNativeParent } from "./native-policy-parent.js";
59
57
  import { openNativeParentAdmission, openNativeRootAdmission } from "./native-parent-admission.js";
60
58
  import { assertNativeStaging, writeNativeStage } from "./native-staged-file.js";
61
59
  import { captureNativeFdClose } from "./native-binding.js";
62
- import { NativePolicyDirectoryMismatch } from "./native-policy-directory-observation.js";
63
- import { assertPolicyStagedDirectoryCurrent, assertStagedDirectoryCurrent, describePolicyStagedDirectory, describeStagedDirectory, refreshPolicyStagedDirectoryObservation, } from "./staged-directory.js";
64
- import { inspectFileIdentitySync } from "./strict-file-identity.js";
65
- import { realpathSync } from "./realpath.js";
66
- import { errorCauseOptions } from "./root-errors.js";
67
- import { isNotFoundPathError, isSymlinkOpenError } from "./path.js";
68
- import { checkedMutationDirectory, } from "./pinned-mutation-observation.js";
69
- import { createPathSegmentRoute, joinPathSegmentRoute } from "./path-segment-route.js";
70
- function sameAbsolutePath(left, right) {
71
- return path.relative(path.resolve(left), path.resolve(right)) === "";
72
- }
73
- function assertDirectChildBasename(basename) {
74
- if (!basename || basename === "." || basename === ".." || basename.includes("/") ||
75
- basename.includes("\0") || (process.platform === "win32" && basename.includes("\\"))) {
76
- throw new FsSafeError("invalid-path", "native parent creation requires one direct-child basename");
77
- }
78
- }
79
- function mkdirPolicyChild(binding, parentFd, basename, mode) {
80
- assertDirectChildBasename(basename);
81
- const mkdirChild = binding.mkdirChildBeneath;
82
- if (typeof mkdirChild === "function") {
83
- const created = mkdirChild.call(binding, parentFd, basename, mode);
84
- if (typeof created === "boolean")
85
- return created;
86
- }
87
- // Old or malformed optional helpers still execute through the established
88
- // recursive primitive, but cannot provide exclusive-creation provenance.
89
- binding.mkdirBeneath(parentFd, basename, mode);
90
- return false;
91
- }
92
- async function authorizePinnedMutation(params, request) {
93
- return await params.mutationAdmission?.authorize(Object.freeze(request));
94
- }
95
- function normalizePolicyParentOpenError(error, params) {
96
- if (!isSymlinkOpenError(error))
97
- return error;
98
- return params.mutationAdmission?.rejectParentSymlinks
99
- ? new FsSafeError("symlink", "symlink path component not allowed", errorCauseOptions(error))
100
- : new FsSafeError("path-mismatch", "native write parent changed during policy admission", errorCauseOptions(error));
101
- }
102
- async function describePosixParent(parentFd, pathname) {
103
- const parentPath = realpathSync.native(pathname);
104
- const directory = describeStagedDirectory(parentFd, parentPath);
105
- const parentPathStat = await inspectDirectoryIdentity(parentPath, inspectFileIdentitySync(() => fsSync.fstatSync(parentFd, { bigint: true })));
106
- return {
107
- parentFd,
108
- parentPath,
109
- directory,
110
- parentPathStat,
111
- observation: checkedMutationDirectory(parentPath, directory.realPath, parentPathStat),
112
- };
113
- }
114
- function describePolicyPosixParent(binding, parentFd, pathname) {
115
- const policyDirectory = describePolicyStagedDirectory(parentFd, pathname, binding);
116
- return {
117
- parentFd,
118
- parentPath: policyDirectory.directory.realPath,
119
- directory: policyDirectory.directory,
120
- parentPathStat: policyDirectory.stat,
121
- observation: policyDirectory.observation,
122
- policyDirectory,
123
- };
124
- }
125
- function policyParentCaptureDeopt(error) {
126
- return error instanceof FsSafeError &&
127
- !(error instanceof NativePolicyDirectoryMismatch) &&
128
- (error.code === "path-mismatch" || error.code === "not-file");
129
- }
130
- function tryDescribePolicyPosixParent(binding, parentFd, pathname) {
131
- try {
132
- return describePolicyPosixParent(binding, parentFd, pathname);
133
- }
134
- catch (error) {
135
- if (!policyParentCaptureDeopt(error))
136
- throw error;
137
- return undefined;
138
- }
139
- }
140
- function assertPosixParentCurrent(parent) {
141
- return parent.policyDirectory
142
- ? assertPolicyStagedDirectoryCurrent(parent.policyDirectory)
143
- : assertStagedDirectoryCurrent(parent.directory);
144
- }
145
- async function capturePolicyAwarePosixParent(binding, params, rootFd, directoryFlags) {
146
- const env_1 = { stack: [], error: void 0, hasError: false };
147
- try {
148
- const closeFd = captureNativeFdClose(binding);
149
- const observationDisposers = new Map();
150
- const disposeObservation = (fd) => {
151
- const dispose = observationDisposers.get(fd);
152
- observationDisposers.delete(fd);
153
- dispose?.();
154
- };
155
- const observationScope = __addDisposableResource(env_1, {
156
- [Symbol.dispose]() { for (const dispose of observationDisposers.values())
157
- dispose(); },
158
- }, false);
159
- const capturePolicyParent = (fd, pathname) => {
160
- const captured = tryDescribePolicyPosixParent(binding, fd, pathname);
161
- const dispose = captured?.policyDirectory?.disposeObservation;
162
- if (dispose)
163
- observationDisposers.set(fd, dispose);
164
- return captured;
165
- };
166
- const segments = params.relativeParentPath.split("/").filter(Boolean);
167
- const parentSpelling = segments.length
168
- ? path.join(params.rootPath, ...segments)
169
- : params.rootPath;
170
- const segmentRoute = createPathSegmentRoute(segments);
171
- const initialTarget = joinPathSegmentRoute(params.rootPath, segmentRoute, 0, params.basename);
172
- let retainedTargetPath = params.mutationAdmission?.beginParentWalk?.();
173
- if (retainedTargetPath && !sameAbsolutePath(retainedTargetPath, initialTarget)) {
174
- retainedTargetPath = undefined;
175
- }
176
- // Preserve the one-open hot path when the complete parent still exists.
177
- // Policy is attached only after the opened descriptor is associated with its
178
- // current canonical pathname, so a contained redirect cannot retain the old
179
- // preflight authorization.
180
- let completeParentFd;
181
- try {
182
- completeParentFd = binding.openBeneath(rootFd, params.relativeParentPath, directoryFlags).fd;
183
- }
184
- catch (error) {
185
- if (error?.code !== "ENOENT" || !params.mkdir) {
186
- // A mechanism rejection must not hide canonical denial/symlink policy.
187
- // This admission only classifies failure; it cannot authorize a retry.
188
- await authorizePinnedMutation(params, {
189
- targetPath: initialTarget, mutationPath: initialTarget, phase: "parent",
190
- });
191
- throw normalizePolicyParentOpenError(error, params);
192
- }
193
- }
194
- if (completeParentFd !== undefined) {
195
- const parentFd = completeParentFd;
196
- try {
197
- let admitted = retainedTargetPath
198
- ? capturePolicyParent(parentFd, parentSpelling)
199
- : undefined;
200
- if (!admitted) {
201
- retainedTargetPath = undefined;
202
- admitted = await describePosixParent(parentFd, parentSpelling);
203
- }
204
- const targetPath = path.join(admitted.parentPath, params.basename);
205
- await authorizePinnedMutation(params, {
206
- targetPath,
207
- mutationPath: targetPath,
208
- phase: "parent",
209
- });
210
- assertPosixParentCurrent(admitted);
211
- return admitted;
212
- }
213
- catch (error) {
214
- disposeObservation(parentFd);
215
- closeFd(parentFd);
216
- throw error;
217
- }
218
- }
219
- // The canonical preflight spelling has no intentional symlinks in its
220
- // existing prefix. Walk missing-parent cases one direct child at a time so
221
- // every existing/opened object is authorized and every mkdir is authorized
222
- // before dispatch. O_NOFOLLOW makes a concurrently introduced link fail
223
- // before the next component can be created through it.
224
- const secureDirectoryFlags = directoryFlags | (fsSync.constants.O_NOFOLLOW ?? 0);
225
- let currentFd = rootFd;
226
- let currentOwnedFd;
227
- let currentPath = params.rootPath;
228
- let current = retainedTargetPath
229
- ? capturePolicyParent(rootFd, currentPath)
230
- : undefined;
231
- if (!current) {
232
- retainedTargetPath = undefined;
233
- current = await describePosixParent(rootFd, currentPath);
234
- }
235
- try {
236
- await authorizePinnedMutation(params, {
237
- targetPath: retainedTargetPath ?? initialTarget,
238
- mutationPath: retainedTargetPath ?? initialTarget,
239
- phase: "parent",
240
- });
241
- assertPosixParentCurrent(current);
242
- for (let index = 0; index < segments.length; index += 1) {
243
- const segment = segments[index];
244
- const childPath = path.join(currentPath, segment);
245
- let childFd;
246
- let createdByMkdir = false;
247
- let createReceipt;
248
- try {
249
- childFd = binding.openBeneath(currentFd, segment, secureDirectoryFlags).fd;
250
- }
251
- catch (openError) {
252
- if (!isNotFoundPathError(openError)) {
253
- throw normalizePolicyParentOpenError(openError, params);
254
- }
255
- const targetPath = retainedTargetPath ?? joinPathSegmentRoute(currentPath, segmentRoute, index, params.basename);
256
- const request = Object.freeze({
257
- targetPath,
258
- mutationPath: childPath,
259
- phase: "parent-create",
260
- });
261
- createReceipt = params.mutationAdmission?.tryAuthorizeAtParent?.(request, current.observation);
262
- if (!createReceipt) {
263
- createReceipt = await authorizePinnedMutation(params, request);
264
- assertPosixParentCurrent(current);
265
- }
266
- params.assertBeforeMutation?.();
267
- // Do not carry pathname freshness across the live authority callback.
268
- assertPosixParentCurrent(current);
269
- createdByMkdir = mkdirPolicyChild(binding, currentFd, segment, 0o777);
270
- try {
271
- childFd = binding.openBeneath(currentFd, segment, secureDirectoryFlags).fd;
272
- }
273
- catch (createdOpenError) {
274
- throw normalizePolicyParentOpenError(createdOpenError, params);
275
- }
276
- }
277
- let child;
278
- try {
279
- const acceleratedChild = retainedTargetPath
280
- ? capturePolicyParent(childFd, childPath)
281
- : undefined;
282
- if (acceleratedChild) {
283
- child = acceleratedChild;
284
- }
285
- else {
286
- retainedTargetPath = undefined;
287
- child = await describePosixParent(childFd, childPath);
288
- }
289
- if (!sameAbsolutePath(child.parentPath, childPath))
290
- retainedTargetPath = undefined;
291
- let childAuthorization;
292
- if (createdByMkdir && createReceipt && params.mutationAdmission?.advanceCreatedDirectory) {
293
- let evidence;
294
- try {
295
- const parent = current.policyDirectory
296
- ? refreshPolicyStagedDirectoryObservation(current.policyDirectory)
297
- : checkedMutationDirectory(currentPath, current.directory.realPath, assertStagedDirectoryCurrent(current.directory));
298
- evidence = Object.freeze({
299
- admission: createReceipt,
300
- parent,
301
- child: child.observation,
302
- });
303
- }
304
- catch {
305
- // Leave failed evidence to the full ordered admission below.
306
- }
307
- if (evidence) {
308
- childAuthorization = params.mutationAdmission.advanceCreatedDirectory(evidence);
309
- }
310
- }
311
- const targetPath = retainedTargetPath ?? joinPathSegmentRoute(child.parentPath, segmentRoute, index + 1, params.basename);
312
- const request = Object.freeze({
313
- targetPath,
314
- mutationPath: targetPath,
315
- phase: "parent",
316
- });
317
- childAuthorization ??= params.mutationAdmission?.tryAuthorizeAtParent?.(request, child.observation);
318
- if (!childAuthorization) {
319
- await authorizePinnedMutation(params, request);
320
- assertPosixParentCurrent(child);
321
- }
322
- }
323
- catch (error) {
324
- disposeObservation(childFd);
325
- closeFd(childFd);
326
- throw error;
327
- }
328
- const previousOwnedFd = currentOwnedFd;
329
- disposeObservation(current.parentFd);
330
- currentOwnedFd = child.parentFd;
331
- currentFd = child.parentFd;
332
- currentPath = child.parentPath;
333
- current = child;
334
- if (previousOwnedFd !== undefined)
335
- closeFd(previousOwnedFd);
336
- if (index === segments.length - 1) {
337
- currentOwnedFd = undefined;
338
- return child;
339
- }
340
- }
341
- // Empty relative parents are handled by the complete-parent fast path.
342
- throw new FsSafeError("path-mismatch", "native write parent admission did not complete");
343
- }
344
- finally {
345
- if (currentOwnedFd !== undefined) {
346
- disposeObservation(currentOwnedFd);
347
- closeFd(currentOwnedFd);
348
- }
349
- }
350
- }
351
- catch (e_1) {
352
- env_1.error = e_1;
353
- env_1.hasError = true;
354
- }
355
- finally {
356
- __disposeResources(env_1);
357
- }
358
- }
359
60
  export async function runPinnedWriteNative(binding, params) {
360
- const env_2 = { stack: [], error: void 0, hasError: false };
61
+ const env_1 = { stack: [], error: void 0, hasError: false };
361
62
  try {
362
63
  const closeFd = captureNativeFdClose(binding);
363
64
  const windows = process.platform === "win32";
@@ -373,13 +74,13 @@ export async function runPinnedWriteNative(binding, params) {
373
74
  reportCloseErrors: completeCreate,
374
75
  });
375
76
  const root = rootAdmission.root;
376
- const posixRoot = __addDisposableResource(env_2, windows ? undefined : root, true);
77
+ const posixRoot = __addDisposableResource(env_1, windows ? undefined : root, true);
377
78
  let parentFd;
378
79
  let windowsOwnsDirectories = false;
379
80
  let admissionFailure;
380
81
  // Until stage construction takes ownership, even admission failures must close
381
82
  // the raw POSIX parent. Disposal preserves both admission and close failures.
382
- const parentGuard = __addDisposableResource(env_2, {
83
+ const parentGuard = __addDisposableResource(env_1, {
383
84
  [Symbol.dispose]() {
384
85
  if (!windows && parentFd !== undefined) {
385
86
  closeFd(parentFd);
@@ -390,17 +91,11 @@ export async function runPinnedWriteNative(binding, params) {
390
91
  let parentPath;
391
92
  let directory;
392
93
  let parentPathStat;
393
- if (!windows && params.mutationAdmission) {
394
- const admitted = await capturePolicyAwarePosixParent(binding, params, root.fd, directoryFlags);
395
- parentFd = admitted.parentFd;
396
- parentPath = admitted.parentPath;
397
- directory = admitted.directory;
398
- parentPathStat = admitted.parentPathStat;
399
- }
400
- else if (windows && params.mutationAdmission) {
401
- const admitted = await capturePolicyAwareWindowsParent(binding, params, rootAdmission);
94
+ if (params.mutationAdmission) {
95
+ const admitted = await capturePolicyAwareNativeParent(binding, params, rootAdmission, windows, directoryFlags);
402
96
  parentFd = admitted.fd;
403
97
  parentPath = admitted.guard.realPath;
98
+ directory = admitted.stagedDirectory;
404
99
  parentPathStat = admitted.guard.stat;
405
100
  }
406
101
  else {
@@ -466,12 +161,12 @@ export async function runPinnedWriteNative(binding, params) {
466
161
  }
467
162
  }
468
163
  }
469
- catch (e_2) {
470
- env_2.error = e_2;
471
- env_2.hasError = true;
164
+ catch (e_1) {
165
+ env_1.error = e_1;
166
+ env_1.hasError = true;
472
167
  }
473
168
  finally {
474
- const result_1 = __disposeResources(env_2);
169
+ const result_1 = __disposeResources(env_1);
475
170
  if (result_1)
476
171
  await result_1;
477
172
  }
@@ -4,10 +4,10 @@ import { type NativeRootAdmission } from "./native-parent-admission.js";
4
4
  import type { NativeBinding } from "./native.js";
5
5
  import type { PinnedWriteParams } from "./pinned-write-types.js";
6
6
  import { type MutationDirectoryObservation } from "./pinned-mutation-observation.js";
7
- type PolicyParent = {
8
- fd: number;
9
- guard: AsyncDirectoryGuard<BigIntStats>;
10
- observation: MutationDirectoryObservation;
11
- };
12
- export declare function capturePolicyAwareWindowsParent(binding: NativeBinding, params: PinnedWriteParams, rootAdmission: NativeRootAdmission): Promise<PolicyParent>;
13
- export {};
7
+ import type { NativePolicyParent } from "./native-policy-parent.js";
8
+ export declare function assertWindowsPolicyParentCurrent(parent: NativePolicyParent): void;
9
+ export declare function closeWindowsPolicyParentAfterFailure(closeFd: (fd: number) => void, fd: number, failure?: {
10
+ error: unknown;
11
+ }, report?: boolean): void;
12
+ export declare function windowsParentObservation(binding: NativeBinding, fd: number, guard: AsyncDirectoryGuard<BigIntStats>): MutationDirectoryObservation;
13
+ export declare function openWindowsPolicyParent(binding: NativeBinding, params: PinnedWriteParams, rootAdmission: NativeRootAdmission, fd: number, parentPath: string, relativePath: string): Promise<NativePolicyParent>;