effect 4.0.2 → 4.0.3

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 (243) hide show
  1. package/dist/Context.js +3 -3
  2. package/dist/Context.js.map +1 -1
  3. package/dist/Crypto.d.ts +33 -5
  4. package/dist/Crypto.d.ts.map +1 -1
  5. package/dist/Crypto.js +8 -2
  6. package/dist/Crypto.js.map +1 -1
  7. package/dist/DateTime.d.ts +9 -6
  8. package/dist/DateTime.d.ts.map +1 -1
  9. package/dist/DateTime.js +9 -6
  10. package/dist/DateTime.js.map +1 -1
  11. package/dist/Duration.d.ts +6 -6
  12. package/dist/Duration.d.ts.map +1 -1
  13. package/dist/Duration.js +27 -8
  14. package/dist/Duration.js.map +1 -1
  15. package/dist/FileSystem.d.ts +44 -2
  16. package/dist/FileSystem.d.ts.map +1 -1
  17. package/dist/FileSystem.js.map +1 -1
  18. package/dist/Schema.d.ts +473 -1
  19. package/dist/Schema.d.ts.map +1 -1
  20. package/dist/Schema.js +355 -4
  21. package/dist/Schema.js.map +1 -1
  22. package/dist/Stdio.d.ts +7 -1
  23. package/dist/Stdio.d.ts.map +1 -1
  24. package/dist/Stdio.js +1 -0
  25. package/dist/Stdio.js.map +1 -1
  26. package/dist/Stream.d.ts +11 -11
  27. package/dist/Stream.js +5 -5
  28. package/dist/ai/McpServer.d.ts +6 -0
  29. package/dist/ai/McpServer.d.ts.map +1 -1
  30. package/dist/ai/McpServer.js +65 -23
  31. package/dist/ai/McpServer.js.map +1 -1
  32. package/dist/ai/internal/mcpProtocol/v2026_07_28.js +5 -0
  33. package/dist/ai/internal/mcpProtocol/v2026_07_28.js.map +1 -1
  34. package/dist/ai/internal/mcpProtocol.js.map +1 -1
  35. package/dist/ai/internal/mcpRuntime.js +1 -0
  36. package/dist/ai/internal/mcpRuntime.js.map +1 -1
  37. package/dist/cli/CliOutput.d.ts +27 -0
  38. package/dist/cli/CliOutput.d.ts.map +1 -1
  39. package/dist/cli/CliOutput.js +33 -10
  40. package/dist/cli/CliOutput.js.map +1 -1
  41. package/dist/cli/Command.d.ts.map +1 -1
  42. package/dist/cli/Command.js +6 -3
  43. package/dist/cli/Command.js.map +1 -1
  44. package/dist/cli/Completions.d.ts +3 -3
  45. package/dist/cli/Completions.d.ts.map +1 -1
  46. package/dist/cli/Completions.js +8 -5
  47. package/dist/cli/Completions.js.map +1 -1
  48. package/dist/cli/GlobalFlag.d.ts +5 -4
  49. package/dist/cli/GlobalFlag.d.ts.map +1 -1
  50. package/dist/cli/GlobalFlag.js +3 -3
  51. package/dist/cli/GlobalFlag.js.map +1 -1
  52. package/dist/cli/Prompt.d.ts +17 -1
  53. package/dist/cli/Prompt.d.ts.map +1 -1
  54. package/dist/cli/Prompt.js +119 -114
  55. package/dist/cli/Prompt.js.map +1 -1
  56. package/dist/cli/internal/ansi.d.ts +0 -1
  57. package/dist/cli/internal/ansi.d.ts.map +1 -1
  58. package/dist/cli/internal/ansi.js +20 -3
  59. package/dist/cli/internal/ansi.js.map +1 -1
  60. package/dist/cli/internal/completions/powershell.d.ts +2 -0
  61. package/dist/cli/internal/completions/powershell.d.ts.map +1 -0
  62. package/dist/cli/internal/completions/powershell.js +273 -0
  63. package/dist/cli/internal/completions/powershell.js.map +1 -0
  64. package/dist/cli/internal/completions/zsh.js +3 -2
  65. package/dist/cli/internal/completions/zsh.js.map +1 -1
  66. package/dist/cli/internal/wizard.d.ts +3 -3
  67. package/dist/cli/internal/wizard.d.ts.map +1 -1
  68. package/dist/cli/internal/wizard.js +21 -18
  69. package/dist/cli/internal/wizard.js.map +1 -1
  70. package/dist/cluster/ClusterSchema.d.ts +28 -0
  71. package/dist/cluster/ClusterSchema.d.ts.map +1 -1
  72. package/dist/cluster/ClusterSchema.js +30 -0
  73. package/dist/cluster/ClusterSchema.js.map +1 -1
  74. package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  75. package/dist/cluster/ClusterWorkflowEngine.js +10 -18
  76. package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
  77. package/dist/cluster/MessageStorage.d.ts +18 -3
  78. package/dist/cluster/MessageStorage.d.ts.map +1 -1
  79. package/dist/cluster/MessageStorage.js +31 -11
  80. package/dist/cluster/MessageStorage.js.map +1 -1
  81. package/dist/cluster/Runners.d.ts.map +1 -1
  82. package/dist/cluster/Runners.js +8 -2
  83. package/dist/cluster/Runners.js.map +1 -1
  84. package/dist/cluster/Sharding.d.ts.map +1 -1
  85. package/dist/cluster/Sharding.js +181 -62
  86. package/dist/cluster/Sharding.js.map +1 -1
  87. package/dist/cluster/SqlMessageStorage.d.ts +59 -19
  88. package/dist/cluster/SqlMessageStorage.d.ts.map +1 -1
  89. package/dist/cluster/SqlMessageStorage.js +84 -55
  90. package/dist/cluster/SqlMessageStorage.js.map +1 -1
  91. package/dist/cluster/SqlRunnerStorage.d.ts +68 -19
  92. package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
  93. package/dist/cluster/SqlRunnerStorage.js +191 -113
  94. package/dist/cluster/SqlRunnerStorage.js.map +1 -1
  95. package/dist/cluster/internal/entityManager.js +104 -37
  96. package/dist/cluster/internal/entityManager.js.map +1 -1
  97. package/dist/http/FindMyWay/internal/router.js +3 -6
  98. package/dist/http/FindMyWay/internal/router.js.map +1 -1
  99. package/dist/http/HttpClient.d.ts +6 -0
  100. package/dist/http/HttpClient.d.ts.map +1 -1
  101. package/dist/http/HttpClient.js +39 -2
  102. package/dist/http/HttpClient.js.map +1 -1
  103. package/dist/http/HttpTraceContext.d.ts.map +1 -1
  104. package/dist/http/HttpTraceContext.js +4 -2
  105. package/dist/http/HttpTraceContext.js.map +1 -1
  106. package/dist/internal/effect.js +12 -7
  107. package/dist/internal/effect.js.map +1 -1
  108. package/dist/internal/version.js +1 -1
  109. package/dist/net/AddressResolver.d.ts +145 -0
  110. package/dist/net/AddressResolver.d.ts.map +1 -0
  111. package/dist/net/AddressResolver.js +114 -0
  112. package/dist/net/AddressResolver.js.map +1 -0
  113. package/dist/net/Dns.d.ts +596 -0
  114. package/dist/net/Dns.d.ts.map +1 -0
  115. package/dist/net/Dns.js +549 -0
  116. package/dist/net/Dns.js.map +1 -0
  117. package/dist/net/Host.d.ts +320 -0
  118. package/dist/net/Host.d.ts.map +1 -0
  119. package/dist/net/Host.js +342 -0
  120. package/dist/net/Host.js.map +1 -0
  121. package/dist/net/IpInterface.d.ts +76 -3
  122. package/dist/net/IpInterface.d.ts.map +1 -1
  123. package/dist/net/IpInterface.js +53 -4
  124. package/dist/net/IpInterface.js.map +1 -1
  125. package/dist/net/IpNetwork.d.ts +82 -8
  126. package/dist/net/IpNetwork.d.ts.map +1 -1
  127. package/dist/net/IpNetwork.js +60 -4
  128. package/dist/net/IpNetwork.js.map +1 -1
  129. package/dist/net/NetAddress.d.ts +388 -35
  130. package/dist/net/NetAddress.d.ts.map +1 -1
  131. package/dist/net/NetAddress.js +350 -34
  132. package/dist/net/NetAddress.js.map +1 -1
  133. package/dist/net/index.d.ts +15 -0
  134. package/dist/net/index.d.ts.map +1 -1
  135. package/dist/net/index.js +15 -0
  136. package/dist/net/index.js.map +1 -1
  137. package/dist/observability/OtlpMetrics.d.ts.map +1 -1
  138. package/dist/observability/OtlpMetrics.js +15 -21
  139. package/dist/observability/OtlpMetrics.js.map +1 -1
  140. package/dist/observability/PrometheusMetrics.js +1 -0
  141. package/dist/observability/PrometheusMetrics.js.map +1 -1
  142. package/dist/persistence/PersistedQueue.d.ts +32 -3
  143. package/dist/persistence/PersistedQueue.d.ts.map +1 -1
  144. package/dist/persistence/PersistedQueue.js +75 -16
  145. package/dist/persistence/PersistedQueue.js.map +1 -1
  146. package/dist/rpc/RpcClient.d.ts +22 -6
  147. package/dist/rpc/RpcClient.d.ts.map +1 -1
  148. package/dist/rpc/RpcClient.js +12 -5
  149. package/dist/rpc/RpcClient.js.map +1 -1
  150. package/dist/rpc/RpcServer.d.ts +6 -0
  151. package/dist/rpc/RpcServer.d.ts.map +1 -1
  152. package/dist/rpc/RpcServer.js +42 -20
  153. package/dist/rpc/RpcServer.js.map +1 -1
  154. package/dist/socket/DatagramSocket.d.ts +456 -0
  155. package/dist/socket/DatagramSocket.d.ts.map +1 -0
  156. package/dist/socket/DatagramSocket.js +535 -0
  157. package/dist/socket/DatagramSocket.js.map +1 -0
  158. package/dist/socket/Socket.d.ts +14 -1
  159. package/dist/socket/Socket.d.ts.map +1 -1
  160. package/dist/socket/Socket.js +9 -1
  161. package/dist/socket/Socket.js.map +1 -1
  162. package/dist/socket/index.d.ts +5 -0
  163. package/dist/socket/index.d.ts.map +1 -1
  164. package/dist/socket/index.js +5 -0
  165. package/dist/socket/index.js.map +1 -1
  166. package/dist/sql/Migrator.d.ts.map +1 -1
  167. package/dist/sql/Migrator.js +7 -2
  168. package/dist/sql/Migrator.js.map +1 -1
  169. package/dist/sql/SqlClient.d.ts +7 -1
  170. package/dist/sql/SqlClient.d.ts.map +1 -1
  171. package/dist/sql/SqlClient.js +31 -6
  172. package/dist/sql/SqlClient.js.map +1 -1
  173. package/dist/testing/TestCrypto.d.ts +73 -0
  174. package/dist/testing/TestCrypto.d.ts.map +1 -0
  175. package/dist/testing/TestCrypto.js +87 -0
  176. package/dist/testing/TestCrypto.js.map +1 -0
  177. package/dist/testing/index.d.ts +5 -0
  178. package/dist/testing/index.d.ts.map +1 -1
  179. package/dist/testing/index.js +5 -0
  180. package/dist/testing/index.js.map +1 -1
  181. package/dist/workflow/DurableDeferred.d.ts +54 -0
  182. package/dist/workflow/DurableDeferred.d.ts.map +1 -1
  183. package/dist/workflow/DurableDeferred.js +78 -49
  184. package/dist/workflow/DurableDeferred.js.map +1 -1
  185. package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
  186. package/dist/workflow/WorkflowEngine.js +2 -1
  187. package/dist/workflow/WorkflowEngine.js.map +1 -1
  188. package/package.json +1 -1
  189. package/src/Context.ts +3 -3
  190. package/src/Crypto.ts +43 -9
  191. package/src/DateTime.ts +9 -6
  192. package/src/Duration.ts +36 -16
  193. package/src/FileSystem.ts +48 -2
  194. package/src/Schema.ts +669 -5
  195. package/src/Stdio.ts +9 -2
  196. package/src/Stream.ts +11 -11
  197. package/src/ai/McpServer.ts +63 -23
  198. package/src/ai/internal/mcpProtocol/v2026_07_28.ts +5 -0
  199. package/src/ai/internal/mcpProtocol.ts +3 -0
  200. package/src/ai/internal/mcpRuntime.ts +2 -0
  201. package/src/cli/CliOutput.ts +33 -16
  202. package/src/cli/Command.ts +4 -3
  203. package/src/cli/Completions.ts +9 -6
  204. package/src/cli/GlobalFlag.ts +19 -11
  205. package/src/cli/Prompt.ts +159 -149
  206. package/src/cli/internal/ansi.ts +26 -3
  207. package/src/cli/internal/completions/powershell.ts +322 -0
  208. package/src/cli/internal/completions/zsh.ts +4 -2
  209. package/src/cli/internal/wizard.ts +34 -26
  210. package/src/cluster/ClusterSchema.ts +32 -0
  211. package/src/cluster/ClusterWorkflowEngine.ts +13 -24
  212. package/src/cluster/MessageStorage.ts +45 -14
  213. package/src/cluster/Runners.ts +8 -2
  214. package/src/cluster/Sharding.ts +207 -49
  215. package/src/cluster/SqlMessageStorage.ts +118 -84
  216. package/src/cluster/SqlRunnerStorage.ts +224 -128
  217. package/src/cluster/internal/entityManager.ts +151 -55
  218. package/src/http/FindMyWay/internal/router.ts +4 -7
  219. package/src/http/HttpClient.ts +56 -2
  220. package/src/http/HttpTraceContext.ts +8 -2
  221. package/src/internal/effect.ts +15 -13
  222. package/src/internal/version.ts +1 -1
  223. package/src/net/AddressResolver.ts +222 -0
  224. package/src/net/Dns.ts +1035 -0
  225. package/src/net/Host.ts +472 -0
  226. package/src/net/IpInterface.ts +117 -7
  227. package/src/net/IpNetwork.ts +116 -17
  228. package/src/net/NetAddress.ts +611 -76
  229. package/src/net/index.ts +18 -0
  230. package/src/observability/OtlpMetrics.ts +12 -23
  231. package/src/observability/PrometheusMetrics.ts +1 -0
  232. package/src/persistence/PersistedQueue.ts +146 -53
  233. package/src/rpc/RpcClient.ts +41 -19
  234. package/src/rpc/RpcServer.ts +60 -25
  235. package/src/socket/DatagramSocket.ts +919 -0
  236. package/src/socket/Socket.ts +22 -2
  237. package/src/socket/index.ts +6 -0
  238. package/src/sql/Migrator.ts +21 -5
  239. package/src/sql/SqlClient.ts +39 -15
  240. package/src/testing/TestCrypto.ts +94 -0
  241. package/src/testing/index.ts +6 -0
  242. package/src/workflow/DurableDeferred.ts +123 -48
  243. package/src/workflow/WorkflowEngine.ts +2 -1
