effect 4.0.0-beta.13 → 4.0.0-beta.15

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 (64) hide show
  1. package/dist/Channel.d.ts +6 -6
  2. package/dist/Channel.d.ts.map +1 -1
  3. package/dist/Channel.js +4 -4
  4. package/dist/Channel.js.map +1 -1
  5. package/dist/Effect.d.ts +7 -7
  6. package/dist/Effect.d.ts.map +1 -1
  7. package/dist/Effect.js.map +1 -1
  8. package/dist/Stream.d.ts +7 -7
  9. package/dist/Stream.d.ts.map +1 -1
  10. package/dist/Stream.js +8 -6
  11. package/dist/Stream.js.map +1 -1
  12. package/dist/Types.d.ts +70 -0
  13. package/dist/Types.d.ts.map +1 -1
  14. package/dist/internal/effect.js +4 -4
  15. package/dist/internal/effect.js.map +1 -1
  16. package/dist/unstable/ai/LanguageModel.d.ts +2 -0
  17. package/dist/unstable/ai/LanguageModel.d.ts.map +1 -1
  18. package/dist/unstable/ai/LanguageModel.js.map +1 -1
  19. package/dist/unstable/cli/Command.d.ts +34 -4
  20. package/dist/unstable/cli/Command.d.ts.map +1 -1
  21. package/dist/unstable/cli/Command.js +75 -20
  22. package/dist/unstable/cli/Command.js.map +1 -1
  23. package/dist/unstable/cli/GlobalFlag.d.ts +25 -62
  24. package/dist/unstable/cli/GlobalFlag.d.ts.map +1 -1
  25. package/dist/unstable/cli/GlobalFlag.js +41 -87
  26. package/dist/unstable/cli/GlobalFlag.js.map +1 -1
  27. package/dist/unstable/cli/internal/command.d.ts +3 -0
  28. package/dist/unstable/cli/internal/command.d.ts.map +1 -1
  29. package/dist/unstable/cli/internal/command.js +2 -0
  30. package/dist/unstable/cli/internal/command.js.map +1 -1
  31. package/dist/unstable/cli/internal/help.d.ts +18 -4
  32. package/dist/unstable/cli/internal/help.d.ts.map +1 -1
  33. package/dist/unstable/cli/internal/help.js +62 -9
  34. package/dist/unstable/cli/internal/help.js.map +1 -1
  35. package/dist/unstable/httpapi/HttpApiBuilder.d.ts +10 -4
  36. package/dist/unstable/httpapi/HttpApiBuilder.d.ts.map +1 -1
  37. package/dist/unstable/httpapi/HttpApiBuilder.js +17 -6
  38. package/dist/unstable/httpapi/HttpApiBuilder.js.map +1 -1
  39. package/dist/unstable/httpapi/HttpApiEndpoint.d.ts +7 -2
  40. package/dist/unstable/httpapi/HttpApiEndpoint.d.ts.map +1 -1
  41. package/dist/unstable/httpapi/HttpApiEndpoint.js.map +1 -1
  42. package/dist/unstable/httpapi/OpenApi.d.ts.map +1 -1
  43. package/dist/unstable/httpapi/OpenApi.js +3 -4
  44. package/dist/unstable/httpapi/OpenApi.js.map +1 -1
  45. package/dist/unstable/reactivity/AtomHttpApi.d.ts +2 -2
  46. package/dist/unstable/reactivity/AtomHttpApi.d.ts.map +1 -1
  47. package/dist/unstable/reactivity/AtomRegistry.js +2 -6
  48. package/dist/unstable/reactivity/AtomRegistry.js.map +1 -1
  49. package/package.json +1 -1
  50. package/src/Channel.ts +24 -14
  51. package/src/Effect.ts +30 -8
  52. package/src/Stream.ts +46 -22
  53. package/src/Types.ts +66 -0
  54. package/src/internal/effect.ts +41 -14
  55. package/src/unstable/ai/LanguageModel.ts +9 -6
  56. package/src/unstable/cli/Command.ts +122 -24
  57. package/src/unstable/cli/GlobalFlag.ts +98 -197
  58. package/src/unstable/cli/internal/command.ts +5 -0
  59. package/src/unstable/cli/internal/help.ts +104 -24
  60. package/src/unstable/httpapi/HttpApiBuilder.ts +68 -13
  61. package/src/unstable/httpapi/HttpApiEndpoint.ts +13 -4
  62. package/src/unstable/httpapi/OpenApi.ts +3 -4
  63. package/src/unstable/reactivity/AtomHttpApi.ts +2 -2
  64. package/src/unstable/reactivity/AtomRegistry.ts +2 -6
