This document captures the current project-specific guidance for AI agents working on DnZip.
DnZip is a .NET CLI tool for creating ZIP archives with optional encryption, recursive directory support, multiple input paths, and optional omission of directory entries.
The main project is src/DnZip/DnZip.csproj.
dotnet build src/DnZip/DnZip.csprojdotnet run --project src/DnZip/DnZip.csproj -- <archiveFilePath> <sourcePath> [sourcePath...] [options]Supported options map to DnZipCommand.Compress parameters:
-r,--recurse: include subdirectories recursively-e,--encrypt: encrypt the archive and prompt for a password-D,--no-dir-entries: do not create directory entries, similar tozip -D
Example:
dotnet run --project src/DnZip/DnZip.csproj -- output.zip ./data ./assets --recursePrefer formatting the solution, not only the main project:
dotnet format src/DnZip.slnxThere is an xUnit test project at src/DnZip.Tests/.
Always run test-related commands from src/DnZip.Tests/ so generated artifacts stay near the test project instead of creating TestResults/ at the repository root.
Run all tests:
cd src/DnZip.Tests
dotnet testRun coverage collection:
cd src/DnZip.Tests
dotnet test --collect:"XPlat Code Coverage" --results-directory ./TestResultsGenerate a coverage report if reportgenerator is available:
cd src/DnZip.Tests
reportgenerator -reports:"./TestResults/**/coverage.cobertura.xml" -targetdir:"./TestResults/CoverageReport" -reporttypes:"TextSummary;Html" -filefilters:"-*ConsoleAppFramework*"Run mutation tests if dotnet-stryker is available:
cd src/DnZip.Tests
dotnet stryker --break-at 80src/DnZip/Program.cs: composition root only; registers encoding and startsConsoleAppFrameworksrc/DnZip/DnZipCommand.cs: CLI command logic, validation, exit-code behavior, password confirmation, and source path resolutionsrc/DnZip/ArchiveSource.cs: resolved archive input with its final entry pathsrc/DnZip/ZipArchiveService.cs: ZIP archive creation and recursive entry writingsrc/DnZip/IPasswordPrompt.cs: abstraction for password inputsrc/DnZip/SharpromptPasswordPrompt.cs: production implementation usingSharpromptsrc/DnZip/IArchiveService.cs: abstraction for archive creation
Keep a strict one file, one class rule.
Examples:
src/DnZip.Tests/DnZipCommandTests.cssrc/DnZip.Tests/ZipArchiveServiceTests.cssrc/DnZip.Tests/FakePasswordPrompt.cssrc/DnZip.Tests/FakeArchiveService.cssrc/DnZip.Tests/TestWorkspace.cs
Do not re-introduce a single large test file that mixes unrelated test classes or helper classes.
Program is intentionally thin and should generally not need direct tests.
- Target framework:
.NET 10 - Indentation: 2 spaces, no tabs
- Prefer LF line endings
- Use Allman braces
- Use block-scoped namespaces
- Classes, interfaces, methods:
PascalCase - Parameters and locals:
camelCase - Private fields:
_camelCase
- Put
usingdirectives at the top of the file - Order groups as:
System.*, third-party namespaces, then project namespaces - Sort each group alphabetically when practical
- Prefer modern C# features when they improve clarity
- Use
varwhen the type is obvious from the right-hand side - Use
string.IsNullOrEmpty()for basic string validation
- Successful CLI execution should return
0 - Failures should return
1 - Expected user-facing failures should print a clear message instead of crashing silently
- Unexpected failures at the command layer should be surfaced to the console and converted to exit code
1
- ZIP creation uses
ICSharpCode.SharpZipLib - Use
Encoding.GetEncoding("Shift_JIS")for archive entry compatibility with Windows tools - Register code pages first with:
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);- Compression level is set to best compression via
zipStream.SetLevel(9) - Use
Path.GetRelativePathandZipEntry.CleanNamewhen building archive paths
- The entry point remains
ConsoleApp.RunAsync(args, command.Compress) - Command parameters become CLI arguments/options automatically
- Short option aliases are defined via XML doc comments on command parameters
- Production password input goes through
IPasswordPrompt SharpromptPasswordPromptis the concrete implementation and should callPrompt.Password(...)- For tests, prefer fake implementations over static hooks
- Preserve 2-space indentation.
- Keep remaining HACK comments until the corresponding feature is actually implemented.
- Keep
Programthin; prefer extracting behavior into classes with explicit dependencies. - If a dependency needs to be faked in tests, introduce an interface and inject it rather than adding static test hooks.
- Keep tests focused per class and per responsibility.
- Run verification after changes. For test-related work, prefer running commands from
src/DnZip.Tests/. - Do not run
git commitorgit pushunless the user explicitly asks. - If CLI syntax changes, update
README.mdas part of the same change.
- Code follows 2-space indentation
-
dotnet buildsucceeds - No new compiler warnings are introduced
- Exit codes remain correct (
0on success,1on failure) - Password prompting stays behind
IPasswordPrompt - Tests remain one-file-per-class