@animalabs/agent-framework 0.22.2 → 0.23.0

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 (997) hide show
  1. package/README.md +108 -4
  2. package/dist/src/agent.d.ts +108 -17
  3. package/dist/src/agent.d.ts.map +1 -1
  4. package/dist/src/agent.js +207 -67
  5. package/dist/src/agent.js.map +1 -1
  6. package/dist/src/api/mcp-server-core.js +1 -1
  7. package/dist/src/api/mcp-server-core.js.map +1 -1
  8. package/dist/src/api/server.d.ts.map +1 -1
  9. package/dist/src/api/server.js +5 -1
  10. package/dist/src/api/server.js.map +1 -1
  11. package/dist/src/api/types.d.ts +1 -1
  12. package/dist/src/api/types.d.ts.map +1 -1
  13. package/dist/src/branch-names.d.ts +14 -0
  14. package/dist/src/branch-names.d.ts.map +1 -0
  15. package/dist/src/branch-names.js +22 -0
  16. package/dist/src/branch-names.js.map +1 -0
  17. package/dist/src/closest-names.d.ts +28 -0
  18. package/dist/src/closest-names.d.ts.map +1 -0
  19. package/dist/src/closest-names.js +98 -0
  20. package/dist/src/closest-names.js.map +1 -0
  21. package/dist/src/code-execution/index.d.ts +1 -1
  22. package/dist/src/code-execution/index.d.ts.map +1 -1
  23. package/dist/src/code-execution/index.js.map +1 -1
  24. package/dist/src/code-execution/py-runner.d.ts +50 -7
  25. package/dist/src/code-execution/py-runner.d.ts.map +1 -1
  26. package/dist/src/code-execution/py-runner.js +258 -90
  27. package/dist/src/code-execution/py-runner.js.map +1 -1
  28. package/dist/src/code-execution/runtime-py.d.ts +3 -2
  29. package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
  30. package/dist/src/code-execution/runtime-py.js +94 -8
  31. package/dist/src/code-execution/runtime-py.js.map +1 -1
  32. package/dist/src/code-execution/tool-definition.d.ts +17 -1
  33. package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
  34. package/dist/src/code-execution/tool-definition.js +72 -6
  35. package/dist/src/code-execution/tool-definition.js.map +1 -1
  36. package/dist/src/config-checks.d.ts +28 -0
  37. package/dist/src/config-checks.d.ts.map +1 -0
  38. package/dist/src/config-checks.js +56 -0
  39. package/dist/src/config-checks.js.map +1 -0
  40. package/dist/src/deadline-timer.d.ts +21 -0
  41. package/dist/src/deadline-timer.d.ts.map +1 -0
  42. package/dist/src/deadline-timer.js +43 -0
  43. package/dist/src/deadline-timer.js.map +1 -0
  44. package/dist/src/error-message.d.ts +30 -0
  45. package/dist/src/error-message.d.ts.map +1 -0
  46. package/dist/src/error-message.js +50 -0
  47. package/dist/src/error-message.js.map +1 -0
  48. package/dist/src/framework.d.ts +1529 -165
  49. package/dist/src/framework.d.ts.map +1 -1
  50. package/dist/src/framework.js +8264 -1939
  51. package/dist/src/framework.js.map +1 -1
  52. package/dist/src/gate/event-gate.d.ts +8 -0
  53. package/dist/src/gate/event-gate.d.ts.map +1 -1
  54. package/dist/src/gate/event-gate.js +36 -5
  55. package/dist/src/gate/event-gate.js.map +1 -1
  56. package/dist/src/held-writes.d.ts +16 -0
  57. package/dist/src/held-writes.d.ts.map +1 -0
  58. package/dist/src/held-writes.js +56 -0
  59. package/dist/src/held-writes.js.map +1 -0
  60. package/dist/src/index.d.ts +10 -4
  61. package/dist/src/index.d.ts.map +1 -1
  62. package/dist/src/index.js +11 -5
  63. package/dist/src/index.js.map +1 -1
  64. package/dist/src/mcpl/capability-grant.d.ts +4 -0
  65. package/dist/src/mcpl/capability-grant.d.ts.map +1 -1
  66. package/dist/src/mcpl/capability-grant.js +1 -1
  67. package/dist/src/mcpl/capability-grant.js.map +1 -1
  68. package/dist/src/mcpl/channel-registry.d.ts +233 -18
  69. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  70. package/dist/src/mcpl/channel-registry.js +975 -386
  71. package/dist/src/mcpl/channel-registry.js.map +1 -1
  72. package/dist/src/mcpl/checkpoint-manager.d.ts +21 -1
  73. package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
  74. package/dist/src/mcpl/checkpoint-manager.js +91 -30
  75. package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
  76. package/dist/src/mcpl/conversation-router.d.ts +19 -3
  77. package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
  78. package/dist/src/mcpl/conversation-router.js +23 -8
  79. package/dist/src/mcpl/conversation-router.js.map +1 -1
  80. package/dist/src/mcpl/convert-block.d.ts +20 -0
  81. package/dist/src/mcpl/convert-block.d.ts.map +1 -0
  82. package/dist/src/mcpl/convert-block.js +88 -0
  83. package/dist/src/mcpl/convert-block.js.map +1 -0
  84. package/dist/src/mcpl/errors.d.ts +13 -0
  85. package/dist/src/mcpl/errors.d.ts.map +1 -1
  86. package/dist/src/mcpl/errors.js +28 -0
  87. package/dist/src/mcpl/errors.js.map +1 -1
  88. package/dist/src/mcpl/hook-orchestrator.d.ts +23 -0
  89. package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
  90. package/dist/src/mcpl/hook-orchestrator.js +83 -72
  91. package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
  92. package/dist/src/mcpl/inbound-source.d.ts +114 -0
  93. package/dist/src/mcpl/inbound-source.d.ts.map +1 -0
  94. package/dist/src/mcpl/inbound-source.js +83 -0
  95. package/dist/src/mcpl/inbound-source.js.map +1 -0
  96. package/dist/src/mcpl/index.d.ts +7 -1
  97. package/dist/src/mcpl/index.d.ts.map +1 -1
  98. package/dist/src/mcpl/index.js +5 -1
  99. package/dist/src/mcpl/index.js.map +1 -1
  100. package/dist/src/mcpl/inference-router.d.ts +19 -13
  101. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  102. package/dist/src/mcpl/inference-router.js +155 -87
  103. package/dist/src/mcpl/inference-router.js.map +1 -1
  104. package/dist/src/mcpl/log-value.d.ts +7 -0
  105. package/dist/src/mcpl/log-value.d.ts.map +1 -1
  106. package/dist/src/mcpl/log-value.js +9 -0
  107. package/dist/src/mcpl/log-value.js.map +1 -1
  108. package/dist/src/mcpl/modern-connection.d.ts +227 -0
  109. package/dist/src/mcpl/modern-connection.d.ts.map +1 -0
  110. package/dist/src/mcpl/modern-connection.js +1088 -0
  111. package/dist/src/mcpl/modern-connection.js.map +1 -0
  112. package/dist/src/mcpl/prefix-rule.d.ts +18 -0
  113. package/dist/src/mcpl/prefix-rule.d.ts.map +1 -0
  114. package/dist/src/mcpl/prefix-rule.js +25 -0
  115. package/dist/src/mcpl/prefix-rule.js.map +1 -0
  116. package/dist/src/mcpl/protocol-family.d.ts +179 -0
  117. package/dist/src/mcpl/protocol-family.d.ts.map +1 -0
  118. package/dist/src/mcpl/protocol-family.js +697 -0
  119. package/dist/src/mcpl/protocol-family.js.map +1 -0
  120. package/dist/src/mcpl/push-coalescer.d.ts +58 -17
  121. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  122. package/dist/src/mcpl/push-coalescer.js +93 -32
  123. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  124. package/dist/src/mcpl/push-handler.d.ts +16 -9
  125. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  126. package/dist/src/mcpl/push-handler.js +18 -83
  127. package/dist/src/mcpl/push-handler.js.map +1 -1
  128. package/dist/src/mcpl/reference-fetcher.d.ts +76 -13
  129. package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
  130. package/dist/src/mcpl/reference-fetcher.js +275 -66
  131. package/dist/src/mcpl/reference-fetcher.js.map +1 -1
  132. package/dist/src/mcpl/references.d.ts +98 -18
  133. package/dist/src/mcpl/references.d.ts.map +1 -1
  134. package/dist/src/mcpl/references.js +170 -32
  135. package/dist/src/mcpl/references.js.map +1 -1
  136. package/dist/src/mcpl/server-connection.d.ts +406 -31
  137. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  138. package/dist/src/mcpl/server-connection.js +1331 -272
  139. package/dist/src/mcpl/server-connection.js.map +1 -1
  140. package/dist/src/mcpl/server-registry.d.ts +35 -6
  141. package/dist/src/mcpl/server-registry.d.ts.map +1 -1
  142. package/dist/src/mcpl/server-registry.js +63 -13
  143. package/dist/src/mcpl/server-registry.js.map +1 -1
  144. package/dist/src/mcpl/skip-reply-wake.d.ts +36 -0
  145. package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -0
  146. package/dist/src/mcpl/skip-reply-wake.js +55 -0
  147. package/dist/src/mcpl/skip-reply-wake.js.map +1 -0
  148. package/dist/src/mcpl/tool-result-normalize.d.ts +54 -0
  149. package/dist/src/mcpl/tool-result-normalize.d.ts.map +1 -0
  150. package/dist/src/mcpl/tool-result-normalize.js +232 -0
  151. package/dist/src/mcpl/tool-result-normalize.js.map +1 -0
  152. package/dist/src/mcpl/transport.d.ts +104 -12
  153. package/dist/src/mcpl/transport.d.ts.map +1 -1
  154. package/dist/src/mcpl/transport.js +315 -85
  155. package/dist/src/mcpl/transport.js.map +1 -1
  156. package/dist/src/mcpl/types.d.ts +76 -19
  157. package/dist/src/mcpl/types.d.ts.map +1 -1
  158. package/dist/src/mcpl/types.js.map +1 -1
  159. package/dist/src/mcpl/visible-content.d.ts +16 -0
  160. package/dist/src/mcpl/visible-content.d.ts.map +1 -1
  161. package/dist/src/mcpl/visible-content.js +26 -0
  162. package/dist/src/mcpl/visible-content.js.map +1 -1
  163. package/dist/src/module-registry.d.ts +34 -6
  164. package/dist/src/module-registry.d.ts.map +1 -1
  165. package/dist/src/module-registry.js +119 -31
  166. package/dist/src/module-registry.js.map +1 -1
  167. package/dist/src/modules/api/index.d.ts +1 -1
  168. package/dist/src/modules/api/index.d.ts.map +1 -1
  169. package/dist/src/modules/api/index.js +3 -2
  170. package/dist/src/modules/api/index.js.map +1 -1
  171. package/dist/src/modules/discord/discord-js-client.d.ts +43 -2
  172. package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -1
  173. package/dist/src/modules/discord/discord-js-client.js +286 -67
  174. package/dist/src/modules/discord/discord-js-client.js.map +1 -1
  175. package/dist/src/modules/discord/index.d.ts +53 -5
  176. package/dist/src/modules/discord/index.d.ts.map +1 -1
  177. package/dist/src/modules/discord/index.js +712 -186
  178. package/dist/src/modules/discord/index.js.map +1 -1
  179. package/dist/src/modules/discord/refusal.d.ts +14 -0
  180. package/dist/src/modules/discord/refusal.d.ts.map +1 -0
  181. package/dist/src/modules/discord/refusal.js +14 -0
  182. package/dist/src/modules/discord/refusal.js.map +1 -0
  183. package/dist/src/modules/discord/types.d.ts +27 -4
  184. package/dist/src/modules/discord/types.d.ts.map +1 -1
  185. package/dist/src/modules/health/index.d.ts.map +1 -1
  186. package/dist/src/modules/health/index.js +8 -3
  187. package/dist/src/modules/health/index.js.map +1 -1
  188. package/dist/src/modules/history/index.d.ts +3 -1
  189. package/dist/src/modules/history/index.d.ts.map +1 -1
  190. package/dist/src/modules/history/index.js +359 -127
  191. package/dist/src/modules/history/index.js.map +1 -1
  192. package/dist/src/modules/history/semantic.d.ts +28 -1
  193. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  194. package/dist/src/modules/history/semantic.js +177 -32
  195. package/dist/src/modules/history/semantic.js.map +1 -1
  196. package/dist/src/modules/index.d.ts +1 -1
  197. package/dist/src/modules/index.d.ts.map +1 -1
  198. package/dist/src/modules/index.js +1 -1
  199. package/dist/src/modules/index.js.map +1 -1
  200. package/dist/src/modules/unknown-tool.d.ts +10 -0
  201. package/dist/src/modules/unknown-tool.d.ts.map +1 -0
  202. package/dist/src/modules/unknown-tool.js +17 -0
  203. package/dist/src/modules/unknown-tool.js.map +1 -0
  204. package/dist/src/modules/workspace/disk-agreement.d.ts +57 -4
  205. package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
  206. package/dist/src/modules/workspace/disk-agreement.js +75 -7
  207. package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
  208. package/dist/src/modules/workspace/effects.d.ts +66 -7
  209. package/dist/src/modules/workspace/effects.d.ts.map +1 -1
  210. package/dist/src/modules/workspace/effects.js +303 -46
  211. package/dist/src/modules/workspace/effects.js.map +1 -1
  212. package/dist/src/modules/workspace/index.d.ts +313 -45
  213. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  214. package/dist/src/modules/workspace/index.js +1404 -304
  215. package/dist/src/modules/workspace/index.js.map +1 -1
  216. package/dist/src/modules/workspace/observe.d.ts +315 -16
  217. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  218. package/dist/src/modules/workspace/observe.js +727 -37
  219. package/dist/src/modules/workspace/observe.js.map +1 -1
  220. package/dist/src/modules/workspace/reconcile.d.ts +58 -7
  221. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  222. package/dist/src/modules/workspace/reconcile.js +521 -56
  223. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  224. package/dist/src/modules/workspace/types.d.ts +28 -5
  225. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  226. package/dist/src/modules/workspace/types.js.map +1 -1
  227. package/dist/src/modules/workspace/watcher.d.ts +49 -2
  228. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  229. package/dist/src/modules/workspace/watcher.js +158 -29
  230. package/dist/src/modules/workspace/watcher.js.map +1 -1
  231. package/dist/src/prose-drafts.d.ts +240 -0
  232. package/dist/src/prose-drafts.d.ts.map +1 -0
  233. package/dist/src/prose-drafts.js +362 -0
  234. package/dist/src/prose-drafts.js.map +1 -0
  235. package/dist/src/prose-segments.d.ts +21 -2
  236. package/dist/src/prose-segments.d.ts.map +1 -1
  237. package/dist/src/prose-segments.js +46 -9
  238. package/dist/src/prose-segments.js.map +1 -1
  239. package/dist/src/recovery/offline-branch.d.ts +1 -0
  240. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  241. package/dist/src/recovery/offline-branch.js +3 -1
  242. package/dist/src/recovery/offline-branch.js.map +1 -1
  243. package/dist/src/safe-slice.d.ts +5 -1
  244. package/dist/src/safe-slice.d.ts.map +1 -1
  245. package/dist/src/safe-slice.js +9 -1
  246. package/dist/src/safe-slice.js.map +1 -1
  247. package/dist/src/silent-heartbeat.d.ts +112 -39
  248. package/dist/src/silent-heartbeat.d.ts.map +1 -1
  249. package/dist/src/silent-heartbeat.js +100 -29
  250. package/dist/src/silent-heartbeat.js.map +1 -1
  251. package/dist/src/tool-args.d.ts +40 -0
  252. package/dist/src/tool-args.d.ts.map +1 -0
  253. package/dist/src/tool-args.js +207 -0
  254. package/dist/src/tool-args.js.map +1 -0
  255. package/dist/src/tool-image-ledger.d.ts +87 -19
  256. package/dist/src/tool-image-ledger.d.ts.map +1 -1
  257. package/dist/src/tool-image-ledger.js +135 -32
  258. package/dist/src/tool-image-ledger.js.map +1 -1
  259. package/dist/src/tool-presentation.d.ts +9 -0
  260. package/dist/src/tool-presentation.d.ts.map +1 -1
  261. package/dist/src/tool-presentation.js +266 -62
  262. package/dist/src/tool-presentation.js.map +1 -1
  263. package/dist/src/tool-result-guard.d.ts.map +1 -1
  264. package/dist/src/tool-result-guard.js +7 -10
  265. package/dist/src/tool-result-guard.js.map +1 -1
  266. package/dist/src/tool-result-history.d.ts +32 -3
  267. package/dist/src/tool-result-history.d.ts.map +1 -1
  268. package/dist/src/tool-result-history.js +106 -19
  269. package/dist/src/tool-result-history.js.map +1 -1
  270. package/dist/src/tune-out/coordinator.d.ts +25 -1
  271. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  272. package/dist/src/tune-out/coordinator.js +260 -65
  273. package/dist/src/tune-out/coordinator.js.map +1 -1
  274. package/dist/src/types/agent.d.ts +44 -22
  275. package/dist/src/types/agent.d.ts.map +1 -1
  276. package/dist/src/types/events.d.ts +25 -0
  277. package/dist/src/types/events.d.ts.map +1 -1
  278. package/dist/src/types/framework.d.ts +38 -7
  279. package/dist/src/types/framework.d.ts.map +1 -1
  280. package/dist/src/types/inference-log.d.ts +1 -1
  281. package/dist/src/types/inference-log.d.ts.map +1 -1
  282. package/dist/src/types/module.d.ts +77 -14
  283. package/dist/src/types/module.d.ts.map +1 -1
  284. package/dist/src/types/trace.d.ts +97 -8
  285. package/dist/src/types/trace.d.ts.map +1 -1
  286. package/dist/src/usage/usage-tracker.d.ts +5 -0
  287. package/dist/src/usage/usage-tracker.d.ts.map +1 -1
  288. package/dist/src/usage/usage-tracker.js +35 -8
  289. package/dist/src/usage/usage-tracker.js.map +1 -1
  290. package/package.json +5 -4
  291. package/src/agent.ts +257 -72
  292. package/src/api/mcp-server-core.ts +1 -1
  293. package/src/api/server.ts +4 -1
  294. package/src/api/types.ts +1 -1
  295. package/src/branch-names.ts +19 -0
  296. package/src/closest-names.ts +94 -0
  297. package/src/code-execution/index.ts +1 -0
  298. package/src/code-execution/py-runner.ts +304 -93
  299. package/src/code-execution/runtime-py.ts +94 -8
  300. package/src/code-execution/tool-definition.ts +85 -7
  301. package/src/config-checks.ts +50 -0
  302. package/src/deadline-timer.ts +44 -0
  303. package/src/error-message.ts +48 -0
  304. package/src/framework.ts +8625 -1984
  305. package/src/gate/event-gate.ts +38 -5
  306. package/src/held-writes.ts +59 -0
  307. package/src/index.ts +29 -5
  308. package/src/mcpl/capability-grant.ts +1 -1
  309. package/src/mcpl/channel-registry.ts +1095 -411
  310. package/src/mcpl/checkpoint-manager.ts +104 -29
  311. package/src/mcpl/conversation-router.ts +28 -8
  312. package/src/mcpl/convert-block.ts +105 -0
  313. package/src/mcpl/errors.ts +28 -0
  314. package/src/mcpl/hook-orchestrator.ts +84 -77
  315. package/src/mcpl/inbound-source.ts +156 -0
  316. package/src/mcpl/index.ts +23 -1
  317. package/src/mcpl/inference-router.ts +179 -103
  318. package/src/mcpl/log-value.ts +10 -0
  319. package/src/mcpl/modern-connection.ts +1182 -0
  320. package/src/mcpl/prefix-rule.ts +32 -0
  321. package/src/mcpl/protocol-family.ts +691 -0
  322. package/src/mcpl/push-coalescer.ts +110 -36
  323. package/src/mcpl/push-handler.ts +20 -90
  324. package/src/mcpl/reference-fetcher.ts +318 -67
  325. package/src/mcpl/references.ts +183 -34
  326. package/src/mcpl/server-connection.ts +1404 -280
  327. package/src/mcpl/server-registry.ts +63 -14
  328. package/src/mcpl/skip-reply-wake.ts +73 -0
  329. package/src/mcpl/tool-result-normalize.ts +294 -0
  330. package/src/mcpl/transport.ts +320 -76
  331. package/src/mcpl/types.ts +77 -19
  332. package/src/mcpl/visible-content.ts +28 -0
  333. package/src/module-registry.ts +126 -36
  334. package/src/modules/api/index.ts +3 -2
  335. package/src/modules/discord/discord-js-client.ts +306 -74
  336. package/src/modules/discord/index.ts +737 -201
  337. package/src/modules/discord/refusal.ts +13 -0
  338. package/src/modules/discord/types.ts +27 -6
  339. package/src/modules/health/index.ts +8 -3
  340. package/src/modules/history/index.ts +410 -120
  341. package/src/modules/history/semantic.ts +189 -32
  342. package/src/modules/index.ts +1 -1
  343. package/src/modules/unknown-tool.ts +16 -0
  344. package/src/modules/workspace/disk-agreement.ts +97 -8
  345. package/src/modules/workspace/effects.ts +291 -36
  346. package/src/modules/workspace/index.ts +1469 -321
  347. package/src/modules/workspace/observe.ts +784 -41
  348. package/src/modules/workspace/reconcile.ts +619 -64
  349. package/src/modules/workspace/types.ts +28 -5
  350. package/src/modules/workspace/watcher.ts +154 -30
  351. package/src/prose-drafts.ts +481 -0
  352. package/src/prose-segments.ts +51 -8
  353. package/src/recovery/offline-branch.ts +4 -1
  354. package/src/safe-slice.ts +9 -1
  355. package/src/silent-heartbeat.ts +184 -59
  356. package/src/tool-args.ts +213 -0
  357. package/src/tool-image-ledger.ts +153 -34
  358. package/src/tool-presentation.ts +233 -42
  359. package/src/tool-result-guard.ts +7 -8
  360. package/src/tool-result-history.ts +124 -20
  361. package/src/tune-out/coordinator.ts +259 -65
  362. package/src/types/agent.ts +44 -24
  363. package/src/types/events.ts +25 -0
  364. package/src/types/framework.ts +38 -7
  365. package/src/types/inference-log.ts +1 -1
  366. package/src/types/module.ts +79 -14
  367. package/src/types/trace.ts +103 -8
  368. package/src/usage/usage-tracker.ts +32 -8
  369. package/dist/test/activation-request-sanitize.test.d.ts +0 -2
  370. package/dist/test/activation-request-sanitize.test.d.ts.map +0 -1
  371. package/dist/test/activation-request-sanitize.test.js +0 -89
  372. package/dist/test/activation-request-sanitize.test.js.map +0 -1
  373. package/dist/test/agent-cache-ttl.test.d.ts +0 -2
  374. package/dist/test/agent-cache-ttl.test.d.ts.map +0 -1
  375. package/dist/test/agent-cache-ttl.test.js +0 -41
  376. package/dist/test/agent-cache-ttl.test.js.map +0 -1
  377. package/dist/test/agent-runtime-settings.test.d.ts +0 -2
  378. package/dist/test/agent-runtime-settings.test.d.ts.map +0 -1
  379. package/dist/test/agent-runtime-settings.test.js +0 -1598
  380. package/dist/test/agent-runtime-settings.test.js.map +0 -1
  381. package/dist/test/api-admin-gate.test.d.ts +0 -2
  382. package/dist/test/api-admin-gate.test.d.ts.map +0 -1
  383. package/dist/test/api-admin-gate.test.js +0 -116
  384. package/dist/test/api-admin-gate.test.js.map +0 -1
  385. package/dist/test/assistant-persist-refusal.test.d.ts +0 -2
  386. package/dist/test/assistant-persist-refusal.test.d.ts.map +0 -1
  387. package/dist/test/assistant-persist-refusal.test.js +0 -63
  388. package/dist/test/assistant-persist-refusal.test.js.map +0 -1
  389. package/dist/test/batched-wake-locus.test.d.ts +0 -2
  390. package/dist/test/batched-wake-locus.test.d.ts.map +0 -1
  391. package/dist/test/batched-wake-locus.test.js +0 -166
  392. package/dist/test/batched-wake-locus.test.js.map +0 -1
  393. package/dist/test/busy-agent-scheduler.test.d.ts +0 -2
  394. package/dist/test/busy-agent-scheduler.test.d.ts.map +0 -1
  395. package/dist/test/busy-agent-scheduler.test.js +0 -92
  396. package/dist/test/busy-agent-scheduler.test.js.map +0 -1
  397. package/dist/test/channel-incoming-targeting.test.d.ts +0 -2
  398. package/dist/test/channel-incoming-targeting.test.d.ts.map +0 -1
  399. package/dist/test/channel-incoming-targeting.test.js +0 -81
  400. package/dist/test/channel-incoming-targeting.test.js.map +0 -1
  401. package/dist/test/channel-label-history.test.d.ts +0 -2
  402. package/dist/test/channel-label-history.test.d.ts.map +0 -1
  403. package/dist/test/channel-label-history.test.js +0 -424
  404. package/dist/test/channel-label-history.test.js.map +0 -1
  405. package/dist/test/channel-lifecycle-provenance.test.d.ts +0 -2
  406. package/dist/test/channel-lifecycle-provenance.test.d.ts.map +0 -1
  407. package/dist/test/channel-lifecycle-provenance.test.js +0 -47
  408. package/dist/test/channel-lifecycle-provenance.test.js.map +0 -1
  409. package/dist/test/channel-registry-routing.test.d.ts +0 -2
  410. package/dist/test/channel-registry-routing.test.d.ts.map +0 -1
  411. package/dist/test/channel-registry-routing.test.js +0 -446
  412. package/dist/test/channel-registry-routing.test.js.map +0 -1
  413. package/dist/test/channel-registry-typing.test.d.ts +0 -2
  414. package/dist/test/channel-registry-typing.test.d.ts.map +0 -1
  415. package/dist/test/channel-registry-typing.test.js +0 -91
  416. package/dist/test/channel-registry-typing.test.js.map +0 -1
  417. package/dist/test/channels-changed-respond-first.test.d.ts +0 -2
  418. package/dist/test/channels-changed-respond-first.test.d.ts.map +0 -1
  419. package/dist/test/channels-changed-respond-first.test.js +0 -74
  420. package/dist/test/channels-changed-respond-first.test.js.map +0 -1
  421. package/dist/test/checkpoint-attribution.test.d.ts +0 -2
  422. package/dist/test/checkpoint-attribution.test.d.ts.map +0 -1
  423. package/dist/test/checkpoint-attribution.test.js +0 -200
  424. package/dist/test/checkpoint-attribution.test.js.map +0 -1
  425. package/dist/test/code-execution.test.d.ts +0 -11
  426. package/dist/test/code-execution.test.d.ts.map +0 -1
  427. package/dist/test/code-execution.test.js +0 -1272
  428. package/dist/test/code-execution.test.js.map +0 -1
  429. package/dist/test/component-defaults.test.d.ts +0 -2
  430. package/dist/test/component-defaults.test.d.ts.map +0 -1
  431. package/dist/test/component-defaults.test.js +0 -54
  432. package/dist/test/component-defaults.test.js.map +0 -1
  433. package/dist/test/conversation-fork-injection-scoping.test.d.ts +0 -2
  434. package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +0 -1
  435. package/dist/test/conversation-fork-injection-scoping.test.js +0 -200
  436. package/dist/test/conversation-fork-injection-scoping.test.js.map +0 -1
  437. package/dist/test/conversation-router.test.d.ts +0 -2
  438. package/dist/test/conversation-router.test.d.ts.map +0 -1
  439. package/dist/test/conversation-router.test.js +0 -174
  440. package/dist/test/conversation-router.test.js.map +0 -1
  441. package/dist/test/conversation-routing.test.d.ts +0 -7
  442. package/dist/test/conversation-routing.test.d.ts.map +0 -1
  443. package/dist/test/conversation-routing.test.js +0 -621
  444. package/dist/test/conversation-routing.test.js.map +0 -1
  445. package/dist/test/deferred-wake-integrity.test.d.ts +0 -29
  446. package/dist/test/deferred-wake-integrity.test.d.ts.map +0 -1
  447. package/dist/test/deferred-wake-integrity.test.js +0 -320
  448. package/dist/test/deferred-wake-integrity.test.js.map +0 -1
  449. package/dist/test/discord-awareness-outbox.test.d.ts +0 -2
  450. package/dist/test/discord-awareness-outbox.test.d.ts.map +0 -1
  451. package/dist/test/discord-awareness-outbox.test.js +0 -371
  452. package/dist/test/discord-awareness-outbox.test.js.map +0 -1
  453. package/dist/test/discord-history-delete-window.test.d.ts +0 -2
  454. package/dist/test/discord-history-delete-window.test.d.ts.map +0 -1
  455. package/dist/test/discord-history-delete-window.test.js +0 -81
  456. package/dist/test/discord-history-delete-window.test.js.map +0 -1
  457. package/dist/test/discord-history-sync.test.d.ts +0 -2
  458. package/dist/test/discord-history-sync.test.d.ts.map +0 -1
  459. package/dist/test/discord-history-sync.test.js +0 -56
  460. package/dist/test/discord-history-sync.test.js.map +0 -1
  461. package/dist/test/discord-typing-keepalive.test.d.ts +0 -2
  462. package/dist/test/discord-typing-keepalive.test.d.ts.map +0 -1
  463. package/dist/test/discord-typing-keepalive.test.js +0 -77
  464. package/dist/test/discord-typing-keepalive.test.js.map +0 -1
  465. package/dist/test/ephemeral-settle.test.d.ts +0 -2
  466. package/dist/test/ephemeral-settle.test.d.ts.map +0 -1
  467. package/dist/test/ephemeral-settle.test.js +0 -354
  468. package/dist/test/ephemeral-settle.test.js.map +0 -1
  469. package/dist/test/event-gate-passthrough.test.d.ts +0 -15
  470. package/dist/test/event-gate-passthrough.test.d.ts.map +0 -1
  471. package/dist/test/event-gate-passthrough.test.js +0 -289
  472. package/dist/test/event-gate-passthrough.test.js.map +0 -1
  473. package/dist/test/event-gate-policy-mutation.test.d.ts +0 -2
  474. package/dist/test/event-gate-policy-mutation.test.d.ts.map +0 -1
  475. package/dist/test/event-gate-policy-mutation.test.js +0 -137
  476. package/dist/test/event-gate-policy-mutation.test.js.map +0 -1
  477. package/dist/test/event-gate-rate-limit.test.d.ts +0 -2
  478. package/dist/test/event-gate-rate-limit.test.d.ts.map +0 -1
  479. package/dist/test/event-gate-rate-limit.test.js +0 -627
  480. package/dist/test/event-gate-rate-limit.test.js.map +0 -1
  481. package/dist/test/event-gate-script.test.d.ts +0 -2
  482. package/dist/test/event-gate-script.test.d.ts.map +0 -1
  483. package/dist/test/event-gate-script.test.js +0 -95
  484. package/dist/test/event-gate-script.test.js.map +0 -1
  485. package/dist/test/event-gate-selfwake.test.d.ts +0 -15
  486. package/dist/test/event-gate-selfwake.test.d.ts.map +0 -1
  487. package/dist/test/event-gate-selfwake.test.js +0 -125
  488. package/dist/test/event-gate-selfwake.test.js.map +0 -1
  489. package/dist/test/event-gate-tags.test.d.ts +0 -2
  490. package/dist/test/event-gate-tags.test.d.ts.map +0 -1
  491. package/dist/test/event-gate-tags.test.js +0 -76
  492. package/dist/test/event-gate-tags.test.js.map +0 -1
  493. package/dist/test/event-gate.test.d.ts +0 -2
  494. package/dist/test/event-gate.test.d.ts.map +0 -1
  495. package/dist/test/event-gate.test.js +0 -919
  496. package/dist/test/event-gate.test.js.map +0 -1
  497. package/dist/test/explicit-prose-routing.test.d.ts +0 -11
  498. package/dist/test/explicit-prose-routing.test.d.ts.map +0 -1
  499. package/dist/test/explicit-prose-routing.test.js +0 -1715
  500. package/dist/test/explicit-prose-routing.test.js.map +0 -1
  501. package/dist/test/framework.test.d.ts +0 -5
  502. package/dist/test/framework.test.d.ts.map +0 -1
  503. package/dist/test/framework.test.js +0 -1048
  504. package/dist/test/framework.test.js.map +0 -1
  505. package/dist/test/gather-context-timeout.test.d.ts +0 -2
  506. package/dist/test/gather-context-timeout.test.d.ts.map +0 -1
  507. package/dist/test/gather-context-timeout.test.js +0 -120
  508. package/dist/test/gather-context-timeout.test.js.map +0 -1
  509. package/dist/test/health-snapshot.test.d.ts +0 -2
  510. package/dist/test/health-snapshot.test.d.ts.map +0 -1
  511. package/dist/test/health-snapshot.test.js +0 -74
  512. package/dist/test/health-snapshot.test.js.map +0 -1
  513. package/dist/test/helpers/coalescing-fixture.d.ts +0 -74
  514. package/dist/test/helpers/coalescing-fixture.d.ts.map +0 -1
  515. package/dist/test/helpers/coalescing-fixture.js +0 -152
  516. package/dist/test/helpers/coalescing-fixture.js.map +0 -1
  517. package/dist/test/helpers/coalescing-kill-child.d.ts +0 -2
  518. package/dist/test/helpers/coalescing-kill-child.d.ts.map +0 -1
  519. package/dist/test/helpers/coalescing-kill-child.js +0 -24
  520. package/dist/test/helpers/coalescing-kill-child.js.map +0 -1
  521. package/dist/test/helpers/mock-membrane.d.ts +0 -53
  522. package/dist/test/helpers/mock-membrane.d.ts.map +0 -1
  523. package/dist/test/helpers/mock-membrane.js +0 -168
  524. package/dist/test/helpers/mock-membrane.js.map +0 -1
  525. package/dist/test/helpers/pytc-stop-rows.d.ts +0 -11
  526. package/dist/test/helpers/pytc-stop-rows.d.ts.map +0 -1
  527. package/dist/test/helpers/pytc-stop-rows.js +0 -143
  528. package/dist/test/helpers/pytc-stop-rows.js.map +0 -1
  529. package/dist/test/helpers/quiesce-crash-child.d.ts +0 -2
  530. package/dist/test/helpers/quiesce-crash-child.d.ts.map +0 -1
  531. package/dist/test/helpers/quiesce-crash-child.js +0 -156
  532. package/dist/test/helpers/quiesce-crash-child.js.map +0 -1
  533. package/dist/test/hide-then-turn.test.d.ts +0 -2
  534. package/dist/test/hide-then-turn.test.d.ts.map +0 -1
  535. package/dist/test/hide-then-turn.test.js +0 -101
  536. package/dist/test/hide-then-turn.test.js.map +0 -1
  537. package/dist/test/history-module-overview.test.d.ts +0 -2
  538. package/dist/test/history-module-overview.test.d.ts.map +0 -1
  539. package/dist/test/history-module-overview.test.js +0 -711
  540. package/dist/test/history-module-overview.test.js.map +0 -1
  541. package/dist/test/history-module-realstore.test.d.ts +0 -2
  542. package/dist/test/history-module-realstore.test.d.ts.map +0 -1
  543. package/dist/test/history-module-realstore.test.js +0 -363
  544. package/dist/test/history-module-realstore.test.js.map +0 -1
  545. package/dist/test/history-module-semantic.test.d.ts +0 -2
  546. package/dist/test/history-module-semantic.test.d.ts.map +0 -1
  547. package/dist/test/history-module-semantic.test.js +0 -213
  548. package/dist/test/history-module-semantic.test.js.map +0 -1
  549. package/dist/test/history-module-ux.test.d.ts +0 -2
  550. package/dist/test/history-module-ux.test.d.ts.map +0 -1
  551. package/dist/test/history-module-ux.test.js +0 -304
  552. package/dist/test/history-module-ux.test.js.map +0 -1
  553. package/dist/test/history-module.test.d.ts +0 -2
  554. package/dist/test/history-module.test.d.ts.map +0 -1
  555. package/dist/test/history-module.test.js +0 -619
  556. package/dist/test/history-module.test.js.map +0 -1
  557. package/dist/test/history-semantic-review-findings.test.d.ts +0 -2
  558. package/dist/test/history-semantic-review-findings.test.d.ts.map +0 -1
  559. package/dist/test/history-semantic-review-findings.test.js +0 -338
  560. package/dist/test/history-semantic-review-findings.test.js.map +0 -1
  561. package/dist/test/history-semantic-sync-converges.test.d.ts +0 -2
  562. package/dist/test/history-semantic-sync-converges.test.d.ts.map +0 -1
  563. package/dist/test/history-semantic-sync-converges.test.js +0 -109
  564. package/dist/test/history-semantic-sync-converges.test.js.map +0 -1
  565. package/dist/test/host-quiesce.test.d.ts +0 -2
  566. package/dist/test/host-quiesce.test.d.ts.map +0 -1
  567. package/dist/test/host-quiesce.test.js +0 -988
  568. package/dist/test/host-quiesce.test.js.map +0 -1
  569. package/dist/test/inference-exhaustion-rewind.test.d.ts +0 -2
  570. package/dist/test/inference-exhaustion-rewind.test.d.ts.map +0 -1
  571. package/dist/test/inference-exhaustion-rewind.test.js +0 -387
  572. package/dist/test/inference-exhaustion-rewind.test.js.map +0 -1
  573. package/dist/test/inference-failure-bounds.test.d.ts +0 -2
  574. package/dist/test/inference-failure-bounds.test.d.ts.map +0 -1
  575. package/dist/test/inference-failure-bounds.test.js +0 -1202
  576. package/dist/test/inference-failure-bounds.test.js.map +0 -1
  577. package/dist/test/inference-failure-observability.test.d.ts +0 -2
  578. package/dist/test/inference-failure-observability.test.d.ts.map +0 -1
  579. package/dist/test/inference-failure-observability.test.js +0 -84
  580. package/dist/test/inference-failure-observability.test.js.map +0 -1
  581. package/dist/test/journal-tool.test.d.ts +0 -2
  582. package/dist/test/journal-tool.test.d.ts.map +0 -1
  583. package/dist/test/journal-tool.test.js +0 -33
  584. package/dist/test/journal-tool.test.js.map +0 -1
  585. package/dist/test/kv-unified-open-flight-retry.test.d.ts +0 -2
  586. package/dist/test/kv-unified-open-flight-retry.test.d.ts.map +0 -1
  587. package/dist/test/kv-unified-open-flight-retry.test.js +0 -189
  588. package/dist/test/kv-unified-open-flight-retry.test.js.map +0 -1
  589. package/dist/test/kv-unified-wiring.test.d.ts +0 -2
  590. package/dist/test/kv-unified-wiring.test.d.ts.map +0 -1
  591. package/dist/test/kv-unified-wiring.test.js +0 -95
  592. package/dist/test/kv-unified-wiring.test.js.map +0 -1
  593. package/dist/test/late-events-after-stop.test.d.ts +0 -2
  594. package/dist/test/late-events-after-stop.test.d.ts.map +0 -1
  595. package/dist/test/late-events-after-stop.test.js +0 -122
  596. package/dist/test/late-events-after-stop.test.js.map +0 -1
  597. package/dist/test/liveness-watchdog.test.d.ts +0 -2
  598. package/dist/test/liveness-watchdog.test.d.ts.map +0 -1
  599. package/dist/test/liveness-watchdog.test.js +0 -94
  600. package/dist/test/liveness-watchdog.test.js.map +0 -1
  601. package/dist/test/machine-close-provenance.test.d.ts +0 -2
  602. package/dist/test/machine-close-provenance.test.d.ts.map +0 -1
  603. package/dist/test/machine-close-provenance.test.js +0 -116
  604. package/dist/test/machine-close-provenance.test.js.map +0 -1
  605. package/dist/test/maintenance-timer.test.d.ts +0 -2
  606. package/dist/test/maintenance-timer.test.d.ts.map +0 -1
  607. package/dist/test/maintenance-timer.test.js +0 -1827
  608. package/dist/test/maintenance-timer.test.js.map +0 -1
  609. package/dist/test/mcp-server-bin.test.d.ts +0 -2
  610. package/dist/test/mcp-server-bin.test.d.ts.map +0 -1
  611. package/dist/test/mcp-server-bin.test.js +0 -142
  612. package/dist/test/mcp-server-bin.test.js.map +0 -1
  613. package/dist/test/mcpl-access-provider.test.d.ts +0 -2
  614. package/dist/test/mcpl-access-provider.test.d.ts.map +0 -1
  615. package/dist/test/mcpl-access-provider.test.js +0 -20
  616. package/dist/test/mcpl-access-provider.test.js.map +0 -1
  617. package/dist/test/mcpl-awareness-barrier.test.d.ts +0 -2
  618. package/dist/test/mcpl-awareness-barrier.test.d.ts.map +0 -1
  619. package/dist/test/mcpl-awareness-barrier.test.js +0 -769
  620. package/dist/test/mcpl-awareness-barrier.test.js.map +0 -1
  621. package/dist/test/mcpl-capability-grant.test.d.ts +0 -10
  622. package/dist/test/mcpl-capability-grant.test.d.ts.map +0 -1
  623. package/dist/test/mcpl-capability-grant.test.js +0 -111
  624. package/dist/test/mcpl-capability-grant.test.js.map +0 -1
  625. package/dist/test/mcpl-capability-scoping.test.d.ts +0 -2
  626. package/dist/test/mcpl-capability-scoping.test.d.ts.map +0 -1
  627. package/dist/test/mcpl-capability-scoping.test.js +0 -266
  628. package/dist/test/mcpl-capability-scoping.test.js.map +0 -1
  629. package/dist/test/mcpl-child-env.test.d.ts +0 -2
  630. package/dist/test/mcpl-child-env.test.d.ts.map +0 -1
  631. package/dist/test/mcpl-child-env.test.js +0 -158
  632. package/dist/test/mcpl-child-env.test.js.map +0 -1
  633. package/dist/test/mcpl-coalesced-content-parity.test.d.ts +0 -2
  634. package/dist/test/mcpl-coalesced-content-parity.test.d.ts.map +0 -1
  635. package/dist/test/mcpl-coalesced-content-parity.test.js +0 -532
  636. package/dist/test/mcpl-coalesced-content-parity.test.js.map +0 -1
  637. package/dist/test/mcpl-coalescing.test.d.ts +0 -2
  638. package/dist/test/mcpl-coalescing.test.d.ts.map +0 -1
  639. package/dist/test/mcpl-coalescing.test.js +0 -1125
  640. package/dist/test/mcpl-coalescing.test.js.map +0 -1
  641. package/dist/test/mcpl-config-diagnostics.test.d.ts +0 -2
  642. package/dist/test/mcpl-config-diagnostics.test.d.ts.map +0 -1
  643. package/dist/test/mcpl-config-diagnostics.test.js +0 -452
  644. package/dist/test/mcpl-config-diagnostics.test.js.map +0 -1
  645. package/dist/test/mcpl-empty-content.test.d.ts +0 -2
  646. package/dist/test/mcpl-empty-content.test.d.ts.map +0 -1
  647. package/dist/test/mcpl-empty-content.test.js +0 -368
  648. package/dist/test/mcpl-empty-content.test.js.map +0 -1
  649. package/dist/test/mcpl-gate-roundtrip.test.d.ts +0 -2
  650. package/dist/test/mcpl-gate-roundtrip.test.d.ts.map +0 -1
  651. package/dist/test/mcpl-gate-roundtrip.test.js +0 -285
  652. package/dist/test/mcpl-gate-roundtrip.test.js.map +0 -1
  653. package/dist/test/mcpl-list-status.test.d.ts +0 -2
  654. package/dist/test/mcpl-list-status.test.d.ts.map +0 -1
  655. package/dist/test/mcpl-list-status.test.js +0 -82
  656. package/dist/test/mcpl-list-status.test.js.map +0 -1
  657. package/dist/test/mcpl-manifest-changed.test.d.ts +0 -2
  658. package/dist/test/mcpl-manifest-changed.test.d.ts.map +0 -1
  659. package/dist/test/mcpl-manifest-changed.test.js +0 -178
  660. package/dist/test/mcpl-manifest-changed.test.js.map +0 -1
  661. package/dist/test/mcpl-push-convert.test.d.ts +0 -2
  662. package/dist/test/mcpl-push-convert.test.d.ts.map +0 -1
  663. package/dist/test/mcpl-push-convert.test.js +0 -42
  664. package/dist/test/mcpl-push-convert.test.js.map +0 -1
  665. package/dist/test/mcpl-reconnect-events.test.d.ts +0 -2
  666. package/dist/test/mcpl-reconnect-events.test.d.ts.map +0 -1
  667. package/dist/test/mcpl-reconnect-events.test.js +0 -144
  668. package/dist/test/mcpl-reconnect-events.test.js.map +0 -1
  669. package/dist/test/mcpl-reconnect-reregistration.test.d.ts +0 -2
  670. package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +0 -1
  671. package/dist/test/mcpl-reconnect-reregistration.test.js +0 -238
  672. package/dist/test/mcpl-reconnect-reregistration.test.js.map +0 -1
  673. package/dist/test/mcpl-reference-fetcher.test.d.ts +0 -2
  674. package/dist/test/mcpl-reference-fetcher.test.d.ts.map +0 -1
  675. package/dist/test/mcpl-reference-fetcher.test.js +0 -427
  676. package/dist/test/mcpl-reference-fetcher.test.js.map +0 -1
  677. package/dist/test/mcpl-reference-fields.test.d.ts +0 -2
  678. package/dist/test/mcpl-reference-fields.test.d.ts.map +0 -1
  679. package/dist/test/mcpl-reference-fields.test.js +0 -149
  680. package/dist/test/mcpl-reference-fields.test.js.map +0 -1
  681. package/dist/test/mcpl-rejection-log-lines.test.d.ts +0 -2
  682. package/dist/test/mcpl-rejection-log-lines.test.d.ts.map +0 -1
  683. package/dist/test/mcpl-rejection-log-lines.test.js +0 -349
  684. package/dist/test/mcpl-rejection-log-lines.test.js.map +0 -1
  685. package/dist/test/mcpl-request-timeout.test.d.ts +0 -2
  686. package/dist/test/mcpl-request-timeout.test.d.ts.map +0 -1
  687. package/dist/test/mcpl-request-timeout.test.js +0 -138
  688. package/dist/test/mcpl-request-timeout.test.js.map +0 -1
  689. package/dist/test/mcpl-runtime-lifecycle.test.d.ts +0 -7
  690. package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +0 -1
  691. package/dist/test/mcpl-runtime-lifecycle.test.js +0 -142
  692. package/dist/test/mcpl-runtime-lifecycle.test.js.map +0 -1
  693. package/dist/test/mcpl-stderr-tail.test.d.ts +0 -2
  694. package/dist/test/mcpl-stderr-tail.test.d.ts.map +0 -1
  695. package/dist/test/mcpl-stderr-tail.test.js +0 -210
  696. package/dist/test/mcpl-stderr-tail.test.js.map +0 -1
  697. package/dist/test/mcpl-tool-class-listing.test.d.ts +0 -2
  698. package/dist/test/mcpl-tool-class-listing.test.d.ts.map +0 -1
  699. package/dist/test/mcpl-tool-class-listing.test.js +0 -147
  700. package/dist/test/mcpl-tool-class-listing.test.js.map +0 -1
  701. package/dist/test/mcpl-tool-classes.test.d.ts +0 -7
  702. package/dist/test/mcpl-tool-classes.test.d.ts.map +0 -1
  703. package/dist/test/mcpl-tool-classes.test.js +0 -80
  704. package/dist/test/mcpl-tool-classes.test.js.map +0 -1
  705. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts +0 -2
  706. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts.map +0 -1
  707. package/dist/test/mcpl-tool-lifecycle-e2e.test.js +0 -237
  708. package/dist/test/mcpl-tool-lifecycle-e2e.test.js.map +0 -1
  709. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts +0 -11
  710. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts.map +0 -1
  711. package/dist/test/mcpl-tool-lifecycle-emitter.test.js +0 -412
  712. package/dist/test/mcpl-tool-lifecycle-emitter.test.js.map +0 -1
  713. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts +0 -2
  714. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts.map +0 -1
  715. package/dist/test/mcpl-tool-lifecycle-script.test.js +0 -288
  716. package/dist/test/mcpl-tool-lifecycle-script.test.js.map +0 -1
  717. package/dist/test/mcpl-tool-lifecycle.test.d.ts +0 -11
  718. package/dist/test/mcpl-tool-lifecycle.test.d.ts.map +0 -1
  719. package/dist/test/mcpl-tool-lifecycle.test.js +0 -270
  720. package/dist/test/mcpl-tool-lifecycle.test.js.map +0 -1
  721. package/dist/test/mcpl-transport-close.test.d.ts +0 -2
  722. package/dist/test/mcpl-transport-close.test.d.ts.map +0 -1
  723. package/dist/test/mcpl-transport-close.test.js +0 -373
  724. package/dist/test/mcpl-transport-close.test.js.map +0 -1
  725. package/dist/test/mcpl-transport-spawn.test.d.ts +0 -2
  726. package/dist/test/mcpl-transport-spawn.test.d.ts.map +0 -1
  727. package/dist/test/mcpl-transport-spawn.test.js +0 -58
  728. package/dist/test/mcpl-transport-spawn.test.js.map +0 -1
  729. package/dist/test/mcpl-ws-transport.test.d.ts +0 -2
  730. package/dist/test/mcpl-ws-transport.test.d.ts.map +0 -1
  731. package/dist/test/mcpl-ws-transport.test.js +0 -259
  732. package/dist/test/mcpl-ws-transport.test.js.map +0 -1
  733. package/dist/test/module-context-integration.test.d.ts +0 -18
  734. package/dist/test/module-context-integration.test.d.ts.map +0 -1
  735. package/dist/test/module-context-integration.test.js +0 -181
  736. package/dist/test/module-context-integration.test.js.map +0 -1
  737. package/dist/test/offline-recovery-branch.test.d.ts +0 -2
  738. package/dist/test/offline-recovery-branch.test.d.ts.map +0 -1
  739. package/dist/test/offline-recovery-branch.test.js +0 -570
  740. package/dist/test/offline-recovery-branch.test.js.map +0 -1
  741. package/dist/test/operator-surgery.test.d.ts +0 -2
  742. package/dist/test/operator-surgery.test.d.ts.map +0 -1
  743. package/dist/test/operator-surgery.test.js +0 -595
  744. package/dist/test/operator-surgery.test.js.map +0 -1
  745. package/dist/test/ops-alert.test.d.ts +0 -2
  746. package/dist/test/ops-alert.test.d.ts.map +0 -1
  747. package/dist/test/ops-alert.test.js +0 -153
  748. package/dist/test/ops-alert.test.js.map +0 -1
  749. package/dist/test/overbudget-drain-breaker.test.d.ts +0 -2
  750. package/dist/test/overbudget-drain-breaker.test.d.ts.map +0 -1
  751. package/dist/test/overbudget-drain-breaker.test.js +0 -198
  752. package/dist/test/overbudget-drain-breaker.test.js.map +0 -1
  753. package/dist/test/pack-installs-alone.test.d.ts +0 -2
  754. package/dist/test/pack-installs-alone.test.d.ts.map +0 -1
  755. package/dist/test/pack-installs-alone.test.js +0 -284
  756. package/dist/test/pack-installs-alone.test.js.map +0 -1
  757. package/dist/test/per-agent-delivery.test.d.ts +0 -2
  758. package/dist/test/per-agent-delivery.test.d.ts.map +0 -1
  759. package/dist/test/per-agent-delivery.test.js +0 -108
  760. package/dist/test/per-agent-delivery.test.js.map +0 -1
  761. package/dist/test/physical-window-restart.test.d.ts +0 -16
  762. package/dist/test/physical-window-restart.test.d.ts.map +0 -1
  763. package/dist/test/physical-window-restart.test.js +0 -487
  764. package/dist/test/physical-window-restart.test.js.map +0 -1
  765. package/dist/test/placed-reaction-baseline.test.d.ts +0 -2
  766. package/dist/test/placed-reaction-baseline.test.d.ts.map +0 -1
  767. package/dist/test/placed-reaction-baseline.test.js +0 -312
  768. package/dist/test/placed-reaction-baseline.test.js.map +0 -1
  769. package/dist/test/present-while-acting.test.d.ts +0 -19
  770. package/dist/test/present-while-acting.test.d.ts.map +0 -1
  771. package/dist/test/present-while-acting.test.js +0 -1649
  772. package/dist/test/present-while-acting.test.js.map +0 -1
  773. package/dist/test/prose-segments.test.d.ts +0 -2
  774. package/dist/test/prose-segments.test.d.ts.map +0 -1
  775. package/dist/test/prose-segments.test.js +0 -52
  776. package/dist/test/prose-segments.test.js.map +0 -1
  777. package/dist/test/prose-stream-router.test.d.ts +0 -2
  778. package/dist/test/prose-stream-router.test.d.ts.map +0 -1
  779. package/dist/test/prose-stream-router.test.js +0 -171
  780. package/dist/test/prose-stream-router.test.js.map +0 -1
  781. package/dist/test/provider-acceleration-cooldown.test.d.ts +0 -2
  782. package/dist/test/provider-acceleration-cooldown.test.d.ts.map +0 -1
  783. package/dist/test/provider-acceleration-cooldown.test.js +0 -435
  784. package/dist/test/provider-acceleration-cooldown.test.js.map +0 -1
  785. package/dist/test/provider-waits.test.d.ts +0 -2
  786. package/dist/test/provider-waits.test.d.ts.map +0 -1
  787. package/dist/test/provider-waits.test.js +0 -2259
  788. package/dist/test/provider-waits.test.js.map +0 -1
  789. package/dist/test/puppet-tool-call.test.d.ts +0 -2
  790. package/dist/test/puppet-tool-call.test.d.ts.map +0 -1
  791. package/dist/test/puppet-tool-call.test.js +0 -226
  792. package/dist/test/puppet-tool-call.test.js.map +0 -1
  793. package/dist/test/puppet-turn-reservation.test.d.ts +0 -2
  794. package/dist/test/puppet-turn-reservation.test.d.ts.map +0 -1
  795. package/dist/test/puppet-turn-reservation.test.js +0 -139
  796. package/dist/test/puppet-turn-reservation.test.js.map +0 -1
  797. package/dist/test/reaction-baseline-platform.test.d.ts +0 -2
  798. package/dist/test/reaction-baseline-platform.test.d.ts.map +0 -1
  799. package/dist/test/reaction-baseline-platform.test.js +0 -124
  800. package/dist/test/reaction-baseline-platform.test.js.map +0 -1
  801. package/dist/test/record-journal.test.d.ts +0 -6
  802. package/dist/test/record-journal.test.d.ts.map +0 -1
  803. package/dist/test/record-journal.test.js +0 -269
  804. package/dist/test/record-journal.test.js.map +0 -1
  805. package/dist/test/refusal-reaction-baseline.test.d.ts +0 -2
  806. package/dist/test/refusal-reaction-baseline.test.d.ts.map +0 -1
  807. package/dist/test/refusal-reaction-baseline.test.js +0 -81
  808. package/dist/test/refusal-reaction-baseline.test.js.map +0 -1
  809. package/dist/test/refusal-rewind.test.d.ts +0 -2
  810. package/dist/test/refusal-rewind.test.d.ts.map +0 -1
  811. package/dist/test/refusal-rewind.test.js +0 -117
  812. package/dist/test/refusal-rewind.test.js.map +0 -1
  813. package/dist/test/refusal-single-call.test.d.ts +0 -2
  814. package/dist/test/refusal-single-call.test.d.ts.map +0 -1
  815. package/dist/test/refusal-single-call.test.js +0 -177
  816. package/dist/test/refusal-single-call.test.js.map +0 -1
  817. package/dist/test/release-bump.test.d.ts +0 -2
  818. package/dist/test/release-bump.test.d.ts.map +0 -1
  819. package/dist/test/release-bump.test.js +0 -248
  820. package/dist/test/release-bump.test.js.map +0 -1
  821. package/dist/test/release-changelog.test.d.ts +0 -2
  822. package/dist/test/release-changelog.test.d.ts.map +0 -1
  823. package/dist/test/release-changelog.test.js +0 -159
  824. package/dist/test/release-changelog.test.js.map +0 -1
  825. package/dist/test/release-holds.test.d.ts +0 -2
  826. package/dist/test/release-holds.test.d.ts.map +0 -1
  827. package/dist/test/release-holds.test.js +0 -456
  828. package/dist/test/release-holds.test.js.map +0 -1
  829. package/dist/test/same-round-think-policy.test.d.ts +0 -2
  830. package/dist/test/same-round-think-policy.test.d.ts.map +0 -1
  831. package/dist/test/same-round-think-policy.test.js +0 -853
  832. package/dist/test/same-round-think-policy.test.js.map +0 -1
  833. package/dist/test/save-recent-image.test.d.ts +0 -26
  834. package/dist/test/save-recent-image.test.d.ts.map +0 -1
  835. package/dist/test/save-recent-image.test.js +0 -974
  836. package/dist/test/save-recent-image.test.js.map +0 -1
  837. package/dist/test/shutdown-errors.test.d.ts +0 -2
  838. package/dist/test/shutdown-errors.test.d.ts.map +0 -1
  839. package/dist/test/shutdown-errors.test.js +0 -662
  840. package/dist/test/shutdown-errors.test.js.map +0 -1
  841. package/dist/test/silent-heartbeat-rows.test.d.ts +0 -2
  842. package/dist/test/silent-heartbeat-rows.test.d.ts.map +0 -1
  843. package/dist/test/silent-heartbeat-rows.test.js +0 -451
  844. package/dist/test/silent-heartbeat-rows.test.js.map +0 -1
  845. package/dist/test/silent-heartbeat.test.d.ts +0 -2
  846. package/dist/test/silent-heartbeat.test.d.ts.map +0 -1
  847. package/dist/test/silent-heartbeat.test.js +0 -165
  848. package/dist/test/silent-heartbeat.test.js.map +0 -1
  849. package/dist/test/state-scaling-e2e.test.d.ts +0 -22
  850. package/dist/test/state-scaling-e2e.test.d.ts.map +0 -1
  851. package/dist/test/state-scaling-e2e.test.js +0 -206
  852. package/dist/test/state-scaling-e2e.test.js.map +0 -1
  853. package/dist/test/state-scaling.test.d.ts +0 -12
  854. package/dist/test/state-scaling.test.d.ts.map +0 -1
  855. package/dist/test/state-scaling.test.js +0 -251
  856. package/dist/test/state-scaling.test.js.map +0 -1
  857. package/dist/test/stop-with-host-operations.test.d.ts +0 -20
  858. package/dist/test/stop-with-host-operations.test.d.ts.map +0 -1
  859. package/dist/test/stop-with-host-operations.test.js +0 -1174
  860. package/dist/test/stop-with-host-operations.test.js.map +0 -1
  861. package/dist/test/stop-with-work-in-flight.test.d.ts +0 -23
  862. package/dist/test/stop-with-work-in-flight.test.d.ts.map +0 -1
  863. package/dist/test/stop-with-work-in-flight.test.js +0 -784
  864. package/dist/test/stop-with-work-in-flight.test.js.map +0 -1
  865. package/dist/test/surgery-marks-receipt.test.d.ts +0 -2
  866. package/dist/test/surgery-marks-receipt.test.d.ts.map +0 -1
  867. package/dist/test/surgery-marks-receipt.test.js +0 -540
  868. package/dist/test/surgery-marks-receipt.test.js.map +0 -1
  869. package/dist/test/thinking-token-stamp.test.d.ts +0 -12
  870. package/dist/test/thinking-token-stamp.test.d.ts.map +0 -1
  871. package/dist/test/thinking-token-stamp.test.js +0 -129
  872. package/dist/test/thinking-token-stamp.test.js.map +0 -1
  873. package/dist/test/timezone.test.d.ts +0 -2
  874. package/dist/test/timezone.test.d.ts.map +0 -1
  875. package/dist/test/timezone.test.js +0 -18
  876. package/dist/test/timezone.test.js.map +0 -1
  877. package/dist/test/tool-batch-hook.test.d.ts +0 -8
  878. package/dist/test/tool-batch-hook.test.d.ts.map +0 -1
  879. package/dist/test/tool-batch-hook.test.js +0 -275
  880. package/dist/test/tool-batch-hook.test.js.map +0 -1
  881. package/dist/test/tool-policy.test.d.ts +0 -2
  882. package/dist/test/tool-policy.test.d.ts.map +0 -1
  883. package/dist/test/tool-policy.test.js +0 -51
  884. package/dist/test/tool-policy.test.js.map +0 -1
  885. package/dist/test/tool-presentation.test.d.ts +0 -2
  886. package/dist/test/tool-presentation.test.d.ts.map +0 -1
  887. package/dist/test/tool-presentation.test.js +0 -268
  888. package/dist/test/tool-presentation.test.js.map +0 -1
  889. package/dist/test/tool-result-content.test.d.ts +0 -2
  890. package/dist/test/tool-result-content.test.d.ts.map +0 -1
  891. package/dist/test/tool-result-content.test.js +0 -37
  892. package/dist/test/tool-result-content.test.js.map +0 -1
  893. package/dist/test/tool-result-guard.test.d.ts +0 -2
  894. package/dist/test/tool-result-guard.test.d.ts.map +0 -1
  895. package/dist/test/tool-result-guard.test.js +0 -3729
  896. package/dist/test/tool-result-guard.test.js.map +0 -1
  897. package/dist/test/tool-result-history.test.d.ts +0 -7
  898. package/dist/test/tool-result-history.test.d.ts.map +0 -1
  899. package/dist/test/tool-result-history.test.js +0 -156
  900. package/dist/test/tool-result-history.test.js.map +0 -1
  901. package/dist/test/tool-result-spill.test.d.ts +0 -13
  902. package/dist/test/tool-result-spill.test.d.ts.map +0 -1
  903. package/dist/test/tool-result-spill.test.js +0 -586
  904. package/dist/test/tool-result-spill.test.js.map +0 -1
  905. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts +0 -2
  906. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts.map +0 -1
  907. package/dist/test/tool-wrapper-prose-guard-integration.test.js +0 -485
  908. package/dist/test/tool-wrapper-prose-guard-integration.test.js.map +0 -1
  909. package/dist/test/tool-wrapper-prose-guard.test.d.ts +0 -2
  910. package/dist/test/tool-wrapper-prose-guard.test.d.ts.map +0 -1
  911. package/dist/test/tool-wrapper-prose-guard.test.js +0 -34
  912. package/dist/test/tool-wrapper-prose-guard.test.js.map +0 -1
  913. package/dist/test/tools-observe-parser-conformance.test.d.ts +0 -2
  914. package/dist/test/tools-observe-parser-conformance.test.d.ts.map +0 -1
  915. package/dist/test/tools-observe-parser-conformance.test.js +0 -129
  916. package/dist/test/tools-observe-parser-conformance.test.js.map +0 -1
  917. package/dist/test/trunk-channel-routing.test.d.ts +0 -19
  918. package/dist/test/trunk-channel-routing.test.d.ts.map +0 -1
  919. package/dist/test/trunk-channel-routing.test.js +0 -652
  920. package/dist/test/trunk-channel-routing.test.js.map +0 -1
  921. package/dist/test/tune-out-e2e.test.d.ts +0 -2
  922. package/dist/test/tune-out-e2e.test.d.ts.map +0 -1
  923. package/dist/test/tune-out-e2e.test.js +0 -142
  924. package/dist/test/tune-out-e2e.test.js.map +0 -1
  925. package/dist/test/tune-out-gate-composition.test.d.ts +0 -2
  926. package/dist/test/tune-out-gate-composition.test.d.ts.map +0 -1
  927. package/dist/test/tune-out-gate-composition.test.js +0 -221
  928. package/dist/test/tune-out-gate-composition.test.js.map +0 -1
  929. package/dist/test/tune-out-lifecycle.test.d.ts +0 -2
  930. package/dist/test/tune-out-lifecycle.test.d.ts.map +0 -1
  931. package/dist/test/tune-out-lifecycle.test.js +0 -121
  932. package/dist/test/tune-out-lifecycle.test.js.map +0 -1
  933. package/dist/test/turn-trigger-provenance.test.d.ts +0 -2
  934. package/dist/test/turn-trigger-provenance.test.d.ts.map +0 -1
  935. package/dist/test/turn-trigger-provenance.test.js +0 -137
  936. package/dist/test/turn-trigger-provenance.test.js.map +0 -1
  937. package/dist/test/unconvertible-tool-result.test.d.ts +0 -2
  938. package/dist/test/unconvertible-tool-result.test.d.ts.map +0 -1
  939. package/dist/test/unconvertible-tool-result.test.js +0 -358
  940. package/dist/test/unconvertible-tool-result.test.js.map +0 -1
  941. package/dist/test/unsent-compiles.test.d.ts +0 -2
  942. package/dist/test/unsent-compiles.test.d.ts.map +0 -1
  943. package/dist/test/unsent-compiles.test.js +0 -139
  944. package/dist/test/unsent-compiles.test.js.map +0 -1
  945. package/dist/test/usage-accounting.test.d.ts +0 -2
  946. package/dist/test/usage-accounting.test.d.ts.map +0 -1
  947. package/dist/test/usage-accounting.test.js +0 -13
  948. package/dist/test/usage-accounting.test.js.map +0 -1
  949. package/dist/test/usage-tracker.test.d.ts +0 -2
  950. package/dist/test/usage-tracker.test.d.ts.map +0 -1
  951. package/dist/test/usage-tracker.test.js +0 -129
  952. package/dist/test/usage-tracker.test.js.map +0 -1
  953. package/dist/test/utils-surface.test.d.ts +0 -2
  954. package/dist/test/utils-surface.test.d.ts.map +0 -1
  955. package/dist/test/utils-surface.test.js +0 -145
  956. package/dist/test/utils-surface.test.js.map +0 -1
  957. package/dist/test/workspace-branch-continuation.test.d.ts +0 -15
  958. package/dist/test/workspace-branch-continuation.test.d.ts.map +0 -1
  959. package/dist/test/workspace-branch-continuation.test.js +0 -183
  960. package/dist/test/workspace-branch-continuation.test.js.map +0 -1
  961. package/dist/test/workspace-materialize-freshness.test.d.ts +0 -16
  962. package/dist/test/workspace-materialize-freshness.test.d.ts.map +0 -1
  963. package/dist/test/workspace-materialize-freshness.test.js +0 -252
  964. package/dist/test/workspace-materialize-freshness.test.js.map +0 -1
  965. package/dist/test/workspace-path-containment.test.d.ts +0 -19
  966. package/dist/test/workspace-path-containment.test.d.ts.map +0 -1
  967. package/dist/test/workspace-path-containment.test.js +0 -91
  968. package/dist/test/workspace-path-containment.test.js.map +0 -1
  969. package/dist/test/workspace-read-file-from-disk.test.d.ts +0 -17
  970. package/dist/test/workspace-read-file-from-disk.test.d.ts.map +0 -1
  971. package/dist/test/workspace-read-file-from-disk.test.js +0 -174
  972. package/dist/test/workspace-read-file-from-disk.test.js.map +0 -1
  973. package/dist/test/workspace-read-image.test.d.ts +0 -2
  974. package/dist/test/workspace-read-image.test.d.ts.map +0 -1
  975. package/dist/test/workspace-read-image.test.js +0 -597
  976. package/dist/test/workspace-read-image.test.js.map +0 -1
  977. package/dist/test/workspace-read-text.test.d.ts +0 -2
  978. package/dist/test/workspace-read-text.test.d.ts.map +0 -1
  979. package/dist/test/workspace-read-text.test.js +0 -101
  980. package/dist/test/workspace-read-text.test.js.map +0 -1
  981. package/dist/test/workspace-restore-order.test.d.ts +0 -16
  982. package/dist/test/workspace-restore-order.test.d.ts.map +0 -1
  983. package/dist/test/workspace-restore-order.test.js +0 -140
  984. package/dist/test/workspace-restore-order.test.js.map +0 -1
  985. package/dist/test/workspace-three-way.test.d.ts +0 -12
  986. package/dist/test/workspace-three-way.test.d.ts.map +0 -1
  987. package/dist/test/workspace-three-way.test.js +0 -4094
  988. package/dist/test/workspace-three-way.test.js.map +0 -1
  989. package/dist/test/workspace-watcher.test.d.ts +0 -2
  990. package/dist/test/workspace-watcher.test.d.ts.map +0 -1
  991. package/dist/test/workspace-watcher.test.js +0 -281
  992. package/dist/test/workspace-watcher.test.js.map +0 -1
  993. package/dist/test/xml-round-persist.test.d.ts +0 -19
  994. package/dist/test/xml-round-persist.test.d.ts.map +0 -1
  995. package/dist/test/xml-round-persist.test.js +0 -235
  996. package/dist/test/xml-round-persist.test.js.map +0 -1
  997. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -37,14 +37,16 @@
