effectful-cli 0.1.0.1 → 0.1.0.2
raw patch · 13 files changed
+119/−27 lines, 13 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- CHANGELOG.md +9/−0
- README.md +0/−2
- effectful-cli.cabal +4/−2
- src/Data/CLI/Args.hs +24/−4
- src/Data/CLI/Class.hs +19/−1
- src/Data/CLI/Impl.hs +2/−1
- src/Data/Error/CLI.hs +12/−5
- src/Effectful/CLI.hs +4/−1
- src/Effectful/CLI/Conc.hs +33/−6
- src/Effectful/CLI/IO.hs +1/−0
- src/Effectful/CLI/Sleep.hs +1/−0
- src/Effectful/CLI/Time.hs +1/−0
- src/Effectful/Logger.hs +9/−5
+ CHANGELOG.md view
@@ -0,0 +1,9 @@+## [1.0.2](https://github.com/haskell-github-trust/effectful-cli/compare/1.0.1...1.0.2) (2026-10-26)++## [1.0.1](https://github.com/haskell-github-trust/effectful-cli/compare/1.0.0...1.0.1) (2026-10-25)++## 1.0.0 (2026-10-20)++### Features++* initial commit ([a158e16](https://github.com/haskell-github-trust/effectful-cli/commit/a158e160d175b2ca552b78c426c9c7f2263208e4))
README.md view
@@ -4,8 +4,6 @@ effect constraints, concurrency, prompts, sleep/time, optparse-applicative helpers and a [monad-logger](https://hackage.haskell.org/package/monad-logger) bridge (stderr or OpenTelemetry). -Port of the private `polysemy-cli` package to effectful.- ## Build ```sh
effectful-cli.cabal view
@@ -1,11 +1,11 @@-cabal-version: 1.12+cabal-version: 1.18 -- This file has been generated from package.yaml by hpack version 0.39.6. -- -- see: https://github.com/sol/hpack name: effectful-cli-version: 0.1.0.1+version: 0.1.0.2 synopsis: CLI helpers for the effectful ecosystem description: Please see the README at https://github.com/haskell-github-trust/effectful-cli category: CLI@@ -17,6 +17,8 @@ build-type: Simple extra-source-files: README.md+extra-doc-files:+ CHANGELOG.md library exposed-modules:
src/Data/CLI/Args.hs view
@@ -1,3 +1,4 @@+-- | Global command-line options shared by all commands. module Data.CLI.Args ( CLIArgs (..), getLogLevel,@@ -11,21 +12,36 @@ import Data.Maybe (fromMaybe) import Options.Applicative --- | @since 0.1.0.0+-- | Parsed global options, with the command of type @c@.+--+-- @since 0.1.0.0 data CLIArgs c = CLIArgs { _logLevel :: Maybe LogLevel+ -- ^ @-l@/@--log-level@ , _debug :: Bool+ -- ^ @-d@/@--debug@ , _autoAccept :: Bool+ -- ^ @-y@/@--yes@ , _autoDecline :: Bool+ -- ^ @-n@/@--no@ , _config :: Maybe FilePath+ -- ^ @-c@/@--config@ , _command :: Either () c+ -- ^ 'Left' for @-v@/@--version@, otherwise the parsed command } logLevels :: [(String, LogLevel)] logLevels =- [("debug", LevelDebug), ("info", LevelInfo), ("warn", LevelWarn), ("error", LevelError)]+ [ ("debug", LevelDebug)+ , ("info", LevelInfo)+ , ("warn", LevelWarn)+ , ("error", LevelError)+ ] --- | Effective log level: @--log-level@ if given, else debug with @--debug@, else info.+-- | Effective log level:+-- * @--log-level@ if given+-- * debug with @--debug@+-- * info otherwise -- -- @since 0.1.0.0 getLogLevel :: CLIArgs c -> LogLevel@@ -40,7 +56,11 @@ -- | Print the version if @--version@ was passed, otherwise run the parsed command. -- -- @since 0.1.0.0-versionOrCommand :: String -> CLIArgs c -> (c -> IO ()) -> IO ()+versionOrCommand+ :: String+ -> CLIArgs c+ -> (c -> IO ())+ -> IO () versionOrCommand v a run = either (const (showVersion v)) run (_command a) -- | Parser for the common CLI options, wrapping the given command parser.
src/Data/CLI/Class.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE FunctionalDependencies #-} +-- | Classes implemented by application configs and commands. module Data.CLI.Class ( CLIConfig (..), Command (..),@@ -9,11 +10,28 @@ import Effectful.CLI (CLIEffects) import Options.Applicative (Parser) +-- | Application config exposing the prompt auto-answer flags.+--+-- @since 0.1.0.0 class CLIConfig a where- autoAccept, autoDecline :: a -> Bool+ -- | Answer yes to all confirmation prompts.+ autoAccept :: a -> Bool + -- | Answer no to all confirmation prompts; takes precedence over 'autoAccept'.+ autoDecline :: a -> Bool++-- | A subcommand @a@ running with config @c@ and application error @e@.+--+-- @since 0.1.0.0 class Command c e a | a -> c e where+ -- | Subcommand name on the command line. cmdname :: a -> String++ -- | One-line description shown in @--help@. doc :: a -> String++ -- | Parser for the subcommand's arguments. parser :: a -> Parser a++ -- | Execute the subcommand. runner :: CLIEffects c e es => a -> Eff es ()
src/Data/CLI/Impl.hs view
@@ -1,3 +1,4 @@+-- | Helpers for building optparse-applicative parsers and subcommands. module Data.CLI.Impl ( unboundEnumError, fromParsec,@@ -88,7 +89,7 @@ :: Bounded a => Command c e a => Command c e b => Enum a => (a -> b) -> Mod CommandFields b mkCommands f = foldMap (mkCommand . f) (sortOn cmdname [minBound ..]) --- | Top-level 'ParserInfo' with @--help@ and a header showing name, description and version.+-- | Top-level t'ParserInfo' with @--help@ and a header showing name, description and version. -- -- @since 0.1.0.0 usage :: String -> String -> String -> Parser a -> ParserInfo a
src/Data/Error/CLI.hs view
@@ -1,14 +1,21 @@+-- | Errors common to CLI applications. module Data.Error.CLI ( CLIError (..), displayCLIError, ) where --- | @since 0.1.0.0+-- | Errors raised by CLI helpers.+--+-- @since 0.1.0.0 data CLIError- = InputError String- | NotFoundError String- | NotImplemented String- | UserCanceled (Maybe String)+ = -- | Invalid user input.+ InputError String+ | -- | Requested item does not exist.+ NotFoundError String+ | -- | Feature not implemented yet.+ NotImplemented String+ | -- | User declined a confirmation, with an optional reason.+ UserCanceled (Maybe String) deriving (Eq, Show) -- | Render a 'CLIError' as a human-readable message.
src/Effectful/CLI.hs view
@@ -1,3 +1,4 @@+-- | Effect stack available to command runners. module Effectful.CLI ( CLIEffects, ) where@@ -9,7 +10,9 @@ import Effectful.Logger (Logger) import Effectful.Reader.Static (Reader) --- | @since 0.1.0.0+-- | Effects available to a command runner, with config @c@ and application error @e@.+--+-- @since 0.1.0.0 type CLIEffects c e es = ( IOE :> es , Reader c :> es
src/Effectful/CLI/Conc.hs view
@@ -1,3 +1,4 @@+-- | Concurrency helpers built on "Effectful.Concurrent.Async". module Effectful.CLI.Conc ( concurrently, concurrently_,@@ -29,37 +30,63 @@ -- | Run all actions concurrently and collect their results. -- -- @since 0.1.0.0-runConcurrently :: Concurrent :> es => Traversable t => t (Eff es a) -> Eff es (t a)+runConcurrently+ :: Concurrent :> es+ => Traversable t+ => t (Eff es a)+ -> Eff es (t a) runConcurrently = mapConcurrently id -- | Run all actions concurrently, discarding results. -- -- @since 0.1.0.0-runConcurrently_ :: Concurrent :> es => Foldable t => t (Eff es a) -> Eff es ()+runConcurrently_+ :: Concurrent :> es+ => Foldable t+ => t (Eff es a)+ -> Eff es () runConcurrently_ = mapConcurrently_ id -- | Map over a list with at most @n@ concurrent actions. -- -- @since 0.1.0.0-batchConcurrently :: Concurrent :> es => Int -> (a -> Eff es b) -> [a] -> Eff es [b]+batchConcurrently+ :: Concurrent :> es+ => Int+ -> (a -> Eff es b)+ -> [a]+ -> Eff es [b] batchConcurrently = pooledMapConcurrentlyN -- | Like 'batchConcurrently', discarding results. -- -- @since 0.1.0.0-batchConcurrently_ :: Concurrent :> es => Int -> (a -> Eff es b) -> [a] -> Eff es ()+batchConcurrently_+ :: Concurrent :> es+ => Int+ -> (a -> Eff es b)+ -> [a]+ -> Eff es () batchConcurrently_ = pooledMapConcurrentlyN_ -- | Like 'batchConcurrently', also passing each element's 1-based index. -- -- @since 0.1.0.0 batchConcurrentlyWithIndex- :: Concurrent :> es => Int -> (Int -> a -> Eff es b) -> [a] -> Eff es [b]+ :: Concurrent :> es+ => Int+ -> (Int -> a -> Eff es b)+ -> [a]+ -> Eff es [b] batchConcurrentlyWithIndex n f = batchConcurrently n (uncurry f) . zip [1 ..] -- | Like 'batchConcurrentlyWithIndex', discarding results. -- -- @since 0.1.0.0 batchConcurrentlyWithIndex_- :: Concurrent :> es => Int -> (Int -> a -> Eff es b) -> [a] -> Eff es ()+ :: Concurrent :> es+ => Int+ -> (Int -> a -> Eff es b)+ -> [a]+ -> Eff es () batchConcurrentlyWithIndex_ n f = batchConcurrently_ n (uncurry f) . zip [1 ..]
src/Effectful/CLI/IO.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE AllowAmbiguousTypes #-} +-- | Terminal output, prompts and confirmations. module Effectful.CLI.IO ( printOutput, printOutputLn,
src/Effectful/CLI/Sleep.hs view
@@ -1,3 +1,4 @@+-- | Logged sleeping helpers. module Effectful.CLI.Sleep ( msleep, sleep,
src/Effectful/CLI/Time.hs view
@@ -1,3 +1,4 @@+-- | Current time helpers, in 'IO' and 'Eff'. module Effectful.CLI.Time ( getLocalTimeIO, getBeginningOfDayIO,
src/Effectful/Logger.hs view
@@ -34,29 +34,33 @@ import OpenTelemetry.Log.Core qualified as OTel import System.IO (stderr) --- | @since 0.1.0.0+-- | monad-logger style log callback.+--+-- @since 0.1.0.0 type LogFunc = Loc -> LogSource -> LogLevel -> LogStr -> IO () --- | @since 0.1.0.0+-- | Static effect providing a 'LogFunc'.+--+-- @since 0.1.0.0 data Logger :: Effect type instance DispatchOf Logger = Static WithSideEffects newtype instance StaticRep Logger = Logger LogFunc --- | Run the 'Logger' effect with the given log callback.+-- | Run the t'Logger' effect with the given log callback. -- -- @since 0.1.0.0 runLogger :: IOE :> es => LogFunc -> Eff (Logger : es) a -> Eff es a runLogger = evalStaticRep . Logger --- | Run the 'Logger' effect, writing to stderr.+-- | Run the t'Logger' effect, writing to stderr. -- -- @since 0.1.0.0 runStderrLogger :: IOE :> es => Eff (Logger : es) a -> Eff es a runStderrLogger = runLogger (defaultOutput stderr) --- | Run the 'Logger' effect, emitting OpenTelemetry log records.+-- | Run the t'Logger' effect, emitting OpenTelemetry log records. -- -- @since 0.1.0.0 runOTelLogger :: IOE :> es => OTel.Logger -> Eff (Logger : es) a -> Eff es a