effect 4.0.3 → 4.0.5

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 (449) hide show
  1. package/AGENTS.md +24 -0
  2. package/CLAUDE.md +24 -0
  3. package/ai-docs/package.json +2 -2
  4. package/ai-docs/src/52_graphql/10_basics.ts +117 -0
  5. package/ai-docs/src/52_graphql/20_testing.ts +45 -0
  6. package/ai-docs/src/52_graphql/30_batching.ts +118 -0
  7. package/ai-docs/src/52_graphql/40_aliased-batching.ts +124 -0
  8. package/ai-docs/src/52_graphql/50_errors-and-retries.ts +74 -0
  9. package/ai-docs/src/52_graphql/index.md +6 -0
  10. package/dist/Array.d.ts +90 -6
  11. package/dist/Array.d.ts.map +1 -1
  12. package/dist/Array.js +4 -2
  13. package/dist/Array.js.map +1 -1
  14. package/dist/Channel.d.ts +6 -1
  15. package/dist/Channel.d.ts.map +1 -1
  16. package/dist/Channel.js +17 -3
  17. package/dist/Channel.js.map +1 -1
  18. package/dist/ConfigProvider.d.ts.map +1 -1
  19. package/dist/ConfigProvider.js +33 -32
  20. package/dist/ConfigProvider.js.map +1 -1
  21. package/dist/Context.d.ts.map +1 -1
  22. package/dist/Context.js +9 -0
  23. package/dist/Context.js.map +1 -1
  24. package/dist/Duration.d.ts.map +1 -1
  25. package/dist/Duration.js +2 -5
  26. package/dist/Duration.js.map +1 -1
  27. package/dist/Effect.d.ts +61 -19
  28. package/dist/Effect.d.ts.map +1 -1
  29. package/dist/Effect.js +58 -39
  30. package/dist/Effect.js.map +1 -1
  31. package/dist/FileSystem.d.ts +23 -9
  32. package/dist/FileSystem.d.ts.map +1 -1
  33. package/dist/FileSystem.js.map +1 -1
  34. package/dist/Match.d.ts +20 -6
  35. package/dist/Match.d.ts.map +1 -1
  36. package/dist/Match.js +2 -2
  37. package/dist/Match.js.map +1 -1
  38. package/dist/Path.d.ts +37 -5
  39. package/dist/Path.d.ts.map +1 -1
  40. package/dist/Path.js +36 -5
  41. package/dist/Path.js.map +1 -1
  42. package/dist/RequestResolver.d.ts.map +1 -1
  43. package/dist/RequestResolver.js +4 -10
  44. package/dist/RequestResolver.js.map +1 -1
  45. package/dist/Scheduler.d.ts +9 -0
  46. package/dist/Scheduler.d.ts.map +1 -1
  47. package/dist/Scheduler.js +9 -0
  48. package/dist/Scheduler.js.map +1 -1
  49. package/dist/Schema.d.ts +15 -2
  50. package/dist/Schema.d.ts.map +1 -1
  51. package/dist/Schema.js +16 -2
  52. package/dist/Schema.js.map +1 -1
  53. package/dist/SchemaGetter.d.ts +4 -0
  54. package/dist/SchemaGetter.d.ts.map +1 -1
  55. package/dist/SchemaGetter.js +52 -33
  56. package/dist/SchemaGetter.js.map +1 -1
  57. package/dist/Sink.d.ts.map +1 -1
  58. package/dist/Sink.js +38 -17
  59. package/dist/Sink.js.map +1 -1
  60. package/dist/Stream.d.ts +11 -0
  61. package/dist/Stream.d.ts.map +1 -1
  62. package/dist/Stream.js +16 -1
  63. package/dist/Stream.js.map +1 -1
  64. package/dist/String.d.ts +12 -0
  65. package/dist/String.d.ts.map +1 -1
  66. package/dist/String.js +17 -4
  67. package/dist/String.js.map +1 -1
  68. package/dist/TxRef.d.ts.map +1 -1
  69. package/dist/TxRef.js +3 -2
  70. package/dist/TxRef.js.map +1 -1
  71. package/dist/Utils.js +8 -3
  72. package/dist/Utils.js.map +1 -1
  73. package/dist/ai/AiError.d.ts +10 -10
  74. package/dist/ai/AiError.d.ts.map +1 -1
  75. package/dist/ai/AiError.js +1 -1
  76. package/dist/ai/AiError.js.map +1 -1
  77. package/dist/ai/AnthropicStructuredOutput.js +0 -2
  78. package/dist/ai/AnthropicStructuredOutput.js.map +1 -1
  79. package/dist/ai/Chat.d.ts +2 -2
  80. package/dist/ai/Chat.d.ts.map +1 -1
  81. package/dist/ai/Decision.d.ts +70 -19
  82. package/dist/ai/Decision.d.ts.map +1 -1
  83. package/dist/ai/Decision.js +37 -3
  84. package/dist/ai/Decision.js.map +1 -1
  85. package/dist/ai/DecisionModel.js +1 -1
  86. package/dist/ai/DecisionModel.js.map +1 -1
  87. package/dist/ai/LanguageModel.d.ts +38 -7
  88. package/dist/ai/LanguageModel.d.ts.map +1 -1
  89. package/dist/ai/LanguageModel.js +70 -40
  90. package/dist/ai/LanguageModel.js.map +1 -1
  91. package/dist/ai/McpServer.d.ts +61 -52
  92. package/dist/ai/McpServer.d.ts.map +1 -1
  93. package/dist/ai/McpServer.js +134 -50
  94. package/dist/ai/McpServer.js.map +1 -1
  95. package/dist/ai/Prompt.d.ts.map +1 -1
  96. package/dist/ai/Prompt.js +28 -5
  97. package/dist/ai/Prompt.js.map +1 -1
  98. package/dist/ai/Response.d.ts +5 -4
  99. package/dist/ai/Response.d.ts.map +1 -1
  100. package/dist/ai/Response.js.map +1 -1
  101. package/dist/cli/Completions.d.ts +5 -0
  102. package/dist/cli/Completions.d.ts.map +1 -1
  103. package/dist/cli/Completions.js.map +1 -1
  104. package/dist/cli/Flag.d.ts +100 -0
  105. package/dist/cli/Flag.d.ts.map +1 -1
  106. package/dist/cli/Flag.js +33 -0
  107. package/dist/cli/Flag.js.map +1 -1
  108. package/dist/cli/Param.d.ts +87 -0
  109. package/dist/cli/Param.d.ts.map +1 -1
  110. package/dist/cli/Param.js +30 -0
  111. package/dist/cli/Param.js.map +1 -1
  112. package/dist/cli/internal/command.d.ts.map +1 -1
  113. package/dist/cli/internal/command.js +2 -1
  114. package/dist/cli/internal/command.js.map +1 -1
  115. package/dist/cli/internal/completions/bash.js +4 -3
  116. package/dist/cli/internal/completions/bash.js.map +1 -1
  117. package/dist/cli/internal/completions/descriptor.js +8 -1
  118. package/dist/cli/internal/completions/descriptor.js.map +1 -1
  119. package/dist/cli/internal/completions/fish.js +4 -4
  120. package/dist/cli/internal/completions/fish.js.map +1 -1
  121. package/dist/cli/internal/completions/powershell.js +3 -2
  122. package/dist/cli/internal/completions/powershell.js.map +1 -1
  123. package/dist/cli/internal/completions/zsh.js +7 -3
  124. package/dist/cli/internal/completions/zsh.js.map +1 -1
  125. package/dist/cli/internal/parser.js +11 -3
  126. package/dist/cli/internal/parser.js.map +1 -1
  127. package/dist/cli/internal/wizard.d.ts.map +1 -1
  128. package/dist/cli/internal/wizard.js +2 -1
  129. package/dist/cli/internal/wizard.js.map +1 -1
  130. package/dist/cluster/ClusterWorkflowEngine.d.ts +1 -0
  131. package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  132. package/dist/cluster/ClusterWorkflowEngine.js +113 -21
  133. package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
  134. package/dist/cluster/MessageStorage.d.ts.map +1 -1
  135. package/dist/cluster/MessageStorage.js +20 -12
  136. package/dist/cluster/MessageStorage.js.map +1 -1
  137. package/dist/cluster/Runners.d.ts.map +1 -1
  138. package/dist/cluster/Runners.js +54 -34
  139. package/dist/cluster/Runners.js.map +1 -1
  140. package/dist/cluster/Sharding.d.ts.map +1 -1
  141. package/dist/cluster/Sharding.js +6 -4
  142. package/dist/cluster/Sharding.js.map +1 -1
  143. package/dist/cluster/internal/entityManager.js +1 -1
  144. package/dist/cluster/internal/entityManager.js.map +1 -1
  145. package/dist/encoding/Sse.d.ts +6 -0
  146. package/dist/encoding/Sse.d.ts.map +1 -1
  147. package/dist/encoding/Sse.js +63 -71
  148. package/dist/encoding/Sse.js.map +1 -1
  149. package/dist/graphql/GraphQL.d.ts +349 -0
  150. package/dist/graphql/GraphQL.d.ts.map +1 -0
  151. package/dist/graphql/GraphQL.js +207 -0
  152. package/dist/graphql/GraphQL.js.map +1 -0
  153. package/dist/graphql/GraphQLClient.d.ts +562 -0
  154. package/dist/graphql/GraphQLClient.d.ts.map +1 -0
  155. package/dist/graphql/GraphQLClient.js +505 -0
  156. package/dist/graphql/GraphQLClient.js.map +1 -0
  157. package/dist/graphql/GraphQLClientError.d.ts +445 -0
  158. package/dist/graphql/GraphQLClientError.d.ts.map +1 -0
  159. package/dist/graphql/GraphQLClientError.js +479 -0
  160. package/dist/graphql/GraphQLClientError.js.map +1 -0
  161. package/dist/graphql/GraphQLGroup.d.ts +118 -0
  162. package/dist/graphql/GraphQLGroup.d.ts.map +1 -0
  163. package/dist/graphql/GraphQLGroup.js +109 -0
  164. package/dist/graphql/GraphQLGroup.js.map +1 -0
  165. package/dist/graphql/GraphQLMiddleware.d.ts +249 -0
  166. package/dist/graphql/GraphQLMiddleware.d.ts.map +1 -0
  167. package/dist/graphql/GraphQLMiddleware.js +130 -0
  168. package/dist/graphql/GraphQLMiddleware.js.map +1 -0
  169. package/dist/graphql/GraphQLProtocol.d.ts +969 -0
  170. package/dist/graphql/GraphQLProtocol.d.ts.map +1 -0
  171. package/dist/graphql/GraphQLProtocol.js +809 -0
  172. package/dist/graphql/GraphQLProtocol.js.map +1 -0
  173. package/dist/graphql/GraphQLResolver.d.ts +453 -0
  174. package/dist/graphql/GraphQLResolver.d.ts.map +1 -0
  175. package/dist/graphql/GraphQLResolver.js +582 -0
  176. package/dist/graphql/GraphQLResolver.js.map +1 -0
  177. package/dist/graphql/index.d.ts +40 -0
  178. package/dist/graphql/index.d.ts.map +1 -0
  179. package/dist/graphql/index.js +41 -0
  180. package/dist/graphql/index.js.map +1 -0
  181. package/dist/http/FetchHttpClient.d.ts +6 -3
  182. package/dist/http/FetchHttpClient.d.ts.map +1 -1
  183. package/dist/http/FetchHttpClient.js +6 -3
  184. package/dist/http/FetchHttpClient.js.map +1 -1
  185. package/dist/http/FindMyWay/internal/router.js +2 -1
  186. package/dist/http/FindMyWay/internal/router.js.map +1 -1
  187. package/dist/http/Headers.d.ts +3 -3
  188. package/dist/http/Headers.d.ts.map +1 -1
  189. package/dist/http/Headers.js +6 -5
  190. package/dist/http/Headers.js.map +1 -1
  191. package/dist/http/HttpClient.d.ts +27 -0
  192. package/dist/http/HttpClient.d.ts.map +1 -1
  193. package/dist/http/HttpClient.js +38 -11
  194. package/dist/http/HttpClient.js.map +1 -1
  195. package/dist/http/HttpClientError.d.ts.map +1 -1
  196. package/dist/http/HttpClientError.js +8 -6
  197. package/dist/http/HttpClientError.js.map +1 -1
  198. package/dist/http/HttpClientRequest.d.ts +147 -4
  199. package/dist/http/HttpClientRequest.d.ts.map +1 -1
  200. package/dist/http/HttpClientRequest.js +47 -1
  201. package/dist/http/HttpClientRequest.js.map +1 -1
  202. package/dist/http/HttpEffect.d.ts.map +1 -1
  203. package/dist/http/HttpEffect.js +14 -7
  204. package/dist/http/HttpEffect.js.map +1 -1
  205. package/dist/http/HttpMiddleware.d.ts +60 -0
  206. package/dist/http/HttpMiddleware.d.ts.map +1 -1
  207. package/dist/http/HttpMiddleware.js +93 -32
  208. package/dist/http/HttpMiddleware.js.map +1 -1
  209. package/dist/http/HttpRouter.d.ts +35 -0
  210. package/dist/http/HttpRouter.d.ts.map +1 -1
  211. package/dist/http/HttpRouter.js +87 -13
  212. package/dist/http/HttpRouter.js.map +1 -1
  213. package/dist/http/HttpServerError.d.ts.map +1 -1
  214. package/dist/http/HttpServerError.js +6 -4
  215. package/dist/http/HttpServerError.js.map +1 -1
  216. package/dist/http/HttpServerRequest.js +2 -2
  217. package/dist/http/HttpServerRequest.js.map +1 -1
  218. package/dist/http/HttpServerResponse.d.ts +8 -6
  219. package/dist/http/HttpServerResponse.d.ts.map +1 -1
  220. package/dist/http/HttpServerResponse.js +27 -16
  221. package/dist/http/HttpServerResponse.js.map +1 -1
  222. package/dist/http/HttpStaticServer.d.ts.map +1 -1
  223. package/dist/http/HttpStaticServer.js +4 -10
  224. package/dist/http/HttpStaticServer.js.map +1 -1
  225. package/dist/http/HttpTraceContext.js +1 -1
  226. package/dist/http/HttpTraceContext.js.map +1 -1
  227. package/dist/http/Multipart.d.ts.map +1 -1
  228. package/dist/http/Multipart.js +15 -1
  229. package/dist/http/Multipart.js.map +1 -1
  230. package/dist/http/Url.d.ts.map +1 -1
  231. package/dist/http/Url.js +2 -1
  232. package/dist/http/Url.js.map +1 -1
  233. package/dist/http/UrlParams.d.ts +112 -8
  234. package/dist/http/UrlParams.d.ts.map +1 -1
  235. package/dist/http/UrlParams.js +141 -14
  236. package/dist/http/UrlParams.js.map +1 -1
  237. package/dist/http/internal/compression.d.ts +1 -1
  238. package/dist/http/internal/compression.d.ts.map +1 -1
  239. package/dist/http/internal/compression.js +2 -10
  240. package/dist/http/internal/compression.js.map +1 -1
  241. package/dist/http/internal/compressionBody.d.ts +2 -0
  242. package/dist/http/internal/compressionBody.d.ts.map +1 -0
  243. package/dist/http/internal/compressionBody.js +36 -0
  244. package/dist/http/internal/compressionBody.js.map +1 -0
  245. package/dist/http/internal/decompression.d.ts +2 -0
  246. package/dist/http/internal/decompression.d.ts.map +1 -0
  247. package/dist/http/internal/decompression.js +162 -0
  248. package/dist/http/internal/decompression.js.map +1 -0
  249. package/dist/http/internal/tracing.js +14 -4
  250. package/dist/http/internal/tracing.js.map +1 -1
  251. package/dist/http/internal/urlParams.d.ts +2 -0
  252. package/dist/http/internal/urlParams.d.ts.map +1 -0
  253. package/dist/http/internal/urlParams.js +4 -0
  254. package/dist/http/internal/urlParams.js.map +1 -0
  255. package/dist/http-api/HttpApiClient.d.ts.map +1 -1
  256. package/dist/http-api/HttpApiClient.js +2 -1
  257. package/dist/http-api/HttpApiClient.js.map +1 -1
  258. package/dist/http-api/HttpApiScalar.d.ts +5 -0
  259. package/dist/http-api/HttpApiScalar.d.ts.map +1 -1
  260. package/dist/http-api/HttpApiScalar.js.map +1 -1
  261. package/dist/internal/core.js +17 -1
  262. package/dist/internal/core.js.map +1 -1
  263. package/dist/internal/dateTime.js +40 -35
  264. package/dist/internal/dateTime.js.map +1 -1
  265. package/dist/internal/effect.js +13 -6
  266. package/dist/internal/effect.js.map +1 -1
  267. package/dist/internal/graphql.d.ts +2 -0
  268. package/dist/internal/graphql.d.ts.map +1 -0
  269. package/dist/internal/graphql.js +205 -0
  270. package/dist/internal/graphql.js.map +1 -0
  271. package/dist/internal/graphqlHeaders.d.ts +4 -0
  272. package/dist/internal/graphqlHeaders.d.ts.map +1 -0
  273. package/dist/internal/graphqlHeaders.js +11 -0
  274. package/dist/internal/graphqlHeaders.js.map +1 -0
  275. package/dist/internal/request.js +20 -1
  276. package/dist/internal/request.js.map +1 -1
  277. package/dist/internal/schema/toCodeDocument.js +4 -1
  278. package/dist/internal/schema/toCodeDocument.js.map +1 -1
  279. package/dist/internal/schema/toJsonSchemaDocument.js +29 -5
  280. package/dist/internal/schema/toJsonSchemaDocument.js.map +1 -1
  281. package/dist/internal/version.js +1 -1
  282. package/dist/net/Host.d.ts +49 -0
  283. package/dist/net/Host.d.ts.map +1 -1
  284. package/dist/net/Host.js +55 -0
  285. package/dist/net/Host.js.map +1 -1
  286. package/dist/net/NetAddress.d.ts +8 -0
  287. package/dist/net/NetAddress.d.ts.map +1 -1
  288. package/dist/net/NetAddress.js +8 -0
  289. package/dist/net/NetAddress.js.map +1 -1
  290. package/dist/observability/Otlp.d.ts +15 -0
  291. package/dist/observability/Otlp.d.ts.map +1 -1
  292. package/dist/observability/Otlp.js +3 -0
  293. package/dist/observability/Otlp.js.map +1 -1
  294. package/dist/observability/OtlpExporter.d.ts +8 -0
  295. package/dist/observability/OtlpExporter.d.ts.map +1 -1
  296. package/dist/observability/OtlpExporter.js +10 -1
  297. package/dist/observability/OtlpExporter.js.map +1 -1
  298. package/dist/observability/OtlpLogger.d.ts +17 -0
  299. package/dist/observability/OtlpLogger.d.ts.map +1 -1
  300. package/dist/observability/OtlpLogger.js +14 -1
  301. package/dist/observability/OtlpLogger.js.map +1 -1
  302. package/dist/observability/OtlpMetrics.d.ts +17 -0
  303. package/dist/observability/OtlpMetrics.d.ts.map +1 -1
  304. package/dist/observability/OtlpMetrics.js +13 -0
  305. package/dist/observability/OtlpMetrics.js.map +1 -1
  306. package/dist/observability/OtlpTracer.d.ts +17 -0
  307. package/dist/observability/OtlpTracer.d.ts.map +1 -1
  308. package/dist/observability/OtlpTracer.js +15 -2
  309. package/dist/observability/OtlpTracer.js.map +1 -1
  310. package/dist/reactivity/AsyncResult.d.ts +6 -0
  311. package/dist/reactivity/AsyncResult.d.ts.map +1 -1
  312. package/dist/reactivity/AsyncResult.js +27 -0
  313. package/dist/reactivity/AsyncResult.js.map +1 -1
  314. package/dist/reactivity/AtomRegistry.js +3 -1
  315. package/dist/reactivity/AtomRegistry.js.map +1 -1
  316. package/dist/rpc/RpcClient.d.ts.map +1 -1
  317. package/dist/rpc/RpcClient.js +6 -1
  318. package/dist/rpc/RpcClient.js.map +1 -1
  319. package/dist/rpc/RpcServer.d.ts.map +1 -1
  320. package/dist/rpc/RpcServer.js +36 -9
  321. package/dist/rpc/RpcServer.js.map +1 -1
  322. package/dist/socket/Socket.d.ts +6 -0
  323. package/dist/socket/Socket.d.ts.map +1 -1
  324. package/dist/socket/Socket.js.map +1 -1
  325. package/dist/sql/SqlClient.d.ts +8 -7
  326. package/dist/sql/SqlClient.d.ts.map +1 -1
  327. package/dist/sql/SqlClient.js +8 -7
  328. package/dist/sql/SqlClient.js.map +1 -1
  329. package/dist/testing/TestClock.d.ts +16 -3
  330. package/dist/testing/TestClock.d.ts.map +1 -1
  331. package/dist/testing/TestClock.js +112 -22
  332. package/dist/testing/TestClock.js.map +1 -1
  333. package/dist/workflow/Activity.js +1 -0
  334. package/dist/workflow/Activity.js.map +1 -1
  335. package/dist/workflow/DurableDeferred.d.ts.map +1 -1
  336. package/dist/workflow/DurableDeferred.js +32 -3
  337. package/dist/workflow/DurableDeferred.js.map +1 -1
  338. package/dist/workflow/Workflow.d.ts +22 -0
  339. package/dist/workflow/Workflow.d.ts.map +1 -1
  340. package/dist/workflow/Workflow.js +15 -3
  341. package/dist/workflow/Workflow.js.map +1 -1
  342. package/dist/workflow/WorkflowEngine.d.ts +44 -3
  343. package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
  344. package/dist/workflow/WorkflowEngine.js +45 -22
  345. package/dist/workflow/WorkflowEngine.js.map +1 -1
  346. package/package.json +6 -3
  347. package/src/Array.ts +95 -6
  348. package/src/Channel.ts +24 -3
  349. package/src/ConfigProvider.ts +40 -44
  350. package/src/Context.ts +9 -0
  351. package/src/Duration.ts +4 -5
  352. package/src/Effect.ts +140 -53
  353. package/src/FileSystem.ts +23 -9
  354. package/src/Match.ts +65 -12
  355. package/src/Path.ts +52 -7
  356. package/src/RequestResolver.ts +4 -10
  357. package/src/Scheduler.ts +9 -0
  358. package/src/Schema.ts +25 -4
  359. package/src/SchemaGetter.ts +47 -35
  360. package/src/Sink.ts +45 -18
  361. package/src/Stream.ts +33 -4
  362. package/src/String.ts +17 -4
  363. package/src/TxRef.ts +4 -2
  364. package/src/Utils.ts +8 -5
  365. package/src/ai/AiError.ts +3 -1
  366. package/src/ai/AnthropicStructuredOutput.ts +2 -2
  367. package/src/ai/Chat.ts +2 -2
  368. package/src/ai/Decision.ts +70 -21
  369. package/src/ai/DecisionModel.ts +1 -1
  370. package/src/ai/LanguageModel.ts +141 -63
  371. package/src/ai/McpServer.ts +259 -145
  372. package/src/ai/Prompt.ts +24 -10
  373. package/src/ai/Response.ts +6 -3
  374. package/src/cli/Completions.ts +5 -0
  375. package/src/cli/Flag.ts +101 -0
  376. package/src/cli/Param.ts +96 -0
  377. package/src/cli/internal/command.ts +2 -1
  378. package/src/cli/internal/completions/bash.ts +4 -3
  379. package/src/cli/internal/completions/descriptor.ts +10 -1
  380. package/src/cli/internal/completions/fish.ts +4 -4
  381. package/src/cli/internal/completions/powershell.ts +5 -2
  382. package/src/cli/internal/completions/zsh.ts +7 -3
  383. package/src/cli/internal/parser.ts +12 -3
  384. package/src/cli/internal/wizard.ts +2 -1
  385. package/src/cluster/ClusterWorkflowEngine.ts +143 -36
  386. package/src/cluster/MessageStorage.ts +14 -3
  387. package/src/cluster/Runners.ts +88 -66
  388. package/src/cluster/Sharding.ts +12 -9
  389. package/src/cluster/internal/entityManager.ts +1 -1
  390. package/src/encoding/Sse.ts +70 -80
  391. package/src/graphql/GraphQL.ts +494 -0
  392. package/src/graphql/GraphQLClient.ts +924 -0
  393. package/src/graphql/GraphQLClientError.ts +542 -0
  394. package/src/graphql/GraphQLGroup.ts +167 -0
  395. package/src/graphql/GraphQLMiddleware.ts +253 -0
  396. package/src/graphql/GraphQLProtocol.ts +1540 -0
  397. package/src/graphql/GraphQLResolver.ts +1038 -0
  398. package/src/graphql/index.ts +48 -0
  399. package/src/http/FetchHttpClient.ts +6 -3
  400. package/src/http/FindMyWay/internal/router.ts +2 -1
  401. package/src/http/Headers.ts +6 -9
  402. package/src/http/HttpClient.ts +72 -11
  403. package/src/http/HttpClientError.ts +10 -6
  404. package/src/http/HttpClientRequest.ts +173 -7
  405. package/src/http/HttpEffect.ts +11 -5
  406. package/src/http/HttpMiddleware.ts +113 -34
  407. package/src/http/HttpRouter.ts +95 -13
  408. package/src/http/HttpServerError.ts +8 -4
  409. package/src/http/HttpServerRequest.ts +2 -2
  410. package/src/http/HttpServerResponse.ts +28 -16
  411. package/src/http/HttpStaticServer.ts +4 -10
  412. package/src/http/HttpTraceContext.ts +1 -1
  413. package/src/http/Multipart.ts +17 -1
  414. package/src/http/Url.ts +2 -1
  415. package/src/http/UrlParams.ts +225 -26
  416. package/src/http/internal/compression.ts +3 -17
  417. package/src/http/internal/compressionBody.ts +56 -0
  418. package/src/http/internal/decompression.ts +226 -0
  419. package/src/http/internal/tracing.ts +21 -4
  420. package/src/http/internal/urlParams.ts +5 -0
  421. package/src/http-api/HttpApiClient.ts +2 -1
  422. package/src/http-api/HttpApiScalar.ts +5 -0
  423. package/src/internal/core.ts +21 -1
  424. package/src/internal/dateTime.ts +13 -10
  425. package/src/internal/effect.ts +13 -7
  426. package/src/internal/graphql.ts +286 -0
  427. package/src/internal/graphqlHeaders.ts +11 -0
  428. package/src/internal/request.ts +31 -3
  429. package/src/internal/schema/toCodeDocument.ts +7 -1
  430. package/src/internal/schema/toJsonSchemaDocument.ts +34 -2
  431. package/src/internal/version.ts +1 -1
  432. package/src/net/Host.ts +72 -0
  433. package/src/net/NetAddress.ts +9 -0
  434. package/src/observability/Otlp.ts +18 -0
  435. package/src/observability/OtlpExporter.ts +14 -3
  436. package/src/observability/OtlpLogger.ts +31 -2
  437. package/src/observability/OtlpMetrics.ts +30 -1
  438. package/src/observability/OtlpTracer.ts +32 -3
  439. package/src/reactivity/AsyncResult.ts +31 -0
  440. package/src/reactivity/AtomRegistry.ts +3 -1
  441. package/src/rpc/RpcClient.ts +6 -1
  442. package/src/rpc/RpcServer.ts +55 -15
  443. package/src/socket/Socket.ts +6 -0
  444. package/src/sql/SqlClient.ts +9 -7
  445. package/src/testing/TestClock.ts +144 -29
  446. package/src/workflow/Activity.ts +1 -0
  447. package/src/workflow/DurableDeferred.ts +43 -5
  448. package/src/workflow/Workflow.ts +31 -5
  449. package/src/workflow/WorkflowEngine.ts +107 -25