37
37
  */
38
38
  import { createHash } from 'node:crypto';
39
39
  import { constants as fsConstants } from 'node:fs';
40
- import { lstat, mkdir, open, readdir, realpath, stat, statfs } from 'node:fs/promises';
41
- import { dirname, join, sep } from 'node:path';
40
+ import { lstat, mkdir, open, readdir, readlink, realpath, stat, statfs } from 'node:fs/promises';
41
+ import { basename, dirname, isAbsolute, join, posix, relative, resolve, sep } from 'node:path';
42
42
  import { sameRootIdentity } from './disk-agreement.js';
43
43
  /**
44
- * Opened with every read or write of a workspace path, where the platform has
45
- * it: for a regular file it changes nothing, and a FIFO or other special file
46
- * swapped in at the path neither blocks the open nor passes the regular-file
47
- * check that follows.
44
+ * Opened with every open of a workspace path that may already be there, a
45
+ * read, a write in place or a directory's sync, where the platform has it:
46
+ * for a regular file or a directory it changes nothing, and a FIFO or other
47
+ * special file swapped in at the path neither blocks the open nor passes the
48
+ * check of its kind that follows. A create needs none: O_CREAT | O_EXCL fails
49
+ * at once on anything already at the path.
48
50
  */
49
51
  export const NONBLOCK = typeof fsConstants.O_NONBLOCK === 'number' ? fsConstants.O_NONBLOCK : 0;
