TimeWarp.Cli 0.6.0-rc9

Prefix Reserved
This is a prerelease version of TimeWarp.Cli.
dotnet add package TimeWarp.Cli --version 0.6.0-rc9
                    
NuGet\Install-Package TimeWarp.Cli -Version 0.6.0-rc9
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="TimeWarp.Cli" Version="0.6.0-rc9" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="TimeWarp.Cli" Version="0.6.0-rc9" />
                    
Directory.Packages.props
<PackageReference Include="TimeWarp.Cli" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add TimeWarp.Cli --version 0.6.0-rc9
                    
#r "nuget: TimeWarp.Cli, 0.6.0-rc9"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package TimeWarp.Cli@0.6.0-rc9
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=TimeWarp.Cli&version=0.6.0-rc9&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=TimeWarp.Cli&version=0.6.0-rc9&prerelease
                    
Install as a Cake Tool

Stars workflow Forks License Issues Open OpenSSF Scorecard

nuget nuget

Twitter Dotnet

Discord Twitter Twitter

<img src="https://raw.githubusercontent.com/TimeWarpEngineering/timewarpengineering.github.io/refs/heads/master/images/LogoNoMarginNoShadow.svg" alt="logo" height="120" style="float: right" />

TimeWarp.Cli

TimeWarp.Cli is a powerful fluent API library for elegant command-line execution in C#. It transforms shell scripting into a type-safe, IntelliSense-friendly experience with a simple static Run() method, async operations, and proper error handling.

Designed for modern C# developers, TimeWarp.Cli brings the power of shell scripting directly into your C# code. Whether you're building automation tools, DevOps scripts, or integrating command-line tools into your applications, TimeWarp.Cli provides the elegant, type-safe API you need.

Why TimeWarp.Cli?

  • Zero Learning Curve: If you know C#, you already know how to use TimeWarp.Cli
  • IntelliSense Everything: Full IDE support with autocomplete, parameter hints, and documentation
  • Type Safety: Catch errors at compile-time, not runtime
  • No String Escaping Hell: Use C# arrays and parameters naturally
  • Built for .NET 10: Modern C# features and performance optimizations
  • Script or Library: Use it in quick scripts or production applications

Give a Star! ⭐

If you find this project useful, please give it a star. Thanks!

Quick Start

#!/usr/bin/dotnet run
#:package TimeWarp.Cli

using TimeWarp.Cli;

// Get command output as string
var date = await Run("date").GetStringAsync();
Console.WriteLine($"Current date: {date}");

// Process output line by line
var files = await Run("find", ".", "-name", "*.cs").GetLinesAsync();
foreach (var file in files)
{
    Console.WriteLine($"Found: {file}");
}

// Execute without capturing output
await Run("echo", "Hello World").ExecuteAsync();

// Chain commands with pipelines
var filteredFiles = await Run("find", ".", "-name", "*.cs")
    .Pipe("grep", "async")
    .GetLinesAsync();

// Use caching for expensive operations
var files = Run("find", "/large/dir", "-name", "*.log").Cached();
var errors = await files.Pipe("grep", "ERROR").GetLinesAsync();
var warnings = await files.Pipe("grep", "WARN").GetLinesAsync();
// Only one expensive find operation executed!

// C# scripts with arguments work seamlessly
await Run("./myscript.cs", "--verbose", "-o", "output.txt").ExecuteAsync();

// Use the new fluent builder API for complex commands
var result = await Shell.Run("git")
    .WithArguments("log", "--oneline", "-n", "10")
    .WithWorkingDirectory("/my/repo")
    .GetStringAsync();

// Provide standard input to commands
var grepResult = await Shell.Run("grep")
    .WithArguments("pattern")
    .WithStandardInput("line1\nline2 with pattern\nline3")
    .GetStringAsync();

// Use fluent command builders for .NET commands
var packages = await DotNet.ListPackages()
    .WithOutdated()
    .AsJson()
    .ToListAsync();

// Interactive file selection with Fzf
var selectedFile = await Fzf.Run()
    .FromInput("file1.txt", "file2.txt", "file3.txt")
    .WithPreview("cat {}")
    .GetStringAsync();

Installation

dotnet add package TimeWarp.Cli

Or reference in your C# script:

#:package TimeWarp.Cli

Check out the latest NuGet package: TimeWarp.Cli nuget

