packages feed

clod 0.1.2 → 0.1.3

raw patch · 6 files changed

+86/−95 lines, 6 filesdep ~bytestringdep ~dhalldep ~directoryPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: bytestring, dhall, directory, filepath, hashable, text, transformers, unix

API changes (from Hackage documentation)

- Clod.AdvancedCapability: instance GHC.Show.Show (Clod.AdvancedCapability.TypedPath p)
- Clod.FileSystem.Checksums: instance GHC.Generics.Generic Clod.FileSystem.Checksums.FileStatus
- Clod.FileSystem.Checksums: instance GHC.Show.Show Clod.FileSystem.Checksums.FileStatus
- Clod.FileSystem.Detection: instance GHC.Show.Show Clod.FileSystem.Detection.TextPatterns
- Clod.FileSystem.Processing: instance GHC.Show.Show Clod.FileSystem.Processing.ManifestEntry
- Clod.IgnorePatterns: instance GHC.Generics.Generic Clod.IgnorePatterns.ClodIgnorePatterns
- Clod.IgnorePatterns: instance GHC.Show.Show Clod.IgnorePatterns.CharClassPattern
- Clod.IgnorePatterns: instance GHC.Show.Show Clod.IgnorePatterns.ClodIgnorePatterns
- Clod.IgnorePatterns: instance GHC.Show.Show Clod.IgnorePatterns.PatternType
- Clod.Types: instance Data.String.IsString Clod.Types.Checksum
- Clod.Types: instance Data.String.IsString Clod.Types.IgnorePattern
- Clod.Types: instance Data.String.IsString Clod.Types.OptimizedName
- Clod.Types: instance Data.String.IsString Clod.Types.OriginalPath
- Clod.Types: instance GHC.Base.Monoid Clod.Types.Checksum
- Clod.Types: instance GHC.Base.Monoid Clod.Types.IgnorePattern
- Clod.Types: instance GHC.Base.Monoid Clod.Types.OptimizedName
- Clod.Types: instance GHC.Base.Monoid Clod.Types.OriginalPath
- Clod.Types: instance GHC.Base.Semigroup Clod.Types.Checksum
- Clod.Types: instance GHC.Base.Semigroup Clod.Types.IgnorePattern
- Clod.Types: instance GHC.Base.Semigroup Clod.Types.OptimizedName
- Clod.Types: instance GHC.Base.Semigroup Clod.Types.OriginalPath
- Clod.Types: instance GHC.Generics.Generic Clod.Types.Checksum
- Clod.Types: instance GHC.Generics.Generic Clod.Types.ClodConfig
- Clod.Types: instance GHC.Generics.Generic Clod.Types.ClodDatabase
- Clod.Types: instance GHC.Generics.Generic Clod.Types.ClodError
- Clod.Types: instance GHC.Generics.Generic Clod.Types.FileEntry
- Clod.Types: instance GHC.Generics.Generic Clod.Types.FileResult
- Clod.Types: instance GHC.Generics.Generic Clod.Types.OptimizedName
- Clod.Types: instance GHC.Generics.Generic Clod.Types.OriginalPath
- Clod.Types: instance GHC.Generics.Generic Clod.Types.SerializableClodDatabase
- Clod.Types: instance GHC.Show.Show Clod.Types.Checksum
- Clod.Types: instance GHC.Show.Show Clod.Types.ClodConfig
- Clod.Types: instance GHC.Show.Show Clod.Types.ClodDatabase
- Clod.Types: instance GHC.Show.Show Clod.Types.ClodError
- Clod.Types: instance GHC.Show.Show Clod.Types.FileEntry
- Clod.Types: instance GHC.Show.Show Clod.Types.FileReadCap
- Clod.Types: instance GHC.Show.Show Clod.Types.FileResult
- Clod.Types: instance GHC.Show.Show Clod.Types.FileWriteCap
- Clod.Types: instance GHC.Show.Show Clod.Types.IgnorePattern
- Clod.Types: instance GHC.Show.Show Clod.Types.OptimizedName
- Clod.Types: instance GHC.Show.Show Clod.Types.OriginalPath
- Clod.Types: instance GHC.Show.Show Clod.Types.SerializableClodDatabase
+ Clod.AdvancedCapability: instance GHC.Internal.Show.Show (Clod.AdvancedCapability.TypedPath p)
+ Clod.FileSystem.Checksums: instance GHC.Internal.Generics.Generic Clod.FileSystem.Checksums.FileStatus
+ Clod.FileSystem.Checksums: instance GHC.Internal.Show.Show Clod.FileSystem.Checksums.FileStatus
+ Clod.FileSystem.Detection: instance GHC.Internal.Show.Show Clod.FileSystem.Detection.TextPatterns
+ Clod.FileSystem.Processing: instance GHC.Internal.Show.Show Clod.FileSystem.Processing.ManifestEntry
+ Clod.IgnorePatterns: instance GHC.Internal.Generics.Generic Clod.IgnorePatterns.ClodIgnorePatterns
+ Clod.IgnorePatterns: instance GHC.Internal.Show.Show Clod.IgnorePatterns.CharClassPattern
+ Clod.IgnorePatterns: instance GHC.Internal.Show.Show Clod.IgnorePatterns.ClodIgnorePatterns
+ Clod.IgnorePatterns: instance GHC.Internal.Show.Show Clod.IgnorePatterns.PatternType
+ Clod.Types: instance GHC.Internal.Base.Monoid Clod.Types.Checksum
+ Clod.Types: instance GHC.Internal.Base.Monoid Clod.Types.IgnorePattern
+ Clod.Types: instance GHC.Internal.Base.Monoid Clod.Types.OptimizedName
+ Clod.Types: instance GHC.Internal.Base.Monoid Clod.Types.OriginalPath
+ Clod.Types: instance GHC.Internal.Base.Semigroup Clod.Types.Checksum
+ Clod.Types: instance GHC.Internal.Base.Semigroup Clod.Types.IgnorePattern
+ Clod.Types: instance GHC.Internal.Base.Semigroup Clod.Types.OptimizedName
+ Clod.Types: instance GHC.Internal.Base.Semigroup Clod.Types.OriginalPath
+ Clod.Types: instance GHC.Internal.Data.String.IsString Clod.Types.Checksum
+ Clod.Types: instance GHC.Internal.Data.String.IsString Clod.Types.IgnorePattern
+ Clod.Types: instance GHC.Internal.Data.String.IsString Clod.Types.OptimizedName
+ Clod.Types: instance GHC.Internal.Data.String.IsString Clod.Types.OriginalPath
+ Clod.Types: instance GHC.Internal.Generics.Generic Clod.Types.Checksum
+ Clod.Types: instance GHC.Internal.Generics.Generic Clod.Types.ClodConfig
+ Clod.Types: instance GHC.Internal.Generics.Generic Clod.Types.ClodDatabase
+ Clod.Types: instance GHC.Internal.Generics.Generic Clod.Types.ClodError
+ Clod.Types: instance GHC.Internal.Generics.Generic Clod.Types.FileEntry
+ Clod.Types: instance GHC.Internal.Generics.Generic Clod.Types.FileResult
+ Clod.Types: instance GHC.Internal.Generics.Generic Clod.Types.OptimizedName
+ Clod.Types: instance GHC.Internal.Generics.Generic Clod.Types.OriginalPath
+ Clod.Types: instance GHC.Internal.Generics.Generic Clod.Types.SerializableClodDatabase
+ Clod.Types: instance GHC.Internal.Show.Show Clod.Types.Checksum
+ Clod.Types: instance GHC.Internal.Show.Show Clod.Types.ClodConfig
+ Clod.Types: instance GHC.Internal.Show.Show Clod.Types.ClodDatabase
+ Clod.Types: instance GHC.Internal.Show.Show Clod.Types.ClodError
+ Clod.Types: instance GHC.Internal.Show.Show Clod.Types.FileEntry
+ Clod.Types: instance GHC.Internal.Show.Show Clod.Types.FileReadCap
+ Clod.Types: instance GHC.Internal.Show.Show Clod.Types.FileResult
+ Clod.Types: instance GHC.Internal.Show.Show Clod.Types.FileWriteCap
+ Clod.Types: instance GHC.Internal.Show.Show Clod.Types.IgnorePattern
+ Clod.Types: instance GHC.Internal.Show.Show Clod.Types.OptimizedName
+ Clod.Types: instance GHC.Internal.Show.Show Clod.Types.OriginalPath
+ Clod.Types: instance GHC.Internal.Show.Show Clod.Types.SerializableClodDatabase
- Clod.AdvancedCapability: [TypedPath] :: FilePath -> TypedPath p
+ Clod.AdvancedCapability: [TypedPath] :: forall (p :: Permission). FilePath -> TypedPath p
- Clod.AdvancedCapability: class HasPermission cap (p :: Permission) | cap -> p
+ Clod.AdvancedCapability: class HasPermission (cap :: k) (p :: Permission) | cap -> p
- Clod.AdvancedCapability: createCapability :: forall p. [FilePath] -> Capability p
+ Clod.AdvancedCapability: createCapability :: forall (p :: Permission). [FilePath] -> Capability p
- Clod.AdvancedCapability: readFile :: forall p m. (MonadIO m, PermissionFor 'Read p) => Capability p -> TypedPath p -> m ByteString
+ Clod.AdvancedCapability: readFile :: forall (p :: Permission) m. (MonadIO m, PermissionFor 'Read p) => Capability p -> TypedPath p -> m ByteString
- Clod.AdvancedCapability: restrictCapability :: forall p p'. Capability p -> Capability p'
+ Clod.AdvancedCapability: restrictCapability :: forall (p :: Permission) (p' :: Permission). Capability p -> Capability p'
- Clod.AdvancedCapability: type PathWithPerm p = TypedPath p
+ Clod.AdvancedCapability: type PathWithPerm (p :: Permission) = TypedPath p
- Clod.AdvancedCapability: type family PermissionFor (required :: Permission) (provided :: Permission) :: Constraint
+ Clod.AdvancedCapability: type family PermissionFor (required :: Permission) (provided :: Permission)
- Clod.AdvancedCapability: unsafeAsPath :: FilePath -> TypedPath p
+ Clod.AdvancedCapability: unsafeAsPath :: forall (p :: Permission). FilePath -> TypedPath p
- Clod.AdvancedCapability: withPath :: forall p m a. MonadIO m => Capability p -> FilePath -> (Maybe (TypedPath p) -> m a) -> m a
+ Clod.AdvancedCapability: withPath :: forall (p :: Permission) m a. MonadIO m => Capability p -> FilePath -> (Maybe (TypedPath p) -> m a) -> m a
- Clod.AdvancedCapability: writeFile :: forall p m. (MonadIO m, PermissionFor 'Write p) => Capability p -> TypedPath p -> ByteString -> m ()
+ Clod.AdvancedCapability: writeFile :: forall (p :: Permission) m. (MonadIO m, PermissionFor 'Write p) => Capability p -> TypedPath p -> ByteString -> m ()
- Clod.Effects: type ClodM a = ReaderT ClodConfig (ExceptT ClodError IO) a
+ Clod.Effects: type ClodM a = ReaderT ClodConfig ExceptT ClodError IO a
- Clod.Types: type ClodM a = ReaderT ClodConfig (ExceptT ClodError IO) a
+ Clod.Types: type ClodM a = ReaderT ClodConfig ExceptT ClodError IO a

Files

clod.cabal view
@@ -1,6 +1,6 @@-cabal-version:       2.0+cabal-version:       2.4 name:                clod-version:             0.1.2+version:             0.1.3 synopsis:            Project file manager for Claude AI integrations description:         Clod (Claude Loader) is a utility for preparing and uploading files to Claude AI's                       Project Knowledge feature. It tracks file changes, respects .gitignore and .clodignore @@ -70,7 +70,31 @@   type:              git   location:          https://github.com/fuzz/clod +common deps+  build-depends:     +    base >= 4.7 && < 5,+    directory >= 1.3 && < 1.5,+    filepath >= 1.4 && < 1.6,+    process >= 1.6 && < 1.7,+    text >= 1.2 && < 2.2,+    bytestring >= 0.10 && < 0.13,+    containers >= 0.6 && < 0.7,+    time >= 1.9 && < 1.13,+    hashable >= 1.3 && < 1.6++common extensions+  default-extensions: +    OverloadedStrings+    TypeOperators+    FlexibleContexts+    GADTs+    DataKinds+    ScopedTypeVariables+    TypeApplications+    RecordWildCards+ library+  import:            deps, extensions   hs-source-dirs:    src   exposed-modules:        Clod.Core@@ -90,70 +114,36 @@   other-modules:     Paths_clod   autogen-modules:   Paths_clod   build-depends:     -    base >= 4.7 && < 5,-    directory >= 1.3 && < 1.4,-    filepath >= 1.4 && < 1.5,-    process >= 1.6 && < 1.7,-    text >= 1.2 && < 1.3,     aeson >= 2.0 && < 3.0,     aeson-pretty >= 0.8 && < 0.9,-    dhall >= 1.41 && < 1.43,-    bytestring >= 0.10 && < 0.12,-    containers >= 0.6 && < 0.7,-    time >= 1.9 && < 1.13,+    dhall >= 1.41 && < 1.44,     temporary >= 1.3 && < 1.4,     mtl >= 2.2 && < 2.4,-    transformers >= 0.5 && < 0.6,-    unix >= 2.7 && < 2.8,+    transformers >= 0.5 && < 0.7,+    unix >= 2.7 && < 2.9,     xxhash-ffi >= 0.3 && < 0.4,-    hashable >= 1.3 && < 1.5,     base16-bytestring >= 1.0 && < 1.1,     magic >= 1.1 && < 1.2,     prettyprinter >= 1.7 && < 1.8,     file-embed >= 0.0.15 && < 0.1   default-language:  Haskell2010-  default-extensions: -    OverloadedStrings-    TypeOperators-    FlexibleContexts-    GADTs-    DataKinds-    ScopedTypeVariables-    TypeApplications-    TemplateHaskell-    LambdaCase-    RecordWildCards+  default-extensions: TemplateHaskell+                      LambdaCase   ghc-options:       -Wall  executable clod+  import:            deps, extensions   hs-source-dirs:    app   main-is:           Main.hs   build-depends:     -    base >= 4.7 && < 5,     clod,-    directory >= 1.3 && < 1.4,-    filepath >= 1.4 && < 1.5,-    text >= 1.2 && < 1.3,     aeson >= 2.0 && < 3.0,-    bytestring >= 0.10 && < 0.12,-    containers >= 0.6 && < 0.7,-    time >= 1.9 && < 1.13,-    process >= 1.6 && < 1.7,-    hashable >= 1.3 && < 1.5,     optparse-applicative >= 0.16 && < 0.18   default-language:  Haskell2010-  default-extensions: -    OverloadedStrings-    TypeOperators-    FlexibleContexts-    GADTs-    DataKinds-    ScopedTypeVariables-    TypeApplications-    RecordWildCards   ghc-options:       -Wall -threaded -rtsopts -with-rtsopts=-N    test-suite clod-test+  import:            deps, extensions   type:              exitcode-stdio-1.0   hs-source-dirs:    test   main-is:           Spec.hs@@ -177,32 +167,15 @@     Clod.ManPagesSpec     Clod.TestHelpers   build-depends:     -    base >= 4.7 && < 5,     clod,-    directory >= 1.3 && < 1.4,-    filepath >= 1.4 && < 1.5,-    process >= 1.6 && < 1.7,     temporary >= 1.3 && < 1.4,-    text >= 1.2 && < 1.3,-    time >= 1.9 && < 1.13,+    unix >= 2.7 && < 2.9,+    optparse-applicative >= 0.16 && < 0.18,     hspec >= 2.8 && < 2.12,     QuickCheck >= 2.14 && < 2.16,-    unix >= 2.7 && < 2.8,-    bytestring >= 0.10 && < 0.12,-    containers >= 0.6 && < 0.7,-    optparse-applicative >= 0.16 && < 0.18,     random >= 1.2 && < 1.4,     mtl >= 2.2 && < 2.4   default-language:  Haskell2010-  default-extensions: -    OverloadedStrings-    TypeOperators-    FlexibleContexts-    GADTs-    DataKinds-    ScopedTypeVariables-    TypeApplications-    RecordWildCards   ghc-options:       -Wall -threaded -rtsopts -with-rtsopts=-N    executable magictest@@ -211,7 +184,7 @@   build-depends:          base >= 4.7 && < 5,     magic >= 1.1 && < 1.2,-    directory >= 1.3 && < 1.4+    directory >= 1.3 && < 1.5   default-language:  Haskell2010   default-extensions: OverloadedStrings   ghc-options:       -Wall -threaded -rtsopts -with-rtsopts=-N
src/Clod/FileSystem/Processing.hs view
@@ -334,10 +334,13 @@       -- Remove trailing slash if present       let cleanDir = if L.isSuffixOf "/" dir then init dir else dir       -- Apply hidden file transformation if needed-      in if not (null cleanDir) && head cleanDir == '.'-         then "dot--" ++ tail cleanDir+      in if not (null cleanDir) && cleanDir `startsWith` '.'+         then "dot--" ++ drop 1 cleanDir          else cleanDir-         +      where+        startsWith :: String -> Char -> Bool+        startsWith [] _ = False+        startsWith (x:_) c = x == c     -- Split a path into its directory components     splitPath :: FilePath -> [String]     splitPath path = filter (not . null) $ map getSegment $ L.groupBy sameGroup path
src/Clod/FileSystem/Transformations.hs view
@@ -51,6 +51,11 @@ -- transformFilename ".gitignore" -- returns "dot--gitignore" -- transformFilename "image.png" -- returns "image.png" (no change) -- @+-- | Helper function to check if a string starts with a character+startsWith :: String -> Char -> Bool+startsWith [] _ = False+startsWith (x:_) c = x == c+ transformFilename :: String -> String -> String transformFilename name original   -- SVG files must be transformed to XML for Claude compatibility@@ -59,9 +64,9 @@       let baseName = take (length name - 4) name       in sanitizeFilename $ baseName ++ "-svg.xml"   -- Handle hidden files (those starting with a dot)-  | not (null name) && head name == '.' =+  | not (null name) && name `startsWith` '.' =       -- Remove the leading dot and add the "dot--" prefix-      "dot--" ++ tail name+      "dot--" ++ drop 1 name   -- Handle empty filename   | null name = "unnamed"   -- Match test case explicitly to keep compatibility with tests
src/Clod/IgnorePatterns.hs view
@@ -482,6 +482,11 @@ -- simpleGlobMatch "file[0-9].txt" "file5.txt"  -- Returns True -- simpleGlobMatch "*.txt" "file.md"  -- Returns False -- @++-- | Helper function to check if a string starts with a character+startsWith :: String -> Char -> Bool+startsWith [] _ = False+startsWith (x:_) c = x == c simpleGlobMatch :: String -> FilePath -> Bool simpleGlobMatch ptn = \filepath -> matchGlob ptn filepath   where@@ -529,14 +534,14 @@       -- Beginning of character class: [       ((CharClassStart cs), (c:path')) ->         let (classSpec, rest) = span (/= ']') cs-            negated = not (null classSpec) && head classSpec == '!'-            actualClass = if negated then tail classSpec else classSpec+            negated = not (null classSpec) && classSpec `startsWith` '!'+            actualClass = if negated then drop 1 classSpec else classSpec         in if null rest  -- Malformed pattern, no closing ]            then False            else               let matches = matchCharacterClass actualClass c                  result = if negated then not matches else matches-             in result && matchGlob (tail rest) path'+             in result && matchGlob (drop 1 rest) path'                -- Regular character matching       ((p:ps), (c:cs)) ->
src/Clod/Types.hs view
@@ -74,7 +74,6 @@ import Control.Monad.Reader (ReaderT, ask, asks, local, runReaderT) import Data.String (IsString(..)) import GHC.Generics (Generic)-import Data.Typeable (Typeable) import Data.List (isPrefixOf) import System.Directory (canonicalizePath) import Data.Time.Clock (UTCTime)@@ -125,7 +124,6 @@   , lastMode       :: !Bool          -- ^ Whether to use the previous staging directory   , ignorePatterns :: ![IgnorePattern] -- ^ Patterns from .gitignore and .clodignore   } deriving stock (Show, Eq, Generic)-    deriving anyclass (Typeable)  -- | Result of processing a file -- @@ -135,7 +133,6 @@   = Success              -- ^ File was successfully processed   | Skipped !String      -- ^ File was skipped with the given reason   deriving stock (Show, Eq, Generic)-  deriving anyclass (Typeable)  -- | Errors that can occur during Clod operation --@@ -149,7 +146,6 @@   | DatabaseError !String              -- ^ Error related to checksums database   | ChecksumError !String              -- ^ Error related to checksum calculation   deriving stock (Show, Eq, Generic)-  deriving anyclass (Typeable)  -- | Newtype for file checksums to prevent mixing with other string types newtype Checksum = Checksum { unChecksum :: String }@@ -169,7 +165,7 @@   , entryLastModified :: !UTCTime        -- ^ Last modified time   , entryOptimizedName :: !OptimizedName -- ^ Name in staging directory   } deriving stock (Show, Eq, Generic)-    deriving anyclass (Typeable, FromDhall, ToDhall, FromJSON, ToJSON)+    deriving anyclass (FromDhall, ToDhall, FromJSON, ToJSON)  -- | Main database structure data ClodDatabase = ClodDatabase@@ -178,7 +174,6 @@   , dbLastStagingDir :: !(Maybe FilePath)          -- ^ Previous staging directory   , dbLastRunTime    :: !UTCTime                  -- ^ Time of last run   } deriving stock (Show, Eq, Generic)-    deriving anyclass (Typeable)  -- | Serialization-friendly version of ClodDatabase data SerializableClodDatabase = SerializableClodDatabase@@ -187,7 +182,7 @@   , serializedLastStagingDir :: !(Maybe FilePath)          -- ^ Previous staging directory   , serializedLastRunTime    :: !UTCTime                  -- ^ Time of last run   } deriving stock (Show, Eq, Generic)-    deriving anyclass (Typeable, FromDhall, ToDhall, FromJSON, ToJSON)+    deriving anyclass (FromDhall, ToDhall, FromJSON, ToJSON)  -- | Convert to serializable form toSerializable :: ClodDatabase -> SerializableClodDatabase
test/Clod/FileSystem/ChecksumsSpec.hs view
@@ -241,9 +241,11 @@           -- Should have one change (just the text file)           length changes `shouldBe` 1           -- The change should be for the text file only-          let (path, status) = head changes-          path `shouldBe` "text.txt"-          status `shouldBe` New+          case changes of+            (path, status):_ -> do+              path `shouldBe` "text.txt"+              status `shouldBe` New+            [] -> expectationFailure "Expected at least one change"           -- The binary file should not be present in the changes           any (("binary.bin" ==) . fst) changes `shouldBe` False   @@ -271,9 +273,11 @@           -- Should have one change           length changes `shouldBe` 1           -- The change should be a new file-          let (path, status) = head changes-          path `shouldBe` "new.txt"-          status `shouldBe` New+          case changes of+            (path, status):_ -> do+              path `shouldBe` "new.txt"+              status `shouldBe` New+            [] -> expectationFailure "Expected at least one change"      it "identifies modified files" $ do     withSystemTempDirectory "clod-test" $ \tmpDir -> do@@ -321,9 +325,11 @@           -- Should have one change           length changes `shouldBe` 1           -- The change should be a modified file-          let (path, status) = head changes-          path `shouldBe` "test.txt"-          status `shouldBe` Modified+          case changes of+            (path, status):_ -> do+              path `shouldBe` "test.txt"+              status `shouldBe` Modified+            [] -> expectationFailure "Expected at least one change"    it "identifies renamed files" $ do     withSystemTempDirectory "clod-test" $ \tmpDir -> do@@ -378,14 +384,18 @@           -- Should have one change           length changes `shouldBe` 1           -- The change should be a renamed file-          let (path, status) = head changes-          path `shouldBe` "renamed.txt"-          case status of-            Renamed oldPath -> oldPath `shouldBe` "original.txt"-            _ -> expectationFailure $ "Expected renamed status, got: " ++ show status+          case changes of+            (path, status):_ -> do+              path `shouldBe` "renamed.txt"+              case status of+                Renamed oldPath -> oldPath `shouldBe` "original.txt"+                _ -> expectationFailure $ "Expected renamed status, got: " ++ show status+            [] -> expectationFailure "Expected at least one change"                      -- Should include the renamed file in the renamed list           length renamed `shouldBe` 1-          let (newPath, oldPath) = head renamed-          newPath `shouldBe` "renamed.txt"-          oldPath `shouldBe` "original.txt"+          case renamed of+            (newPath, oldPath):_ -> do+              newPath `shouldBe` "renamed.txt"+              oldPath `shouldBe` "original.txt"+            [] -> expectationFailure "Expected at least one renamed file"