@@ -50,7 +50,9 @@ import type {
50
50
  ExcludeTag,
51
51
  ExtractReason,
52
52
  ExtractTag,
53
+ NarrowReason,
53
54
  NoInfer,
55
+ OmitReason,
54
56
  ReasonOf,
55
57
  ReasonTags,
56
58
  Simplify,
@@ -2824,8 +2826,16 @@ export const catchReason: {
2824
2826
  >(
2825
2827
  errorTag: K,
2826
2828
  reasonTag: RK,
2827
- f: (reason: ExtractReason<ExtractTag<NoInfer<E>, K>, RK>) => Effect.Effect<A2, E2, R2>,
2828
- orElse?: ((reasons: ExcludeReason<ExtractTag<NoInfer<E>, K>, RK>) => Effect.Effect<A3, E3, R3>) | undefined
2829
+ f: (
2830
+ reason: ExtractReason<ExtractTag<NoInfer<E>, K>, RK>,
2831
+ error: NarrowReason<ExtractTag<NoInfer<E>, K>, RK>
2832
+ ) => Effect.Effect<A2, E2, R2>,
2833
+ orElse?:
2834
+ | ((
2835
+ reasons: ExcludeReason<ExtractTag<NoInfer<E>, K>, RK>,
2836
+ error: OmitReason<ExtractTag<NoInfer<E>, K>, RK>
2837
+ ) => Effect.Effect<A3, E3, R3>)
2838
+ | undefined
2829
2839
  ): <A, R>(
2830
2840
  self: Effect.Effect<A, E, R>
2831
2841
  ) => Effect.Effect<
@@ -2849,8 +2859,16 @@ export const catchReason: {
2849
2859
  self: Effect.Effect<A, E, R>,
2850
2860
  errorTag: K,
2851
2861
  reasonTag: RK,
2852
- f: (reason: ExtractReason<ExtractTag<E, K>, RK>) => Effect.Effect<A2, E2, R2>,
2853
- orElse?: ((reasons: ExcludeReason<ExtractTag<E, K>, RK>) => Effect.Effect<A3, E3, R3>) | undefined
2862
+ f: (
2863
+ reason: ExtractReason<ExtractTag<E, K>, RK>,
2864
+ error: NarrowReason<ExtractTag<E, K>, RK>
2865
+ ) => Effect.Effect<A2, E2, R2>,
2866
+ orElse?:
2867
+ | ((
2868
+ reasons: ExcludeReason<ExtractTag<E, K>, RK>,
2869
+ error: OmitReason<ExtractTag<E, K>, RK>
2870
+ ) => Effect.Effect<A3, E3, R3>)
2871
+ | undefined
2854
2872
  ): Effect.Effect<
2855
2873
  A | A2 | Exclude<A3, unassigned>,
2856
2874
  (A3 extends unassigned ? E : ExcludeTag<E, K>) | E2 | E3,
@@ -2874,8 +2892,13 @@ export const catchReason: {
2874
2892
  self: Effect.Effect<A, E, R>,
2875
2893
  errorTag: K,
2876
2894
  reasonTag: RK,
2877
- f: (reason: ExtractReason<ExtractTag<E, K>, RK>) => Effect.Effect<A2, E2, R2>,
2878
- orElse?: ((reasons: ExcludeReason<ExtractTag<E, K>, RK>) => Effect.Effect<A3, E3, R3>) | undefined
2895
+ f: (reason: ExtractReason<ExtractTag<E, K>, RK>, error: ExtractTag<E, K>) => Effect.Effect<A2, E2, R2>,
2896
+ orElse?:
2897
+ | ((
2898
+ reasons: ExcludeReason<ExtractTag<E, K>, RK>,
2899
+ error: OmitReason<ExtractTag<E, K>, RK>
2900
+ ) => Effect.Effect<A3, E3, R3>)
2901
+ | undefined
2879
2902
  ): Effect.Effect<
2880
2903
  A | A2 | Exclude<A3, unassigned>,
2881
2904
  (A3 extends unassigned ? E : ExcludeTag<E, K>) | E2 | E3,
@@ -2886,8 +2909,8 @@ export const catchReason: {
2886
2909
  ((e: any) => isTagged(e, errorTag) && hasProperty(e, "reason")) as any,
2887
2910
  (e: any): Effect.Effect<A2 | A3, E | E2 | E3, R2 | R3> => {
2888
2911
  const reason = e.reason as any
2889
- if (isTagged(reason, reasonTag)) return f(reason as any)
2890
- return orElse ? internalCall(() => orElse(reason)) : fail(e)
2912
+ if (isTagged(reason, reasonTag)) return f(reason as any, e)
2913
+ return orElse ? internalCall(() => orElse(reason, e)) : fail(e)
2891
2914
  }
2892
2915
  ) as any
2893
2916
  )
@@ -2899,7 +2922,8 @@ export const catchReasons: {
2899
2922
  E,
2900
2923
  Cases extends {
2901
2924
  [RK in ReasonTags<ExtractTag<NoInfer<E>, K>>]+?: (
2902
- reason: ExtractReason<ExtractTag<NoInfer<E>, K>, RK>
2925
+ reason: ExtractReason<ExtractTag<NoInfer<E>, K>, RK>,
2926
+ error: NarrowReason<ExtractTag<NoInfer<E>, K>, RK>
2903
2927
  ) => Effect.Effect<any, any, any>
2904
2928
  },
2905
2929
  A2 = unassigned,
@@ -2910,7 +2934,8 @@ export const catchReasons: {
2910
2934
  cases: Cases,
2911
2935
  orElse?:
2912
2936
  | ((
2913
- reason: ExcludeReason<ExtractTag<NoInfer<E>, K>, Extract<keyof Cases, string>>
2937
+ reason: ExcludeReason<ExtractTag<NoInfer<E>, K>, Extract<keyof Cases, string>>,
2938
+ error: OmitReason<ExtractTag<NoInfer<E>, K>, Extract<keyof Cases, string>>
2914
2939
  ) => Effect.Effect<A2, E2, R2>)
2915
2940
  | undefined
2916
2941
  ): <A, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<
@@ -2937,7 +2962,8 @@ export const catchReasons: {
2937
2962
  K extends Tags<E>,
2938
2963
  Cases extends {
2939
2964
  [RK in ReasonTags<ExtractTag<E, K>>]+?: (
2940
- reason: ExtractReason<ExtractTag<E, K>, RK>
2965
+ reason: ExtractReason<ExtractTag<E, K>, RK>,
2966
+ error: NarrowReason<ExtractTag<E, K>, RK>
2941
2967
  ) => Effect.Effect<any, any, any>
2942
2968
  },
2943
2969
  A2 = unassigned,
@@ -2949,7 +2975,8 @@ export const catchReasons: {
2949
2975
  cases: Cases,
2950
2976
  orElse?:
2951
2977
  | ((
2952
- reason: ExcludeReason<ExtractTag<NoInfer<E>, K>, Extract<keyof Cases, string>>
2978
+ reason: ExcludeReason<ExtractTag<NoInfer<E>, K>, Extract<keyof Cases, string>>,
2979
+ error: OmitReason<ExtractTag<NoInfer<E>, K>, Extract<keyof Cases, string>>
2953
2980
  ) => Effect.Effect<A2, E2, R2>)
2954
2981
  | undefined
2955
2982
  ): Effect.Effect<
@@ -2982,9 +3009,9 @@ export const catchReasons: {
2982
3009
  const reason = e.reason
2983
3010
  keys ??= Object.keys(cases)
2984
3011
  if (keys.includes(reason._tag)) {
2985
- return internalCall(() => (cases as any)[reason._tag](reason))
3012
+ return internalCall(() => (cases as any)[reason._tag](reason, e))
2986
3013
  }
2987
- return orElse ? internalCall(() => orElse(reason)) : fail(e)
3014
+ return orElse ? internalCall(() => orElse(reason, e)) : fail(e)
2988
3015
  }
2989
3016
  )
2990
3017
  })
