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.
- package/dist/Context.js +3 -3
- package/dist/Context.js.map +1 -1
- package/dist/Crypto.d.ts +33 -5
- package/dist/Crypto.d.ts.map +1 -1
- package/dist/Crypto.js +8 -2
- package/dist/Crypto.js.map +1 -1
- package/dist/DateTime.d.ts +9 -6
- package/dist/DateTime.d.ts.map +1 -1
- package/dist/DateTime.js +9 -6
- package/dist/DateTime.js.map +1 -1
- package/dist/Duration.d.ts +6 -6
- package/dist/Duration.d.ts.map +1 -1
- package/dist/Duration.js +27 -8
- package/dist/Duration.js.map +1 -1
- package/dist/FileSystem.d.ts +44 -2
- package/dist/FileSystem.d.ts.map +1 -1
- package/dist/FileSystem.js.map +1 -1
- package/dist/Schema.d.ts +473 -1
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +355 -4
- package/dist/Schema.js.map +1 -1
- package/dist/Stdio.d.ts +7 -1
- package/dist/Stdio.d.ts.map +1 -1
- package/dist/Stdio.js +1 -0
- package/dist/Stdio.js.map +1 -1
- package/dist/Stream.d.ts +11 -11
- package/dist/Stream.js +5 -5
- package/dist/ai/McpServer.d.ts +6 -0
- package/dist/ai/McpServer.d.ts.map +1 -1
- package/dist/ai/McpServer.js +65 -23
- package/dist/ai/McpServer.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2026_07_28.js +5 -0
- package/dist/ai/internal/mcpProtocol/v2026_07_28.js.map +1 -1
- package/dist/ai/internal/mcpProtocol.js.map +1 -1
- package/dist/ai/internal/mcpRuntime.js +1 -0
- package/dist/ai/internal/mcpRuntime.js.map +1 -1
- package/dist/cli/CliOutput.d.ts +27 -0
- package/dist/cli/CliOutput.d.ts.map +1 -1
- package/dist/cli/CliOutput.js +33 -10
- package/dist/cli/CliOutput.js.map +1 -1
- package/dist/cli/Command.d.ts.map +1 -1
- package/dist/cli/Command.js +6 -3
- package/dist/cli/Command.js.map +1 -1
- package/dist/cli/Completions.d.ts +3 -3
- package/dist/cli/Completions.d.ts.map +1 -1
- package/dist/cli/Completions.js +8 -5
- package/dist/cli/Completions.js.map +1 -1
- package/dist/cli/GlobalFlag.d.ts +5 -4
- package/dist/cli/GlobalFlag.d.ts.map +1 -1
- package/dist/cli/GlobalFlag.js +3 -3
- package/dist/cli/GlobalFlag.js.map +1 -1
- package/dist/cli/Prompt.d.ts +17 -1
- package/dist/cli/Prompt.d.ts.map +1 -1
- package/dist/cli/Prompt.js +119 -114
- package/dist/cli/Prompt.js.map +1 -1
- package/dist/cli/internal/ansi.d.ts +0 -1
- package/dist/cli/internal/ansi.d.ts.map +1 -1
- package/dist/cli/internal/ansi.js +20 -3
- package/dist/cli/internal/ansi.js.map +1 -1
- package/dist/cli/internal/completions/powershell.d.ts +2 -0
- package/dist/cli/internal/completions/powershell.d.ts.map +1 -0
- package/dist/cli/internal/completions/powershell.js +273 -0
- package/dist/cli/internal/completions/powershell.js.map +1 -0
- package/dist/cli/internal/completions/zsh.js +3 -2
- package/dist/cli/internal/completions/zsh.js.map +1 -1
- package/dist/cli/internal/wizard.d.ts +3 -3
- package/dist/cli/internal/wizard.d.ts.map +1 -1
- package/dist/cli/internal/wizard.js +21 -18
- package/dist/cli/internal/wizard.js.map +1 -1
- package/dist/cluster/ClusterSchema.d.ts +28 -0
- package/dist/cluster/ClusterSchema.d.ts.map +1 -1
- package/dist/cluster/ClusterSchema.js +30 -0
- package/dist/cluster/ClusterSchema.js.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.js +10 -18
- package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
- package/dist/cluster/MessageStorage.d.ts +18 -3
- package/dist/cluster/MessageStorage.d.ts.map +1 -1
- package/dist/cluster/MessageStorage.js +31 -11
- package/dist/cluster/MessageStorage.js.map +1 -1
- package/dist/cluster/Runners.d.ts.map +1 -1
- package/dist/cluster/Runners.js +8 -2
- package/dist/cluster/Runners.js.map +1 -1
- package/dist/cluster/Sharding.d.ts.map +1 -1
- package/dist/cluster/Sharding.js +181 -62
- package/dist/cluster/Sharding.js.map +1 -1
- package/dist/cluster/SqlMessageStorage.d.ts +59 -19
- package/dist/cluster/SqlMessageStorage.d.ts.map +1 -1
- package/dist/cluster/SqlMessageStorage.js +84 -55
- package/dist/cluster/SqlMessageStorage.js.map +1 -1
- package/dist/cluster/SqlRunnerStorage.d.ts +68 -19
- package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
- package/dist/cluster/SqlRunnerStorage.js +191 -113
- package/dist/cluster/SqlRunnerStorage.js.map +1 -1
- package/dist/cluster/internal/entityManager.js +104 -37
- package/dist/cluster/internal/entityManager.js.map +1 -1
- package/dist/http/FindMyWay/internal/router.js +3 -6
- package/dist/http/FindMyWay/internal/router.js.map +1 -1
- package/dist/http/HttpClient.d.ts +6 -0
- package/dist/http/HttpClient.d.ts.map +1 -1
- package/dist/http/HttpClient.js +39 -2
- package/dist/http/HttpClient.js.map +1 -1
- package/dist/http/HttpTraceContext.d.ts.map +1 -1
- package/dist/http/HttpTraceContext.js +4 -2
- package/dist/http/HttpTraceContext.js.map +1 -1
- package/dist/internal/effect.js +12 -7
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/version.js +1 -1
- package/dist/net/AddressResolver.d.ts +145 -0
- package/dist/net/AddressResolver.d.ts.map +1 -0
- package/dist/net/AddressResolver.js +114 -0
- package/dist/net/AddressResolver.js.map +1 -0
- package/dist/net/Dns.d.ts +596 -0
- package/dist/net/Dns.d.ts.map +1 -0
- package/dist/net/Dns.js +549 -0
- package/dist/net/Dns.js.map +1 -0
- package/dist/net/Host.d.ts +320 -0
- package/dist/net/Host.d.ts.map +1 -0
- package/dist/net/Host.js +342 -0
- package/dist/net/Host.js.map +1 -0
- package/dist/net/IpInterface.d.ts +76 -3
- package/dist/net/IpInterface.d.ts.map +1 -1
- package/dist/net/IpInterface.js +53 -4
- package/dist/net/IpInterface.js.map +1 -1
- package/dist/net/IpNetwork.d.ts +82 -8
- package/dist/net/IpNetwork.d.ts.map +1 -1
- package/dist/net/IpNetwork.js +60 -4
- package/dist/net/IpNetwork.js.map +1 -1
- package/dist/net/NetAddress.d.ts +388 -35
- package/dist/net/NetAddress.d.ts.map +1 -1
- package/dist/net/NetAddress.js +350 -34
- package/dist/net/NetAddress.js.map +1 -1
- package/dist/net/index.d.ts +15 -0
- package/dist/net/index.d.ts.map +1 -1
- package/dist/net/index.js +15 -0
- package/dist/net/index.js.map +1 -1
- package/dist/observability/OtlpMetrics.d.ts.map +1 -1
- package/dist/observability/OtlpMetrics.js +15 -21
- package/dist/observability/OtlpMetrics.js.map +1 -1
- package/dist/observability/PrometheusMetrics.js +1 -0
- package/dist/observability/PrometheusMetrics.js.map +1 -1
- package/dist/persistence/PersistedQueue.d.ts +32 -3
- package/dist/persistence/PersistedQueue.d.ts.map +1 -1
- package/dist/persistence/PersistedQueue.js +75 -16
- package/dist/persistence/PersistedQueue.js.map +1 -1
- package/dist/rpc/RpcClient.d.ts +22 -6
- package/dist/rpc/RpcClient.d.ts.map +1 -1
- package/dist/rpc/RpcClient.js +12 -5
- package/dist/rpc/RpcClient.js.map +1 -1
- package/dist/rpc/RpcServer.d.ts +6 -0
- package/dist/rpc/RpcServer.d.ts.map +1 -1
- package/dist/rpc/RpcServer.js +42 -20
- package/dist/rpc/RpcServer.js.map +1 -1
- package/dist/socket/DatagramSocket.d.ts +456 -0
- package/dist/socket/DatagramSocket.d.ts.map +1 -0
- package/dist/socket/DatagramSocket.js +535 -0
- package/dist/socket/DatagramSocket.js.map +1 -0
- package/dist/socket/Socket.d.ts +14 -1
- package/dist/socket/Socket.d.ts.map +1 -1
- package/dist/socket/Socket.js +9 -1
- package/dist/socket/Socket.js.map +1 -1
- package/dist/socket/index.d.ts +5 -0
- package/dist/socket/index.d.ts.map +1 -1
- package/dist/socket/index.js +5 -0
- package/dist/socket/index.js.map +1 -1
- package/dist/sql/Migrator.d.ts.map +1 -1
- package/dist/sql/Migrator.js +7 -2
- package/dist/sql/Migrator.js.map +1 -1
- package/dist/sql/SqlClient.d.ts +7 -1
- package/dist/sql/SqlClient.d.ts.map +1 -1
- package/dist/sql/SqlClient.js +31 -6
- package/dist/sql/SqlClient.js.map +1 -1
- package/dist/testing/TestCrypto.d.ts +73 -0
- package/dist/testing/TestCrypto.d.ts.map +1 -0
- package/dist/testing/TestCrypto.js +87 -0
- package/dist/testing/TestCrypto.js.map +1 -0
- package/dist/testing/index.d.ts +5 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +5 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/workflow/DurableDeferred.d.ts +54 -0
- package/dist/workflow/DurableDeferred.d.ts.map +1 -1
- package/dist/workflow/DurableDeferred.js +78 -49
- package/dist/workflow/DurableDeferred.js.map +1 -1
- package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
- package/dist/workflow/WorkflowEngine.js +2 -1
- package/dist/workflow/WorkflowEngine.js.map +1 -1
- package/package.json +1 -1
- package/src/Context.ts +3 -3
- package/src/Crypto.ts +43 -9
- package/src/DateTime.ts +9 -6
- package/src/Duration.ts +36 -16
- package/src/FileSystem.ts +48 -2
- package/src/Schema.ts +669 -5
- package/src/Stdio.ts +9 -2
- package/src/Stream.ts +11 -11
- package/src/ai/McpServer.ts +63 -23
- package/src/ai/internal/mcpProtocol/v2026_07_28.ts +5 -0
- package/src/ai/internal/mcpProtocol.ts +3 -0
- package/src/ai/internal/mcpRuntime.ts +2 -0
- package/src/cli/CliOutput.ts +33 -16
- package/src/cli/Command.ts +4 -3
- package/src/cli/Completions.ts +9 -6
- package/src/cli/GlobalFlag.ts +19 -11
- package/src/cli/Prompt.ts +159 -149
- package/src/cli/internal/ansi.ts +26 -3
- package/src/cli/internal/completions/powershell.ts +322 -0
- package/src/cli/internal/completions/zsh.ts +4 -2
- package/src/cli/internal/wizard.ts +34 -26
- package/src/cluster/ClusterSchema.ts +32 -0
- package/src/cluster/ClusterWorkflowEngine.ts +13 -24
- package/src/cluster/MessageStorage.ts +45 -14
- package/src/cluster/Runners.ts +8 -2
- package/src/cluster/Sharding.ts +207 -49
- package/src/cluster/SqlMessageStorage.ts +118 -84
- package/src/cluster/SqlRunnerStorage.ts +224 -128
- package/src/cluster/internal/entityManager.ts +151 -55
- package/src/http/FindMyWay/internal/router.ts +4 -7
- package/src/http/HttpClient.ts +56 -2
- package/src/http/HttpTraceContext.ts +8 -2
- package/src/internal/effect.ts +15 -13
- package/src/internal/version.ts +1 -1
- package/src/net/AddressResolver.ts +222 -0
- package/src/net/Dns.ts +1035 -0
- package/src/net/Host.ts +472 -0
- package/src/net/IpInterface.ts +117 -7
- package/src/net/IpNetwork.ts +116 -17
- package/src/net/NetAddress.ts +611 -76
- package/src/net/index.ts +18 -0
- package/src/observability/OtlpMetrics.ts +12 -23
- package/src/observability/PrometheusMetrics.ts +1 -0
- package/src/persistence/PersistedQueue.ts +146 -53
- package/src/rpc/RpcClient.ts +41 -19
- package/src/rpc/RpcServer.ts +60 -25
- package/src/socket/DatagramSocket.ts +919 -0
- package/src/socket/Socket.ts +22 -2
- package/src/socket/index.ts +6 -0
- package/src/sql/Migrator.ts +21 -5
- package/src/sql/SqlClient.ts +39 -15
- package/src/testing/TestCrypto.ts +94 -0
- package/src/testing/index.ts +6 -0
- package/src/workflow/DurableDeferred.ts +123 -48
- 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
|
package/src/ai/McpServer.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
821
|
+
core,
|
|
812
822
|
subscribeServerNotifications: PubSub.subscribe(serverNotifications),
|
|
813
|
-
|
|
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
|
-
//
|
|
853
|
-
|
|
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
|
|
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
|
|
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
|
? {}
|
package/src/cli/CliOutput.ts
CHANGED
|
@@ -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
|
|
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
|
-
*
|
|
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
|
-
|
|
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 =
|
|
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) =>
|
|
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,
|
|
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
|
package/src/cli/Command.ts
CHANGED
|
@@ -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)
|
package/src/cli/Completions.ts
CHANGED
|
@@ -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
|
|
4
|
-
* low-level script generation surface used by the unstable CLI package
|
|
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
|
|
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
|
}
|
package/src/cli/GlobalFlag.ts
CHANGED
|
@@ -224,21 +224,29 @@ export const Wizard: Action<boolean> = Action({
|
|
|
224
224
|
*
|
|
225
225
|
* **Details**
|
|
226
226
|
*
|
|
227
|
-
* Accepted values are `bash`, `zsh`, `fish`,
|
|
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<
|
|
235
|
-
flag: Flag.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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<
|
|
328
|
+
Action<Option.Option<Completions_.Shell>>,
|
|
321
329
|
Setting<"log-level", Option.Option<LogLevelType>>
|
|
322
330
|
] = [Help, Version, Wizard, Completions, LogLevel]
|
|
323
331
|
|