package/src/ai/Prompt.ts CHANGED
@@ -2159,11 +2159,11 @@ export const fromResponseParts = (parts: ReadonlyArray<Response.AnyPart>): Promp
2159
2159
  return empty
2160
2160
  }
2161
2161
 
2162
- const assistantParts: Array<AssistantMessagePart> = []
2162
+ const assistantParts: Array<AssistantMessagePart | undefined> = []
2163
2163
  const toolParts: Array<ToolMessagePart> = []
2164
2164
 
2165
- const activeTextDeltas = new Map<string, { text: string; options: ProviderOptions }>()
2166
- const activeReasoningDeltas = new Map<string, { text: string; options: ProviderOptions }>()
2165
+ const activeTextDeltas = new Map<string, { index: number; text: string; options: ProviderOptions }>()
2166
+ const activeReasoningDeltas = new Map<string, { index: number; text: string; options: ProviderOptions }>()
2167
2167
 
2168
2168
  for (const part of parts) {
2169
2169
  switch (part.type) {
@@ -2175,7 +2175,8 @@ export const fromResponseParts = (parts: ReadonlyArray<Response.AnyPart>): Promp
2175
2175
 
2176
2176
  // Text Parts (streaming)
2177
2177
  case "text-start": {
2178
- activeTextDeltas.set(part.id, { text: "", options: part.metadata })
2178
+ activeTextDeltas.set(part.id, { index: assistantParts.length, text: "", options: part.metadata })
2179
+ assistantParts.push(undefined)
2179
2180
  break
2180
2181
  }
2181
2182
  case "text-delta": {
@@ -2190,7 +2191,8 @@ export const fromResponseParts = (parts: ReadonlyArray<Response.AnyPart>): Promp
2190
2191
  if (activeTextDeltas.has(part.id)) {
2191
2192
  const active = activeTextDeltas.get(part.id)!
2192
2193
  active.options = mergeOptions(active.options, part.metadata)
2193
- assistantParts.push(makePart("text", active))
2194
+ assistantParts[active.index] = makePart("text", { text: active.text, options: active.options })
2195
+ activeTextDeltas.delete(part.id)
2194
2196
  }
2195
2197
  break
2196
2198
  }
@@ -2203,7 +2205,8 @@ export const fromResponseParts = (parts: ReadonlyArray<Response.AnyPart>): Promp
2203
2205
 
2204
2206
  // Reasoning Parts (streaming)
2205
2207
  case "reasoning-start": {
2206
- activeReasoningDeltas.set(part.id, { text: "", options: part.metadata })
2208
+ activeReasoningDeltas.set(part.id, { index: assistantParts.length, text: "", options: part.metadata })
2209
+ assistantParts.push(undefined)
2207
2210
  break
2208
2211
  }
2209
2212
  case "reasoning-delta": {
@@ -2218,7 +2221,8 @@ export const fromResponseParts = (parts: ReadonlyArray<Response.AnyPart>): Promp
2218
2221
  if (activeReasoningDeltas.has(part.id)) {
2219
2222
  const active = activeReasoningDeltas.get(part.id)!
2220
2223
  active.options = mergeOptions(active.options, part.metadata)
2221
- assistantParts.push(makePart("reasoning", active))
2224
+ assistantParts[active.index] = makePart("reasoning", { text: active.text, options: active.options })
2225
+ activeReasoningDeltas.delete(part.id)
2222
2226
  }
2223
2227
  break
2224
2228
  }
@@ -2272,14 +2276,24 @@ export const fromResponseParts = (parts: ReadonlyArray<Response.AnyPart>): Promp
2272
2276
  }
2273
2277
  }
