@animalabs/agent-framework 0.22.2 → 0.22.4

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 (940) hide show
  1. package/README.md +3 -1
  2. package/dist/src/agent.d.ts +77 -12
  3. package/dist/src/agent.d.ts.map +1 -1
  4. package/dist/src/agent.js +143 -41
  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/py-runner.d.ts +16 -5
  22. package/dist/src/code-execution/py-runner.d.ts.map +1 -1
  23. package/dist/src/code-execution/py-runner.js +186 -74
  24. package/dist/src/code-execution/py-runner.js.map +1 -1
  25. package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
  26. package/dist/src/code-execution/runtime-py.js +49 -3
  27. package/dist/src/code-execution/runtime-py.js.map +1 -1
  28. package/dist/src/code-execution/tool-definition.d.ts +12 -1
  29. package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
  30. package/dist/src/code-execution/tool-definition.js +21 -3
  31. package/dist/src/code-execution/tool-definition.js.map +1 -1
  32. package/dist/src/config-checks.d.ts +28 -0
  33. package/dist/src/config-checks.d.ts.map +1 -0
  34. package/dist/src/config-checks.js +52 -0
  35. package/dist/src/config-checks.js.map +1 -0
  36. package/dist/src/deadline-timer.d.ts +21 -0
  37. package/dist/src/deadline-timer.d.ts.map +1 -0
  38. package/dist/src/deadline-timer.js +43 -0
  39. package/dist/src/deadline-timer.js.map +1 -0
  40. package/dist/src/error-message.d.ts +30 -0
  41. package/dist/src/error-message.d.ts.map +1 -0
  42. package/dist/src/error-message.js +50 -0
  43. package/dist/src/error-message.js.map +1 -0
  44. package/dist/src/framework.d.ts +828 -88
  45. package/dist/src/framework.d.ts.map +1 -1
  46. package/dist/src/framework.js +5011 -1326
  47. package/dist/src/framework.js.map +1 -1
  48. package/dist/src/gate/event-gate.d.ts +8 -0
  49. package/dist/src/gate/event-gate.d.ts.map +1 -1
  50. package/dist/src/gate/event-gate.js +27 -3
  51. package/dist/src/gate/event-gate.js.map +1 -1
  52. package/dist/src/index.d.ts +4 -2
  53. package/dist/src/index.d.ts.map +1 -1
  54. package/dist/src/index.js +4 -2
  55. package/dist/src/index.js.map +1 -1
  56. package/dist/src/mcpl/channel-registry.d.ts +144 -6
  57. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  58. package/dist/src/mcpl/channel-registry.js +424 -263
  59. package/dist/src/mcpl/channel-registry.js.map +1 -1
  60. package/dist/src/mcpl/checkpoint-manager.d.ts +21 -1
  61. package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
  62. package/dist/src/mcpl/checkpoint-manager.js +91 -30
  63. package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
  64. package/dist/src/mcpl/conversation-router.d.ts +19 -3
  65. package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
  66. package/dist/src/mcpl/conversation-router.js +23 -8
  67. package/dist/src/mcpl/conversation-router.js.map +1 -1
  68. package/dist/src/mcpl/convert-block.d.ts +20 -0
  69. package/dist/src/mcpl/convert-block.d.ts.map +1 -0
  70. package/dist/src/mcpl/convert-block.js +89 -0
  71. package/dist/src/mcpl/convert-block.js.map +1 -0
  72. package/dist/src/mcpl/errors.d.ts +13 -0
  73. package/dist/src/mcpl/errors.d.ts.map +1 -1
  74. package/dist/src/mcpl/errors.js +28 -0
  75. package/dist/src/mcpl/errors.js.map +1 -1
  76. package/dist/src/mcpl/hook-orchestrator.d.ts +23 -0
  77. package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
  78. package/dist/src/mcpl/hook-orchestrator.js +83 -72
  79. package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
  80. package/dist/src/mcpl/inbound-source.d.ts +114 -0
  81. package/dist/src/mcpl/inbound-source.d.ts.map +1 -0
  82. package/dist/src/mcpl/inbound-source.js +83 -0
  83. package/dist/src/mcpl/inbound-source.js.map +1 -0
  84. package/dist/src/mcpl/index.d.ts +3 -1
  85. package/dist/src/mcpl/index.d.ts.map +1 -1
  86. package/dist/src/mcpl/index.js +3 -1
  87. package/dist/src/mcpl/index.js.map +1 -1
  88. package/dist/src/mcpl/inference-router.d.ts +15 -11
  89. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  90. package/dist/src/mcpl/inference-router.js +153 -84
  91. package/dist/src/mcpl/inference-router.js.map +1 -1
  92. package/dist/src/mcpl/push-coalescer.d.ts +33 -11
  93. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  94. package/dist/src/mcpl/push-coalescer.js +52 -20
  95. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  96. package/dist/src/mcpl/push-handler.d.ts +16 -9
  97. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  98. package/dist/src/mcpl/push-handler.js +18 -83
  99. package/dist/src/mcpl/push-handler.js.map +1 -1
  100. package/dist/src/mcpl/reference-fetcher.d.ts +14 -2
  101. package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
  102. package/dist/src/mcpl/reference-fetcher.js +72 -30
  103. package/dist/src/mcpl/reference-fetcher.js.map +1 -1
  104. package/dist/src/mcpl/references.d.ts +47 -12
  105. package/dist/src/mcpl/references.d.ts.map +1 -1
  106. package/dist/src/mcpl/references.js +74 -21
  107. package/dist/src/mcpl/references.js.map +1 -1
  108. package/dist/src/mcpl/server-connection.d.ts +89 -10
  109. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  110. package/dist/src/mcpl/server-connection.js +405 -129
  111. package/dist/src/mcpl/server-connection.js.map +1 -1
  112. package/dist/src/mcpl/server-registry.d.ts +10 -1
  113. package/dist/src/mcpl/server-registry.d.ts.map +1 -1
  114. package/dist/src/mcpl/server-registry.js +14 -3
  115. package/dist/src/mcpl/server-registry.js.map +1 -1
  116. package/dist/src/mcpl/skip-reply-wake.d.ts +36 -0
  117. package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -0
  118. package/dist/src/mcpl/skip-reply-wake.js +55 -0
  119. package/dist/src/mcpl/skip-reply-wake.js.map +1 -0
  120. package/dist/src/mcpl/transport.d.ts +51 -2
  121. package/dist/src/mcpl/transport.d.ts.map +1 -1
  122. package/dist/src/mcpl/transport.js +114 -20
  123. package/dist/src/mcpl/transport.js.map +1 -1
  124. package/dist/src/mcpl/types.d.ts +14 -3
  125. package/dist/src/mcpl/types.d.ts.map +1 -1
  126. package/dist/src/mcpl/types.js.map +1 -1
  127. package/dist/src/mcpl/visible-content.d.ts +15 -0
  128. package/dist/src/mcpl/visible-content.d.ts.map +1 -1
  129. package/dist/src/mcpl/visible-content.js +25 -0
  130. package/dist/src/mcpl/visible-content.js.map +1 -1
  131. package/dist/src/module-registry.d.ts +19 -1
  132. package/dist/src/module-registry.d.ts.map +1 -1
  133. package/dist/src/module-registry.js +54 -25
  134. package/dist/src/module-registry.js.map +1 -1
  135. package/dist/src/modules/api/index.js +1 -1
  136. package/dist/src/modules/api/index.js.map +1 -1
  137. package/dist/src/modules/discord/discord-js-client.d.ts +1 -0
  138. package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -1
  139. package/dist/src/modules/discord/discord-js-client.js +25 -9
  140. package/dist/src/modules/discord/discord-js-client.js.map +1 -1
  141. package/dist/src/modules/discord/index.d.ts +29 -3
  142. package/dist/src/modules/discord/index.d.ts.map +1 -1
  143. package/dist/src/modules/discord/index.js +379 -143
  144. package/dist/src/modules/discord/index.js.map +1 -1
  145. package/dist/src/modules/discord/types.d.ts +14 -1
  146. package/dist/src/modules/discord/types.d.ts.map +1 -1
  147. package/dist/src/modules/health/index.d.ts.map +1 -1
  148. package/dist/src/modules/health/index.js +2 -1
  149. package/dist/src/modules/health/index.js.map +1 -1
  150. package/dist/src/modules/history/index.d.ts +3 -1
  151. package/dist/src/modules/history/index.d.ts.map +1 -1
  152. package/dist/src/modules/history/index.js +359 -127
  153. package/dist/src/modules/history/index.js.map +1 -1
  154. package/dist/src/modules/history/semantic.d.ts +28 -1
  155. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  156. package/dist/src/modules/history/semantic.js +177 -32
  157. package/dist/src/modules/history/semantic.js.map +1 -1
  158. package/dist/src/modules/unknown-tool.d.ts +10 -0
  159. package/dist/src/modules/unknown-tool.d.ts.map +1 -0
  160. package/dist/src/modules/unknown-tool.js +17 -0
  161. package/dist/src/modules/unknown-tool.js.map +1 -0
  162. package/dist/src/modules/workspace/disk-agreement.d.ts +32 -2
  163. package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
  164. package/dist/src/modules/workspace/disk-agreement.js +30 -2
  165. package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
  166. package/dist/src/modules/workspace/effects.d.ts +64 -6
  167. package/dist/src/modules/workspace/effects.d.ts.map +1 -1
  168. package/dist/src/modules/workspace/effects.js +291 -44
  169. package/dist/src/modules/workspace/effects.js.map +1 -1
  170. package/dist/src/modules/workspace/index.d.ts +119 -23
  171. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  172. package/dist/src/modules/workspace/index.js +793 -247
  173. package/dist/src/modules/workspace/index.js.map +1 -1
  174. package/dist/src/modules/workspace/observe.d.ts +75 -8
  175. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  176. package/dist/src/modules/workspace/observe.js +174 -14
  177. package/dist/src/modules/workspace/observe.js.map +1 -1
  178. package/dist/src/modules/workspace/reconcile.d.ts +58 -7
  179. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  180. package/dist/src/modules/workspace/reconcile.js +521 -56
  181. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  182. package/dist/src/modules/workspace/types.d.ts +18 -4
  183. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  184. package/dist/src/modules/workspace/types.js.map +1 -1
  185. package/dist/src/modules/workspace/watcher.d.ts +7 -2
  186. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  187. package/dist/src/modules/workspace/watcher.js +28 -4
  188. package/dist/src/modules/workspace/watcher.js.map +1 -1
  189. package/dist/src/prose-drafts.d.ts +240 -0
  190. package/dist/src/prose-drafts.d.ts.map +1 -0
  191. package/dist/src/prose-drafts.js +362 -0
  192. package/dist/src/prose-drafts.js.map +1 -0
  193. package/dist/src/prose-segments.d.ts +21 -2
  194. package/dist/src/prose-segments.d.ts.map +1 -1
  195. package/dist/src/prose-segments.js +46 -9
  196. package/dist/src/prose-segments.js.map +1 -1
  197. package/dist/src/recovery/offline-branch.d.ts +1 -0
  198. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  199. package/dist/src/recovery/offline-branch.js +3 -1
  200. package/dist/src/recovery/offline-branch.js.map +1 -1
  201. package/dist/src/safe-slice.d.ts +5 -1
  202. package/dist/src/safe-slice.d.ts.map +1 -1
  203. package/dist/src/safe-slice.js +9 -1
  204. package/dist/src/safe-slice.js.map +1 -1
  205. package/dist/src/thinking-token-stamp.d.ts +12 -0
  206. package/dist/src/thinking-token-stamp.d.ts.map +1 -1
  207. package/dist/src/thinking-token-stamp.js +34 -3
  208. package/dist/src/thinking-token-stamp.js.map +1 -1
  209. package/dist/src/tool-image-ledger.d.ts +87 -19
  210. package/dist/src/tool-image-ledger.d.ts.map +1 -1
  211. package/dist/src/tool-image-ledger.js +135 -32
  212. package/dist/src/tool-image-ledger.js.map +1 -1
  213. package/dist/src/tool-presentation.d.ts +9 -0
  214. package/dist/src/tool-presentation.d.ts.map +1 -1
  215. package/dist/src/tool-presentation.js +257 -60
  216. package/dist/src/tool-presentation.js.map +1 -1
  217. package/dist/src/tool-result-guard.d.ts.map +1 -1
  218. package/dist/src/tool-result-guard.js +7 -10
  219. package/dist/src/tool-result-guard.js.map +1 -1
  220. package/dist/src/tool-result-history.d.ts +32 -3
  221. package/dist/src/tool-result-history.d.ts.map +1 -1
  222. package/dist/src/tool-result-history.js +106 -19
  223. package/dist/src/tool-result-history.js.map +1 -1
  224. package/dist/src/tune-out/coordinator.d.ts +25 -1
  225. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  226. package/dist/src/tune-out/coordinator.js +260 -65
  227. package/dist/src/tune-out/coordinator.js.map +1 -1
  228. package/dist/src/types/agent.d.ts +17 -5
  229. package/dist/src/types/agent.d.ts.map +1 -1
  230. package/dist/src/types/events.d.ts +17 -0
  231. package/dist/src/types/events.d.ts.map +1 -1
  232. package/dist/src/types/framework.d.ts +21 -5
  233. package/dist/src/types/framework.d.ts.map +1 -1
  234. package/dist/src/types/inference-log.d.ts +1 -1
  235. package/dist/src/types/inference-log.d.ts.map +1 -1
  236. package/dist/src/types/module.d.ts +23 -4
  237. package/dist/src/types/module.d.ts.map +1 -1
  238. package/dist/src/types/trace.d.ts +95 -6
  239. package/dist/src/types/trace.d.ts.map +1 -1
  240. package/dist/src/usage/usage-tracker.d.ts +5 -0
  241. package/dist/src/usage/usage-tracker.d.ts.map +1 -1
  242. package/dist/src/usage/usage-tracker.js +35 -8
  243. package/dist/src/usage/usage-tracker.js.map +1 -1
  244. package/package.json +6 -4
  245. package/src/agent.ts +169 -41
  246. package/src/api/mcp-server-core.ts +1 -1
  247. package/src/api/server.ts +4 -1
  248. package/src/api/types.ts +1 -1
  249. package/src/branch-names.ts +19 -0
  250. package/src/closest-names.ts +94 -0
  251. package/src/code-execution/py-runner.ts +200 -76
  252. package/src/code-execution/runtime-py.ts +49 -3
  253. package/src/code-execution/tool-definition.ts +28 -4
  254. package/src/config-checks.ts +48 -0
  255. package/src/deadline-timer.ts +44 -0
  256. package/src/error-message.ts +48 -0
  257. package/src/framework.ts +5352 -1388
  258. package/src/gate/event-gate.ts +28 -3
  259. package/src/index.ts +11 -2
  260. package/src/mcpl/channel-registry.ts +517 -286
  261. package/src/mcpl/checkpoint-manager.ts +104 -29
  262. package/src/mcpl/conversation-router.ts +28 -8
  263. package/src/mcpl/convert-block.ts +97 -0
  264. package/src/mcpl/errors.ts +28 -0
  265. package/src/mcpl/hook-orchestrator.ts +84 -77
  266. package/src/mcpl/inbound-source.ts +156 -0
  267. package/src/mcpl/index.ts +10 -1
  268. package/src/mcpl/inference-router.ts +174 -99
  269. package/src/mcpl/push-coalescer.ts +60 -24
  270. package/src/mcpl/push-handler.ts +20 -90
  271. package/src/mcpl/reference-fetcher.ts +71 -26
  272. package/src/mcpl/references.ts +81 -22
  273. package/src/mcpl/server-connection.ts +427 -132
  274. package/src/mcpl/server-registry.ts +15 -4
  275. package/src/mcpl/skip-reply-wake.ts +73 -0
  276. package/src/mcpl/transport.ts +120 -18
  277. package/src/mcpl/types.ts +14 -3
  278. package/src/mcpl/visible-content.ts +27 -0
  279. package/src/module-registry.ts +58 -23
  280. package/src/modules/api/index.ts +1 -1
  281. package/src/modules/discord/discord-js-client.ts +26 -10
  282. package/src/modules/discord/index.ts +391 -158
  283. package/src/modules/discord/types.ts +15 -2
  284. package/src/modules/health/index.ts +2 -1
  285. package/src/modules/history/index.ts +410 -120
  286. package/src/modules/history/semantic.ts +189 -32
  287. package/src/modules/unknown-tool.ts +16 -0
  288. package/src/modules/workspace/disk-agreement.ts +51 -3
  289. package/src/modules/workspace/effects.ts +279 -35
  290. package/src/modules/workspace/index.ts +810 -260
  291. package/src/modules/workspace/observe.ts +194 -20
  292. package/src/modules/workspace/reconcile.ts +619 -64
  293. package/src/modules/workspace/types.ts +18 -4
  294. package/src/modules/workspace/watcher.ts +27 -4
  295. package/src/prose-drafts.ts +481 -0
  296. package/src/prose-segments.ts +51 -8
  297. package/src/recovery/offline-branch.ts +4 -1
  298. package/src/safe-slice.ts +9 -1
  299. package/src/thinking-token-stamp.ts +34 -3
  300. package/src/tool-image-ledger.ts +153 -34
  301. package/src/tool-presentation.ts +224 -40
  302. package/src/tool-result-guard.ts +7 -8
  303. package/src/tool-result-history.ts +124 -20
  304. package/src/tune-out/coordinator.ts +259 -65
  305. package/src/types/agent.ts +17 -7
  306. package/src/types/events.ts +17 -0
  307. package/src/types/framework.ts +21 -5
  308. package/src/types/inference-log.ts +1 -1
  309. package/src/types/module.ts +24 -4
  310. package/src/types/trace.ts +101 -6
  311. package/src/usage/usage-tracker.ts +32 -8
  312. package/dist/test/activation-request-sanitize.test.d.ts +0 -2
  313. package/dist/test/activation-request-sanitize.test.d.ts.map +0 -1
  314. package/dist/test/activation-request-sanitize.test.js +0 -89
  315. package/dist/test/activation-request-sanitize.test.js.map +0 -1
  316. package/dist/test/agent-cache-ttl.test.d.ts +0 -2
  317. package/dist/test/agent-cache-ttl.test.d.ts.map +0 -1
  318. package/dist/test/agent-cache-ttl.test.js +0 -41
  319. package/dist/test/agent-cache-ttl.test.js.map +0 -1
  320. package/dist/test/agent-runtime-settings.test.d.ts +0 -2
  321. package/dist/test/agent-runtime-settings.test.d.ts.map +0 -1
  322. package/dist/test/agent-runtime-settings.test.js +0 -1598
  323. package/dist/test/agent-runtime-settings.test.js.map +0 -1
  324. package/dist/test/api-admin-gate.test.d.ts +0 -2
  325. package/dist/test/api-admin-gate.test.d.ts.map +0 -1
  326. package/dist/test/api-admin-gate.test.js +0 -116
  327. package/dist/test/api-admin-gate.test.js.map +0 -1
  328. package/dist/test/assistant-persist-refusal.test.d.ts +0 -2
  329. package/dist/test/assistant-persist-refusal.test.d.ts.map +0 -1
  330. package/dist/test/assistant-persist-refusal.test.js +0 -63
  331. package/dist/test/assistant-persist-refusal.test.js.map +0 -1
  332. package/dist/test/batched-wake-locus.test.d.ts +0 -2
  333. package/dist/test/batched-wake-locus.test.d.ts.map +0 -1
  334. package/dist/test/batched-wake-locus.test.js +0 -166
  335. package/dist/test/batched-wake-locus.test.js.map +0 -1
  336. package/dist/test/busy-agent-scheduler.test.d.ts +0 -2
  337. package/dist/test/busy-agent-scheduler.test.d.ts.map +0 -1
  338. package/dist/test/busy-agent-scheduler.test.js +0 -92
  339. package/dist/test/busy-agent-scheduler.test.js.map +0 -1
  340. package/dist/test/channel-incoming-targeting.test.d.ts +0 -2
  341. package/dist/test/channel-incoming-targeting.test.d.ts.map +0 -1
  342. package/dist/test/channel-incoming-targeting.test.js +0 -81
  343. package/dist/test/channel-incoming-targeting.test.js.map +0 -1
  344. package/dist/test/channel-label-history.test.d.ts +0 -2
  345. package/dist/test/channel-label-history.test.d.ts.map +0 -1
  346. package/dist/test/channel-label-history.test.js +0 -424
  347. package/dist/test/channel-label-history.test.js.map +0 -1
  348. package/dist/test/channel-lifecycle-provenance.test.d.ts +0 -2
  349. package/dist/test/channel-lifecycle-provenance.test.d.ts.map +0 -1
  350. package/dist/test/channel-lifecycle-provenance.test.js +0 -47
  351. package/dist/test/channel-lifecycle-provenance.test.js.map +0 -1
  352. package/dist/test/channel-registry-routing.test.d.ts +0 -2
  353. package/dist/test/channel-registry-routing.test.d.ts.map +0 -1
  354. package/dist/test/channel-registry-routing.test.js +0 -446
  355. package/dist/test/channel-registry-routing.test.js.map +0 -1
  356. package/dist/test/channel-registry-typing.test.d.ts +0 -2
  357. package/dist/test/channel-registry-typing.test.d.ts.map +0 -1
  358. package/dist/test/channel-registry-typing.test.js +0 -91
  359. package/dist/test/channel-registry-typing.test.js.map +0 -1
  360. package/dist/test/channels-changed-respond-first.test.d.ts +0 -2
  361. package/dist/test/channels-changed-respond-first.test.d.ts.map +0 -1
  362. package/dist/test/channels-changed-respond-first.test.js +0 -74
  363. package/dist/test/channels-changed-respond-first.test.js.map +0 -1
  364. package/dist/test/checkpoint-attribution.test.d.ts +0 -2
  365. package/dist/test/checkpoint-attribution.test.d.ts.map +0 -1
  366. package/dist/test/checkpoint-attribution.test.js +0 -200
  367. package/dist/test/checkpoint-attribution.test.js.map +0 -1
  368. package/dist/test/code-execution.test.d.ts +0 -11
  369. package/dist/test/code-execution.test.d.ts.map +0 -1
  370. package/dist/test/code-execution.test.js +0 -1272
  371. package/dist/test/code-execution.test.js.map +0 -1
  372. package/dist/test/component-defaults.test.d.ts +0 -2
  373. package/dist/test/component-defaults.test.d.ts.map +0 -1
  374. package/dist/test/component-defaults.test.js +0 -54
  375. package/dist/test/component-defaults.test.js.map +0 -1
  376. package/dist/test/conversation-fork-injection-scoping.test.d.ts +0 -2
  377. package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +0 -1
  378. package/dist/test/conversation-fork-injection-scoping.test.js +0 -200
  379. package/dist/test/conversation-fork-injection-scoping.test.js.map +0 -1
  380. package/dist/test/conversation-router.test.d.ts +0 -2
  381. package/dist/test/conversation-router.test.d.ts.map +0 -1
  382. package/dist/test/conversation-router.test.js +0 -174
  383. package/dist/test/conversation-router.test.js.map +0 -1
  384. package/dist/test/conversation-routing.test.d.ts +0 -7
  385. package/dist/test/conversation-routing.test.d.ts.map +0 -1
  386. package/dist/test/conversation-routing.test.js +0 -621
  387. package/dist/test/conversation-routing.test.js.map +0 -1
  388. package/dist/test/deferred-wake-integrity.test.d.ts +0 -29
  389. package/dist/test/deferred-wake-integrity.test.d.ts.map +0 -1
  390. package/dist/test/deferred-wake-integrity.test.js +0 -320
  391. package/dist/test/deferred-wake-integrity.test.js.map +0 -1
  392. package/dist/test/discord-awareness-outbox.test.d.ts +0 -2
  393. package/dist/test/discord-awareness-outbox.test.d.ts.map +0 -1
  394. package/dist/test/discord-awareness-outbox.test.js +0 -371
  395. package/dist/test/discord-awareness-outbox.test.js.map +0 -1
  396. package/dist/test/discord-history-delete-window.test.d.ts +0 -2
  397. package/dist/test/discord-history-delete-window.test.d.ts.map +0 -1
  398. package/dist/test/discord-history-delete-window.test.js +0 -81
  399. package/dist/test/discord-history-delete-window.test.js.map +0 -1
  400. package/dist/test/discord-history-sync.test.d.ts +0 -2
  401. package/dist/test/discord-history-sync.test.d.ts.map +0 -1
  402. package/dist/test/discord-history-sync.test.js +0 -56
  403. package/dist/test/discord-history-sync.test.js.map +0 -1
  404. package/dist/test/discord-typing-keepalive.test.d.ts +0 -2
  405. package/dist/test/discord-typing-keepalive.test.d.ts.map +0 -1
  406. package/dist/test/discord-typing-keepalive.test.js +0 -77
  407. package/dist/test/discord-typing-keepalive.test.js.map +0 -1
  408. package/dist/test/ephemeral-settle.test.d.ts +0 -2
  409. package/dist/test/ephemeral-settle.test.d.ts.map +0 -1
  410. package/dist/test/ephemeral-settle.test.js +0 -354
  411. package/dist/test/ephemeral-settle.test.js.map +0 -1
  412. package/dist/test/event-gate-passthrough.test.d.ts +0 -15
  413. package/dist/test/event-gate-passthrough.test.d.ts.map +0 -1
  414. package/dist/test/event-gate-passthrough.test.js +0 -289
  415. package/dist/test/event-gate-passthrough.test.js.map +0 -1
  416. package/dist/test/event-gate-policy-mutation.test.d.ts +0 -2
  417. package/dist/test/event-gate-policy-mutation.test.d.ts.map +0 -1
  418. package/dist/test/event-gate-policy-mutation.test.js +0 -137
  419. package/dist/test/event-gate-policy-mutation.test.js.map +0 -1
  420. package/dist/test/event-gate-rate-limit.test.d.ts +0 -2
  421. package/dist/test/event-gate-rate-limit.test.d.ts.map +0 -1
  422. package/dist/test/event-gate-rate-limit.test.js +0 -627
  423. package/dist/test/event-gate-rate-limit.test.js.map +0 -1
  424. package/dist/test/event-gate-script.test.d.ts +0 -2
  425. package/dist/test/event-gate-script.test.d.ts.map +0 -1
  426. package/dist/test/event-gate-script.test.js +0 -95
  427. package/dist/test/event-gate-script.test.js.map +0 -1
  428. package/dist/test/event-gate-selfwake.test.d.ts +0 -15
  429. package/dist/test/event-gate-selfwake.test.d.ts.map +0 -1
  430. package/dist/test/event-gate-selfwake.test.js +0 -125
  431. package/dist/test/event-gate-selfwake.test.js.map +0 -1
  432. package/dist/test/event-gate-tags.test.d.ts +0 -2
  433. package/dist/test/event-gate-tags.test.d.ts.map +0 -1
  434. package/dist/test/event-gate-tags.test.js +0 -76
  435. package/dist/test/event-gate-tags.test.js.map +0 -1
  436. package/dist/test/event-gate.test.d.ts +0 -2
  437. package/dist/test/event-gate.test.d.ts.map +0 -1
  438. package/dist/test/event-gate.test.js +0 -919
  439. package/dist/test/event-gate.test.js.map +0 -1
  440. package/dist/test/explicit-prose-routing.test.d.ts +0 -11
  441. package/dist/test/explicit-prose-routing.test.d.ts.map +0 -1
  442. package/dist/test/explicit-prose-routing.test.js +0 -1715
  443. package/dist/test/explicit-prose-routing.test.js.map +0 -1
  444. package/dist/test/framework.test.d.ts +0 -5
  445. package/dist/test/framework.test.d.ts.map +0 -1
  446. package/dist/test/framework.test.js +0 -1048
  447. package/dist/test/framework.test.js.map +0 -1
  448. package/dist/test/gather-context-timeout.test.d.ts +0 -2
  449. package/dist/test/gather-context-timeout.test.d.ts.map +0 -1
  450. package/dist/test/gather-context-timeout.test.js +0 -120
  451. package/dist/test/gather-context-timeout.test.js.map +0 -1
  452. package/dist/test/health-snapshot.test.d.ts +0 -2
  453. package/dist/test/health-snapshot.test.d.ts.map +0 -1
  454. package/dist/test/health-snapshot.test.js +0 -74
  455. package/dist/test/health-snapshot.test.js.map +0 -1
  456. package/dist/test/helpers/coalescing-fixture.d.ts +0 -74
  457. package/dist/test/helpers/coalescing-fixture.d.ts.map +0 -1
  458. package/dist/test/helpers/coalescing-fixture.js +0 -152
  459. package/dist/test/helpers/coalescing-fixture.js.map +0 -1
  460. package/dist/test/helpers/coalescing-kill-child.d.ts +0 -2
  461. package/dist/test/helpers/coalescing-kill-child.d.ts.map +0 -1
  462. package/dist/test/helpers/coalescing-kill-child.js +0 -24
  463. package/dist/test/helpers/coalescing-kill-child.js.map +0 -1
  464. package/dist/test/helpers/mock-membrane.d.ts +0 -53
  465. package/dist/test/helpers/mock-membrane.d.ts.map +0 -1
  466. package/dist/test/helpers/mock-membrane.js +0 -168
  467. package/dist/test/helpers/mock-membrane.js.map +0 -1
  468. package/dist/test/helpers/pytc-stop-rows.d.ts +0 -11
  469. package/dist/test/helpers/pytc-stop-rows.d.ts.map +0 -1
  470. package/dist/test/helpers/pytc-stop-rows.js +0 -143
  471. package/dist/test/helpers/pytc-stop-rows.js.map +0 -1
  472. package/dist/test/helpers/quiesce-crash-child.d.ts +0 -2
  473. package/dist/test/helpers/quiesce-crash-child.d.ts.map +0 -1
  474. package/dist/test/helpers/quiesce-crash-child.js +0 -156
  475. package/dist/test/helpers/quiesce-crash-child.js.map +0 -1
  476. package/dist/test/hide-then-turn.test.d.ts +0 -2
  477. package/dist/test/hide-then-turn.test.d.ts.map +0 -1
  478. package/dist/test/hide-then-turn.test.js +0 -101
  479. package/dist/test/hide-then-turn.test.js.map +0 -1
  480. package/dist/test/history-module-overview.test.d.ts +0 -2
  481. package/dist/test/history-module-overview.test.d.ts.map +0 -1
  482. package/dist/test/history-module-overview.test.js +0 -711
  483. package/dist/test/history-module-overview.test.js.map +0 -1
  484. package/dist/test/history-module-realstore.test.d.ts +0 -2
  485. package/dist/test/history-module-realstore.test.d.ts.map +0 -1
  486. package/dist/test/history-module-realstore.test.js +0 -363
  487. package/dist/test/history-module-realstore.test.js.map +0 -1
  488. package/dist/test/history-module-semantic.test.d.ts +0 -2
  489. package/dist/test/history-module-semantic.test.d.ts.map +0 -1
  490. package/dist/test/history-module-semantic.test.js +0 -213
  491. package/dist/test/history-module-semantic.test.js.map +0 -1
  492. package/dist/test/history-module-ux.test.d.ts +0 -2
  493. package/dist/test/history-module-ux.test.d.ts.map +0 -1
  494. package/dist/test/history-module-ux.test.js +0 -304
  495. package/dist/test/history-module-ux.test.js.map +0 -1
  496. package/dist/test/history-module.test.d.ts +0 -2
  497. package/dist/test/history-module.test.d.ts.map +0 -1
  498. package/dist/test/history-module.test.js +0 -619
  499. package/dist/test/history-module.test.js.map +0 -1
  500. package/dist/test/history-semantic-review-findings.test.d.ts +0 -2
  501. package/dist/test/history-semantic-review-findings.test.d.ts.map +0 -1
  502. package/dist/test/history-semantic-review-findings.test.js +0 -338
  503. package/dist/test/history-semantic-review-findings.test.js.map +0 -1
  504. package/dist/test/history-semantic-sync-converges.test.d.ts +0 -2
  505. package/dist/test/history-semantic-sync-converges.test.d.ts.map +0 -1
  506. package/dist/test/history-semantic-sync-converges.test.js +0 -109
  507. package/dist/test/history-semantic-sync-converges.test.js.map +0 -1
  508. package/dist/test/host-quiesce.test.d.ts +0 -2
  509. package/dist/test/host-quiesce.test.d.ts.map +0 -1
  510. package/dist/test/host-quiesce.test.js +0 -988
  511. package/dist/test/host-quiesce.test.js.map +0 -1
  512. package/dist/test/inference-exhaustion-rewind.test.d.ts +0 -2
  513. package/dist/test/inference-exhaustion-rewind.test.d.ts.map +0 -1
  514. package/dist/test/inference-exhaustion-rewind.test.js +0 -387
  515. package/dist/test/inference-exhaustion-rewind.test.js.map +0 -1
  516. package/dist/test/inference-failure-bounds.test.d.ts +0 -2
  517. package/dist/test/inference-failure-bounds.test.d.ts.map +0 -1
  518. package/dist/test/inference-failure-bounds.test.js +0 -1202
  519. package/dist/test/inference-failure-bounds.test.js.map +0 -1
  520. package/dist/test/inference-failure-observability.test.d.ts +0 -2
  521. package/dist/test/inference-failure-observability.test.d.ts.map +0 -1
  522. package/dist/test/inference-failure-observability.test.js +0 -84
  523. package/dist/test/inference-failure-observability.test.js.map +0 -1
  524. package/dist/test/journal-tool.test.d.ts +0 -2
  525. package/dist/test/journal-tool.test.d.ts.map +0 -1
  526. package/dist/test/journal-tool.test.js +0 -33
  527. package/dist/test/journal-tool.test.js.map +0 -1
  528. package/dist/test/kv-unified-open-flight-retry.test.d.ts +0 -2
  529. package/dist/test/kv-unified-open-flight-retry.test.d.ts.map +0 -1
  530. package/dist/test/kv-unified-open-flight-retry.test.js +0 -189
  531. package/dist/test/kv-unified-open-flight-retry.test.js.map +0 -1
  532. package/dist/test/kv-unified-wiring.test.d.ts +0 -2
  533. package/dist/test/kv-unified-wiring.test.d.ts.map +0 -1
  534. package/dist/test/kv-unified-wiring.test.js +0 -95
  535. package/dist/test/kv-unified-wiring.test.js.map +0 -1
  536. package/dist/test/late-events-after-stop.test.d.ts +0 -2
  537. package/dist/test/late-events-after-stop.test.d.ts.map +0 -1
  538. package/dist/test/late-events-after-stop.test.js +0 -122
  539. package/dist/test/late-events-after-stop.test.js.map +0 -1
  540. package/dist/test/liveness-watchdog.test.d.ts +0 -2
  541. package/dist/test/liveness-watchdog.test.d.ts.map +0 -1
  542. package/dist/test/liveness-watchdog.test.js +0 -94
  543. package/dist/test/liveness-watchdog.test.js.map +0 -1
  544. package/dist/test/machine-close-provenance.test.d.ts +0 -2
  545. package/dist/test/machine-close-provenance.test.d.ts.map +0 -1
  546. package/dist/test/machine-close-provenance.test.js +0 -116
  547. package/dist/test/machine-close-provenance.test.js.map +0 -1
  548. package/dist/test/maintenance-timer.test.d.ts +0 -2
  549. package/dist/test/maintenance-timer.test.d.ts.map +0 -1
  550. package/dist/test/maintenance-timer.test.js +0 -1827
  551. package/dist/test/maintenance-timer.test.js.map +0 -1
  552. package/dist/test/mcp-server-bin.test.d.ts +0 -2
  553. package/dist/test/mcp-server-bin.test.d.ts.map +0 -1
  554. package/dist/test/mcp-server-bin.test.js +0 -142
  555. package/dist/test/mcp-server-bin.test.js.map +0 -1
  556. package/dist/test/mcpl-access-provider.test.d.ts +0 -2
  557. package/dist/test/mcpl-access-provider.test.d.ts.map +0 -1
  558. package/dist/test/mcpl-access-provider.test.js +0 -20
  559. package/dist/test/mcpl-access-provider.test.js.map +0 -1
  560. package/dist/test/mcpl-awareness-barrier.test.d.ts +0 -2
  561. package/dist/test/mcpl-awareness-barrier.test.d.ts.map +0 -1
  562. package/dist/test/mcpl-awareness-barrier.test.js +0 -769
  563. package/dist/test/mcpl-awareness-barrier.test.js.map +0 -1
  564. package/dist/test/mcpl-capability-grant.test.d.ts +0 -10
  565. package/dist/test/mcpl-capability-grant.test.d.ts.map +0 -1
  566. package/dist/test/mcpl-capability-grant.test.js +0 -111
  567. package/dist/test/mcpl-capability-grant.test.js.map +0 -1
  568. package/dist/test/mcpl-capability-scoping.test.d.ts +0 -2
  569. package/dist/test/mcpl-capability-scoping.test.d.ts.map +0 -1
  570. package/dist/test/mcpl-capability-scoping.test.js +0 -266
  571. package/dist/test/mcpl-capability-scoping.test.js.map +0 -1
  572. package/dist/test/mcpl-child-env.test.d.ts +0 -2
  573. package/dist/test/mcpl-child-env.test.d.ts.map +0 -1
  574. package/dist/test/mcpl-child-env.test.js +0 -158
  575. package/dist/test/mcpl-child-env.test.js.map +0 -1
  576. package/dist/test/mcpl-coalesced-content-parity.test.d.ts +0 -2
  577. package/dist/test/mcpl-coalesced-content-parity.test.d.ts.map +0 -1
  578. package/dist/test/mcpl-coalesced-content-parity.test.js +0 -532
  579. package/dist/test/mcpl-coalesced-content-parity.test.js.map +0 -1
  580. package/dist/test/mcpl-coalescing.test.d.ts +0 -2
  581. package/dist/test/mcpl-coalescing.test.d.ts.map +0 -1
  582. package/dist/test/mcpl-coalescing.test.js +0 -1125
  583. package/dist/test/mcpl-coalescing.test.js.map +0 -1
  584. package/dist/test/mcpl-config-diagnostics.test.d.ts +0 -2
  585. package/dist/test/mcpl-config-diagnostics.test.d.ts.map +0 -1
  586. package/dist/test/mcpl-config-diagnostics.test.js +0 -452
  587. package/dist/test/mcpl-config-diagnostics.test.js.map +0 -1
  588. package/dist/test/mcpl-empty-content.test.d.ts +0 -2
  589. package/dist/test/mcpl-empty-content.test.d.ts.map +0 -1
  590. package/dist/test/mcpl-empty-content.test.js +0 -368
  591. package/dist/test/mcpl-empty-content.test.js.map +0 -1
  592. package/dist/test/mcpl-gate-roundtrip.test.d.ts +0 -2
  593. package/dist/test/mcpl-gate-roundtrip.test.d.ts.map +0 -1
  594. package/dist/test/mcpl-gate-roundtrip.test.js +0 -285
  595. package/dist/test/mcpl-gate-roundtrip.test.js.map +0 -1
  596. package/dist/test/mcpl-list-status.test.d.ts +0 -2
  597. package/dist/test/mcpl-list-status.test.d.ts.map +0 -1
  598. package/dist/test/mcpl-list-status.test.js +0 -82
  599. package/dist/test/mcpl-list-status.test.js.map +0 -1
  600. package/dist/test/mcpl-manifest-changed.test.d.ts +0 -2
  601. package/dist/test/mcpl-manifest-changed.test.d.ts.map +0 -1
  602. package/dist/test/mcpl-manifest-changed.test.js +0 -178
  603. package/dist/test/mcpl-manifest-changed.test.js.map +0 -1
  604. package/dist/test/mcpl-push-convert.test.d.ts +0 -2
  605. package/dist/test/mcpl-push-convert.test.d.ts.map +0 -1
  606. package/dist/test/mcpl-push-convert.test.js +0 -42
  607. package/dist/test/mcpl-push-convert.test.js.map +0 -1
  608. package/dist/test/mcpl-reconnect-events.test.d.ts +0 -2
  609. package/dist/test/mcpl-reconnect-events.test.d.ts.map +0 -1
  610. package/dist/test/mcpl-reconnect-events.test.js +0 -144
  611. package/dist/test/mcpl-reconnect-events.test.js.map +0 -1
  612. package/dist/test/mcpl-reconnect-reregistration.test.d.ts +0 -2
  613. package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +0 -1
  614. package/dist/test/mcpl-reconnect-reregistration.test.js +0 -238
  615. package/dist/test/mcpl-reconnect-reregistration.test.js.map +0 -1
  616. package/dist/test/mcpl-reference-fetcher.test.d.ts +0 -2
  617. package/dist/test/mcpl-reference-fetcher.test.d.ts.map +0 -1
  618. package/dist/test/mcpl-reference-fetcher.test.js +0 -427
  619. package/dist/test/mcpl-reference-fetcher.test.js.map +0 -1
  620. package/dist/test/mcpl-reference-fields.test.d.ts +0 -2
  621. package/dist/test/mcpl-reference-fields.test.d.ts.map +0 -1
  622. package/dist/test/mcpl-reference-fields.test.js +0 -149
  623. package/dist/test/mcpl-reference-fields.test.js.map +0 -1
  624. package/dist/test/mcpl-rejection-log-lines.test.d.ts +0 -2
  625. package/dist/test/mcpl-rejection-log-lines.test.d.ts.map +0 -1
  626. package/dist/test/mcpl-rejection-log-lines.test.js +0 -349
  627. package/dist/test/mcpl-rejection-log-lines.test.js.map +0 -1
  628. package/dist/test/mcpl-request-timeout.test.d.ts +0 -2
  629. package/dist/test/mcpl-request-timeout.test.d.ts.map +0 -1
  630. package/dist/test/mcpl-request-timeout.test.js +0 -138
  631. package/dist/test/mcpl-request-timeout.test.js.map +0 -1
  632. package/dist/test/mcpl-runtime-lifecycle.test.d.ts +0 -7
  633. package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +0 -1
  634. package/dist/test/mcpl-runtime-lifecycle.test.js +0 -142
  635. package/dist/test/mcpl-runtime-lifecycle.test.js.map +0 -1
  636. package/dist/test/mcpl-stderr-tail.test.d.ts +0 -2
  637. package/dist/test/mcpl-stderr-tail.test.d.ts.map +0 -1
  638. package/dist/test/mcpl-stderr-tail.test.js +0 -210
  639. package/dist/test/mcpl-stderr-tail.test.js.map +0 -1
  640. package/dist/test/mcpl-tool-class-listing.test.d.ts +0 -2
  641. package/dist/test/mcpl-tool-class-listing.test.d.ts.map +0 -1
  642. package/dist/test/mcpl-tool-class-listing.test.js +0 -147
  643. package/dist/test/mcpl-tool-class-listing.test.js.map +0 -1
  644. package/dist/test/mcpl-tool-classes.test.d.ts +0 -7
  645. package/dist/test/mcpl-tool-classes.test.d.ts.map +0 -1
  646. package/dist/test/mcpl-tool-classes.test.js +0 -80
  647. package/dist/test/mcpl-tool-classes.test.js.map +0 -1
  648. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts +0 -2
  649. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts.map +0 -1
  650. package/dist/test/mcpl-tool-lifecycle-e2e.test.js +0 -237
  651. package/dist/test/mcpl-tool-lifecycle-e2e.test.js.map +0 -1
  652. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts +0 -11
  653. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts.map +0 -1
  654. package/dist/test/mcpl-tool-lifecycle-emitter.test.js +0 -412
  655. package/dist/test/mcpl-tool-lifecycle-emitter.test.js.map +0 -1
  656. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts +0 -2
  657. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts.map +0 -1
  658. package/dist/test/mcpl-tool-lifecycle-script.test.js +0 -288
  659. package/dist/test/mcpl-tool-lifecycle-script.test.js.map +0 -1
  660. package/dist/test/mcpl-tool-lifecycle.test.d.ts +0 -11
  661. package/dist/test/mcpl-tool-lifecycle.test.d.ts.map +0 -1
  662. package/dist/test/mcpl-tool-lifecycle.test.js +0 -270
  663. package/dist/test/mcpl-tool-lifecycle.test.js.map +0 -1
  664. package/dist/test/mcpl-transport-close.test.d.ts +0 -2
  665. package/dist/test/mcpl-transport-close.test.d.ts.map +0 -1
  666. package/dist/test/mcpl-transport-close.test.js +0 -373
  667. package/dist/test/mcpl-transport-close.test.js.map +0 -1
  668. package/dist/test/mcpl-transport-spawn.test.d.ts +0 -2
  669. package/dist/test/mcpl-transport-spawn.test.d.ts.map +0 -1
  670. package/dist/test/mcpl-transport-spawn.test.js +0 -58
  671. package/dist/test/mcpl-transport-spawn.test.js.map +0 -1
  672. package/dist/test/mcpl-ws-transport.test.d.ts +0 -2
  673. package/dist/test/mcpl-ws-transport.test.d.ts.map +0 -1
  674. package/dist/test/mcpl-ws-transport.test.js +0 -259
  675. package/dist/test/mcpl-ws-transport.test.js.map +0 -1
  676. package/dist/test/module-context-integration.test.d.ts +0 -18
  677. package/dist/test/module-context-integration.test.d.ts.map +0 -1
  678. package/dist/test/module-context-integration.test.js +0 -181
  679. package/dist/test/module-context-integration.test.js.map +0 -1
  680. package/dist/test/offline-recovery-branch.test.d.ts +0 -2
  681. package/dist/test/offline-recovery-branch.test.d.ts.map +0 -1
  682. package/dist/test/offline-recovery-branch.test.js +0 -570
  683. package/dist/test/offline-recovery-branch.test.js.map +0 -1
  684. package/dist/test/operator-surgery.test.d.ts +0 -2
  685. package/dist/test/operator-surgery.test.d.ts.map +0 -1
  686. package/dist/test/operator-surgery.test.js +0 -595
  687. package/dist/test/operator-surgery.test.js.map +0 -1
  688. package/dist/test/ops-alert.test.d.ts +0 -2
  689. package/dist/test/ops-alert.test.d.ts.map +0 -1
  690. package/dist/test/ops-alert.test.js +0 -153
  691. package/dist/test/ops-alert.test.js.map +0 -1
  692. package/dist/test/overbudget-drain-breaker.test.d.ts +0 -2
  693. package/dist/test/overbudget-drain-breaker.test.d.ts.map +0 -1
  694. package/dist/test/overbudget-drain-breaker.test.js +0 -198
  695. package/dist/test/overbudget-drain-breaker.test.js.map +0 -1
  696. package/dist/test/pack-installs-alone.test.d.ts +0 -2
  697. package/dist/test/pack-installs-alone.test.d.ts.map +0 -1
  698. package/dist/test/pack-installs-alone.test.js +0 -284
  699. package/dist/test/pack-installs-alone.test.js.map +0 -1
  700. package/dist/test/per-agent-delivery.test.d.ts +0 -2
  701. package/dist/test/per-agent-delivery.test.d.ts.map +0 -1
  702. package/dist/test/per-agent-delivery.test.js +0 -108
  703. package/dist/test/per-agent-delivery.test.js.map +0 -1
  704. package/dist/test/physical-window-restart.test.d.ts +0 -16
  705. package/dist/test/physical-window-restart.test.d.ts.map +0 -1
  706. package/dist/test/physical-window-restart.test.js +0 -487
  707. package/dist/test/physical-window-restart.test.js.map +0 -1
  708. package/dist/test/placed-reaction-baseline.test.d.ts +0 -2
  709. package/dist/test/placed-reaction-baseline.test.d.ts.map +0 -1
  710. package/dist/test/placed-reaction-baseline.test.js +0 -312
  711. package/dist/test/placed-reaction-baseline.test.js.map +0 -1
  712. package/dist/test/present-while-acting.test.d.ts +0 -19
  713. package/dist/test/present-while-acting.test.d.ts.map +0 -1
  714. package/dist/test/present-while-acting.test.js +0 -1649
  715. package/dist/test/present-while-acting.test.js.map +0 -1
  716. package/dist/test/prose-segments.test.d.ts +0 -2
  717. package/dist/test/prose-segments.test.d.ts.map +0 -1
  718. package/dist/test/prose-segments.test.js +0 -52
  719. package/dist/test/prose-segments.test.js.map +0 -1
  720. package/dist/test/prose-stream-router.test.d.ts +0 -2
  721. package/dist/test/prose-stream-router.test.d.ts.map +0 -1
  722. package/dist/test/prose-stream-router.test.js +0 -171
  723. package/dist/test/prose-stream-router.test.js.map +0 -1
  724. package/dist/test/provider-acceleration-cooldown.test.d.ts +0 -2
  725. package/dist/test/provider-acceleration-cooldown.test.d.ts.map +0 -1
  726. package/dist/test/provider-acceleration-cooldown.test.js +0 -435
  727. package/dist/test/provider-acceleration-cooldown.test.js.map +0 -1
  728. package/dist/test/provider-waits.test.d.ts +0 -2
  729. package/dist/test/provider-waits.test.d.ts.map +0 -1
  730. package/dist/test/provider-waits.test.js +0 -2259
  731. package/dist/test/provider-waits.test.js.map +0 -1
  732. package/dist/test/puppet-tool-call.test.d.ts +0 -2
  733. package/dist/test/puppet-tool-call.test.d.ts.map +0 -1
  734. package/dist/test/puppet-tool-call.test.js +0 -226
  735. package/dist/test/puppet-tool-call.test.js.map +0 -1
  736. package/dist/test/puppet-turn-reservation.test.d.ts +0 -2
  737. package/dist/test/puppet-turn-reservation.test.d.ts.map +0 -1
  738. package/dist/test/puppet-turn-reservation.test.js +0 -139
  739. package/dist/test/puppet-turn-reservation.test.js.map +0 -1
  740. package/dist/test/reaction-baseline-platform.test.d.ts +0 -2
  741. package/dist/test/reaction-baseline-platform.test.d.ts.map +0 -1
  742. package/dist/test/reaction-baseline-platform.test.js +0 -124
  743. package/dist/test/reaction-baseline-platform.test.js.map +0 -1
  744. package/dist/test/record-journal.test.d.ts +0 -6
  745. package/dist/test/record-journal.test.d.ts.map +0 -1
  746. package/dist/test/record-journal.test.js +0 -269
  747. package/dist/test/record-journal.test.js.map +0 -1
  748. package/dist/test/refusal-reaction-baseline.test.d.ts +0 -2
  749. package/dist/test/refusal-reaction-baseline.test.d.ts.map +0 -1
  750. package/dist/test/refusal-reaction-baseline.test.js +0 -81
  751. package/dist/test/refusal-reaction-baseline.test.js.map +0 -1
  752. package/dist/test/refusal-rewind.test.d.ts +0 -2
  753. package/dist/test/refusal-rewind.test.d.ts.map +0 -1
  754. package/dist/test/refusal-rewind.test.js +0 -117
  755. package/dist/test/refusal-rewind.test.js.map +0 -1
  756. package/dist/test/refusal-single-call.test.d.ts +0 -2
  757. package/dist/test/refusal-single-call.test.d.ts.map +0 -1
  758. package/dist/test/refusal-single-call.test.js +0 -177
  759. package/dist/test/refusal-single-call.test.js.map +0 -1
  760. package/dist/test/release-bump.test.d.ts +0 -2
  761. package/dist/test/release-bump.test.d.ts.map +0 -1
  762. package/dist/test/release-bump.test.js +0 -248
  763. package/dist/test/release-bump.test.js.map +0 -1
  764. package/dist/test/release-changelog.test.d.ts +0 -2
  765. package/dist/test/release-changelog.test.d.ts.map +0 -1
  766. package/dist/test/release-changelog.test.js +0 -159
  767. package/dist/test/release-changelog.test.js.map +0 -1
  768. package/dist/test/release-holds.test.d.ts +0 -2
  769. package/dist/test/release-holds.test.d.ts.map +0 -1
  770. package/dist/test/release-holds.test.js +0 -456
  771. package/dist/test/release-holds.test.js.map +0 -1
  772. package/dist/test/same-round-think-policy.test.d.ts +0 -2
  773. package/dist/test/same-round-think-policy.test.d.ts.map +0 -1
  774. package/dist/test/same-round-think-policy.test.js +0 -853
  775. package/dist/test/same-round-think-policy.test.js.map +0 -1
  776. package/dist/test/save-recent-image.test.d.ts +0 -26
  777. package/dist/test/save-recent-image.test.d.ts.map +0 -1
  778. package/dist/test/save-recent-image.test.js +0 -974
  779. package/dist/test/save-recent-image.test.js.map +0 -1
  780. package/dist/test/shutdown-errors.test.d.ts +0 -2
  781. package/dist/test/shutdown-errors.test.d.ts.map +0 -1
  782. package/dist/test/shutdown-errors.test.js +0 -662
  783. package/dist/test/shutdown-errors.test.js.map +0 -1
  784. package/dist/test/silent-heartbeat-rows.test.d.ts +0 -2
  785. package/dist/test/silent-heartbeat-rows.test.d.ts.map +0 -1
  786. package/dist/test/silent-heartbeat-rows.test.js +0 -451
  787. package/dist/test/silent-heartbeat-rows.test.js.map +0 -1
  788. package/dist/test/silent-heartbeat.test.d.ts +0 -2
  789. package/dist/test/silent-heartbeat.test.d.ts.map +0 -1
  790. package/dist/test/silent-heartbeat.test.js +0 -165
  791. package/dist/test/silent-heartbeat.test.js.map +0 -1
  792. package/dist/test/state-scaling-e2e.test.d.ts +0 -22
  793. package/dist/test/state-scaling-e2e.test.d.ts.map +0 -1
  794. package/dist/test/state-scaling-e2e.test.js +0 -206
  795. package/dist/test/state-scaling-e2e.test.js.map +0 -1
  796. package/dist/test/state-scaling.test.d.ts +0 -12
  797. package/dist/test/state-scaling.test.d.ts.map +0 -1
  798. package/dist/test/state-scaling.test.js +0 -251
  799. package/dist/test/state-scaling.test.js.map +0 -1
  800. package/dist/test/stop-with-host-operations.test.d.ts +0 -20
  801. package/dist/test/stop-with-host-operations.test.d.ts.map +0 -1
  802. package/dist/test/stop-with-host-operations.test.js +0 -1174
  803. package/dist/test/stop-with-host-operations.test.js.map +0 -1
  804. package/dist/test/stop-with-work-in-flight.test.d.ts +0 -23
  805. package/dist/test/stop-with-work-in-flight.test.d.ts.map +0 -1
  806. package/dist/test/stop-with-work-in-flight.test.js +0 -784
  807. package/dist/test/stop-with-work-in-flight.test.js.map +0 -1
  808. package/dist/test/surgery-marks-receipt.test.d.ts +0 -2
  809. package/dist/test/surgery-marks-receipt.test.d.ts.map +0 -1
  810. package/dist/test/surgery-marks-receipt.test.js +0 -540
  811. package/dist/test/surgery-marks-receipt.test.js.map +0 -1
  812. package/dist/test/thinking-token-stamp.test.d.ts +0 -12
  813. package/dist/test/thinking-token-stamp.test.d.ts.map +0 -1
  814. package/dist/test/thinking-token-stamp.test.js +0 -129
  815. package/dist/test/thinking-token-stamp.test.js.map +0 -1
  816. package/dist/test/timezone.test.d.ts +0 -2
  817. package/dist/test/timezone.test.d.ts.map +0 -1
  818. package/dist/test/timezone.test.js +0 -18
  819. package/dist/test/timezone.test.js.map +0 -1
  820. package/dist/test/tool-batch-hook.test.d.ts +0 -8
  821. package/dist/test/tool-batch-hook.test.d.ts.map +0 -1
  822. package/dist/test/tool-batch-hook.test.js +0 -275
  823. package/dist/test/tool-batch-hook.test.js.map +0 -1
  824. package/dist/test/tool-policy.test.d.ts +0 -2
  825. package/dist/test/tool-policy.test.d.ts.map +0 -1
  826. package/dist/test/tool-policy.test.js +0 -51
  827. package/dist/test/tool-policy.test.js.map +0 -1
  828. package/dist/test/tool-presentation.test.d.ts +0 -2
  829. package/dist/test/tool-presentation.test.d.ts.map +0 -1
  830. package/dist/test/tool-presentation.test.js +0 -268
  831. package/dist/test/tool-presentation.test.js.map +0 -1
  832. package/dist/test/tool-result-content.test.d.ts +0 -2
  833. package/dist/test/tool-result-content.test.d.ts.map +0 -1
  834. package/dist/test/tool-result-content.test.js +0 -37
  835. package/dist/test/tool-result-content.test.js.map +0 -1
  836. package/dist/test/tool-result-guard.test.d.ts +0 -2
  837. package/dist/test/tool-result-guard.test.d.ts.map +0 -1
  838. package/dist/test/tool-result-guard.test.js +0 -3729
  839. package/dist/test/tool-result-guard.test.js.map +0 -1
  840. package/dist/test/tool-result-history.test.d.ts +0 -7
  841. package/dist/test/tool-result-history.test.d.ts.map +0 -1
  842. package/dist/test/tool-result-history.test.js +0 -156
  843. package/dist/test/tool-result-history.test.js.map +0 -1
  844. package/dist/test/tool-result-spill.test.d.ts +0 -13
  845. package/dist/test/tool-result-spill.test.d.ts.map +0 -1
  846. package/dist/test/tool-result-spill.test.js +0 -586
  847. package/dist/test/tool-result-spill.test.js.map +0 -1
  848. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts +0 -2
  849. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts.map +0 -1
  850. package/dist/test/tool-wrapper-prose-guard-integration.test.js +0 -485
  851. package/dist/test/tool-wrapper-prose-guard-integration.test.js.map +0 -1
  852. package/dist/test/tool-wrapper-prose-guard.test.d.ts +0 -2
  853. package/dist/test/tool-wrapper-prose-guard.test.d.ts.map +0 -1
  854. package/dist/test/tool-wrapper-prose-guard.test.js +0 -34
  855. package/dist/test/tool-wrapper-prose-guard.test.js.map +0 -1
  856. package/dist/test/tools-observe-parser-conformance.test.d.ts +0 -2
  857. package/dist/test/tools-observe-parser-conformance.test.d.ts.map +0 -1
  858. package/dist/test/tools-observe-parser-conformance.test.js +0 -129
  859. package/dist/test/tools-observe-parser-conformance.test.js.map +0 -1
  860. package/dist/test/trunk-channel-routing.test.d.ts +0 -19
  861. package/dist/test/trunk-channel-routing.test.d.ts.map +0 -1
  862. package/dist/test/trunk-channel-routing.test.js +0 -652
  863. package/dist/test/trunk-channel-routing.test.js.map +0 -1
  864. package/dist/test/tune-out-e2e.test.d.ts +0 -2
  865. package/dist/test/tune-out-e2e.test.d.ts.map +0 -1
  866. package/dist/test/tune-out-e2e.test.js +0 -142
  867. package/dist/test/tune-out-e2e.test.js.map +0 -1
  868. package/dist/test/tune-out-gate-composition.test.d.ts +0 -2
  869. package/dist/test/tune-out-gate-composition.test.d.ts.map +0 -1
  870. package/dist/test/tune-out-gate-composition.test.js +0 -221
  871. package/dist/test/tune-out-gate-composition.test.js.map +0 -1
  872. package/dist/test/tune-out-lifecycle.test.d.ts +0 -2
  873. package/dist/test/tune-out-lifecycle.test.d.ts.map +0 -1
  874. package/dist/test/tune-out-lifecycle.test.js +0 -121
  875. package/dist/test/tune-out-lifecycle.test.js.map +0 -1
  876. package/dist/test/turn-trigger-provenance.test.d.ts +0 -2
  877. package/dist/test/turn-trigger-provenance.test.d.ts.map +0 -1
  878. package/dist/test/turn-trigger-provenance.test.js +0 -137
  879. package/dist/test/turn-trigger-provenance.test.js.map +0 -1
  880. package/dist/test/unconvertible-tool-result.test.d.ts +0 -2
  881. package/dist/test/unconvertible-tool-result.test.d.ts.map +0 -1
  882. package/dist/test/unconvertible-tool-result.test.js +0 -358
  883. package/dist/test/unconvertible-tool-result.test.js.map +0 -1
  884. package/dist/test/unsent-compiles.test.d.ts +0 -2
  885. package/dist/test/unsent-compiles.test.d.ts.map +0 -1
  886. package/dist/test/unsent-compiles.test.js +0 -139
  887. package/dist/test/unsent-compiles.test.js.map +0 -1
  888. package/dist/test/usage-accounting.test.d.ts +0 -2
  889. package/dist/test/usage-accounting.test.d.ts.map +0 -1
  890. package/dist/test/usage-accounting.test.js +0 -13
  891. package/dist/test/usage-accounting.test.js.map +0 -1
  892. package/dist/test/usage-tracker.test.d.ts +0 -2
  893. package/dist/test/usage-tracker.test.d.ts.map +0 -1
  894. package/dist/test/usage-tracker.test.js +0 -129
  895. package/dist/test/usage-tracker.test.js.map +0 -1
  896. package/dist/test/utils-surface.test.d.ts +0 -2
  897. package/dist/test/utils-surface.test.d.ts.map +0 -1
  898. package/dist/test/utils-surface.test.js +0 -145
  899. package/dist/test/utils-surface.test.js.map +0 -1
  900. package/dist/test/workspace-branch-continuation.test.d.ts +0 -15
  901. package/dist/test/workspace-branch-continuation.test.d.ts.map +0 -1
  902. package/dist/test/workspace-branch-continuation.test.js +0 -183
  903. package/dist/test/workspace-branch-continuation.test.js.map +0 -1
  904. package/dist/test/workspace-materialize-freshness.test.d.ts +0 -16
  905. package/dist/test/workspace-materialize-freshness.test.d.ts.map +0 -1
  906. package/dist/test/workspace-materialize-freshness.test.js +0 -252
  907. package/dist/test/workspace-materialize-freshness.test.js.map +0 -1
  908. package/dist/test/workspace-path-containment.test.d.ts +0 -19
  909. package/dist/test/workspace-path-containment.test.d.ts.map +0 -1
  910. package/dist/test/workspace-path-containment.test.js +0 -91
  911. package/dist/test/workspace-path-containment.test.js.map +0 -1
  912. package/dist/test/workspace-read-file-from-disk.test.d.ts +0 -17
  913. package/dist/test/workspace-read-file-from-disk.test.d.ts.map +0 -1
  914. package/dist/test/workspace-read-file-from-disk.test.js +0 -174
  915. package/dist/test/workspace-read-file-from-disk.test.js.map +0 -1
  916. package/dist/test/workspace-read-image.test.d.ts +0 -2
  917. package/dist/test/workspace-read-image.test.d.ts.map +0 -1
  918. package/dist/test/workspace-read-image.test.js +0 -597
  919. package/dist/test/workspace-read-image.test.js.map +0 -1
  920. package/dist/test/workspace-read-text.test.d.ts +0 -2
  921. package/dist/test/workspace-read-text.test.d.ts.map +0 -1
  922. package/dist/test/workspace-read-text.test.js +0 -101
  923. package/dist/test/workspace-read-text.test.js.map +0 -1
  924. package/dist/test/workspace-restore-order.test.d.ts +0 -16
  925. package/dist/test/workspace-restore-order.test.d.ts.map +0 -1
  926. package/dist/test/workspace-restore-order.test.js +0 -140
  927. package/dist/test/workspace-restore-order.test.js.map +0 -1
  928. package/dist/test/workspace-three-way.test.d.ts +0 -12
  929. package/dist/test/workspace-three-way.test.d.ts.map +0 -1
  930. package/dist/test/workspace-three-way.test.js +0 -4094
  931. package/dist/test/workspace-three-way.test.js.map +0 -1
  932. package/dist/test/workspace-watcher.test.d.ts +0 -2
  933. package/dist/test/workspace-watcher.test.d.ts.map +0 -1
  934. package/dist/test/workspace-watcher.test.js +0 -281
  935. package/dist/test/workspace-watcher.test.js.map +0 -1
  936. package/dist/test/xml-round-persist.test.d.ts +0 -19
  937. package/dist/test/xml-round-persist.test.d.ts.map +0 -1
  938. package/dist/test/xml-round-persist.test.js +0 -235
  939. package/dist/test/xml-round-persist.test.js.map +0 -1
  940. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -38,8 +38,8 @@