Key Features

  • Simple Static API: Global Run() method for immediate access
  • Fluent Interface: Chain operations naturally with .Pipe(), .Cached(), etc.
  • Async-First Design: All operations support modern async/await patterns
  • Smart Error Handling: Commands throw on errors by default, with opt-in graceful degradation
  • Pipeline Support: Chain commands with Unix-like pipe semantics
  • Standard Input Support: Provide stdin to commands with .WithStandardInput()
  • Opt-in Caching: Cache expensive command results with .Cached() method
  • Configuration Options: Working directory, environment variables, and more
  • Cancellation Support: Full CancellationToken support for timeouts and manual cancellation
  • Cross-Platform: Works on Windows, Linux, and macOS
  • C# Script Support: Seamless execution of C# scripts with proper argument handling
  • Command Builders: Fluent builders for complex commands (DotNet, Fzf, Ghq, Gwq)

Error Handling

TimeWarp.Cli provides intelligent error handling that distinguishes between different failure types:

Default Behavior (Throws Exceptions)

// Throws CommandExecutionException on non-zero exit code
await Run("ls", "/nonexistent").GetStringAsync();

// Throws exception if command not found
await Run("nonexistentcommand").GetStringAsync();

Graceful Degradation (Opt-in)

// Returns empty string/array on command failure
var options = new CommandOptions().WithValidation(CommandResultValidation.None);
var result = await Run("ls", "/nonexistent", options).GetStringAsync(); // ""

// Note: Process start failures (command not found) always throw
await Run("nonexistentcommand", options).GetStringAsync(); // Still throws!

Special Cases

  • Empty/whitespace commands return empty results (no exception)
  • Null command options return empty results (defensive programming)
  • Pipeline failures propagate based on validation settings

Testing and Mocking

TimeWarp.Cli provides built-in support for mocking commands during testing through the CliConfiguration class:

Basic Mocking

// Set up mock commands for testing
CliConfiguration.SetCommandPath("fzf", "/path/to/mock/fzf");
CliConfiguration.SetCommandPath("git", "/path/to/mock/git");

// Your code using these commands will now use the mocks
var selected = await Fzf.Run()
    .FromInput("option1", "option2", "option3")
    .GetStringAsync(); // Uses mock fzf

// Clean up after tests
CliConfiguration.Reset();

Creating Mock Executables

// Create a simple mock script
File.WriteAllText("/tmp/mock-fzf", "#!/bin/bash\necho 'mock-selection'");
Run("chmod", "+x", "/tmp/mock-fzf");

// Configure TimeWarp.Cli to use it
CliConfiguration.SetCommandPath("fzf", "/tmp/mock-fzf");

Testing Interactive Commands

For commands like fzf that are normally interactive, you can either:

  1. Use mock executables as shown above
  2. Use non-interactive modes (e.g., fzf --filter)

API Reference

  • CliConfiguration.SetCommandPath(command, path) - Set custom executable path
  • CliConfiguration.ClearCommandPath(command) - Remove custom path for a command
  • CliConfiguration.Reset() - Clear all custom paths
  • CliConfiguration.HasCustomPath(command) - Check if command has custom path
  • CliConfiguration.AllCommandPaths - Get all configured paths

Architecture

TimeWarp.Cli is built on several key architectural principles:

  • Static Entry Point: Minimal ceremony with global Run() method
  • Immutable Design: Thread-safe, readonly objects throughout
  • Integration Testing: Real command validation over mocking
  • Predictable Error Handling: Clear distinction between failure types
  • Opt-in Complexity: Advanced features available when needed

See our Architectural Decision Records for detailed design rationale.

Documentation

Example Scripts

See Spikes/CsScripts/ for example scripts demonstrating TimeWarp.Cli usage patterns.

Unlicense

License
This project is licensed under the Unlicense.

Contributing

Your contributions are welcome! Before starting any work, please open a discussion.

See our Kanban board for current development tasks and priorities.

Contact

If you have an issue and don't receive a timely response, feel free to reach out on our Discord server.

Discord

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.6.0-rc9 116 7/17/2025
0.6.0-rc8 116 7/17/2025
0.6.0-rc7 112 7/16/2025
0.6.0-rc6 118 7/15/2025
0.6.0-rc4 123 7/14/2025
0.6.0-rc3 116 7/14/2025
0.6.0-rc2 115 7/14/2025
0.6.0-rc12 73 7/18/2025
0.6.0-rc11 104 7/18/2025
0.6.0-rc10 114 7/17/2025
0.6.0-rc1 116 7/14/2025
0.6.0-beta9 69 7/11/2025
0.6.0-beta8 67 7/11/2025
0.6.0-beta7 72 7/11/2025
0.6.0-beta6 74 7/11/2025
0.6.0-beta5 79 7/11/2025
0.6.0-beta4 82 7/11/2025
0.6.0-beta3 122 7/10/2025
0.6.0-beta2 117 7/10/2025
0.6.0-beta12 90 7/12/2025
0.6.0-beta11 86 7/12/2025
0.6.0-beta10 46 7/12/2025