packages feed

ai-agent-diff-patch-0.0.1.0: app/AiAgentPatch.hs

{-# LANGUAGE OverloadedStrings #-}

-- | Boot layer: entry point for the ai-agent-patch executable.
-- Handles command-line argument parsing and error reporting only.
-- All file I/O, line-ending handling, and patch computation are delegated
-- to U.patch (AIAgent.DiffPatch.Unified).
module Main where

import System.IO
import System.Exit
import Options.Applicative
import qualified Data.ByteString as BS
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import Data.Text.Encoding.Error (lenientDecode)
import qualified AIAgent.DiffPatch.Unified as U
import Paths_ai_agent_diff_patch (version)
import Data.Version (showVersion)

-- | Command-line arguments for ai-agent-patch.
data ArgData = ArgData
  { _origFileArgData  :: FilePath
  , _patchFileArgData :: FilePath
  } deriving (Show)

-- | Read a file as UTF-8 String, independent of the system locale.
readFileUtf8 :: FilePath -> IO String
readFileUtf8 path = T.unpack . TE.decodeUtf8With lenientDecode <$> BS.readFile path

-- | Entry point.
main :: IO ()
main = do
  hSetBinaryMode stdout True
  hSetBinaryMode stderr True
  args <- execParser parseInfo
  patchText <- readFileUtf8 (_patchFileArgData args)
  result <- U.patch (_origFileArgData args) patchText
  case result of
    Right () -> return ()
    Left err -> do
      BS.hPutStr stderr (TE.encodeUtf8 (T.pack ("Patch failed: " ++ err ++ "\n")))
      exitFailure

-- | Version option: display version string and exit.
verOpt :: Parser (a -> a)
verOpt = infoOption msg $ mconcat
  [ short 'v'
  , long  "version"
  , help  "Show version"
  ]
  where
    msg = "ai-agent-patch-" ++ showVersion version

-- | Parser info with help text.
parseInfo :: ParserInfo ArgData
parseInfo = info (helper <*> verOpt <*> options) $ mconcat
  [ fullDesc
  , header   "ai-agent-patch - Apply a unified diff patch to a file"
  , progDesc "Read ORIGINAL-FILE and PATCH-FILE, output patched text to stdout."
  ]

-- | Positional argument parser.
options :: Parser ArgData
options = ArgData
  <$> strArgument (metavar "ORIGINAL-FILE" <> help "File to patch")
  <*> strArgument (metavar "PATCH-FILE"    <> help "Unified diff patch file")