never executed always true always false
1 module PureClaw.Channels.CLI
2 ( -- * CLI channel
3 mkCLIChannelHandle
4 ) where
5
6 import Data.Text qualified as T
7 import Data.Text.IO qualified as TIO
8 import System.Console.Haskeline qualified as HL
9 import System.Directory (createDirectoryIfMissing)
10 import System.IO (hFlush, stderr, stdout)
11
12 import PureClaw.CLI.Config (getPureclawDir)
13 import PureClaw.Core.Types
14 import PureClaw.Handles.Channel
15
16 -- | Create a channel handle that uses haskeline for line editing.
17 -- Provides readline-style input: backspace, arrow keys, up/down history,
18 -- Ctrl-A/E, etc. History is persisted to @~\/.pureclaw\/history@.
19 mkCLIChannelHandle :: IO ChannelHandle
20 mkCLIChannelHandle = do
21 histPath <- haskelineHistoryPath
22 let settings = HL.defaultSettings { HL.historyFile = Just histPath }
23 pure ChannelHandle
24 { _ch_receive = do
25 mLine <- HL.runInputT settings (HL.getInputLine "> ")
26 case mLine of
27 Nothing -> ioError (userError "EOF") -- Ctrl-D: agent loop catches this
28 Just line -> pure IncomingMessage
29 { _im_userId = UserId "cli-user"
30 , _im_content = T.pack line
31 }
32 , _ch_send = \msg -> do
33 TIO.putStrLn ""
34 TIO.putStrLn (_om_content msg)
35 TIO.putStrLn ""
36 , _ch_sendError = \err ->
37 TIO.hPutStrLn stderr $ "Error: " <> T.pack (show err)
38 , _ch_sendChunk = \case
39 ChunkText t -> do
40 TIO.putStr t
41 hFlush stdout
42 ChunkDone -> TIO.putStrLn ""
43 , _ch_streaming = True
44 , _ch_readSecret = do
45 mLine <- HL.runInputT settings (HL.getPassword Nothing "")
46 pure (maybe "" T.pack mLine)
47 , _ch_prompt = \promptText -> do
48 mLine <- HL.runInputT settings (HL.getInputLine (T.unpack promptText))
49 pure (maybe "" T.pack mLine)
50 , _ch_promptSecret = \promptText -> do
51 mLine <- HL.runInputT settings (HL.getPassword Nothing (T.unpack promptText))
52 pure (maybe "" T.pack mLine)
53 }
54
55 -- | Path to the haskeline history file: @~\/.pureclaw\/history@.
56 -- Creates the directory if it does not exist.
57 haskelineHistoryPath :: IO FilePath
58 haskelineHistoryPath = do
59 dir <- getPureclawDir
60 createDirectoryIfMissing True dir
61 pure (dir <> "/history")