niceeval 0.13.1 → 0.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (548) hide show
  1. package/INDEX.md +25 -2
  2. package/README.md +9 -10
  3. package/README.zh.md +9 -10
  4. package/dist/agents/ai-sdk.cjs.map +1 -1
  5. package/dist/agents/ai-sdk.d.cts +1 -1
  6. package/dist/agents/ai-sdk.d.mts +1 -1
  7. package/dist/agents/ai-sdk.d.ts +1 -1
  8. package/dist/agents/bub-install-spec.cjs +19 -5
  9. package/dist/agents/bub-install-spec.cjs.map +1 -1
  10. package/dist/agents/bub-install-spec.d.cts +9 -2
  11. package/dist/agents/bub-install-spec.d.mts +9 -2
  12. package/dist/agents/bub-install-spec.d.ts +9 -2
  13. package/dist/agents/bub-install-spec.js +14 -12
  14. package/dist/agents/bub.cjs +10 -6
  15. package/dist/agents/bub.cjs.map +1 -1
  16. package/dist/agents/bub.d.cts +2 -2
  17. package/dist/agents/bub.d.mts +2 -2
  18. package/dist/agents/bub.d.ts +2 -2
  19. package/dist/agents/claude-code.cjs.map +1 -1
  20. package/dist/agents/claude-code.d.cts +2 -2
  21. package/dist/agents/claude-code.d.mts +2 -2
  22. package/dist/agents/claude-code.d.ts +2 -2
  23. package/dist/agents/codex.cjs +4 -4
  24. package/dist/agents/codex.cjs.map +1 -1
  25. package/dist/agents/codex.d.cts +3 -3
  26. package/dist/agents/codex.d.mts +3 -3
  27. package/dist/agents/codex.d.ts +3 -3
  28. package/dist/agents/coding-cli-versions.cjs +10 -1
  29. package/dist/agents/coding-cli-versions.cjs.map +1 -1
  30. package/dist/agents/coding-cli-versions.d.cts +8 -3
  31. package/dist/agents/coding-cli-versions.d.mts +8 -3
  32. package/dist/agents/coding-cli-versions.d.ts +8 -3
  33. package/dist/agents/coding-cli-versions.js +18 -12
  34. package/dist/agents/deepseek-harness.cjs +151 -0
  35. package/dist/agents/deepseek-harness.cjs.map +1 -0
  36. package/dist/agents/deepseek-harness.d.cts +14 -0
  37. package/dist/agents/deepseek-harness.d.mts +14 -0
  38. package/dist/agents/deepseek-harness.d.ts +14 -0
  39. package/dist/agents/deepseek-harness.js +7 -0
  40. package/dist/agents/deepseek-harness.js.map +1 -0
  41. package/dist/agents/exact-npm-plugins.cjs +28 -0
  42. package/dist/agents/exact-npm-plugins.cjs.map +1 -0
  43. package/dist/agents/exact-npm-plugins.d.cts +10 -0
  44. package/dist/agents/exact-npm-plugins.d.mts +10 -0
  45. package/dist/agents/exact-npm-plugins.d.ts +10 -0
  46. package/dist/agents/exact-npm-plugins.js +8 -0
  47. package/dist/agents/exact-npm-plugins.js.map +1 -0
  48. package/dist/agents/index.cjs +5 -1
  49. package/dist/agents/index.cjs.map +1 -1
  50. package/dist/agents/index.d.cts +4 -0
  51. package/dist/agents/index.d.mts +4 -0
  52. package/dist/agents/index.d.ts +4 -0
  53. package/dist/agents/index.js +54 -50
  54. package/dist/agents/index.mjs +54 -50
  55. package/dist/agents/omp.cjs +170 -0
  56. package/dist/agents/omp.cjs.map +1 -0
  57. package/dist/agents/omp.d.cts +14 -0
  58. package/dist/agents/omp.d.mts +14 -0
  59. package/dist/agents/omp.d.ts +14 -0
  60. package/dist/agents/omp.js +7 -0
  61. package/dist/agents/omp.js.map +1 -0
  62. package/dist/agents/openclaw.cjs +51 -2
  63. package/dist/agents/openclaw.cjs.map +1 -1
  64. package/dist/agents/openclaw.d.cts +2 -0
  65. package/dist/agents/openclaw.d.mts +2 -0
  66. package/dist/agents/openclaw.d.ts +2 -0
  67. package/dist/agents/types.cjs.map +1 -1
  68. package/dist/agents/types.d.cts +4 -4
  69. package/dist/agents/types.d.mts +4 -4
  70. package/dist/agents/types.d.ts +4 -4
  71. package/dist/agents/ui-message-stream.cjs +24 -7
  72. package/dist/agents/ui-message-stream.cjs.map +1 -1
  73. package/dist/analysis/api.cjs +28 -2
  74. package/dist/analysis/api.cjs.map +1 -1
  75. package/dist/analysis/api.d.cts +22 -1
  76. package/dist/analysis/api.d.mts +22 -1
  77. package/dist/analysis/api.d.ts +22 -1
  78. package/dist/analysis/api.js +8 -6
  79. package/dist/analysis/bindings.cjs +11 -18
  80. package/dist/analysis/bindings.cjs.map +1 -1
  81. package/dist/analysis/bindings.d.cts +177 -49
  82. package/dist/analysis/bindings.d.mts +177 -49
  83. package/dist/analysis/bindings.d.ts +177 -49
  84. package/dist/analysis/contracts.cjs +1 -0
  85. package/dist/analysis/contracts.cjs.map +1 -1
  86. package/dist/analysis/contracts.d.cts +43 -3
  87. package/dist/analysis/contracts.d.mts +43 -3
  88. package/dist/analysis/contracts.d.ts +43 -3
  89. package/dist/analysis/cost-projection.cjs +2 -1
  90. package/dist/analysis/cost-projection.cjs.map +1 -1
  91. package/dist/analysis/cost-projection.d.cts +1 -1
  92. package/dist/analysis/cost-projection.d.mts +1 -1
  93. package/dist/analysis/cost-projection.d.ts +1 -1
  94. package/dist/analysis/cost.cjs +13 -3
  95. package/dist/analysis/cost.cjs.map +1 -1
  96. package/dist/analysis/cost.d.cts +10 -3
  97. package/dist/analysis/cost.d.mts +10 -3
  98. package/dist/analysis/cost.d.ts +10 -3
  99. package/dist/analysis/experiment-groups.cjs +96 -0
  100. package/dist/analysis/experiment-groups.cjs.map +1 -0
  101. package/dist/analysis/experiment-groups.d.cts +9 -0
  102. package/dist/analysis/experiment-groups.d.mts +9 -0
  103. package/dist/analysis/experiment-groups.d.ts +9 -0
  104. package/dist/analysis/experiment-groups.js +10 -0
  105. package/dist/analysis/experiment-groups.js.map +1 -0
  106. package/dist/analysis/index.cjs +4 -1
  107. package/dist/analysis/index.cjs.map +1 -1
  108. package/dist/analysis/index.d.cts +4 -2
  109. package/dist/analysis/index.d.mts +4 -2
  110. package/dist/analysis/index.d.ts +4 -2
  111. package/dist/analysis/index.js +40 -36
  112. package/dist/analysis/index.mjs +40 -36
  113. package/dist/assertions/limits.cjs +4 -0
  114. package/dist/assertions/limits.cjs.map +1 -1
  115. package/dist/assertions/limits.d.cts +4 -0
  116. package/dist/assertions/limits.d.mts +4 -0
  117. package/dist/assertions/limits.d.ts +4 -0
  118. package/dist/assertions/match.cjs +63 -25
  119. package/dist/assertions/match.cjs.map +1 -1
  120. package/dist/assertions/match.d.cts +7 -0
  121. package/dist/assertions/match.d.mts +7 -0
  122. package/dist/assertions/match.d.ts +7 -0
  123. package/dist/assertions/record/attachment.cjs +32 -4
  124. package/dist/assertions/record/attachment.cjs.map +1 -1
  125. package/dist/assertions/record/diff.cjs +10 -4
  126. package/dist/assertions/record/diff.cjs.map +1 -1
  127. package/dist/assertions/record/producer.cjs +101 -4
  128. package/dist/assertions/record/producer.cjs.map +1 -1
  129. package/dist/assertions/record/producer.d.cts +4 -1
  130. package/dist/assertions/record/producer.d.mts +4 -1
  131. package/dist/assertions/record/producer.d.ts +4 -1
  132. package/dist/assertions/runtime.cjs +45 -5
  133. package/dist/assertions/runtime.cjs.map +1 -1
  134. package/dist/cli/record.cjs +113 -8
  135. package/dist/cli/record.cjs.map +1 -1
  136. package/dist/cli/record.d.cts +20 -1
  137. package/dist/cli/record.d.mts +20 -1
  138. package/dist/cli/record.d.ts +20 -1
  139. package/dist/cli/record.js +4 -2
  140. package/dist/cli.cjs +386 -31
  141. package/dist/cli.cjs.map +1 -1
  142. package/dist/cli.d.cts +10 -2
  143. package/dist/cli.d.mts +10 -2
  144. package/dist/cli.d.ts +10 -2
  145. package/dist/context/send-retry.cjs +4 -4
  146. package/dist/context/send-retry.cjs.map +1 -1
  147. package/dist/coordination/host/runtime.cjs +8 -30
  148. package/dist/coordination/host/runtime.cjs.map +1 -1
  149. package/dist/coordination/host/runtime.d.cts +3 -3
  150. package/dist/coordination/host/runtime.d.mts +3 -3
  151. package/dist/coordination/host/runtime.d.ts +3 -3
  152. package/dist/coordination/host/types.cjs.map +1 -1
  153. package/dist/coordination/host/types.d.cts +0 -5
  154. package/dist/coordination/host/types.d.mts +0 -5
  155. package/dist/coordination/host/types.d.ts +0 -5
  156. package/dist/coordination/platform/node.cjs +90 -9
  157. package/dist/coordination/platform/node.cjs.map +1 -1
  158. package/dist/define.cjs +25 -1
  159. package/dist/define.cjs.map +1 -1
  160. package/dist/experiment/host/index.cjs +1 -0
  161. package/dist/experiment/host/index.cjs.map +1 -1
  162. package/dist/i18n/en.cjs +26 -8
  163. package/dist/i18n/en.cjs.map +1 -1
  164. package/dist/i18n/en.d.cts +19 -6
  165. package/dist/i18n/en.d.mts +19 -6
  166. package/dist/i18n/en.d.ts +19 -6
  167. package/dist/index.cjs.map +1 -1
  168. package/dist/index.d.cts +1 -1
  169. package/dist/index.d.mts +1 -1
  170. package/dist/index.d.ts +1 -1
  171. package/dist/o11y/parsers/hermes.cjs +1 -1
  172. package/dist/o11y/parsers/hermes.cjs.map +1 -1
  173. package/dist/o11y/prices.json +1 -1
  174. package/dist/o11y/record/families.cjs +12 -3
  175. package/dist/o11y/record/families.cjs.map +1 -1
  176. package/dist/o11y/record/families.d.cts +8 -8
  177. package/dist/o11y/record/families.d.mts +8 -8
  178. package/dist/o11y/record/families.d.ts +8 -8
  179. package/dist/o11y/record/family-projectors.d.cts +66 -18
  180. package/dist/o11y/record/family-projectors.d.mts +66 -18
  181. package/dist/o11y/record/family-projectors.d.ts +66 -18
  182. package/dist/o11y/record/family-writers.d.cts +11 -3
  183. package/dist/o11y/record/family-writers.d.mts +11 -3
  184. package/dist/o11y/record/family-writers.d.ts +11 -3
  185. package/dist/o11y/record/runner-producer.cjs +14 -4
  186. package/dist/o11y/record/runner-producer.cjs.map +1 -1
  187. package/dist/record/codec/core.d.cts +2 -2
  188. package/dist/record/codec/core.d.mts +2 -2
  189. package/dist/record/codec/core.d.ts +2 -2
  190. package/dist/record/family/catalog.d.cts +44 -12
  191. package/dist/record/family/catalog.d.mts +44 -12
  192. package/dist/record/family/catalog.d.ts +44 -12
  193. package/dist/record/family/index.js +128 -124
  194. package/dist/record/family/observability-v1.cjs +35 -0
  195. package/dist/record/family/observability-v1.cjs.map +1 -0
  196. package/dist/record/family/observability-v1.d.cts +3 -0
  197. package/dist/record/family/observability-v1.d.mts +3 -0
  198. package/dist/record/family/observability-v1.d.ts +3 -0
  199. package/dist/record/family/observability-v1.js +6 -0
  200. package/dist/record/family/observability-v1.js.map +1 -0
  201. package/dist/record/family/observability.cjs +58 -9
  202. package/dist/record/family/observability.cjs.map +1 -1
  203. package/dist/record/family/observability.d.cts +1014 -15
  204. package/dist/record/family/observability.d.mts +1014 -15
  205. package/dist/record/family/observability.d.ts +1014 -15
  206. package/dist/record/family/observability.js +22 -18
  207. package/dist/record/host/runtime.cjs +600 -31
  208. package/dist/record/host/runtime.cjs.map +1 -1
  209. package/dist/record/host/types.cjs.map +1 -1
  210. package/dist/record/host/types.d.cts +33 -9
  211. package/dist/record/host/types.d.mts +33 -9
  212. package/dist/record/host/types.d.ts +33 -9
  213. package/dist/record/maintenance/runtime.cjs +1 -2
  214. package/dist/record/maintenance/runtime.cjs.map +1 -1
  215. package/dist/record/model/core.cjs.map +1 -1
  216. package/dist/record/model/core.d.cts +1 -1
  217. package/dist/record/model/core.d.mts +1 -1
  218. package/dist/record/model/core.d.ts +1 -1
  219. package/dist/record/model/definition.d.cts +6 -6
  220. package/dist/record/model/definition.d.mts +6 -6
  221. package/dist/record/model/definition.d.ts +6 -6
  222. package/dist/record/model/identifiers.cjs +1 -1
  223. package/dist/record/model/identifiers.cjs.map +1 -1
  224. package/dist/record/model/identifiers.d.cts +1 -1
  225. package/dist/record/model/identifiers.d.mts +1 -1
  226. package/dist/record/model/identifiers.d.ts +1 -1
  227. package/dist/record/platform/node.cjs +159 -23
  228. package/dist/record/platform/node.cjs.map +1 -1
  229. package/dist/record/platform/services.cjs.map +1 -1
  230. package/dist/record/platform/services.d.cts +15 -2
  231. package/dist/record/platform/services.d.mts +15 -2
  232. package/dist/record/platform/services.d.ts +15 -2
  233. package/dist/record/reader/errors.cjs +37 -1
  234. package/dist/record/reader/errors.cjs.map +1 -1
  235. package/dist/record/reader/errors.d.cts +49 -1
  236. package/dist/record/reader/errors.d.mts +49 -1
  237. package/dist/record/reader/errors.d.ts +49 -1
  238. package/dist/record/reader/errors.js +22 -12
  239. package/dist/record/reader/format.cjs +76 -17
  240. package/dist/record/reader/format.cjs.map +1 -1
  241. package/dist/record/reader/format.d.cts +11 -4
  242. package/dist/record/reader/format.d.mts +11 -4
  243. package/dist/record/reader/format.d.ts +11 -4
  244. package/dist/record/reader/format.js +2 -0
  245. package/dist/record/reader/index.js +32 -18
  246. package/dist/record/reader/runtime.cjs +64 -0
  247. package/dist/record/reader/runtime.cjs.map +1 -1
  248. package/dist/record/reader/runtime.d.cts +15 -0
  249. package/dist/record/reader/runtime.d.mts +15 -0
  250. package/dist/record/reader/runtime.d.ts +15 -0
  251. package/dist/record/reader/runtime.js +2 -0
  252. package/dist/report/assets/styles.css +53 -29
  253. package/dist/report/built-in/analysis-values.cjs +21 -13
  254. package/dist/report/built-in/analysis-values.cjs.map +1 -1
  255. package/dist/report/built-in/analysis-values.d.cts +11 -22
  256. package/dist/report/built-in/analysis-values.d.mts +11 -22
  257. package/dist/report/built-in/analysis-values.d.ts +11 -22
  258. package/dist/report/built-in/analysis-values.js +4 -6
  259. package/dist/report/built-in/index.cjs +1 -3
  260. package/dist/report/built-in/index.cjs.map +1 -1
  261. package/dist/report/built-in/index.d.cts +1 -1
  262. package/dist/report/built-in/index.d.mts +1 -1
  263. package/dist/report/built-in/index.d.ts +1 -1
  264. package/dist/report/built-in/index.js +4 -8
  265. package/dist/report/built-in/index.mjs +4 -8
  266. package/dist/report/built-in/machine.cjs +0 -2
  267. package/dist/report/built-in/machine.cjs.map +1 -1
  268. package/dist/report/built-in/machine.d.cts +0 -2
  269. package/dist/report/built-in/machine.d.mts +0 -2
  270. package/dist/report/built-in/machine.d.ts +0 -2
  271. package/dist/report/built-in/result-components.cjs +49 -51
  272. package/dist/report/built-in/result-components.cjs.map +1 -1
  273. package/dist/report/built-in/result-components.d.cts +16 -17
  274. package/dist/report/built-in/result-components.d.mts +16 -17
  275. package/dist/report/built-in/result-components.d.ts +16 -17
  276. package/dist/report/built-in/result-components.js +0 -4
  277. package/dist/report/built-in/run-membership-overview.cjs +126 -17
  278. package/dist/report/built-in/run-membership-overview.cjs.map +1 -1
  279. package/dist/report/built-in/run-membership-overview.d.cts +14 -0
  280. package/dist/report/built-in/run-membership-overview.d.mts +14 -0
  281. package/dist/report/built-in/run-membership-overview.d.ts +14 -0
  282. package/dist/report/built-in/run-membership-overview.js +4 -2
  283. package/dist/report/built-in/standard.cjs +80 -45
  284. package/dist/report/built-in/standard.cjs.map +1 -1
  285. package/dist/report/built-in/standard.d.cts +19 -41
  286. package/dist/report/built-in/standard.d.mts +19 -41
  287. package/dist/report/built-in/standard.d.ts +19 -41
  288. package/dist/report/built-in/standard.js +6 -6
  289. package/dist/report/components/attempt-detail/compute.cjs +78 -2
  290. package/dist/report/components/attempt-detail/compute.cjs.map +1 -1
  291. package/dist/report/components/attempt-detail/compute.d.cts +1 -1
  292. package/dist/report/components/attempt-detail/compute.d.mts +1 -1
  293. package/dist/report/components/attempt-detail/compute.d.ts +1 -1
  294. package/dist/report/components/attempt-detail/content.cjs +1 -1
  295. package/dist/report/components/attempt-detail/content.cjs.map +1 -1
  296. package/dist/report/components/entity-lists/compute.cjs +42 -5
  297. package/dist/report/components/entity-lists/compute.cjs.map +1 -1
  298. package/dist/report/components/entity-lists/compute.d.cts +10 -8
  299. package/dist/report/components/entity-lists/compute.d.mts +10 -8
  300. package/dist/report/components/entity-lists/compute.d.ts +10 -8
  301. package/dist/report/components/entity-lists/content.cjs +31 -6
  302. package/dist/report/components/entity-lists/content.cjs.map +1 -1
  303. package/dist/report/components/entity-lists/index.cjs +9 -4
  304. package/dist/report/components/entity-lists/index.cjs.map +1 -1
  305. package/dist/report/components/entity-lists/index.d.cts +4 -7
  306. package/dist/report/components/entity-lists/index.d.mts +4 -7
  307. package/dist/report/components/entity-lists/index.d.ts +4 -7
  308. package/dist/report/components/summaries/compute.cjs +8 -1
  309. package/dist/report/components/summaries/compute.cjs.map +1 -1
  310. package/dist/report/components/summaries/compute.d.cts +9 -1
  311. package/dist/report/components/summaries/compute.d.mts +9 -1
  312. package/dist/report/components/summaries/compute.d.ts +9 -1
  313. package/dist/report/components/summaries/index.cjs +48 -4
  314. package/dist/report/components/summaries/index.cjs.map +1 -1
  315. package/dist/report/components/summaries/index.d.cts +7 -4
  316. package/dist/report/components/summaries/index.d.mts +7 -4
  317. package/dist/report/components/summaries/index.d.ts +7 -4
  318. package/dist/report/definition/cell.cjs +3 -0
  319. package/dist/report/definition/cell.cjs.map +1 -1
  320. package/dist/report/definition/cell.d.cts +2 -0
  321. package/dist/report/definition/cell.d.mts +2 -0
  322. package/dist/report/definition/cell.d.ts +2 -0
  323. package/dist/report/definition/primitives/chart.cjs +8 -5
  324. package/dist/report/definition/primitives/chart.cjs.map +1 -1
  325. package/dist/report/definition/primitives/points-dataset.cjs +1 -0
  326. package/dist/report/definition/primitives/points-dataset.cjs.map +1 -1
  327. package/dist/report/definition/primitives.cjs +15 -2
  328. package/dist/report/definition/primitives.cjs.map +1 -1
  329. package/dist/report/definition/report.cjs +27 -3
  330. package/dist/report/definition/report.cjs.map +1 -1
  331. package/dist/report/definition/report.d.cts +8 -0
  332. package/dist/report/definition/report.d.mts +8 -0
  333. package/dist/report/definition/report.d.ts +8 -0
  334. package/dist/report/execution/machine.cjs +30 -14
  335. package/dist/report/execution/machine.cjs.map +1 -1
  336. package/dist/report/execution/machine.d.cts +20 -10
  337. package/dist/report/execution/machine.d.mts +20 -10
  338. package/dist/report/execution/machine.d.ts +20 -10
  339. package/dist/report/execution/machine.js +6 -6
  340. package/dist/report/host/execute.cjs +25 -16
  341. package/dist/report/host/execute.cjs.map +1 -1
  342. package/dist/report/host/execute.d.cts +4 -0
  343. package/dist/report/host/execute.d.mts +4 -0
  344. package/dist/report/host/execute.d.ts +4 -0
  345. package/dist/report/host/from-record.cjs +22 -5
  346. package/dist/report/host/from-record.cjs.map +1 -1
  347. package/dist/report/host/machine.cjs +53 -11
  348. package/dist/report/host/machine.cjs.map +1 -1
  349. package/dist/report/host/site-runtime.cjs +9 -8
  350. package/dist/report/host/site-runtime.cjs.map +1 -1
  351. package/dist/report/host/site-runtime.d.cts +1 -1
  352. package/dist/report/host/site-runtime.d.mts +1 -1
  353. package/dist/report/host/site-runtime.d.ts +1 -1
  354. package/dist/report/host/static.cjs +56 -9
  355. package/dist/report/host/static.cjs.map +1 -1
  356. package/dist/report/index.cjs.map +1 -1
  357. package/dist/report/index.d.cts +1 -1
  358. package/dist/report/index.d.mts +1 -1
  359. package/dist/report/index.d.ts +1 -1
  360. package/dist/report/model/dataset.cjs +7 -2
  361. package/dist/report/model/dataset.cjs.map +1 -1
  362. package/dist/report/model/locale.cjs +2 -0
  363. package/dist/report/model/locale.cjs.map +1 -1
  364. package/dist/report/model/locale.d.cts +1 -0
  365. package/dist/report/model/locale.d.mts +1 -0
  366. package/dist/report/model/locale.d.ts +1 -0
  367. package/dist/report/model/metrics.cjs +3 -1
  368. package/dist/report/model/metrics.cjs.map +1 -1
  369. package/dist/report/model/pricing.cjs +16 -11
  370. package/dist/report/model/pricing.cjs.map +1 -1
  371. package/dist/report/react/styles.css +53 -29
  372. package/dist/runner/adoption.cjs +1 -0
  373. package/dist/runner/adoption.cjs.map +1 -1
  374. package/dist/runner/attempt.cjs +44 -5
  375. package/dist/runner/attempt.cjs.map +1 -1
  376. package/dist/runner/attempt.d.cts +13 -1
  377. package/dist/runner/attempt.d.mts +13 -1
  378. package/dist/runner/attempt.d.ts +13 -1
  379. package/dist/runner/config-identity.cjs +10 -2
  380. package/dist/runner/config-identity.cjs.map +1 -1
  381. package/dist/runner/config-identity.d.cts +4 -2
  382. package/dist/runner/config-identity.d.mts +4 -2
  383. package/dist/runner/config-identity.d.ts +4 -2
  384. package/dist/runner/feedback/human.cjs +298 -59
  385. package/dist/runner/feedback/human.cjs.map +1 -1
  386. package/dist/runner/feedback/json.cjs +14 -6
  387. package/dist/runner/feedback/json.cjs.map +1 -1
  388. package/dist/runner/feedback/json.d.cts +3 -2
  389. package/dist/runner/feedback/json.d.mts +3 -2
  390. package/dist/runner/feedback/json.d.ts +3 -2
  391. package/dist/runner/feedback/reducer.cjs +2 -0
  392. package/dist/runner/feedback/reducer.cjs.map +1 -1
  393. package/dist/runner/judge-config.cjs +1 -1
  394. package/dist/runner/judge-config.cjs.map +1 -1
  395. package/dist/runner/ledger.cjs +124 -12
  396. package/dist/runner/ledger.cjs.map +1 -1
  397. package/dist/runner/project-current.cjs +13 -5
  398. package/dist/runner/project-current.cjs.map +1 -1
  399. package/dist/runner/run.cjs +564 -256
  400. package/dist/runner/run.cjs.map +1 -1
  401. package/dist/runner/sandbox-pool.cjs +161 -30
  402. package/dist/runner/sandbox-pool.cjs.map +1 -1
  403. package/dist/runner/sandbox-pool.d.cts +34 -2
  404. package/dist/runner/sandbox-pool.d.mts +34 -2
  405. package/dist/runner/sandbox-pool.d.ts +34 -2
  406. package/dist/runner/shared-state-lease.cjs +803 -0
  407. package/dist/runner/shared-state-lease.cjs.map +1 -0
  408. package/dist/runner/shared-state-lease.d.cts +121 -0
  409. package/dist/runner/shared-state-lease.d.mts +121 -0
  410. package/dist/runner/shared-state-lease.d.ts +121 -0
  411. package/dist/runner/shared-state-lease.js +24 -0
  412. package/dist/runner/shared-state-lease.js.map +1 -0
  413. package/dist/runner/teardown-registry.cjs +97 -34
  414. package/dist/runner/teardown-registry.cjs.map +1 -1
  415. package/dist/runner/teardown-registry.d.cts +27 -1
  416. package/dist/runner/teardown-registry.d.mts +27 -1
  417. package/dist/runner/teardown-registry.d.ts +27 -1
  418. package/dist/runner/teardown-registry.js +20 -16
  419. package/dist/runner/types.cjs.map +1 -1
  420. package/dist/runner/types.d.cts +31 -5
  421. package/dist/runner/types.d.mts +31 -5
  422. package/dist/runner/types.d.ts +31 -5
  423. package/dist/sample/analysis.cjs +249 -459
  424. package/dist/sample/analysis.cjs.map +1 -1
  425. package/dist/sample/capability.cjs +138 -7
  426. package/dist/sample/capability.cjs.map +1 -1
  427. package/dist/sample/capability.d.cts +3 -1
  428. package/dist/sample/capability.d.mts +3 -1
  429. package/dist/sample/capability.d.ts +3 -1
  430. package/dist/sample/capability.js +8 -6
  431. package/dist/sandbox/docker-agent-image.cjs +5 -1
  432. package/dist/sandbox/docker-agent-image.cjs.map +1 -1
  433. package/dist/sandbox/docker-agent-image.d.cts +2 -0
  434. package/dist/sandbox/docker-agent-image.d.mts +2 -0
  435. package/dist/sandbox/docker-agent-image.d.ts +2 -0
  436. package/dist/sandbox/docker-agent-image.js +14 -10
  437. package/dist/sandbox/docker-profile/schema.cjs +283 -534
  438. package/dist/sandbox/docker-profile/schema.cjs.map +1 -1
  439. package/dist/sandbox/docker-profile/schema.d.cts +10 -27
  440. package/dist/sandbox/docker-profile/schema.d.mts +10 -27
  441. package/dist/sandbox/docker-profile/schema.d.ts +10 -27
  442. package/dist/sandbox/e2b-agent-template.cjs +5 -2
  443. package/dist/sandbox/e2b-agent-template.cjs.map +1 -1
  444. package/dist/sandbox/index.cjs +4 -2
  445. package/dist/sandbox/index.cjs.map +1 -1
  446. package/dist/sandbox/index.d.cts +1 -1
  447. package/dist/sandbox/index.d.mts +1 -1
  448. package/dist/sandbox/index.d.ts +1 -1
  449. package/dist/sandbox/index.js +120 -116
  450. package/dist/sandbox/index.mjs +120 -116
  451. package/dist/sandbox/keep-registry.cjs +28 -66
  452. package/dist/sandbox/keep-registry.cjs.map +1 -1
  453. package/dist/sandbox/types.cjs.map +1 -1
  454. package/dist/sandbox/types.d.cts +1 -1
  455. package/dist/sandbox/types.d.mts +1 -1
  456. package/dist/sandbox/types.d.ts +1 -1
  457. package/dist/shared/aggregate.cjs +16 -6
  458. package/dist/shared/aggregate.cjs.map +1 -1
  459. package/dist/shared/aggregate.d.cts +12 -4
  460. package/dist/shared/aggregate.d.mts +12 -4
  461. package/dist/shared/aggregate.d.ts +12 -4
  462. package/dist/shared/turn-label.cjs +20 -2
  463. package/dist/shared/turn-label.cjs.map +1 -1
  464. package/dist/shared/turn-label.d.cts +2 -0
  465. package/dist/shared/turn-label.d.mts +2 -0
  466. package/dist/shared/turn-label.d.ts +2 -0
  467. package/dist/shared/turn-label.js +4 -2
  468. package/dist/vendor/remark/remark-gfm.cjs +7 -7
  469. package/dist/vendor/remark/remark-gfm.cjs.map +1 -1
  470. package/dist/vendor/remark/remark-parse.cjs +12 -12
  471. package/dist/vendor/remark/remark-parse.cjs.map +1 -1
  472. package/dist/vendor/remark/remark.cjs +13 -13
  473. package/dist/vendor/remark/remark.cjs.map +1 -1
  474. package/dist/view/server.cjs +6 -0
  475. package/dist/view/server.cjs.map +1 -1
  476. package/docs-site/images/hitl-handshake-zh.svg +3 -3
  477. package/docs-site/zh/examples/ai-agent-application.mdx +1 -1
  478. package/docs-site/zh/examples/coding-agent-extensions.mdx +1 -1
  479. package/docs-site/zh/examples/integrations/ai-sdk-v7.mdx +4 -3
  480. package/docs-site/zh/examples/integrations/claude-sdk.mdx +3 -3
  481. package/docs-site/zh/examples/integrations/codex-sdk.mdx +5 -5
  482. package/docs-site/zh/examples/integrations/langgraph.mdx +4 -4
  483. package/docs-site/zh/examples/integrations/pi-sdk.mdx +5 -5
  484. package/docs-site/zh/explanation/adapter.mdx +5 -5
  485. package/docs-site/zh/explanation/assert.mdx +7 -7
  486. package/docs-site/zh/explanation/drive.mdx +4 -2
  487. package/docs-site/zh/explanation/evals.mdx +10 -8
  488. package/docs-site/zh/explanation/experiment.mdx +2 -2
  489. package/docs-site/zh/explanation/hitl.mdx +9 -9
  490. package/docs-site/zh/explanation/judge.mdx +5 -5
  491. package/docs-site/zh/explanation/overview.mdx +3 -3
  492. package/docs-site/zh/explanation/runner.mdx +1 -1
  493. package/docs-site/zh/index.mdx +3 -3
  494. package/docs-site/zh/reference/builtin-agents.mdx +13 -13
  495. package/docs-site/zh/reference/capabilities.mdx +1 -1
  496. package/docs-site/zh/reference/cli.mdx +18 -12
  497. package/docs-site/zh/reference/define-agent.mdx +130 -5
  498. package/docs-site/zh/reference/define-config.mdx +2 -2
  499. package/docs-site/zh/reference/define-eval.mdx +4 -4
  500. package/docs-site/zh/reference/events.mdx +11 -11
  501. package/docs-site/zh/reference/official-adapters.mdx +6 -6
  502. package/docs-site/zh/reference/results-data.mdx +6 -0
  503. package/docs-site/zh/troubleshooting/debugging.mdx +1 -1
  504. package/docs-site/zh/troubleshooting/recover-after-kill.mdx +37 -5
  505. package/docs-site/zh/tutorials/accept-results.mdx +72 -0
  506. package/docs-site/zh/tutorials/agent-onboarding.mdx +6 -6
  507. package/docs-site/zh/tutorials/authoring.mdx +9 -13
  508. package/docs-site/zh/tutorials/ci-integration.mdx +6 -6
  509. package/docs-site/zh/tutorials/compare-runs.mdx +61 -0
  510. package/docs-site/zh/tutorials/concurrency.mdx +13 -12
  511. package/docs-site/zh/tutorials/configuration.mdx +4 -6
  512. package/docs-site/zh/tutorials/connect-your-agent.mdx +1 -1
  513. package/docs-site/zh/tutorials/control-run-cost.mdx +58 -0
  514. package/docs-site/zh/tutorials/criteria-files.mdx +2 -2
  515. package/docs-site/zh/tutorials/custom-reports.mdx +2 -2
  516. package/docs-site/zh/tutorials/debug-lifecycle-plan.mdx +46 -0
  517. package/docs-site/zh/tutorials/docker-in-docker.mdx +52 -43
  518. package/docs-site/zh/tutorials/eval-groups.mdx +6 -6
  519. package/docs-site/zh/tutorials/evaluation-kinds.mdx +3 -3
  520. package/docs-site/zh/tutorials/experiments.mdx +2 -3
  521. package/docs-site/zh/tutorials/handle-execution-failures.mdx +18 -10
  522. package/docs-site/zh/tutorials/install-custom-sandbox-agent.mdx +16 -8
  523. package/docs-site/zh/tutorials/nixos-managed-dind.mdx +160 -0
  524. package/docs-site/zh/tutorials/plugins.mdx +14 -0
  525. package/docs-site/zh/tutorials/rerun-and-cache.mdx +4 -2
  526. package/docs-site/zh/tutorials/sandbox-agent.mdx +17 -11
  527. package/docs-site/zh/tutorials/sandbox-providers.mdx +17 -13
  528. package/docs-site/zh/tutorials/sandbox-reuse.mdx +12 -19
  529. package/docs-site/zh/tutorials/select-and-preview.mdx +65 -0
  530. package/docs-site/zh/tutorials/verify-judge.mdx +78 -0
  531. package/docs-site/zh/tutorials/viewing-results.mdx +38 -1
  532. package/docs-site/zh/tutorials/write-experiment.mdx +7 -5
  533. package/docs-site/zh/tutorials/write-send.mdx +9 -8
  534. package/package.json +9 -5
  535. package/dist/report/built-in/overview.cjs +0 -44
  536. package/dist/report/built-in/overview.cjs.map +0 -1
  537. package/dist/report/built-in/overview.d.cts +0 -6
  538. package/dist/report/built-in/overview.d.mts +0 -6
  539. package/dist/report/built-in/overview.d.ts +0 -6
  540. package/dist/report/built-in/overview.js +0 -9
  541. package/dist/report/built-in/overview.js.map +0 -1
  542. package/dist/runner/gate-lease.cjs +0 -283
  543. package/dist/runner/gate-lease.cjs.map +0 -1
  544. package/dist/runner/gate-lease.d.cts +0 -62
  545. package/dist/runner/gate-lease.d.mts +0 -62
  546. package/dist/runner/gate-lease.d.ts +0 -62
  547. package/dist/runner/gate-lease.js +0 -22
  548. package/dist/runner/gate-lease.js.map +0 -1
