@xrkseek/harness 0.4.8 → 0.4.10

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 (245) hide show
  1. package/node_modules/@xrkseek/cordis/LICENSE +21 -0
  2. package/node_modules/@xrkseek/cordis/README.md +14 -0
  3. package/node_modules/@xrkseek/cordis/bin.js +16 -0
  4. package/node_modules/@xrkseek/cordis/lib/index.js +1828 -0
  5. package/node_modules/@xrkseek/cordis/lib/types/context.d.ts +101 -0
  6. package/node_modules/@xrkseek/cordis/lib/types/context.d.ts.map +1 -0
  7. package/node_modules/@xrkseek/cordis/lib/types/events.d.ts +240 -0
  8. package/node_modules/@xrkseek/cordis/lib/types/events.d.ts.map +1 -0
  9. package/node_modules/@xrkseek/cordis/lib/types/fiber.d.ts +202 -0
  10. package/node_modules/@xrkseek/cordis/lib/types/fiber.d.ts.map +1 -0
  11. package/node_modules/@xrkseek/cordis/lib/types/index.d.ts +15 -0
  12. package/node_modules/@xrkseek/cordis/lib/types/index.d.ts.map +1 -0
  13. package/node_modules/@xrkseek/cordis/lib/types/logger.d.ts +105 -0
  14. package/node_modules/@xrkseek/cordis/lib/types/logger.d.ts.map +1 -0
  15. package/node_modules/@xrkseek/cordis/lib/types/reflect.d.ts +186 -0
  16. package/node_modules/@xrkseek/cordis/lib/types/reflect.d.ts.map +1 -0
  17. package/node_modules/@xrkseek/cordis/lib/types/registry.d.ts +201 -0
  18. package/node_modules/@xrkseek/cordis/lib/types/registry.d.ts.map +1 -0
  19. package/node_modules/@xrkseek/cordis/lib/types/service.d.ts +55 -0
  20. package/node_modules/@xrkseek/cordis/lib/types/service.d.ts.map +1 -0
  21. package/node_modules/@xrkseek/cordis/lib/types/utils.d.ts +62 -0
  22. package/node_modules/@xrkseek/cordis/lib/types/utils.d.ts.map +1 -0
  23. package/node_modules/@xrkseek/cordis/package.json +49 -0
  24. package/node_modules/@xrkseek/cordis/src/context.d.ts +101 -0
  25. package/node_modules/@xrkseek/cordis/src/context.d.ts.map +1 -0
  26. package/node_modules/@xrkseek/cordis/src/context.js +99 -0
  27. package/node_modules/@xrkseek/cordis/src/context.js.map +1 -0
  28. package/node_modules/@xrkseek/cordis/src/context.ts +146 -0
  29. package/node_modules/@xrkseek/cordis/src/events.d.ts +240 -0
  30. package/node_modules/@xrkseek/cordis/src/events.d.ts.map +1 -0
  31. package/node_modules/@xrkseek/cordis/src/events.js +199 -0
  32. package/node_modules/@xrkseek/cordis/src/events.js.map +1 -0
  33. package/node_modules/@xrkseek/cordis/src/events.ts +352 -0
  34. package/node_modules/@xrkseek/cordis/src/fiber.d.ts +202 -0
  35. package/node_modules/@xrkseek/cordis/src/fiber.d.ts.map +1 -0
  36. package/node_modules/@xrkseek/cordis/src/fiber.js +677 -0
  37. package/node_modules/@xrkseek/cordis/src/fiber.js.map +1 -0
  38. package/node_modules/@xrkseek/cordis/src/fiber.ts +754 -0
  39. package/node_modules/@xrkseek/cordis/src/index.d.ts +15 -0
  40. package/node_modules/@xrkseek/cordis/src/index.d.ts.map +1 -0
  41. package/node_modules/@xrkseek/cordis/src/index.js +15 -0
  42. package/node_modules/@xrkseek/cordis/src/index.js.map +1 -0
  43. package/node_modules/@xrkseek/cordis/src/index.ts +14 -0
  44. package/node_modules/@xrkseek/cordis/src/logger.d.ts +105 -0
  45. package/node_modules/@xrkseek/cordis/src/logger.d.ts.map +1 -0
  46. package/node_modules/@xrkseek/cordis/src/logger.js +193 -0
  47. package/node_modules/@xrkseek/cordis/src/logger.js.map +1 -0
  48. package/node_modules/@xrkseek/cordis/src/logger.ts +270 -0
  49. package/node_modules/@xrkseek/cordis/src/reflect.d.ts +186 -0
  50. package/node_modules/@xrkseek/cordis/src/reflect.d.ts.map +1 -0
  51. package/node_modules/@xrkseek/cordis/src/reflect.js +311 -0
  52. package/node_modules/@xrkseek/cordis/src/reflect.js.map +1 -0
  53. package/node_modules/@xrkseek/cordis/src/reflect.ts +418 -0
  54. package/node_modules/@xrkseek/cordis/src/registry.d.ts +201 -0
  55. package/node_modules/@xrkseek/cordis/src/registry.d.ts.map +1 -0
  56. package/node_modules/@xrkseek/cordis/src/registry.js +218 -0
  57. package/node_modules/@xrkseek/cordis/src/registry.js.map +1 -0
  58. package/node_modules/@xrkseek/cordis/src/registry.ts +337 -0
  59. package/node_modules/@xrkseek/cordis/src/service.d.ts +55 -0
  60. package/node_modules/@xrkseek/cordis/src/service.d.ts.map +1 -0
  61. package/node_modules/@xrkseek/cordis/src/service.js +113 -0
  62. package/node_modules/@xrkseek/cordis/src/service.js.map +1 -0
  63. package/node_modules/@xrkseek/cordis/src/service.ts +115 -0
  64. package/node_modules/@xrkseek/cordis/src/utils.d.ts +62 -0
  65. package/node_modules/@xrkseek/cordis/src/utils.d.ts.map +1 -0
  66. package/node_modules/@xrkseek/cordis/src/utils.js +271 -0
  67. package/node_modules/@xrkseek/cordis/src/utils.js.map +1 -0
  68. package/node_modules/@xrkseek/cordis/src/utils.ts +287 -0
  69. package/node_modules/@xrkseek/core-agent-loop/dist/index.d.ts.map +1 -1
  70. package/node_modules/@xrkseek/core-agent-loop/dist/index.js +39 -68
  71. package/node_modules/@xrkseek/core-agent-loop/dist/index.js.map +1 -1
  72. package/node_modules/@xrkseek/core-session/dist/compaction.d.ts +4 -3
  73. package/node_modules/@xrkseek/core-session/dist/compaction.d.ts.map +1 -1
  74. package/node_modules/@xrkseek/core-session/dist/compaction.js.map +1 -1
  75. package/node_modules/@xrkseek/core-tools/dist/subagent-prompt.d.ts.map +1 -1
  76. package/node_modules/@xrkseek/core-tools/dist/subagent-prompt.js +2 -1
  77. package/node_modules/@xrkseek/core-tools/dist/subagent-prompt.js.map +1 -1
  78. package/node_modules/@xrkseek/exec-image-gen/README.md +1 -1
  79. package/node_modules/@xrkseek/exec-image-gen/dist/catalog.d.ts +16 -0
  80. package/node_modules/@xrkseek/exec-image-gen/dist/catalog.d.ts.map +1 -0
  81. package/node_modules/@xrkseek/exec-image-gen/dist/catalog.js +152 -0
  82. package/node_modules/@xrkseek/exec-image-gen/dist/catalog.js.map +1 -0
  83. package/node_modules/@xrkseek/exec-image-gen/dist/deepinfra-http.d.ts +9 -0
  84. package/node_modules/@xrkseek/exec-image-gen/dist/deepinfra-http.d.ts.map +1 -0
  85. package/node_modules/@xrkseek/exec-image-gen/dist/deepinfra-http.js +21 -0
  86. package/node_modules/@xrkseek/exec-image-gen/dist/deepinfra-http.js.map +1 -0
  87. package/node_modules/@xrkseek/exec-image-gen/dist/fal-http.d.ts +16 -0
  88. package/node_modules/@xrkseek/exec-image-gen/dist/fal-http.d.ts.map +1 -0
  89. package/node_modules/@xrkseek/exec-image-gen/dist/fal-http.js +189 -0
  90. package/node_modules/@xrkseek/exec-image-gen/dist/fal-http.js.map +1 -0
  91. package/node_modules/@xrkseek/exec-image-gen/dist/index.d.ts +10 -5
  92. package/node_modules/@xrkseek/exec-image-gen/dist/index.d.ts.map +1 -1
  93. package/node_modules/@xrkseek/exec-image-gen/dist/index.js +174 -18
  94. package/node_modules/@xrkseek/exec-image-gen/dist/index.js.map +1 -1
  95. package/node_modules/@xrkseek/exec-image-gen/dist/krea-http.d.ts +16 -0
  96. package/node_modules/@xrkseek/exec-image-gen/dist/krea-http.d.ts.map +1 -0
  97. package/node_modules/@xrkseek/exec-image-gen/dist/krea-http.js +144 -0
  98. package/node_modules/@xrkseek/exec-image-gen/dist/krea-http.js.map +1 -0
  99. package/node_modules/@xrkseek/exec-image-gen/dist/meta-ai-http.d.ts +9 -0
  100. package/node_modules/@xrkseek/exec-image-gen/dist/meta-ai-http.d.ts.map +1 -0
  101. package/node_modules/@xrkseek/exec-image-gen/dist/meta-ai-http.js +21 -0
  102. package/node_modules/@xrkseek/exec-image-gen/dist/meta-ai-http.js.map +1 -0
  103. package/node_modules/@xrkseek/exec-image-gen/dist/openai-http.d.ts +4 -1
  104. package/node_modules/@xrkseek/exec-image-gen/dist/openai-http.d.ts.map +1 -1
  105. package/node_modules/@xrkseek/exec-image-gen/dist/openai-http.js +7 -5
  106. package/node_modules/@xrkseek/exec-image-gen/dist/openai-http.js.map +1 -1
  107. package/node_modules/@xrkseek/exec-image-gen/dist/openrouter-http.d.ts +14 -0
  108. package/node_modules/@xrkseek/exec-image-gen/dist/openrouter-http.d.ts.map +1 -0
  109. package/node_modules/@xrkseek/exec-image-gen/dist/openrouter-http.js +117 -0
  110. package/node_modules/@xrkseek/exec-image-gen/dist/openrouter-http.js.map +1 -0
  111. package/node_modules/@xrkseek/exec-image-gen/dist/tools.d.ts.map +1 -1
  112. package/node_modules/@xrkseek/exec-image-gen/dist/tools.js +43 -6
  113. package/node_modules/@xrkseek/exec-image-gen/dist/tools.js.map +1 -1
  114. package/node_modules/@xrkseek/exec-image-gen/dist/types.d.ts +1 -1
  115. package/node_modules/@xrkseek/exec-image-gen/dist/types.d.ts.map +1 -1
  116. package/node_modules/@xrkseek/exec-image-gen/dist/types.js.map +1 -1
  117. package/node_modules/@xrkseek/exec-image-gen/dist/xai-http.d.ts +16 -0
  118. package/node_modules/@xrkseek/exec-image-gen/dist/xai-http.d.ts.map +1 -0
  119. package/node_modules/@xrkseek/exec-image-gen/dist/xai-http.js +137 -0
  120. package/node_modules/@xrkseek/exec-image-gen/dist/xai-http.js.map +1 -0
  121. package/node_modules/@xrkseek/exec-memory/dist/consolidate-pipeline.d.ts +52 -0
  122. package/node_modules/@xrkseek/exec-memory/dist/consolidate-pipeline.d.ts.map +1 -0
  123. package/node_modules/@xrkseek/exec-memory/dist/consolidate-pipeline.js +216 -0
  124. package/node_modules/@xrkseek/exec-memory/dist/consolidate-pipeline.js.map +1 -0
  125. package/node_modules/@xrkseek/exec-memory/dist/index.d.ts +1 -0
  126. package/node_modules/@xrkseek/exec-memory/dist/index.d.ts.map +1 -1
  127. package/node_modules/@xrkseek/exec-memory/dist/index.js +1 -0
  128. package/node_modules/@xrkseek/exec-memory/dist/index.js.map +1 -1
  129. package/node_modules/@xrkseek/exec-memory/dist/tools.d.ts.map +1 -1
  130. package/node_modules/@xrkseek/exec-memory/dist/tools.js +20 -7
  131. package/node_modules/@xrkseek/exec-memory/dist/tools.js.map +1 -1
  132. package/node_modules/@xrkseek/exec-video-gen/README.md +1 -1
  133. package/node_modules/@xrkseek/exec-video-gen/dist/catalog.d.ts +14 -1
  134. package/node_modules/@xrkseek/exec-video-gen/dist/catalog.d.ts.map +1 -1
  135. package/node_modules/@xrkseek/exec-video-gen/dist/catalog.js +99 -1
  136. package/node_modules/@xrkseek/exec-video-gen/dist/catalog.js.map +1 -1
  137. package/node_modules/@xrkseek/exec-video-gen/dist/deepinfra-http.d.ts +9 -0
  138. package/node_modules/@xrkseek/exec-video-gen/dist/deepinfra-http.d.ts.map +1 -0
  139. package/node_modules/@xrkseek/exec-video-gen/dist/deepinfra-http.js +17 -0
  140. package/node_modules/@xrkseek/exec-video-gen/dist/deepinfra-http.js.map +1 -0
  141. package/node_modules/@xrkseek/exec-video-gen/dist/fal-http.d.ts +14 -0
  142. package/node_modules/@xrkseek/exec-video-gen/dist/fal-http.d.ts.map +1 -0
  143. package/node_modules/@xrkseek/exec-video-gen/dist/fal-http.js +342 -0
  144. package/node_modules/@xrkseek/exec-video-gen/dist/fal-http.js.map +1 -0
  145. package/node_modules/@xrkseek/exec-video-gen/dist/index.d.ts +8 -6
  146. package/node_modules/@xrkseek/exec-video-gen/dist/index.d.ts.map +1 -1
  147. package/node_modules/@xrkseek/exec-video-gen/dist/index.js +122 -19
  148. package/node_modules/@xrkseek/exec-video-gen/dist/index.js.map +1 -1
  149. package/node_modules/@xrkseek/exec-video-gen/dist/openai-http.d.ts +4 -1
  150. package/node_modules/@xrkseek/exec-video-gen/dist/openai-http.d.ts.map +1 -1
  151. package/node_modules/@xrkseek/exec-video-gen/dist/openai-http.js +21 -15
  152. package/node_modules/@xrkseek/exec-video-gen/dist/openai-http.js.map +1 -1
  153. package/node_modules/@xrkseek/exec-video-gen/dist/openrouter-http.d.ts +9 -0
  154. package/node_modules/@xrkseek/exec-video-gen/dist/openrouter-http.d.ts.map +1 -0
  155. package/node_modules/@xrkseek/exec-video-gen/dist/openrouter-http.js +18 -0
  156. package/node_modules/@xrkseek/exec-video-gen/dist/openrouter-http.js.map +1 -0
  157. package/node_modules/@xrkseek/exec-video-gen/dist/tools.d.ts.map +1 -1
  158. package/node_modules/@xrkseek/exec-video-gen/dist/tools.js +26 -6
  159. package/node_modules/@xrkseek/exec-video-gen/dist/tools.js.map +1 -1
  160. package/node_modules/@xrkseek/exec-video-gen/dist/types.d.ts +1 -1
  161. package/node_modules/@xrkseek/exec-video-gen/dist/types.d.ts.map +1 -1
  162. package/node_modules/@xrkseek/exec-video-gen/dist/types.js.map +1 -1
  163. package/node_modules/@xrkseek/exec-video-gen/dist/xai-http.d.ts +18 -0
  164. package/node_modules/@xrkseek/exec-video-gen/dist/xai-http.d.ts.map +1 -0
  165. package/node_modules/@xrkseek/exec-video-gen/dist/xai-http.js +263 -0
  166. package/node_modules/@xrkseek/exec-video-gen/dist/xai-http.js.map +1 -0
  167. package/node_modules/@xrkseek/preset-harness/dist/preset.d.ts.map +1 -1
  168. package/node_modules/@xrkseek/preset-harness/dist/preset.js +12 -3
  169. package/node_modules/@xrkseek/preset-harness/dist/preset.js.map +1 -1
  170. package/node_modules/@xrkseek/preset-harness/dist/tsconfig.tsbuildinfo +1 -1
  171. package/node_modules/@xrkseek/preset-minimal/dist/tsconfig.tsbuildinfo +1 -1
  172. package/node_modules/@xrkseek/preset-server/dist/tsconfig.tsbuildinfo +1 -1
  173. package/node_modules/@xrkseek/server-face/dist/agent-team-graph.d.ts +31 -0
  174. package/node_modules/@xrkseek/server-face/dist/agent-team-graph.d.ts.map +1 -1
  175. package/node_modules/@xrkseek/server-face/dist/agent-team-graph.js +125 -1
  176. package/node_modules/@xrkseek/server-face/dist/agent-team-graph.js.map +1 -1
  177. package/node_modules/@xrkseek/server-face/dist/context.d.ts +19 -1
  178. package/node_modules/@xrkseek/server-face/dist/context.d.ts.map +1 -1
  179. package/node_modules/@xrkseek/server-face/dist/index.d.ts +3 -3
  180. package/node_modules/@xrkseek/server-face/dist/index.d.ts.map +1 -1
  181. package/node_modules/@xrkseek/server-face/dist/index.js +1 -1
  182. package/node_modules/@xrkseek/server-face/dist/index.js.map +1 -1
  183. package/node_modules/@xrkseek/server-face/dist/mcp-oauth.d.ts.map +1 -1
  184. package/node_modules/@xrkseek/server-face/dist/mcp-oauth.js +25 -3
  185. package/node_modules/@xrkseek/server-face/dist/mcp-oauth.js.map +1 -1
  186. package/node_modules/@xrkseek/server-face/dist/ralph-tool.d.ts +2 -0
  187. package/node_modules/@xrkseek/server-face/dist/ralph-tool.d.ts.map +1 -1
  188. package/node_modules/@xrkseek/server-face/dist/ralph-tool.js +11 -5
  189. package/node_modules/@xrkseek/server-face/dist/ralph-tool.js.map +1 -1
  190. package/node_modules/@xrkseek/server-face/dist/runtime.d.ts.map +1 -1
  191. package/node_modules/@xrkseek/server-face/dist/runtime.js +1 -0
  192. package/node_modules/@xrkseek/server-face/dist/runtime.js.map +1 -1
  193. package/node_modules/@xrkseek/server-face/dist/session-status.d.ts +16 -0
  194. package/node_modules/@xrkseek/server-face/dist/session-status.d.ts.map +1 -1
  195. package/node_modules/@xrkseek/server-face/dist/session-status.js +44 -5
  196. package/node_modules/@xrkseek/server-face/dist/session-status.js.map +1 -1
  197. package/node_modules/@xrkseek/server-face/dist/settings-credentials.d.ts +9 -0
  198. package/node_modules/@xrkseek/server-face/dist/settings-credentials.d.ts.map +1 -1
  199. package/node_modules/@xrkseek/server-face/dist/settings-credentials.js +50 -0
  200. package/node_modules/@xrkseek/server-face/dist/settings-credentials.js.map +1 -1
  201. package/node_modules/@xrkseek/server-face/dist/settings-document.d.ts.map +1 -1
  202. package/node_modules/@xrkseek/server-face/dist/settings-document.js +40 -0
  203. package/node_modules/@xrkseek/server-face/dist/settings-document.js.map +1 -1
  204. package/node_modules/@xrkseek/server-face/dist/settings-schemas.d.ts.map +1 -1
  205. package/node_modules/@xrkseek/server-face/dist/settings-schemas.js +20 -4
  206. package/node_modules/@xrkseek/server-face/dist/settings-schemas.js.map +1 -1
  207. package/node_modules/@xrkseek/server-face/dist/subagent-tools.d.ts.map +1 -1
  208. package/node_modules/@xrkseek/server-face/dist/subagent-tools.js +191 -0
  209. package/node_modules/@xrkseek/server-face/dist/subagent-tools.js.map +1 -1
  210. package/node_modules/@xrkseek/server-face/dist/wire/rpc-error.d.ts.map +1 -1
  211. package/node_modules/@xrkseek/server-face/dist/wire/rpc-error.js +8 -0
  212. package/node_modules/@xrkseek/server-face/dist/wire/rpc-error.js.map +1 -1
  213. package/node_modules/@xrkseek/server-host/dist/index.d.ts.map +1 -1
  214. package/node_modules/@xrkseek/server-host/dist/index.js +140 -24
  215. package/node_modules/@xrkseek/server-host/dist/index.js.map +1 -1
  216. package/node_modules/@xrkseek/server-host/dist/sidebar-face-bridge.d.ts.map +1 -1
  217. package/node_modules/@xrkseek/server-host/dist/sidebar-face-bridge.js +6 -0
  218. package/node_modules/@xrkseek/server-host/dist/sidebar-face-bridge.js.map +1 -1
  219. package/node_modules/@xrkseek/server-host/dist/workflow-engine-mount.d.ts +40 -0
  220. package/node_modules/@xrkseek/server-host/dist/workflow-engine-mount.d.ts.map +1 -0
  221. package/node_modules/@xrkseek/server-host/dist/workflow-engine-mount.js +162 -0
  222. package/node_modules/@xrkseek/server-host/dist/workflow-engine-mount.js.map +1 -0
  223. package/node_modules/@xrkseek/server-host/package.json +2 -0
  224. package/node_modules/@xrkseek/server-http/dist/sidebar/sidebar-adapter.d.ts.map +1 -1
  225. package/node_modules/@xrkseek/server-http/dist/sidebar/sidebar-adapter.js +20 -0
  226. package/node_modules/@xrkseek/server-http/dist/sidebar/sidebar-adapter.js.map +1 -1
  227. package/node_modules/@xrkseek/server-http/dist/sidebar/sidebar-face-bridge.d.ts +10 -2
  228. package/node_modules/@xrkseek/server-http/dist/sidebar/sidebar-face-bridge.d.ts.map +1 -1
  229. package/node_modules/@xrkseek/xrk-workflow/README.i18n.yaml +6 -0
  230. package/node_modules/@xrkseek/xrk-workflow/README.md +73 -0
  231. package/node_modules/@xrkseek/xrk-workflow/README.zh.md +72 -0
  232. package/node_modules/@xrkseek/xrk-workflow/lib/types/index.d.ts +177 -0
  233. package/node_modules/@xrkseek/xrk-workflow/lib/types/index.js +730 -0
  234. package/node_modules/@xrkseek/xrk-workflow/lib/types/index.js.map +1 -0
  235. package/node_modules/@xrkseek/xrk-workflow/lib/types/invariant.d.ts +13 -0
  236. package/node_modules/@xrkseek/xrk-workflow/lib/types/invariant.js +118 -0
  237. package/node_modules/@xrkseek/xrk-workflow/lib/types/invariant.js.map +1 -0
  238. package/node_modules/@xrkseek/xrk-workflow/lib/types/runtime-types.d.ts +45 -0
  239. package/node_modules/@xrkseek/xrk-workflow/lib/types/runtime-types.js +9 -0
  240. package/node_modules/@xrkseek/xrk-workflow/lib/types/runtime-types.js.map +1 -0
  241. package/node_modules/@xrkseek/xrk-workflow/lib/types/types.d.ts +118 -0
  242. package/node_modules/@xrkseek/xrk-workflow/lib/types/types.js +16 -0
  243. package/node_modules/@xrkseek/xrk-workflow/lib/types/types.js.map +1 -0
  244. package/node_modules/@xrkseek/xrk-workflow/package.json +51 -0
  245. package/package.json +5 -1