2274
2278
 
2275
- if (assistantParts.length === 0 && toolParts.length === 0) {
2279
+ // Keep partial text from unended blocks. Unended reasoning is dropped since it
2280
+ // may lack the signature or encrypted content providers require for replay.
2281
+ for (const active of activeTextDeltas.values()) {
2282
+ if (active.text.length > 0) {
2283
+ assistantParts[active.index] = makePart("text", { text: active.text, options: active.options })
2284
+ }
2285
+ }
2286
+
2287
+ const assistantContent = assistantParts.filter((part) => part !== undefined)
2288
+
2289
+ if (assistantContent.length === 0 && toolParts.length === 0) {
2276
2290
  return empty
2277
2291
  }
2278
2292
 
2279
2293
  const messages: Array<Message> = []
2280
2294
 
2281
- if (assistantParts.length > 0) {
2282
- messages.push(makeMessage("assistant", { content: assistantParts }))
2295
+ if (assistantContent.length > 0) {
2296
+ messages.push(makeMessage("assistant", { content: assistantContent }))
2283
2297
  }
2284
2298
 
2285
2299
  if (toolParts.length > 0) {
@@ -441,16 +441,19 @@ export const StreamPart = <T extends Toolkit.Any | Toolkit.WithHandler<any>>(
441
441
  export type ToolCallParts<
442
442
  Tools extends Record<string, Tool.Any>,
443
443
  ParametersMode extends ToolParametersMode = "decoded"
444
- > = ToolCallPartForName<Tools, ParametersMode, keyof Tools>
444
+ > = ParametersMode extends "deferred" ?
445
+ ToolCallPartForName<Tools, "opaque", keyof Tools> | ToolCallPart<string, unknown>
446
+ : ToolCallPartForName<Tools, ParametersMode, keyof Tools>
445
447
 
446
448
  /**
447
- * Controls whether tool parameters are decoded, encoded, or opaque.
449
+ * Controls tool parameter decoding. `"deferred"` allows undeclared tool names
450
+ * with opaque parameters, leaving validation to the caller.
448
451
  *
449
452
  * @stability unstable
450
453
  * @category utility types
451
454
  * @since 4.0.0
452
455
  */
453
- export type ToolParametersMode = "decoded" | "encoded" | "opaque"
456
+ export type ToolParametersMode = "decoded" | "encoded" | "opaque" | "deferred"
454
457
 
455
458
  type ToolCallPartForName<
456
459
  Tools extends Record<string, Tool.Any>,
@@ -48,6 +48,11 @@ export interface FlagDescriptor {
48
48
  readonly aliases: ReadonlyArray<string>
49
49
  readonly description: string | undefined
50
50
  readonly type: FlagType
51
+ /**
52
+ * Whether the flag's value is optional. Its value can only be attached with
53
+ * `=` (`--name=value`), never given as the next word.
54
+ */
55
+ readonly optionalValue?: boolean | undefined
51
56
  }
52
57
 
53
58
  /**
package/src/cli/Flag.ts CHANGED
@@ -611,6 +611,107 @@ export const withDescription: {
611
611
  <A>(self: Flag<A>, description: string): Flag<A>
612
612
  } = dual(2, <A>(self: Flag<A>, description: string) => Param.withDescription(self, description))
613
613
 
614
+ /**
615
+ * Lets a flag be given without a value, in which case `value` is used.
616
+ *
617
+ * **Details**
618
+ *
619
+ * Follows GNU-style optional values, like `--color[=WHEN]`. An explicit value
620
+ * must be attached with `=` (`--watch=until-done` or `-w=until-done`). A bare
621
+ * `--watch` is parsed as `--watch=<value>`, so `value` is validated like any
622
+ * other input. The flag never consumes the next token, so in `--watch build`,
623
+ * `build` stays a positional argument or subcommand. The flag is still
624
+ * required unless it is made optional or given a default.
625
+ *
626
+ * **Example** (Flag with an optional value)
627
+ *
628
+ * ```ts import.meta.vitest
629
+ * import { Flag } from "effect/cli"
630
+ *
631
+ * const watch = Flag.Literals("watch", ["first-failure", "until-done"]).pipe(
632
+ * Flag.withOptionalValue("first-failure"),
633
+ * Flag.optional
634
+ * )
635
+ * // --watch => Option.some("first-failure")
636
+ * // --watch=until-done => Option.some("until-done")
637
+ * // (absent) => Option.none()
638
+ * // In help: --watch [=choice]
639
+ * watch.kind // => "flag"
640
+ * ```
641
+ *
642
+ * @stability unstable
643
+ * @category combinators
644
+ * @since 4.1.0
645
+ */
646
+ export const withOptionalValue: {
647
+ /**
648
+ * Lets a flag be given without a value, in which case `value` is used.
649
+ *
650
+ * **Details**
651
+ *
652
+ * Follows GNU-style optional values, like `--color[=WHEN]`. An explicit value
653
+ * must be attached with `=` (`--watch=until-done` or `-w=until-done`). A bare
654
+ * `--watch` is parsed as `--watch=<value>`, so `value` is validated like any
655
+ * other input. The flag never consumes the next token, so in `--watch build`,
656
+ * `build` stays a positional argument or subcommand. The flag is still
657
+ * required unless it is made optional or given a default.
658
+ *
659
+ * **Example** (Flag with an optional value)
660
+ *
661
+ * ```ts import.meta.vitest
662
+ * import { Flag } from "effect/cli"
663
+ *
664
+ * const watch = Flag.Literals("watch", ["first-failure", "until-done"]).pipe(
665
+ * Flag.withOptionalValue("first-failure"),
666
+ * Flag.optional
667
+ * )
668
+ * // --watch => Option.some("first-failure")
669
+ * // --watch=until-done => Option.some("until-done")
670
+ * // (absent) => Option.none()
671
+ * // In help: --watch [=choice]
672
+ * watch.kind // => "flag"
673
+ * ```
674
+ *
675
+ * @stability unstable
676
+ * @category combinators
677
+ * @since 4.1.0
678
+ */
679
+ (value: string): <A>(self: Flag<A>) => Flag<A>
680
+ /**
681
+ * Lets a flag be given without a value, in which case `value` is used.
682
+ *
683
+ * **Details**
684
+ *
685
+ * Follows GNU-style optional values, like `--color[=WHEN]`. An explicit value
686
+ * must be attached with `=` (`--watch=until-done` or `-w=until-done`). A bare
687
+ * `--watch` is parsed as `--watch=<value>`, so `value` is validated like any
688
+ * other input. The flag never consumes the next token, so in `--watch build`,
689
+ * `build` stays a positional argument or subcommand. The flag is still
690
+ * required unless it is made optional or given a default.
691
+ *
692
+ * **Example** (Flag with an optional value)
693
+ *
694
+ * ```ts import.meta.vitest
695
+ * import { Flag } from "effect/cli"
696
+ *
697
+ * const watch = Flag.Literals("watch", ["first-failure", "until-done"]).pipe(
698
+ * Flag.withOptionalValue("first-failure"),
699
+ * Flag.optional
700
+ * )
701
+ * // --watch => Option.some("first-failure")
702
+ * // --watch=until-done => Option.some("until-done")
703
+ * // (absent) => Option.none()
704
+ * // In help: --watch [=choice]
705
+ * watch.kind // => "flag"
706
+ * ```
707
+ *
708
+ * @stability unstable
709
+ * @category combinators
710
+ * @since 4.1.0
711
+ */
712
+ <A>(self: Flag<A>, value: string): Flag<A>
713
+ } = dual(2, <A>(self: Flag<A>, value: string) => Param.withOptionalValue(self, value))
714
+
614
715
  // -------------------------------------------------------------------------------------
615
716
  // metadata
616
717
  // -------------------------------------------------------------------------------------
package/src/cli/Param.ts CHANGED
@@ -213,6 +213,10 @@ export interface Single<Kind extends ParamKind, out A> extends Param<Kind, A> {
213
213
  readonly primitiveType: Primitive.Primitive<A>
214
214
  readonly typeName?: string | undefined
215
215
  readonly hidden: boolean
216
+ /**
217
+ * Raw value used for a bare flag. See `withOptionalValue`.
218
+ */
219
+ readonly optionalValue?: string | undefined
216
220
  }
217
221
 
218
222
  /**
@@ -362,6 +366,7 @@ export const makeSingle = <const Kind extends ParamKind, A>(params: {
362
366
  readonly description?: Option.Option<string> | undefined
363
367
  readonly aliases?: ReadonlyArray<string> | undefined
364
368
  readonly hidden?: boolean | undefined
369
+ readonly optionalValue?: string | undefined
365
370
  }): Single<Kind, A> => {
366
371
  const parse: Parse<A> = (args) =>
367
372
  params.kind === argumentKind
@@ -2664,6 +2669,97 @@ export const withMetavar: {
2664
2669
  typeName: metavar
2665
2670
  })))
2666
2671
 
2672
+ /**
2673
+ * Lets a flag be given without a value, in which case `value` is used.
2674
+ *
2675
+ * **Details**
2676
+ *
2677
+ * Follows GNU-style optional values. An explicit value must be attached with
2678
+ * `=` (`--watch=until-done`), and a bare `--watch` is parsed as
2679
+ * `--watch=<value>`. The flag never consumes the next token. It is still
2680
+ * required unless it is made optional or given a default.
2681
+ *
2682
+ * **Example** (Flag with an optional value)
2683
+ *
2684
+ * ```ts import.meta.vitest
2685
+ * import { Param } from "effect/cli"
2686
+ *
2687
+ * const watch = Param.String(Param.flagKind, "watch").pipe(
2688
+ * Param.withOptionalValue("first-failure"),
2689
+ * Param.optional
2690
+ * )
2691
+ * watch.kind // => "flag"
2692
+ * ```
2693
+ *
2694
+ * @stability unstable
2695
+ * @category combinators
2696
+ * @since 4.1.0
2697
+ */
2698
+ export const withOptionalValue: {
2699
+ /**
2700
+ * Lets a flag be given without a value, in which case `value` is used.
2701
+ *
2702
+ * **Details**
2703
+ *
2704
+ * Follows GNU-style optional values. An explicit value must be attached with
2705
+ * `=` (`--watch=until-done`), and a bare `--watch` is parsed as
2706
+ * `--watch=<value>`. The flag never consumes the next token. It is still
2707
+ * required unless it is made optional or given a default.
2708
+ *
2709
+ * **Example** (Flag with an optional value)
2710
+ *
2711
+ * ```ts import.meta.vitest
2712
+ * import { Param } from "effect/cli"
2713
+ *
2714
+ * const watch = Param.String(Param.flagKind, "watch").pipe(
2715
+ * Param.withOptionalValue("first-failure"),
2716
+ * Param.optional
2717
+ * )
2718
+ * watch.kind // => "flag"
2719
+ * ```
2720
+ *
2721
+ * @stability unstable
2722
+ * @category combinators
2723
+ * @since 4.1.0
2724
+ */
2725
+ (value: string): <A>(self: Param<typeof flagKind, A>) => Param<typeof flagKind, A>
2726
+ /**
2727
+ * Lets a flag be given without a value, in which case `value` is used.
2728
+ *
2729
+ * **Details**
2730
+ *
2731
+ * Follows GNU-style optional values. An explicit value must be attached with
2732
+ * `=` (`--watch=until-done`), and a bare `--watch` is parsed as
2733
+ * `--watch=<value>`. The flag never consumes the next token. It is still
2734
+ * required unless it is made optional or given a default.
2735
+ *
2736
+ * **Example** (Flag with an optional value)
2737
+ *
2738
+ * ```ts import.meta.vitest
2739
+ * import { Param } from "effect/cli"
2740
+ *
2741
+ * const watch = Param.String(Param.flagKind, "watch").pipe(
2742
+ * Param.withOptionalValue("first-failure"),
2743
+ * Param.optional
2744
+ * )
2745
+ * watch.kind // => "flag"
2746
+ * ```
2747
+ *
2748
+ * @stability unstable
2749
+ * @category combinators
2750
+ * @since 4.1.0
2751
+ */
2752
+ <A>(self: Param<typeof flagKind, A>, value: string): Param<typeof flagKind, A>
2753
+ } = dual(2, <A>(
2754
+ self: Param<typeof flagKind, A>,
2755
+ value: string
2756
+ ) =>
2757
+ transformSingle(self, (single) =>
2758
+ makeSingle({
2759
+ ...single,
2760
+ optionalValue: value
2761
+ })))
2762
+
2667
2763
  /**
2668
2764
  * Validates parsed values against a Schema, providing detailed error messages.
2669
2765
  *
@@ -242,10 +242,11 @@ export const toFlagDoc = (
242
242
  metadata: ReturnType<typeof Param.getParamMetadata>
243
243
  ): FlagDoc => {
244
244
  const formattedAliases = single.aliases.map((alias) => alias.length === 1 ? `-${alias}` : `--${alias}`)
245
+ const type = single.typeName ?? Primitive.getTypeName(single.primitiveType)
245
246
  return {
246
247
  name: single.name,
247
248
  aliases: formattedAliases,
248
- type: single.typeName ?? Primitive.getTypeName(single.primitiveType),
249
+ type: single.optionalValue === undefined ? type : `[=${type}]`,
249
250
  description: appendChoiceKeys(single.description, Primitive.getChoiceKeys(single.primitiveType)),
250
251
  required: single.primitiveType._tag !== "Boolean" && !metadata.isOptional
251
252
  }
@@ -7,6 +7,7 @@
7
7
  * @internal
8
8
  */
9
9
  import type * as Completions from "../../Completions.ts"
10
+ import { takesSeparateValue } from "./descriptor.ts"
10
11
 
11
12
  // ---------------------------------------------------------------------------
12
13
  // Helpers
@@ -164,7 +165,7 @@ const generateFunction = (
164
165
  lines.push(``)
165
166
 
166
167
  // Build flag-value dispatch
167
- const flagsWithValues = descriptor.flags.filter((f) => f.type._tag !== "Boolean")
168
+ const flagsWithValues = descriptor.flags.filter(takesSeparateValue)
168
169
  if (flagsWithValues.length > 0) {
169
170
  lines.push(` # Flag value completions`)
170
171
  lines.push(` case "$prev" in`)
@@ -196,7 +197,7 @@ const generateFunction = (
196
197
  lines.push(` fi`)
197
198
  lines.push(` case "\${words[i]}" in`)
198
199
  for (const flag of descriptor.flags) {
199
- if (flag.type._tag === "Boolean") continue
200
+ if (!takesSeparateValue(flag)) continue
200
201
  const forms = flagNamesForWordlist(flag)
201
202
  lines.push(` ${forms.join("|")}) _skip_next=1 ;;`)
202
203
  lines.push(` ${forms.map((form) => `${form}=*`).join("|")}) ;;`)
@@ -248,7 +249,7 @@ const generateFunction = (
248
249
  lines.push(` --) _end_of_options=1 ;;`)
249
250
  for (const flag of descriptor.flags) {
250
251
  const forms = flagNamesForWordlist(flag)
251
- if (flag.type._tag === "Boolean") {
252
+ if (!takesSeparateValue(flag)) {
252
253
  lines.push(` ${forms.join("|")}) ;;`)
253
254
  } else {
254
255
  lines.push(` ${forms.join("|")}) _skip_next=1 ;;`)
@@ -95,7 +95,8 @@ export const fromCommand = (
95
95
  name: single.name,
96
96
  aliases: single.aliases,
97
97
  description: Option.getOrUndefined(single.description),
98
- type: toFlagType(single as Param.Single<"flag", unknown>)
98
+ type: toFlagType(single as Param.Single<"flag", unknown>),
99
+ optionalValue: single.optionalValue !== undefined
99
100
  })
100
101
  }
101
102
  }
@@ -139,3 +140,11 @@ export const fromCommand = (
139
140
  subcommands
140
141
  }
141
142
  }
143
+
144
+ /**
145
+ * Whether the flag reads its value from the next word.
146
+ *
147
+ * @internal
148
+ */
149
+ export const takesSeparateValue = (flag: Completions.FlagDescriptor): boolean =>
150
+ flag.type._tag !== "Boolean" && flag.optionalValue !== true
@@ -7,6 +7,7 @@
7
7
  * @internal
8
8
  */
9
9
  import type * as Completions from "../../Completions.ts"
10
+ import { takesSeparateValue } from "./descriptor.ts"
10
11
 
11
12
  // ---------------------------------------------------------------------------
12
13
  // Helpers
@@ -88,7 +89,7 @@ const flagCompletionArgs = (flag: Completions.FlagDescriptor): Array<string> =>
88
89
  if (flag.description) {
89
90
  args.push(`-d '${escapeFishString(flag.description)}'`)
90
91
  }
91
- const valueArgs = flagValueArgs(flag.type)
92
+ const valueArgs = takesSeparateValue(flag) ? flagValueArgs(flag.type) : undefined
92
93
  if (valueArgs) {
93
94
  args.push(valueArgs)
94
95
  }
@@ -159,8 +160,7 @@ const generateCompletions = (
159
160
 
160
161
  // Flag completions
161
162
  for (const flag of descriptor.flags) {
162
- const isBoolean = flag.type._tag === "Boolean"
163
- const dedup = isBoolean ? flagContainsOptCondition(flag) : valueFlagDedupCondition(flag)
163
+ const dedup = takesSeparateValue(flag) ? valueFlagDedupCondition(flag) : flagContainsOptCondition(flag)
164
164
  const flagCondition = condition ? `${condition}; and ${dedup}` : dedup
165
165
  const flagCondArg = flagCondition ? `-n '${flagCondition}'` : ``
166
166
 
@@ -170,7 +170,7 @@ const generateCompletions = (
170
170
  lines.push(parts.join(" "))
171
171
 
172
172
  // Boolean negation
173
- if (isBoolean) {
173
+ if (flag.type._tag === "Boolean") {
174
174
  const negParts = [`complete -c ${executableName}`]
175
175
  if (flagCondArg) negParts.push(flagCondArg)
176
176
  negParts.push(`-l no-${flag.name}`)
@@ -48,7 +48,9 @@ const valueFields = (type: Completions.FlagType | Completions.ArgumentType): str
48
48
 
49
49
  const flagEntry = (flag: Completions.FlagDescriptor): string =>
50
50
  `@{ name = ${quotePs(flag.name)}; forms = ${psArray(flagForms(flag))}; ` +
51
- `takesValue = $${flag.type._tag !== "Boolean"}; ${valueFields(flag.type)}; ` +
51
+ `takesValue = $${flag.type._tag !== "Boolean"}; ` +
52
+ (flag.optionalValue === true ? `optionalValue = $true; ` : "") +
53
+ `${valueFields(flag.type)}; ` +
52
54
  `description = ${psOptional(flag.description)} }`
53
55
 
54
56
  const argumentEntry = (argument: Completions.ArgumentDescriptor): string =>
@@ -235,7 +237,8 @@ const completer = (dataName: string): string =>
235
237
  continue
236
238
  }
237
239
  $used[$flag.name] = $true
238
- if (-not $hasValue) { $pending = $flag }
240
+ # A flag with an optional value only takes a value attached with '='.
241
+ if (-not $hasValue -and -not $flag.optionalValue) { $pending = $flag }
239
242
  }
240
243
  continue
241
244
  }
@@ -72,16 +72,20 @@ const argAction = (type: Completions.ArgumentType): string => {
72
72
  const flagSpecs = (flag: Completions.FlagDescriptor): Array<string> => {
73
73
  const specs: Array<string> = []
74
74
  const desc = flag.description ? `[${escapeZshExplanation(flag.description)}]` : ""
75
- const action = valueAction(flag.type)
75
+ // An optional value must follow `=` in the same word (`--name=-`), and `::`
76
+ // marks it optional.
77
+ const optional = flag.optionalValue === true && flag.type._tag !== "Boolean"
78
+ const valueSuffix = optional ? "=-" : ""
79
+ const action = optional ? `:${valueAction(flag.type)}` : valueAction(flag.type)
76
80
  const excl = `(${allForms(flag).join(" ")})`
77
81
 
78
82
  // Primary long name
79
- specs.push(`'${excl}--${flag.name}${desc}${action}'`)
83
+ specs.push(`'${excl}--${flag.name}${valueSuffix}${desc}${action}'`)
80
84
 
81
85
  // Aliases
82
86
  for (const alias of flag.aliases) {
83
87
  const prefix = alias.length === 1 ? "-" : "--"
84
- specs.push(`'${excl}${prefix}${alias}${desc}${action}'`)
88
+ specs.push(`'${excl}${prefix}${alias}${valueSuffix}${desc}${action}'`)
85
89
  }
86
90
 
87
91
  // Boolean negation
@@ -425,8 +425,9 @@ const asBooleanLiteral = (token: Token | undefined): string | undefined =>
425
425
  *
426
426
  * Value resolution order:
427
427
  * 1. Inline value: --flag=value or -f=value
428
- * 2. Boolean special case: implicit "true" or explicit boolean literal
429
- * 3. Next token: consume following Value token if present
428
+ * 2. Optional value: the flag's configured value, without consuming a token
429
+ * 3. Boolean special case: implicit "true" or explicit boolean literal
430
+ * 4. Next token: consume following Value token if present
430
431
  */
431
432
  const consumeFlagValue = (
432
433
  cursor: TokenCursor,
@@ -465,7 +466,7 @@ const consumeFlagValueWithTokens = (
465
466
  }
466
467
  }
467
468
 
468
- const literal = asBooleanLiteral(cursor.peek())
469
+ const literal = spec.optionalValue === undefined ? asBooleanLiteral(cursor.peek()) : undefined
469
470
  if (literal !== undefined) {
470
471
  const literalToken = cursor.take()
471
472
  return {
@@ -490,6 +491,14 @@ const consumeFlagValueWithTokens = (
490
491
  }
491
492
  }
492
493
 
494
+ if (spec.optionalValue !== undefined) {
495
+ return {
496
+ _tag: "Value",
497
+ value: spec.optionalValue,
498
+ tokens: []
499
+ }
500
+ }
501
+
493
502
  // Boolean flags: check for explicit literal or default to "true"
494
503
  if (Primitive.isBoolean(spec.primitiveType)) {
495
504
  const literal = asBooleanLiteral(cursor.peek())
@@ -171,8 +171,9 @@ const promptParam = Effect.fnUntraced(
171
171
  return values
172
172
  }
173
173
  // Inline option-looking values so the lexer cannot interpret them as flags or the -- delimiter.
174
+ // Flags with an optional value only accept an inline value.
174
175
  return values.flatMap((value) =>
175
- value.value.startsWith("-") && value.value.length > 1
176
+ single.optionalValue !== undefined || (value.value.startsWith("-") && value.value.length > 1)
176
177
  ? [commandLineArg(`--${single.name}=${value.value}`, `--${single.name}=${value.displayValue}`)]
177
178
  : [commandLineArg(`--${single.name}`), value]
178
179
  )