package/src/Stdio.ts CHANGED
@@ -79,6 +79,12 @@ export interface Stdio {
79
79
  * @since 4.0.0
80
80
  */
81
81
  readonly stdoutIsTerminal: Effect.Effect<boolean>
82
+ /**
83
+ * Whether standard error is attached to a terminal.
84
+ *
85
+ * @since 4.0.0
86
+ */
87
+ readonly stderrIsTerminal: Effect.Effect<boolean>
82
88
  stdout(options?: {
83
89
  readonly endOnDone?: boolean | undefined
84
90
  }): Sink.Sink<void, string | Uint8Array, never, PlatformError>
@@ -127,12 +133,13 @@ export const Stdio: Context.Service<Stdio, Stdio> = Context.Service<Stdio>(TypeI
127
133
  */
128
134
  export const make = (
129
135
  options:
130
- & Omit<Stdio, TypeId | "stdinIsTerminal" | "stdoutIsTerminal">
131
- & Partial<Pick<Stdio, "stdinIsTerminal" | "stdoutIsTerminal">>
136
+ & Omit<Stdio, TypeId | "stdinIsTerminal" | "stdoutIsTerminal" | "stderrIsTerminal">
137
+ & Partial<Pick<Stdio, "stdinIsTerminal" | "stdoutIsTerminal" | "stderrIsTerminal">>
132
138
  ): Stdio => ({
133
139
  [TypeId]: TypeId,
134
140
  stdinIsTerminal: Effect.succeed(false),
135
141
  stdoutIsTerminal: Effect.succeed(false),
142
+ stderrIsTerminal: Effect.succeed(false),
136
143
  ...options
137
144
  })
138
145
 
package/src/Stream.ts CHANGED
@@ -20774,7 +20774,7 @@ export const mkUint8Array = <E, R>(self: Stream<Uint8Array, E, R>): Effect.Effec
20774
20774
  *
20775
20775
  * const stream = Stream.make(1, 2, 3, 4, 5)
20776
20776
  * const readableStream = Stream.toReadableStreamWith(stream, Context.empty())
20777
- * const values = await Array.fromAsync(readableStream)
20777
+ * const values = await globalThis.Array.fromAsync(readableStream)
20778
20778
  * values // => [ 1, 2, 3, 4, 5 ]
20779
20779
  * ```
20780
20780
  *
@@ -20802,7 +20802,7 @@ export const toReadableStreamWith: {
20802
20802
  *
20803
20803
  * const stream = Stream.make(1, 2, 3, 4, 5)
20804
20804
  * const readableStream = Stream.toReadableStreamWith(stream, Context.empty())
20805
- * const values = await Array.fromAsync(readableStream)
20805
+ * const values = await globalThis.Array.fromAsync(readableStream)
20806
20806
  * values // => [ 1, 2, 3, 4, 5 ]
20807
20807
  * ```
20808
20808
  *
@@ -20833,7 +20833,7 @@ export const toReadableStreamWith: {
20833
20833
  *
20834
20834
  * const stream = Stream.make(1, 2, 3, 4, 5)
20835
20835
  * const readableStream = Stream.toReadableStreamWith(stream, Context.empty())
20836
- * const values = await Array.fromAsync(readableStream)
20836
+ * const values = await globalThis.Array.fromAsync(readableStream)
20837
20837
  * values // => [ 1, 2, 3, 4, 5 ]
20838
20838
  * ```
20839
20839
  *
@@ -20906,7 +20906,7 @@ export const toReadableStreamWith: {
20906
20906
  * import { Stream } from "effect"
20907
20907
  *
20908
20908
  * const readableStream = Stream.toReadableStream(Stream.make(1, 2, 3))
20909
- * const values = await Array.fromAsync(readableStream)
20909
+ * const values = await globalThis.Array.fromAsync(readableStream)
20910
20910
  * values // => [ 1, 2, 3 ]
20911
20911
  * ```
20912
20912
  *
@@ -20928,7 +20928,7 @@ export const toReadableStream: {
20928
20928
  * import { Stream } from "effect"
20929
20929
  *
20930
20930
  * const readableStream = Stream.toReadableStream(Stream.make(1, 2, 3))
20931
- * const values = await Array.fromAsync(readableStream)
20931
+ * const values = await globalThis.Array.fromAsync(readableStream)
20932
20932
  * values // => [ 1, 2, 3 ]
20933
20933
  * ```
20934
20934
  *
@@ -20952,7 +20952,7 @@ export const toReadableStream: {
20952
20952
  * import { Stream } from "effect"
20953
20953
  *
20954
20954
  * const readableStream = Stream.toReadableStream(Stream.make(1, 2, 3))
20955
- * const values = await Array.fromAsync(readableStream)
20955
+ * const values = await globalThis.Array.fromAsync(readableStream)
20956
20956
  * values // => [ 1, 2, 3 ]
20957
20957
  * ```
20958
20958
  *
@@ -21132,7 +21132,7 @@ export const toReadableStreamEffect: {
21132
21132
  * const stream = Stream.make(1, 2, 3)
21133
21133
  * const iterable = Stream.toAsyncIterableWith(stream, Context.empty())
21134
21134
  *
21135
- * await Array.fromAsync(iterable) // => [1, 2, 3]
21135
+ * await globalThis.Array.fromAsync(iterable) // => [1, 2, 3]
21136
21136
  * ```
21137
21137
  *
21138
21138
  * @stability stable
@@ -21156,7 +21156,7 @@ export const toAsyncIterableWith: {
21156
21156
  * const stream = Stream.make(1, 2, 3)
21157
21157
  * const iterable = Stream.toAsyncIterableWith(stream, Context.empty())
21158
21158
  *
21159
- * await Array.fromAsync(iterable) // => [1, 2, 3]
21159
+ * await globalThis.Array.fromAsync(iterable) // => [1, 2, 3]
21160
21160
  * ```
21161
21161
  *
21162
21162
  * @stability stable
@@ -21180,7 +21180,7 @@ export const toAsyncIterableWith: {
21180
21180
  * const stream = Stream.make(1, 2, 3)
21181
21181
  * const iterable = Stream.toAsyncIterableWith(stream, Context.empty())
21182
21182
  *
21183
- * await Array.fromAsync(iterable) // => [1, 2, 3]
21183
+ * await globalThis.Array.fromAsync(iterable) // => [1, 2, 3]
21184
21184
  * ```
21185
21185
  *
21186
21186
  * @stability stable
@@ -21282,7 +21282,7 @@ export const toAsyncIterableWith: {
21282
21282
  *
21283
21283
  * const program = Effect.gen(function*() {
21284
21284
  * const iterable = yield* Stream.toAsyncIterableEffect(stream)
21285
- * return yield* Effect.promise(() => Array.fromAsync(iterable))
21285
+ * return yield* Effect.promise(() => globalThis.Array.fromAsync(iterable))
21286
21286
  * })
21287
21287
  *
21288
21288
  * await Effect.runPromise(program) // => [1, 2, 3]
@@ -21308,7 +21308,7 @@ export const toAsyncIterableEffect = <A, E, R>(self: Stream<A, E, R>): Effect.Ef
21308
21308
  *
21309
21309
  * const stream = Stream.make(1, 2, 3)
21310
21310
  *
21311
- * await Array.fromAsync(Stream.toAsyncIterable(stream)) // => [1, 2, 3]
21311
+ * await globalThis.Array.fromAsync(Stream.toAsyncIterable(stream)) // => [1, 2, 3]
21312
21312
  * ```
21313
21313
  *
21314
21314
  * @stability stable
@@ -94,6 +94,7 @@ type CompletionContext = typeof Complete.payloadSchema.Type["context"]
94
94
 
95
95
  interface QueuedServerNotification {
96
96
  readonly notification: McpCore.ServerNotification
97
+ listChangeRevision?: number | undefined
97
98
  readonly targetClientId?: number | undefined
98
99
  readonly delivered: Deferred.Deferred<void>
99
100
  readonly requestContext?: McpRequestContext["Service"] | undefined
@@ -103,7 +104,7 @@ interface QueuedServerNotification {
103
104
  const internalState = new WeakMap<object, {
104
105
  readonly core: McpCore.McpCore
105
106
  readonly notifications: Queue.Dequeue<QueuedServerNotification>
106
- readonly notificationDelivery: { consumers: number }
107
+ readonly notificationDelivery: { consumers: number; listChangeRevision: number }
107
108
  }>()
108
109
  type ServerExtensions = NonNullable<ServerCapabilities["extensions"]>
109
110
  type ServerNotificationRequest<
@@ -321,8 +322,8 @@ export class McpServer extends Context.Service<McpServer, {
321
322
  readonly annotations: Context.Context<never>
322
323
  }> = []
323
324
  const notificationsQueue = yield* Queue.make<QueuedServerNotification>()
324
- const notificationDelivery = { consumers: 0 }
325
- const pendingListChanges = new Set<string>()
325
+ const notificationDelivery = { consumers: 0, listChangeRevision: 0 }
326
+ const pendingListChanges = new Map<string, QueuedServerNotification>()
326
327
  const dispatcher = (yield* Scheduler).makeDispatcher()
327
328
  const notifications = yield* RpcClient.makeNoSerialization(BroadcastServerNotificationRpcs, {
328
329
  spanPrefix: "McpServer/Notifications",
@@ -337,7 +338,7 @@ export class McpServer extends Context.Service<McpServer, {
337
338
  if (notification === undefined) {
338
339
  return Effect.void
339
340
  }
340
- const queued = {
341
+ const queued: QueuedServerNotification = {
341
342
  notification,
342
343
  delivered,
343
344
  requestContext: Context.getOrUndefined(fiber.context, McpRequestContext),
@@ -345,14 +346,19 @@ export class McpServer extends Context.Service<McpServer, {
345
346
  }
346
347
  let enqueued = false
347
348
  if (message.tag.includes("list_changed")) {
348
- if (!pendingListChanges.has(message.tag)) {
349
+ const revision = ++notificationDelivery.listChangeRevision
350
+ const pending = pendingListChanges.get(message.tag)
351
+ if (pending !== undefined) {
352
+ // A coalesced change may be newer than an intervening subscription.
353
+ pending.listChangeRevision = revision
354
+ } else {
355
+ queued.listChangeRevision = revision
349
356
  enqueued = true
350
- const tag = message.tag
357
+ pendingListChanges.set(message.tag, queued)
351
358
  dispatcher.scheduleTask(() => {
352
- Queue.offerUnsafe(notificationsQueue, queued)
353
359
  pendingListChanges.delete(message.tag)
360
+ Queue.offerUnsafe(notificationsQueue, queued)
354
361
  }, 0)
355
- pendingListChanges.add(tag)
356
362
  }
357
363
  } else {
358
364
  enqueued = true
@@ -651,12 +657,14 @@ const MCP_SESSION_ID_HEADER = "mcp-session-id"
651
657
  const MCP_PROTOCOL_VERSION_HEADER = "mcp-protocol-version"
652
658
  const MCP_INVALID_BATCH_METHOD = "invalid/json-rpc-batch"
653
659
  const cancelledResponses = new WeakMap<object, string | number>()
660
+ const httpPostResponses = new WeakMap<HttpServerRequest.HttpServerRequest, { expected: number }>()
654
661
  const requestKey = (requestId: string | number): string => `${typeof requestId}:${requestId}`
655
662
 
656
663
  interface ActiveRequest {
657
664
  readonly requestId: RpcMessage.RequestId
658
665
  readonly prepared: McpRuntime.PreparedRequest
659
666
  readonly cancelled: boolean
667
+ readonly httpPost: { expected: number } | undefined
660
668
  }
661
669
 
662
670
  class McpClientKey extends Data.Class<{
@@ -716,6 +724,7 @@ const runWithRuntime = Effect.fnUntraced(function*(
716
724
  readonly websiteUrl?: string | undefined
717
725
  readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
718
726
  readonly extensions?: ServerExtensions | undefined
727
+ readonly allowSubscriptions?: boolean | undefined
719
728
  },
720
729
  runtime: McpRuntime.ServerRuntimeShape,
721
730
  transport: "custom" | "http" | "stdio"
@@ -807,10 +816,12 @@ const runWithRuntime = Effect.fnUntraced(function*(
807
816
  })
808
817
  })
809
818
  let writeFromClient!: (clientId: number, message: RpcMessage.FromClientEncoded) => Effect.Effect<void>
819
+ const { core, notificationDelivery, notifications } = internalState.get(server)!
810
820
  const handlers = yield* runtime.installHandlers({
811
- core: internalState.get(server)!.core,
821
+ core,
812
822
  subscribeServerNotifications: PubSub.subscribe(serverNotifications),
813
- ...(!protocol.supportsNotifications ? {} : {
823
+ getListChangeRevision: () => notificationDelivery.listChangeRevision,
824
+ ...(!protocol.supportsNotifications || options.allowSubscriptions === false ? {} : {
814
825
  sendNotification,
815
826
  markSubscriptionCancelled: (clientId: number, requestId: RpcMessage.RequestId) =>
816
827
  Effect.sync(() => {
@@ -848,10 +859,13 @@ const runWithRuntime = Effect.fnUntraced(function*(
848
859
  if (request._tag === "Interrupt") {
849
860
  // A cancelled reverse request may never receive a reply.
850
861
  removeReverseRequestClient(requestKey(request.requestId), key)
862
+ return sendNotification(key.profile.protocolVersion, key.clientId, {
863
+ tag: "notifications/cancelled",
864
+ payload: { requestId: request.requestId }
865
+ })
851
866
  }
852
- // Ack & co are not part of FromServerEncoded, but the JSON-RPC
853
- // serializer encodes them symmetrically for reverse control flow
854
- return protocol.send(key.clientId, request as any)
867
+ // Effect RPC control messages are not part of the MCP protocol.
868
+ return Effect.void
855
869
  },
856
870
  supportsAck: true,
857
871
  supportsTransferables: false,
@@ -950,12 +964,13 @@ const runWithRuntime = Effect.fnUntraced(function*(
950
964
  if (response._tag === "Exit") {
951
965
  const requests = activeRequests.get(clientId)
952
966
  const key = requestKey(response.requestId)
953
- const cancelled = requests?.get(key)?.cancelled
967
+ const active = requests?.get(key)
954
968
  if (requests !== undefined && requests.delete(key) && requests.size === 0) {
955
969
  activeRequests.delete(clientId)
956
970
  }
957
- if (cancelled === true) {
971
+ if (active?.cancelled === true) {
958
972
  if (transport === "custom") return Effect.void
973
+ if (active.httpPost !== undefined) active.httpPost.expected--
959
974
  cancelledResponses.set(response, response.requestId)
960
975
  return protocol.send(clientId, response)
961
976
  }
@@ -1003,6 +1018,11 @@ const runWithRuntime = Effect.fnUntraced(function*(
1003
1018
  }
1004
1019
  switch (request._tag) {
1005
1020
  case "Request": {
1021
+ if (httpRequest !== undefined && request.isNotification !== true) {
1022
+ const httpPost = httpPostResponses.get(httpRequest) ?? { expected: 0 }
1023
+ httpPost.expected++
1024
+ httpPostResponses.set(httpRequest, httpPost)
1025
+ }
1006
1026
  const headers = isHttp
1007
1027
  ? Context.getUnsafe(
1008
1028
  Fiber.getCurrent()!.context,
@@ -1138,7 +1158,8 @@ const runWithRuntime = Effect.fnUntraced(function*(
1138
1158
  requests.set(requestKey(request.id), {
1139
1159
  requestId: RpcMessage.RequestId(request.id),
1140
1160
  prepared,
1141
- cancelled: false
1161
+ cancelled: false,
1162
+ httpPost: httpRequest === undefined ? undefined : httpPostResponses.get(httpRequest)
1142
1163
  })
1143
1164
  activeRequests.set(clientId, requests)
1144
1165
  }
@@ -1231,7 +1252,6 @@ const runWithRuntime = Effect.fnUntraced(function*(
1231
1252
  })
1232
1253
  }
1233
1254
 
1234
- const { notificationDelivery, notifications } = internalState.get(server)!
1235
1255
  yield* Effect.acquireRelease(
1236
1256
  Effect.sync(() => {
1237
1257
  notificationDelivery.consumers++
@@ -1244,9 +1264,9 @@ const runWithRuntime = Effect.fnUntraced(function*(
1244
1264
  const notificationTails = new Map<number, Deferred.Deferred<void>>()
1245
1265
  yield* Queue.take(notifications).pipe(
1246
1266
  Effect.flatMap(Effect.fnUntraced(function*(queued) {
1247
- const { delivered, notification, targetClientId, requestContext, requestHeaders } = queued
1267
+ const { delivered, listChangeRevision, notification, targetClientId, requestContext, requestHeaders } = queued
1248
1268
  if (McpProtocolInternal.isSubscriptionServerNotification(notification)) {
1249
- yield* PubSub.publish(serverNotifications, { notification, targetClientId })
1269
+ yield* PubSub.publish(serverNotifications, { notification, targetClientId, listChangeRevision })
1250
1270
  }
1251
1271
  const clientIds = yield* patchedProtocol.clientIds
1252
1272
  for (const clientId of clientStates.keys()) {
@@ -1422,6 +1442,7 @@ const layerWithRuntime = (options: {
1422
1442
  readonly websiteUrl?: string | undefined
1423
1443
  readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
1424
1444
  readonly extensions?: ServerExtensions | undefined
1445
+ readonly allowSubscriptions?: boolean | undefined
1425
1446
  }, transport: "custom" | "http" | "stdio"): Layer.Layer<
1426
1447
  McpServer | McpServerClient,
1427
1448
  never,
@@ -1568,6 +1589,11 @@ const mcpStdioSerialization = (
1568
1589
  * holding a session id can end that session, so authenticate requests in the
1569
1590
  * surrounding router.
1570
1591
  *
1592
+ * Set `allowSubscriptions: false` to disable `v2026_07_28` subscriptions.
1593
+ * Discovery advertises `listChanged: false`, and `subscriptions/listen` returns
1594
+ * Method not found. Request-scoped progress and logs, legacy protocols, and
1595
+ * default subscription behavior are unchanged.
1596
+ *
1571
1597
  * `layerHttp` always implements the single-endpoint Streamable HTTP topology.
1572
1598
  * Using `v2024_11_05` here is a custom compatibility transport for that
1573
1599
  * revision's schema. It does not implement the historical two-endpoint
@@ -1592,6 +1618,7 @@ export const layerHttp = (options: {
1592
1618
  readonly extensions?: ServerExtensions | undefined
1593
1619
  readonly allowedOrigins?: ReadonlyArray<string> | undefined
1594
1620
  readonly allowSessionTermination?: boolean | undefined
1621
+ readonly allowSubscriptions?: boolean | undefined
1595
1622
  }): Layer.Layer<McpServer | McpServerClient, Cause.IllegalArgumentError, HttpRouter.HttpRouter> => {
1596
1623
  const runtime = McpRuntime.layer(options.protocols)
1597
1624
  return layerWithRuntime(options, "http").pipe(
@@ -1658,17 +1685,30 @@ const layerMcpProtocolHttp = (options: {
1658
1685
  if (admission._tag === "Rejected") {
1659
1686
  return admission.response
1660
1687
  }
1661
- const response = Effect.map(httpEffect, (response) => {
1688
+ const toResponse = (response: HttpServerResponse.HttpServerResponse) => {
1662
1689
  // Completed responses may already contain notifications followed by the result.
1663
1690
  const hasMultipleMessages = response.body._tag === "Uint8Array" &&
1664
1691
  response.body.body.subarray(0, -1).includes(10)
1665
1692
  return admission.isSubscription || response.body._tag === "Stream" || hasMultipleMessages
1666
1693
  ? toServerSentEvents(response, admission.isSubscription)
1667
1694
  : response
1695
+ }
1696
+ if (admission.acknowledge) {
1697
+ return yield* Effect.catchCause(
1698
+ Effect.map(httpEffect, toResponse),
1699
+ () => Effect.succeed(HttpServerResponse.empty({ status: 202 }))
1700
+ )
1701
+ }
1702
+ return yield* Effect.flatMap(httpEffect, (response) => {
1703
+ if (response.body._tag !== "Uint8Array" || response.body.body.length > 0) {
1704
+ return Effect.succeed(toResponse(response))
1705
+ }
1706
+ // Only fully cancelled request POSTs may return an empty SSE response.
1707
+ // https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server
1708
+ return httpPostResponses.get(request)?.expected === 0
1709
+ ? Effect.succeed(HttpServerResponse.stream(Stream.empty, { contentType: "text/event-stream" }))
1710
+ : Effect.die(new Error("MCP request ended without writing its response"))
1668
1711
  })
1669
- return yield* admission.acknowledge
1670
- ? Effect.catchCause(response, () => Effect.succeed(HttpServerResponse.empty({ status: 202 })))
1671
- : response
1672
1712
  })
1673
1713
  })
1674
1714
  return protocol
@@ -386,6 +386,8 @@ export const makeHandlers = (
386
386
  }
387
387
  const presence = yield* context.registrationPresence
388
388
  const eventsScope = yield* Scope.fork(yield* Effect.scope)
389
+ // Ignore changes emitted before this subscription, even if delivery was deferred.
390
+ const listChangeRevision = context.getListChangeRevision?.() ?? 0
389
391
  const events = yield* Scope.provide(context.subscribeServerNotifications, eventsScope)
390
392
  const honored = {
391
393
  ...(presence.tools && request.notifications.toolsListChanged === true
@@ -410,6 +412,9 @@ export const makeHandlers = (
410
412
  yield* Effect.gen(function*() {
411
413
  while (true) {
412
414
  const event = yield* PubSub.take(events)
415
+ if (event.listChangeRevision !== undefined && event.listChangeRevision <= listChangeRevision) {
416
+ continue
417
+ }
413
418
  if (event.targetClientId !== undefined && event.targetClientId !== client.id) {
414
419
  continue
415
420
  }
@@ -382,6 +382,8 @@ export interface HandlerInstallationContext {
382
382
  never,
383
383
  Scope.Scope
384
384
  >
385
+ /** Current list-change revision; subscriptions ignore changes emitted at or before it. */
386
+ readonly getListChangeRevision?: (() => number) | undefined
385
387
  readonly sendNotification?: (
386
388
  protocolVersion: string,
387
389
  clientId: number,
@@ -419,6 +421,7 @@ export interface HandlerInstallationContext {
419
421
  */
420
422
  export interface CanonicalServerNotification {
421
423
  readonly notification: SubscriptionServerNotification
424
+ readonly listChangeRevision?: number | undefined
422
425
  readonly targetClientId?: number | undefined
423
426
  }
424
427
 
@@ -123,6 +123,7 @@ export type HttpAdmission =
123
123
  */
124
124
  export interface HandlerInstallationOptions {
125
125
  readonly core: McpCore.McpCore
126
+ readonly getListChangeRevision?: () => number
126
127
  readonly subscribeServerNotifications: McpProtocol.HandlerInstallationContext["subscribeServerNotifications"]
127
128
  readonly sendNotification?: NonNullable<McpProtocol.HandlerInstallationContext["sendNotification"]>
128
129
  readonly markSubscriptionCancelled?: NonNullable<
@@ -512,6 +513,7 @@ export const make = Effect.fnUntraced(function*(
512
513
  const contextMap = new Map<string, unknown>()
513
514
  const installationContext: McpProtocol.HandlerInstallationContext = {
514
515
  subscribeServerNotifications: options.subscribeServerNotifications,
516
+ getListChangeRevision: options.getListChangeRevision,
515
517
  ...(options.sendNotification === undefined ? {} : { sendNotification: options.sendNotification }),
516
518
  ...(options.markSubscriptionCancelled === undefined
517
519
  ? {}
@@ -16,6 +16,7 @@ import * as Layer from "../Layer.ts"
16
16
  import * as Option from "../Option.ts"
17
17
  import type * as CliError from "./CliError.ts"
18
18
  import type { HelpDoc } from "./HelpDoc.ts"
19
+ import * as Ansi from "./internal/ansi.ts"
19
20
 
20
21
  /**
21
22
  * Defines the service interface for formatting CLI output including help, errors, and version info.
@@ -306,17 +307,7 @@ const escapeControlCharacters = (text: string): string =>
306
307
  * @since 4.0.0
307
308
  */
308
309
  export const defaultFormatter = (options?: { colors?: boolean }): Formatter => {
309
- const globalProcess = (globalThis as any).process
310
- const hasProcess = typeof globalProcess === "object" && globalProcess !== null
311
-
312
- const useColor = options?.colors !== undefined
313
- ? options.colors
314
- // Auto-detect based on environment
315
- : (hasProcess &&
316
- typeof globalProcess.stdout === "object" &&
317
- globalProcess.stdout !== null &&
318
- globalProcess.stdout.isTTY === true &&
319
- !globalProcess.env?.NO_COLOR)
310
+ const useColor = options?.colors ?? Ansi.detectColors()
320
311
 
321
312
  // Color palette using ANSI escape codes
322
313
  const colors = useColor
@@ -390,7 +381,7 @@ const stripAnsi = (text: string): string => {
390
381
  }
391
382
 
392
383
  /**
393
- * Gets the terminal display width of a string (excluding ANSI codes).
384
+ * Segments text into grapheme clusters.
394
385
  * @internal
395
386
  */
396
387
  const graphemeSegmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" })
@@ -424,7 +415,33 @@ const graphemeWidth = (grapheme: string): number => {
424
415
  return isFullWidthCodePoint(visible.codePointAt(0)!) ? 2 : 1
425
416
  }
426
417
 
427
- const visualLength = (text: string): number => {
418
+ /**
419
+ * Measures the number of terminal cells a string occupies.
420
+ *
421
+ * **Details**
422
+ *
423
+ * Uses the same measurement as built-in help and table rendering. ANSI styling
424
+ * is stripped before measuring graphemes: zero-width graphemes count as `0`,
425
+ * emoji presentation sequences and fullwidth characters as `2`, and other
426
+ * graphemes as `1`.
427
+ *
428
+ * **Example** (Measuring terminal-cell widths)
429
+ *
430
+ * ```ts import.meta.vitest
431
+ * import { CliOutput } from "effect/cli"
432
+ *
433
+ * CliOutput.displayWidth("file") // => 4
434
+ * CliOutput.displayWidth("ファイル") // => 8
435
+ * CliOutput.displayWidth("é") // => 1
436
+ * CliOutput.displayWidth("1️⃣") // => 2
437
+ * CliOutput.displayWidth("\u001B[1mbold\u001B[0m") // => 4
438
+ * ```
439
+ *
440
+ * @stability unstable
441
+ * @category measuring
442
+ * @since 4.0.3
443
+ */
444
+ export const displayWidth = (text: string): number => {
428
445
  let length = 0
429
446
  for (const { segment } of graphemeSegmenter.segment(stripAnsi(text))) {
430
447
  length += graphemeWidth(segment)
@@ -437,7 +454,7 @@ const visualLength = (text: string): number => {
437
454
  * @internal
438
455
  */
439
456
  const pad = (s: string, width: number) => {
440
- const actualLength = visualLength(s)
457
+ const actualLength = displayWidth(s)
441
458
  const padding = Math.max(0, width - actualLength)
442
459
  return s + " ".repeat(padding)
443
460
  }
@@ -456,9 +473,9 @@ interface Row {
456
473
  * @internal
457
474
  */
458
475
  const renderTable = (rows: ReadonlyArray<Row>, widthCap?: number) => {
459
- const maxColumn = Math.max(...rows.map((r) => visualLength(r.left))) + 4
476
+ const maxColumn = Math.max(...rows.map((r) => displayWidth(r.left))) + 4
460
477
  const col = widthCap === undefined ? maxColumn : Math.min(maxColumn, widthCap)
461
- return rows.map(({ left, right }) => ` ${pad(left, Math.max(col, visualLength(left) + 1))}${right}`).join("\n")
478
+ return rows.map(({ left, right }) => ` ${pad(left, Math.max(col, displayWidth(left) + 1))}${right}`).join("\n")
462
479
  }
463
480
 
464
481
  const formatSubcommandName = (name: string, alias: string | undefined): string => alias ? `${name}, ${alias}` : name
@@ -3104,14 +3104,15 @@ export const runWith = <const Name extends string, Input, E, R, ContextInput>(
3104
3104
  if (!hasEntry) continue
3105
3105
  const [, value] = yield* flag.flag.parse(emptyArgs)
3106
3106
  if (flag === GlobalFlag.Wizard) {
3107
+ const { colors } = yield* Prompt.Theme
3107
3108
  return yield* Effect.gen(function*() {
3108
- yield* Console.log(Wizard.renderIntroduction(command.name, config.version, command.description))
3109
+ yield* Console.log(Wizard.renderIntroduction(command.name, config.version, command.description, colors))
3109
3110
  const prefix = [
3110
3111
  command.name,
3111
3112
  ...args.filter((arg) => arg !== "--wizard" && !arg.startsWith("--wizard="))
3112
3113
  ]
3113
3114
  const wizardResult = yield* Wizard.run(command, { commandPath, prefix })
3114
- yield* Console.log(Wizard.renderCompletion(wizardResult.displayArgs))
3115
+ yield* Console.log(Wizard.renderCompletion(wizardResult.displayArgs, colors))
3115
3116
  const shouldRun = yield* Prompt.run(Prompt.Toggle({
3116
3117
  message: "Run this command?",
3117
3118
  initial: true,
@@ -3123,7 +3124,7 @@ export const runWith = <const Name extends string, Input, E, R, ContextInput>(
3123
3124
  yield* runWith(command, { ...config, renderErrors: false })(wizardResult.args.slice(1))
3124
3125
  }
3125
3126
  }).pipe(
3126
- Effect.catchTag("QuitError", () => Console.log(Wizard.renderQuit()))
3127
+ Effect.catchTag("QuitError", () => Console.log(Wizard.renderQuit(colors)))
3127
3128
  )
3128
3129
  }
3129
3130
  yield* flag.run(value, handlerCtx)
@@ -1,14 +1,15 @@
1
1
  /**
2
2
  * The `Completions` module turns a plain description of an Effect CLI command
3
- * tree into shell completion scripts for Bash, Zsh, and Fish. It is the
4
- * low-level script generation surface used by the unstable CLI package and by
5
- * the built-in completions global flag.
3
+ * tree into shell completion scripts for Bash, Zsh, Fish, and PowerShell. It
4
+ * is the low-level script generation surface used by the unstable CLI package
5
+ * and by the built-in completions global flag.
6
6
  *
7
7
  * @stability unstable
8
8
  * @since 4.0.0
9
9
  */
10
10
  import * as Bash from "./internal/completions/bash.ts"
11
11
  import * as Fish from "./internal/completions/fish.ts"
12
+ import * as PowerShell from "./internal/completions/powershell.ts"
12
13
  import * as Zsh from "./internal/completions/zsh.ts"
13
14
 
14
15
  /**
@@ -18,7 +19,7 @@ import * as Zsh from "./internal/completions/zsh.ts"
18
19
  * @category models
19
20
  * @since 4.0.0
20
21
  */
21
- export type Shell = "bash" | "zsh" | "fish"
22
+ export type Shell = "bash" | "zsh" | "fish" | "powershell"
22
23
 
23
24
  /**
24
25
  * Describes a command for completion script generation.
@@ -105,8 +106,8 @@ export type ArgumentType =
105
106
  *
106
107
  * **Details**
107
108
  *
108
- * Dispatches by `shell` to Bash, Zsh, or Fish generation and returns a static
109
- * script string for `executableName`.
109
+ * Dispatches by `shell` to Bash, Zsh, Fish, or PowerShell generation and
110
+ * returns a static script string for `executableName`.
110
111
  *
111
112
  * @see {@link Shell} for supported shell names
112
113
  * @see {@link CommandDescriptor} for the command shape used by completion generation
@@ -127,5 +128,7 @@ export const generate = (
127
128
  return Zsh.generate(executableName, descriptor)
128
129
  case "fish":
129
130
  return Fish.generate(executableName, descriptor)
131
+ case "powershell":
132
+ return PowerShell.generate(executableName, descriptor)
130
133
  }
131
134
  }
@@ -224,21 +224,29 @@ export const Wizard: Action<boolean> = Action({
224
224
  *
225
225
  * **Details**
226
226
  *
227
- * Accepted values are `bash`, `zsh`, `fish`, and `sh`; `sh` is normalized to
228
- * `bash`.
227
+ * Accepted values are `bash`, `zsh`, `fish`, `powershell`, `sh`, and `pwsh`;
228
+ * `sh` is normalized to `bash` and `pwsh` to `powershell`.
229
229
  *
230
230
  * @stability unstable
231
231
  * @category references
232
232
  * @since 4.0.0
233
233
  */
234
- export const Completions: Action<Option.Option<"bash" | "zsh" | "fish">> = Action({
235
- flag: Flag.Literals("completions", ["bash", "zsh", "fish", "sh"] as const)
236
- .pipe(
237
- Flag.optional,
238
- Flag.map((v) => Option.map(v, (s) => s === "sh" ? "bash" : s)),
239
- Flag.withMetavar("<bash|zsh|fish|sh>"),
240
- Flag.withDescription("Print shell completion script")
241
- ),
234
+ export const Completions: Action<Option.Option<Completions_.Shell>> = Action({
235
+ flag: Flag.ChoiceWithValue(
236
+ "completions",
237
+ [
238
+ ["bash", "bash"],
239
+ ["zsh", "zsh"],
240
+ ["fish", "fish"],
241
+ ["powershell", "powershell"],
242
+ ["sh", "bash"],
243
+ ["pwsh", "powershell"]
244
+ ] as const
245
+ ).pipe(
246
+ Flag.optional,
247
+ Flag.withMetavar("<bash|zsh|fish|powershell|sh|pwsh>"),
248
+ Flag.withDescription("Print shell completion script")
249
+ ),
242
250
  run: Effect.fnUntraced(function*(shell, { command }) {
243
251
  if (Option.isNone(shell)) return
244
252
  const descriptor = CommandDescriptor.fromCommand(command)
@@ -317,7 +325,7 @@ export const BuiltIns: readonly [
317
325
  Action<boolean>,
318
326
  Action<boolean>,
319
327
  Action<boolean>,
320
- Action<Option.Option<"bash" | "zsh" | "fish">>,
328
+ Action<Option.Option<Completions_.Shell>>,
321
329
  Setting<"log-level", Option.Option<LogLevelType>>
322
330
  ] = [Help, Version, Wizard, Completions, LogLevel]
323
331