@@ -0,0 +1,199 @@
1
+ import { defineProperty } from '@xrkseek/cosmokit';
2
+ import { Context } from "./context.js";
3
+ import { DisposableList, symbols } from "./utils.js";
4
+ /**
5
+ * Return whether an event result should stop a bail-style dispatch.
6
+ *
7
+ * @param value — a listener's return value.
8
+ * @returns `true` unless `value` is `null`, `false`, or `undefined`.
9
+ */
10
+ export function isBailed(value) {
11
+ return value !== null && value !== false && value !== undefined;
12
+ }
13
+ /**
14
+ * Event bus installed as `ctx.events` and mixed into every context.
15
+ *
16
+ * The service supports concurrent, synchronous, serial, bail, and waterfall
17
+ * dispatch and automatically disposes listeners with their owning fiber.
18
+ */
19
+ export class EventsService {
20
+ ctx;
21
+ _hooks = {};
22
+ constructor(ctx) {
23
+ this.ctx = ctx;
24
+ defineProperty(this, symbols.tracker, {
25
+ property: 'ctx',
26
+ noShadow: true,
27
+ });
28
+ this.on('internal/listener', function (name, listener, options) {
29
+ if (name === 'internal/update' && !options.global) {
30
+ const hooks = this.fiber._hooks['internal/update'] ??= new DisposableList();
31
+ const method = options.prepend ? 'unshift' : 'push';
32
+ return hooks[method](listener);
33
+ }
34
+ });
35
+ this.on('internal/update', function (config, noSave, next) {
36
+ const cbs = [...this._hooks['internal/update'] || []];
37
+ const _next = () => {
38
+ const cb = cbs.shift() ?? next;
39
+ return cb.call(this, config, noSave, _next);
40
+ };
41
+ return _next();
42
+ }, { global: true, prepend: true });
43
+ }
44
+ /**
45
+ * Resolve listeners for one dispatch and apply context filtering.
46
+ *
47
+ * @param type — the dispatch mode, reported on `internal/dispatch`.
48
+ * @param args — the raw dispatch arguments; consumed up to the event name.
49
+ * @returns the matching listener callbacks, bound to the dispatch `this`.
50
+ */
51
+ dispatch(type, args) {
52
+ const thisArg = typeof args[0] === 'object' || typeof args[0] === 'function' ? args.shift() : null;
53
+ const name = args.shift();
54
+ if (!name.startsWith('internal/')) {
55
+ this.emit('internal/dispatch', type, name, args, thisArg);
56
+ }
57
+ const filter = thisArg?.[Context.filter];
58
+ return (this._hooks[name] || [])
59
+ .filter(hook => hook.global || !filter || filter.call(thisArg, hook.ctx))
60
+ .map(hook => hook.callback.bind(thisArg));
61
+ }
62
+ /**
63
+ * Run listeners concurrently and wait for all of them.
64
+ *
65
+ * @param args — optional `this`, the event name, then listener arguments.
66
+ * @returns a promise resolving once every listener has settled.
67
+ */
68
+ async parallel(...args) {
69
+ const results = await Promise.allSettled(this.dispatch('emit', args).map(async (cb) => cb(...args)));
70
+ const errors = results.filter((result) => result.status === 'rejected');
71
+ if (errors.length)
72
+ throw new AggregateError(errors.map(error => error.reason));
73
+ }
74
+ /**
75
+ * Run listeners synchronously without waiting for returned promises.
76
+ *
77
+ * @param args — optional `this`, the event name, then listener arguments.
78
+ */
79
+ emit(...args) {
80
+ this.dispatch('emit', args).map(cb => cb(...args));
81
+ }
82
+ /**
83
+ * Run listeners in order, awaiting each, until one returns a bail value.
84
+ *
85
+ * @param args — optional `this`, the event name, then listener arguments.
86
+ * @returns the first bail value (see {@link isBailed}), if any.
87
+ */
88
+ async serial(...args) {
89
+ for (const cb of this.dispatch('serial', args)) {
90
+ const result = await cb(...args);
91
+ if (isBailed(result))
92
+ return result;
93
+ }
94
+ }
95
+ /**
96
+ * Run listeners synchronously until one returns a bail value.
97
+ *
98
+ * @param args — optional `this`, the event name, then listener arguments.
99
+ * @returns the first bail value (see {@link isBailed}), if any.
100
+ */
101
+ bail(...args) {
102
+ for (const cb of this.dispatch('bail', args)) {
103
+ const result = cb(...args);
104
+ if (isBailed(result))
105
+ return result;
106
+ }
107
+ }
108
+ /**
109
+ * Compose listeners around the final `next` callback.
110
+ *
111
+ * The last dispatch argument is treated as the innermost `next`. Listeners
112
+ * run outermost-first; a listener that does not call `next()` vetoes the
113
+ * rest of the chain, including the built-in behavior.
114
+ *
115
+ * @param args — optional `this`, the event name, listener arguments, then `next`.
116
+ * @returns the outermost listener's return value.
117
+ */
118
+ waterfall(...args) {
119
+ const cbs = this.dispatch('waterfall', args);
120
+ const inner = args.pop();
121
+ const next = () => {
122
+ const cb = cbs.shift() ?? inner;
123
+ return cb(...args);
124
+ };
125
+ args.push(next);
126
+ return next();
127
+ }
128
+ /**
129
+ * Store a listener record as an effect on the current fiber.
130
+ *
131
+ * @param label — effect label shown in fiber diagnostics.
132
+ * @param hooks — the listener list for one event.
133
+ * @param callback — the listener to store.
134
+ * @param options — placement and filtering options.
135
+ * @returns a disposer that unregisters the listener.
136
+ */
137
+ register(label, hooks, callback, options) {
138
+ const method = options.prepend ? 'unshift' : 'push';
139
+ return this.ctx.fiber.effect(() => {
140
+ hooks[method]({ ctx: this.ctx, callback, ...options });
141
+ return () => this.unregister(hooks, callback);
142
+ }, label);
143
+ }
144
+ /**
145
+ * Remove a stored listener record.
146
+ *
147
+ * @param hooks — the listener list for one event.
148
+ * @param callback — the listener to remove.
149
+ * @returns `true` if the listener was found and removed.
150
+ */
151
+ unregister(hooks, callback) {
152
+ const index = hooks.findIndex(hook => hook.callback === callback);
153
+ if (index >= 0) {
154
+ hooks.splice(index, 1);
155
+ return true;
156
+ }
157
+ }
158
+ /**
159
+ * Register an event listener owned by the current fiber.
160
+ *
161
+ * The listener is removed automatically when the fiber unloads. Throws
162
+ * `CordisError('INACTIVE_EFFECT')` if the fiber is already disposed.
163
+ *
164
+ * @param name — the event name to listen for.
165
+ * @param listener — called with the dispatch arguments.
166
+ * @param options — listener options; a boolean is shorthand for `prepend`.
167
+ * @returns a disposer removing the listener; `true` if it was still registered.
168
+ */
169
+ on(name, listener, options) {
170
+ if (typeof options !== 'object') {
171
+ options = { prepend: options };
172
+ }
173
+ // handle special events
174
+ this.ctx.fiber.assertActive();
175
+ listener = this.ctx.reflect.bind(listener);
176
+ const result = this.bail(this.ctx, 'internal/listener', name, listener, options);
177
+ if (result)
178
+ return result;
179
+ const hooks = this._hooks[name] ||= [];
180
+ const label = `ctx.on(${typeof name === 'string' ? JSON.stringify(name) : name.toString()})`;
181
+ return this.register(label, hooks, listener, options);
182
+ }
183
+ /**
184
+ * Register an event listener that disposes itself after the first call.
185
+ *
186
+ * @param name — the event name to listen for.
187
+ * @param listener — called at most once with the dispatch arguments.
188
+ * @param options — listener options; a boolean is shorthand for `prepend`.
189
+ * @returns a disposer removing the listener; `true` if it was still registered.
190
+ */
191
+ once(name, listener, options) {
192
+ const dispose = this.on(name, function (...args) {
193
+ dispose();
194
+ return listener.apply(this, args);
195
+ }, options);
196
+ return dispose;
197
+ }
198
+ }
199
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,352 @@
1
+ import { defineProperty } from '@xrkseek/cosmokit'
2
+ import type { Promisify } from '@xrkseek/cosmokit'
3
+ import { Context } from './context.ts'
4
+ import { Fiber, FiberState } from './fiber.ts'
5
+ import { DisposableList, symbols } from './utils.ts'
6
+
7
+ /**
8
+ * Return whether an event result should stop a bail-style dispatch.
9
+ *
10
+ * @param value — a listener's return value.
11
+ * @returns `true` unless `value` is `null`, `false`, or `undefined`.
12
+ */
13
+ export function isBailed(value: any) {
14
+ return value !== null && value !== false && value !== undefined
15
+ }
16
+
17
+ /** Extract the parameter tuple from a function type. */
18
+ export type Parameters<F> = F extends (...args: infer P) => any ? P : never
19
+ /** Extract the return type from a function type. */
20
+ export type ReturnType<F> = F extends (...args: any) => infer R ? R : never
21
+ /** Extract the explicit `this` type from a function type. */
22
+ export type ThisType<F> = F extends (this: infer T, ...args: any) => any ? T : never
23
+
24
+ /**
25
+ * Event dispatch strategy used by the event service.
26
+ *
27
+ * `emit` runs synchronous listeners without awaiting them, `parallel` awaits
28
+ * all listeners together, `serial` awaits them in order until one bails,
29
+ * `bail` stops on the first synchronous bail value, and `waterfall` composes
30
+ * listeners around a final `next` callback.
31
+ */
32
+ export type DispatchMode = 'emit' | 'parallel' | 'serial' | 'bail' | 'waterfall'
33
+
34
+ declare module './context.ts' {
35
+ export interface Context {
36
+ /* eslint-disable max-len */
37
+ /**
38
+ * Dispatch an event, running all listeners concurrently.
39
+ *
40
+ * @param name — the event name.
41
+ * @param args — arguments passed to every listener.
42
+ * @returns a promise resolving once every listener has settled.
43
+ */
44
+ parallel<K extends keyof Events>(name: K, ...args: Parameters<Events[K]>): Promise<void>
45
+ /** Same as above, with an explicit `this` for listeners (also used for filtering). */
46
+ parallel<K extends keyof Events>(thisArg: NoInfer<ThisType<Events[K]>>, name: K, ...args: Parameters<Events[K]>): Promise<void>
47
+ /**
48
+ * Dispatch an event synchronously, ignoring listener return values.
49
+ *
50
+ * @param name — the event name.
51
+ * @param args — arguments passed to every listener.
52
+ */
53
+ emit<K extends keyof Events>(name: K, ...args: Parameters<Events[K]>): void
54
+ /** Same as above, with an explicit `this` for listeners (also used for filtering). */
55
+ emit<K extends keyof Events>(thisArg: NoInfer<ThisType<Events[K]>>, name: K, ...args: Parameters<Events[K]>): void
56
+ /**
57
+ * Dispatch an event, awaiting listeners in order until one bails.
58
+ *
59
+ * @param name — the event name.
60
+ * @param args — arguments passed to each listener.
61
+ * @returns the first bail value (non-null, non-false, non-undefined), if any.
62
+ */
63
+ serial<K extends keyof Events>(name: K, ...args: Parameters<Events[K]>): Promisify<ReturnType<Events[K]>>
64
+ /** Same as above, with an explicit `this` for listeners (also used for filtering). */
65
+ serial<K extends keyof Events>(thisArg: NoInfer<ThisType<Events[K]>>, name: K, ...args: Parameters<Events[K]>): Promisify<ReturnType<Events[K]>>
66
+ /**
67
+ * Dispatch an event, calling listeners in order until one bails.
68
+ *
69
+ * @param name — the event name.
70
+ * @param args — arguments passed to each listener.
71
+ * @returns the first bail value (non-null, non-false, non-undefined), if any.
72
+ */
73
+ bail<K extends keyof Events>(name: K, ...args: Parameters<Events[K]>): ReturnType<Events[K]>
74
+ /** Same as above, with an explicit `this` for listeners (also used for filtering). */
75
+ bail<K extends keyof Events>(thisArg: NoInfer<ThisType<Events[K]>>, name: K, ...args: Parameters<Events[K]>): ReturnType<Events[K]>
76
+ /**
77
+ * Dispatch an event whose last argument is a `next` continuation.
78
+ *
79
+ * Each listener wraps the rest of the chain: calling `next()` invokes the
80
+ * next listener (finally the built-in behavior); not calling it vetoes.
81
+ *
82
+ * @param name — the event name.
83
+ * @param args — listener arguments; the final one is the innermost `next`.
84
+ * @returns the outermost listener's return value.
85
+ */
86
+ waterfall<K extends keyof Events>(name: K, ...args: Parameters<Events[K]>): ReturnType<Events[K]>
87
+ /** Same as above, with an explicit `this` for listeners (also used for filtering). */
88
+ waterfall<K extends keyof Events>(thisArg: NoInfer<ThisType<Events[K]>>, name: K, ...args: Parameters<Events[K]>): ReturnType<Events[K]>
89
+ /**
90
+ * Register an event listener owned by the current fiber.
91
+ *
92
+ * @param name — the event name to listen for.
93
+ * @param listener — called with the dispatch arguments.
94
+ * @param options — listener options; a boolean is shorthand for `prepend`.
95
+ * @returns a disposer removing the listener; `true` if it was still registered.
96
+ */
97
+ on<K extends keyof Events>(name: K, listener: Events[K], options?: boolean | EventOptions): () => boolean
98
+ /**
99
+ * Same as `on()`, but the listener disposes itself after its first call.
100
+ *
101
+ * @param name — the event name to listen for.
102
+ * @param listener — called at most once with the dispatch arguments.
103
+ * @param options — listener options; a boolean is shorthand for `prepend`.
104
+ * @returns a disposer removing the listener; `true` if it was still registered.
105
+ */
106
+ once<K extends keyof Events>(name: K, listener: Events[K], options?: boolean | EventOptions): () => boolean
107
+ /* eslint-enable max-len */
108
+ }
109
+ }
110
+
111
+ /** Options accepted by `ctx.on()` and `ctx.once()`. */
112
+ export interface EventOptions {
113
+ /** Add the listener before existing listeners for the same event. */
114
+ prepend?: boolean
115
+ /** Receive the event regardless of context filter checks. */
116
+ global?: boolean
117
+ }
118
+
119
+ /** Registered listener record stored by the event service. */
120
+ export interface Hook extends EventOptions {
121
+ ctx: Context
122
+ callback: (...args: any[]) => any
123
+ }
124
+
125
+ /**
126
+ * Event bus installed as `ctx.events` and mixed into every context.
127
+ *
128
+ * The service supports concurrent, synchronous, serial, bail, and waterfall
129
+ * dispatch and automatically disposes listeners with their owning fiber.
130
+ */
131
+ export class EventsService {
132
+ _hooks: Record<keyof any, Hook[]> = {}
133
+
134
+ constructor(private ctx: Context) {
135
+ defineProperty(this, symbols.tracker, {
136
+ property: 'ctx',
137
+ noShadow: true,
138
+ })
139
+
140
+ this.on('internal/listener', function (this: Context, name, listener, options: EventOptions) {
141
+ if (name === 'internal/update' && !options.global) {
142
+ const hooks = this.fiber._hooks['internal/update'] ??= new DisposableList()
143
+ const method = options.prepend ? 'unshift' : 'push'
144
+ return hooks[method](listener)
145
+ }
146
+ })
147
+
148
+ this.on('internal/update', function (config, noSave, next) {
149
+ const cbs = [...this._hooks['internal/update'] || []]
150
+ const _next = () => {
151
+ const cb = cbs.shift() ?? next
152
+ return cb.call(this, config, noSave, _next)
153
+ }
154
+ return _next()
155
+ }, { global: true, prepend: true })
156
+ }
157
+
158
+ /**
159
+ * Resolve listeners for one dispatch and apply context filtering.
160
+ *
161
+ * @param type — the dispatch mode, reported on `internal/dispatch`.
162
+ * @param args — the raw dispatch arguments; consumed up to the event name.
163
+ * @returns the matching listener callbacks, bound to the dispatch `this`.
164
+ */
165
+ dispatch(type: string, args: any[]) {
166
+ const thisArg = typeof args[0] === 'object' || typeof args[0] === 'function' ? args.shift() : null
167
+ const name: string = args.shift()
168
+ if (!name.startsWith('internal/')) {
169
+ this.emit('internal/dispatch', type, name, args, thisArg)
170
+ }
171
+ const filter = thisArg?.[Context.filter]
172
+ return (this._hooks[name] || [])
173
+ .filter(hook => hook.global || !filter || filter.call(thisArg, hook.ctx))
174
+ .map(hook => hook.callback.bind(thisArg))
175
+ }
176
+
177
+ /**
178
+ * Run listeners concurrently and wait for all of them.
179
+ *
180
+ * @param args — optional `this`, the event name, then listener arguments.
181
+ * @returns a promise resolving once every listener has settled.
182
+ */
183
+ async parallel(...args: any[]) {
184
+ const results = await Promise.allSettled(this.dispatch('emit', args).map(async cb => cb(...args)))
185
+ const errors = results.filter((result): result is PromiseRejectedResult => result.status === 'rejected')
186
+ if (errors.length) throw new AggregateError(errors.map(error => error.reason))
187
+ }
188
+
189
+ /**
190
+ * Run listeners synchronously without waiting for returned promises.
191
+ *
192
+ * @param args — optional `this`, the event name, then listener arguments.
193
+ */
194
+ emit(...args: any[]) {
195
+ this.dispatch('emit', args).map(cb => cb(...args))
196
+ }
197
+
198
+ /**
199
+ * Run listeners in order, awaiting each, until one returns a bail value.
200
+ *
201
+ * @param args — optional `this`, the event name, then listener arguments.
202
+ * @returns the first bail value (see {@link isBailed}), if any.
203
+ */
204
+ async serial(...args: any[]) {
205
+ for (const cb of this.dispatch('serial', args)) {
206
+ const result = await cb(...args)
207
+ if (isBailed(result)) return result
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Run listeners synchronously until one returns a bail value.
213
+ *
214
+ * @param args — optional `this`, the event name, then listener arguments.
215
+ * @returns the first bail value (see {@link isBailed}), if any.
216
+ */
217
+ bail(...args: any[]) {
218
+ for (const cb of this.dispatch('bail', args)) {
219
+ const result = cb(...args)
220
+ if (isBailed(result)) return result
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Compose listeners around the final `next` callback.
226
+ *
227
+ * The last dispatch argument is treated as the innermost `next`. Listeners
228
+ * run outermost-first; a listener that does not call `next()` vetoes the
229
+ * rest of the chain, including the built-in behavior.
230
+ *
231
+ * @param args — optional `this`, the event name, listener arguments, then `next`.
232
+ * @returns the outermost listener's return value.
233
+ */
234
+ waterfall(...args: any[]) {
235
+ const cbs = this.dispatch('waterfall', args)
236
+ const inner = args.pop()
237
+ const next = () => {
238
+ const cb = cbs.shift() ?? inner
239
+ return cb(...args)
240
+ }
241
+ args.push(next)
242
+ return next()
243
+ }
244
+
245
+ /**
246
+ * Store a listener record as an effect on the current fiber.
247
+ *
248
+ * @param label — effect label shown in fiber diagnostics.
249
+ * @param hooks — the listener list for one event.
250
+ * @param callback — the listener to store.
251
+ * @param options — placement and filtering options.
252
+ * @returns a disposer that unregisters the listener.
253
+ */
254
+ register(label: string, hooks: Hook[], callback: any, options: EventOptions): () => void {
255
+ const method = options.prepend ? 'unshift' : 'push'
256
+ return this.ctx.fiber.effect(() => {
257
+ hooks[method]({ ctx: this.ctx, callback, ...options })
258
+ return () => this.unregister(hooks, callback)
259
+ }, label)
260
+ }
261
+
262
+ /**
263
+ * Remove a stored listener record.
264
+ *
265
+ * @param hooks — the listener list for one event.
266
+ * @param callback — the listener to remove.
267
+ * @returns `true` if the listener was found and removed.
268
+ */
269
+ unregister(hooks: Hook[], callback: any) {
270
+ const index = hooks.findIndex(hook => hook.callback === callback)
271
+ if (index >= 0) {
272
+ hooks.splice(index, 1)
273
+ return true
274
+ }
275
+ }
276
+
277
+ /**
278
+ * Register an event listener owned by the current fiber.
279
+ *
280
+ * The listener is removed automatically when the fiber unloads. Throws
281
+ * `CordisError('INACTIVE_EFFECT')` if the fiber is already disposed.
282
+ *
283
+ * @param name — the event name to listen for.
284
+ * @param listener — called with the dispatch arguments.
285
+ * @param options — listener options; a boolean is shorthand for `prepend`.
286
+ * @returns a disposer removing the listener; `true` if it was still registered.
287
+ */
288
+ on(name: string | symbol, listener: (...args: any) => any, options?: boolean | EventOptions) {
289
+ if (typeof options !== 'object') {
290
+ options = { prepend: options }
291
+ }
292
+
293
+ // handle special events
294
+ this.ctx.fiber.assertActive()
295
+ listener = this.ctx.reflect.bind(listener)
296
+ const result = this.bail(this.ctx, 'internal/listener', name, listener, options)
297
+ if (result) return result
298
+
299
+ const hooks = this._hooks[name] ||= []
300
+ const label = `ctx.on(${typeof name === 'string' ? JSON.stringify(name) : name.toString()})`
301
+ return this.register(label, hooks, listener, options)
302
+ }
303
+
304
+ /**
305
+ * Register an event listener that disposes itself after the first call.
306
+ *
307
+ * @param name — the event name to listen for.
308
+ * @param listener — called at most once with the dispatch arguments.
309
+ * @param options — listener options; a boolean is shorthand for `prepend`.
310
+ * @returns a disposer removing the listener; `true` if it was still registered.
311
+ */
312
+ once(name: string, listener: (...args: any) => any, options?: boolean | EventOptions) {
313
+ const dispose = this.on(name, function (...args: any[]) {
314
+ dispose()
315
+ return listener.apply(this, args)
316
+ }, options)
317
+ return dispose
318
+ }
319
+ }
320
+
321
+ /**
322
+ * Built-in framework events used by core services and extension points.
323
+ *
324
+ * Plugin and status events track fiber lifecycle, service events observe
325
+ * dependency registration, update/get/set/listener events allow core services
326
+ * to intercept runtime operations, and `internal/dispatch` exposes event-bus
327
+ * diagnostics before public events are delivered.
328
+ */
329
+ export interface Events {
330
+ /** A plugin fiber was created or its uid was cleared on disposal. */
331
+ 'internal/plugin'(fiber: Fiber): void
332
+ /** A fiber changed lifecycle state; receives the fiber and its previous state. */
333
+ 'internal/status'(fiber: Fiber, oldValue: FiberState): void
334
+ /**
335
+ * Resolve raw plugin config after the fiber's injections become active.
336
+ * @param config - the raw config for this activation.
337
+ * @mode waterfall
338
+ */
339
+ 'internal/config'(this: Fiber, config: any, next: () => any): any
340
+ /** Interception hook for a service binding (no core producer). */
341
+ 'internal/service'(this: Context, name: string, value: any): void
342
+ /** Waterfall: a fiber config update is being applied; skip `next()` to veto. */
343
+ 'internal/update'(this: Fiber, config: any, noSave: boolean, next: () => void | Promise<void>): void | Promise<void>
344
+ /** Waterfall: a service is being read through the context proxy. */
345
+ 'internal/get'(ctx: Context, name: string, error: Error, next: () => any): any
346
+ /** Waterfall: a service is being written through the context proxy. */
347
+ 'internal/set'(ctx: Context, name: string, value: any, error: Error, next: () => boolean): boolean
348
+ /** Bail: a listener is being registered; a non-null result replaces registration. */
349
+ 'internal/listener'(this: Context, name: string, listener: any, prepend: boolean): void
350
+ /** An event is being dispatched to listeners (fired for non-internal events only). */
351
+ 'internal/dispatch'(mode: DispatchMode, name: string, args: any[], thisArg: any): void
352
+ }