@@ -527,13 +527,16 @@ export type ExtractError<Options> = Options extends {
527
527
  * @category utility types
528
528
  */
529
529
  export type ExtractServices<Options> = Options extends {
530
- readonly toolkit: Toolkit.WithHandler<infer _Tools>
531
- }
530
+ readonly disableToolCallResolution: true
531
+ } ? never
532
+ : Options extends {
533
+ readonly toolkit: Toolkit.WithHandler<infer _Tools>
534
+ }
532
535
  // Required for tool call execution
533
- ?
534
- | Tool.ResultEncodingServices<_Tools[keyof _Tools]>
535
- // Required for decoding large language model responses
536
- | Tool.ResultDecodingServices<_Tools[keyof _Tools]>
536
+ ?
537
+ | Tool.ResultEncodingServices<_Tools[keyof _Tools]>
538
+ // Required for decoding large language model responses
539
+ | Tool.ResultDecodingServices<_Tools[keyof _Tools]>
537
540
  : Options extends {
538
541
  readonly toolkit: Effect.Yieldable<
539
542
  Toolkit.Toolkit<infer _Tools>,
@@ -6,10 +6,12 @@ import * as Console from "../../Console.ts"
6
6
  import * as Effect from "../../Effect.ts"
7
7
  import type * as FileSystem from "../../FileSystem.ts"
8
8
  import { dual } from "../../Function.ts"
9
- import * as Layer from "../../Layer.ts"
9
+ import type * as Layer from "../../Layer.ts"
10
+ import * as Option from "../../Option.ts"
10
11
  import type * as Path from "../../Path.ts"
11
12
  import type { Pipeable } from "../../Pipeable.ts"
12
13
  import * as Predicate from "../../Predicate.ts"
14
+ import * as References from "../../References.ts"
13
15
  import * as Result from "../../Result.ts"
14
16
  import * as ServiceMap from "../../ServiceMap.ts"
15
17
  import * as Terminal from "../../Terminal.ts"
@@ -20,7 +22,7 @@ import * as CliOutput from "./CliOutput.ts"
20
22
  import * as GlobalFlag from "./GlobalFlag.ts"
21
23
  import { checkForDuplicateFlags, makeCommand, toImpl, TypeId } from "./internal/command.ts"
22
24
  import { parseConfig } from "./internal/config.ts"
23
- import { getHelpForCommandPath } from "./internal/help.ts"
25
+ import { getGlobalFlagsForCommandPath, getGlobalFlagsForCommandTree, getHelpForCommandPath } from "./internal/help.ts"
24
26
  import * as Lexer from "./internal/lexer.ts"
25
27
  import * as Parser from "./internal/parser.ts"
26
28
  import * as Param from "./Param.ts"
@@ -586,7 +588,7 @@ export const make: {
586
588
  name: Name,
587
589
  config: Config,
588
590
  handler: (config: Command.Config.Infer<Config>) => Effect.Effect<void, E, R>
589
- ): Command<Name, Command.Config.Infer<Config>, E, R>
591
+ ): Command<Name, Command.Config.Infer<Config>, E, Exclude<R, GlobalFlag.BuiltInSettingContext>>
590
592
  } = ((
591
593
  name: string,
592
594
  config?: Command.Config,
@@ -659,7 +661,7 @@ export const withHandler: {
659
661
  */
660
662
  <A, R, E>(handler: (value: A) => Effect.Effect<void, E, R>): <Name extends string, XR, XE>(
661
663
  self: Command<Name, A, XE, XR>
662
- ) => Command<Name, A, E, R>
664
+ ) => Command<Name, A, E, Exclude<R, GlobalFlag.BuiltInSettingContext>>
663
665
  /* ========================================================================== */
664
666
  /* Combinators */
665
667
  /* ========================================================================== */
@@ -691,11 +693,12 @@ export const withHandler: {
691
693
  <Name extends string, A, XR, XE, R, E>(
692
694
  self: Command<Name, A, XE, XR>,
693
695
  handler: (value: A) => Effect.Effect<void, E, R>
694
- ): Command<Name, A, E, R>
696
+ ): Command<Name, A, E, Exclude<R, GlobalFlag.BuiltInSettingContext>>
695
697
  } = dual(2, <Name extends string, A, XR, XE, R, E>(
696
698
  self: Command<Name, A, XE, XR>,
697
699
  handler: (value: A) => Effect.Effect<void, E, R>
698
- ): Command<Name, A, E, R> => makeCommand({ ...toImpl(self), handle: handler }))
700
+ ): Command<Name, A, E, Exclude<R, GlobalFlag.BuiltInSettingContext>> =>
701
+ makeCommand({ ...toImpl(self), handle: handler }))
699
702
 