50
52
  /** Bytes hashed per read when streaming a file larger than the read limit. */
@@ -79,6 +81,467 @@ export function nameOf(relativePath) {
79
81
  function lexicalOf(view, rel) {
80
82
  return rel === '' ? view.root : join(view.root, rel);
81
83
  }
84
+ const UNSURE_PREFIX = 'cannot tell whether "';
85
+ /**
86
+ * On a mount that doesn't follow symlinks, what is on the way to a
87
+ * mount-relative path: the first directory, from beneath the mount's root
88
+ * down to the path itself (or, `through` 'parents', down to its parent), that
89
+ * is a symlink, or one the walk couldn't ask. Null when there is none, or
90
+ * when the mount follows symlinks. The path is
91
+ * walked as the lookups that follow resolve it, with `.` and `..` taken out,
92
+ * so a `..` after a name that isn't there hides nothing beyond it, and the
93
+ * root, which is the configured path whatever it resolves to, is never on the
94
+ * way, even where the path names it on its way back into the mount. Each
95
+ * directory is asked only whether it is a link, by readlink, from the root
96
+ * down. EINVAL means it isn't, and the walk goes on. Nothing there, a file in
97
+ * the way, or a directory this user can't search (ENOENT, ENOTDIR, EACCES)
98
+ * ends it with nothing found, since nothing beneath is reached through a link
99
+ * and the caller's own lookup meets the same answer. Any other answer, EPERM
100
+ * included, leaves it unsure of what's beneath, and the path is refused for
101
+ * that.
102
+ */
103
+ export async function linkOnTheWay(view, rel, through = 'path') {
104
+ if (view.followSymlinks)
105
+ return null;
106
+ const resolved = relative(resolve(view.root), resolve(view.root, rel));
107
+ if (resolved === '' || resolved === '..' || resolved.startsWith(`..${sep}`) || isAbsolute(resolved))
108
+ return null;
109
+ const parts = resolved.split(sep);
110
+ const last = through === 'path' ? parts.length : parts.length - 1;
111
+ for (let i = 1; i <= last; i++) {
112
+ const at = parts.slice(0, i).join('/');
113
+ try {
114
+ await readlink(join(view.root, at));
115
+ return { link: at };
116
+ }
117
+ catch (err) {
118
+ const code = errno(err);
119
+ if (code === 'EINVAL')
120
+ continue; // not a link: on to the next directory
121
+ if (code === 'ENOENT' || code === 'ENOTDIR' || code === 'EACCES')
122
+ return null;
123
+ return { unsure: at, code: code ?? String(err) };
124
+ }
125
+ }
126
+ return null;
127
+ }
128
+ /**
129
+ * On a mount that doesn't follow symlinks, what refuses the mount-relative
130
+ * `rel`, which realpath resolved to `real` (or, `through` 'parents', whose
131
+ * parent it resolved to `real`): the first symlink on its way, or a
132
+ * directory there the walk couldn't ask. Null when the mount follows
133
+ * symlinks, or there's none. Where `real` is the root's canonical path joined
134
+ * with what was resolved (`rel`, or with `through` 'parents', its parent),
135
+ * nothing beneath the root resolved through a link, and nothing more is
136
+ * asked: that is every path through ordinary directories, at no cost
137
+ * per path. Otherwise each directory is asked in turn (linkOnTheWay), since a
138
+ * name spelled otherwise than disk spells it, on a file system that ignores
139
+ * case or Unicode normalization, also resolves to another string, and isn't
140
+ * a link.
141
+ */
142
+ export async function linkRefusal(view, rootReal, rel, real, through = 'path') {
143
+ if (view.followSymlinks)
144
+ return null;
145
+ const resolvedAt = through === 'path' ? rel : parentOf(rel);
146
+ if (resolvedAt === '' || real === join(rootReal, resolvedAt))
147
+ return null;
148
+ return linkOnTheWay(view, rel, through);
149
+ }
150
+ export async function linkLeads(root, rootReal, link) {
151
+ const leads = await realpath(join(root, link)).catch(() => null);
152
+ if (leads === null)
153
+ return { kind: 'nowhere' };
154
+ if (!contained(rootReal, leads))
155
+ return { kind: 'outside' };
156
+ const directory = await stat(leads).then((info) => info.isDirectory(), () => false);
157
+ return { kind: 'inside', target: relative(rootReal, leads).split(sep).join('/'), directory };
158
+ }
159
+ /**
160
+ * The nested mount whose directory holds `target` (mount-relative), the
161
+ * innermost where nested mounts nest, as #460 picks one; undefined when none
162
+ * does.
163
+ */
164
+ export function nestedHolder(target, nested) {
165
+ return nested
166
+ .filter((n) => target === n.dir || target.startsWith(`${n.dir}/`))
167
+ .sort((a, b) => b.dir.length - a.dir.length)[0];
168
+ }
169
+ /**
170
+ * Why a path is refused for what linkOnTheWay found, given where a link
171
+ * leads (linkLeads). For a link, the link is the subject, with where it
172
+ * leads: for a link inside the mount, its target, and for a link to a
173
+ * directory there, the setting the mount's host can change (the link stands
174
+ * among the path's directories, so following a link to a file can't make the
175
+ * path beneath it exist); for one leading outside the mount, that it does;
176
+ * for one that can't be resolved, nothing more. A target in a nested mount's
177
+ * directory (`nested`) is that mount's: the refusal names the mount and the
178
+ * path to use there in place of the link, and offers no setting, since
179
+ * following the link would only reach into another mount's directory. For a
180
+ * directory the walk couldn't ask, which one, and the answer it got. Paths
181
+ * are spelled as the tools take them, from the mount's name.
182
+ */
183
+ export function linkWords(name, found, leads, nested = []) {
184
+ const spell = (rel) => `"${rel === '' ? name : `${name}/${rel}`}"`;
185
+ if (!('link' in found))
186
+ return `${UNSURE_PREFIX}${name}/${found.unsure}" is a symlink (${found.code})`;
187
+ const link = `${spell(found.link)} is a symlink`;
188
+ if (leads === null || leads.kind === 'nowhere')
189
+ return `${link}, which this mount does not follow`;
190
+ if (leads.kind === 'outside')
191
+ return `${link} leading outside the mount, which this mount does not follow`;
192
+ const holder = nestedHolder(leads.target, nested);
193
+ if (holder) {
194
+ const rest = leads.target.slice(holder.dir.length + 1);
195
+ return `${link} to ${spell(leads.target)}, which this mount does not follow; it lies in mount "${holder.name}", ` +
196
+ `nested in mount "${name}": use "${rest ? `${holder.name}/${rest}` : holder.name}" in place of ${spell(found.link)}`;
197
+ }
198
+ const setting = leads.directory ? "; the mount's host can set followSymlinks: true" : '';
199
+ return `${link} to ${spell(leads.target)}, which this mount does not follow${setting}`;
200
+ }
201
+ /** Why a path is refused for what linkOnTheWay found (linkWords, with where the link leads). */
202
+ export async function linkReason(view, rootReal, found) {
203
+ return linkWords(view.name, found, 'link' in found ? await linkLeads(view.root, rootReal, found.link) : null, view.nested);
204
+ }
205
+ /**
206
+ * The nested mount whose root holds `real`, a canonical path, the innermost,
207
+ * with the path to use there; undefined when none does. A path the lexical
208
+ * checks pass (inOtherMount, the tools' holderOf) reaches another mount's
209
+ * directory this way through a symlink the mount follows, so each check that
210
+ * resolves a path canonically asks this too.
211
+ */
212
+ export function nestedAtReal(real, nested = []) {
213
+ const holder = nested
214
+ .flatMap((n) => (n.real !== undefined && contained(n.real, real) ? [{ name: n.name, real: n.real }] : []))
215
+ .sort((a, b) => b.real.length - a.real.length)[0];
216
+ if (!holder)
217
+ return undefined;
218
+ const rest = relative(holder.real, real).split(sep).join('/');
219
+ return { name: holder.name, use: rest ? `${holder.name}/${rest}` : holder.name };
220
+ }
221
+ /**
222
+ * Why a mount-relative path that resolves into a nested mount's directory is
223
+ * refused (nestedAtReal): what it leads into, and the path to use in its
224
+ * place. Spelled as the tools take paths, from the mount's name.
225
+ */
226
+ export function leadsInto(name, rel, holder) {
227
+ return `"${rel === '' ? name : `${name}/${rel}`}" leads into mount "${holder.name}", nested in mount "${name}": use "${holder.use}" in its place`;
228
+ }
229
+ // ===========================================================================
230
+ // Disk's spelling of a path
231
+ // ===========================================================================
232
+ const sameFile = (a, b) => a.dev === b.dev && a.ino === b.ino;
233
+ /** A letter's other case: its upper case if it's in lower case, else its lower case. */
234
+ const otherCase = (c) => (c === c.toLowerCase() ? c.toUpperCase() : c.toLowerCase());
235
+ /**
236
+ * The name with each letter's case flipped, where its other case is one
237
+ * letter whose own other case is the letter again, so the flip changes only
238
+ * pairs that any folding disk folds together. `ß`, whose upper case is `SS`,
239
+ * and dotless `ı`, whose upper case `I` lowers to `i`, stay as they are.
240
+ */
241
+ const flippedCase = (name) => [...name].map((c) => {
242
+ const other = otherCase(c);
243
+ return [...other].length === 1 && otherCase(other) === c ? other : c;
244
+ }).join('');
245
+ /** Names compared as NFC in lower case. */
246
+ const folded = (name) => name.normalize('NFC').toLowerCase();
247
+ /**
248
+ * Names compared more loosely, through upper case and back, which also folds
249
+ * `ß` with `ss`, `ſ` with `s` and `ς` with `σ`, as a disk that folds fully
250
+ * does. It also folds dotless `ı` with `i`, which a disk may keep apart;
251
+ * the same-file check keeps that from naming another file.
252
+ */
253
+ export const foldedLoosely = (name) => name.normalize('NFC').toLowerCase().toUpperCase().toLowerCase();
254
+ /**
255
+ * Whether `dir` folds case, told without writing: by looking up flipped a
256
+ * name it lists whose flipped spelling it doesn't list too (a name with no
257
+ * letter to flip is its own flipped spelling, and two hard links that differ
258
+ * only in case are one file on any disk). Where no name it lists tells, or
259
+ * it can't be listed, the directory holding it is asked instead, where both
260
+ * are on one device, each as a link to it leads: its own name looked up
261
+ * flipped there, or, for a name with no letter to flip, that directory's own
262
+ * folding. A directory on a device of its own is taken to tell case apart. A
263
+ * directory not there yet folds as the one it would be made in. Where
264
+ * nothing tells, it's taken to tell case apart.
265
+ */
266
+ export async function foldsCase(dir) {
267
+ const holder = dirname(dir);
268
+ let listed;
269
+ try {
270
+ listed = new Set(await readdir(dir));
271
+ }
272
+ catch (error) {
273
+ if (error.code === 'ENOENT' && holder !== dir)
274
+ return foldsCase(holder);
275
+ listed = new Set();
276
+ }
277
+ const look = (path) => lstat(path, { bigint: true }).catch(() => null);
278
+ const name = [...listed].find((n) => !listed.has(flippedCase(n)));
279
+ if (name !== undefined) {
280
+ const [named, flipped] = await Promise.all([look(join(dir, name)), look(join(dir, flippedCase(name)))]);
281
+ return named != null && flipped != null && sameFile(named, flipped);
282
+ }
283
+ if (holder === dir)
284
+ return false;
285
+ // The directory and its holder are looked up through links, so a root
286
+ // that is one, or is reached through one, is compared by the device it
287
+ // lies on. Whether the holder folds is told by its own entries, the root's
288
+ // name and the flipped name, each looked up without following a link
289
+ // there: a link at the flipped name to the root is another file, and a
290
+ // root that is a link is found as itself.
291
+ const see = (path) => stat(path, { bigint: true }).catch(() => null);
292
+ const own = basename(dir);
293
+ const [self, held, entry, flipped] = await Promise.all([see(dir), see(holder), look(dir), look(join(holder, flippedCase(own)))]);
294
+ if (self == null || held == null || self.dev !== held.dev)
295
+ return false;
296
+ if (flippedCase(own) === own)
297
+ return foldsCase(holder);
298
+ return entry != null && flipped != null && sameFile(entry, flipped);
299
+ }
300
+ /**
301
+ * A name in simple case folding, letter by letter: each letter as the lower
302
+ * case of its upper case, so `Σ` and a word's last `ς` are both `σ`, `ſ` is
303
+ * `s` and `µ` is `μ`. A letter whose upper case is more than one letter
304
+ * takes its own lower case instead, as the Greek `ᾈ` takes `ᾀ` and `ß` stays
305
+ * `ß`. A letter whose lower case is more than one letter too, as `İ`'s is,
306
+ * stays as it is, and so does dotless `ı`, whose upper case `I` lowers to
307
+ * `i`, which case folding keeps apart from it. Unicode normalization is left
308
+ * alone, and so are letters only a fuller folding joins, such as `ß` with
309
+ * `ss`: no listing shows two such names to be one file, and a disk that
310
+ * folds case needn't join them.
311
+ */
312
+ export const lowered = (name) => [...name].map((c) => {
313
+ if (c === '\u0131')
314
+ return c;
315
+ const upper = c.toUpperCase();
316
+ const lower = [...upper].length === 1 ? upper.toLowerCase() : c.toLowerCase();
317
+ return [...lower].length === 1 ? lower : c;
318
+ }).join('');
319
+ /**
320
+ * The name `segment` takes among the workspace's entries directly under the
321
+ * directory `prefix` (its path and `/`, or `''` for the mount's root): the
322
+ * segment itself where an entry is there under it, else the first name, in
323
+ * the order given, equal to it in simple case folding (lowered), else null.
324
+ * A name is compared again only where another name came between its entries,
325
+ * as `N.txt` comes between `N` and `N/x` in path order, so the step doesn't
326
+ * fold a name once for every entry beneath it.
327
+ */
328
+ function entryName(paths, prefix, segment) {
329
+ const want = lowered(segment);
330
+ let found = null;
331
+ let previous = null;
332
+ for (const path of paths) {
333
+ if (!path.startsWith(prefix))
334
+ continue;
335
+ const rest = path.slice(prefix.length);
336
+ const slash = rest.indexOf('/');
337
+ const name = slash === -1 ? rest : rest.slice(0, slash);
338
+ if (name === previous)
339
+ continue;
340
+ previous = name;
341
+ if (name === segment)
342
+ return segment;
343
+ if (found === null && lowered(name) === want)
344
+ found = name;
345
+ }
346
+ return found;
347
+ }
348
+ /**
349
+ * The name `dir` lists for `segment`: `segment` itself, unless disk folds it
350
+ * there and lists it otherwise. `dir` is listed only where a variant of
351
+ * `segment`, its case flipped or its other Unicode normalization form, finds
352
+ * the same file (device and inode) as `given`, the segment's own entry, as
353
+ * on a disk that folds names. The last segment isn't looked up as given, so
354
+ * for it any variant found leads to the listing: on a disk that tells
355
+ * spellings apart, that's only where `dir` holds a variant as a name of its
356
+ * own. The name as given wins if it's listed; otherwise the segment takes
357
+ * the listed name that folds to it and is the same file, so the name
358
+ * returned reaches the file the segment does, or is the segment as given.
359
+ * Names are compared as NFC in lower case first, and only where none of
360
+ * those is the file, more loosely (foldedLoosely). A directory that can't be
361
+ * listed, or a name that can't be looked up, leaves the segment as given. A
362
+ * segment with no variant at all, no letter to flip and one normalization
363
+ * form, is looked up as given and keeps its spelling; for a last segment
364
+ * with a letter that case maps, such as `ς`, the listing then says whether
365
+ * disk lists it as given. `found` says whether the lookups found disk's
366
+ * file: for a directory, its own lookup; for a last segment, whether a
367
+ * variant was found, which on a disk that tells spellings apart may be
368
+ * another file, or for one with no variant, whether disk has it as given, by
369
+ * the listing where it was read. `caseFolds` says what looking the segment
370
+ * up with its case flipped showed of `dir`: that it folds case, that it
371
+ * tells case apart, or nothing (null), for a segment with no letter to flip.
372
+ * For a segment not looked up as given (`given` null), `caseFolds` is set
373
+ * from whatever file the flipped spelling finds, which tells nothing of
374
+ * `dir`; diskSpelling reads it only for directories, which are looked up as
375
+ * given.
376
+ */
377
+ async function listedName(dir, segment, given) {
378
+ const flipped = flippedCase(segment);
379
+ const variants = new Set([flipped, segment.normalize('NFC'), segment.normalize('NFD')]);
380
+ variants.delete(segment);
381
+ // A segment with no variant to try, such as `2024` or `ς`, is looked up
382
+ // as given, the only way to learn that disk has it. A last segment with a
383
+ // letter that case maps, as `ς` does, can reach a file disk lists in
384
+ // another spelling, such as `σ`, on a disk that folds more than case
385
+ // pairs, so there the listing settles whether disk lists it as given.
386
+ if (variants.size === 0) {
387
+ const own = given ?? await lstat(join(dir, segment), { bigint: true }).catch(() => null);
388
+ if (given !== null || own === null || (segment.toLowerCase() === segment && segment.toUpperCase() === segment)) {
389
+ return { name: segment, found: own !== null, caseFolds: null };
390
+ }
391
+ const listed = await readdir(dir).catch(() => null);
392
+ return { name: segment, found: listed?.includes(segment) ?? true, caseFolds: null };
393
+ }
394
+ let folds = false;
395
+ let caseFolds = flipped === segment ? null : false;
396
+ for (const variant of variants) {
397
+ const other = await lstat(join(dir, variant), { bigint: true }).catch(() => null);
398
+ if (other !== null && (given === null || sameFile(other, given))) {
399
+ folds = true;
400
+ if (variant === flipped)
401
+ caseFolds = true;
402
+ break;
403
+ }
404
+ }
405
+ const as = (name) => ({ name, found: folds, caseFolds });
406
+ if (!folds)
407
+ return as(segment);
408
+ const listed = await readdir(dir).catch(() => null);
409
+ if (listed === null || listed.includes(segment))
410
+ return as(segment);
411
+ const target = given ?? await lstat(join(dir, segment), { bigint: true }).catch(() => null);
412
+ if (target === null)
413
+ return as(segment);
414
+ for (const fold of [folded, foldedLoosely]) {
415
+ for (const name of listed) {
416
+ if (fold(name) !== fold(segment))
417
+ continue;
418
+ const info = await lstat(join(dir, name), { bigint: true }).catch(() => null);
419
+ if (info !== null && sameFile(info, target))
420
+ return as(name);
421
+ }
422
+ }
423
+ return as(segment);
424
+ }
425
+ /**
426
+ * `relativePath` as disk spells it. On a disk that folds names, as macOS's
427
+ * does by default (case and Unicode normalization), `SRC/a.ts` reaches
428
+ * `src/a.ts`, and whatever names what it finds from the spelling it was
429
+ * given takes the file in a second time, under a name disk doesn't list. So
430
+ * each segment, from the mount's root down, takes the name its directory
431
+ * lists for it (listedName). The walk goes on beneath a segment only if it's
432
+ * a directory, a symlink not included, so nothing past a link is read. It
433
+ * passes over an empty or `.` segment, which names the directory reached,
434
+ * and goes back up at `..`, to the directory it came from. At the mount's
435
+ * root a `..` stops it, keeping the rest as given: a path can climb above
436
+ * the root and come back in, as `../proj/x` does for a root named `proj`, and
437
+ * walking that would list the directory above the root. An absolute path
438
+ * keeps its spelling too: it names a place from the filesystem's root, not
439
+ * the mount's, so walking it from the mount's root would respell it against
440
+ * other directories, and the path returned could lead outside the mount.
441
+ *
442
+ * Given the workspace's `entries`, an entry not yet on disk spells its path
443
+ * as its file will. A path the workspace holds an entry at exactly keeps its
444
+ * spelling whole, and so does a last segment where the workspace holds an
445
+ * entry at exactly that path once its directories have taken disk's
446
+ * spelling, so an entry that disk lists in another spelling, or in a
447
+ * directory disk lists in another, stays reachable by its own path. `has`
448
+ * counts a path the workspace records an intent at, such as a deletion disk
449
+ * hasn't been given yet, so that's reached by its own path too. And where
450
+ * the directory reached folds case, each segment disk has nothing for takes
451
+ * the name of an entry it equals in simple case folding (entryName), as the
452
+ * disk will once that entry is written: a second draft spelled in another
453
+ * case is the first one. None of this applies where disk's spelling puts the
454
+ * path in a nested mount's directory, by the nested-mount checks' own
455
+ * reading (`holder`): there the path keeps disk's spelling, so they refuse
456
+ * at least what they refuse without the entries. The root's folding is read
457
+ * at start (`rootFoldsCase`), and a directory beneath it is taken to fold as
458
+ * the directory holding it did when its name was looked up with its case
459
+ * flipped, or, for a name with no letter to flip, as the nearest directory
460
+ * above that told, so the step reads nothing more of disk for this.
461
+ */
462
+ export async function diskSpelling(root, relativePath, entries) {
463
+ if (relativePath === '' || isAbsolute(relativePath))
464
+ return relativePath;
465
+ // A path that names an entry exactly keeps its spelling, read before the
466
+ // walk awaits disk, so the entries' walk needn't run for it.
467
+ const exact = entries?.has(relativePath) ?? false;
468
+ // The path as disk spells it, and as the workspace's entries spell it.
469
+ const segments = relativePath.split('/');
470
+ const spelled = [...segments];
471
+ // The directories walked into, the mount's root first; their names below
472
+ // the root, as returned; and whether each folds case: the root's as read at
473
+ // start, and beneath it, whether looking its name up with its case flipped
474
+ // found it in the directory holding it (null for a name with no letter to
475
+ // flip).
476
+ const dirs = [root];
477
+ const names = [];
478
+ const folding = [entries?.rootFoldsCase ?? null];
479
+ // From segment `from` on, disk has nothing: each segment takes an entry's
480
+ // name, where the directory reached folds case, passing over an empty or
481
+ // `.` segment, and the rest keeps its spelling from the first segment no
482
+ // entry has a name for, a `..` included.
483
+ const fromEntries = (from) => {
484
+ // The nearest directory, from the one reached up, that told.
485
+ let folds = null;
486
+ for (let k = folding.length - 1; folds === null && k >= 0; k--)
487
+ folds = folding[k];
488
+ if (!entries || exact || !folds)
489
+ return;
490
+ let prefix = names.length === 0 ? '' : `${names.join('/')}/`;
491
+ const paths = entries.under(prefix);
492
+ for (let j = from; j < spelled.length; j++) {
493
+ const segment = spelled[j];
494
+ if (segment === '' || segment === '.')
495
+ continue;
496
+ const name = entryName(paths, prefix, segment);
497
+ if (name === null)
498
+ return;
499
+ spelled[j] = name;
500
+ prefix = `${prefix}${name}/`;
501
+ }
502
+ };
503
+ for (let i = 0; i < segments.length; i++) {
504
+ const segment = segments[i];
505
+ if (segment === '' || segment === '.')
506
+ continue;
507
+ if (segment === '..') {
508
+ if (dirs.length === 1)
509
+ break;
510
+ dirs.pop();
511
+ names.pop();
512
+ folding.pop();
513
+ continue;
514
+ }
515
+ const dir = dirs[dirs.length - 1];
516
+ if (i === segments.length - 1) {
517
+ const { name, found } = await listedName(dir, segment, null);
518
+ segments[i] = name;
519
+ if (!exact && !entries?.has([...names, segment].join('/'))) {
520
+ spelled[i] = name;
521
+ if (!found)
522
+ fromEntries(i);
523
+ }
524
+ break;
525
+ }
526
+ const given = await lstat(join(dir, segment), { bigint: true }).catch(() => null);
527
+ if (given === null) {
528
+ fromEntries(i);
529
+ break;
530
+ }
531
+ const { name, caseFolds } = await listedName(dir, segment, given);
532
+ segments[i] = name;
533
+ spelled[i] = name;
534
+ if (!given.isDirectory())
535
+ break;
536
+ dirs.push(join(dir, name));
537
+ names.push(name);
538
+ folding.push(caseFolds);
539
+ }
540
+ const asDisk = segments.join('/');
541
+ if (!entries || entries.holder(asDisk) !== undefined)
542
+ return asDisk;
543
+ return exact ? relativePath : spelled.join('/');
544
+ }
82
545
  /** Errors meaning a directory can't be synced on this filesystem, not that syncing it failed. */
83
546
  const DIRECTORY_SYNC_UNSUPPORTED = new Set(['EINVAL', 'ENOTSUP']);
84
547
  /**
@@ -128,7 +591,11 @@ export class CheckedDir {
128
591
  async sync() {
129
592
  if (process.platform === 'win32')
130
593
  return;
131
- const handle = await open(this.real, 'r');
594
+ // NONBLOCK: a FIFO put at its path since it was checked opens at once,
595
+ // and is refused below as not this directory, instead of holding the
596
+ // open, and with it the mount's turn, until something opens it for
597
+ // writing.
598
+ const handle = await open(this.real, fsConstants.O_RDONLY | NONBLOCK);
132
599
  try {
133
600
  const info = await handle.stat({ bigint: true });
134
601
  if (!info.isDirectory() || info.dev !== this.dev || info.ino !== this.ino)
@@ -167,8 +634,18 @@ async function locateDir(view, rootReal, rel) {
167
634
  const code = errno(err);
168
635
  if (code === 'ENOENT' || code === 'ENOTDIR')
169
636
  return rel === '' ? { kind: 'unobserved', reason: ROOT_UNAVAILABLE } : { kind: 'missing' };
637
+ // A link on the way that can't be resolved, such as a loop, is still a
638
+ // link this mount doesn't follow.
639
+ const found = rel === '' ? null : await linkOnTheWay(view, rel);
640
+ if (found !== null)
641
+ return { kind: 'unobserved', reason: await linkReason(view, rootReal, found) };
170
642
  return { kind: 'unobserved', reason: `cannot resolve the directory (${code ?? String(err)})` };
171
643
  }
644
+ // A mount that doesn't follow symlinks goes through none on the way to a
645
+ // directory, inside the mount or out of it.
646
+ const found = await linkRefusal(view, rootReal, rel, real);
647
+ if (found !== null)
648
+ return { kind: 'unobserved', reason: await linkReason(view, rootReal, found) };
172
649
  if (rel === '') {
173
650
  // The root is whatever the configured path names, and it must still be
174
651
  // the root the pass was given.
@@ -178,6 +655,13 @@ async function locateDir(view, rootReal, rel) {
178
655
  else if (!contained(rootReal, real)) {
179
656
  return { kind: 'unobserved', reason: OUTSIDE_PARENT, outside: true };
180
657
  }
658
+ else {
659
+ // Through a link this mount follows, a directory can be a nested
660
+ // mount's, which the mount neither reads nor writes.
661
+ const holder = nestedAtReal(real, view.nested);
662
+ if (holder)
663
+ return { kind: 'unobserved', reason: leadsInto(view.name, rel, holder) };
664
+ }
181
665
  const checked = await checkedAt(view, rel, real);
182
666
  if (checked) {
183
667
  // A root that isn't the directory disk last agreed under proves nothing
@@ -238,6 +722,11 @@ async function createDir(view, rootReal, rel) {
238
722
  return { kind: 'unobserved', reason: ROOT_UNAVAILABLE };
239
723
  for (let i = depth; i < parts.length; i++) {
240
724
  const childRel = parts.slice(0, i + 1).join('/');
725
+ // Nothing is made in a nested mount's directory, its root included where
726
+ // it isn't made yet, by a path that reaches it through a link.
727
+ const holder = nestedAtReal(base.at(parts[i]), view.nested);
728
+ if (holder)
729
+ return { kind: 'unobserved', reason: leadsInto(view.name, childRel, holder) };
241
730
  try {
242
731
  await mkdir(base.at(parts[i]));
243
732
  }
@@ -249,8 +738,14 @@ async function createDir(view, rootReal, rel) {
249
738
  // Made, or there already (made meanwhile, or not a directory): it must
250
739
  // be a real directory now, never a symlink or file in its place.
251
740
  const checked = await checkedAt(view, childRel, base.at(parts[i]));
252
- if (!checked)
741
+ if (!checked) {
742
+ // A symlink in the way, such as one that leads nowhere, on a mount that
743
+ // doesn't follow symlinks, is named as one.
744
+ const there = view.followSymlinks ? null : await lstat(base.at(parts[i])).catch(() => null);
745
+ if (there?.isSymbolicLink())
746
+ return { kind: 'unobserved', reason: await linkReason(view, rootReal, { link: childRel }) };
253
747
  return { kind: 'unobserved', reason: 'a parent path is not a directory' };
748
+ }
254
749
  base = checked;
255
750
  }
256
751
  return { kind: 'checked', dir: base };
@@ -263,10 +758,12 @@ async function createDir(view, rootReal, rel) {
263
758
  * which nothing can exist. Either proves it only while every directory the
264
759
  * walk went through, the root included, is still the one its path names
265
760
  * afterwards: a root or parent replaced during the walk would otherwise lend
266
- * its replacement's absence to the original's path. Symlinked directories
267
- * inside the mount are followed as parents; any other symlink proves
268
- * nothing. Returns the directory whose entries prove it, or why absence
269
- * couldn't be shown.
761
+ * its replacement's absence to the original's path. On a mount that follows
762
+ * symlinks, symlinked directories inside the mount are followed as parents;
763
+ * on one that doesn't, a symlinked directory on the way proves nothing, and
764
+ * the reason says so (linkReason). Any other symlink proves nothing.
765
+ * Returns the directory whose entries prove it, or why absence couldn't be
766
+ * shown.
270
767
  */
271
768
  export async function confirmAbsent(view, rootReal, rel, target = 'entry') {
272
769
  const root = await locateDir(view, rootReal, '');
@@ -309,6 +806,9 @@ export async function confirmAbsent(view, rootReal, rel, target = 'entry') {
309
806
  if (info.isSymbolicLink()) {
310
807
  if (last && target === 'entry')
311
808
  return CHANGED; // present: the link itself
809
+ // A mount that doesn't follow symlinks goes through none on the way.
810
+ if (!view.followSymlinks)
811
+ return linkReason(view, rootReal, { link: childRel });
312
812
  const located = await locateDir(view, rootReal, childRel);
313
813
  if (located.kind !== 'checked')
314
814
  return BENEATH_SYMLINK;
@@ -397,17 +897,29 @@ export async function filesystemTrustsCtime(root) {
397
897
  /**
398
898
  * Where a path's parent directory canonically lies: inside the mount, gone
399
899
  * (absence is then proven separately), or somewhere a no-follow open would
400
- * still reach through — O_NOFOLLOW guards only the final component.
900
+ * still reach through — O_NOFOLLOW guards only the final component — which
901
+ * on a mount that doesn't follow symlinks is any symlink on the way.
401
902
  */
402
- async function parentPlacement(rootReal, lexical) {
903
+ async function parentPlacement(view, rootReal, relativePath) {
403
904
  try {
404
- const parent = await realpath(dirname(lexical));
405
- return contained(rootReal, parent) ? 'inside' : { reason: OUTSIDE_PARENT };
905
+ const parent = await realpath(dirname(join(view.root, relativePath)));
906
+ const found = await linkRefusal(view, rootReal, relativePath, parent, 'parents');
907
+ if (found !== null)
908
+ return { reason: await linkReason(view, rootReal, found) };
909
+ if (!contained(rootReal, parent))
910
+ return { reason: OUTSIDE_PARENT };
911
+ const holder = nestedAtReal(parent, view.nested);
912
+ return holder ? { reason: leadsInto(view.name, parentOf(relativePath), holder) } : 'inside';
406
913
  }
407
914
  catch (err) {
408
915
  const code = errno(err);
409
916
  if (code === 'ENOENT' || code === 'ENOTDIR')
410
917
  return 'gone';
918
+ // A link on the way that can't be resolved, such as a loop, is still a
919
+ // link this mount doesn't follow.
920
+ const found = await linkOnTheWay(view, relativePath, 'parents');
921
+ if (found !== null)
922
+ return { reason: await linkReason(view, rootReal, found) };
411
923
  return { reason: `cannot resolve the parent directory (${code ?? String(err)})` };
412
924
  }
413
925
  }
@@ -419,7 +931,7 @@ async function parentPlacement(rootReal, lexical) {
419
931
  */
420
932
  export async function observePath(view, rootReal, relativePath) {
421
933
  const lexical = join(view.root, relativePath);
422
- const placement = await parentPlacement(rootReal, lexical);
934
+ const placement = await parentPlacement(view, rootReal, relativePath);
423
935
  if (placement === 'gone')
424
936
  return absence(view, rootReal, relativePath);
425
937
  if (placement !== 'inside')
@@ -453,6 +965,9 @@ export async function observePath(view, rootReal, relativePath) {
453
965
  }
454
966
  if (!contained(rootReal, real))
455
967
  return { kind: 'unobserved', reason: 'a symlink that leaves the mount' };
968
+ const holder = nestedAtReal(real, view.nested);
969
+ if (holder)
970
+ return { kind: 'unobserved', reason: leadsInto(view.name, relativePath, holder) };
456
971
  if (!target.isFile()) {
457
972
  return { kind: 'unobserved', reason: target.isDirectory() ? 'a symlink to a directory, not walked' : 'not a regular file' };
458
973
  }
@@ -464,13 +979,14 @@ export async function observePath(view, rootReal, relativePath) {
464
979
  else if (!info.isFile()) {
465
980
  return { kind: 'unobserved', reason: 'not a regular file' };
466
981
  }
467
- return { kind: 'file', size: Number(info.size), mtimeMs: Number(info.mtimeMs), fp: statFingerprint(info) };
982
+ return { kind: 'file', size: Number(info.size), mtimeMs: Number(info.mtimeMs), mode: Number(info.mode & 511n), fp: statFingerprint(info) };
468
983
  }
469
984
  /**
470
985
  * Open a mount-relative file for reading, located: a regular file that
471
- * canonically lies inside the mount — whatever the symlink policy, since a
472
- * symlinked parent escapes O_NOFOLLOW — and is the file the canonical path
473
- * names now. The handle is the caller's to close.
986
+ * canonically lies inside the mount, whatever the symlink policy, since
987
+ * O_NOFOLLOW guards only the final component; on a mount that doesn't follow
988
+ * symlinks, reached through no symlinked directory either (linkRefusal); and
989
+ * the file the canonical path names now. The handle is the caller's to close.
474
990
  */
475
991
  async function openContained(view, rootReal, relativePath) {
476
992
  const lexical = join(view.root, relativePath);
@@ -491,8 +1007,11 @@ async function openContained(view, rootReal, relativePath) {
491
1007
  const code = errno(err);
492
1008
  if (code === 'ENOENT' || code === 'ENOTDIR')
493
1009
  return absence(view, rootReal, relativePath);
494
- if (code === 'ELOOP' && !view.followSymlinks)
495
- return { kind: 'unobserved', reason: NOT_FOLLOWED };
1010
+ if (code === 'ELOOP' && !view.followSymlinks) {
1011
+ // The link at the path, or a looping one on its way.
1012
+ const found = await linkOnTheWay(view, relativePath, 'parents');
1013
+ return { kind: 'unobserved', reason: found === null ? NOT_FOLLOWED : await linkReason(view, rootReal, found) };
1014
+ }
496
1015
  if (code === 'EISDIR')
497
1016
  return { kind: 'unobserved', reason: 'a directory' };
498
1017
  return { kind: 'unobserved', reason: `cannot open (${code ?? String(err)})` };
@@ -500,14 +1019,25 @@ async function openContained(view, rootReal, relativePath) {
500
1019
  let keep = false;
501
1020
  try {
502
1021
  const info = await handle.stat({ bigint: true });
503
- if (!info.isFile())
504
- return { kind: 'unobserved', reason: info.isDirectory() ? 'a directory' : 'not a regular file' };
505
1022
  const real = await realpath(lexical).catch(() => null);
506
1023
  if (real === null)
507
1024
  return { kind: 'unobserved', reason: 'the file changed while it was read' };
1025
+ // O_NOFOLLOW guards only the final component: a mount that doesn't
1026
+ // follow symlinks goes through none among the directories on the way
1027
+ // either. Asked of what the path resolved to after the open, which the
1028
+ // check below holds to the descriptor's file, and before what the
1029
+ // descriptor holds, so a link gets its own answer whatever it leads to.
1030
+ const found = await linkRefusal(view, rootReal, relativePath, real);
1031
+ if (found !== null)
1032
+ return { kind: 'unobserved', reason: await linkReason(view, rootReal, found) };
1033
+ if (!info.isFile())
1034
+ return { kind: 'unobserved', reason: info.isDirectory() ? 'a directory' : 'not a regular file' };
508
1035
  if (!contained(rootReal, real)) {
509
1036
  return { kind: 'unobserved', reason: view.followSymlinks ? 'a symlink that leaves the mount' : OUTSIDE_PARENT };
510
1037
  }
1038
+ const holder = nestedAtReal(real, view.nested);
1039
+ if (holder)
1040
+ return { kind: 'unobserved', reason: leadsInto(view.name, relativePath, holder) };
511
1041
  const named = await stat(real, { bigint: true }).catch(() => null);
512
1042
  if (named === null || named.dev !== info.dev || named.ino !== info.ino) {
513
1043
  return { kind: 'unobserved', reason: 'the file changed while it was read' };
@@ -537,10 +1067,44 @@ async function openContained(view, rootReal, relativePath) {
537
1067
  await handle.close();
538
1068
  }
539
1069
  }
1070
+ /**
1071
+ * Read an open file from its start, at most `limit` bytes, and whether it
1072
+ * goes on past them. Where the file ends is what the reads find: `sizeHint`,
1073
+ * the size its fstat gave, only sizes the first buffer. Once a buffer is
1074
+ * full, one byte read past it tells whether the file goes on. At the limit,
1075
+ * that byte says it does, and isn't kept. Short of it, the file has grown
1076
+ * since its fstat: the byte is kept, and the read goes on in a larger buffer,
1077
+ * up to the limit. A file that has shrunk ends where the reads find its end.
1078
+ * A fractional `limit` allows the whole bytes in it.
1079
+ */
1080
+ export async function readPrefix(handle, limit, sizeHint) {
1081
+ const cap = Math.floor(limit);
1082
+ const next = Buffer.alloc(1);
1083
+ let bytes = Buffer.alloc(Math.min(cap, sizeHint));
1084
+ let length = 0;
1085
+ for (;;) {
1086
+ while (length < bytes.length) {
1087
+ const { bytesRead } = await handle.read(bytes, length, bytes.length - length, length);
1088
+ if (bytesRead === 0)
1089
+ return { bytes: bytes.subarray(0, length), more: false };
1090
+ length += bytesRead;
1091
+ }
1092
+ if ((await handle.read(next, 0, 1, length)).bytesRead === 0)
1093
+ return { bytes, more: false };
1094
+ if (length === cap)
1095
+ return { bytes, more: true };
1096
+ // Longer than its fstat said: read on, up to the limit.
1097
+ const grown = Buffer.alloc(Math.min(cap, Math.max(2 * length, length + 64 * 1024)));
1098
+ bytes.copy(grown, 0, 0, length);
1099
+ grown[length++] = next[0];
1100
+ bytes = grown;
1101
+ }
1102
+ }
540
1103
  /**
541
1104
  * Read and hash a mount-relative file through one located descriptor. The
542
- * whole file is returned when it is at most `limit` bytes; larger files are
543
- * hashed in chunks and only their head is kept.
1105
+ * whole file is returned when it is at most `limit` bytes, both at its fstat
1106
+ * and as read; any other file, including one that grew past `limit` since its
1107
+ * fstat, is hashed in chunks and only its head is kept.
544
1108
  */
545
1109
  export async function readPath(view, rootReal, relativePath, limit) {
546
1110
  const opened = await openContained(view, rootReal, relativePath);
@@ -551,12 +1115,18 @@ export async function readPath(view, rootReal, relativePath, limit) {
551
1115
  const hashedAt = Date.now();
552
1116
  const size = Number(info.size);
553
1117
  const fp = { ...statFingerprint(info), hashedAt };
554
- if (size <= limit) {
555
- const bytes = await handle.readFile();
1118
+ // A file within the limit at its fstat is read no further than the limit,
1119
+ // so one that has grown past it since is hashed below, from its start,
1120
+ // never loaded whole. One over the limit at its fstat is hashed below
1121
+ // without that read.
1122
+ const within = size <= limit ? await readPrefix(handle, limit, size) : null;
1123
+ if (within && !within.more) {
1124
+ const { bytes } = within;
556
1125
  return {
557
1126
  kind: 'read',
558
1127
  size: bytes.byteLength,
559
1128
  mtimeMs: Number(info.mtimeMs),
1129
+ mode: Number(info.mode & 511n),
560
1130
  fp: { ...fp, size: bytes.byteLength },
561
1131
  hash: createHash('sha256').update(bytes).digest('hex'),
562
1132
  bytes,
@@ -580,6 +1150,7 @@ export async function readPath(view, rootReal, relativePath, limit) {
580
1150
  kind: 'read',
581
1151
  size: offset,
582
1152
  mtimeMs: Number(info.mtimeMs),
1153
+ mode: Number(info.mode & 511n),
583
1154
  fp: { ...fp, size: offset },
584
1155
  hash: hash.digest('hex'),
585
1156
  bytes: null,
@@ -700,6 +1271,98 @@ export function coveredByIgnore(relativePath, patterns) {
700
1271
  }
701
1272
  return false;
702
1273
  }
1274
+ /**
1275
+ * The ignore patterns a walk that names `scope` reads beneath it: a pattern
1276
+ * covering the scope itself, or a directory above it, doesn't apply beneath
1277
+ * it (#276); one covering only something inside it does.
1278
+ */
1279
+ export function ignoreBeneath(scope, patterns) {
1280
+ return patterns.filter((pattern) => !coveredByIgnore(scope, [pattern]));
1281
+ }
1282
+ /**
1283
+ * Names editors give the files they keep beside the one being edited: vim's
1284
+ * swap files (`.name.swp`, and `.name.swx` while it checks it can make one),
1285
+ * backups ending in `~`, and Sublime Text's save-in-progress files, ending
1286
+ * in `.subl…tmp`. A walk passes over an entry with such a name as it passes
1287
+ * over what the ignore list covers, a directory with what lies beneath it,
1288
+ * and the watcher ignores it; a sync that names one takes it in. They are
1289
+ * the families chokidar's `atomic` option hid from the watcher, but that
1290
+ * tested them against the whole path, unanchored, so it also hid
1291
+ * `report.v2.swp`, and under a directory with a dot in its name, a plain
1292
+ * `notes.swp`. Here each is matched against an entry's name, to its end,
1293
+ * and vim's from its start.
1294
+ */
1295
+ const EDITOR_FILE = /^\..+\.sw[px]$|~$|\.subl.*\.tmp$/;
1296
+ /** The walk's reason for an entry the mount's ignore list covers. */
1297
+ export const IGNORED = 'ignored by the mount';
1298
+ /** The walk's reason for an entry `EDITOR_FILE` names. */
1299
+ const EDITOR_FILE_REASON = "an editor's swap or backup file";
1300
+ /** Whether a reason the walk gave an entry is one it passes over by design. */
1301
+ export function passedOverByDesign(why) {
1302
+ return why === IGNORED || why === EDITOR_FILE_REASON || why === OTHER_MOUNT;
1303
+ }
1304
+ /** Why a pass passes over a directory that another mount nested in this one holds, and what lies beneath it. */
1305
+ export const OTHER_MOUNT = "another mount's directory";
1306
+ /**
1307
+ * Whether a mount-relative path is another mount's directory, or lies
1308
+ * beneath one, read as a join reads it: `.` and `..` segments within the
1309
+ * path and repeated or trailing separators resolved, links not followed. A
1310
+ * stored key such as `a//b/x`, which chronicle accepts, is read as `a/b/x`.
1311
+ * A leading `..` that climbs above the mount's root is left as written.
1312
+ * Every nested-mount check (a pass's, a walk's, a push's, grep's) asks this.
1313
+ */
1314
+ export function inOtherMount(relativePath, others) {
1315
+ const lexical = posix.normalize(relativePath).replace(/\/+$/, '');
1316
+ return others.some((dir) => lexical === dir || lexical.startsWith(dir + '/'));
1317
+ }
1318
+ /**
1319
+ * Why a walk passes over an entry by design, by its mount-relative path and
1320
+ * its name: another mount's directory, the ignore list, or an editor's file
1321
+ * name. Undefined when none covers it.
1322
+ */
1323
+ function passedOverBecause(relativePath, name, patterns, others) {
1324
+ if (inOtherMount(relativePath, others))
1325
+ return OTHER_MOUNT;
1326
+ if (isIgnored(relativePath, name, patterns))
1327
+ return IGNORED;
1328
+ if (EDITOR_FILE.test(name))
1329
+ return EDITOR_FILE_REASON;
1330
+ return undefined;
1331
+ }
1332
+ /**
1333
+ * Why a sync without a path, and the watcher, pass over a mount-relative
1334
+ * path: the path itself or a directory above it is passed over by design, as
1335
+ * the walk reads each entry by its path and name. A path in another mount's
1336
+ * directory is that mount's, whatever else covers a directory above it.
1337
+ * Undefined when nothing covers it.
1338
+ */
1339
+ export function passedOverAt(relativePath, patterns, others) {
1340
+ if (inOtherMount(relativePath, others))
1341
+ return OTHER_MOUNT;
1342
+ const segments = relativePath.split('/').filter(Boolean);
1343
+ for (let i = 0; i < segments.length; i++) {
1344
+ const why = passedOverBecause(segments.slice(0, i + 1).join('/'), segments[i], patterns, others);
1345
+ if (why !== undefined)
1346
+ return why;
1347
+ }
1348
+ return undefined;
1349
+ }
1350
+ /**
1351
+ * Why a walk of `scope` passes over a directory between it and a path beneath
1352
+ * it: the first directory strictly beneath the scope and above the path that
1353
+ * the mount passes over by design, by its path and name, with the patterns
1354
+ * the walk reads there. Undefined when none is.
1355
+ */
1356
+ export function passedOverBetween(scope, relativePath, patterns, others) {
1357
+ const segments = relativePath.split('/').filter(Boolean);
1358
+ const from = scope === '' ? 0 : scope.split('/').filter(Boolean).length;
1359
+ for (let i = from; i < segments.length - 1; i++) {
1360
+ const why = passedOverBecause(segments.slice(0, i + 1).join('/'), segments[i], patterns, others);
1361
+ if (why !== undefined)
1362
+ return why;
1363
+ }
1364
+ return undefined;
1365
+ }
703
1366
  /** Simple ignore patterns, as the watcher and the old walk read them. */
704
1367
  export function isIgnored(relativePath, name, patterns) {
705
1368
  for (const pattern of patterns) {
@@ -763,6 +1426,29 @@ export async function walkScope(view, rootReal, scope, recursive, cap, opts = {}
763
1426
  files: new Set(), seen: new Set(), othersTaken: new Set(), dirs: new Set(), others: new Map(), complete: new Set(), missing: new Set(),
764
1427
  incomplete: [],
765
1428
  };
1429
+ // A walk that isn't named passes over a scope the mount passes over by
1430
+ // design, at it or a directory above it, as its parent's listing would pass
1431
+ // over its entry: a name rule (a bare-name ignore entry, an editor's name)
1432
+ // doesn't match what lies beneath, as a path rule (`cache/**`) does. So a
1433
+ // listing, glob or grep there never starts tracking what the mount leaves
1434
+ // out, and a stored copy beneath it is unobserved, as beneath any region
1435
+ // passed over by design. Its region says how to take what's there in: a
1436
+ // sync that names it, whose scope is walked (#276), below.
1437
+ // Another mount's directory is passed over by every walk, named or not,
1438
+ // and no sync of this mount takes it in, so its region gives no advice.
1439
+ if (scope !== '' && inOtherMount(scope, view.others)) {
1440
+ walk.others.set(scope, OTHER_MOUNT);
1441
+ walk.incomplete.push({ path: scope, reason: OTHER_MOUNT, kind: 'ignored' });
1442
+ return walk;
1443
+ }
1444
+ if (!opts.named && scope !== '') {
1445
+ const why = passedOverAt(scope, view.ignore, view.others);
1446
+ if (why !== undefined) {
1447
+ walk.others.set(scope, why);
1448
+ walk.incomplete.push({ path: scope, reason: `${why}: a sync that names this path takes in what's there, editors' files aside`, kind: 'ignored' });
1449
+ return walk;
1450
+ }
1451
+ }
766
1452
  const top = await checkDir(view, rootReal, scope);
767
1453
  if (top.kind === 'absent') {
768
1454
  walk.missing.add(scope);
@@ -775,9 +1461,11 @@ export async function walkScope(view, rootReal, scope, recursive, cap, opts = {}
775
1461
  // A scope a path sync names is walked even where the ignore list covers
776
1462
  // it: a pattern covering the scope itself, or a directory above it, doesn't
777
1463
  // apply beneath it. So a named directory's contents are synced, as a named
778
- // file is (agent-framework #276). A listing keeps the ignore: its pass
779
- // would otherwise start tracking what it lists.
780
- const ignore = opts.named ? view.ignore.filter((pattern) => !coveredByIgnore(scope, [pattern])) : view.ignore;
1464
+ // file is (agent-framework #276), apart from what a pattern covering only
1465
+ // something inside it covers, and editors' files, which are passed over
1466
+ // there as anywhere. A listing keeps the ignore: its pass would otherwise
1467
+ // start tracking what it lists.
1468
+ const ignore = opts.named ? ignoreBeneath(scope, view.ignore) : view.ignore;
781
1469
  // A position outside the scope, or for a walk that doesn't descend, is no
782
1470
  // position in this walk's order.
783
1471
  const after = recursive && opts.resumeAfter !== undefined && (scope === '' || opts.resumeAfter.startsWith(scope + '/'))
@@ -887,9 +1575,10 @@ export async function walkScope(view, rootReal, scope, recursive, cap, opts = {}
887
1575
  const regions = [];
888
1576
  for (const entry of entries) {
889
1577
  const childRel = rel ? `${rel}/${entry.name}` : entry.name;
890
- if (isIgnored(childRel, entry.name, ignore)) {
891
- others.push([childRel, 'ignored by the mount']);
892
- regions.push({ path: childRel, reason: 'ignored by the mount', kind: 'ignored' });
1578
+ const passedOver = passedOverBecause(childRel, entry.name, ignore, view.others);
1579
+ if (passedOver !== undefined) {
1580
+ others.push([childRel, passedOver]);
1581
+ regions.push({ path: childRel, reason: passedOver, kind: 'ignored' });
893
1582
  continue;
894
1583
  }
895
1584
  if (entry.isDirectory()) {
@@ -998,7 +1687,7 @@ export async function walkScope(view, rootReal, scope, recursive, cap, opts = {}
998
1687
  for (const f of walk.seen)
999
1688
  holdingUntaken.add(parentOf(f));
1000
1689
  for (const [p, why] of walk.others)
1001
- if (why !== 'ignored by the mount' && !walk.othersTaken.has(p))
1690
+ if (!passedOverByDesign(why) && !walk.othersTaken.has(p))
1002
1691
  holdingUntaken.add(parentOf(p));
1003
1692
  for (const d of holdingUntaken) {
1004
1693
  walk.incomplete.push({ path: d, reason: `${capped} before everything here was taken`, kind: 'cap' });
@@ -1015,7 +1704,8 @@ export async function walkScope(view, rootReal, scope, recursive, cap, opts = {}
1015
1704
  // The cap stopped the walk only if it left something: a walk whose last
1016
1705
  // file used up the cap covered its scope. A directory the walk didn't list
1017
1706
  // counts as left, even one that holds nothing it would take (empty, or
1018
- // only ignored names): telling them apart would take another read. Such a
1707
+ // only names it passes over by design): telling them apart would take
1708
+ // another read. Such a
1019
1709
  // walk keeps its place and reports the directory as not visited, and the
1020
1710
  // next one lists it on its way to the wrap.
1021
1711
  if (left === 0 && lastTaken !== undefined && (holdingUntaken.size > 0 || unlisted > 0))