38
38
  * a wrong adoption.
39
39
  */
40
40
  import { candidateOf, sameCandidate, sameRootIdentity, } from './disk-agreement.js';
41
- import { ROOT_REPLACED, fingerprintVouches, locateRoot, looksBinary, observePath, provenAbsent, readHead, readPath, sniffImageMime, walkScope, } from './observe.js';
42
- import { EffectFailed, chainOf, syncDirectories, unlinkContained, writeContained } from './effects.js';
41
+ import { IGNORED, OTHER_MOUNT, ROOT_REPLACED, fingerprintVouches, ignoreBeneath, inOtherMount, locateRoot, looksBinary, observePath, passedOverAt, passedOverBetween, provenAbsent, readHead, readPath, sniffImageMime, walkScope, } from './observe.js';
42
+ import { EffectFailed, chainOf, chmodContained, narrowedTo, syncDirectories, unlinkContained, writeContained } from './effects.js';
43
43
  const ABSENT = { kind: 'absent' };
44
44
  export const WALK_CAP = 5000;
45
45
  function diskCandidate(d) {
@@ -52,7 +52,58 @@ function diskCandidate(d) {
52
52
  function agreedFromDisk(d) {
53
53
  if (d.kind !== 'file')
54
54
  return { kind: 'absent' };
55
- return { kind: 'content', hash: d.hash, size: d.size, ...(d.fp ? { fp: d.fp } : {}) };
55
+ return { kind: 'content', hash: d.hash, size: d.size, ...(d.mode !== undefined ? { mode: d.mode } : {}), ...(d.fp ? { fp: d.fp } : {}) };
56
+ }
57
+ /** The file-type bits git records with a regular file's mode. */
58
+ const REGULAR_FILE = 0o100000;
59
+ /** A tree entry's mode for permission bits: with the regular-file type bits, as git records one. */
60
+ export function treeMode(perm) {
61
+ return REGULAR_FILE | (perm & 0o777);
62
+ }
63
+ /**
64
+ * The mode a tree entry takes for disk's permission bits, or, where disk's
65
+ * aren't observed, the entry's own. With neither, the placeholder an entry
66
+ * without a recorded mode has (see entryMode).
67
+ */
68
+ function treeModeOf(perm, s) {
69
+ if (perm !== undefined)
70
+ return { mode: treeMode(perm) };
71
+ if (s?.mode !== undefined)
72
+ return { mode: treeMode(s.mode) };
73
+ return { mode: 0o644 };
74
+ }
75
+ /**
76
+ * The permission bits a tree entry records, or undefined when it records
77
+ * none. An entry without the file-type bits was written before modes were
78
+ * recorded, which wrote 0o644 whatever disk had: a placeholder, not a mode.
79
+ */
80
+ export function entryMode(mode) {
81
+ return (mode & 0o170000) === REGULAR_FILE ? mode & 0o777 : undefined;
82
+ }
83
+ /** The store's side of a tree entry. */
84
+ export function storeSide(entry) {
85
+ if (!entry)
86
+ return null;
87
+ const mode = entryMode(entry.mode);
88
+ return { hash: entry.blobHash, size: entry.size, ...(mode !== undefined ? { mode } : {}) };
89
+ }
90
+ /**
91
+ * Where disk and the store hold the same bytes, what their modes ask for.
92
+ * A mode the store doesn't record agrees with any, and takes disk's
93
+ * (`fill`). The store's mode goes to disk (`push`) only where the evidence
94
+ * shows disk still has the mode they last agreed on; otherwise disk's mode
95
+ * is taken in as a change (`adopt`): disk changed it, or nothing says which
96
+ * side did, and an unknown never moves disk.
97
+ */
98
+ function modeAction(disk, store, agreed) {
99
+ if (store === undefined)
100
+ return 'fill';
101
+ if (store === disk)
102
+ return undefined;
103
+ return agreed !== undefined && agreed === disk ? 'push' : 'adopt';
104
+ }
105
+ function octal(mode) {
106
+ return `0${mode.toString(8).padStart(3, '0')}`;
56
107
  }
57
108
  function inScope(path, scope) {
58
109
  if (scope.kind === 'paths')
@@ -76,7 +127,7 @@ async function learnDisk(mount, path, tracked, opts) {
76
127
  const p = tracked.p;
77
128
  const trusted = (fp) => mount.ctimeTrustedDev !== null && fp.dev === mount.ctimeTrustedDev;
78
129
  if (!opts.rehash && p?.kind === 'content' && fingerprintVouches(p.fp, seen.fp, trusted(seen.fp))) {
79
- return { kind: 'file', hash: p.hash, size: seen.size, mtimeMs: seen.mtimeMs, fp: p.fp ?? null, ingestible: null };
130
+ return { kind: 'file', hash: p.hash, size: seen.size, mtimeMs: seen.mtimeMs, ...(mount.modesObserved ? { mode: seen.mode } : {}), fp: p.fp ?? null, ingestible: null };
80
131
  }
81
132
  const nothingTracked = p === undefined && !tracked.hasStore && !tracked.hasIntent;
82
133
  if (nothingTracked && seen.size > mount.view.maxFileSize) {
@@ -96,6 +147,7 @@ async function learnDisk(mount, path, tracked, opts) {
96
147
  hash: read.hash,
97
148
  size: read.size,
98
149
  mtimeMs: read.mtimeMs,
150
+ ...(mount.modesObserved ? { mode: read.mode } : {}),
99
151
  // A fingerprint is recorded only where it can later vouch for the bytes.
100
152
  fp: trusted(read.fp) ? read.fp : null,
101
153
  ingestible,
@@ -129,10 +181,66 @@ function keepStoreSide(hasStore, bi) {
129
181
  function settleAdoption(p, s) {
130
182
  const sc = s ? { kind: 'content', hash: s.hash } : ABSENT;
131
183
  if (sameCandidate(sc, p.expect)) {
132
- return p.expect.kind === 'absent' ? { kind: 'absent' } : { kind: 'content', hash: p.expect.hash, size: s.size };
184
+ // Where modes are observed, the adoption took disk's mode with its bytes,
185
+ // so the entry's mode is the one they agreed on, but for an adoption that
186
+ // took the mode a stopped push of ours meant the old bytes to have: its
187
+ // entry holds that mode while disk holds the push's narrowed one, which a
188
+ // later sync then takes in. Where modes aren't observed, the entry's mode
189
+ // is the store's own, and the evidence records none.
190
+ return p.expect.kind === 'absent'
191
+ ? { kind: 'absent' }
192
+ : { kind: 'content', hash: p.expect.hash, size: s.size, ...(s.mode !== undefined ? { mode: s.mode } : {}) };
133
193
  }
134
194
  return p.prior ?? 'forget';
135
195
  }
196
+ /**
197
+ * What's in the way, and the way out, when disk's shape keeps a push from a
198
+ * path: no push writes a file over a directory or unlinks one, unlinks
199
+ * anything but a regular file or a followed symlink to one, or writes below
200
+ * a file or a symlink the walk won't take (`writeContained`,
201
+ * `unlinkContained`), forced or not. Null for any other reason, which is
202
+ * passed on as it is.
203
+ */
204
+ function inTheWay(reason, deletion) {
205
+ // Observation's words for what a deletion never unlinks, which the unlink
206
+ // refuses in the same words.
207
+ if (deletion && (reason === 'not a regular file' || reason === 'a symlink to a directory, not walked')) {
208
+ const what = reason === 'not a regular file'
209
+ ? 'a pipe, socket or device at this path, or a symlink to one'
210
+ : 'a symlink to a directory at this path';
211
+ return `disk has ${what}, and no push unlinks it, forced or not — ask whoever runs this host if it should go`;
212
+ }
213
+ if (reason === 'a directory') {
214
+ return deletion
215
+ ? 'disk has a directory at this path, and no push unlinks one, forced or not — if it should go, move or remove it on disk'
216
+ : 'disk has a directory at this path, and no push writes a file over one, forced or not — ' +
217
+ 'move or remove that directory on disk and materialize again, or write the file under another path';
218
+ }
219
+ // A deletion below a file finds nothing there to unlink, so only a write
220
+ // meets this one.
221
+ if (reason === 'a parent path is not a directory') {
222
+ return 'disk has a file or a symlink where this path needs a directory, and no push writes below one, forced or not — ' +
223
+ 'move or remove it on disk and materialize again, or write the file under another path';
224
+ }
225
+ return null;
226
+ }
227
+ /**
228
+ * The forced way out the refusal of a disk copy that couldn't be verified
229
+ * names, if any. A forced push skips the verification, so it gets past the
230
+ * note only where its effect can go on. A file the module can't read (EACCES)
231
+ * is overwritten, or unlinked, where disk lets the workspace write it, or
232
+ * unlink it, which a read's EACCES doesn't show: force is named on that
233
+ * condition. No other note names force: a forced push stops at some (a
234
+ * symlink the mount doesn't follow, what isn't a regular file, a parent it
235
+ * can't use); another writer still at the file ("the file changed while it
236
+ * was read") is answered by materializing again; and the rest aren't known
237
+ * to pass.
238
+ */
239
+ function forcedWay(note, deletion, forced) {
240
+ if (note === 'cannot open (EACCES)')
241
+ return `, or, if disk lets the workspace ${deletion ? 'unlink' : 'write'} the file, ${forced}`;
242
+ return '';
243
+ }
136
244
  /**
137
245
  * The synchronous precondition of every workspace mutation: evidence owed a
138
246
  * barrier is made durable first, and an adoption left pending on the
@@ -151,13 +259,32 @@ export function settleAdoptionBeforeMutation(store, agreement, mount, path) {
151
259
  if (p?.kind !== 'pending' || p.effect !== 'adopt' || p.branchId !== store.currentBranch().id)
152
260
  return;
153
261
  const entry = store.treeGet(mount.treeStateId, path);
154
- const settled = settleAdoption(p, entry ? { hash: entry.blobHash, size: entry.size } : null);
262
+ const settled = settleAdoption(p, entry ? { hash: entry.blobHash, size: entry.size, ...(entryMode(entry.mode) !== undefined ? { mode: entryMode(entry.mode) } : {}) } : null);
155
263
  if (settled === 'forget')
156
264
  agreement.forget(mount.name, path);
157
265
  else
158
266
  agreement.set(mount.name, path, settled, { afterCommittedState: true });
159
267
  agreement.barrier();
160
268
  }
269
+ /**
270
+ * What a push of ours that stopped partway left on disk, read by its own
271
+ * modes (Pending's `modes`): the new bytes at `from & to` or `to` were meant
272
+ * to have `to`; the old bytes at `from & to`, narrower than `from`, still
273
+ * have `from` as theirs. New bytes at `from` are a push's only where
274
+ * `from & to` is `from`: a push that narrows does so before its bytes, so
275
+ * otherwise they were given `from` since. Undefined where disk shows
276
+ * anything else: no push of ours, or a mode set since it stopped.
277
+ */
278
+ function pushedMode(p, dc, d) {
279
+ const m = p.modes;
280
+ if (p.effect !== 'disk' || m === undefined || d.kind !== 'file' || d.mode === undefined)
281
+ return undefined;
282
+ const narrowed = m.from & m.to;
283
+ if (sameCandidate(dc, p.expect))
284
+ return d.mode === narrowed || d.mode === m.to ? m.to : undefined;
285
+ const prior = p.prior ? candidateOf(p.prior) : null;
286
+ return prior && sameCandidate(dc, prior) && narrowed !== m.from && d.mode === narrowed ? m.from : undefined;
287
+ }
161
288
  /**
162
289
  * Resolve a pending intent against what was observed. Returns the evidence
163
290
  * the rule should use, and whether that resolution should be recorded.
@@ -169,11 +296,24 @@ function resolvePending(p, dc, s, d, branchId) {
169
296
  if (sameCandidate(dc, p.expect)) {
170
297
  // Our own effect shows on disk, but nothing proves it durable: decided
171
298
  // on, never recorded. Only a push whose barriers succeed completes it.
299
+ // Where disk's mode is one of the push's own, the push that completes
300
+ // it gives the store's mode there.
172
301
  const shown = p.expect.kind === 'absent' ? { kind: 'absent' } : agreedFromDisk(d);
173
- return { p: shown, unconfirmed: true };
302
+ return { p: shown, unconfirmed: true, ...(pushedMode(p, dc, d) !== undefined ? { ownMode: true } : {}) };
174
303
  }
175
- if (priorCandidate && sameCandidate(dc, priorCandidate))
304
+ if (priorCandidate && sameCandidate(dc, priorCandidate)) {
305
+ // The push narrowed the mode and stopped before its bytes: disk's mode
306
+ // is the push's, so the rule decides from it, and the next push writes
307
+ // the bytes at it and then widens to the store's. The old bytes are
308
+ // never given the store's mode. Nothing is recorded: the intent, with
309
+ // the modes that map disk's narrowed one back to the old bytes' own,
310
+ // stays, carried by a push that goes on with it (pushPaths), until a
311
+ // push completes it or a sync adopts disk's copy.
312
+ if (prior.kind === 'content' && d.kind === 'file' && pushedMode(p, dc, d) !== undefined) {
313
+ return { p: { ...prior, mode: d.mode } };
314
+ }
176
315
  return { p: prior, record: prior };
316
+ }
177
317
  // A write whose prior was unknown left no file: it never created one (a
178
318
  // partial write leaves a file behind), so P is as unknown as before.
179
319
  if (!prior && dc.kind === 'absent' && p.expect.kind === 'content')
@@ -210,9 +350,12 @@ function adoptDisk(d, s) {
210
350
  return { state: 'synced', ...(s ? { adopt: 'remove', op: 'deleted' } : {}), p: { kind: 'absent' }, intent: {} };
211
351
  }
212
352
  // Disk agreeing with the store is disk's state already, whatever the file
213
- // is: a binary or oversize file the workspace holds stays held.
214
- if (s && s.hash === d.hash)
215
- return { state: 'synced', p: agreedFromDisk(d), intent: {} };
353
+ // is: a binary or oversize file the workspace holds stays held. Its mode
354
+ // is disk's too.
355
+ if (s && s.hash === d.hash) {
356
+ const mode = d.mode === undefined ? undefined : s.mode === undefined ? 'fill' : s.mode !== d.mode ? 'adopt' : undefined;
357
+ return { state: 'synced', p: agreedFromDisk(d), intent: {}, ...(mode ? { mode } : {}), ...(mode === 'adopt' ? { op: 'modified' } : {}) };
358
+ }
216
359
  if (d.ingestible)
217
360
  return { state: 'synced', adopt: 'ingest', op: s ? 'modified' : 'created', p: agreedFromDisk(d), intent: {} };
218
361
  return { state: 'disk-only', ...(s ? { adopt: 'drop', op: 'deleted' } : {}), p: 'forget', intent: {} };
@@ -243,12 +386,22 @@ function decide(d, s, pIn, bi, branchId, adopt) {
243
386
  if (adopt) {
244
387
  // What a path sync gives up is exactly what a sync without a path would
245
388
  // have kept of the workspace's own (a draft, a deletion, a conflict's
246
- // workspace side), and the verdict says which.
247
- const taken = adoptDisk(d, s);
389
+ // workspace side), and the verdict says which. Where a push of ours
390
+ // stopped partway, disk's mode is the push's: the store takes the one
391
+ // the push meant those bytes to have, and the evidence keeps disk's, so
392
+ // a later push moves disk there.
393
+ const meant = pIn?.kind === 'pending' ? pushedMode(pIn, dc, d) : undefined;
394
+ const taken = adoptDisk(meant === undefined ? d : { ...d, mode: meant }, s);
395
+ if (meant !== undefined) {
396
+ if (taken.p !== undefined && taken.p !== 'forget' && taken.p.kind === 'content')
397
+ taken.p = agreedFromDisk(d);
398
+ if (taken.adopt === 'ingest' || taken.mode !== undefined)
399
+ taken.diskMode = meant;
400
+ }
248
401
  // A give-up is an adoption, or the intent it clears: a deletion or a
249
402
  // conflict given up for a disk copy the workspace can't hold changes no
250
403
  // tree entry, and is listed all the same.
251
- if (taken.adopt || (bi && taken.intent !== undefined)) {
404
+ if (taken.adopt || taken.mode === 'adopt' || (bi && taken.intent !== undefined)) {
252
405
  const kept = decide(d, s, pIn, bi, branchId, false);
253
406
  if (WORKSPACE_KEPT.has(kept.state))
254
407
  taken.discards = kept.state;
@@ -261,6 +414,9 @@ function decide(d, s, pIn, bi, branchId, adopt) {
261
414
  // verdict below records newer evidence.
262
415
  let p = pIn;
263
416
  let resolution;
417
+ // Evidence a resolution decides from without recording it: a stopped
418
+ // push's narrowing, whose intent stays (resolvePending).
419
+ let unrecorded;
264
420
  let uncaptured = false;
265
421
  if (p?.kind === 'pending') {
266
422
  const resolved = resolvePending(p, dc, s, d, branchId);
@@ -269,13 +425,19 @@ function decide(d, s, pIn, bi, branchId, adopt) {
269
425
  // follows from that, and nothing is recorded — no completion, no
270
426
  // agreement, no branch-intent change — until a push confirms it.
271
427
  const state = sameCandidate(dc, sc) ? 'synced' : bi?.conflict ? 'conflict' : keepStoreSide(s !== null, bi);
272
- return { state, note: UNCONFIRMED_NOTE, unconfirmed: true };
428
+ return {
429
+ state, note: UNCONFIRMED_NOTE, unconfirmed: true,
430
+ ...(resolved.ownMode ? { ownMode: true } : {}),
431
+ };
273
432
  }
274
433
  p = resolved.p;
275
434
  resolution = resolved.record;
435
+ if (resolution === undefined && p !== undefined && (p.kind === 'content' || p.kind === 'absent'))
436
+ unrecorded = p;
276
437
  uncaptured = resolved.uncaptured === true;
277
438
  }
278
- const verdict = (v) => (resolution && v.p === undefined ? { ...v, p: resolution } : v);
439
+ const verdict = (v) => (resolution && v.p === undefined ? { ...v, p: resolution }
440
+ : unrecorded && v.p === undefined && v.prior === undefined ? { ...v, prior: unrecorded } : v);
279
441
  // Agreement settles everything, a recorded conflict included.
280
442
  if (sameCandidate(dc, sc)) {
281
443
  const settles = bi?.tombstone || bi?.conflict || bi?.origin ? { intent: {} } : {};
@@ -291,11 +453,23 @@ function decide(d, s, pIn, bi, branchId, adopt) {
291
453
  const recorded = p?.kind === 'content' ? p : null;
292
454
  // Re-record only when P says something else, or a fresh fingerprint can
293
455
  // replace one that no longer vouches. A fresh one exists only where it's
294
- // trusted, so both are judged as trusted here.
295
- const stale = !recorded || recorded.hash !== agreed.hash || recorded.size !== agreed.size ||
456
+ // trusted, so both are judged as trusted here. Evidence a resolution left
457
+ // unrecorded, a stopped push's narrowing, is stale too: the agreement
458
+ // replaces that push's intent, and the mode rule gives the store's mode.
459
+ const stale = unrecorded !== undefined || !recorded || recorded.hash !== agreed.hash || recorded.size !== agreed.size || recorded.mode !== agreed.mode ||
296
460
  (agreed.fp !== undefined && fingerprintVouches(agreed.fp, agreed.fp, true) &&
297
461
  !fingerprintVouches(recorded.fp, agreed.fp, true));
298
- return verdict({ state: 'synced', ...(stale ? { p: agreed } : {}), ...settles });
462
+ const mode = agreed.mode === undefined ? undefined : modeAction(agreed.mode, s.mode, recorded?.mode);
463
+ if (mode === 'push') {
464
+ return verdict({
465
+ state: 'workspace-draft',
466
+ mode,
467
+ note: `the workspace's mode (${octal(s.mode)}) differs from disk's (${octal(agreed.mode)}): materialize to apply it`,
468
+ ...(stale ? { p: agreed } : {}),
469
+ ...settles,
470
+ });
471
+ }
472
+ return verdict({ state: 'synced', ...(mode ? { mode } : {}), ...(mode === 'adopt' ? { op: 'modified' } : {}), ...(stale ? { p: agreed } : {}), ...settles });
299
473
  }
300
474
  // A recorded conflict stays until it is resolved explicitly or disk and store converge.
301
475
  if (bi?.conflict)
@@ -437,12 +611,43 @@ async function gather(store, agreement, mount, scope, opts) {
437
611
  gathered.facts.set(path, { kind: 'unobserved', reason: rootUnavailable });
438
612
  continue;
439
613
  }
614
+ // What the mount passes over by design stays unobserved by a pass that
615
+ // names no path, however it reaches it, so no listing's absence proves a
616
+ // copy there gone. In another mount's directory, no pass of this mount
617
+ // observes anything, named or not.
618
+ // Beneath a directory a by-design rule covers, a pass that isn't named
619
+ // observes nothing. A path a rule covers by its own name is observed as a
620
+ // walk observes it: passed over where the walk lists it, and absent where
621
+ // the walk lists its directory without it; a pass that reaches it by its
622
+ // path alone, as a listing, glob or grep naming it does, passes over it.
623
+ // A pass that names its scope, as a sync naming a path and a file tool's
624
+ // pass on the path it acts on do, sets aside only what covers the scope,
625
+ // at it or above it, as its walk does (#276): a directory passed over by
626
+ // design beneath a named directory stays passed over, and so does what
627
+ // lies beneath it.
628
+ let byDesign;
629
+ if (inOtherMount(path, mount.view.others)) {
630
+ byDesign = OTHER_MOUNT;
631
+ }
632
+ else if (!opts.named) {
633
+ const slash = path.lastIndexOf('/');
634
+ const above = slash < 0 ? undefined : passedOverAt(path.slice(0, slash), mount.view.ignore, mount.view.others);
635
+ const own = above === undefined && !walk ? passedOverAt(path, mount.view.ignore, mount.view.others) : undefined;
636
+ byDesign = above ?? own;
637
+ }
638
+ else if (scope.kind === 'dir') {
639
+ byDesign = passedOverBetween(scope.dir, path, ignoreBeneath(scope.dir, mount.view.ignore), mount.view.others);
640
+ }
641
+ if (byDesign !== undefined) {
642
+ gathered.facts.set(path, { kind: 'unobserved', reason: byDesign });
643
+ continue;
644
+ }
440
645
  if (walk && provenAbsent(walk, path)) {
441
646
  gathered.facts.set(path, { kind: 'absent' });
442
647
  continue;
443
648
  }
444
- if (walk?.others.get(path) === 'ignored by the mount') {
445
- gathered.facts.set(path, { kind: 'unobserved', reason: 'ignored by the mount' });
649
+ if (walk?.others.get(path) === IGNORED) {
650
+ gathered.facts.set(path, { kind: 'unobserved', reason: IGNORED });
446
651
  continue;
447
652
  }
448
653
  if (walk && !walk.files.has(path) && !walk.othersTaken.has(path)) {
@@ -527,8 +732,7 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
527
732
  result.branchId = branchId;
528
733
  const planned = [];
529
734
  for (const [path, d] of facts) {
530
- const entry = store.treeGet(mount.treeStateId, path);
531
- const s = entry ? { hash: entry.blobHash, size: entry.size } : null;
735
+ const s = storeSide(store.treeGet(mount.treeStateId, path));
532
736
  const p = agreement.get(mount.name, path);
533
737
  const bi = mount.intents.get(path);
534
738
  const verdict = decide(d, s, p, bi, branchId, opts.adopt?.(path) === true);
@@ -561,13 +765,20 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
561
765
  const v = x.verdict;
562
766
  if (v.adopt === 'ingest' && x.d.kind === 'file' && x.d.ingestible) {
563
767
  const blobHash = store.storeBlob(x.d.ingestible, 'text/plain');
564
- store.treeSet(mount.treeStateId, x.path, { blobHash, size: x.d.ingestible.byteLength, mode: 0o644 });
768
+ store.treeSet(mount.treeStateId, x.path, { blobHash, size: x.d.ingestible.byteLength, ...treeModeOf(v.diskMode ?? x.d.mode, x.s) });
565
769
  committed = true;
566
770
  }
567
771
  else if ((v.adopt === 'remove' || v.adopt === 'drop') && x.s) {
568
772
  store.treeRemove(mount.treeStateId, x.path);
569
773
  committed = true;
570
774
  }
775
+ else if ((v.mode === 'fill' || v.mode === 'adopt') && x.d.kind === 'file' && x.s) {
776
+ // The same bytes, with disk's mode. A fill records a mode where the
777
+ // entry had none, which is no change: an undo or a branch whose entry
778
+ // still has none agrees with any mode, so neither reads it as one.
779
+ store.treeSet(mount.treeStateId, x.path, { blobHash: x.s.hash, size: x.s.size, ...treeModeOf(v.diskMode ?? x.d.mode, x.s) });
780
+ committed = true;
781
+ }
571
782
  if (v.conflict) {
572
783
  const record = { kind: v.conflict, at: Date.now(), disk: counterpartOf(store, x.d) };
573
784
  mount.intents.update(x.path, (cur) => ({ ...cur, conflict: record }));
@@ -578,10 +789,11 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
578
789
  mount.intents.put(x.path, v.intent);
579
790
  committed = true;
580
791
  }
581
- if (v.op && v.adopt)
582
- result.ops.push({ path: x.path, op: v.op });
792
+ const changed = v.adopt !== undefined || v.mode === 'adopt';
793
+ if (v.op && changed)
794
+ result.ops.push({ path: x.path, op: v.op, ...(v.adopt === undefined ? { modeOnly: true } : {}) });
583
795
  if (v.discards)
584
- result.discarded.push({ path: x.path, was: v.discards, ...(v.op && v.adopt ? { op: v.op } : {}) });
796
+ result.discarded.push({ path: x.path, was: v.discards, ...(v.op && changed ? { op: v.op } : {}) });
585
797
  }
586
798
  // 4. Completions and agreements, after the commits they assert are synced —
587
799
  // this pass's, and any earlier tool write's an agreement rests on.
@@ -658,9 +870,17 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
658
870
  // A link's own region hides only what lies beneath it: the link itself
659
871
  // is reported by path, with its own reason.
660
872
  const hides = tracked.some((p) => (region.kind !== 'symlink' && p === region.path) || p.startsWith(region.path + '/'));
661
- if (region.kind === 'error' || region.kind === 'cap' || hides)
873
+ // A scope passed over whole is the answer to the pass that asked for
874
+ // it, so it's always named. Another mount's directory met beneath the
875
+ // scope is passed over by design even where this mount's tree holds
876
+ // copies there: no tool of this mount syncs, pushes or clears them
877
+ // (listings show them, naming their holder), so naming the directory
878
+ // as unreached would never clear.
879
+ const wholeScope = scope.kind === 'dir' && scope.dir !== '' && region.path === scope.dir;
880
+ const unreached = hides && region.reason !== OTHER_MOUNT;
881
+ if (region.kind === 'error' || region.kind === 'cap' || unreached || wholeScope)
662
882
  result.incomplete.push({ path: region.path, reason: region.reason });
663
- // An ignored name that hides nothing tracked is reported nowhere else:
883
+ // A name passed over by design that hides nothing tracked is reported nowhere else:
664
884
  // counted, so a sync that says 0 also says what it didn't look at
665
885
  // (agent-framework #276). A symlink region isn't counted: a link the
666
886
  // walk took is a candidate the pass reports by path, taken through the
@@ -673,11 +893,15 @@ export async function reconcilePass(store, agreement, mount, scope, opts = {}) {
673
893
  }
674
894
  return result;
675
895
  }
896
+ /** Why a push skips a path in another mount's directory nested in its own. */
897
+ export const NOT_PUSHED_IN_OTHER_MOUNT = "it lies in another mount's directory, which no push of this mount writes";
676
898
  /**
677
899
  * Make disk hold the store's version of each path, under the same rule:
678
900
  * drafts are written, agreement is left alone, conflicts and unverifiable
679
901
  * disk copies are refused unless `force`, and a workspace deletion reaches
680
902
  * disk only with `applyDeletions` (with `force` too when disk changed since).
903
+ * Forced or not, nothing but a regular file, or a followed symlink to one, is
904
+ * written over or unlinked (effects.ts).
681
905
  * A path nothing has evidence about is written only when `named`.
682
906
  * A path whose earlier push shows on disk unconfirmed is pushed again, so its
683
907
  * completion rests on barriers that succeeded.
@@ -696,7 +920,7 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
696
920
  agreement.ensureReconciled();
697
921
  if (agreement.needsBarrier)
698
922
  agreement.barrier(); // as a pass does: nothing decided from unsynced evidence
699
- const result = { written: [], unchanged: [], deleted: [], skipped: [], pendingDeletions: [] };
923
+ const result = { written: [], unchanged: [], deleted: [], skipped: [], modesKept: [], pendingDeletions: [] };
700
924
  if (mount.readOnly)
701
925
  return result;
702
926
  // A root that isn't available takes no writes, forced or not: restoring the
@@ -708,6 +932,20 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
708
932
  result.skipped.push({ path, reason: root.reason });
709
933
  return result;
710
934
  }
935
+ // Another mount's directory nested in this one is that mount's: no push
936
+ // of this mount writes or deletes a path in it, forced or not. (On a mount
937
+ // that follows links, a link of this mount's that leads there is read as
938
+ // this mount's own path; on one that doesn't, the link is refused.)
939
+ if (mount.view.others.length > 0) {
940
+ const own = [];
941
+ for (const path of paths) {
942
+ if (inOtherMount(path, mount.view.others))
943
+ result.skipped.push({ path, reason: NOT_PUSHED_IN_OTHER_MOUNT });
944
+ else
945
+ own.push(path);
946
+ }
947
+ paths = own;
948
+ }
711
949
  const plans = [];
712
950
  // Observe disk.
713
951
  const facts = new Map();
@@ -737,11 +975,20 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
737
975
  result.sequence = store.currentSequence();
738
976
  let recorded = false;
739
977
  for (const [path, d] of facts) {
740
- const entry = store.treeGet(mount.treeStateId, path);
741
- const s = entry ? { hash: entry.blobHash, size: entry.size } : null;
978
+ const s = storeSide(store.treeGet(mount.treeStateId, path));
742
979
  const p = agreement.get(mount.name, path);
743
980
  const bi = mount.intents.get(path);
744
981
  const v = decide(d, s, p, bi, branchId, false);
982
+ // The ways out a refusal names, as materialize takes them: a deletion
983
+ // reaches disk only with applyDeletions.
984
+ const again = s ? 'materialize again' : 'materialize again with applyDeletions';
985
+ // Where disk has deleted a file the workspace holds, a sync takes the
986
+ // deletion, which removes the workspace's copy, and a forced push writes
987
+ // the workspace's copy back: there is no disk copy to adopt or overwrite.
988
+ const gone = s !== null && d.kind === 'absent';
989
+ const forced = !s ? 'materialize it with force and applyDeletions to delete it'
990
+ : gone ? "materialize it with force to write the workspace's copy back" : 'materialize it with force to overwrite it';
991
+ const takeDisk = gone ? "sync this path to take disk's deletion, which removes the workspace's copy" : 'sync this path to adopt the disk version';
745
992
  // What the effect may find: what this observation saw, unless forced.
746
993
  const expect = opts.force || d.kind === 'unobserved' || d.kind === 'unhashed'
747
994
  ? { kind: 'any' }
@@ -756,18 +1003,51 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
756
1003
  result.skipped.push({
757
1004
  path,
758
1005
  reason: 'stale copy: disk changed since it last agreed with the workspace, which did not — ' +
759
- 'sync this path to adopt the disk version, or pass force to overwrite it',
1006
+ `${takeDisk}, or ${forced}`,
760
1007
  });
761
1008
  continue;
762
1009
  }
763
1010
  const priorP = p && (p.kind === 'absent' || p.kind === 'content') ? p : null;
764
1011
  const blob = store.getBlob(s.hash);
765
- if (blob)
766
- plans.push({ path, kind: 'write', blob, hash: s.hash, prior: priorP, before: agreement.get(mount.name, path), expect });
1012
+ const forcedMode = mount.modesObserved && s.mode !== undefined && s.mode !== (d.kind === 'file' ? d.mode : undefined) ? s.mode : undefined;
1013
+ const agreedMode = priorP?.kind === 'content' ? priorP.mode : undefined;
1014
+ if (blob) {
1015
+ plans.push({
1016
+ path, kind: 'write', blob, hash: s.hash, prior: priorP, before: agreement.get(mount.name, path), expect,
1017
+ ...(forcedMode !== undefined ? { apply: forcedMode } : {}),
1018
+ ...(forcedMode !== undefined && d.kind === 'file' && agreedMode !== d.mode ? { overDisk: true } : {}),
1019
+ ...(s.mode !== undefined ? { storeMode: s.mode } : {}),
1020
+ // Refused over disk's mode, the completion records what an unforced
1021
+ // write would: the mode disk last agreed with.
1022
+ ...(agreedMode !== undefined ? { priorMode: agreedMode } : {}),
1023
+ ...(d.kind === 'file' && d.mode !== undefined ? { seenMode: d.mode } : {}),
1024
+ });
1025
+ }
767
1026
  else
768
1027
  result.skipped.push({ path, reason: 'the workspace copy is missing from the store' });
769
1028
  continue;
770
1029
  }
1030
+ if (v.mode === 'adopt' && s && d.kind === 'file') {
1031
+ // Disk's mode changed since it last agreed, on the bytes the store
1032
+ // holds, and the store's didn't. A sync takes it in. Recording disk's
1033
+ // mode here would read as the store's change, which the next push
1034
+ // would revert; forced, disk takes the store's mode, as forced bytes do.
1035
+ if (!opts.force) {
1036
+ // modeAction adopts where disk changed the mode since they agreed, and
1037
+ // where nothing records a mode they agreed on.
1038
+ const agreedMode = p?.kind === 'content' ? p.mode : undefined;
1039
+ result.skipped.push({
1040
+ path,
1041
+ reason: (agreedMode === undefined
1042
+ ? `disk's mode (${octal(d.mode)}) differs from the workspace's (${octal(s.mode)}), and nothing records which side changed it`
1043
+ : `disk's mode (${octal(d.mode)}) changed since it last agreed with the workspace's (${octal(s.mode)})`) +
1044
+ ' — sync this path to take disk\'s mode in, or materialize this path with force to apply the workspace\'s',
1045
+ });
1046
+ continue;
1047
+ }
1048
+ plans.push({ path, kind: 'chmod', mode: s.mode, hash: s.hash, size: s.size, prior: null, before: p, expect, overDisk: true });
1049
+ continue;
1050
+ }
771
1051
  // Whatever the verdict learned about disk (an agreement, a resolved
772
1052
  // intent) is recorded before anything is pushed over it, and the root it
773
1053
  // was learned under before that (once per mount), as a pass does.
@@ -782,8 +1062,22 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
782
1062
  // The prior a new intent carries is the last confirmed evidence: for a
783
1063
  // path whose earlier push is unconfirmed, that push's own prior, never
784
1064
  // the bytes it wrote.
785
- const known = v.unconfirmed ? p.prior ?? undefined : v.p === 'forget' ? undefined : v.p !== undefined ? v.p : p;
1065
+ const known = v.unconfirmed ? p.prior ?? undefined : v.p === 'forget' ? undefined : v.p !== undefined ? v.p : v.prior ?? p;
786
1066
  const prior = known && (known.kind === 'absent' || known.kind === 'content') ? known : null;
1067
+ // A push that re-plans over our own narrowing push, stopped before its
1068
+ // bytes, plans from disk's narrowed mode (the verdict's prior, which
1069
+ // resolvePending leaves unrecorded), as above, and goes on as that push:
1070
+ // its intent carries the stopped push's prior, the old bytes at their own
1071
+ // mode, never the mode it narrowed them to, and modes from that mode, so a
1072
+ // stop of this push too reads disk's narrowed mode as the push's own.
1073
+ // Past the adoptions handled above, a verdict carries a prior with P still
1074
+ // pending only from that narrowing, whose push recorded its modes.
1075
+ const stopped = v.prior !== undefined && p?.kind === 'pending' ? p : undefined;
1076
+ if (v.mode === 'push' && s && d.kind === 'file') {
1077
+ // Forced, disk takes the store's mode whatever it holds now, as it takes its bytes.
1078
+ plans.push({ path, kind: 'chmod', mode: s.mode, ...(opts.force ? {} : { from: d.mode }), hash: s.hash, size: s.size, prior, before: agreement.get(mount.name, path), expect });
1079
+ continue;
1080
+ }
787
1081
  if (v.state === 'synced' && !v.unconfirmed) {
788
1082
  if (v.intent !== undefined) {
789
1083
  mount.intents.put(path, v.intent);
@@ -795,7 +1089,25 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
795
1089
  }
796
1090
  if (v.state === 'unverified') {
797
1091
  if (!opts.force) {
798
- result.skipped.push({ path, reason: `cannot verify disk copy (${v.note ?? 'not observed'}) — fix it and materialize again, or pass force to overwrite it` });
1092
+ // An intent that can't be read is the one note fixing doesn't
1093
+ // answer: nothing is decided over it until a sync of the path
1094
+ // replaces it (decide()), and a sync replaces it only where it sees
1095
+ // disk's copy, so a copy it can't see is named first. For the rest,
1096
+ // fixing what the note names holds, and forcedWay says where force
1097
+ // does too. Where disk has deleted the file, that sync takes the
1098
+ // deletion.
1099
+ const sync = gone
1100
+ ? "sync this path to take disk's deletion, which removes the workspace's copy and replaces the intent"
1101
+ : 'sync this path to adopt the disk version, which replaces the intent';
1102
+ result.skipped.push({
1103
+ path,
1104
+ reason: bi?.unreadable !== undefined
1105
+ ? d.kind === 'absent' || d.kind === 'file'
1106
+ ? `${v.note} — ${sync}`
1107
+ : `${v.note}, and disk's copy can't be verified (${d.kind === 'unobserved' ? d.reason : 'not hashed'}) — once it can be, ${sync}`
1108
+ : inTheWay(v.note, !s) ??
1109
+ `cannot verify disk copy (${v.note ?? 'not observed'}) — fix it and ${again}${forcedWay(v.note, !s, forced)}`,
1110
+ });
799
1111
  continue;
800
1112
  }
801
1113
  }
@@ -815,15 +1127,20 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
815
1127
  }
816
1128
  result.skipped.push({
817
1129
  path,
818
- reason: noEvidence
819
- ? `disk holds a different copy, and nothing records which is newer (conflict: ${kind}) — ` +
820
- 'sync this path to adopt the disk version, or materialize this path with force to overwrite it'
821
- : kind === 'interrupted'
822
- ? 'disk holds bytes that match neither what was being written there nor what disk last agreed with ' +
823
- '(conflict: interrupted), as a write that failed or was cut off partway leaves — check the file, then ' +
824
- 'pass force to write the workspace copy over it, or sync this path to adopt the disk copy as it is'
825
- : `stale copy: disk changed since it last agreed with the workspace (conflict: ${kind}) — ` +
826
- 'sync this path to adopt the disk version, or pass force to overwrite it',
1130
+ // Whatever was recorded, a disk with no copy now is answered for what
1131
+ // it holds; a path with no evidence still needs its push named.
1132
+ reason: gone
1133
+ ? `disk has no copy of this file (conflict: ${kind}) — ${takeDisk}, or ` +
1134
+ `materialize ${noEvidence ? 'this path' : 'it'} with force to write the workspace's copy back`
1135
+ : noEvidence
1136
+ ? `disk holds a different copy, and nothing records which is newer (conflict: ${kind}) — ` +
1137
+ `sync this path to adopt the disk version, or materialize this path with force ${s ? 'to overwrite it' : 'and applyDeletions to delete it'}`
1138
+ : kind === 'interrupted'
1139
+ ? 'disk holds bytes that match neither what was being written there nor what disk last agreed with ' +
1140
+ '(conflict: interrupted), as a write that failed or was cut off partway leaves — check the file, then ' +
1141
+ `${forced}, or sync this path to adopt the disk copy as it is`
1142
+ : `stale copy: disk changed since it last agreed with the workspace (conflict: ${kind}) — ` +
1143
+ `sync this path to adopt the disk version, or ${forced}`,
827
1144
  });
828
1145
  continue;
829
1146
  }
@@ -853,7 +1170,14 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
853
1170
  continue;
854
1171
  }
855
1172
  if (!opts.applyDeletions) {
856
- result.pendingDeletions.push(path);
1173
+ // A deletion no push makes, forced or not (inTheWay), is refused for
1174
+ // that, as an unforced push refuses it, rather than left for
1175
+ // applyDeletions, which couldn't make it either.
1176
+ const lasting = inTheWay(v.note, true);
1177
+ if (lasting !== null)
1178
+ result.skipped.push({ path, reason: lasting });
1179
+ else
1180
+ result.pendingDeletions.push(path);
857
1181
  continue;
858
1182
  }
859
1183
  if (d.kind === 'absent')
@@ -866,18 +1190,61 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
866
1190
  result.skipped.push({ path, reason: 'the workspace copy is missing from the store' });
867
1191
  continue;
868
1192
  }
869
- plans.push({ path, kind: 'write', blob, hash: s.hash, prior, before: agreement.get(mount.name, path), expect });
1193
+ // The store's mode goes to disk with its bytes where the file is new,
1194
+ // the push is forced, or disk still has the mode they last agreed on. A
1195
+ // push that completes our own unconfirmed one, whose bytes landed, is a
1196
+ // push like any other: it gives the store's mode where disk shows one of
1197
+ // the stopped push's own (pushedMode) or the one they last agreed on, and
1198
+ // keeps any other, set since it stopped (Ada-1017, room-203 #131062,
1199
+ // #131518). A mode disk changed since stays, and so does the evidence
1200
+ // that it did, up to the moment of the write.
1201
+ const dm = d.kind === 'file' ? d.mode : undefined;
1202
+ const priorMode = prior?.kind === 'content' ? prior.mode : undefined;
1203
+ const own = v.unconfirmed === true && v.ownMode === true;
1204
+ const apply = mount.modesObserved && s.mode !== undefined && s.mode !== dm &&
1205
+ (dm === undefined || opts.force === true || own || priorMode === dm) ? s.mode : undefined;
1206
+ plans.push({
1207
+ path, kind: 'write', blob, hash: s.hash, prior: stopped ? stopped.prior : prior, before: agreement.get(mount.name, path), expect,
1208
+ // With no mode in the store's entry, its `to` is the mode the push
1209
+ // leaves, the one the stopped push narrowed to: it claims none it lacks.
1210
+ ...(stopped ? { ownModes: { from: stopped.modes.from, to: s.mode ?? (stopped.modes.from & stopped.modes.to) } } : {}),
1211
+ ...(apply !== undefined ? { apply } : {}),
1212
+ ...(apply !== undefined && dm !== undefined && opts.force !== true ? { from: dm } : {}),
1213
+ // Forced over a mode disk changed: without force, the bytes would keep it.
1214
+ ...(apply !== undefined && dm !== undefined && priorMode !== dm && !own ? { overDisk: true } : {}),
1215
+ ...(s.mode !== undefined ? { storeMode: s.mode } : {}),
1216
+ ...(priorMode !== undefined ? { priorMode } : {}),
1217
+ ...(dm !== undefined ? { seenMode: dm } : {}),
1218
+ });
870
1219
  }
871
1220
  // 1. Durable intents before any disk effect, the root they write under first.
1221
+ // A chmod announces none: it leaves the bytes as they are. Stopped before
1222
+ // its completion, it leaves disk at the store's mode or still at the one
1223
+ // the evidence agreed, and the next observation decides from that: synced
1224
+ // and recorded, or pushed again. Nothing is lost either way. A forced
1225
+ // chmod has no guard: stopped before it, disk keeps whatever mode it found,
1226
+ // which the next observation reads as disk's, and forced again, it applies
1227
+ // the store's.
872
1228
  if (plans.length > 0)
873
1229
  agreement.recordRootIdentity(mount.name, root.identity);
874
- plans.forEach((step, i) => {
1230
+ const announced = plans.filter((step) => step.kind !== 'chmod');
1231
+ announced.forEach((step, i) => {
875
1232
  agreement.intend(mount.name, step.path, {
876
1233
  effect: 'disk',
877
1234
  prior: step.prior,
878
1235
  expect: step.kind === 'write' ? { kind: 'content', hash: step.hash } : ABSENT,
879
1236
  branchId,
880
- }, { durable: i === plans.length - 1 });
1237
+ // A write whose plan gives a mode (`apply`) records the modes it may
1238
+ // leave, so a stop is read by them: the mode it saw, or for a file it
1239
+ // creates the one it creates it at, and the one it gives. A file a
1240
+ // forced push creates at its entry's mode with no mode planned records
1241
+ // none. One that goes on as our own stopped narrowing records that
1242
+ // push's, from the old bytes' own mode, whether or not it gives a mode
1243
+ // itself.
1244
+ ...(step.kind === 'write' && step.ownModes !== undefined ? { modes: step.ownModes }
1245
+ : step.kind === 'write' && step.apply !== undefined
1246
+ ? { modes: { from: step.seenMode ?? step.apply, to: step.apply } } : {}),
1247
+ }, { durable: i === announced.length - 1 });
881
1248
  });
882
1249
  // 2. Effects, each bound at its point of use.
883
1250
  const effected = [];
@@ -885,8 +1252,51 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
885
1252
  opts.beforeEffect?.(step.path);
886
1253
  try {
887
1254
  if (step.kind === 'write') {
888
- await writeContained(mount.view, mount.rootReal, step.path, step.blob, step.expect);
889
- effected.push({ step, dirs: chainOf(step.path) });
1255
+ const { perm, widenRefused, modeKept } = await writeContained(mount.view, mount.rootReal, step.path, step.blob, step.expect, step.apply, step.from, step.overDisk === true,
1256
+ // Where modes go unobserved, nothing is applied, a created file's included.
1257
+ mount.modesObserved ? step.storeMode : undefined);
1258
+ effected.push({ step, dirs: chainOf(step.path), mode: perm, widenRefused, modeKept });
1259
+ }
1260
+ else if (step.kind === 'chmod') {
1261
+ // An inode change, made durable by the file's own fsync.
1262
+ const { refused, narrowing } = await chmodContained(mount.view, mount.rootReal, step.path, step.mode, step.expect, step.from);
1263
+ // A chmod announces no intent, so a refused one leaves the evidence
1264
+ // as planning read it, unless it says otherwise below.
1265
+ if (refused && narrowing && !step.overDisk) {
1266
+ // A narrowing of the store's own change that the kernel refused
1267
+ // stays owed, as a write's does: taking disk's wider mode in would
1268
+ // let a later write put new bytes out at it.
1269
+ result.skipped.push({
1270
+ path: step.path,
1271
+ reason: `not given the workspace's mode (${octal(step.mode)}): the kernel refused to narrow it, as it does for a file another user owns, ` +
1272
+ 'so it stays owed: a retry is refused the same way until the file\'s owner or an administrator narrows it',
1273
+ });
1274
+ continue;
1275
+ }
1276
+ if (refused && step.overDisk) {
1277
+ // Forced over a mode disk changed, or one nothing records: the
1278
+ // path is as it was before the push, so a sync takes disk's mode
1279
+ // in, as it would have without force.
1280
+ result.skipped.push({
1281
+ path: step.path,
1282
+ reason: `not given the workspace's mode (${octal(step.mode)}): the kernel refused the chmod, so disk keeps its mode, and a sync takes it in`,
1283
+ });
1284
+ continue;
1285
+ }
1286
+ if (refused) {
1287
+ // A widening of the store's own change that the kernel refused:
1288
+ // disk keeps its mode, and the evidence records none, so a sync
1289
+ // takes disk's in by the rule for an unknown rather than owing a
1290
+ // mode this process can never give.
1291
+ agreement.set(mount.name, step.path, { kind: 'content', hash: step.hash, size: step.size });
1292
+ recorded = true;
1293
+ result.skipped.push({
1294
+ path: step.path,
1295
+ reason: `not given the workspace's mode (${octal(step.mode)}): the kernel refused the chmod, and a sync takes disk's mode in`,
1296
+ });
1297
+ continue;
1298
+ }
1299
+ effected.push({ step, dirs: [] });
890
1300
  }
891
1301
  else {
892
1302
  // Its directory is synced whether this unlink removed the entry or
@@ -901,7 +1311,8 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
901
1311
  // exactly what it was, whatever kind that was.
902
1312
  agreement.restore(mount.name, step.path, step.before);
903
1313
  recorded = true;
904
- result.skipped.push({ path: step.path, reason: `not ${step.kind === 'write' ? 'written' : 'unlinked'}: ${failure.message}` });
1314
+ const why = inTheWay(failure.message, step.kind === 'unlink') ?? failure.message;
1315
+ result.skipped.push({ path: step.path, reason: `not ${step.kind === 'unlink' ? 'unlinked' : step.kind === 'chmod' ? 'given the workspace\'s mode' : 'written'}: ${why}` });
905
1316
  }
906
1317
  else {
907
1318
  // No completion: the intent stays pending, and the next observation
@@ -917,7 +1328,8 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
917
1328
  // 4. Completions. P is physical and global. Branch intent belongs to the
918
1329
  // branch this push planned on: it is settled only while that branch is
919
1330
  // still selected, and otherwise by convergence when the branch returns.
920
- for (const { step, dirs } of effected) {
1331
+ for (const { step, dirs, mode: written, widenRefused, modeKept } of effected) {
1332
+ const mode = mount.modesObserved ? written : undefined;
921
1333
  const failed = dirs.find((dir) => unsynced.has(dir));
922
1334
  if (failed !== undefined) {
923
1335
  result.skipped.push({
@@ -927,11 +1339,64 @@ export async function pushPaths(store, agreement, mount, paths, opts = {}) {
927
1339
  });
928
1340
  continue;
929
1341
  }
930
- const value = step.kind === 'write' ? { kind: 'content', hash: step.hash, size: step.blob.byteLength } : { kind: 'absent' };
1342
+ // The mode the evidence records: the one the push gave the file, if the
1343
+ // file has it; disk's own, where the store records none or the same; and
1344
+ // otherwise the one disk last agreed with, so a mode disk changed since
1345
+ // reads as disk's. (Where modes go unobserved, the evidence's writer
1346
+ // records none.)
1347
+ // A widening of the workspace's own change that the kernel refused
1348
+ // records none: a sync takes disk's mode in, rather than owing one this
1349
+ // process can never give. Forced over a mode disk changed, or one nothing
1350
+ // records (overDisk), any refused chmod ends where an unforced write
1351
+ // would: the evidence records the mode disk last agreed with, if any, and
1352
+ // a sync takes disk's mode in.
1353
+ const agreedMode = step.kind === 'chmod'
1354
+ ? step.mode
1355
+ : step.kind === 'write'
1356
+ ? widenRefused && !step.overDisk
1357
+ ? undefined
1358
+ : step.apply !== undefined && step.apply === mode
1359
+ ? mode
1360
+ : step.storeMode === undefined || step.storeMode === mode ? mode : step.priorMode
1361
+ : undefined;
1362
+ const value = step.kind === 'unlink'
1363
+ ? { kind: 'absent' }
1364
+ : { kind: 'content', hash: step.hash, size: step.kind === 'write' ? step.blob.byteLength : step.size, ...(agreedMode !== undefined ? { mode: agreedMode } : {}) };
931
1365
  agreement.set(mount.name, step.path, value);
932
1366
  recorded = true;
1367
+ // Bytes written where the kernel refused the mode, or where disk's mode
1368
+ // changed since it last agreed, keep disk's mode, and the push says so
1369
+ // beside what it wrote: the bytes reached disk, so it's no refusal.
1370
+ if (step.kind === 'write' && widenRefused && mode !== undefined) {
1371
+ result.modesKept.push({
1372
+ path: step.path,
1373
+ reason: `written, its mode left at ${octal(mode)}: the kernel refused the chmod, ` +
1374
+ `so the workspace's (${octal(step.apply ?? step.storeMode ?? mode)}) isn't given, and a sync takes disk's mode in`,
1375
+ });
1376
+ }
1377
+ else if (step.kind === 'write' && modeKept && mode !== undefined) {
1378
+ // Forced over a mode disk changed, and refused: the bytes are written
1379
+ // at it, the evidence records it as an unforced write's would.
1380
+ result.modesKept.push({
1381
+ path: step.path,
1382
+ reason: `written, its mode left at ${octal(mode)}: the kernel refused to narrow it ` +
1383
+ `${narrowedTo(mode & (step.apply ?? mode), step.apply ?? mode)}, so disk keeps its mode, and a sync takes it in`,
1384
+ });
1385
+ }
1386
+ else if (step.kind === 'write' && mode !== undefined && step.storeMode !== undefined && mode !== step.storeMode) {
1387
+ result.modesKept.push({
1388
+ path: step.path,
1389
+ reason: (step.priorMode === undefined
1390
+ ? `written, keeping disk's mode (${octal(mode)}), which differs from the workspace's (${octal(step.storeMode)}), and nothing records which side changed it`
1391
+ : `written, keeping disk's mode (${octal(mode)}), which changed since it last agreed with the workspace's (${octal(step.storeMode)})`) +
1392
+ ' — sync this path to take disk\'s mode in, or materialize this path with force to apply the workspace\'s',
1393
+ });
1394
+ }
933
1395
  const planned = store.currentBranch().id === branchId;
934
- if (step.kind === 'write') {
1396
+ if (step.kind === 'chmod') {
1397
+ result.written.push(step.path);
1398
+ }
1399
+ else if (step.kind === 'write') {
935
1400
  if (planned)
936
1401
  mount.intents.update(step.path, (cur) => { const next = { ...cur }; delete next.conflict; delete next.origin; return next; });
937
1402
  result.written.push(step.path);