@@ -1,283 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GATE_LEASE_EXPIRY_MS = exports.GATE_LEASE_HEARTBEAT_INTERVAL_MS = void 0;
4
- exports.gateLeasesDirOf = gateLeasesDirOf;
5
- exports.readGateLeasesEffect = readGateLeasesEffect;
6
- exports.isGateLeaseExpired = isGateLeaseExpired;
7
- exports.tryAcquireGateSlotOnceEffect = tryAcquireGateSlotOnceEffect;
8
- exports.acquireGateSlotEffect = acquireGateSlotEffect;
9
- exports.drainHeldGateLeasesEffect = drainHeldGateLeasesEffect;
10
- exports.pendingHeldGateLeaseCount = pendingHeldGateLeaseCount;
11
- // 实验闸租约:把实验级 `maxConcurrency` 的 N 个名额做成跨 Invocation 共用的逐槽租约。
12
- // 与 ./lock.ts 的用例锁同一套文件纪律(O_EXCL 独占创建、心跳续租、过期判据、rename 接管、
13
- // 释放即删除),建在 ../shared/entry-file-store.ts 的原语之上,不复制第三份纪律。
14
- // 契约见 docs/feature/experiments/architecture.md「并发 Invocation:用例锁」末条与
15
- // docs/runner.md#调度有界并发。
16
- const promises_1 = require("node:fs/promises");
17
- const node_path_1 = require("node:path");
18
- const effect_1 = require("effect");
19
- const entry_file_store_ts_1 = require("../shared/entry-file-store.cjs");
20
- const lock_ts_1 = require("./lock.cjs");
21
- function recordOf(value) {
22
- return typeof value === "object" && value !== null && !Array.isArray(value)
23
- ? value
24
- : undefined;
25
- }
26
- function isPositiveInteger(value) {
27
- return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
28
- }
29
- function isSlot(value) {
30
- return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
31
- }
32
- function isTimestamp(value) {
33
- return typeof value === "string" && Number.isFinite(Date.parse(value));
34
- }
35
- function errnoCode(cause) {
36
- return typeof cause === "object" && cause !== null && "code" in cause && typeof cause.code === "string"
37
- ? cause.code
38
- : undefined;
39
- }
40
- function nodeIo(operation) {
41
- return effect_1.Effect.tryPromise({ try: operation, catch: (cause) => cause });
42
- }
43
- function withOpenFile(path, flags, use) {
44
- return effect_1.Effect.scoped(effect_1.Effect.acquireRelease(nodeIo(() => (0, promises_1.open)(path, flags)), (handle) => nodeIo(() => handle.close()).pipe(effect_1.Effect.orDie)).pipe(effect_1.Effect.flatMap(use)));
45
- }
46
- /** 验证租约的全部持久字段;按槽读取时还会核对身份,防止错位记录冒充当前持有者。 */
47
- function decodeGateLeaseRecord(value, expected = {}) {
48
- const record = recordOf(value);
49
- if (record === undefined ||
50
- typeof record.experimentId !== "string" ||
51
- !isSlot(record.slot) ||
52
- !isPositiveInteger(record.declaredN) ||
53
- !isPositiveInteger(record.pid) ||
54
- typeof record.host !== "string" ||
55
- !isTimestamp(record.startedAt) ||
56
- !isTimestamp(record.heartbeatAt) ||
57
- (expected.experimentId !== undefined && record.experimentId !== expected.experimentId) ||
58
- (expected.slot !== undefined && record.slot !== expected.slot)) {
59
- return undefined;
60
- }
61
- return {
62
- experimentId: record.experimentId,
63
- slot: record.slot,
64
- declaredN: record.declaredN,
65
- pid: record.pid,
66
- host: record.host,
67
- startedAt: record.startedAt,
68
- heartbeatAt: record.heartbeatAt,
69
- };
70
- }
71
- /** 持有者续租心跳的周期。与用例锁同参数。 */
72
- exports.GATE_LEASE_HEARTBEAT_INTERVAL_MS = lock_ts_1.CASE_LOCK_HEARTBEAT_INTERVAL_MS;
73
- /** `heartbeatAt` 落后当前时间超过这个阈值(三个心跳周期)即视为持有者已死。 */
74
- exports.GATE_LEASE_EXPIRY_MS = lock_ts_1.CASE_LOCK_EXPIRY_MS;
75
- function gateLeasesDirOf(niceevalRoot) {
76
- return (0, lock_ts_1.locksDirOf)(niceevalRoot);
77
- }
78
- function gateLeaseEntryId(experimentId, slot) {
79
- return (0, entry_file_store_ts_1.slugHashEntryId)(`gate-${experimentId}-${slot}`, ["gate-lease", experimentId, String(slot)]);
80
- }
81
- /** Effect 主 API:读取该实验当前在场的全部租约记录,无副作用。 */
82
- function readGateLeasesEffect(niceevalRoot, experimentId) {
83
- return (0, entry_file_store_ts_1.readAllEntryFilesEffect)(gateLeasesDirOf(niceevalRoot), decodeGateLeaseRecord).pipe(effect_1.Effect.map((entries) => entries
84
- .map(({ entry }) => entry)
85
- .filter((entry) => entry.experimentId === experimentId)
86
- .sort((a, b) => a.slot - b.slot)));
87
- }
88
- /** 过期判据:只看心跳时间戳,不看 pid。 */
89
- function isGateLeaseExpired(record, nowMs) {
90
- const heartbeatMs = Date.parse(record.heartbeatAt);
91
- if (Number.isNaN(heartbeatMs))
92
- return true;
93
- return nowMs - heartbeatMs > exports.GATE_LEASE_EXPIRY_MS;
94
- }
95
- /** 本进程声明的 N:非法值收敛到 1,避免永久满位。 */
96
- function normalizeN(n) {
97
- const floored = Math.floor(n);
98
- return Number.isFinite(floored) && floored >= 1 ? floored : 1;
99
- }
100
- /** min-N:有效名额取自己声明和所有新鲜租约声明的最小值。 */
101
- function effectiveSlotCount(maxConcurrency, leases, nowMs) {
102
- let n = normalizeN(maxConcurrency);
103
- for (const lease of leases) {
104
- if (isGateLeaseExpired(lease, nowMs))
105
- continue;
106
- const declared = normalizeN(lease.declaredN);
107
- if (declared < n)
108
- n = declared;
109
- }
110
- return n;
111
- }
112
- /** O_EXCL 独占创建租约文件;存在时返回 false,不覆盖。 */
113
- function createLeaseFileExclusiveEffect(dir, id, record) {
114
- const path = (0, node_path_1.join)(dir, `${id}.json`);
115
- return nodeIo(() => (0, promises_1.mkdir)(dir, { recursive: true })).pipe(effect_1.Effect.zipRight(withOpenFile(path, "wx", (handle) => nodeIo(() => handle.writeFile(JSON.stringify(record, null, 2), "utf-8")).pipe(effect_1.Effect.zipRight(nodeIo(() => handle.sync()))))), effect_1.Effect.zipRight((0, entry_file_store_ts_1.fsyncDirEffect)(dir)), effect_1.Effect.as(true), effect_1.Effect.catchAll((cause) => errnoCode(cause) === "EEXIST" ? effect_1.Effect.succeed(false) : effect_1.Effect.fail(cause)));
116
- }
117
- /** 同一持有者判定:身份(pid/host)加上取位时刻——接管重建后 `startedAt` 必然不同。 */
118
- function isSameHolder(record, mine) {
119
- return record.pid === mine.pid && record.host === mine.host && record.startedAt === mine.startedAt;
120
- }
121
- /** 一次非阻塞取位:空槽 O_EXCL 创建,满位时只接管过期或损坏槽。 */
122
- function tryAcquireGateSlotOnceEffect(niceevalRoot, experimentId, maxConcurrency, identity, nowMs) {
123
- const dir = gateLeasesDirOf(niceevalRoot);
124
- return effect_1.Effect.gen(function* () {
125
- const effectiveN = effectiveSlotCount(maxConcurrency, yield* readGateLeasesEffect(niceevalRoot, experimentId), nowMs);
126
- const stamp = new Date(nowMs).toISOString();
127
- const recordFor = (slot) => ({
128
- experimentId,
129
- slot,
130
- declaredN: normalizeN(maxConcurrency),
131
- pid: identity.pid,
132
- host: identity.host,
133
- startedAt: stamp,
134
- heartbeatAt: stamp,
135
- });
136
- const acquired = (slot, record, options) => ({ kind: "acquired", slot, record, ...options });
137
- // 第一趟不预读占用情况:O_EXCL 本身就是判据。
138
- for (let slot = 0; slot < effectiveN; slot += 1) {
139
- const record = recordFor(slot);
140
- if (yield* createLeaseFileExclusiveEffect(dir, gateLeaseEntryId(experimentId, slot), record)) {
141
- return acquired(slot, record, { takenOver: false });
142
- }
143
- }
144
- // 第二趟只对坏条目或过期条目执行 rename 认领;输掉竞态后继续下一槽。
145
- for (let slot = 0; slot < effectiveN; slot += 1) {
146
- const id = gateLeaseEntryId(experimentId, slot);
147
- const current = yield* (0, entry_file_store_ts_1.readEntryFileEffect)(dir, id, (value) => decodeGateLeaseRecord(value, { experimentId, slot }));
148
- if (current === undefined) {
149
- if (!(yield* (0, entry_file_store_ts_1.claimEntryFileEffect)(dir, id)))
150
- continue;
151
- const record = recordFor(slot);
152
- if (!(yield* createLeaseFileExclusiveEffect(dir, id, record)))
153
- continue;
154
- return acquired(slot, record, { takenOver: false });
155
- }
156
- if (!isGateLeaseExpired(current, nowMs))
157
- continue;
158
- if (!(yield* (0, entry_file_store_ts_1.claimEntryFileEffect)(dir, id)))
159
- continue;
160
- const record = recordFor(slot);
161
- if (!(yield* createLeaseFileExclusiveEffect(dir, id, record)))
162
- continue;
163
- return acquired(slot, record, { takenOver: true, takenOverFrom: current });
164
- }
165
- const holders = (yield* readGateLeasesEffect(niceevalRoot, experimentId)).filter((lease) => !isGateLeaseExpired(lease, nowMs));
166
- return { kind: "full", holders };
167
- });
168
- }
169
- /** 续租只改 heartbeat;槽被接管后不写、不删别人的租约。 */
170
- function renewHeartbeatEffect(dir, id, mine, nowMs, isReleased) {
171
- if (isReleased())
172
- return effect_1.Effect.void;
173
- return (0, entry_file_store_ts_1.readEntryFileEffect)(dir, id, (value) => decodeGateLeaseRecord(value, { experimentId: mine.experimentId, slot: mine.slot })).pipe(effect_1.Effect.flatMap((current) => {
174
- if (current === undefined || !isSameHolder(current, mine) || isReleased())
175
- return effect_1.Effect.void;
176
- return (0, entry_file_store_ts_1.writeEntryFileEffect)(dir, id, { ...current, heartbeatAt: new Date(nowMs).toISOString() });
177
- }));
178
- }
179
- function makeAbortError(signal) {
180
- const reason = signal?.reason;
181
- if (reason instanceof Error)
182
- return reason;
183
- const err = new Error("aborted while waiting for experiment gate slot");
184
- err.name = "AbortError";
185
- return err;
186
- }
187
- function awaitAbort(signal) {
188
- if (signal === undefined)
189
- return effect_1.Effect.never;
190
- return effect_1.Effect.async((resume, effectSignal) => {
191
- let completed = false;
192
- const cleanup = () => {
193
- signal.removeEventListener("abort", onAbort);
194
- effectSignal.removeEventListener("abort", onEffectAbort);
195
- };
196
- const cancel = () => {
197
- if (completed)
198
- return;
199
- completed = true;
200
- cleanup();
201
- };
202
- const onAbort = () => {
203
- if (completed)
204
- return;
205
- cancel();
206
- resume(effect_1.Effect.fail(makeAbortError(signal)));
207
- };
208
- const onEffectAbort = () => cancel();
209
- signal.addEventListener("abort", onAbort, { once: true });
210
- effectSignal.addEventListener("abort", onEffectAbort, { once: true });
211
- // Both listeners must be live before inspecting either signal: otherwise
212
- // an abort between inspection and registration could strand the waiter.
213
- if (effectSignal.aborted)
214
- onEffectAbort();
215
- else if (signal.aborted)
216
- onAbort();
217
- return effect_1.Effect.sync(cancel);
218
- });
219
- }
220
- function delayOrAbortEffect(ms, signal) {
221
- if (signal?.aborted)
222
- return effect_1.Effect.fail(makeAbortError(signal));
223
- return effect_1.Effect.raceFirst(effect_1.Effect.sleep(ms), awaitAbort(signal)).pipe(effect_1.Effect.asVoid);
224
- }
225
- const held = new Map();
226
- function heldKey(niceevalRoot, id) {
227
- return `${niceevalRoot} ${id}`;
228
- }
229
- /** 高层 Effect 入口:等待可中断;心跳顺序化,release 等正在飞的不可中断续租结束再删除。 */
230
- function acquireGateSlotEffect(niceevalRoot, experimentId, maxConcurrency, identity, opts = {}) {
231
- const heartbeatIntervalMs = opts.heartbeatIntervalMs ?? exports.GATE_LEASE_HEARTBEAT_INTERVAL_MS;
232
- const pollIntervalMs = opts.pollIntervalMs ?? heartbeatIntervalMs;
233
- let waitStarted = false;
234
- const acquireLoop = () => effect_1.Effect.suspend(() => {
235
- if (opts.signal?.aborted)
236
- return effect_1.Effect.fail(makeAbortError(opts.signal));
237
- return effect_1.Clock.currentTimeMillis.pipe(effect_1.Effect.flatMap((nowMs) => tryAcquireGateSlotOnceEffect(niceevalRoot, experimentId, maxConcurrency, identity, nowMs)), effect_1.Effect.flatMap((result) => {
238
- if (result.kind === "acquired")
239
- return effect_1.Effect.succeed(result);
240
- const reportWait = waitStarted
241
- ? effect_1.Effect.void
242
- : effect_1.Effect.sync(() => {
243
- waitStarted = true;
244
- opts.onWaitStart?.(result.holders);
245
- });
246
- return reportWait.pipe(effect_1.Effect.zipRight(delayOrAbortEffect(pollIntervalMs, opts.signal)), effect_1.Effect.zipRight(acquireLoop()));
247
- }));
248
- });
249
- return effect_1.Effect.uninterruptibleMask((restore) => restore(acquireLoop()).pipe(effect_1.Effect.flatMap(({ slot, takenOver, takenOverFrom, record }) => {
250
- const dir = gateLeasesDirOf(niceevalRoot);
251
- const id = gateLeaseEntryId(experimentId, slot);
252
- const key = heldKey(niceevalRoot, id);
253
- let released = false;
254
- const heartbeat = effect_1.Effect.forever(effect_1.Effect.sleep(heartbeatIntervalMs).pipe(effect_1.Effect.zipRight(effect_1.Effect.uninterruptible(effect_1.Clock.currentTimeMillis.pipe(effect_1.Effect.flatMap((nowMs) => renewHeartbeatEffect(dir, id, record, nowMs, () => released)))).pipe(effect_1.Effect.ignore))));
255
- // A child inherits the parent's interruptibility. This branch still
256
- // runs under the acquisition mask, so restore the heartbeat before
257
- // forking; otherwise release would wait forever while interrupting an
258
- // uninterruptible sleeping fiber.
259
- return effect_1.Effect.forkDaemon(restore(heartbeat)).pipe(effect_1.Effect.map((fiber) => {
260
- const release = effect_1.Effect.uninterruptible(effect_1.Effect.suspend(() => {
261
- if (released)
262
- return effect_1.Effect.void;
263
- released = true;
264
- held.delete(key);
265
- return effect_1.Fiber.interrupt(fiber).pipe(effect_1.Effect.zipRight((0, entry_file_store_ts_1.readEntryFileEffect)(dir, id, (value) => decodeGateLeaseRecord(value, { experimentId, slot }))), effect_1.Effect.flatMap((current) => current !== undefined && !isSameHolder(current, record)
266
- ? effect_1.Effect.void
267
- : nodeIo(() => (0, promises_1.rm)((0, node_path_1.join)(dir, `${id}.json`), { force: true })).pipe(effect_1.Effect.zipRight((0, entry_file_store_ts_1.fsyncDirEffect)(dir)))));
268
- }));
269
- held.set(key, release);
270
- return { claim: { slot, release }, takenOver, ...(takenOverFrom === undefined ? {} : { takenOverFrom }) };
271
- }));
272
- })));
273
- }
274
- /** 强清兜底:尽力释放当前进程持有的每一条租约。 */
275
- function drainHeldGateLeasesEffect() {
276
- const releases = [...held.values()];
277
- return effect_1.Effect.forEach(releases, (release) => effect_1.Effect.exit(release), { discard: true }).pipe(effect_1.Effect.as(releases.length));
278
- }
279
- /** 当前进程仍持有的实验闸租约数量,供退出清理与可观察状态汇总。 */
280
- function pendingHeldGateLeaseCount() {
281
- return held.size;
282
- }
283
- //# sourceMappingURL=gate-lease.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"gate-lease.js","sourceRoot":"","sources":["gate-lease.ts"],"names":[],"mappings":"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","sourcesContent":["// 实验闸租约:把实验级 `maxConcurrency` 的 N 个名额做成跨 Invocation 共用的逐槽租约。\n// 与 ./lock.ts 的用例锁同一套文件纪律(O_EXCL 独占创建、心跳续租、过期判据、rename 接管、\n// 释放即删除),建在 ../shared/entry-file-store.ts 的原语之上,不复制第三份纪律。\n// 契约见 docs/feature/experiments/architecture.md「并发 Invocation:用例锁」末条与\n// docs/runner.md#调度有界并发。\nimport { mkdir, open, rm, type FileHandle } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { Clock, Effect, Fiber } from \"effect\";\nimport { claimEntryFileEffect, fsyncDirEffect, readAllEntryFilesEffect, readEntryFileEffect, slugHashEntryId, writeEntryFileEffect, } from \"../shared/entry-file-store.ts\";\nimport { CASE_LOCK_EXPIRY_MS, CASE_LOCK_HEARTBEAT_INTERVAL_MS, locksDirOf } from \"./lock.ts\";\n/** 逐槽租约文件的 JSON 形状。身份的权威在内容,文件名只须无碰撞、不承载解析。 */\nexport interface GateLeaseRecord {\n experimentId: string;\n /** 槽位序号,取值 0..N-1。 */\n slot: number;\n /** 本持有者 resolved 的名额上限 N。用于 min-N:生效名额取在场声明的最小值。 */\n declaredN: number;\n pid: number;\n host: string;\n startedAt: string; // ISO\n heartbeatAt: string; // ISO\n}\ntype GateSlotAcquired = {\n kind: \"acquired\";\n slot: number;\n takenOver: boolean;\n takenOverFrom?: GateLeaseRecord;\n record: GateLeaseRecord;\n};\ntype GateSlotAttempt = GateSlotAcquired | {\n kind: \"full\";\n holders: GateLeaseRecord[];\n};\nfunction recordOf(value: unknown): globalThis.Record<string, unknown> | undefined {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? value as globalThis.Record<string, unknown>\n : undefined;\n}\nfunction isPositiveInteger(value: unknown): value is number {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value > 0;\n}\nfunction isSlot(value: unknown): value is number {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\nfunction isTimestamp(value: unknown): value is string {\n return typeof value === \"string\" && Number.isFinite(Date.parse(value));\n}\nfunction errnoCode(cause: unknown): string | undefined {\n return typeof cause === \"object\" && cause !== null && \"code\" in cause && typeof cause.code === \"string\"\n ? cause.code\n : undefined;\n}\nfunction nodeIo<A>(operation: (signal: AbortSignal) => Promise<A>): Effect.Effect<A, unknown> {\n return Effect.tryPromise({ try: operation, catch: (cause) => cause });\n}\nfunction withOpenFile<A>(path: string, flags: string, use: (handle: FileHandle) => Effect.Effect<A, unknown>): Effect.Effect<A, unknown> {\n return Effect.scoped(Effect.acquireRelease(nodeIo(() => open(path, flags)), (handle) => nodeIo(() => handle.close()).pipe(Effect.orDie)).pipe(Effect.flatMap(use)));\n}\n/** 验证租约的全部持久字段;按槽读取时还会核对身份,防止错位记录冒充当前持有者。 */\nfunction decodeGateLeaseRecord(value: unknown, expected: {\n experimentId?: string;\n slot?: number;\n} = {}): GateLeaseRecord | undefined {\n const record = recordOf(value);\n if (record === undefined ||\n typeof record.experimentId !== \"string\" ||\n !isSlot(record.slot) ||\n !isPositiveInteger(record.declaredN) ||\n !isPositiveInteger(record.pid) ||\n typeof record.host !== \"string\" ||\n !isTimestamp(record.startedAt) ||\n !isTimestamp(record.heartbeatAt) ||\n (expected.experimentId !== undefined && record.experimentId !== expected.experimentId) ||\n (expected.slot !== undefined && record.slot !== expected.slot)) {\n return undefined;\n }\n return {\n experimentId: record.experimentId,\n slot: record.slot,\n declaredN: record.declaredN,\n pid: record.pid,\n host: record.host,\n startedAt: record.startedAt,\n heartbeatAt: record.heartbeatAt,\n };\n}\n/** 持有者续租心跳的周期。与用例锁同参数。 */\nexport const GATE_LEASE_HEARTBEAT_INTERVAL_MS = CASE_LOCK_HEARTBEAT_INTERVAL_MS;\n/** `heartbeatAt` 落后当前时间超过这个阈值(三个心跳周期)即视为持有者已死。 */\nexport const GATE_LEASE_EXPIRY_MS = CASE_LOCK_EXPIRY_MS;\nexport function gateLeasesDirOf(niceevalRoot: string): string {\n return locksDirOf(niceevalRoot);\n}\nfunction gateLeaseEntryId(experimentId: string, slot: number): string {\n return slugHashEntryId(`gate-${experimentId}-${slot}`, [\"gate-lease\", experimentId, String(slot)]);\n}\n/** Effect 主 API:读取该实验当前在场的全部租约记录,无副作用。 */\nexport function readGateLeasesEffect(niceevalRoot: string, experimentId: string): Effect.Effect<GateLeaseRecord[], unknown> {\n return readAllEntryFilesEffect(gateLeasesDirOf(niceevalRoot), decodeGateLeaseRecord).pipe(Effect.map((entries) => entries\n .map(({ entry }) => entry)\n .filter((entry) => entry.experimentId === experimentId)\n .sort((a, b) => a.slot - b.slot)));\n}\n/** 过期判据:只看心跳时间戳,不看 pid。 */\nexport function isGateLeaseExpired(record: GateLeaseRecord, nowMs: number): boolean {\n const heartbeatMs = Date.parse(record.heartbeatAt);\n if (Number.isNaN(heartbeatMs))\n return true;\n return nowMs - heartbeatMs > GATE_LEASE_EXPIRY_MS;\n}\n/** 本进程声明的 N:非法值收敛到 1,避免永久满位。 */\nfunction normalizeN(n: number): number {\n const floored = Math.floor(n);\n return Number.isFinite(floored) && floored >= 1 ? floored : 1;\n}\n/** min-N:有效名额取自己声明和所有新鲜租约声明的最小值。 */\nfunction effectiveSlotCount(maxConcurrency: number, leases: readonly GateLeaseRecord[], nowMs: number): number {\n let n = normalizeN(maxConcurrency);\n for (const lease of leases) {\n if (isGateLeaseExpired(lease, nowMs))\n continue;\n const declared = normalizeN(lease.declaredN);\n if (declared < n)\n n = declared;\n }\n return n;\n}\n/** O_EXCL 独占创建租约文件;存在时返回 false,不覆盖。 */\nfunction createLeaseFileExclusiveEffect(dir: string, id: string, record: GateLeaseRecord): Effect.Effect<boolean, unknown> {\n const path = join(dir, `${id}.json`);\n return nodeIo(() => mkdir(dir, { recursive: true })).pipe(Effect.zipRight(withOpenFile(path, \"wx\", (handle) => nodeIo(() => handle.writeFile(JSON.stringify(record, null, 2), \"utf-8\")).pipe(Effect.zipRight(nodeIo(() => handle.sync()))))), Effect.zipRight(fsyncDirEffect(dir)), Effect.as(true), Effect.catchAll((cause) => errnoCode(cause) === \"EEXIST\" ? Effect.succeed(false) : Effect.fail(cause)));\n}\n/** 同一持有者判定:身份(pid/host)加上取位时刻——接管重建后 `startedAt` 必然不同。 */\nfunction isSameHolder(record: GateLeaseRecord, mine: GateLeaseRecord): boolean {\n return record.pid === mine.pid && record.host === mine.host && record.startedAt === mine.startedAt;\n}\n/** 一次非阻塞取位:空槽 O_EXCL 创建,满位时只接管过期或损坏槽。 */\nexport function tryAcquireGateSlotOnceEffect(niceevalRoot: string, experimentId: string, maxConcurrency: number, identity: {\n pid: number;\n host: string;\n}, nowMs: number): Effect.Effect<GateSlotAttempt, unknown> {\n const dir = gateLeasesDirOf(niceevalRoot);\n return Effect.gen(function* () {\n const effectiveN = effectiveSlotCount(maxConcurrency, yield* readGateLeasesEffect(niceevalRoot, experimentId), nowMs);\n const stamp = new Date(nowMs).toISOString();\n const recordFor = (slot: number): GateLeaseRecord => ({\n experimentId,\n slot,\n declaredN: normalizeN(maxConcurrency),\n pid: identity.pid,\n host: identity.host,\n startedAt: stamp,\n heartbeatAt: stamp,\n });\n const acquired = (slot: number, record: GateLeaseRecord, options: {\n takenOver: boolean;\n takenOverFrom?: GateLeaseRecord;\n }): GateSlotAcquired => ({ kind: \"acquired\", slot, record, ...options });\n // 第一趟不预读占用情况:O_EXCL 本身就是判据。\n for (let slot = 0; slot < effectiveN; slot += 1) {\n const record = recordFor(slot);\n if (yield* createLeaseFileExclusiveEffect(dir, gateLeaseEntryId(experimentId, slot), record)) {\n return acquired(slot, record, { takenOver: false });\n }\n }\n // 第二趟只对坏条目或过期条目执行 rename 认领;输掉竞态后继续下一槽。\n for (let slot = 0; slot < effectiveN; slot += 1) {\n const id = gateLeaseEntryId(experimentId, slot);\n const current = yield* readEntryFileEffect(dir, id, (value) => decodeGateLeaseRecord(value, { experimentId, slot }));\n if (current === undefined) {\n if (!(yield* claimEntryFileEffect(dir, id)))\n continue;\n const record = recordFor(slot);\n if (!(yield* createLeaseFileExclusiveEffect(dir, id, record)))\n continue;\n return acquired(slot, record, { takenOver: false });\n }\n if (!isGateLeaseExpired(current, nowMs))\n continue;\n if (!(yield* claimEntryFileEffect(dir, id)))\n continue;\n const record = recordFor(slot);\n if (!(yield* createLeaseFileExclusiveEffect(dir, id, record)))\n continue;\n return acquired(slot, record, { takenOver: true, takenOverFrom: current });\n }\n const holders = (yield* readGateLeasesEffect(niceevalRoot, experimentId)).filter((lease) => !isGateLeaseExpired(lease, nowMs));\n return { kind: \"full\", holders };\n });\n}\n/** 续租只改 heartbeat;槽被接管后不写、不删别人的租约。 */\nfunction renewHeartbeatEffect(dir: string, id: string, mine: GateLeaseRecord, nowMs: number, isReleased: () => boolean): Effect.Effect<void, unknown> {\n if (isReleased())\n return Effect.void;\n return readEntryFileEffect(dir, id, (value) => decodeGateLeaseRecord(value, { experimentId: mine.experimentId, slot: mine.slot })).pipe(Effect.flatMap((current) => {\n if (current === undefined || !isSameHolder(current, mine) || isReleased())\n return Effect.void;\n return writeEntryFileEffect(dir, id, { ...current, heartbeatAt: new Date(nowMs).toISOString() });\n }));\n}\nfunction makeAbortError(signal: AbortSignal | undefined): Error {\n const reason = signal?.reason;\n if (reason instanceof Error)\n return reason;\n const err = new Error(\"aborted while waiting for experiment gate slot\");\n err.name = \"AbortError\";\n return err;\n}\nfunction awaitAbort(signal: AbortSignal | undefined): Effect.Effect<never, Error> {\n if (signal === undefined)\n return Effect.never;\n return Effect.async((resume, effectSignal) => {\n let completed = false;\n const cleanup = (): void => {\n signal.removeEventListener(\"abort\", onAbort);\n effectSignal.removeEventListener(\"abort\", onEffectAbort);\n };\n const cancel = (): void => {\n if (completed)\n return;\n completed = true;\n cleanup();\n };\n const onAbort = (): void => {\n if (completed)\n return;\n cancel();\n resume(Effect.fail(makeAbortError(signal)));\n };\n const onEffectAbort = (): void => cancel();\n signal.addEventListener(\"abort\", onAbort, { once: true });\n effectSignal.addEventListener(\"abort\", onEffectAbort, { once: true });\n // Both listeners must be live before inspecting either signal: otherwise\n // an abort between inspection and registration could strand the waiter.\n if (effectSignal.aborted)\n onEffectAbort();\n else if (signal.aborted)\n onAbort();\n return Effect.sync(cancel);\n });\n}\nfunction delayOrAbortEffect(ms: number, signal: AbortSignal | undefined): Effect.Effect<void, Error> {\n if (signal?.aborted)\n return Effect.fail(makeAbortError(signal));\n return Effect.raceFirst(Effect.sleep(ms), awaitAbort(signal)).pipe(Effect.asVoid);\n}\nexport interface GateLeaseEffectClaim {\n readonly slot: number;\n readonly release: Effect.Effect<void, unknown>;\n}\nexport interface AcquireGateSlotEffectResult {\n claim: GateLeaseEffectClaim;\n takenOver: boolean;\n takenOverFrom?: GateLeaseRecord;\n}\nconst held = new Map<string, Effect.Effect<void, unknown>>();\nfunction heldKey(niceevalRoot: string, id: string): string {\n return `${niceevalRoot} ${id}`;\n}\n/** 高层 Effect 入口:等待可中断;心跳顺序化,release 等正在飞的不可中断续租结束再删除。 */\nexport function acquireGateSlotEffect(niceevalRoot: string, experimentId: string, maxConcurrency: number, identity: {\n pid: number;\n host: string;\n}, opts: {\n signal?: AbortSignal;\n pollIntervalMs?: number;\n heartbeatIntervalMs?: number;\n onWaitStart?: (holders: GateLeaseRecord[]) => void;\n} = {}): Effect.Effect<AcquireGateSlotEffectResult, unknown> {\n const heartbeatIntervalMs = opts.heartbeatIntervalMs ?? GATE_LEASE_HEARTBEAT_INTERVAL_MS;\n const pollIntervalMs = opts.pollIntervalMs ?? heartbeatIntervalMs;\n let waitStarted = false;\n const acquireLoop = (): Effect.Effect<{\n slot: number;\n takenOver: boolean;\n takenOverFrom?: GateLeaseRecord;\n record: GateLeaseRecord;\n }, unknown> => Effect.suspend(() => {\n if (opts.signal?.aborted)\n return Effect.fail(makeAbortError(opts.signal));\n return Clock.currentTimeMillis.pipe(Effect.flatMap((nowMs) => tryAcquireGateSlotOnceEffect(niceevalRoot, experimentId, maxConcurrency, identity, nowMs)), Effect.flatMap((result) => {\n if (result.kind === \"acquired\")\n return Effect.succeed(result);\n const reportWait = waitStarted\n ? Effect.void\n : Effect.sync(() => {\n waitStarted = true;\n opts.onWaitStart?.(result.holders);\n });\n return reportWait.pipe(Effect.zipRight(delayOrAbortEffect(pollIntervalMs, opts.signal)), Effect.zipRight(acquireLoop()));\n }));\n });\n return Effect.uninterruptibleMask((restore) => restore(acquireLoop()).pipe(Effect.flatMap(({ slot, takenOver, takenOverFrom, record }) => {\n const dir = gateLeasesDirOf(niceevalRoot);\n const id = gateLeaseEntryId(experimentId, slot);\n const key = heldKey(niceevalRoot, id);\n let released = false;\n const heartbeat = Effect.forever(Effect.sleep(heartbeatIntervalMs).pipe(Effect.zipRight(Effect.uninterruptible(Clock.currentTimeMillis.pipe(Effect.flatMap((nowMs) => renewHeartbeatEffect(dir, id, record, nowMs, () => released)))).pipe(Effect.ignore))));\n // A child inherits the parent's interruptibility. This branch still\n // runs under the acquisition mask, so restore the heartbeat before\n // forking; otherwise release would wait forever while interrupting an\n // uninterruptible sleeping fiber.\n return Effect.forkDaemon(restore(heartbeat)).pipe(Effect.map((fiber) => {\n const release = Effect.uninterruptible(Effect.suspend(() => {\n if (released)\n return Effect.void;\n released = true;\n held.delete(key);\n return Fiber.interrupt(fiber).pipe(Effect.zipRight(readEntryFileEffect(dir, id, (value) => decodeGateLeaseRecord(value, { experimentId, slot }))), Effect.flatMap((current) => current !== undefined && !isSameHolder(current, record)\n ? Effect.void\n : nodeIo(() => rm(join(dir, `${id}.json`), { force: true })).pipe(Effect.zipRight(fsyncDirEffect(dir)))));\n }));\n held.set(key, release);\n return { claim: { slot, release }, takenOver, ...(takenOverFrom === undefined ? {} : { takenOverFrom }) };\n }));\n })));\n}\n/** 强清兜底:尽力释放当前进程持有的每一条租约。 */\nexport function drainHeldGateLeasesEffect(): Effect.Effect<number> {\n const releases = [...held.values()];\n return Effect.forEach(releases, (release) => Effect.exit(release), { discard: true }).pipe(Effect.as(releases.length));\n}\n/** 当前进程仍持有的实验闸租约数量,供退出清理与可观察状态汇总。 */\nexport function pendingHeldGateLeaseCount(): number {\n return held.size;\n}\n"]}
@@ -1,62 +0,0 @@
1
- import { Effect } from "effect";
2
- /** 逐槽租约文件的 JSON 形状。身份的权威在内容,文件名只须无碰撞、不承载解析。 */
3
- export interface GateLeaseRecord {
4
- experimentId: string;
5
- /** 槽位序号,取值 0..N-1。 */
6
- slot: number;
7
- /** 本持有者 resolved 的名额上限 N。用于 min-N:生效名额取在场声明的最小值。 */
8
- declaredN: number;
9
- pid: number;
10
- host: string;
11
- startedAt: string;
12
- heartbeatAt: string;
13
- }
14
- type GateSlotAcquired = {
15
- kind: "acquired";
16
- slot: number;
17
- takenOver: boolean;
18
- takenOverFrom?: GateLeaseRecord;
19
- record: GateLeaseRecord;
20
- };
21
- type GateSlotAttempt = GateSlotAcquired | {
22
- kind: "full";
23
- holders: GateLeaseRecord[];
24
- };
25
- /** 持有者续租心跳的周期。与用例锁同参数。 */
26
- export declare const GATE_LEASE_HEARTBEAT_INTERVAL_MS = 10000;
27
- /** `heartbeatAt` 落后当前时间超过这个阈值(三个心跳周期)即视为持有者已死。 */
28
- export declare const GATE_LEASE_EXPIRY_MS = 30000;
29
- export declare function gateLeasesDirOf(niceevalRoot: string): string;
30
- /** Effect 主 API:读取该实验当前在场的全部租约记录,无副作用。 */
31
- export declare function readGateLeasesEffect(niceevalRoot: string, experimentId: string): Effect.Effect<GateLeaseRecord[], unknown>;
32
- /** 过期判据:只看心跳时间戳,不看 pid。 */
33
- export declare function isGateLeaseExpired(record: GateLeaseRecord, nowMs: number): boolean;
34
- /** 一次非阻塞取位:空槽 O_EXCL 创建,满位时只接管过期或损坏槽。 */
35
- export declare function tryAcquireGateSlotOnceEffect(niceevalRoot: string, experimentId: string, maxConcurrency: number, identity: {
36
- pid: number;
37
- host: string;
38
- }, nowMs: number): Effect.Effect<GateSlotAttempt, unknown>;
39
- export interface GateLeaseEffectClaim {
40
- readonly slot: number;
41
- readonly release: Effect.Effect<void, unknown>;
42
- }
43
- export interface AcquireGateSlotEffectResult {
44
- claim: GateLeaseEffectClaim;
45
- takenOver: boolean;
46
- takenOverFrom?: GateLeaseRecord;
47
- }
48
- /** 高层 Effect 入口:等待可中断;心跳顺序化,release 等正在飞的不可中断续租结束再删除。 */
49
- export declare function acquireGateSlotEffect(niceevalRoot: string, experimentId: string, maxConcurrency: number, identity: {
50
- pid: number;
51
- host: string;
52
- }, opts?: {
53
- signal?: AbortSignal;
54
- pollIntervalMs?: number;
55
- heartbeatIntervalMs?: number;
56
- onWaitStart?: (holders: GateLeaseRecord[]) => void;
57
- }): Effect.Effect<AcquireGateSlotEffectResult, unknown>;
58
- /** 强清兜底:尽力释放当前进程持有的每一条租约。 */
59
- export declare function drainHeldGateLeasesEffect(): Effect.Effect<number>;
60
- /** 当前进程仍持有的实验闸租约数量,供退出清理与可观察状态汇总。 */
61
- export declare function pendingHeldGateLeaseCount(): number;
62
- export {};
@@ -1,62 +0,0 @@
1
- import { Effect } from "effect";
2
- /** 逐槽租约文件的 JSON 形状。身份的权威在内容,文件名只须无碰撞、不承载解析。 */
3
- export interface GateLeaseRecord {
4
- experimentId: string;
5
- /** 槽位序号,取值 0..N-1。 */
6
- slot: number;
7
- /** 本持有者 resolved 的名额上限 N。用于 min-N:生效名额取在场声明的最小值。 */
8
- declaredN: number;
9
- pid: number;
10
- host: string;
11
- startedAt: string;
12
- heartbeatAt: string;
13
- }
14
- type GateSlotAcquired = {
15
- kind: "acquired";
16
- slot: number;
17
- takenOver: boolean;
18
- takenOverFrom?: GateLeaseRecord;
19
- record: GateLeaseRecord;
20
- };
21
- type GateSlotAttempt = GateSlotAcquired | {
22
- kind: "full";
23
- holders: GateLeaseRecord[];
24
- };
25
- /** 持有者续租心跳的周期。与用例锁同参数。 */
26
- export declare const GATE_LEASE_HEARTBEAT_INTERVAL_MS = 10000;
27
- /** `heartbeatAt` 落后当前时间超过这个阈值(三个心跳周期)即视为持有者已死。 */
28
- export declare const GATE_LEASE_EXPIRY_MS = 30000;
29
- export declare function gateLeasesDirOf(niceevalRoot: string): string;
30
- /** Effect 主 API:读取该实验当前在场的全部租约记录,无副作用。 */
31
- export declare function readGateLeasesEffect(niceevalRoot: string, experimentId: string): Effect.Effect<GateLeaseRecord[], unknown>;
32
- /** 过期判据:只看心跳时间戳,不看 pid。 */
33
- export declare function isGateLeaseExpired(record: GateLeaseRecord, nowMs: number): boolean;
34
- /** 一次非阻塞取位:空槽 O_EXCL 创建,满位时只接管过期或损坏槽。 */
35
- export declare function tryAcquireGateSlotOnceEffect(niceevalRoot: string, experimentId: string, maxConcurrency: number, identity: {
36
- pid: number;
37
- host: string;
38
- }, nowMs: number): Effect.Effect<GateSlotAttempt, unknown>;
39
- export interface GateLeaseEffectClaim {
40
- readonly slot: number;
41
- readonly release: Effect.Effect<void, unknown>;
42
- }
43
- export interface AcquireGateSlotEffectResult {
44
- claim: GateLeaseEffectClaim;
45
- takenOver: boolean;
46
- takenOverFrom?: GateLeaseRecord;
47
- }
48
- /** 高层 Effect 入口:等待可中断;心跳顺序化,release 等正在飞的不可中断续租结束再删除。 */
49
- export declare function acquireGateSlotEffect(niceevalRoot: string, experimentId: string, maxConcurrency: number, identity: {
50
- pid: number;
51
- host: string;
52
- }, opts?: {
53
- signal?: AbortSignal;
54
- pollIntervalMs?: number;
55
- heartbeatIntervalMs?: number;
56
- onWaitStart?: (holders: GateLeaseRecord[]) => void;
57
- }): Effect.Effect<AcquireGateSlotEffectResult, unknown>;
58
- /** 强清兜底:尽力释放当前进程持有的每一条租约。 */
59
- export declare function drainHeldGateLeasesEffect(): Effect.Effect<number>;
60
- /** 当前进程仍持有的实验闸租约数量,供退出清理与可观察状态汇总。 */
61
- export declare function pendingHeldGateLeaseCount(): number;
62
- export {};
@@ -1,62 +0,0 @@
1
- import { Effect } from "effect";
2
- /** 逐槽租约文件的 JSON 形状。身份的权威在内容,文件名只须无碰撞、不承载解析。 */
3
- export interface GateLeaseRecord {
4
- experimentId: string;
5
- /** 槽位序号,取值 0..N-1。 */
6
- slot: number;
7
- /** 本持有者 resolved 的名额上限 N。用于 min-N:生效名额取在场声明的最小值。 */
8
- declaredN: number;
9
- pid: number;
10
- host: string;
11
- startedAt: string;
12
- heartbeatAt: string;
13
- }
14
- type GateSlotAcquired = {
15
- kind: "acquired";
16
- slot: number;
17
- takenOver: boolean;
18
- takenOverFrom?: GateLeaseRecord;
19
- record: GateLeaseRecord;
20
- };
21
- type GateSlotAttempt = GateSlotAcquired | {
22
- kind: "full";
23
- holders: GateLeaseRecord[];
24
- };
25
- /** 持有者续租心跳的周期。与用例锁同参数。 */
26
- export declare const GATE_LEASE_HEARTBEAT_INTERVAL_MS = 10000;
27
- /** `heartbeatAt` 落后当前时间超过这个阈值(三个心跳周期)即视为持有者已死。 */
28
- export declare const GATE_LEASE_EXPIRY_MS = 30000;
29
- export declare function gateLeasesDirOf(niceevalRoot: string): string;
30
- /** Effect 主 API:读取该实验当前在场的全部租约记录,无副作用。 */
31
- export declare function readGateLeasesEffect(niceevalRoot: string, experimentId: string): Effect.Effect<GateLeaseRecord[], unknown>;
32
- /** 过期判据:只看心跳时间戳,不看 pid。 */
33
- export declare function isGateLeaseExpired(record: GateLeaseRecord, nowMs: number): boolean;
34
- /** 一次非阻塞取位:空槽 O_EXCL 创建,满位时只接管过期或损坏槽。 */
35
- export declare function tryAcquireGateSlotOnceEffect(niceevalRoot: string, experimentId: string, maxConcurrency: number, identity: {
36
- pid: number;
37
- host: string;
38
- }, nowMs: number): Effect.Effect<GateSlotAttempt, unknown>;
39
- export interface GateLeaseEffectClaim {
40
- readonly slot: number;
41
- readonly release: Effect.Effect<void, unknown>;
42
- }
43
- export interface AcquireGateSlotEffectResult {
44
- claim: GateLeaseEffectClaim;
45
- takenOver: boolean;
46
- takenOverFrom?: GateLeaseRecord;
47
- }
48
- /** 高层 Effect 入口:等待可中断;心跳顺序化,release 等正在飞的不可中断续租结束再删除。 */
49
- export declare function acquireGateSlotEffect(niceevalRoot: string, experimentId: string, maxConcurrency: number, identity: {
50
- pid: number;
51
- host: string;
52
- }, opts?: {
53
- signal?: AbortSignal;
54
- pollIntervalMs?: number;
55
- heartbeatIntervalMs?: number;
56
- onWaitStart?: (holders: GateLeaseRecord[]) => void;
57
- }): Effect.Effect<AcquireGateSlotEffectResult, unknown>;
58
- /** 强清兜底:尽力释放当前进程持有的每一条租约。 */
59
- export declare function drainHeldGateLeasesEffect(): Effect.Effect<number>;
60
- /** 当前进程仍持有的实验闸租约数量,供退出清理与可观察状态汇总。 */
61
- export declare function pendingHeldGateLeaseCount(): number;
62
- export {};
@@ -1,22 +0,0 @@
1
- import { createRequire as __niceevalCreateRequire } from "node:module";
2
- const __niceevalRequire = __niceevalCreateRequire(import.meta.url);
3
- const __niceevalCanonical = __niceevalRequire("./gate-lease.cjs");
4
- const __niceevalExport0 = __niceevalCanonical["GATE_LEASE_EXPIRY_MS"];
5
- export { __niceevalExport0 as GATE_LEASE_EXPIRY_MS };
6
- const __niceevalExport1 = __niceevalCanonical["GATE_LEASE_HEARTBEAT_INTERVAL_MS"];
7
- export { __niceevalExport1 as GATE_LEASE_HEARTBEAT_INTERVAL_MS };
8
- const __niceevalExport2 = __niceevalCanonical["acquireGateSlotEffect"];
9
- export { __niceevalExport2 as acquireGateSlotEffect };
10
- const __niceevalExport3 = __niceevalCanonical["drainHeldGateLeasesEffect"];
11
- export { __niceevalExport3 as drainHeldGateLeasesEffect };
12
- const __niceevalExport4 = __niceevalCanonical["gateLeasesDirOf"];
13
- export { __niceevalExport4 as gateLeasesDirOf };
14
- const __niceevalExport5 = __niceevalCanonical["isGateLeaseExpired"];
15
- export { __niceevalExport5 as isGateLeaseExpired };
16
- const __niceevalExport6 = __niceevalCanonical["pendingHeldGateLeaseCount"];
17
- export { __niceevalExport6 as pendingHeldGateLeaseCount };
18
- const __niceevalExport7 = __niceevalCanonical["readGateLeasesEffect"];
19
- export { __niceevalExport7 as readGateLeasesEffect };
20
- const __niceevalExport8 = __niceevalCanonical["tryAcquireGateSlotOnceEffect"];
21
- export { __niceevalExport8 as tryAcquireGateSlotOnceEffect };
22
- //# sourceMappingURL=gate-lease.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"gate-lease.js","sources":[],"names":[],"mappings":""}