700
703
  interface SubcommandGroupInternal {
701
704
  readonly group: string | undefined
@@ -940,6 +943,7 @@ export const withSubcommands: {
940
943
  shortDescription: impl.shortDescription,
941
944
  alias: impl.alias,
942
945
  annotations: impl.annotations,
946
+ globalFlags: impl.globalFlags,
943
947
  examples: impl.examples,
944
948
  service: impl.service,
945
949
  subcommands: normalized.groups,
@@ -948,7 +952,50 @@ export const withSubcommands: {
948
952
  })
949
953
  })
950
954
 
955
+ /**
956
+ * Declares global flags for a command scope.
957
+ *
958
+ * Declared global flags apply to the command and all of its descendants.
959
+ *
960
+ * @since 4.0.0
961
+ * @category combinators
962
+ */
963
+ export const withGlobalFlags: {
964
+ /**
965
+ * Declares global flags for a command scope.
966
+ *
967
+ * Declared global flags apply to the command and all of its descendants.
968
+ *
969
+ * @since 4.0.0
970
+ * @category combinators
971
+ */
972
+ <const GlobalFlags extends ReadonlyArray<GlobalFlag.GlobalFlag<any>>>(globalFlags: GlobalFlags): <Name extends string, Input, E, R>(
973
+ self: Command<Name, Input, E, R>
974
+ ) => Command<Name, Input, E, Exclude<R, ExtractGlobalFlagContext<GlobalFlags>>>
975
+ /**
976
+ * Declares global flags for a command scope.
977
+ *
978
+ * Declared global flags apply to the command and all of its descendants.
979
+ *
980
+ * @since 4.0.0
981
+ * @category combinators
982
+ */
983
+ <Name extends string, Input, E, R, const GlobalFlags extends ReadonlyArray<GlobalFlag.GlobalFlag<any>>>(self: Command<Name, Input, E, R>, globalFlags: GlobalFlags): Command<Name, Input, E, Exclude<R, ExtractGlobalFlagContext<GlobalFlags>>>
984
+ } = dual(
985
+ 2,
986
+ <Name extends string, Input, E, R, const GlobalFlags extends ReadonlyArray<GlobalFlag.GlobalFlag<any>>>(
987
+ self: Command<Name, Input, E, R>,
988
+ globalFlags: GlobalFlags
989
+ ): Command<Name, Input, E, Exclude<R, ExtractGlobalFlagContext<GlobalFlags>>> => {
990
+ const impl = toImpl(self)
991
+ const next = Array.from(new Set([...impl.globalFlags, ...globalFlags]))
992
+ return makeCommand({ ...impl, globalFlags: next })
993
+ }
994
+ )
995
+
951
996
  // Type extractors for subcommand arrays - T[number] gives union of all elements
997
+ type ExtractGlobalFlagContext<T extends ReadonlyArray<GlobalFlag.GlobalFlag<any>>> = T[number] extends
998
+ GlobalFlag.Setting<infer Id, any> ? GlobalFlag.Setting.Identifier<Id> : never
952
999
  type ExtractSubcommand<T> = T extends Command<any, any, any, any> ? T
953
1000
  : T extends Command.SubcommandGroup<infer Commands> ? Commands[number]
954
1001
  : never
@@ -1532,6 +1579,45 @@ export const provideEffectDiscard: {
1532
1579
  /* Execution */
1533
1580
  /* ========================================================================== */
1534
1581
 
1582
+ const getOutOfScopeGlobalFlagErrors = (
1583
+ allFlags: ReadonlyArray<GlobalFlag.GlobalFlag<any>>,
1584
+ activeFlags: ReadonlyArray<GlobalFlag.GlobalFlag<any>>,
1585
+ flagMap: Record<string, ReadonlyArray<string>>,
1586
+ commandPath: ReadonlyArray<string>
1587
+ ): ReadonlyArray<CliError.CliError> => {
1588
+ const activeSet = new Set(activeFlags)
1589
+ const errors: Array<CliError.CliError> = []
1590
+ const seen = new Set<string>()
1591
+
1592
+ for (const flag of allFlags) {
1593
+ if (activeSet.has(flag)) {
1594
+ continue
1595
+ }
1596
+
1597
+ const singles = Param.extractSingleParams(flag.flag)
1598
+ for (const single of singles) {
1599
+ const entries = flagMap[single.name]
1600
+ if (!entries || entries.length === 0) {
1601
+ continue
1602
+ }
1603
+ const option = `--${single.name}`
1604
+ if (seen.has(option)) {
1605
+ continue
1606
+ }
1607
+ seen.add(option)
1608
+ errors.push(
1609
+ new CliError.UnrecognizedOption({
1610
+ option,
1611
+ suggestions: [],
1612
+ command: commandPath
1613
+ })
1614
+ )
1615
+ }
1616
+ }
1617
+
1618
+ return errors
1619
+ }
1620
+
1535
1621
  const showHelp = <Name extends string, Input, E, R>(
1536
1622
  command: Command<Name, Input, E, R>,
1537
1623
  commandPath: ReadonlyArray<string>,
@@ -1539,7 +1625,7 @@ const showHelp = <Name extends string, Input, E, R>(
1539
1625
  ): Effect.Effect<void, never, Environment> =>
1540
1626
  Effect.gen(function*() {
1541
1627
  const formatter = yield* CliOutput.Formatter
1542
- const helpDoc = yield* getHelpForCommandPath(command, commandPath, GlobalFlag.Registry)
1628
+ const helpDoc = yield* getHelpForCommandPath(command, commandPath, GlobalFlag.BuiltIns)
1543
1629
  yield* Console.log(formatter.formatHelpDoc(helpDoc))
1544
1630
  if (errors && errors.length > 0) {
1545
1631
  yield* Console.error(formatter.formatErrors(errors))
@@ -1696,15 +1782,11 @@ export const runWith = <const Name extends string, Input, E, R>(
1696
1782
  function*(args: ReadonlyArray<string>) {
1697
1783
  const { tokens, trailingOperands } = Lexer.lex(args)
1698
1784
 
1699
- // 1. Read registry and resolve each reference to its current value
1700
- const refs = yield* GlobalFlag.Registry
1701
- const flags: Array<GlobalFlag.GlobalFlag<any>> = []
1702
- for (const ref of refs) {
1703
- flags.push(yield* ref)
1704
- }
1785
+ // 1. Collect known global flags from the command tree
1786
+ const allFlags = getGlobalFlagsForCommandTree(command, GlobalFlag.BuiltIns)
1705
1787
 
1706
1788
  // 2. Extract global flag tokens
1707
- const allFlagParams = flags.flatMap((f) => Param.extractSingleParams(f.flag))
1789
+ const allFlagParams = allFlags.flatMap((f) => Param.extractSingleParams(f.flag))
1708
1790
  const globalRegistry = Parser.createFlagRegistry(allFlagParams.filter(Param.isFlagParam))
1709
1791
  const { flagMap, remainder } = Parser.consumeKnownFlags(tokens, globalRegistry)
1710
1792
  const emptyArgs: Param.ParsedArgs = { flags: flagMap, arguments: [] }
@@ -1713,9 +1795,17 @@ export const runWith = <const Name extends string, Input, E, R>(
1713
1795
  const parsedArgs = yield* Parser.parseArgs({ tokens: remainder, trailingOperands }, command)
1714
1796
  const commandPath = [command.name, ...Parser.getCommandPath(parsedArgs)] as const
1715
1797
  const handlerCtx: GlobalFlag.HandlerContext = { command, commandPath, version: config.version }
1798
+ const activeFlags = getGlobalFlagsForCommandPath(command, commandPath, GlobalFlag.BuiltIns)
1716
1799
 
1717
- // 4. Process action flags first present action wins, then exit
1718
- for (const flag of flags) {
1800
+ // 4. Reject globals that were passed outside the active command scope
1801
+ const outOfScopeErrors = getOutOfScopeGlobalFlagErrors(allFlags, activeFlags, flagMap, commandPath)
1802
+ if (outOfScopeErrors.length > 0) {
1803
+ const parseErrors = parsedArgs.errors ?? []
1804
+ return yield* showHelp(command, commandPath, [...outOfScopeErrors, ...parseErrors])
1805
+ }
1806
+
1807
+ // 5. Process action flags — first present action wins, then exit
1808
+ for (const flag of activeFlags) {
1719
1809
  if (flag._tag !== "Action") continue
1720
1810
  const singles = Param.extractSingleParams(flag.flag)
1721
1811
  const hasEntry = singles.some((s) => {
@@ -1728,7 +1818,7 @@ export const runWith = <const Name extends string, Input, E, R>(
1728
1818
  return
1729
1819
  }
1730
1820
 
1731
- // 5. Handle parsing errors
1821
+ // 6. Handle parsing errors
1732
1822
  if (parsedArgs.errors && parsedArgs.errors.length > 0) {
1733
1823
  return yield* showHelp(command, commandPath, parsedArgs.errors)
1734
1824
  }
@@ -1737,17 +1827,25 @@ export const runWith = <const Name extends string, Input, E, R>(
1737
1827
  return yield* showHelp(command, commandPath, [parseResult.failure])
1738
1828
  }
1739
1829
 
1740
- // 6. Compose setting flag layers
1741
- let contextLayer: Layer.Layer<never> = Layer.empty
1742
- for (const flag of flags) {
1830
+ // 7. Provide setting values
1831
+ let program = commandImpl.handle(parseResult.success, [command.name])
1832
+ for (const flag of activeFlags) {
1743
1833
  if (flag._tag !== "Setting") continue
1744
1834
  const [, value] = yield* flag.flag.parse(emptyArgs)
1745
- contextLayer = Layer.merge(contextLayer, flag.layer(value))
1835
+ program = Effect.provideService(program, flag, value)
1746
1836
  }
1747
1837
 
1748
- // 7. Run command handler with composed context
1749
- const program = commandImpl.handle(parseResult.success, [command.name])
1750
- yield* Effect.provide(program, contextLayer)
1838
+ const [, logLevel] = yield* GlobalFlag.LogLevel.flag.parse(emptyArgs)
1839
+ program = Effect.provideService(program, GlobalFlag.LogLevel, logLevel)
1840
+
1841
+ // 8. Apply built-in setting behavior
1842
+ const services = Option.match(logLevel, {
1843
+ onNone: () => ServiceMap.empty(),
1844
+ onSome: (level) => ServiceMap.make(References.MinimumLogLevel, level)
1845
+ })
1846
+
1847
+ // 9. Run command handler with composed context
1848
+ yield* Effect.provideServices(program, services)
1751
1849
  },
1752
1850
  Effect.catchIf(
1753
1851
  ((error: any) =>