--- title: TimeWarp Software tagline: Time to Build description: A showcase of TimeWarp Engineering's NuGet libraries and open source projects. --- A showcase of [TimeWarp Engineering](https://github.com/TimeWarpEngineering)'s NuGet libraries and open source projects. This site is **agent-first**: every page is generated from canonical markdown, and that markdown is served directly to AI agents. This page is available as [markdown](/index.md) — no HTML parsing required. [Browse the packages](/packages/) — every TimeWarp NuGet has a landing page, generated straight from the NuGet catalog — or pick up an [Agent Skill](/skills/) for your AI coding agent. Manage skills with [TimeWarp.Skills](/packages/timewarp.skills/) (`dnx TimeWarp.Skills`). Agents: start at [/llms.txt](/llms.txt) or grab the whole site as [/llms-full.txt](/llms-full.txt). Optional support: the [tip jar](/tip/) (content stays free; payment only at `/api/tip` when tips are enabled). --- --- title: Tip jar tagline: Voluntary support description: Free docs for the optional tip jar. Site content stays free; x402 payment only at /api/tip. Agents can pay Base USDC, Lightning sats, or Cardano ADA; humans can also pay Lightning to tip@timewarp.software. --- All catalog, skill, project, and discovery content on timewarp.software is **free**. We never require payment to crawl, train on, or use these materials. If an agent (or human) found them useful, they may optionally tip. Tips are voluntary; they are not a fee for content access. Two rails, one Hub wallet: 1. **Lightning Address** for humans (`tip@timewarp.software`). 2. **x402** on `/api/tip` for agents — Base USDC, Lightning sats, **and** Cardano ADA (three accepts on one resource). ## What never requires payment These surfaces stay free and must **never** return HTTP 402 from tip middleware: - This page (`/tip/`, [markdown twin](/tip/index.md)) - Homepage, packages, skills, projects - `/llms.txt`, `/llms-full.txt`, package and skills JSON indexes - `/.well-known/*` discovery files **including** LNURL-pay (`/.well-known/lnurlp/tip`) - Every page’s markdown twin (`…/index.md`) ## Lightning Address (humans) | Item | Value | |------|--------| | Address | **`tip@timewarp.software`** | | LNURL-pay | `GET /.well-known/lnurlp/tip` (LUD-06 / LUD-16) | | Callback | `GET /lnurlp/tip/callback?amount=` | | Wallet | Any LNURL-pay wallet (Wallet of Satoshi, Alby, …) | The well-known LNURL endpoint is a mailbox, not a paywall: it never returns HTTP 402. Amounts are chosen in the wallet within the advertised min/max. ## x402 `/api/tip` (agents) | Item | Value | |------|--------| | Endpoint | `GET` or `POST` **`/api/tip`** (trailing slash accepted; `/api` is a discovery alias) | | USDC | **`$0.10`** `exact` on Base mainnet `eip155:8453`, USDC `0x833589fCD6eDb6E08f4c7c32D4f71b54bdA02913`, Coinbase CDP facilitator | | Lightning | **`1000 sats`** `exact` on Bitcoin `bip122:000000000019d6689c085ae165831e93` (CAIP-2). The 402 `accepts` entry has `extra.paymentMethod = "lightning"` and a BOLT11 in `extra.invoice` | | Cardano | **`1 ADA`** (`1000000` lovelace) `exact` on `cardano:mainnet`, paid to a TimeWarp `addr1…` address, verified and broadcast by the [cardano402.com](https://cardano402.com/) facilitator | | Protocol | [x402](https://x402.org/) — HTTP 402 + payment headers | USDC is **not** replaced. Lightning and Cardano are extra accepts on the same resource. Testnet (Base Sepolia `eip155:84532`) is used only in local development for the USDC rail. Lightning x402 follows the [Alby facilitator](https://github.com/getAlby/x402-facilitator) flow (not Coinbase CDP): 1. `GET /api/tip` → 402. Decode `PAYMENT-REQUIRED`. Use the accept whose `extra.paymentMethod` is `"lightning"`. Pay `extra.invoice` with any Lightning wallet. 2. Retry the same URL with `payment-signature` = base64(`{ x402Version: 2, scheme, network, payload: { invoice }, accepted }`). 3. The worker verifies via receive-only NWC `lookup_invoice` (Hub stays off the public net). If the Hub is down, the USDC accept still 402s; Lightning invoices may be omitted until the Hub is back. Cardano x402 uses the official [`@x402/cardano`](https://developers.cardano.org/x402/) `exact` scheme (address payment; no Masumi escrow). Your Cardano x402 client signs a transaction that pays `payTo`; the facilitator verifies it and submits it on chain. It is non-custodial and never holds TimeWarp keys. - **Facilitator caveat:** [cardano402.com](https://cardano402.com/) is an independent operator ([MorganOnCode/cardano402](https://github.com/MorganOnCode/cardano402)), not Coinbase and not the Cardano Foundation. When it is unreachable (or not listing `cardano:mainnet`), the ADA accept is **omitted** from the 402 and the USDC and Lightning accepts keep working. - **Why 1 ADA:** an ADA-only output must carry the ledger minimum (about 1 ADA), so a ~$0.10-sized ADA tip cannot exist on chain. You also pay the normal Cardano network fee. - `lovelace` is not USD-pegged: x402 Cardano clients usually need `spendControls.allowedAssets` to include `lovelace` before they will pay. ### Responses on `/api/tip` only | Condition | Status | |-----------|--------| | Tips disabled or misconfigured | **503** (never 402) | | Tips enabled, no payment | **402** + `PAYMENT-REQUIRED` | | Payment verified and settled | **200** thank-you + `PAYMENT-RESPONSE` | The 200 JSON (or markdown) `amount` and `network` match the rail that settled: USDC `$0.10` on Base (`eip155:8453`), `1000 sats` (or `TIP_LIGHTNING_SATS`) on Bitcoin Lightning (`bip122:000000000019d6689c085ae165831e93`), or `1 ADA` on `cardano:mainnet`. Payment **never** applies to free documentation, catalog routes, or LNURL-pay. ## For agents 1. Read this page or `/llms.txt` (Docs lists free tip docs; Optional lists the tip action URL). 2. Call `/api/tip` with an x402-capable client. Buyer quickstart: [docs.x402.org](https://docs.x402.org/getting-started/quickstart-for-buyers). Lightning-capable clients pay the BOLT11 in `extra.invoice` then retry with `payload.invoice`. Cardano clients pick the `cardano:mainnet` accept (`asset: "lovelace"`). 3. On success, expect JSON (or markdown if you send `Accept: text/markdown`) saying thank you, with `amount` and `network` matching the rail you paid. Tips do not unlock content. Free routes stay free under this design. --- --- title: TimeWarp.State description: State management for .NET. Blazor components, JavaScript interop, and render subscriptions are in TimeWarp.State.Blazor. type: package latest: 12.0.0-beta.13 stable: 11.0.3 repository: https://github.com/TimeWarpEngineering/timewarp-state --- State management for .NET. Blazor components, JavaScript interop, and render subscriptions are in TimeWarp.State.Blazor. | | | |---|---| | Latest stable | `11.0.3` | | Latest prerelease | `12.0.0-beta.13` | | Downloads | 33,499 | | Last published | 2026-10-13 | | Target frameworks | `net11.0` | ## Install ```sh dotnet add package TimeWarp.State dotnet add package TimeWarp.State --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.State) · [Source](https://github.com/TimeWarpEngineering/timewarp-state) · Part of the [timewarp-state](/projects/timewarp-state/) family --- [![Stars](https://img.shields.io/github/stars/TimeWarpEngineering/timewarp-state?logo=github)](https://github.com/TimeWarpEngineering/timewarp-state) [![workflow](https://github.com/TimeWarpEngineering/timewarp-state/actions/workflows/workflow.yml/badge.svg)](https://github.com/TimeWarpEngineering/timewarp-state/actions) [![Forks](https://img.shields.io/github/forks/TimeWarpEngineering/timewarp-state)](https://github.com/TimeWarpEngineering/timewarp-state) [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-state.svg?style=flat-square&logo=github)](https://github.com/TimeWarpEngineering/timewarp-state/issues) [![Issues Open](https://img.shields.io/github/issues/TimeWarpEngineering/timewarp-state.svg?logo=github)](https://github.com/TimeWarpEngineering/timewarp-state/issues) [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/TimeWarpEngineering/timewarp-state/badge)](https://scorecard.dev/viewer/?uri=github.com/TimeWarpEngineering/timewarp-state) [![nuget](https://img.shields.io/nuget/v/TimeWarp.State?logo=nuget)](https://www.nuget.org/packages/TimeWarp.State/) [![nuget](https://img.shields.io/nuget/dt/TimeWarp.State?logo=nuget)](https://www.nuget.org/packages/TimeWarp.State/) [![Twitter](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2FTimeWarpEngineering%2Ftimewarp-state)](https://twitter.com/intent/tweet?url=https://github.com/TimeWarpEngineering/timewarp-state) [![Dotnet](https://img.shields.io/badge/dotnet-11.0-blue)](https://dotnet.microsoft.com) [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) [![Twitter](https://img.shields.io/twitter/follow/StevenTCramer.svg)](https://twitter.com/intent/follow?screen_name=StevenTCramer) [![Twitter](https://img.shields.io/twitter/follow/TheFreezeTeam1.svg)](https://twitter.com/intent/follow?screen_name=TheFreezeTeam1) logo # TimeWarp.State **TimeWarp.State** (previously known as Blazor-State) is a fully asynchronous state management library. The core package has no Blazor dependency, so console and other non-UI hosts can dispatch actions through the same store. Blazor components, JavaScript interop, and render subscriptions are in **TimeWarp.State.Blazor**. It handles both Reducers and Effects consistently using async Handlers. By utilizing the TimeWarp.Mediator pipeline, TimeWarp.State enables a flexible, middleware-driven architecture for managing state, similar to the request-processing pipeline in ASP.NET. This approach allows developers to inject custom behaviors, such as logging, validation, and caching, directly into the state management flow. Hosts consume **TimeWarp.Mediator 14-beta** via generated `AddGeneratedMediator()` / named pipelines — not MediatR and not reflection `AddMediator()`. In addition to the core library, we offer **[TimeWarp.State.Blazor](/source/timewarp-state-blazor)** (components, JavaScript interop, render subscriptions), **[TimeWarp.State.Plus](/source/timewarp-state-plus)** (routing, persistence, action tracking; depends on TimeWarp.State.Blazor; package id unchanged), and **[TimeWarp.State.Telemetry](/source/timewarp-state-telemetry)** (OpenTelemetry action spans for the Aspire dashboard or any OTel backend). **[TimeWarp.State DevTools](/documentation/topics/devtools.md)** is a dev-only Blazor inspector (`AddTimeWarpStateDevTools()`) on top of those spans. It is the action log, state tree, and diff. It is not a production dependency. The [console sample](samples/07-console/overview.md) dispatches an action without Blazor. The [persistence sample](samples/05-persistence/readme.md) shows session storage and local storage with `[PersistentState]`. The [render control sample](samples/06-render-control/readme.md) shows `ShouldRender`, parameter checks, and `RegisterRenderTrigger`. The [telemetry sample](samples/04-telemetry/overview.md) wires the DevTools app into Aspire. ## Give a Star! :star: If you find this project useful, please give it a star. Thanks! ## Getting Started I recommend the [state and action handler sample](samples/00-state-action-handler) for a step-by-step guide to building a Blazor app with TimeWarp.State. The published docs are at [timewarpengineering.github.io/timewarp-state](https://timewarpengineering.github.io/timewarp-state/). See full [documentation](https://timewarpengineering.github.io/timewarp-state/). logo ## Installation ```console dotnet add package TimeWarp.State dotnet add package TimeWarp.State.Blazor dotnet add package TimeWarp.State.Plus dotnet add package TimeWarp.State.Telemetry ``` Blazor hosts call `AddTimeWarpState` and `AddTimeWarpStateBlazor`. Console hosts call `AddTimeWarpState` only. See [Migrate to 12.0.0-beta.10](documentation/migrations/migration12.0.0-beta.10.md). Check out the latest NuGet packages on the [TimeWarp Enterprises NuGet page](https://www.nuget.org/profiles/TimeWarp.Enterprises). * [TimeWarp.State](https://www.nuget.org/packages/TimeWarp.State/) [![nuget](https://img.shields.io/nuget/v/TimeWarp.State?logo=nuget)](https://www.nuget.org/packages/TimeWarp.State/) * [TimeWarp.State.Blazor](https://www.nuget.org/packages/TimeWarp.State.Blazor/) [![nuget](https://img.shields.io/nuget/v/TimeWarp.State.Blazor?logo=nuget)](https://www.nuget.org/packages/TimeWarp.State.Blazor/) * [TimeWarp.State.Plus](https://www.nuget.org/packages/TimeWarp.State.Plus/) [![nuget](https://img.shields.io/nuget/v/TimeWarp.State.Plus?logo=nuget)](https://www.nuget.org/packages/TimeWarp.State.Plus/) * [TimeWarp.State.Telemetry](https://www.nuget.org/packages/TimeWarp.State.Telemetry/) [![nuget](https://img.shields.io/nuget/v/TimeWarp.State.Telemetry?logo=nuget)](https://www.nuget.org/packages/TimeWarp.State.Telemetry/) ## JavaScript dispatch JavaScript can dispatch actions with `timeWarpState.DispatchRequest(name, request)`. It is opt-in: allow each action explicitly, everything else is rejected. ```csharp builder.Services.AddJavaScriptDispatch(b => b.Allow()); ``` See [Enable JavaScript interop](documentation/topics/enable-javascript-interop.md). ## Action catalog Mark user-facing actions with `[CatalogAction]` to enumerate and execute them at runtime, for example from a Ctrl-K command palette or as agent tools: ```csharp public static class AddPasskeyActionSet { [CatalogAction(Description = "Add a passkey to the signed-in account.", Permissions = ["credentials.write"])] public sealed class Action : IAction { public Action(string label) { Label = label; } public string Label { get; } } } ``` ```csharp builder.Services.AddActionCatalog(typeof(AssemblyMarker).Assembly); ActionCatalogEntry entry = actionCatalog.Find("Credentials.AddPasskey")!; await entry.Execute(store, ["Laptop"]); ``` The source generator emits a per-assembly registry with name, description, permissions, visibility, parameters and input schema, plus a reflection-free `Execute`. It is opt-in: unmarked actions are never cataloged. Permissions are opaque ids that the consumer enforces; `[TrackAction]` (busy indicator) is unrelated. See [Action catalog](documentation/topics/action-catalog.md). ## Releases View the [Release Notes](https://timewarpengineering.github.io/timewarp-state/ReleaseNotes/Release11.0.0.html) for detailed information on each release. ## Unlicense [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-state.svg?style=flat-square&logo=github)](https://unlicense.org) This project is licensed under the [Unlicense](https://unlicense.org). ## Contributing Your contributions are welcome! Before starting any work, please open a [discussion](https://github.com/TimeWarpEngineering/timewarp-state/discussions). Help with the [documentation](https://timewarpengineering.github.io/timewarp-state/) is also greatly appreciated. ## Contact If you have an issue and don't receive a timely response, feel free to reach out on our [Discord server](https://discord.gg/A55JARGKKP). [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) --- --- title: timewarp-simple-icons description: All of the simple-icons wrapped as Blazor components. type: package latest: 16.35.0 stable: 16.35.0 repository: https://github.com/TimeWarpEngineering/timewarp-simple-icons --- All of the simple-icons wrapped as Blazor components. | | | |---|---| | Latest stable | `16.35.0` | | Downloads | 28,810 | | Last published | 2026-10-11 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package timewarp-simple-icons ``` [NuGet](https://www.nuget.org/packages/timewarp-simple-icons) · [Source](https://github.com/TimeWarpEngineering/timewarp-simple-icons) --- [![Dotnet](https://img.shields.io/badge/dotnet-10.0-blue)](https://dotnet.microsoft.com) [![Stars](https://img.shields.io/github/stars/TimeWarpEngineering/timewarp-simple-icons?logo=github)](https://github.com/TimeWarpEngineering/timewarp-simple-icons) [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) [![nuget](https://img.shields.io/nuget/v/timewarp-simple-icons?logo=nuget)](https://www.nuget.org/packages/timewarp-simple-icons/) [![nuget](https://img.shields.io/nuget/dt/timewarp-simple-icons?logo=nuget)](https://www.nuget.org/packages/timewarp-simple-icons/) [![Issues Open](https://img.shields.io/github/issues/TimeWarpEngineering/timewarp-simple-icons?logo=github)](https://github.com/TimeWarpEngineering/timewarp-simple-icons/issues) [![Forks](https://img.shields.io/github/forks/TimeWarpEngineering/timewarp-simple-icons)](https://github.com/TimeWarpEngineering/timewarp-simple-icons) [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-simple-icons?logo=github)](https://unlicense.org) [![Twitter](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2FTimeWarpEngineering%2Ftimewarp-simple-icons)](https://twitter.com/intent/tweet?url=https://github.com/TimeWarpEngineering/timewarp-simple-icons) [![Twitter](https://img.shields.io/twitter/follow/StevenTCramer.svg)](https://twitter.com/intent/follow?screen_name=StevenTCramer) [![Twitter](https://img.shields.io/twitter/follow/TheFreezeTeam1.svg)](https://twitter.com/intent/follow?screen_name=TheFreezeTeam1) # timewarp-simple-icons ![TimeWarp Logo](assets/logo.png) All [simple-icons](https://github.com/simple-icons/simple-icons) wrapped as Blazor components. See and search all at https://simpleicons.org/ ## Give a Star! :star: If you like or are using this project please give it a star. Thank you! ## Usage ```razor ``` Outputs ![](assets/20220731140539.png) ## Installation You can see the latest NuGet packages from the official [TimeWarp NuGet page](https://www.nuget.org/profiles/TimeWarp.Enterprises). * [timewarp-simple-icons](https://www.nuget.org/packages/timewarp-simple-icons/) [![nuget](https://img.shields.io/nuget/v/timewarp-simple-icons?logo=nuget)](https://www.nuget.org/packages/timewarp-simple-icons/) ```console dotnet add package timewarp-simple-icons ``` ## License [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-simple-icons?logo=github)](https://unlicense.org) ## Contributing Time is of the essence. Before developing a Pull Request I recommend opening a [discussion](https://github.com/TimeWarpEngineering/timewarp-simple-icons/discussions). Please feel free to make suggestions and help out with the [documentation](https://timewarpengineering.github.io/timewarp-simple-icons/). Please refer to [Markdown](http://daringfireball.net/projects/markdown/) for how to write markdown files. ### Publishing and icon updates Publishing is handled by GitHub Actions (`.github/workflows/workflow.yml`) with NuGet Trusted Publishing (OIDC). Prefer the `bin/dev` CLI over ad-hoc scripts: * **CI / release pack & push:** `bin/dev workflow` (or push a release / let the workflow run) * **Sync icons from upstream simple-icons:** `bin/dev update-icons` (optional `--publish` with an API key from OIDC Trusted Publishing) Helper PowerShell scripts live under `scripts/` (`update.ps1`, `transform.ps1`, `publish.ps1`, `watch-sample.ps1`) if you need local one-offs. Version is set in `source/Directory.Build.props`. After regenerating icons, run the sample app, update `releases.md`, then commit and push. ## Contact Sometimes the GitHub notifications get lost in the shuffle. If you file an [issue](https://github.com/TimeWarpEngineering/timewarp-simple-icons/issues) and don't get a response in a timely manner feel free to contact us on our [Discord server](https://discord.gg/A55JARGKKP). [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) ## References https://github.com/simple-icons/simple-icons ### Commands used ```PowerShell dotnet new sln dotnet new razorclasslib -n timewarp-simple-icons dotnet sln add .\source\timewarp-simple-icons\timewarp-simple-icons.csproj dotnet new tool-manifest dotnet tool install dotnet-cleanup dotnet cleanup -y ``` --- --- title: TimeWarp.Nuru description: Route-based CLI framework for .NET - batteries included with telemetry, REPL, and shell completion type: package latest: 3.0.0 stable: 3.0.0 repository: https://github.com/TimeWarpEngineering/timewarp-nuru --- Route-based CLI framework for .NET - batteries included with telemetry, REPL, and shell completion | | | |---|---| | Latest stable | `3.0.0` | | Downloads | 28,668 | | Last published | 2026-10-14 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Nuru ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Nuru) · [Source](https://github.com/TimeWarpEngineering/timewarp-nuru) · Part of the [timewarp-nuru](/projects/timewarp-nuru/) family --- # TimeWarp.Nuru
[![NuGet Version](https://img.shields.io/nuget/v/TimeWarp.Nuru.svg)](https://www.nuget.org/packages/TimeWarp.Nuru/) [![NuGet Downloads](https://img.shields.io/nuget/dt/TimeWarp.Nuru.svg)](https://www.nuget.org/packages/TimeWarp.Nuru/) [![Build Status](https://img.shields.io/github/actions/workflow/status/TimeWarpEngineering/timewarp-nuru/build.yml?branch=master)](https://github.com/TimeWarpEngineering/timewarp-nuru/actions) [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-nuru.svg)](https://github.com/TimeWarpEngineering/timewarp-nuru/blob/master/LICENSE) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/TimeWarpEngineering/timewarp-nuru) **Route-based CLI framework for .NET - bringing web-style routing to command-line applications**
> **Nuru** means "light" in Swahili - illuminating the path to your commands with clarity and simplicity. ## 📦 Installation ```bash dotnet add package TimeWarp.Nuru ``` ## 🚀 Quick Start TimeWarp.Nuru offers two patterns for defining CLI commands. Start with the Endpoint DSL for structured apps, or Fluent DSL for quick scripts. ### Endpoint DSL Define routes as classes with `[NuruRoute]` attributes: ```csharp using TimeWarp.Mediator; using TimeWarp.Nuru; [NuruRoute("add", Description = "Add two numbers together")] public sealed class AddCommand : ICommand { [Parameter(Order = 0)] public double X { get; set; } [Parameter(Order = 1)] public double Y { get; set; } public sealed class Handler : ICommandHandler { public Task Handle(AddCommand command, CancellationToken ct) { Console.WriteLine($"{command.X} + {command.Y} = {command.X + command.Y}"); return Unit.Task; } } } // In your main file: NuruApp app = NuruApp.CreateBuilder() .DiscoverEndpoints() .Build(); return await app.RunAsync(args); ``` Add `[NuruRouteExample("add 2 3", Description = "Add two numbers")]` (repeatable) to a command class to show concrete usage in `add --help` and in `--capabilities` JSON. ### Fluent DSL Define routes inline with a fluent builder API: ```csharp using TimeWarp.Nuru; NuruApp app = NuruApp.CreateBuilder() .Map("add {x:double} {y:double}") .WithHandler((double x, double y) => Console.WriteLine($"{x} + {y} = {x + y}")) .AsCommand() .Done() .Build(); return await app.RunAsync(args); ``` ```bash dotnet run -- add 15 25 # Output: 15 + 25 = 40 ``` **→ [Full Getting Started Guide](documentation/user/getting-started.md)** ## ✨ Key Features | Feature | Description | Learn More | |---------|-------------|------------| | 🎯 **Web-Style Routing** | Familiar `"deploy {env} --version {tag}"` syntax | [Routing Guide](documentation/user/features/routing.md) | | 📦 **Endpoint DSL** | Class-based commands with `DiscoverEndpoints()` auto-discovery | [Architecture Choices](documentation/user/guides/architecture-choices.md) | | 🔧 **Fluent DSL** | Inline routes with `.Map().WithHandler().Done()` chain | [Architecture Choices](documentation/user/guides/architecture-choices.md) | | 🛡️ **Roslyn Analyzer** | Catch route errors at compile-time | [Analyzer Docs](documentation/user/features/analyzer.md) | | ⌨️ **Shell Completion** | Tab completion for bash, zsh, PowerShell, fish | [Shell Completion](#-shell-completion) | | 🤖 **MCP Server** | AI-assisted development with Claude | [MCP Server Guide](documentation/user/tools/mcp-server.md) | | 📊 **Logging Package** | Zero-overhead structured logging | [Logging Docs](documentation/user/features/logging.md) | | 🚀 **Native AOT** | Zero warnings, 3.3 MB binaries, instant startup | [Deployment Guide](documentation/user/guides/deployment.md#native-aot-compilation) | | 🔒 **Type-Safe Parameters** | Automatic type conversion and validation | [Supported Types](documentation/user/reference/supported-types.md) | | 📖 **Auto-Help** | Generate help from route patterns | [Auto-Help Feature](documentation/user/features/auto-help.md) | | 🎨 **Rich Terminal** | Colors, tables, panels, rules via [TimeWarp.Terminal](https://github.com/TimeWarpEngineering/timewarp-terminal) | [Terminal Guide](documentation/user/features/terminal-abstractions.md) | ## 📚 Documentation ### Getting Started - **[Getting Started Guide](documentation/user/getting-started.md)** - Build your first CLI app in 5 minutes - **[Use Cases](documentation/user/use-cases.md)** - Greenfield apps & progressive enhancement patterns - **[Architecture Choices](documentation/user/guides/architecture-choices.md)** - Choose Endpoint DSL or Fluent DSL ### Core Features - **[Routing Patterns](documentation/user/features/routing.md)** - Complete route syntax reference - **[Roslyn Analyzer](documentation/user/features/analyzer.md)** - Compile-time validation - **[Logging System](documentation/user/features/logging.md)** - Structured logging setup - **[Auto-Help](documentation/user/features/auto-help.md)** - Automatic help generation - **[Output Handling](documentation/user/features/output-handling.md)** - stdout/stderr best practices - **[Terminal Abstractions](documentation/user/features/terminal-abstractions.md)** - Testable I/O & colored output ### Tools & Deployment - **[MCP Server](documentation/user/tools/mcp-server.md)** - AI-powered development assistance - **[Deployment Guide](documentation/user/guides/deployment.md)** - Native AOT, runfiles, distribution - **[Best Practices](documentation/user/guides/best-practices.md)** - Patterns for maintainable CLIs ### Reference - **[Performance Benchmarks](documentation/user/reference/performance.md)** - Detailed performance metrics - **[Supported Types](documentation/user/reference/supported-types.md)** - Complete type reference - **[API Documentation](documentation/user/reference/)** - Technical reference ## 🎯 Two Powerful Use Cases ### 🆕 Greenfield CLI Applications Build modern command-line tools from scratch: ``` myapp/ ├── calculator.cs # Single runfile - just 5 lines └── endpoints/ ├── add-command.cs ├── factorial-command.cs └── ... ``` **Endpoint DSL approach** (class-based, organized by file): ```csharp // In endpoints/add-command.cs [NuruRoute("add", Description = "Add two numbers")] public sealed class AddCommand : ICommand { [Parameter] public double X { get; set; } [Parameter] public double Y { get; set; } public sealed class Handler : ICommandHandler { public Task Handle(AddCommand c, CancellationToken ct) { Console.WriteLine($"{c.X} + {c.Y} = {c.X + c.Y}"); return Unit.Task; } } } ``` **Fluent DSL approach** (inline definitions): ```csharp NuruApp.CreateBuilder() .Map("deploy {env} --version {tag?}") .WithHandler((string env, string? tag) => Deploy(env, tag)) .AsCommand() .Done() .Build(); ``` ### 🔄 Progressive Enhancement Wrap existing CLIs to add auth, logging, or validation: ```csharp NuruApp app = NuruApp.CreateBuilder(args) .Map("deploy prod") .WithHandler(async () => { if (!await ValidateAccess()) return 1; return await Shell.ExecuteAsync("existing-cli", "deploy", "prod"); }) .AsCommand() .Done() .Map("{*args}") .WithHandler(async (string[] args) => await Shell.ExecuteAsync("existing-cli", args)) .AsCommand() .Done() .Build(); ``` **→ [Detailed Use Cases with Examples](documentation/user/use-cases.md)** ## 🌟 Working Examples **[Calculator Samples](samples/02-calculator/)** - Three complete implementations you can run now: - **[01-calc-endpoints.cs](samples/02-calculator/01-calc-endpoints.cs)** - Endpoint DSL pattern (testable, DI) - **[02-calc-fluent.cs](samples/02-calculator/02-calc-fluent.cs)** - Fluent DSL approach (inline handlers) - **[03-calc-mixed.cs](samples/02-calculator/03-calc-mixed.cs)** - Mixed approach (both patterns together) ```bash ./samples/02-calculator/01-calc-endpoints.cs add 10 20 # Endpoint DSL: structured ./samples/02-calculator/02-calc-fluent.cs factorial 5 # Fluent DSL: inline ``` **[AOT Example](samples/05-aot-example/)** - Native AOT compilation with source generators ## ⚡ Performance | Implementation | Memory | Speed (37 tests) | Binary Size | |----------------|--------|------------------|-------------| | Direct (JIT) | ~4 KB | 2.49s | N/A | | Direct (AOT) | ~4 KB | **0.30s** 🚀 | 3.3 MB | | Endpoints (AOT) | Moderate | **0.42s** 🚀 | 4.8 MB | **Native AOT is 88-93% faster than JIT** → [Full Performance Benchmarks](documentation/user/reference/performance.md) ## 🤖 AI-Powered Development **For AI agents:** Load the built-in [Nuru Skill](skills/tw-nuru/SKILL.md) for instant access to: - Complete DSL syntax and patterns - Testing with TestTerminal - Route examples and type conversion > 💡 **Tip:** No MCP installation needed - the skill provides all essential patterns. **For MCP Server:** The `TimeWarp.Nuru.Mcp` package is frozen and is **not part of the 3.0 release**. Its answers do not match 3.0; use the Nuru skill above. Older prereleases install with: ```bash dotnet tool install --global TimeWarp.Nuru.Mcp ``` Get instant help: - Validate route patterns before writing code - Generate handler code automatically - Get syntax examples on demand - Real-time error guidance **→ [MCP Server Setup Guide](documentation/user/tools/mcp-server.md)** ## ⌨️ Shell Completion Enable tab completion for your CLI with one line of code: ```csharp NuruApp app = NuruApp.CreateBuilder(args) .Map("deploy {env} --version {tag}") .WithHandler((string env, string tag) => Deploy(env, tag)) .AsCommand() .Done() .Map("status") .WithHandler(() => ShowStatus()) .AsQuery() .Done() .EnableStaticCompletion() // ← Add this .Build(); ``` Generate completion scripts for your shell: ```bash # Bash ./myapp --generate-completion bash >> ~/.bashrc # Zsh ./myapp --generate-completion zsh >> ~/.zshrc # PowerShell ./myapp --generate-completion powershell >> $PROFILE # Fish ./myapp --generate-completion fish > ~/.config/fish/completions/myapp.fish ``` **Supports:** - ✅ Command completion (`deploy`, `status`) - ✅ Option completion (`--version`, `--force`) - ✅ Short option aliases (`-v`, `-f`) - ✅ All 4 major shells (bash, zsh, PowerShell, fish) **See [completion-example](samples/15-completion/) for a complete working example.** ## 🤝 Contributing We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for details. **For Contributors:** - **[Developer Documentation](documentation/developer/overview.md)** - Architecture and design - **[Standards](documentation/developer/standards/)** - Coding conventions - **[Releasing Guide](documentation/developer/guides/releasing.md)** - How we cut and publish releases ## 📄 License This project is licensed under the Unlicense - see the [license](license) file for details. ---
**Ready to build powerful CLI applications?** **[Get Started in 5 Minutes](documentation/user/getting-started.md)** • **[View Examples](samples/02-calculator/)** • **[Read the Docs](documentation/user/overview.md)**
--- --- title: TimeWarp.State.Plus description: TimeWarp.State.Plus extends TimeWarp.State and TimeWarp.State.Blazor with routing, persistence, and action tracking. type: package latest: 12.0.0-beta.13 stable: 11.0.3 repository: https://github.com/TimeWarpEngineering/timewarp-state --- TimeWarp.State.Plus extends TimeWarp.State and TimeWarp.State.Blazor with routing, persistence, and action tracking. | | | |---|---| | Latest stable | `11.0.3` | | Latest prerelease | `12.0.0-beta.13` | | Downloads | 26,234 | | Last published | 2026-10-13 | | Target frameworks | `net11.0` | ## Install ```sh dotnet add package TimeWarp.State.Plus dotnet add package TimeWarp.State.Plus --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.State.Plus) · [Source](https://github.com/TimeWarpEngineering/timewarp-state) · Part of the [timewarp-state](/projects/timewarp-state/) family See [TimeWarp.State](/packages/timewarp.state/) for the full documentation of this family. --- --- title: TimeWarp.Architecture description: TimeWarp Architecture Templates type: package latest: 2.0.0-beta.19 stable: 1.0.15+6.0.402 repository: https://github.com/TimeWarpEngineering/timewarp-architecture --- TimeWarp Architecture Templates | | | |---|---| | Latest stable | `1.0.15+6.0.402` | | Latest prerelease | `2.0.0-beta.19` | | Downloads | 17,879 | | Last published | 2026-09-16 | | Target frameworks | `net9.0` | ## Install ```sh dotnet add package TimeWarp.Architecture dotnet add package TimeWarp.Architecture --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Architecture) · [Source](https://github.com/TimeWarpEngineering/timewarp-architecture) · Part of the [timewarp-architecture](/projects/timewarp-architecture/) family --- [![Dotnet](https://img.shields.io/badge/dotnet-10.0-blue)](https://dotnet.microsoft.com) [![Stars](https://img.shields.io/github/stars/TimeWarpEngineering/timewarp-architecture?logo=github)](https://github.com/TimeWarpEngineering/timewarp-architecture) [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) [![workflow](https://github.com/TimeWarpEngineering/timewarp-architecture/actions/workflows/workflow.yml/badge.svg)](https://github.com/TimeWarpEngineering/timewarp-architecture/actions/workflows/workflow.yml) [![NuGet](https://img.shields.io/nuget/v/TimeWarp.Architecture.svg)](https://www.nuget.org/packages/TimeWarp.Architecture/) [![NuGet](https://img.shields.io/nuget/dt/TimeWarp.Architecture.svg)](https://www.nuget.org/packages/TimeWarp.Architecture/) [![Twitter](https://img.shields.io/twitter/follow/StevenTCramer.svg)](https://twitter.com/intent/follow?screen_name=StevenTCramer) [![Twitter](https://img.shields.io/twitter/follow/TheFreezeTeam1.svg)](https://twitter.com/intent/follow?screen_name=TheFreezeTeam1) # TimeWarp Architecture ## timewarp-architecture ### Documentation Purpose/Design regions plus `skills/` are the documentation of record (`AGENTS.md`). Generated apps include `skills/` in their template output. ### Installation ```console dotnet new --install TimeWarp.Architecture ``` ### Usage ```console dotnet new timewarp-architecture -n MyTimeWarpApp ``` ## Content The template creates the distributed app projects and their corresponding test projects. --- --- title: TimeWarp.Nuru.Analyzers description: Roslyn analyzers for TimeWarp.Nuru route pattern validation type: package latest: 3.0.0 stable: 3.0.0 repository: https://github.com/TimeWarpEngineering/timewarp-nuru --- Roslyn analyzers for TimeWarp.Nuru route pattern validation | | | |---|---| | Latest stable | `3.0.0` | | Downloads | 15,916 | | Last published | 2026-10-14 | ## Install ```sh dotnet add package TimeWarp.Nuru.Analyzers ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Nuru.Analyzers) · [Source](https://github.com/TimeWarpEngineering/timewarp-nuru) · Part of the [timewarp-nuru](/projects/timewarp-nuru/) family See [TimeWarp.Nuru](/packages/timewarp.nuru/) for the full documentation of this family. --- --- title: TimeWarp.Mediator.Contracts description: Contract-only package for TimeWarp.Mediator: IRequest, ICommand, IQuery, INotification, IStreamRequest, their handler and pipeline-behavior interfaces, ISender/IPublisher/IMediator, and the scope/modu… type: package latest: 14.0.0 stable: 14.0.0 repository: https://github.com/TimeWarpEngineering/timewarp-mediator --- Contract-only package for TimeWarp.Mediator: IRequest, ICommand, IQuery, INotification, IStreamRequest, their handler and pipeline-behavior interfaces, ISender/IPublisher/IMediator, and the scope/module attributes the source generator reads. Reference it from message libraries without depending on a dispatcher. | | | |---|---| | Latest stable | `14.0.0` | | Downloads | 14,817 | | Last published | 2026-10-13 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Mediator.Contracts ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Mediator.Contracts) · [Source](https://github.com/TimeWarpEngineering/timewarp-mediator) · Part of the [timewarp-mediator](/projects/timewarp-mediator/) family See [TimeWarp.Mediator](/packages/timewarp.mediator/) for the full documentation of this family. --- --- title: TimeWarp.Nuru.Mcp description: MCP server for TimeWarp.Nuru providing route validation, syntax documentation, example code, and handler generation for AI-assisted CLI development. type: package latest: 3.0.0-beta.76 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-nuru --- MCP server for TimeWarp.Nuru providing route validation, syntax documentation, example code, and handler generation for AI-assisted CLI development. | | | |---|---| | Latest prerelease | `3.0.0-beta.76` | | Stable release | none yet (prerelease only) | | Downloads | 14,602 | | Last published | 2026-08-14 | ## Install ```sh dnx TimeWarp.Nuru.Mcp -- --help dotnet tool install -g TimeWarp.Nuru.Mcp --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Nuru.Mcp) · [Source](https://github.com/TimeWarpEngineering/timewarp-nuru) · Part of the [timewarp-nuru](/projects/timewarp-nuru/) family See [TimeWarp.Nuru](/packages/timewarp.nuru/) for the full documentation of this family. --- --- title: TimeWarp.Mediator description: Reflection-based mediator (MediatR fork): AddMediator() registers request/response, notifications, streams, and pipeline behaviors over Microsoft.Extensions.DependencyInjection by assembly scan. The s… type: package latest: 14.0.0 stable: 14.0.0 repository: https://github.com/TimeWarpEngineering/timewarp-mediator --- Reflection-based mediator (MediatR fork): AddMediator() registers request/response, notifications, streams, and pipeline behaviors over Microsoft.Extensions.DependencyInjection by assembly scan. The source-generated, AOT-friendly dispatcher is separate (TimeWarp.Mediator.Contracts and TimeWarp.Mediator.Generators, AddGeneratedMediator) and does not reference this package. | | | |---|---| | Latest stable | `14.0.0` | | Downloads | 14,585 | | Last published | 2026-10-13 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Mediator ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Mediator) · [Source](https://github.com/TimeWarpEngineering/timewarp-mediator) · Part of the [timewarp-mediator](/projects/timewarp-mediator/) family --- # TimeWarp.Mediator The reflection dispatcher for TimeWarp Mediator 14.0: assembly scanning, pipeline behaviors, streams, pre/post processors, and the exception cascade. It is the MediatR-shaped API. It is not the source-generated mediator. ## Install ```bash dotnet add package TimeWarp.Mediator --version 14.0.0 ``` 14.0.0 targets net10.0 only. Stay on 13.0.0 when you cannot: ```bash dotnet add package TimeWarp.Mediator --version 13.0.0 ``` ## Example ```csharp public sealed class Ping : IRequest { } public sealed class PingHandler : IRequestHandler { public Task Handle(Ping request, CancellationToken cancellationToken) => Task.FromResult("Pong"); } services.AddMediator(cfg => cfg.RegisterServicesFromAssemblyContaining()); string reply = await provider.GetRequiredService().Send(new Ping()); ``` `AddMediator()` registers `IMediator`, `ISender`, `IPublisher`, and the handlers it finds. It does not register the generated mediator. The reflection runtime is not trim or NativeAOT safe (IL2026 / IL3050). ## Migration 14.0.0 is not a drop-in for 13.0.0, and neither stack is a drop-in for the other. - From MediatR: `using MediatR;` becomes `using TimeWarp.Mediator;`, and `AddMediatR` becomes `AddMediator`. - From 13.x reflection to the generated stack: reference `TimeWarp.Mediator.Contracts` and `TimeWarp.Mediator.Generators`, mark handler assemblies with `[assembly: MediatorAssembly]`, and call `AddGeneratedMediator()`. Drop this package once nothing calls `AddMediator()`. - Generated dispatch does not run streams, pre/post processors, or the exception cascade. Stay on this package if you need those. - `ServiceFactory` is removed; resolve through `IServiceProvider`. The handler wrappers and `ServiceRegistrar` are internal. Call `ISender.Send`, `IPublisher.Publish`, and `AddMediator`. Matrix and steps: [13.x reflection to 14.x generated](https://github.com/TimeWarpEngineering/timewarp-mediator/blob/master/migration.md#13x-reflection-to-14x-generated). ## Documentation - [Repository readme](https://github.com/TimeWarpEngineering/timewarp-mediator#readme) - [Generated vs reflection](https://github.com/TimeWarpEngineering/timewarp-mediator/blob/master/documentation/generated-vs-legacy.md) - [Diagnostics TWM001–TWM011](https://github.com/TimeWarpEngineering/timewarp-mediator/blob/master/documentation/diagnostics.md) - [Release notes](https://github.com/TimeWarpEngineering/timewarp-mediator/blob/master/documentation/release-notes/release-notes-v14.0.0.md) ## License Licensed as `Unlicense AND Apache-2.0`. The Apache-2.0 terms cover code derived from [MediatR](https://github.com/jbogard/MediatR) by Jimmy Bogard. The `notice` and `unlicense` files ship in this package. --- --- title: TimeWarp.Amuru description: Fluent API for elegant C# scripting with pipeline support type: package latest: 2.0.0 stable: 2.0.0 repository: https://github.com/TimeWarpEngineering/timewarp-amuru --- Fluent API for elegant C# scripting with pipeline support | | | |---|---| | Latest stable | `2.0.0` | | Downloads | 12,696 | | Last published | 2026-10-14 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Amuru ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Amuru) · [Source](https://github.com/TimeWarpEngineering/timewarp-amuru) · Part of the [timewarp-amuru](/projects/timewarp-amuru/) family --- [![Stars](https://img.shields.io/github/stars/TimeWarpEngineering/timewarp-amuru?logo=github)](https://github.com/TimeWarpEngineering/timewarp-amuru) [![workflow](https://github.com/TimeWarpEngineering/timewarp-amuru/actions/workflows/workflow.yml/badge.svg)](https://github.com/TimeWarpEngineering/timewarp-amuru/actions) [![Forks](https://img.shields.io/github/forks/TimeWarpEngineering/timewarp-amuru)](https://github.com/TimeWarpEngineering/timewarp-amuru) [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-amuru.svg?style=flat-square&logo=github)](https://github.com/TimeWarpEngineering/timewarp-amuru/issues) [![Issues Open](https://img.shields.io/github/issues/TimeWarpEngineering/timewarp-amuru.svg?logo=github)](https://github.com/TimeWarpEngineering/timewarp-amuru/issues) [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/TimeWarpEngineering/timewarp-amuru/badge)](https://scorecard.dev/viewer/?uri=github.com/TimeWarpEngineering/timewarp-amuru) [![nuget](https://img.shields.io/nuget/v/TimeWarp.Amuru?logo=nuget)](https://www.nuget.org/packages/TimeWarp.Amuru/) [![nuget](https://img.shields.io/nuget/dt/TimeWarp.Amuru?logo=nuget)](https://www.nuget.org/packages/TimeWarp.Amuru/) [![Twitter](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2FTimeWarpEngineering%2Ftimewarp-amuru)](https://twitter.com/intent/tweet?url=https://github.com/TimeWarpEngineering/timewarp-amuru) [![Dotnet](https://img.shields.io/badge/dotnet-10.0-blue)](https://dotnet.microsoft.com) [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) [![Twitter](https://img.shields.io/twitter/follow/StevenTCramer.svg)](https://twitter.com/intent/follow?screen_name=StevenTCramer) [![Twitter](https://img.shields.io/twitter/follow/TheFreezeTeam1.svg)](https://twitter.com/intent/follow?screen_name=TheFreezeTeam1) logo # TimeWarp.Amuru *Amuru means "command" in Swahili* **TimeWarp.Amuru** is a 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 `Builder()` method, async operations, and shell-like error handling. Designed for modern C# developers, TimeWarp.Amuru 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.Amuru provides the elegant, type-safe API you need. ## Why TimeWarp.Amuru? - **Zero Learning Curve**: If you know C#, you already know how to use TimeWarp.Amuru - **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 - **Native AOT Ready**: Both packages declare and validate AOT/trimming compatibility - **Built for .NET 10**: Modern C# features and first-class file-based app (runfile) support - **Script or Library**: Use it in quick scripts or production applications ## Give a Star! :star: If you find this project useful, please give it a star. Thanks! ## Installation ```bash # Core library: process execution, mocking, native file and text operations dotnet add package TimeWarp.Amuru # Optional: fluent builders for dotnet/git/fzf plus repo services dotnet add package TimeWarp.Amuru.Tools ``` This readme documents the 2.0 API, first available in `2.0.0`. See [the 2.0 release notes](documentation/release-notes/2.0.0.md). Or reference in your C# runfile: ```csharp #:package TimeWarp.Amuru@ ``` Both packages share the `TimeWarp.Amuru` namespace — adding the Tools reference lights up `DotNet.*`, `Git.*`, and `Fzf.*` with no code changes. ### Optional: CLI Tools ```bash # Global CLI tool with additional utilities (private package) dotnet tool install --global TimeWarp.Ganda --source https://nuget.pkg.github.com/TimeWarpEngineering/index.json ``` See the [Ganda repository](https://github.com/TimeWarpEngineering/timewarp-ganda) for details. ## Quick Start ```csharp #!/usr/bin/dotnet -- #:package TimeWarp.Amuru using TimeWarp.Amuru; using static System.Console; // Default behavior - stream to console (like bash/PowerShell) await Shell.Builder("npm").WithArguments("install").RunAsync(); // Capture output when needed CommandOutput result = await Shell.Builder("git").WithArguments("status").CaptureAsync(); if (result.Success) { WriteLine($"Git says: {result.Stdout}"); } // Stream large files without memory issues await foreach (string line in Shell.Builder("tail").WithArguments("-f", "/var/log/app.log").StreamStdoutAsync()) { WriteLine($"Log: {line}"); } // Chain commands with pipelines CommandOutput found = await Shell.Builder("find") .WithArguments(".", "-name", "*.cs") .Pipe("grep", "async") .CaptureAsync(); WriteLine($"Found {found.GetLines().Length} async lines"); // Work with CommandOutput CommandOutput output = await Shell.Builder("docker").WithArguments("ps").CaptureAsync(); WriteLine($"Exit code: {output.ExitCode}"); WriteLine($"Success: {output.Success}"); WriteLine($"Stdout: {output.Stdout}"); WriteLine($"Stderr: {output.Stderr}"); WriteLine($"Combined: {output.Combined}"); // Use the fluent builder API for complex commands CommandOutput log = await Shell.Builder("git") .WithArguments("log", "--oneline", "-n", "10") .WithWorkingDirectory("/my/repo") .CaptureAsync(cancellationToken); // Provide standard input to commands CommandOutput grepResult = await Shell.Builder("grep") .WithArguments("pattern") .WithStandardInput("line1\nline2 with pattern\nline3") .CaptureAsync(); // Full interactive mode for stream-based tools (fzf, REPLs) await Shell.Builder("fzf").PassthroughAsync(); // TUI applications (vim, nano, edit) need true TTY passthrough await Shell.Builder("vim") .WithArguments("myfile.txt") .TtyPassthroughAsync(); ``` ### Tool Builders (TimeWarp.Amuru.Tools) ```csharp // Global dotnet options CommandOutput sdks = await DotNet.WithListSdks().CaptureAsync(); CommandOutput version = await DotNet.WithVersion().CaptureAsync(); // Base builder for custom arguments CommandOutput custom = await DotNet.Builder() .WithArguments("--list-runtimes") .CaptureAsync(); // Build and test with streaming output await DotNet.Build() .WithConfiguration("Release") .RunAsync(); await DotNet.Test() .WithFilter("Category=Unit") .RunAsync(); // Git operations with typed results string? repoRoot = Git.FindRoot(); GitWorktreeListResult listed = await Git.WorktreeListPorcelainAsync("/my/repo"); IReadOnlyList worktrees = listed.Success ? Git.ParseWorktreeList(listed.Porcelain ?? "") : []; // Interactive selection with Fzf string selectedFile = await Fzf.Builder() .FromInput("file1.txt", "file2.txt", "file3.txt") .WithPreview("cat {}") .SelectAsync(); ``` ## Key Features - **Shell-Like Default**: `RunAsync()` streams to console just like bash/PowerShell - **Explicit Capture**: `CaptureAsync()` for when you need to process output - **Memory-Efficient Streaming**: `IAsyncEnumerable` for large data without buffering - **One Result Type**: `CommandOutput` with Stdout, Stderr, Combined, ExitCode, Success, and RunTime — from every execution mode - **Shell-Like Error Handling**: non-zero exit codes are values, not exceptions; strict validation is one opt-in call away - **Built-In Command Mocking**: `CommandMock` with strict-by-default matching — tests can never silently run real commands - **Pipeline Support**: Chain commands with Unix-like pipe semantics - **Standard Input Support**: Provide stdin to commands with `.WithStandardInput()` - **NO CACHING Philosophy**: Like shells, commands run fresh every time - **Cancellation Support**: Full CancellationToken support throughout - **Per-command timeout**: `WithTimeout` reports `TimedOut` and exit 124; a caller cancellation token still cancels - **Cross-Platform**: Works on Windows, Linux, and macOS (including `.cs` script execution on Windows via the dotnet host) - **Interactive Commands**: `PassthroughAsync()` for stream-based tools, `TtyPassthroughAsync()` for TUI apps (vim, nano), `SelectAsync()` for selection tools - **.NET 10 Script Support**: AppContext extensions and ScriptContext for file-based apps - **Native text**: `SelectString` (grep) and `ReplaceInFiles` (in-place replace) under `TimeWarp.Amuru.Native.Text`, with `Grep` / `Sed` bash aliases. See [Native text commands](documentation/developer/reference/native-text-commands.md) ## Output Handling ### Core API Methods ```csharp // RunAsync() - Default shell behavior, streams to console await Shell.Builder("npm").WithArguments("install").RunAsync(); // Returns: exit code (int) // CaptureAsync() - Silent execution with full output capture CommandOutput result = await Shell.Builder("git").WithArguments("status").CaptureAsync(); // Returns: CommandOutput; no console output // RunAndCaptureAsync() - Stream to console AND capture CommandOutput logged = await Shell.Builder("dotnet").WithArguments("build").RunAndCaptureAsync(); // PassthroughAsync() - Stream-based interactive tools (fzf, REPLs) CommandOutput fzfResult = await Shell.Builder("fzf").PassthroughAsync(); // TtyPassthroughAsync() - True TTY for TUI applications (vim, nano, edit) CommandOutput vimResult = await Shell.Builder("vim").WithArguments("file.txt").TtyPassthroughAsync(); // SelectAsync() - Selection tools (shows UI on stderr, captures stdout selection) string selected = await Shell.Builder("fzf").SelectAsync(); ``` ### The CommandOutput Type ```csharp CommandOutput output = await Shell.Builder("docker").WithArguments("ps").CaptureAsync(); // Access individual streams Console.WriteLine($"Stdout: {output.Stdout}"); Console.WriteLine($"Stderr: {output.Stderr}"); Console.WriteLine($"Combined: {output.Combined}"); // Captured in arrival order // Check status Console.WriteLine($"Exit code: {output.ExitCode}"); Console.WriteLine($"Success: {output.Success}"); // ExitCode == 0 Console.WriteLine($"Runtime: {output.RunTime}"); // Line processing (interior blank lines preserved; no trailing empty entry) foreach (string line in output.GetLines()) { ProcessLine(line); } // Or line-level access with source-stream metadata foreach (OutputLine line in output.OutputLines) { Console.WriteLine($"{(line.IsError ? "ERR" : "OUT")}: {line.Text}"); } // Pretty-print a result with status coloring output.WriteToConsole(); ``` ### Streaming Large Data ```csharp // Stream lines as they arrive (no buffering) await foreach (string line in Shell.Builder("tail") .WithArguments("-f", "/var/log/app.log") .StreamStdoutAsync(cancellationToken)) { Console.WriteLine($"Log: {line}"); } ``` ### Method Comparison | Method | Console Output | Captures | Returns | Primary Use Case | |--------|---------------|----------|---------|------------------| | `RunAsync()` | ✅ Real-time | ❌ | Exit code | Default scripting | | `CaptureAsync()` | ❌ Silent | ✅ All streams | CommandOutput | Process output | | `RunAndCaptureAsync()` | ✅ Real-time | ✅ All streams | CommandOutput | Logging + capture | | `PassthroughAsync()` | ✅ Piped | ❌ | CommandOutput | Stream-based interactive | | `TtyPassthroughAsync()` | ✅ TTY | ❌ | CommandOutput | TUI apps (vim, nano) | | `SelectAsync()` | ✅ UI only | ✅ Selection | string | Selection tools | | `StreamStdoutAsync()` | ❌ | ✅ As stream | IAsyncEnumerable | Large data | ### Design Philosophy: NO CACHING TimeWarp.Amuru intentionally does NOT cache command results: ```csharp // Shells don't cache - neither do we await Shell.Builder("date").RunAsync(); // Shows current time await Shell.Builder("date").RunAsync(); // Shows NEW current time // If you need caching, it's trivial in C#: private static CommandOutput? cachedResult; CommandOutput result = cachedResult ??= await Shell.Builder("expensive-command").CaptureAsync(); ``` ## Error Handling TimeWarp.Amuru handles failure the way shells do: **a non-zero exit code is a value you inspect, not an exception**. ### Default Behavior (Never Throws on Exit Codes) ```csharp CommandOutput result = await Shell.Builder("ls").WithArguments("/nonexistent").CaptureAsync(); if (!result.Success) { Console.WriteLine($"Command failed with exit code: {result.ExitCode}"); Console.WriteLine($"Error: {result.Stderr}"); } ``` ### Strict Validation (Opt-in Throwing) ```csharp // Throws on any non-zero exit code await Shell.Builder("git") .WithArguments("push") .WithZeroExitCodeValidation() .RunAsync(); ``` ### Commands That Never Ran An empty/invalid command or a failed pipeline composition never throws, but it is never mistaken for success either — it reports `CommandResult.NeverRanExitCode` (-1): ```csharp CommandOutput result = await Shell.Builder("").CaptureAsync(); // result.Success == false, result.ExitCode == CommandResult.NeverRanExitCode ``` Note: a **missing executable** (e.g. a typo'd command name) still throws at execution time — that is an environment error, not an exit code. ### Cancellation and Timeouts ```csharp // With explicit cancellation token using CancellationTokenSource cts = new(TimeSpan.FromSeconds(30)); await Shell.Builder("long-running-command").RunAsync(cts.Token); // Per-command limit. Default validation reports the timeout instead of throwing. CommandOutput output = await Shell.Builder("long-running-command") .WithTimeout(TimeSpan.FromSeconds(30)) .CaptureAsync(); // output.TimedOut is true and output.ExitCode is 124 when the limit is hit ``` ## Testing and Mocking ### CommandMock (Recommended) `CommandMock` intercepts command execution in-process — no mock executables needed. It is **strict by default**: a command with no matching setup throws instead of silently running the real thing. ```csharp using TimeWarp.Amuru.Testing; using (CommandMock.Enable()) { CommandMock.Setup("git", "status") .Returns("On branch main\nnothing to commit"); CommandOutput output = await Shell.Builder("git").WithArguments("status").CaptureAsync(); // output.Stdout == "On branch main\nnothing to commit" — no real git ran CommandMock.VerifyCalled("git", "status"); } // Simulate failures and exceptions using (CommandMock.Enable()) { CommandMock.Setup("git", "push").ReturnsError("remote: Permission denied", 128); CommandMock.Setup("flaky-tool").Throws(new TimeoutException("simulated")); CommandMock.Setup("slow-tool").Delays(TimeSpan.FromSeconds(2)); // ... } // Mixed mocked + real commands (opt out of strict mode) using (CommandMock.Enable(MockBehavior.Loose)) { CommandMock.Setup("deploy-tool").Returns("deployed"); // unmocked commands fall through to real execution } ``` Mocking is scoped per async context (parallel tests stay isolated) and covers every execution mode — run, capture, streaming, select, and passthrough. `Pipe` compositions are the documented exception (use loose mode). ### CliConfiguration (Path Overrides) For cases where you want a real replacement executable, redirect a command process-wide: ```csharp CliConfiguration.SetCommandPath("fzf", "/tmp/mock-bin/fzf"); // ... code using fzf now runs the replacement ... CliConfiguration.Reset(); ``` API: `SetCommandPath`, `ClearCommandPath`, `Reset`, `HasCustomPath`, `AllCommandPaths`. Overrides are process-global by design — use `CommandMock` for per-test isolation. ## .NET 10 File-Based App Support TimeWarp.Amuru provides specialized support for .NET 10's file-based apps (single-file C# scripts): - **AppContext Extensions** — `AppContext.EntryPointFilePath()` / `EntryPointFileDirectoryPath()` without magic strings - **ScriptContext** — scoped working-directory management with cleanup on dispose or process exit (contexts nest safely) - **`.cs` as a command** — `Shell.Builder("script.cs")` runs another runfile (shebang on Unix, dotnet host on Windows) 📖 **[See the documentation](documentation/developer/how-to-guides/)** for detailed usage guides and examples. ## Architecture - **Static Entry Point**: Minimal ceremony with `Shell.Builder()` / `Shell.Run()` - **Two Packages, One Namespace**: `TimeWarp.Amuru` (core) and `TimeWarp.Amuru.Tools` (tool builders); both ship together at one version - **Shell Semantics**: exit codes are values; composition never throws; nothing is cached - **Predictable Error Handling**: never-ran, non-zero-exit, and environment failures are all distinguishable - **Opt-in Complexity**: Advanced features available when needed See our [Architectural Decision Records](documentation/conceptual/architectural-decision-records/overview.md) for detailed design rationale. ## Documentation - **[Documentation overview](documentation/overview.md)** - Entry point to conceptual, developer, and user docs - **[Native text commands](documentation/developer/reference/native-text-commands.md)** - `SelectString` and `ReplaceInFiles` - **[Migration Guide](analysis/migration-guide.md)** - Guide for migrating from older versions - **[command-extensions.cs](source/timewarp-amuru/core/command-extensions.cs)** - Collocated command construction design documentation - **[command-result.cs](source/timewarp-amuru/core/command-result.cs)** - Collocated command execution design documentation - **[Samples](samples/)** - Compiling example scripts referenced against the live source ## Unlicense [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-amuru.svg?style=flat-square&logo=github)](https://unlicense.org) This project is licensed under the [Unlicense](https://unlicense.org). ## Related Packages - **[TimeWarp.Amuru.Tools](https://www.nuget.org/packages/TimeWarp.Amuru.Tools/)** - Fluent dotnet/git/fzf builders and repo services on top of this library - **[TimeWarp.Multiavatar](https://www.nuget.org/packages/TimeWarp.Multiavatar/)** - Avatar generation library ([repository](https://github.com/TimeWarpEngineering/timewarp-multiavatar)) - **[TimeWarp.Ganda](https://github.com/TimeWarpEngineering/timewarp-ganda)** - Shell toolkit CLI (private, separate repository) ## Contributing Your contributions are welcome! Before starting any work, please open a [discussion](https://github.com/TimeWarpEngineering/timewarp-amuru/discussions). See our [Kanban board](kanban/overview.md) 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](https://discord.gg/A55JARGKKP). [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) --- --- title: TimeWarp.Terminal description: Terminal abstractions and widgets for console applications - IConsole, ITerminal, panels, tables, rules, and ANSI color support type: package latest: 1.0.2 stable: 1.0.2 repository: https://github.com/TimeWarpEngineering/timewarp-terminal --- Terminal abstractions and widgets for console applications - IConsole, ITerminal, panels, tables, rules, and ANSI color support | | | |---|---| | Latest stable | `1.0.2` | | Downloads | 10,442 | | Last published | 2026-09-21 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Terminal ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Terminal) · [Source](https://github.com/TimeWarpEngineering/timewarp-terminal) · Part of the [timewarp-terminal](/projects/timewarp-terminal/) family --- # TimeWarp.Terminal Terminal abstractions and widgets for console applications - IConsole, ITerminal, panels, tables, rules, and ANSI color support. ## Installation ```bash dotnet add package TimeWarp.Terminal ``` ## Quick Start ```csharp using TimeWarp.Terminal; // Use the static Terminal class (Console-compatible API) Terminal.WriteLine("Hello, World!".Green()); Terminal.WriteLine("Warning!".Yellow().Bold()); // Or get a terminal instance — all Write methods return ITerminal for fluent chaining ITerminal terminal = TimeWarpTerminal.Default; terminal .WritePanel("Important message", "Notice") .WriteRule("Section") .WriteTable(t => t .AddColumn("Name") .AddColumn("Value") .AddRow("Status", "OK".Green())) .WriteLine("Done!"); ``` ## Static Terminal API The `Terminal` static class provides a Console-compatible API for easy migration: ```csharp using static TimeWarp.Terminal.Terminal; // Direct replacement for Console methods WriteLine("Hello, World!"); WriteErrorLine("Error occurred!"); string? input = ReadLine(); Clear(); // Properties int width = WindowWidth; bool interactive = IsInteractive; bool colorSupport = SupportsColor; // Cursor operations SetCursorPosition(10, 5); var (left, top) = GetCursorPosition(); ``` ### Testing with Static Terminal Use `TestTerminalContext` to redirect the static `Terminal` class in tests: ```csharp using TestTerminal terminal = new(); using IDisposable scope = TestTerminalContext.Use(terminal); Terminal.WriteLine("Hello"); terminal.OutputContains("Hello").ShouldBeTrue(); ``` The scope is async-context isolated - each test flow sees only its own `TestTerminal`, so parallel tests never interfere with each other, and the global terminal is never mutated. Disposing the scope restores the previous context automatically. For serial tests you can also swap `Terminal.Instance` directly, but remember to restore it: ```csharp using TestTerminal testTerminal = new(); Terminal.Instance = testTerminal; Terminal.WriteLine("test output"); Assert.Contains("test output", testTerminal.Output); // Restore after test Terminal.Instance = TimeWarpTerminal.Default; ``` ## Interfaces ### IConsole Basic console I/O abstraction for testable console applications. ```csharp public interface IConsole { IConsole Write(string message); IConsole WriteLine(string? message = null); Task WriteLineAsync(string? message = null); IConsole WriteErrorLine(string? message = null); Task WriteErrorLineAsync(string? message = null); string? ReadLine(); } ``` ### ITerminal Extended terminal interface with cursor control, colors, and hyperlinks. ```csharp public interface ITerminal : IConsole { new ITerminal Write(string message); new ITerminal WriteLine(string? message = null); new ITerminal WriteErrorLine(string? message = null); ConsoleKeyInfo ReadKey(bool intercept); void SetCursorPosition(int left, int top); (int Left, int Top) GetCursorPosition(); int WindowWidth { get; } bool IsInteractive { get; } bool SupportsColor { get; } bool SupportsHyperlinks { get; } void Clear(); } ``` ## Implementations | Class | Description | |-------|-------------| | `TimeWarpTerminal` | Production `ITerminal` with full terminal capabilities | | `TimeWarpConsole` | Production `IConsole` wrapping `System.Console` | | `TestTerminal` | Test implementation with captured output and scripted input | | `TestConsole` | Simpler test implementation for basic I/O testing | ### Testing Example ```csharp using TestTerminal terminal = new(); // Queue input for ReadLine terminal = new TestTerminal("line1\nline2"); // Queue keys for ReadKey terminal.QueueKey(ConsoleKey.Enter); terminal.QueueKeys("hello"); terminal.QueueLine("complete line"); // Run code that uses ITerminal myCommand.Execute(terminal); // Verify output Assert.Contains("expected text", terminal.Output); Assert.Contains("error message", terminal.ErrorOutput); ``` ## Widgets ### Panel Bordered panel with optional header and content. ```csharp // Simple panel terminal.WritePanel("This is important information"); // Panel with header terminal.WritePanel("Content here", "Notice"); // Fluent builder with full options terminal.WritePanel ( panel => panel .Header("Configuration".Cyan().Bold()) .Content("Setting: value") .Border(BorderStyle.Rounded) .BorderColor(AnsiColors.Cyan) .Padding(2, 1) .Width(60) .WordWrap(true) ); ``` **Border Styles:** `Rounded`, `Square`, `Doubled`, `Heavy`, `None` ### Table Formatted table with columns, alignment, and styling. ```csharp // Simple table terminal.WriteTable ( t => t .AddColumn("Name") .AddColumn("Value", Alignment.Right) .AddRow("CPU", "45%") .AddRow("Memory", "2.1 GB") ); // Full-featured table terminal.WriteTable(t => t .AddColumn("Package") .AddColumn("Downloads", Alignment.Right) .AddColumn(new TableColumn("Path") { TruncateMode = TruncateMode.Start }) .AddRow("GuardClauses", "12M", "/home/user/packages/guard") .Border(BorderStyle.Rounded) .BorderColor(AnsiColors.Cyan) .Expand()); // tables shrink to fit the terminal automatically terminal.WriteTable(table); ``` **Alignment:** `Left` (default), `Right`, `Center` **TruncateMode:** `End` (default), `Start`, `Middle` ### Rule Horizontal rule with optional centered title. ```csharp // Simple rule terminal.WriteRule(); // Rule with title terminal.WriteRule("Section Title"); // Styled rule terminal.WriteRule("Results".Cyan().Bold()); // Fluent builder terminal.WriteRule(rule => rule .Title("Configuration") .Style(LineStyle.Doubled) .Color(AnsiColors.Cyan)); ``` **Line Styles:** `Thin`, `Doubled`, `Heavy` ## Layout (companion package) Flexbox-composed layouts for side-by-side panels, status-bar rows, and dashboards. This is a **companion package** — it is not pulled in by `TimeWarp.Terminal`. ```bash dotnet add package TimeWarp.Terminal.Layout ``` ```csharp using TimeWarp.Terminal; using TimeWarp.Flexbox; terminal.WriteLayout(layout => layout .Direction(FlexDirection.Row) .Gap(2) .Item(i => i.Grow(1), panel => panel.Header("Build").Content(buildSummary)) .Item(i => i.Grow(2), table => table.AddColumns("Test", "Result").AddRow("unit", "pass"))); // Column of rows (dashboard) terminal.WriteLayout(layout => layout .Direction(FlexDirection.Column) .Row(r => r.Item(statusPanel).Item(versionPanel)) .Row(r => r.Item(i => i.Grow(1), logTable))); ``` ## ANSI Colors Extension methods for colored and styled console output. ```csharp // Foreground colors terminal.WriteLine("Success!".Green()); terminal.WriteLine("Warning!".Yellow()); terminal.WriteLine("Error!".Red()); // Chained styles terminal.WriteLine("Important".Red().Bold().Underline()); // Background colors terminal.WriteLine("Highlighted".OnYellow()); terminal.WriteLine("Inverted".Black().OnWhite()); ``` ### Available Colors **Standard:** `Black`, `Red`, `Green`, `Yellow`, `Blue`, `Magenta`, `Cyan`, `White`, `Gray` **Bright:** `BrightRed`, `BrightGreen`, `BrightYellow`, `BrightBlue`, `BrightMagenta`, `BrightCyan`, `BrightWhite` ### Styles `Bold()`, `Dim()`, `Italic()`, `Underline()`, `Strikethrough()` ### Background Colors `OnBlack()`, `OnRed()`, `OnGreen()`, `OnYellow()`, `OnBlue()`, `OnMagenta()`, `OnCyan()`, `OnWhite()` ## ConsoleColor Support Use `ConsoleColor` enum values for color output without needing ANSI escape codes directly. This provides a Console-compatible API for colored output. ```csharp // Single foreground color Terminal.WriteLine("Error!", ConsoleColor.Red); Terminal.WriteLine("Success!", ConsoleColor.Green); Terminal.WriteLine("Warning!", ConsoleColor.Yellow); // Foreground and background colors Terminal.WriteLine("Highlighted", ConsoleColor.Black, ConsoleColor.Yellow); Terminal.WriteLine("Inverted", ConsoleColor.White, ConsoleColor.Black); // Error output with color Terminal.WriteErrorLine("Error: File not found", ConsoleColor.Red); // Write without newline Terminal.Write("Loading...", ConsoleColor.Cyan); // Widgets with colors Terminal.WriteTable(table => table .AddColumn("Name") .AddColumn("Value") .AddRow("Status", "OK"), ConsoleColor.White, ConsoleColor.DarkBlue); Terminal.WritePanel("Important content", "Notice", ConsoleColor.White, ConsoleColor.DarkBlue); ``` ### Supported Colors All `ConsoleColor` values are mapped to their ANSI equivalents: **Foreground:** `Black`, `Red`, `Green`, `Yellow`, `Blue`, `Magenta`, `Cyan`, `White`, `Gray`, `DarkGray`, `DarkRed`, `DarkGreen`, `DarkYellow`, `DarkBlue`, `DarkMagenta`, `DarkCyan` **Background:** Maps to corresponding ANSI background codes (`BgBlack`, `BgRed`, etc.) ## Hyperlinks OSC 8 hyperlinks for supported terminals (Windows Terminal, iTerm2, VS Code, etc.). ```csharp // Write a clickable link terminal.WriteLink("https://github.com", "GitHub"); terminal.WriteLinkLine("https://example.com", "Click here"); // String extension method string link = "Click here".Link("https://example.com"); terminal.WriteLine(link); // Styled hyperlink terminal.WriteLine("Visit us".Link("https://example.com").Cyan().Underline()); // Check terminal support if (terminal.SupportsHyperlinks) terminal.WriteLinkLine("https://docs.com", "View docs"); else terminal.WriteLine("View docs at https://docs.com"); ``` ## AnsiStringUtils Utilities for working with ANSI-styled strings. ```csharp // Get visible length (excludes ANSI codes) int length = AnsiStringUtils.GetVisibleLength("Hello".Red()); // 5 // Strip all ANSI codes string plain = AnsiStringUtils.StripAnsiCodes("\x1b[31mError\x1b[0m"); // "Error" // Pad accounting for ANSI codes string padded = AnsiStringUtils.PadRightVisible("Hi".Red(), 10); string centered = AnsiStringUtils.CenterVisible("Title".Bold(), 40); // Wrap text preserving ANSI codes string[] lines = AnsiStringUtils.WrapText(longStyledText, maxWidth: 80); ``` --- --- title: TimeWarp.Build.Tasks description: MSBuild tasks for TimeWarp projects including git metadata injection and build automation type: package latest: 1.0.0 stable: 1.0.0 repository: https://github.com/TimeWarpEngineering/timewarp-build-tasks --- MSBuild tasks for TimeWarp projects including git metadata injection and build automation | | | |---|---| | Latest stable | `1.0.0` | | Downloads | 10,371 | | Last published | 2025-10-14 | ## Install ```sh dotnet add package TimeWarp.Build.Tasks ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Build.Tasks) · [Source](https://github.com/TimeWarpEngineering/timewarp-build-tasks) --- [![Stars](https://img.shields.io/github/stars/TimeWarpEngineering/timewarp-build-tasks?logo=github)](https://github.com/TimeWarpEngineering/timewarp-build-tasks) [![Forks](https://img.shields.io/github/forks/TimeWarpEngineering/timewarp-build-tasks)](https://github.com/TimeWarpEngineering/timewarp-build-tasks) [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-build-tasks.svg?style=flat-square&logo=github)](https://github.com/TimeWarpEngineering/timewarp-build-tasks/issues) [![Issues Open](https://img.shields.io/github/issues/TimeWarpEngineering/timewarp-build-tasks.svg?logo=github)](https://github.com/TimeWarpEngineering/timewarp-build-tasks/issues) [![nuget](https://img.shields.io/nuget/v/TimeWarp.Build.Tasks?logo=nuget)](https://www.nuget.org/packages/TimeWarp.Build.Tasks/) [![nuget](https://img.shields.io/nuget/dt/TimeWarp.Build.Tasks?logo=nuget)](https://www.nuget.org/packages/TimeWarp.Build.Tasks/) [![Twitter](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2FTimeWarpEngineering%2Ftimewarp-build-tasks)](https://twitter.com/intent/tweet?url=https://github.com/TimeWarpEngineering/timewarp-build-tasks) [![Dotnet](https://img.shields.io/badge/dotnet-10.0-blue)](https://dotnet.microsoft.com) [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) [![Twitter](https://img.shields.io/twitter/follow/StevenTCramer.svg)](https://twitter.com/intent/follow?screen_name=StevenTCramer) [![Twitter](https://img.shields.io/twitter/follow/TheFreezeTeam1.svg)](https://twitter.com/intent/follow?screen_name=TheFreezeTeam1) logo # TimeWarp.Build.Tasks **TimeWarp.Build.Tasks** is an MSBuild tasks library that provides build-time automation for .NET projects. The library automatically injects git metadata (commit hash and timestamp) into your assemblies at build time, enabling better traceability and versioning in production deployments. This build-time dependency integrates seamlessly into your build pipeline without adding runtime overhead, making it ideal for CI/CD workflows and production builds where tracking exact source versions is critical. ## Give a Star! :star: If you find this project useful, please give it a star. Thanks! ## Features - **Automatic Git Metadata Injection** - Embeds commit hash and timestamp into assembly metadata - **Build-Time Only** - No runtime dependencies or performance impact - **Transitive Support** - Automatically applied to projects that reference packages using this library - **Configurable** - Can be disabled per-project with `TimeWarpEnableGitMetadata=false` - **Fallback Handling** - Gracefully handles non-git repositories without breaking builds ## Installation ```console dotnet add package TimeWarp.Build.Tasks ``` Check out the latest NuGet packages on the [TimeWarp Enterprises NuGet page](https://www.nuget.org/profiles/TimeWarp.Enterprises). * [TimeWarp.Build.Tasks](https://www.nuget.org/packages/TimeWarp.Build.Tasks/) [![nuget](https://img.shields.io/nuget/v/TimeWarp.Build.Tasks?logo=nuget)](https://www.nuget.org/packages/TimeWarp.Build.Tasks/) ## Usage Once installed, git metadata is automatically injected into your assemblies during build. Access the metadata at runtime: ```csharp using System.Reflection; var assembly = typeof(Program).Assembly; var commitHash = assembly.GetCustomAttributes() .FirstOrDefault(a => a.Key == "CommitHash")?.Value; var commitDate = assembly.GetCustomAttributes() .FirstOrDefault(a => a.Key == "CommitDate")?.Value; Console.WriteLine($"Built from commit: {commitHash}"); Console.WriteLine($"Commit date: {commitDate}"); ``` ### Disabling Git Metadata To disable automatic git metadata injection for a specific project: ```xml false ``` ## Documentation See full [documentation](https://timewarpengineering.github.io/timewarp-build-tasks/). ## Unlicense [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-build-tasks.svg?style=flat-square&logo=github)](https://unlicense.org) This project is licensed under the [Unlicense](https://unlicense.org). ## Contributing Your contributions are welcome! Before starting any work, please open a [discussion](https://github.com/TimeWarpEngineering/timewarp-build-tasks/discussions). Help with the [documentation](https://timewarpengineering.github.io/timewarp-build-tasks/) is also greatly appreciated. ## Contact If you have an issue and don't receive a timely response, feel free to reach out on our [Discord server](https://discord.gg/A55JARGKKP). [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) --- --- title: TimeWarp.State.Policies description: Policies for TimeWarp State management library type: package latest: 12.0.0-beta.13 stable: 11.0.3 repository: https://github.com/TimeWarpEngineering/timewarp-state --- Policies for TimeWarp State management library | | | |---|---| | Latest stable | `11.0.3` | | Latest prerelease | `12.0.0-beta.13` | | Downloads | 9,800 | | Last published | 2026-10-13 | | Target frameworks | `net11.0` | ## Install ```sh dotnet add package TimeWarp.State.Policies dotnet add package TimeWarp.State.Policies --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.State.Policies) · [Source](https://github.com/TimeWarpEngineering/timewarp-state) · Part of the [timewarp-state](/projects/timewarp-state/) family See [TimeWarp.State](/packages/timewarp.state/) for the full documentation of this family. --- --- title: TimeWarp.Builder description: Fluent builder interfaces and scope extensions for TimeWarp projects type: package latest: 1.0.0 stable: 1.0.0 repository: https://github.com/TimeWarpEngineering/timewarp-builder --- Fluent builder interfaces and scope extensions for TimeWarp projects | | | |---|---| | Latest stable | `1.0.0` | | Downloads | 8,472 | | Last published | 2026-07-02 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Builder ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Builder) · [Source](https://github.com/TimeWarpEngineering/timewarp-builder) --- # TimeWarp.Builder [![NuGet](https://img.shields.io/nuget/vpre/TimeWarp.Builder.svg)](https://www.nuget.org/packages/TimeWarp.Builder) [![NuGet Downloads](https://img.shields.io/nuget/dt/TimeWarp.Builder.svg)](https://www.nuget.org/packages/TimeWarp.Builder) [![CI/CD](https://github.com/TimeWarpEngineering/timewarp-builder/actions/workflows/workflow.yml/badge.svg)](https://github.com/TimeWarpEngineering/timewarp-builder/actions/workflows/workflow.yml) [![License: Unlicense](https://img.shields.io/badge/license-Unlicense-blue.svg)](LICENSE) Fluent builder interfaces and Kotlin-inspired scope extensions for .NET. ## Installation ```bash dotnet add package TimeWarp.Builder --prerelease ``` ## Requirements - .NET 10.0 or later - Fully AOT- and trim-compatible (no reflection, no dynamic code) ## Interfaces ### IBuilder\ Interface for standalone builders that create objects via `Build()`. `TBuilt` is covariant, so an `IBuilder` can be used wherever an `IBuilder` is expected. ```csharp public class MyWidgetBuilder : IBuilder { public Widget Build() => new Widget(_options); } // Usage Widget widget = new MyWidgetBuilder() .WithColor("blue") .WithSize(10) .Build(); ``` ### INestedBuilder\ Interface for nested builders that return to a parent context via `Done()`. `Done()` performs three things: builds the child, hands the result to the parent, and returns the parent for continued chaining. ```csharp // Nested builder returns to parent after building app.Map(route => route .WithLiteral("deploy") .WithParameter("env") .Done()) // Returns to parent builder .WithHandler(handler); ``` ## Scope Extensions Kotlin-inspired extension methods for fluent object manipulation. Because they attach to every type (unconstrained `T`), any object can participate in a fluent chain without its type opting in. | Method | Returns | Use for | |--------|---------|---------| | `Also` | The original object | Side effects mid-chain (logging, diagnostics) | | `Apply` | The original object | Configuring the object mid-chain | | `Let` | The transform result | Converting to a different type/value | | `Run` | Nothing (`void`) | Terminal action at the end of a chain | ### Also vs Apply `Also` and `Apply` are mechanically identical — both execute an action and return the original object. They exist separately to signal *intent* at the call site, mirroring Kotlin's `also`/`apply` distinction: use `Apply` when the action configures the object itself, and `Also` when the action is an incidental side effect like logging. ```csharp app.Map("status", handler) .Apply(r => r.AsQuery()) // configures the route .Also(r => logger.LogDebug("mapped {r}", r)); // side effect, not configuration ``` ### Also Executes an action on the object and returns the original object. ```csharp var builder = new AppBuilder() .Also(b => logger.LogDebug("Building app...")) .Configure(options); ``` ### Apply Configures the object and returns the original object. ```csharp app.Map("status", handler) .Apply(r => r.AsQuery()); ``` ### Let Transforms the object to a different type. ```csharp int length = "hello".Let(s => s.Length); // 5 ``` ### Run Executes an action on the object with no return value. Terminal operation in a method chain. ```csharp app.Build().Run(a => a.RunAsync(args)); ``` All four methods throw `ArgumentNullException` when the delegate is null. ## Used By - [TimeWarp.Nuru](https://github.com/TimeWarpEngineering/timewarp-nuru) — route, endpoint, group, and key-binding builders implement `IBuilder` / `INestedBuilder` - [TimeWarp.Terminal](https://github.com/TimeWarpEngineering/timewarp-terminal) ## Testing Tests are [TimeWarp.Jaribu](https://github.com/TimeWarpEngineering/timewarp-jaribu) runfiles under `tests/`. Run them all with `dev test`, or any file directly: ```bash dotnet run tests/scope-extensions.also.cs ``` ## Unlicense This is free and unencumbered software released into the public domain — see [LICENSE](LICENSE). --- --- title: TimeWarp.Fixie description: The TimeWarp Fixie testing convention type: package latest: 3.1.0+9.0.300 stable: 3.1.0+9.0.300 repository: https://github.com/TimeWarpEngineering/timewarp-fixie --- The TimeWarp Fixie testing convention | | | |---|---| | Latest stable | `3.1.0+9.0.300` | | Downloads | 6,258 | | Last published | 2025-06-04 | | Target frameworks | `net9.0` | ## Install ```sh dotnet add package TimeWarp.Fixie ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Fixie) · [Source](https://github.com/TimeWarpEngineering/timewarp-fixie) --- [![Dotnet](https://img.shields.io/badge/dotnet-6.0-blue)](https://dotnet.microsoft.com) [![Stars](https://img.shields.io/github/stars/TimeWarpEngineering/timewarp-fixie?logo=github)](https://github.com/TimeWarpEngineering/timewarp-fixie) [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) [![nuget](https://img.shields.io/nuget/v/TimeWarp.Fixie?logo=nuget)](https://www.nuget.org/packages/TimeWarp.Fixie/) [![nuget](https://img.shields.io/nuget/dt/TimeWarp.Fixie?logo=nuget)](https://www.nuget.org/packages/TimeWarp.Fixie/) [![Issues Open](https://img.shields.io/github/issues/TimeWarpEngineering/timewarp-fixie?logo=github)](https://github.com/TimeWarpEngineering/timewarp-fixie/issues) [![Forks](https://img.shields.io/github/forks/TimeWarpEngineering/timewarp-fixie)](https://github.com/TimeWarpEngineering/timewarp-fixie) [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-fixie?logo=github)](https://unlicense.org) [![Twitter](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2FTimeWarpEngineering%2Ftimewarp-fixie)](https://twitter.com/intent/tweet?url=https://github.com/TimeWarpEngineering/timewarp-fixie) [![Twitter](https://img.shields.io/twitter/follow/StevenTCramer.svg)](https://twitter.com/intent/follow?screen_name=StevenTCramer) [![Twitter](https://img.shields.io/twitter/follow/TheFreezeTeam1.svg)](https://twitter.com/intent/follow?screen_name=TheFreezeTeam1) # timewarp-fixie ![TimeWarp Logo](assets/Logo.png) [Fixie](https://github.com/fixie/fixie/wiki) is a dotnet test framework similar to NUnit and xUnit, but with an emphasis on low-ceremony defaults and flexible customizations. TimeWarp-fixie is a project that uses conventions to simplify using Fixie even further. ## Feature overview * Dependency Injection support for test cases. * No need to decorate test methods with [Test] attributes. Public methods are test cases by default. * Skip - can mark tests to be skipped. * Tags - Add tags to your tests and filter runs based on the tag. * Inputs - Allow for parameterized tests. (similar to how "Theory" works in xUnit) * Lifecycle Methods - if the `Setup` or `Cleanup` methods are found on the test class they will be executed appropriately. * NotTest - Can mark methods with `NotTest` attribute if they are not tests. * Filter tests by name * Filter tests by Tags ## Give a Star! :star: If you like or are using this project please give it a star. Thank you! ## Installation You can see the latest NuGet packages from the official [TimeWarp NuGet page](https://www.nuget.org/profiles/TimeWarp.Enterprises). * [timewarp-fixie](https://www.nuget.org/packages/TimeWarp.Fixie/) [![nuget](https://img.shields.io/nuget/v/TimeWarp.Fixie?logo=nuget)](https://www.nuget.org/packages/TimeWarp.Fixie/) ## Usage ### Creating a New Test Project Create a new test project: ```console dotnet new classlib -n MyProject.Tests ``` Add NuGet packages to the project: ```console dotnet add package TimeWarp.Fixie dotnet add package Fixie.TestAdapter ``` Create a dotnet tool manifest: ```console dotnet new tool-manifest ``` Add Fixie.Console to the manifest: ```console dotnet tool install Fixie.Console ``` ### Configuring Testing Convention Inside your Fixie project, create a class that inherits from `Fixie.Conventions.TestingConvention`: ```csharp class TestingConvention : TimeWarp.Fixie.TestingConvention { } ``` This will use the `TimeWarp.Fixie` convention. ### Creating a Sample Test First, add Shouldly (you could use basic Asserts or any other assertion library): ```csharp dotnet add package Shouldly ``` Create a sample test class named `ConventionTests.cs`: ```csharp namespace ConventionTest_; using Shouldly; using TimeWarp.Fixie; [TestTag(TestTags.Fast)] public class SimpleNoApplicationTest_Should_ { public static void AlwaysPass() => true.ShouldBeTrue(); [Skip("Demonstrates skip attribute")] public static void SkipExample() => true.ShouldBeFalse(); [TestTag(TestTags.Fast)] public static void TagExample() => true.ShouldBeTrue(); [Input(5, 3, 2)] [Input(8, 5, 3)] public static void Subtract(int x, int y, int expectedDifference) { int result = x - y; result.ShouldBe(expectedDifference); } } ``` ### Executing the Tests ```console dotnet fixie ``` ## Features ### Dependency Injection Tests are instantiated from the dependency injection container set up for tests, so you can use the same pattern for testing as for production apps. ### Configuring Services for the Execution Phase To customize the services used in the execution phase, inherit from `TestingConvention` and override the service configuration: ```csharp namespace TimeWarp.Architecture.Testing; public class TimeWarpTestingConvention : TestingConvention { public TimeWarpTestingConvention() : base(ConfigureAdditionalServicesCallback) { } private static void ConfigureAdditionalServicesCallback(ServiceCollection serviceCollection) { Console.WriteLine("ConfigureAdditionalServices"); serviceCollection .AddSingleton() .AddSingleton() .AddSingleton>() .AddSingleton(); } } ``` ### Class-Specific Service Configuration You can configure services specific to individual test classes by adding a static `ConfigureServices` method to your test class. This allows different test classes to use different mock implementations: ```csharp public class UserServiceTests { private readonly IUserRepository UserRepository; public UserServiceTests(IUserRepository userRepository) { UserRepository = userRepository; } // Configure services specific to this test class public static void ConfigureServices(IServiceCollection services) { services.AddScoped(); services.AddScoped(); } public void Should_Create_User() { // Test implementation using MockUserRepository } } public class OrderServiceTests { private readonly IUserRepository UserRepository; public OrderServiceTests(IUserRepository userRepository) { UserRepository = userRepository; } // Different mocks for this test class public static void ConfigureServices(IServiceCollection services) { services.AddScoped(); services.AddScoped(); } public void Should_Process_Order() { // Test implementation using FakeUserRepository } } ``` ### No Need to Decorate Test Methods with [Test] Attributes Public methods are test cases by convention: ```csharp // Xunit style [Test] // <==== Not needed with TimeWarp Fixie Convention public void SomeTest() { Assert.Fail(); } ``` ```csharp // TimeWarp Fixie Convention: all public methods are tests public void SomeTest() { Assert.Fail(); } ``` ### Skip - Mark Tests to Be Skipped ```csharp [Skip("Reason for skipping")] public static void SkipExample() => true.Should().BeFalse(); ``` ### Tags You can add tags to any of your tests. We include some in the `TestTags` static class, but they are just strings, so you can add whatever you like: ```csharp [TestTag(TestTags.Fast)] [TestTag("Bug123")] public static void TagExample() => true.Should().BeTrue(); ``` ### Parameterized Tests Similar to how xUnit uses `[Theory]`, you can run a test for each set of parameters: ```csharp [Input(5, 3, 2)] [Input(8, 5, 3)] public static void Subtract(int aX, int aY, int aExpectedDifference) { int result = aX - aY; result.Should().Be(aExpectedDifference); } ``` ### Lifecycle Methods If the `Setup` or `Cleanup` methods are found on the test class, they will be executed appropriately for each test: ```csharp public class LifecycleExamples { public static void AlwaysPass() => true.Should().BeTrue(); [Input(5, 3, 2)] [Input(8, 5, 3)] public static void Subtract(int aX, int aY, int aExpectedDifference) { // Will run lifecycles around each Input int result = aX - aY; result.Should().Be(aExpectedDifference); } public static void Setup() => Console.WriteLine("Sample Setup"); public static void Cleanup() => Console.WriteLine("Sample Cleanup"); } ``` ### NotTest If you have a class that needs to be public but does not contain tests, you can mark it as such with the `[NotTest]` attribute. For example: ```csharp [NotTest] [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class NotTest : Attribute { } ``` ### Filtering Tests by Name From Fixie's [docs](https://github.com/fixie/fixie/wiki/dotnet-fixie#filtering-with---tests): The optional argument `--tests` (abbreviated `-t`) lets you specify which tests to run. **Run a single test by full name:** ```console dotnet fixie --tests Full.Namespace.MyTestClass.MyTestMethod ``` **Run tests with implicit wildcard (most test name prefixes are similar):** ```console dotnet fixie --tests MyTestClass.MyTestMethod ``` **Run tests with explicit wildcard (`*` matches any sequence of zero or more characters):** ```console dotnet fixie --tests MyTest*.TestMethod* ``` **Run an entire test class:** ```console dotnet fixie --tests MyTestClass.* ``` **Leveraging PascalCase naming convention for partial matches:** ```console dotnet fixie --tests MyTestClass.Should_Create_User ``` --- --- title: timewarp-heroicons description: All of the Tailwind HeroIcons wrapped as Blazor components. type: package latest: 2.2.0 stable: 2.2.0 repository: https://github.com/TimeWarpEngineering/timewarp-heroicons --- All of the Tailwind HeroIcons wrapped as Blazor components. | | | |---|---| | Latest stable | `2.2.0` | | Downloads | 4,580 | | Last published | 2026-08-12 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package timewarp-heroicons ``` [NuGet](https://www.nuget.org/packages/timewarp-heroicons) · [Source](https://github.com/TimeWarpEngineering/timewarp-heroicons) --- [![Dotnet](https://img.shields.io/badge/dotnet-6.0-blue)](https://dotnet.microsoft.com) [![Stars](https://img.shields.io/github/stars/TimeWarpEngineering/timewarp-heroicons?logo=github)](https://github.com/TimeWarpEngineering/timewarp-heroicons) [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) [![nuget](https://img.shields.io/nuget/v/timewarp-heroicons?logo=nuget)](https://www.nuget.org/packages/timewarp-heroicons/) [![nuget](https://img.shields.io/nuget/dt/timewarp-heroicons?logo=nuget)](https://www.nuget.org/packages/timewarp-heroicons/) [![Issues Open](https://img.shields.io/github/issues/TimeWarpEngineering/timewarp-heroicons?logo=github)](https://github.com/TimeWarpEngineering/timewarp-heroicons/issues) [![Forks](https://img.shields.io/github/forks/TimeWarpEngineering/timewarp-heroicons)](https://github.com/TimeWarpEngineering/timewarp-heroicons) [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-heroicons?logo=github)](https://unlicense.org) [![Twitter](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2FTimeWarpEngineering%2Ftimewarp-heroicons)](https://twitter.com/intent/tweet?url=https://github.com/TimeWarpEngineering/timewarp-heroicons) [![Twitter](https://img.shields.io/twitter/follow/StevenTCramer.svg)](https://twitter.com/intent/follow?screen_name=StevenTCramer) [![Twitter](https://img.shields.io/twitter/follow/TheFreezeTeam1.svg)](https://twitter.com/intent/follow?screen_name=TheFreezeTeam1) # timewarp-heroicons All the HeroIcons wrapped as Blazor components. ![TimeWarp Logo](assets/brand-logo.png) All [heroicons](https://github.com/tailwindlabs/heroicons) wrapped as Blazor components. See and search all at https://heroicons.com/ ## Give a Star! :star: If you like or are using this project please give it a star. Thank you! ## Usage ```razor ``` Outputs ![](assets/sample-output.png) ## Installation You can see the latest NuGet packages from the official [TimeWarp NuGet page](https://www.nuget.org/profiles/TimeWarp.Enterprises). * [timewarp-heroicons](https://www.nuget.org/packages/timewarp-heroicons/) [![nuget](https://img.shields.io/nuget/v/timewarp-heroicons?logo=nuget)](https://www.nuget.org/packages/timewarp-heroicons/) ```console dotnet add package timewarp-heroicons ``` ## License [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-heroicons?logo=github)](https://unlicense.org) ## Contributing Time is of the essence. Before developing a Pull Request I recommend opening a [discussion](https://github.com/TimeWarpEngineering/timewarp-heroicons/discussions). Please feel free to make suggestions and help out with the [documentation](https://timewarpengineering.github.io/timewarp-heroicons/). Please refer to [Markdown](http://daringfireball.net/projects/markdown/) for how to write markdown files. ### Steps to publish NuGet package * [ ] Clone the [heroicons](https://github.com/tailwindlabs/heroicons) repo. * [ ] Set the PowerShell variable `$heroicons` to the path where you cloned the heroicons repo in the above step. (Add `$heroicons = ""` to your profile) * [ ] Ensure your copy of the heroicons repo is up to date by running (`update.ps1`). * [ ] Set the Version in `timewarp-heroicons/source/timewarp-heroicons/timewarp-heroicons.csproj` to the same version that is in `simple-icons/package.json`. * [ ] Transform the cloned [simple-icons](https://github.com/simple-icons/simple-icons) into razor files by running `transform.ps1`. * [ ] Run the test app to make sure the icons render properly. * [ ] Update `releases.md`. * [ ] Commit and push the changes to GitHub. * [ ] Tweet to let people know. ## Contact Sometimes the github notifications get lost in the shuffle. If you file an [issue](https://github.com/TimeWarpEngineering/timewarp-heroicons/issues) and don't get a response in a timely manner feel free to ping on our [Discord server](https://discord.gg/A55JARGKKP). [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) ## References https://github.com/heroicons/heroicons ### Commands used ```PowerShell dotnet new sln dotnet new razorclasslib -n timewarp-heroicons dotnet sln add .\Source\timewarp-heroicons\timewarp-heroicons.csproj dotnet new tool-manifest dotnet tool install dotnet-cleanup dotnet cleanup -y ``` --- --- title: TimeWarp.Jaribu description: Lightweight testing helpers for single-file C# programs and scripts. Jaribu (Swahili: test/trial) provides TestRunner pattern and assertion helpers for executable .cs files. type: package latest: 1.0.0-beta.15 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-jaribu --- Lightweight testing helpers for single-file C# programs and scripts. Jaribu (Swahili: test/trial) provides TestRunner pattern and assertion helpers for executable .cs files. | | | |---|---| | Latest prerelease | `1.0.0-beta.15` | | Stable release | none yet (prerelease only) | | Downloads | 4,449 | | Last published | 2026-08-03 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Jaribu --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Jaribu) · [Source](https://github.com/TimeWarpEngineering/timewarp-jaribu) · Part of the [timewarp-jaribu](/projects/timewarp-jaribu/) family --- # TimeWarp.Jaribu Lightweight test framework for .NET with two execution modes: - **Runfile Mode**: Direct `.cs` file execution for rapid development - **M.T.P. Mode**: IDE integration and `dotnet test` support Jaribu (Swahili: test/trial) provides a convention-based TestRunner pattern that discovers public static async Task methods as tests. Write once, run anywhere—from quick scripts to full IDE integration. ## Features - **Convention over Configuration**: Discover public static async Task methods as tests via reflection. - **Assertion Helpers**: Simple, fluent assertions inspired by Shouldly. - **Attributes**: Support for [Skip], [TestTag], [Timeout], and [Input]. - **Parameterized Tests**: Easy data-driven testing. - **Tag Filtering**: Run specific test groups. - **Minimal Dependencies**: Only Shouldly for assertions. - **Visual Studio Test Explorer integration** (M.T.P. Mode) - **VS Code Test Explorer integration** (M.T.P. Mode) - **`dotnet test` support** (M.T.P. Mode) ## Two Execution Modes TimeWarp.Jaribu supports two distinct ways to run your tests: | Mode | Best For | How to Run | |------|----------|------------| | **Runfile Mode** | Rapid development, single-file tests | `./my-tests.cs` (Linux/macOS) or `dotnet my-tests.cs` | | **M.T.P. Mode** | IDE integration, team CI | `dotnet test` | Both modes use the same test discovery conventions and attributes. Your test classes work in either mode without modification. ### When to Use Runfile Mode - Rapid prototyping and experimentation - Single-file test apps that run like shell scripts (Linux/macOS shebang support) - CI pipelines with custom orchestration - When you prefer direct execution without project files - Unix-style workflows where tests are executable scripts ### When to Use M.T.P. Mode - Visual Studio or VS Code Test Explorer integration - Standard `dotnet test` workflow - Team environments with mixed IDEs - CI pipelines expecting standard test output (TRX, JUnit, etc.) ## Installation For **Runfile Mode** (single-file scripts): ``` dotnet add package TimeWarp.Jaribu ``` For **M.T.P. Mode** (IDE integration and `dotnet test`): ``` dotnet add package TimeWarp.Jaribu.TestingPlatform ``` --- ## Runfile Mode Runfile Mode executes test files directly without a project file. Ideal for rapid development and single-file tests. On **Linux/macOS**, test files with a shebang can be executed directly like scripts: ```bash ./my-tests.cs # Direct execution (requires shebang + chmod +x) dotnet my-tests.cs # Works on all platforms ``` ### Basic Test File (Runfile) Create a single-file test script (e.g., `my-tests.cs`): ```csharp #!/usr/bin/env dotnet run #:package TimeWarp.Jaribu using static TimeWarp.Jaribu.TestHelpers; return await RunAllTests(); public static class MyTests { [System.Runtime.CompilerServices.ModuleInitializer] internal static void Register() => RegisterTests(); public static async Task BasicTest() { 1.ShouldBe(1); } [TestTag("integration")] public static async Task IntegrationTest() { // Test logic here } } ``` Make it executable and run directly (Linux/macOS): ```bash chmod +x my-tests.cs ./my-tests.cs ``` Or run with dotnet (all platforms): ```bash dotnet my-tests.cs ``` ### TestRunner For programmatic use: ```csharp using TimeWarp.Jaribu; // Simple usage - returns exit code (0 = success, 1 = failure) int exitCode = await TestRunner.RunTests(); // Sink-based API - get detailed test information via ITestResultSink // Use NullSink for silent execution, TerminalSink for console output using TerminalSink sink = new(); TestRunStats stats = await TestRunner.RunTestsAsync(sink); // Access aggregated stats Console.WriteLine($"Passed: {stats.PassedCount}"); Console.WriteLine($"Failed: {stats.FailedCount}"); Console.WriteLine($"Skipped: {stats.SkippedCount}"); Console.WriteLine($"Duration: {stats.Duration}"); Console.WriteLine($"Success: {stats.Success}"); ``` ### Multi-Class Test Registration Run tests from multiple test classes with aggregated results: ```csharp using TimeWarp.Jaribu; // Register test classes explicitly (no assembly scanning) TestRunner.RegisterTests(); TestRunner.RegisterTests(); TestRunner.RegisterTests(); // Run all registered and get exit code (0 = success, 1 = failure) return await TestRunner.RunAllTests(); // Or with tag filter return await TestRunner.RunAllTests(filterTag: "Unit"); ``` **Note**: Use `TestRunner.ClearRegisteredTests()` to clear all registrations if needed. ### Multi-File Test Orchestration Organize tests across multiple files that work both standalone and aggregated: - **Standalone mode**: Run individual test files directly with `dotnet file.cs` - **Multi mode**: An orchestrator compiles multiple test files together with aggregated results This pattern uses `[ModuleInitializer]` for auto-registration and conditional compilation to prevent double-execution. #### Test file pattern ```csharp #!/usr/bin/dotnet -- #:project ../../source/MyProject/MyProject.csproj #if !JARIBU_MULTI return await RunAllTests(); #endif [TestTag("Unit")] public class MyTests { [ModuleInitializer] internal static void Register() => RegisterTests(); public static async Task SomeTest() { // Test logic } } ``` **Key elements:** - `#!/usr/bin/dotnet --` enables direct execution as a script - `#:project` references dependencies (Jaribu, your project, etc.) - `#if !JARIBU_MULTI` only self-executes when run standalone - `[ModuleInitializer]` auto-registers when compiled in multi mode #### Create an orchestrator Create a simple entry point that runs all auto-registered tests: ```csharp #!/usr/bin/dotnet -- #:project ../source/MyProject/MyProject.csproj // Tests auto-registered via [ModuleInitializer] return await RunAllTests(); ``` #### Configure Directory.Build.props Configure which test files to include and define the `JARIBU_MULTI` constant: ```xml $(DefineConstants);JARIBU_MULTI ``` This allows CI pipelines to run different subsets of tests by configuring separate orchestrators with different file includes. #### Real-world example Jaribu uses this pattern for its own test suite: - `tests/TimeWarp.Jaribu.Tests/jaribu-*.cs` - Test files following the dual-mode pattern - `tests/TimeWarp.Jaribu.Tests/ci-tests/` - CI orchestrator with curated test selection --- ## M.T.P. Mode M.T.P. (Microsoft.Testing.Platform) Mode integrates with Visual Studio Test Explorer, VS Code Test Explorer, and the standard `dotnet test` command. ### Project Setup Create a test project with the TestingPlatform package: ```xml net10.0 Exe enable enable ``` ### Test Class Example ```csharp using System.Runtime.CompilerServices; using static TimeWarp.Jaribu.TestHelpers; public class MyTests { [ModuleInitializer] internal static void Register() => RegisterTests(); public static async Task AdditionTest() { (1 + 1).ShouldBe(2); await Task.CompletedTask; } [TestTag("Integration")] public static async Task IntegrationTest() { // Integration test logic await Task.CompletedTask; } [Skip("Not yet implemented")] public static async Task FutureTest() { await Task.CompletedTask; } } ``` ### Running Tests ```bash # Run all tests dotnet test # Run with detailed output dotnet test --logger "console;verbosity=detailed" # List discovered tests dotnet run -- --list-tests # Filter by test name (MTP platform filter) dotnet run -- --filter "Name~Addition" # Jaribu selection / tag filters (M.T.P. adapter options) dotnet run -- --filter-tag Integration dotnet run -- --filter-class SpaSuite dotnet run -- --filter-method Login # Env fallback for tag (CLI --filter-tag wins when both set) JARIBU_FILTER_TAG=Integration dotnet test # Run directly (also works) dotnet run ``` **Jaribu filter options under M.T.P.:** | Option | Match | Semantics | |--------|-------|-----------| | `--filter-tag` | Exact tag (case-insensitive); CLI over `JARIBU_FILTER_TAG` | Non-matching tagged methods reported **Skipped** | | `--filter-class` | Substring of class `FullName` (ordinal ignore-case) | Non-matching classes **omitted** (selection) | | `--filter-method` | Substring of method name (ordinal ignore-case) | Non-matching methods **omitted** (selection) | Selection filters never emit Skipped nodes for omitted items. Tag filter keeps existing Skipped semantics for method-level tags; a class whose class-level tags exist and none match is omitted entirely — from both discovery (`--list-tests`) and the run. MTP uid/tree filters apply on both discovery and run. ### IDE Integration 1. Open the test project in Visual Studio or VS Code 2. Test Explorer automatically discovers all registered test classes 3. Run, debug, or filter tests from the Test Explorer panel **Visual Studio**: Tests appear in Test Explorer (Test → Test Explorer) **VS Code**: Install the C# Dev Kit extension; tests appear in the Testing sidebar --- ## API Reference ### Core Types ```csharp // Test state aligned with Microsoft.Testing.Platform public enum TestNodeState { Discovered, InProgress, Passed, Failed, Skipped, Timeout, Error, Cancelled } // Individual test result public record TestNodeInfo( string Uid, // "Namespace.Class.Method" string DisplayName, // "MethodName" or "MethodName(param1, param2)" TestNodeState State, TimeSpan? Duration = null, Exception? Exception = null, string? Message = null, IReadOnlyList? Parameters = null ); // Aggregated stats for a test class run public record TestRunStats( string ClassName, DateTimeOffset StartTime, TimeSpan Duration, int PassedCount, int FailedCount, int SkippedCount ) { public int TotalTests => PassedCount + FailedCount + SkippedCount; public bool Success => FailedCount == 0; } ``` ### Sink-Based Architecture Test output flows through `ITestResultSink` implementations, enabling pluggable output destinations: ```csharp // Interface for receiving test lifecycle events public interface ITestResultSink { Task OnTestDiscoveredAsync(TestNodeInfo node); Task OnTestStartedAsync(TestNodeInfo node); Task OnTestCompletedAsync(TestNodeInfo node); Task OnRunStartedAsync(string className, string? filterTag = null); Task OnRunCompletedAsync(TestRunStats stats, IReadOnlyList results); } ``` **Built-in sinks:** - **`TerminalSink`** — Pretty console output with colored tables (used by `RunTests()`) - **`NullSink`** — Silent sink for testing/benchmarking (`NullSink.Instance`) - **`MtpSink`** — Publishes to MTP's `IMessageBus` for `dotnet test` integration (internal) ### Setup and CleanUp Define `Setup()` and `CleanUp()` methods to run code before and after each test: ```csharp public static class MyTests { public static async Task Setup() { // Runs before EACH test // Initialize test data, create temp files, etc. await Task.CompletedTask; } public static async Task CleanUp() { // Runs after EACH test // Clean up resources, delete temp files, etc. await Task.CompletedTask; } public static async Task Test1() { // Setup runs before this test // Test logic here // CleanUp runs after this test } public static async Task Test2() { // Setup runs before this test (fresh state) // Test logic here // CleanUp runs after this test } } ``` **Note**: For one-time initialization that does not need dispose, static constructors or static field initialization still work. Prefer `SetupOnce` / `CleanUpOnce` when you need deterministic teardown (shared hosts, fixed ports, etc.). ### SetupOnce and CleanUpOnce Class-scoped fixture hooks run once around a class's tests (not per test): ```csharp public static class MyTests { private static ApiTestServerApplication? Host; public static async Task SetupOnce() { // Runs once before the first test that actually executes Host = new ApiTestServerApplication(); await Task.CompletedTask; } public static async Task CleanUpOnce() { // Runs once after the last test, only if SetupOnce ran if (Host is IAsyncDisposable disposable) await disposable.DisposeAsync(); Host = null; } public static async Task Test1() { /* uses Host */ await Task.CompletedTask; } public static async Task Test2() { /* uses Host */ await Task.CompletedTask; } } ``` **Behavior:** - **Lazy:** `SetupOnce` runs immediately before the first method that actually executes. A class whose tests are all `[Skip]`ped or method-tag-filtered out never invokes the hooks. - **Dispose:** Authors dispose shared fixtures explicitly in `CleanUpOnce`. The framework does not auto-scan fields for `IAsyncDisposable`. - **Cleanup guarantee:** `CleanUpOnce` runs in a try/finally around the class loop only if `SetupOnce` was invoked (success or failure). - **`SetupOnce` failure:** remaining discovered tests are reported Failed with the hook exception; test bodies do not run. `CleanUpOnce` still runs if setup was attempted. - **`CleanUpOnce` failure:** tests keep their real results; a synthetic failed node `{ClassFullName}.CleanUpOnce` is emitted so the run fails (exit code 1). - **Signature:** hooks must be `public static Task` with no parameters. A method *named* `SetupOnce`/`CleanUpOnce` with a non-conforming signature fails the class (no silent ignore). - **`RunSingleTestAsync` bypass:** class hooks apply only through the class-loop entry points (`RunTests` / `RunAllTests` / `RunTestsAsync`). Direct `RunSingleTestAsync` calls run per-test `Setup`/`CleanUp` only; callers own fixture lifetime. - **Timeout caveat:** `[Timeout]` abandons the still-running test task via `Task.WhenAny`. That task may touch a shared fixture after `CleanUpOnce` disposes it. Prefer cooperative cancellation if this becomes an issue in practice. ### Session fixtures (cross-class) When multiple test classes need the same expensive resource (e.g. a shared Aspire `DistributedApplication`), register a **session fixture** once and resolve it from each class. Session scope amortizes create cost across classes under M.T.P. or `RunAllTests`. ```csharp public sealed class AppHostFixture : IAsyncDisposable { public static async Task CreateAsync() { // boot host return new AppHostFixture(); } public async ValueTask DisposeAsync() { /* tear down */ } } [ModuleInitializer] internal static void Register() { RegisterTests(); RegisterTests(); RegisterSessionFixture(); } // In each class that needs the host public static async Task SetupOnce() { Host = await SessionFixture.GetAsync(); } public static async Task CleanUpOnce() { // Do NOT dispose the session fixture — the session owns dispose. Host = null; } ``` **Contract:** | API | Role | |-----|------| | `RegisterSessionFixture()` | Explicit registration (ModuleInitializer); requires `public static Task CreateAsync()` and `IAsyncDisposable` | | `SessionFixture.GetAsync()` | Lazy resolve within an active session | | Session end | Disposes all created instances | **Lifetime:** | Host | Boundary | Create | Dispose | |------|----------|--------|---------| | **M.T.P. run** | CreateTestSession → CloseTestSession | Lazy on first `GetAsync` | All created in CloseTestSession | | **M.T.P. discovery** | Session still opens/closes | Never (no `GetAsync`) | No-op | | **`RunAllTests`** | Synthetic session wrap | Lazy across classes | After last registered class | | **Lone `RunTestsAsync`** | Session-of-one if none active | Lazy within that class | End of that call | - Double-registration of the same `T` fails fast. - Unregistered `GetAsync` throws a teaching error (not null). - Classes that never call `GetAsync` never create the fixture. - Prefer class `SetupOnce`/`CleanUpOnce` when the fixture is per-class only; use session fixtures only when sharing across classes pays off. ## Documentation See the [developer documentation](documentation/) for advanced usage, attributes, and best practices. ## Building from Source 1. Clone the repository. 2. Run `dotnet build`. 3. Run tests with `dotnet test tests/timewarp-jaribu/multi-file-runners/mtp-runner/`. ## Contributing Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. ## License [MIT License](license) --- --- title: TimeWarp.SourceGenerators description: Package Description type: package latest: 1.0.0-beta.11 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-source-generators --- Package Description | | | |---|---| | Latest prerelease | `1.0.0-beta.11` | | Stable release | none yet (prerelease only) | | Downloads | 3,677 | | Last published | 2026-09-20 | | Target frameworks | `.NETStandard2.0` | ## Install ```sh dotnet add package TimeWarp.SourceGenerators --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.SourceGenerators) · [Source](https://github.com/TimeWarpEngineering/timewarp-source-generators) --- [![Dotnet](https://img.shields.io/badge/dotnet-6.0-blue)](https://dotnet.microsoft.com) [![Stars](https://img.shields.io/github/stars/TimeWarpEngineering/timewarp-source-generators?logo=github)](https://github.com/TimeWarpEngineering/timewarp-source-generators) [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) [![workflow](https://github.com/TimeWarpEngineering/timewarp-source-generators/actions/workflows/workflow.yml/badge.svg)](https://github.com/TimeWarpEngineering/timewarp-source-generators/actions) [![nuget](https://img.shields.io/nuget/v/TimeWarp.SourceGenerators?logo=nuget)](https://www.nuget.org/packages/TimeWarp.SourceGenerators/) [![nuget](https://img.shields.io/nuget/dt/TimeWarp.SourceGenerators?logo=nuget)](https://www.nuget.org/packages/TimeWarp.SourceGenerators/) [![Issues Open](https://img.shields.io/github/issues/TimeWarpEngineering/timewarp-source-generators.svg?logo=github)](https://github.com/TimeWarpEngineering/timewarp-source-generators/issues) [![Forks](https://img.shields.io/github/forks/TimeWarpEngineering/timewarp-source-generators)](https://github.com/TimeWarpEngineering/timewarp-source-generators) [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-source-generators.svg?style=flat-square&logo=github)](https://github.com/TimeWarpEngineering/timewarp-source-generators/issues) [![Twitter](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2FTimeWarpEngineering%2Ftimewarp-source-generators)](https://twitter.com/intent/tweet?url=https://github.com/TimeWarpEngineering/timewarp-source-generators) [![Twitter](https://img.shields.io/twitter/follow/StevenTCramer.svg)](https://twitter.com/intent/follow?screen_name=StevenTCramer) [![Twitter](https://img.shields.io/twitter/follow/TheFreezeTeam1.svg)](https://twitter.com/intent/follow?screen_name=TheFreezeTeam1) # TimeWarp.SourceGenerators ![TimeWarp Logo](assets/logo.png) TimeWarp.SourceGenerators is our collection of source generators. ## Give a Star! :star: If you like or are using this project please give it a star. Thank you! ## Features ### Interface Delegation Generator Implements Delphi-style interface delegation for C#. Mark fields or properties with `[Implements]` to automatically generate forwarding methods for interface members. #### Usage ```csharp public partial class DataService : ILogger, IDataProcessor { [Implements] private readonly ILogger Logger; [Implements] private readonly IDataProcessor Processor; public DataService(ILogger logger, IDataProcessor processor) { Logger = logger; Processor = processor; } // Optionally override specific methods public string Process(string input) { // Custom implementation return Processor.Process(input.ToUpper()); } } ``` The generator will automatically create forwarding implementations for all interface methods and properties, except those you explicitly implement. #### Requirements - Class must be marked as `partial` - Class must implement the interface being delegated - Field/property type must be the interface or implement the interface #### Diagnostics - **TW0004**: Class must be partial for interface delegation - **TW0005**: Class does not implement the delegated interface - **TW0006**: Multiple fields delegate the same interface ### File Name Rule Analyzer Enforces kebab-case naming for C# files, including multi-dot partials (e.g. `application-state.close-modal.cs`) when every segment is kebab-case. #### Configuration Configure exceptions in `.editorconfig`: ```ini [*.cs] dotnet_diagnostic.TW0001.excluded_files = Program.cs;Startup.cs;*.Designer.cs ``` ### Global Usings Rule Analyzer (TW0007) Reports file-level `using` directives that should move to kebab-case `global-usings.cs`, including usings **after** a file-scoped `namespace X;` (the gap in BDSoftware GlobalUsingsAnalyzer 1.4.0). Disabled by default. ```ini [*.cs] dotnet_diagnostic.TW0007.severity = warning dotnet_diagnostic.TW0007.filename = global-usings.cs ``` See [configure-global-usings-analyzer.md](./documentation/developer/how-to-guides/configure-global-usings-analyzer.md). ### Diagnostic ID prefixes (SSOT) | Prefix | Package | |--------|---------| | **TW** | **TimeWarp.SourceGenerators** (this package) — shipped diagnostics **TW0001**–**TW0007** | | **TWA** | **TimeWarp Architecture** only — not used by this package | Do **not** enable, suppress, or configure this package’s rules with Architecture IDs such as `TWA001` / `TWA*`. File-name kebab-case is **TW0001** (`dotnet_diagnostic.TW0001.*`, `#pragma warning disable TW0001`). Architecture `TWA*` keys do not apply here. ## Getting started To quickly get started I recommend reviewing the samples in this repo. ## Installation ```console dotnet add package TimeWarp.SourceGenerators ``` You can see the latest NuGet packages from the official [TimeWarp NuGet page](https://www.nuget.org/profiles/TimeWarp.Enterprises). * [TimeWarp.SourceGenerators](https://www.nuget.org/packages/TimeWarp.SourceGenerators/) [![nuget](https://img.shields.io/nuget/v/TimeWarp.SourceGenerators?logo=nuget)](https://www.nuget.org/packages/TimeWarp.SourceGenerators/) ## Releases See the [Release Notes](./documentation/releases.md) ## Unlicense [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-source-generators.svg?style=flat-square&logo=github)](https://unlicense.org) ## Contributing Time is of the essence. Before developing a Pull Request I recommend opening a [discussion](https://github.com/TimeWarpEngineering/timewarp-source-generators/discussions). Please feel free to make suggestions and help out with the [documentation](https://timewarpengineering.github.io/timewarp-source-generators/). Please refer to [Markdown](http://daringfireball.net/projects/markdown/) for how to write markdown files. ## Contact Sometimes the github notifications get lost in the shuffle. If you file an [issue](https://github.com/TimeWarpEngineering/timewarp-source-generators/issues) and don't get a response in a timely manner feel free to ping on our [Discord server](https://discord.gg/A55JARGKKP). [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) --- --- title: TimeWarp.Cli description: Fluent API for elegant C# scripting with pipeline support type: package latest: 0.6.0-rc9 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-amuru --- Fluent API for elegant C# scripting with pipeline support | | | |---|---| | Latest prerelease | `0.6.0-rc9` | | Stable release | none yet (prerelease only) | | Downloads | 3,527 | | Last published | 2025-07-17 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Cli --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Cli) · [Source](https://github.com/TimeWarpEngineering/timewarp-amuru) · Part of the [timewarp-amuru](/projects/timewarp-amuru/) family See [TimeWarp.Amuru](/packages/timewarp.amuru/) for the full documentation of this family. --- --- title: TimeWarp.Nuru.DevCli description: Reusable dev-cli endpoints for TimeWarp repositories - clean, self-install, check-version type: package latest: 3.0.0 stable: 3.0.0 repository: https://github.com/TimeWarpEngineering/timewarp-nuru --- Reusable dev-cli endpoints for TimeWarp repositories - clean, self-install, check-version | | | |---|---| | Latest stable | `3.0.0` | | Downloads | 3,298 | | Last published | 2026-10-14 | ## Install ```sh dotnet add package TimeWarp.Nuru.DevCli ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Nuru.DevCli) · [Source](https://github.com/TimeWarpEngineering/timewarp-nuru) · Part of the [timewarp-nuru](/projects/timewarp-nuru/) family See [TimeWarp.Nuru](/packages/timewarp.nuru/) for the full documentation of this family. --- --- title: TimeWarp.Multiavatar description: A .NET library for generating unique, deterministic avatars from any text input. Creates beautiful SVG avatars with 48 billion unique variations based on SHA256 hashing. type: package latest: 1.0.0-beta.13 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-multiavatar --- A .NET library for generating unique, deterministic avatars from any text input. Creates beautiful SVG avatars with 48 billion unique variations based on SHA256 hashing. | | | |---|---| | Latest prerelease | `1.0.0-beta.13` | | Stable release | none yet (prerelease only) | | Downloads | 2,478 | | Last published | 2025-10-11 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Multiavatar --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Multiavatar) · [Source](https://github.com/TimeWarpEngineering/timewarp-multiavatar) --- # TimeWarp.Multiavatar A .NET port of [Multiavatar](https://github.com/multiavatar/Multiavatar) by [Gie Katon](https://github.com/giekaton). We make no claim to Multiavatar in any way. See the Multiavatar license here: https://multiavatar.com/license ## .NET Installation ```bash dotnet add package TimeWarp.Multiavatar ``` ## .NET Usage ```csharp using TimeWarp.Multiavatar; // Generate avatar SVG from any text string svg = MultiavatarGenerator.Generate("user@example.com"); // Generate without environment circle string svgNoEnv = MultiavatarGenerator.Generate("username", sansEnv: true); // Save to file File.WriteAllText("avatar.svg", svg); ``` ## Command Line Tool Install the TimeWarp.Ganda.Tool: ```bash dotnet tool install --global TimeWarp.Ganda.Tool timewarp multiavatar "user@example.com" --output avatar.svg ``` ## Standalone Executable ```bash multiavatar "user@example.com" --output avatar.svg multiavatar "username" --no-env multiavatar "test" --output-hash ``` --- # Original Multiavatar README The following is the original README from https://github.com/multiavatar/Multiavatar --- # Multiavatar # [Multiavatar](https://multiavatar.com) is a multicultural avatar maker. Multiavatar represents people from multiple races, multiple cultures, multiple age groups, multiple worldviews and walks of life. In total, it is possible to generate **12,230,590,464** unique avatars. ### Installation and usage ### Include the script and pass any string to the 'multiavatar' function. It will return the SVG code for the avatar. Using npm: `npm i @multiavatar/multiavatar` CommonJS: ``` const multiavatar = require('@multiavatar/multiavatar') let svgCode = multiavatar('Binx Bond') ``` ES Module: ``` import multiavatar from '@multiavatar/multiavatar/esm' let svgCode = multiavatar('Binx Bond') ``` Using the script tag: ``` ``` Include from CDN: ``` ``` ### Info ### The initial unique 48 (16x3) avatar characters are designed to work as the source from which all 12 billion avatars are generated. You can find them in the `svg` folder. These initial characters can be edited with a vector drawing program, such as Inkscape. They are in grayscale, since the color is applied later by the script, and grayscale is better for shapes design. Every avatar consists of 6 parts: - Environment - Clothes - Head - Mouth - Eyes - Top Also, there are different versions of different parts. In some final avatars, additional parts are added or replaced. ### API ### To get an avatar as SVG code, add the avatar's ID to the URL: ``` https://api.multiavatar.com/Binx Bond ``` To get an avatar as SVG file, add .svg to the URL: ``` https://api.multiavatar.com/Binx Bond.svg ``` To get an avatar as PNG file, add .png to the URL: ``` https://api.multiavatar.com/Binx Bond.png ``` ### Avatar Viewer ### To see all 48 default avatars and their versions, use the Avatar Viewer: ``` https://multiavatar.com/avatar-viewer ``` ### License ### You can use Multiavatar for free, as long as the conditions described in the [LICENSE](https://multiavatar.com/license) are followed. ### More info ### For more information and extended functionality, visit [multiavatar.com](https://multiavatar.com) --- ## License for this .NET Port We make no claim to Multiavatar in any way. See the Multiavatar license here: https://multiavatar.com/license The original Multiavatar project allows free use for both commercial and non-commercial purposes. Please review their license for complete terms. --- --- title: TimeWarp.OptionsValidation description: Integrates FluentValidation with Microsoft.Extensions.Options for configuration validation at startup. type: package latest: 1.0.0-beta.5 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-options-validation --- Integrates FluentValidation with Microsoft.Extensions.Options for configuration validation at startup. | | | |---|---| | Latest prerelease | `1.0.0-beta.5` | | Stable release | none yet (prerelease only) | | Downloads | 2,363 | | Last published | 2026-06-10 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.OptionsValidation --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.OptionsValidation) · [Source](https://github.com/TimeWarpEngineering/timewarp-options-validation) --- [![Dotnet](https://img.shields.io/badge/dotnet-10.0-blue)](https://dotnet.microsoft.com) [![Stars](https://img.shields.io/github/stars/TimeWarpEngineering/timewarp-options-validation?logo=github)](https://github.com/TimeWarpEngineering/timewarp-options-validation) [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) [![workflow](https://github.com/TimeWarpEngineering/timewarp-options-validation/actions/workflows/workflow.yml/badge.svg)](https://github.com/TimeWarpEngineering/timewarp-options-validation/actions) [![nuget](https://img.shields.io/nuget/v/TimeWarp.OptionsValidation?logo=nuget)](https://www.nuget.org/packages/TimeWarp.OptionsValidation/) [![nuget](https://img.shields.io/nuget/dt/TimeWarp.OptionsValidation?logo=nuget)](https://www.nuget.org/packages/TimeWarp.OptionsValidation/) [![Issues Open](https://img.shields.io/github/issues/TimeWarpEngineering/timewarp-options-validation.svg?logo=github)](https://github.com/TimeWarpEngineering/timewarp-options-validation/issues) [![Forks](https://img.shields.io/github/forks/TimeWarpEngineering/timewarp-options-validation)](https://github.com/TimeWarpEngineering/timewarp-options-validation) [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-options-validation.svg?style=flat-square&logo=github)](https://github.com/TimeWarpEngineering/timewarp-options-validation/issues) [![Twitter](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2FTimeWarpEngineering%2Ftimewarp-options-validation)](https://twitter.com/intent/tweet?url=https://github.com/TimeWarpEngineering/timewarp-options-validation) [![Twitter](https://img.shields.io/twitter/follow/StevenTCramer.svg)](https://twitter.com/intent/follow?screen_name=StevenTCramer) [![Twitter](https://img.shields.io/twitter/follow/TheFreezeTeam1.svg)](https://twitter.com/intent/follow?screen_name=TheFreezeTeam1) # TimeWarp.OptionsValidation ![TimeWarp Logo](assets/logo.png) TimeWarp.OptionsValidation integrates FluentValidation with Microsoft.Extensions.Options to provide automatic validation of your configuration settings at application startup. ## Why Use This Library? Configuration errors are a common source of runtime failures. TimeWarp.OptionsValidation helps you **fail fast** by validating all configuration settings when your application starts, rather than discovering errors when the configuration is first accessed (which could be hours or days later in production). **Key Benefits:** - Validates configuration settings using FluentValidation rules - Integrates seamlessly with Microsoft.Extensions.Options - Catches configuration errors at startup, not at runtime - Provides clear, actionable error messages - Supports both IConfiguration binding and programmatic configuration ## Give a Star! :star: If you like or are using this project please give it a star. Thank you! ## Installation ```console dotnet add package TimeWarp.OptionsValidation ``` You can see the latest NuGet packages from the official [TimeWarp NuGet page](https://www.nuget.org/profiles/TimeWarp.Enterprises). * [TimeWarp.OptionsValidation](https://www.nuget.org/packages/TimeWarp.OptionsValidation/) [![nuget](https://img.shields.io/nuget/v/TimeWarp.OptionsValidation?logo=nuget)](https://www.nuget.org/packages/TimeWarp.OptionsValidation/) ## Usage ### Basic Setup with Automatic Startup Validation Use `AddFluentValidatedOptions()` which returns `OptionsBuilder`, allowing you to chain with `.ValidateOnStart()` for automatic startup validation. #### 1. Define Your Options Class with Nested Validator ```csharp using FluentValidation; public class DatabaseOptions { public string ConnectionString { get; set; } = string.Empty; public int MaxRetries { get; set; } public int CommandTimeout { get; set; } // Nested validator - sealed and only used here public sealed class Validator : AbstractValidator { public Validator() { RuleFor(x => x.ConnectionString) .NotEmpty() .WithMessage("Database connection string is required"); RuleFor(x => x.MaxRetries) .GreaterThan(0) .LessThanOrEqualTo(10) .WithMessage("MaxRetries must be between 1 and 10"); RuleFor(x => x.CommandTimeout) .GreaterThanOrEqualTo(30) .WithMessage("CommandTimeout must be at least 30 seconds"); } } } ``` #### 2. Register with Automatic Startup Validation ```csharp using Microsoft.Extensions.DependencyInjection; var builder = WebApplication.CreateBuilder(args); // Register options with automatic startup validation builder.Services .AddFluentValidatedOptions(builder.Configuration) .ValidateOnStart(); // ✅ Validates when host starts, throws on error var app = builder.Build(); app.Run(); // Validation happens automatically before this runs ``` **What this does:** - Binds the `DatabaseOptions` section from appsettings.json - Registers the FluentValidation validator - **Validates configuration at startup** (before `app.Run()`) - **Fails fast with clear error messages** if configuration is invalid - No manual validation calls needed! ### Configuration Binding The library automatically discovers which configuration section to bind based on simple, predictable rules. #### Default: Class Name By default, the library uses the **class name** as the configuration section name: ```csharp public class DatabaseOptions { public string ConnectionString { get; set; } = string.Empty; // ... } ``` Binds to `"DatabaseOptions"` section: ```json { "DatabaseOptions": { "ConnectionString": "Server=localhost;Database=myapp;", "MaxRetries": 3, "CommandTimeout": 30 } } ``` ```csharp // Automatically binds to "DatabaseOptions" section services .AddFluentValidatedOptions(configuration) .ValidateOnStart(); ``` #### Custom Configuration Key with `[ConfigurationKey]` Attribute Override the default by decorating your options class with `[ConfigurationKey]`: **Simple Configuration Key:** ```csharp using TimeWarp.OptionsValidation; [ConfigurationKey("Database")] public class DatabaseOptions { public string ConnectionString { get; set; } = string.Empty; // ... } ``` Binds to `"Database"` section: ```json { "Database": { "ConnectionString": "Server=localhost;Database=myapp;", "MaxRetries": 3, "CommandTimeout": 30 } } ``` **Hierarchical Key with Colon Separator:** ```csharp [ConfigurationKey("MyApp:Settings:Database")] public class DatabaseOptions { public string ConnectionString { get; set; } = string.Empty; // ... } ``` Binds to nested `"MyApp" → "Settings" → "Database"` path: ```json { "MyApp": { "Settings": { "Database": { "ConnectionString": "Server=localhost;Database=myapp;", "MaxRetries": 3, "CommandTimeout": 30 } } } } ``` ```csharp // Automatically binds to configuration key specified in attribute services .AddFluentValidatedOptions(configuration) .ValidateOnStart(); ``` #### Advanced: Manual Section Binding For dynamic section paths or complex scenarios not covered by the attribute: ```csharp // Manual binding for runtime-determined paths string environment = builder.Environment.EnvironmentName; services.AddOptions() .Bind(configuration.GetSection($"{environment}:Database")) .ValidateFluentValidation() .ValidateOnStart(); ``` **Automatic Configuration Key Resolution Summary:** - ✅ Uses class name: `DatabaseOptions` → `"DatabaseOptions"` - ✅ Simple override: `[ConfigurationKey("Database")]` → `"Database"` - ✅ Hierarchical paths: `[ConfigurationKey("MyApp:Settings:Database")]` → `"MyApp" → "Settings" → "Database"` - ❌ Does NOT trim suffixes like "Options" automatically - ❌ Does NOT pluralize names automatically ### Programmatic Configuration You can also configure options programmatically without IConfiguration: ```csharp services .AddFluentValidatedOptions(options => { options.ConnectionString = "Server=localhost;Database=myapp;"; options.MaxRetries = 3; options.CommandTimeout = 30; }) .ValidateOnStart(); ``` ### Complete Startup Example ```csharp using Microsoft.Extensions.DependencyInjection; var builder = WebApplication.CreateBuilder(args); // Register multiple validated options with automatic startup validation builder.Services .AddFluentValidatedOptions(builder.Configuration) .ValidateOnStart(); builder.Services .AddFluentValidatedOptions(builder.Configuration) .ValidateOnStart(); builder.Services .AddFluentValidatedOptions(builder.Configuration) .ValidateOnStart(); var app = builder.Build(); app.Run(); // All options validated before this runs ``` If any configuration is invalid, the application will **fail to start** with clear error messages indicating exactly which settings are invalid and why. ### Without Startup Validation If you don't need automatic startup validation, simply omit `.ValidateOnStart()`: ```csharp // Validates on first access instead of at startup services.AddFluentValidatedOptions(configuration); // No .ValidateOnStart() call - validation happens lazily ``` This approach validates options when they're first accessed rather than at application startup. ## Features - **Automatic Startup Validation**: Use `.ValidateOnStart()` to fail fast on invalid configuration - **Automatic Key Discovery**: Uses the class name as the configuration key by default - **Custom Key Mapping**: Use `[ConfigurationKey]` attribute to override the configuration key - **Hierarchical Keys**: Support for nested configuration paths using colon separators - **Seamless Integration**: Works with Microsoft.Extensions.Options infrastructure and `OptionsBuilder` - **FluentValidation Power**: Rich validation rules, custom validators, conditional validation - **Clear Error Messages**: Detailed, actionable error messages from FluentValidation - **Type Safety**: Strongly-typed options with compile-time checking - **Flexible API**: Choose between fluent API (with `.ValidateOnStart()`) or simple registration ## Releases See the [Release Notes](./documentation/releases.md) ## Unlicense [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-options-validation.svg?style=flat-square&logo=github)](https://unlicense.org) ## Contributing Time is of the essence. Before developing a Pull Request I recommend opening a [discussion](https://github.com/TimeWarpEngineering/timewarp-options-validation/discussions). Please feel free to make suggestions and help out with the [documentation](https://timewarpengineering.github.io/timewarp-options-validation/). Please refer to [Markdown](http://daringfireball.net/projects/markdown/) for how to write markdown files. ## Contact Sometimes the github notifications get lost in the shuffle. If you file an [issue](https://github.com/TimeWarpEngineering/timewarp-options-validation/issues) and don't get a response in a timely manner feel free to ping on our [Discord server](https://discord.gg/A55JARGKKP). [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) --- --- title: TimeWarp.Amuru.Tools description: Fluent builders for common CLI tools (dotnet, git, fzf) plus TimeWarp repo services, built on TimeWarp.Amuru type: package latest: 2.0.0 stable: 2.0.0 repository: https://github.com/TimeWarpEngineering/timewarp-amuru --- Fluent builders for common CLI tools (dotnet, git, fzf) plus TimeWarp repo services, built on TimeWarp.Amuru | | | |---|---| | Latest stable | `2.0.0` | | Downloads | 1,716 | | Last published | 2026-10-14 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Amuru.Tools ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Amuru.Tools) · [Source](https://github.com/TimeWarpEngineering/timewarp-amuru) · Part of the [timewarp-amuru](/projects/timewarp-amuru/) family See [TimeWarp.Amuru](/packages/timewarp.amuru/) for the full documentation of this family. --- --- title: TimeWarp.Foundation.Domain description: Domain primitives (Enumeration, Entity, IAggregateRoot) for the TimeWarp foundation layer. Dependency-free. type: package latest: 2.0.0-beta.19 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-architecture --- Domain primitives (Enumeration, Entity, IAggregateRoot) for the TimeWarp foundation layer. Dependency-free. | | | |---|---| | Latest prerelease | `2.0.0-beta.19` | | Stable release | none yet (prerelease only) | | Downloads | 1,451 | | Last published | 2026-09-16 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Foundation.Domain --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Foundation.Domain) · [Source](https://github.com/TimeWarpEngineering/timewarp-architecture) · Part of the [timewarp-architecture](/projects/timewarp-architecture/) family See [TimeWarp.Architecture](/packages/timewarp.architecture/) for the full documentation of this family. --- --- title: TimeWarp.Nuru.Search description: CLI search tool for indexing and searching Nuru CLI endpoints across multiple CLIs type: package latest: 3.0.0 stable: 3.0.0 repository: https://github.com/TimeWarpEngineering/timewarp-nuru --- CLI search tool for indexing and searching Nuru CLI endpoints across multiple CLIs | | | |---|---| | Latest stable | `3.0.0` | | Downloads | 1,397 | | Last published | 2026-10-14 | ## Install ```sh dnx TimeWarp.Nuru.Search -- --help dotnet tool install -g TimeWarp.Nuru.Search ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Nuru.Search) · [Source](https://github.com/TimeWarpEngineering/timewarp-nuru) · Part of the [timewarp-nuru](/projects/timewarp-nuru/) family See [TimeWarp.Nuru](/packages/timewarp.nuru/) for the full documentation of this family. --- --- title: TimeWarp.Modules description: Lightweight IModule composition abstraction used by the TimeWarp foundation layer. type: package latest: 2.0.0-beta.19 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-architecture --- Lightweight IModule composition abstraction used by the TimeWarp foundation layer. | | | |---|---| | Latest prerelease | `2.0.0-beta.19` | | Stable release | none yet (prerelease only) | | Downloads | 1,350 | | Last published | 2026-09-16 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Modules --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Modules) · [Source](https://github.com/TimeWarpEngineering/timewarp-architecture) · Part of the [timewarp-architecture](/projects/timewarp-architecture/) family See [TimeWarp.Architecture](/packages/timewarp.architecture/) for the full documentation of this family. --- --- title: TimeWarp.QuickBooks description: QuickBooks Online API integration with OAuth authentication and data access capabilities. type: package latest: 1.0.0-beta.3 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-quickbooks --- QuickBooks Online API integration with OAuth authentication and data access capabilities. | | | |---|---| | Latest prerelease | `1.0.0-beta.3` | | Stable release | none yet (prerelease only) | | Downloads | 1,336 | | Last published | 2025-10-21 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.QuickBooks --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.QuickBooks) · [Source](https://github.com/TimeWarpEngineering/timewarp-quickbooks) --- [![Dotnet](https://img.shields.io/badge/dotnet-9.0-blue)](https://dotnet.microsoft.com) [![Stars](https://img.shields.io/github/stars/TimeWarpEngineering/timewarp-quickbooks?logo=github)](https://github.com/TimeWarpEngineering/timewarp-quickbooks) [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) [![Build Status](https://github.com/TimeWarpEngineering/timewarp-quickbooks/actions/workflows/ci-build.yml/badge.svg)](https://github.com/TimeWarpEngineering/timewarp-quickbooks/actions/workflows/ci-build.yml) [![NuGet](https://img.shields.io/nuget/v/TimeWarp.QuickBooks?logo=nuget)](https://www.nuget.org/packages/TimeWarp.QuickBooks/) [![NuGet](https://img.shields.io/nuget/dt/TimeWarp.QuickBooks?logo=nuget)](https://www.nuget.org/packages/TimeWarp.QuickBooks/) [![Issues Open](https://img.shields.io/github/issues/TimeWarpEngineering/timewarp-quickbooks.svg?logo=github)](https://github.com/TimeWarpEngineering/timewarp-quickbooks/issues) [![Forks](https://img.shields.io/github/forks/TimeWarpEngineering/timewarp-quickbooks)](https://github.com/TimeWarpEngineering/timewarp-quickbooks) [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-quickbooks.svg?style=flat-square&logo=github)](https://github.com/TimeWarpEngineering/timewarp-quickbooks/blob/master/LICENSE) [![Twitter](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2FTimeWarpEngineering%2Ftimewarp-quickbooks)](https://twitter.com/intent/tweet?url=https://github.com/TimeWarpEngineering/timewarp-quickbooks) [![Twitter](https://img.shields.io/twitter/follow/StevenTCramer.svg)](https://twitter.com/intent/follow?screen_name=StevenTCramer) [![Twitter](https://img.shields.io/twitter/follow/TheFreezeTeam1.svg)](https://twitter.com/intent/follow?screen_name=TheFreezeTeam1) # TimeWarp.QuickBooks ![TimeWarp Logo](assets/logo.svg) TimeWarp.QuickBooks is a .NET library for QuickBooks Online integration. ## Give a Star! :star: If you like or are using this project please give it a star. Thank you! ## Features - Easy authentication with QuickBooks Online API - Simple interfaces for common QuickBooks operations - Comprehensive testing with TimeWarp.Fixie - Designed with modern .NET practices ## Getting started To quickly get started I recommend reviewing the samples in this repo. ## Installation ```console dotnet add package TimeWarp.QuickBooks ``` You can see the latest NuGet packages from the official [TimeWarp NuGet page](https://www.nuget.org/profiles/TimeWarp.Enterprises). * [TimeWarp.QuickBooks](https://www.nuget.org/packages/TimeWarp.QuickBooks/) [![NuGet](https://img.shields.io/nuget/v/TimeWarp.QuickBooks?logo=nuget)](https://www.nuget.org/packages/TimeWarp.QuickBooks/) ## CI/CD Pipeline This project uses GitHub Actions for continuous integration and deployment: - **CI Build**: Runs on pull requests to validate code quality - **Release Build**: Automatically publishes new versions to NuGet when pushed to the master branch ### Required GitHub Secrets To use the GitHub Actions workflows, you need to configure the following secret in your repository: - `PUBLISH_TO_NUGET_ORG`: Your NuGet API key for publishing packages ## Documentation Comprehensive documentation is available in the Documentation directory: - [User Documentation](Documentation/User/Overview.md) - How to use the library - [Developer Documentation](Documentation/Developer/Overview.md) - How to contribute or extend the library ## Development Process This project follows the Kanban methodology for task management. You can find current work in the [Kanban](Kanban/ReadMe.md) directory. ### Running Tests ```console pwsh run-tests.ps1 ``` ## Contributing We welcome contributions! Please see our contribution guidelines for details. ## Unlicense [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-quickbooks.svg?style=flat-square&logo=github)](https://unlicense.org) ## Contact Sometimes the GitHub notifications get lost in the shuffle. If you file an [issue](https://github.com/TimeWarpEngineering/timewarp-quickbooks/issues) and don't get a response in a timely manner feel free to ping on our [Discord server](https://discord.gg/A55JARGKKP). [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) ## Acknowledgments - [TimeWarp.Fixie](https://github.com/TimeWarpEngineering/timewarp-fixie) for testing infrastructure --- --- title: TimeWarp.Foundation.Contracts description: Shared contracts, request/response markers, route/auth/query source generator, and common types for the TimeWarp foundation layer. type: package latest: 2.0.0-beta.19 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-architecture --- Shared contracts, request/response markers, route/auth/query source generator, and common types for the TimeWarp foundation layer. | | | |---|---| | Latest prerelease | `2.0.0-beta.19` | | Stable release | none yet (prerelease only) | | Downloads | 1,324 | | Last published | 2026-09-16 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Foundation.Contracts --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Foundation.Contracts) · [Source](https://github.com/TimeWarpEngineering/timewarp-architecture) · Part of the [timewarp-architecture](/projects/timewarp-architecture/) family See [TimeWarp.Architecture](/packages/timewarp.architecture/) for the full documentation of this family. --- --- title: TimeWarp.Foundation.Application description: Application-layer abstractions and TimeWarp.Mediator pipeline behaviors for the TimeWarp foundation layer. type: package latest: 2.0.0-beta.19 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-architecture --- Application-layer abstractions and TimeWarp.Mediator pipeline behaviors for the TimeWarp foundation layer. | | | |---|---| | Latest prerelease | `2.0.0-beta.19` | | Stable release | none yet (prerelease only) | | Downloads | 1,296 | | Last published | 2026-09-16 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Foundation.Application --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Foundation.Application) · [Source](https://github.com/TimeWarpEngineering/timewarp-architecture) · Part of the [timewarp-architecture](/projects/timewarp-architecture/) family See [TimeWarp.Architecture](/packages/timewarp.architecture/) for the full documentation of this family. --- --- title: TimeWarp.Foundation.Infrastructure description: Infrastructure services (date-time, current-user) and aggregate EF persistence (AggregateDbContext) for the TimeWarp foundation layer. type: package latest: 2.0.0-beta.19 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-architecture --- Infrastructure services (date-time, current-user) and aggregate EF persistence (AggregateDbContext) for the TimeWarp foundation layer. | | | |---|---| | Latest prerelease | `2.0.0-beta.19` | | Stable release | none yet (prerelease only) | | Downloads | 1,217 | | Last published | 2026-09-16 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Foundation.Infrastructure --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Foundation.Infrastructure) · [Source](https://github.com/TimeWarpEngineering/timewarp-architecture) · Part of the [timewarp-architecture](/projects/timewarp-architecture/) family See [TimeWarp.Architecture](/packages/timewarp.architecture/) for the full documentation of this family. --- --- title: TimeWarp.Foundation.Server description: ASP.NET server building blocks (modules, base endpoints, CORS, service discovery) for the TimeWarp foundation layer. type: package latest: 2.0.0-beta.19 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-architecture --- ASP.NET server building blocks (modules, base endpoints, CORS, service discovery) for the TimeWarp foundation layer. | | | |---|---| | Latest prerelease | `2.0.0-beta.19` | | Stable release | none yet (prerelease only) | | Downloads | 1,134 | | Last published | 2026-09-16 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Foundation.Server --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Foundation.Server) · [Source](https://github.com/TimeWarpEngineering/timewarp-architecture) · Part of the [timewarp-architecture](/projects/timewarp-architecture/) family See [TimeWarp.Architecture](/packages/timewarp.architecture/) for the full documentation of this family. --- --- title: TimeWarpRooTools description: TimeWarp Roo Code Tools type: package latest: 1.0.0-beta.2 stable: none repository: --- TimeWarp Roo Code Tools | | | |---|---| | Latest prerelease | `1.0.0-beta.2` | | Stable release | none yet (prerelease only) | | Downloads | 987 | | Last published | 2025-04-14 | ## Install ```sh dnx TimeWarpRooTools -- --help dotnet tool install -g TimeWarpRooTools --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarpRooTools) --- # TimeWarp Roo Tools (`roo`) **TimeWarp Roo Tools** is a command-line toolkit for TimeWarp development workflows. This repository serves as a placeholder for future CLI tools. Built with .NET 9.0, it's designed to streamline workflows for developers working with TimeWarp projects. This project is authored by Steven T. Cramer. ## Future Tools (TBD) This repository will be used for developing TimeWarp development tools. Currently, it serves as a placeholder for future CLI tools that will enhance the TimeWarp development experience. ## Prerequisites - **.NET SDK 9.0**: Required to install and run the tool. - **Visual Studio Code**: Optional, for using the `timewarp-roo` extension to automate setup. ## Installation ### Option 1: Via VS Code Extension (Recommended) The easiest way to install `roo` is with the `timewarp-roo` VS Code extension, which handles both the .NET SDK and tool installation. 1. **Install the C# Dev Kit Extension**: - Open VS Code. - Go to Extensions (`Ctrl+Shift+X` or `Cmd+Shift+X` on macOS). - Search for **C# Dev Kit** (published by Microsoft) and install it. - Follow the prompts to install the .NET SDK 9.0 if it's not already present. 2. **Install the `timewarp-roo` Extension**: - In VS Code, install the `timewarp-roo` extension from the Marketplace (once published) or sideload it: ```bash code --install-extension path/to/timewarp-roo-0.0.1.vsix ``` - On first activation, `timewarp-roo` will install `roo` globally using `dotnet tool install -g TimeWarpRooTools`. 3. **Verify Installation**: - Open a terminal (in VS Code or elsewhere) and run: ```bash roo --version ``` - Expected output: `1.0.0` ### Option 2: Manual Installation If you prefer not to use VS Code or the extension: 1. **Install .NET SDK 9.0**: - Download and install from [dotnet.microsoft.com](https://dotnet.microsoft.com/download/dotnet/9.0). 2. **Install the Tool**: - Run the following command to install `roo` globally from NuGet: ```bash dotnet tool install -g TimeWarpRooTools ``` - Or, if you've built it locally: ```bash cd Tools/TimewarpRooTools dotnet pack dotnet tool install --add-source ./nupkg -g TimeWarpRooTools ``` 3. **Verify Installation**: - Run: ```bash roo --version ``` - Expected output: `1.0.0` ## Commands - **`roo --version`**: - Displays the current version of the tool (e.g., `1.0.0`). - **`roo --check-update`**: - Forces a check for the latest version on NuGet and updates the local cache. - **`roo --no-check`**: - Skips the automatic version check (useful offline). ## Building from Source 1. **Clone the Repository**: ```bash git clone https://github.com/TimeWarpEngineering/timewarp-roo.git cd timewarp-roo/Tools/TimewarpRooTools ``` 2. **Build and Run**: ```bash dotnet build dotnet run -- --version ``` 3. **Pack as a Tool**: ```bash dotnet pack ``` ## Troubleshooting - **.NET 9.0 Not Found**: If the SDK isn't available, edit `TimeWarpRooTools.csproj` to use `net8.0` and retry. - **Installation Fails**: Ensure you have internet access and the correct .NET SDK version installed (`dotnet --list-sdks`). - **Command Not Found**: Verify `roo` is in your PATH after installation (`~/.dotnet/tools` on Unix-like systems, `%USERPROFILE%\.dotnet\tools` on Windows). ## Contributing Contributions are welcome! Fork the repo, make changes, and submit a pull request to [TimeWarpEngineering/timewarp-roo](https://github.com/TimeWarpEngineering/timewarp-roo). ## License This project is licensed under the MIT License. See [LICENSE](LICENSE) for details. ## Author - **Steven T. Cramer** --- --- title: TimeWarp.Architecture.Analyzers description: Roslyn convention analyzers for TimeWarp Architecture (TWA0002–0016, TWA0020–0024). Analyzer-only package; safe to reference from every project including contracts. type: package latest: 2.0.0-beta.19 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-architecture --- Roslyn convention analyzers for TimeWarp Architecture (TWA0002–0016, TWA0020–0024). Analyzer-only package; safe to reference from every project including contracts. | | | |---|---| | Latest prerelease | `2.0.0-beta.19` | | Stable release | none yet (prerelease only) | | Downloads | 985 | | Last published | 2026-09-16 | ## Install ```sh dotnet add package TimeWarp.Architecture.Analyzers --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Architecture.Analyzers) · [Source](https://github.com/TimeWarpEngineering/timewarp-architecture) · Part of the [timewarp-architecture](/projects/timewarp-architecture/) family See [TimeWarp.Architecture](/packages/timewarp.architecture/) for the full documentation of this family. --- --- title: TimeWarp.Architecture.Generators description: Roslyn source generators and diagnostics for TimeWarp Architecture (FastEndpoint, Page, StateAccess, mock-factory registry, TypedId, ingress route prefixes) — TWA0001 and TWA0017/0018/0019. Analyzer-o… type: package latest: 2.0.0-beta.19 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-architecture --- Roslyn source generators and diagnostics for TimeWarp Architecture (FastEndpoint, Page, StateAccess, mock-factory registry, TypedId, ingress route prefixes) — TWA0001 and TWA0017/0018/0019. Analyzer-only; attach only where generators should run — not repo-wide. | | | |---|---| | Latest prerelease | `2.0.0-beta.19` | | Stable release | none yet (prerelease only) | | Downloads | 978 | | Last published | 2026-09-16 | ## Install ```sh dotnet add package TimeWarp.Architecture.Generators --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Architecture.Generators) · [Source](https://github.com/TimeWarpEngineering/timewarp-architecture) · Part of the [timewarp-architecture](/projects/timewarp-architecture/) family See [TimeWarp.Architecture](/packages/timewarp.architecture/) for the full documentation of this family. --- --- title: TimeWarp.Jaribu.TestingPlatform description: Microsoft.Testing.Platform adapter for TimeWarp.Jaribu test framework type: package latest: 1.0.0-beta.15 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-jaribu --- Microsoft.Testing.Platform adapter for TimeWarp.Jaribu test framework | | | |---|---| | Latest prerelease | `1.0.0-beta.15` | | Stable release | none yet (prerelease only) | | Downloads | 948 | | Last published | 2026-08-03 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Jaribu.TestingPlatform --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Jaribu.TestingPlatform) · [Source](https://github.com/TimeWarpEngineering/timewarp-jaribu) · Part of the [timewarp-jaribu](/projects/timewarp-jaribu/) family See [TimeWarp.Jaribu](/packages/timewarp.jaribu/) for the full documentation of this family. --- --- title: TimeWarp.Architecture.Attributes description: Runtime marker attributes for TimeWarp Architecture generators (e.g. [ApiEndpoint], [assembly: ApiEndpointsEmbedded]) and convention opt-outs ([TypeStemIdentifier]). Public library — not a private dep… type: package latest: 2.0.0-beta.19 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-architecture --- Runtime marker attributes for TimeWarp Architecture generators (e.g. [ApiEndpoint], [assembly: ApiEndpointsEmbedded]) and convention opt-outs ([TypeStemIdentifier]). Public library — not a private dependency of the Generators package. | | | |---|---| | Latest prerelease | `2.0.0-beta.19` | | Stable release | none yet (prerelease only) | | Downloads | 924 | | Last published | 2026-09-16 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Architecture.Attributes --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Architecture.Attributes) · [Source](https://github.com/TimeWarpEngineering/timewarp-architecture) · Part of the [timewarp-architecture](/projects/timewarp-architecture/) family See [TimeWarp.Architecture](/packages/timewarp.architecture/) for the full documentation of this family. --- --- title: TimeWarp.Components description: Style-agnostic Blazor base components (DisplayComponent/ParentComponent, IAttributeComponent/IParentComponent) and CssBuilder. No state dependency. type: package latest: 1.0.0-beta.2 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-components --- Style-agnostic Blazor base components (DisplayComponent/ParentComponent, IAttributeComponent/IParentComponent) and CssBuilder. No state dependency. | | | |---|---| | Latest prerelease | `1.0.0-beta.2` | | Stable release | none yet (prerelease only) | | Downloads | 879 | | Last published | 2026-06-21 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Components --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Components) · [Source](https://github.com/TimeWarpEngineering/timewarp-components) --- # timewarp-components TimeWarp.Components — style-agnostic Blazor base components (DisplayComponent/ParentComponent, IAttributeComponent/IParentComponent) and CssBuilder. No state dependency. --- --- title: TimeWarp.Identity description: Principal identity (passkeys, agent keys, Entra-linked credentials, sessions/tokens, trust tiers) for TimeWarp applications. type: package latest: 2.0.0-beta.19 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-architecture --- Principal identity (passkeys, agent keys, Entra-linked credentials, sessions/tokens, trust tiers) for TimeWarp applications. | | | |---|---| | Latest prerelease | `2.0.0-beta.19` | | Stable release | none yet (prerelease only) | | Downloads | 766 | | Last published | 2026-09-16 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Identity --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Identity) · [Source](https://github.com/TimeWarpEngineering/timewarp-architecture) · Part of the [timewarp-architecture](/projects/timewarp-architecture/) family See [TimeWarp.Architecture](/packages/timewarp.architecture/) for the full documentation of this family. --- --- title: TimeWarp.Mediator.Generators description: Source generator for TimeWarp.Mediator: builds the message graph at compile time and emits a sealed, reflection-free, AOT-friendly IMediator plus per-scope ISender/IPublisher named pip… type: package latest: 14.0.0 stable: 14.0.0 repository: https://github.com/TimeWarpEngineering/timewarp-mediator --- Source generator for TimeWarp.Mediator: builds the message graph at compile time and emits a sealed, reflection-free, AOT-friendly IMediator plus per-scope ISender/IPublisher named pipelines and AddGeneratedMediator() registration. Bundles TimeWarp.Mediator.Analyzers (TWM001-TWM004) and reports TWM005-TWM011. | | | |---|---| | Latest stable | `14.0.0` | | Downloads | 370 | | Last published | 2026-10-13 | ## Install ```sh dotnet add package TimeWarp.Mediator.Generators ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Mediator.Generators) · [Source](https://github.com/TimeWarpEngineering/timewarp-mediator) · Part of the [timewarp-mediator](/projects/timewarp-mediator/) family See [TimeWarp.Mediator](/packages/timewarp.mediator/) for the full documentation of this family. --- --- title: TimeWarp.Mediator.Analyzers description: Roslyn analyzers for TimeWarp.Mediator message graphs: TWM001 (request with no handler), TWM002 (duplicate handler), TWM003 (scope mismatch), TWM004 (wrong-scope send). Already bundled in TimeWarp.Med… type: package latest: 14.0.0 stable: 14.0.0 repository: https://github.com/TimeWarpEngineering/timewarp-mediator --- Roslyn analyzers for TimeWarp.Mediator message graphs: TWM001 (request with no handler), TWM002 (duplicate handler), TWM003 (scope mismatch), TWM004 (wrong-scope send). Already bundled in TimeWarp.Mediator.Generators; reference this package directly only from libraries that do not run the generator. | | | |---|---| | Latest stable | `14.0.0` | | Downloads | 344 | | Last published | 2026-10-13 | ## Install ```sh dotnet add package TimeWarp.Mediator.Analyzers ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Mediator.Analyzers) · [Source](https://github.com/TimeWarpEngineering/timewarp-mediator) · Part of the [timewarp-mediator](/projects/timewarp-mediator/) family See [TimeWarp.Mediator](/packages/timewarp.mediator/) for the full documentation of this family. --- --- title: TimeWarp.402 description: Internet-native x402 payment (challenge, verify, settle, credits) for TimeWarp applications. type: package latest: 2.0.0-beta.19 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-architecture --- Internet-native x402 payment (challenge, verify, settle, credits) for TimeWarp applications. | | | |---|---| | Latest prerelease | `2.0.0-beta.19` | | Stable release | none yet (prerelease only) | | Downloads | 329 | | Last published | 2026-09-16 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.402 --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.402) · [Source](https://github.com/TimeWarpEngineering/timewarp-architecture) · Part of the [timewarp-architecture](/projects/timewarp-architecture/) family See [TimeWarp.Architecture](/packages/timewarp.architecture/) for the full documentation of this family. --- --- title: TimeWarp.Flexbox description: A pure C# implementation of the Flexbox layout algorithm for .NET applications type: package latest: 1.0.0 stable: 1.0.0 repository: https://github.com/TimeWarpEngineering/timewarp-flexbox --- A pure C# implementation of the Flexbox layout algorithm for .NET applications | | | |---|---| | Latest stable | `1.0.0` | | Downloads | 232 | | Last published | 2026-07-04 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Flexbox ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Flexbox) · [Source](https://github.com/TimeWarpEngineering/timewarp-flexbox) --- # TimeWarp.Flexbox A pure C# implementation of the Flexbox layout algorithm for .NET applications. TimeWarp.Flexbox is a from-scratch C# port of the algorithm behind Facebook's [Yoga](https://github.com/facebook/yoga) layout engine. It computes CSS-flexbox layouts (positions and sizes) for a tree of nodes — no UI framework required — and its behavior is verified against Yoga's own generated conformance suite (530 tests, LTR and RTL). The library has zero runtime dependencies and is fully **Native AOT and trimming compatible** (`IsAotCompatible`): no reflection, no dynamic code. A PublishAot smoke test runs in CI on every build. ## Installation ```bash dotnet add package TimeWarp.Flexbox ``` ```xml ``` ## Usage ```csharp using TimeWarp.Flexbox; // Create a flex container Node root = new(); root.Style.FlexDirection = FlexDirection.Row; root.Style.SetDimension(Dimension.Width, StyleSizeLength.Points(300)); root.Style.SetDimension(Dimension.Height, StyleSizeLength.Points(200)); // Add children that share the free space 1:2 Node left = new(); left.Style.FlexGrow = 1; root.InsertChild(left, 0); Node right = new(); right.Style.FlexGrow = 2; root.InsertChild(right, 1); // Calculate layout CalculateLayout.Calculate(root, float.NaN, float.NaN, Direction.LTR); // Read computed positions and sizes Console.WriteLine($"left: x={left.Layout.GetPosition(PhysicalEdge.Left)} width={left.Layout.GetDimension(Dimension.Width)}"); Console.WriteLine($"right: x={right.Layout.GetPosition(PhysicalEdge.Left)} width={right.Layout.GetDimension(Dimension.Width)}"); // left: x=0 width=100 // right: x=100 width=200 ``` Styles are set through `Node.Style`: - Dimensions: `SetDimension`, `SetMinDimension`, `SetMaxDimension` with `StyleSizeLength.Points(..)`, `.Percent(..)`, `.Auto` - Flex: `FlexDirection`, `FlexGrow`, `FlexShrink`, `FlexBasis`, `FlexWrap` - Alignment: `JustifyContent`, `AlignItems`, `AlignSelf`, `AlignContent` - Box model: `SetMargin`, `SetPadding`, `SetBorder` per `Edge`, `SetGap` per `Gutter` - Positioning: `PositionType` (relative/absolute/static) with `SetPosition` insets Results are read from `Node.Layout` after calling `CalculateLayout.Calculate` (or the equivalent instance convenience `root.CalculateLayout()`): `GetPosition(PhysicalEdge)` and `GetDimension(Dimension)`. ### Defaults Defaults match Yoga (not web CSS): `flex-direction: column`, `flex-shrink: 0`, `align-content: flex-start`, and `box-sizing: border-box`. Construct nodes with `new Node(new Config { UseWebDefaults = true })` for web-style defaults. ### Demo Run the visual demo to see computed layouts rendered as ASCII boxes, or as an HTML page comparing the engine's output against your browser's native flexbox: ```bash ./samples/layout-demo/layout-demo.cs # terminal ./samples/layout-demo/layout-demo.cs --html out.html # browser comparison ``` ## License MIT — see [LICENSE](LICENSE) for details. Behavior modeled on Facebook's [Yoga](https://github.com/facebook/yoga) (MIT, Copyright (c) Meta Platforms, Inc.). --- --- title: TimeWarp.Skills description: CLI for managing agent skill sources and syncing them to harness skill directories. type: package latest: 1.0.0-beta.23 stable: none repository: --- CLI for managing agent skill sources and syncing them to harness skill directories. Install with: dnx TimeWarp.Skills -- list or dotnet tool install -g TimeWarp.Skills | | | |---|---| | Latest prerelease | `1.0.0-beta.23` | | Stable release | none yet (prerelease only) | | Downloads | 193 | | Last published | 2026-08-13 | ## Install ```sh dnx TimeWarp.Skills -- --help dotnet tool install -g TimeWarp.Skills --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Skills) --- # TimeWarp.Skills CLI for managing agent **skill sources** and syncing them into harness skill directories (OpenCode, Claude, Grok, and other tools that load skills from a `skills/` folder). ## Install ```bash # Ephemeral (like npx) dnx TimeWarp.Skills -- list # Global tool dotnet tool install -g TimeWarp.Skills skills list ``` ## Config home | | Path | |--|------| | **Skills home (default)** | `~/.timewarp/skills/` | | **Config file** | `~/.timewarp/skills/config.json` | | **HTTP stage cache** | `~/.timewarp/skills/cache/skill-sources/` | | **Override** | `SKILLS_HOME` environment variable | Config holds skill sources and distribution targets only. ## Quick start ```bash # Add a skill from a local path (folder containing SKILL.md) skills add my-skill ~/projects/my-repo/skills/my-skill # Or from a GitHub tree URL skills add blazor-css \ https://github.com/TimeWarpEngineering/timewarp-architecture/tree/master/skills/blazor-css-strategy # Configure where skills are written (harness config dir → /skills/) skills target add opencode --env OPENCODE_CONFIG_DIR # or skills target add claude --path ~/.claude # Sync sources into all enabled targets skills sync # Inspect skills list skills targets skills audit ``` ## Commands | Command | Description | |---------|-------------| | `skills add ` | Register a source (path or GitHub tree URL) | | `skills list` | List configured sources | | `skills remove ` | Remove a source and prune managed copies | | `skills sync` | Copy sources into all enabled targets | | `skills audit` | Report drift (missing / stale / orphaned) | | `skills target add\|remove\|enable\|disable` | Manage distribution targets | | `skills targets` | List targets and resolution status | ## Source locators - **Local path** — absolute, `~/…`, or an existing relative directory that contains `SKILL.md` - **GitHub tree URL** — `https://github.com///tree//` ## License Unlicense — public domain. --- --- title: TimeWarp.Terminal.Layout description: Flexbox-composed terminal layouts for TimeWarp.Terminal widgets type: package latest: 1.0.2 stable: 1.0.2 repository: https://github.com/TimeWarpEngineering/timewarp-terminal --- Flexbox-composed terminal layouts for TimeWarp.Terminal widgets | | | |---|---| | Latest stable | `1.0.2` | | Downloads | 83 | | Last published | 2026-09-21 | | Target frameworks | `net10.0` | ## Install ```sh dotnet add package TimeWarp.Terminal.Layout ``` [NuGet](https://www.nuget.org/packages/TimeWarp.Terminal.Layout) · [Source](https://github.com/TimeWarpEngineering/timewarp-terminal) · Part of the [timewarp-terminal](/projects/timewarp-terminal/) family See [TimeWarp.Terminal](/packages/timewarp.terminal/) for the full documentation of this family. --- --- title: TimeWarp.State.Telemetry description: OpenTelemetry instrumentation for the TimeWarp.State mediator pipeline: action spans, timing, and opt-in AOT-safe state snapshots. type: package latest: 12.0.0-beta.13 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-state --- OpenTelemetry instrumentation for the TimeWarp.State mediator pipeline: action spans, timing, and opt-in AOT-safe state snapshots. | | | |---|---| | Latest prerelease | `12.0.0-beta.13` | | Stable release | none yet (prerelease only) | | Downloads | 34 | | Last published | 2026-10-13 | | Target frameworks | `net11.0` | ## Install ```sh dotnet add package TimeWarp.State.Telemetry --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.State.Telemetry) · [Source](https://github.com/TimeWarpEngineering/timewarp-state) · Part of the [timewarp-state](/projects/timewarp-state/) family See [TimeWarp.State](/packages/timewarp.state/) for the full documentation of this family. --- --- title: TimeWarp.State.Blazor description: Blazor components, JavaScript interop, and render subscriptions for TimeWarp.State. type: package latest: 12.0.0-beta.13 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-state --- Blazor components, JavaScript interop, and render subscriptions for TimeWarp.State. | | | |---|---| | Latest prerelease | `12.0.0-beta.13` | | Stable release | none yet (prerelease only) | | Downloads | 0 | | Last published | 2026-10-13 | | Target frameworks | `net11.0` | ## Install ```sh dotnet add package TimeWarp.State.Blazor --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.State.Blazor) · [Source](https://github.com/TimeWarpEngineering/timewarp-state) · Part of the [timewarp-state](/projects/timewarp-state/) family See [TimeWarp.State](/packages/timewarp.state/) for the full documentation of this family. --- --- title: TimeWarp.State.DevTools.Export description: Dev-only exporter that copies TimeWarp.State activity spans to the DevTools inspector. Not a production dependency. type: package latest: 12.0.0-beta.13 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-state --- Dev-only exporter that copies TimeWarp.State activity spans to the DevTools inspector. Not a production dependency. | | | |---|---| | Latest prerelease | `12.0.0-beta.13` | | Stable release | none yet (prerelease only) | | Downloads | 0 | | Last published | 2026-10-13 | | Target frameworks | `net11.0` | ## Install ```sh dotnet add package TimeWarp.State.DevTools.Export --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.State.DevTools.Export) · [Source](https://github.com/TimeWarpEngineering/timewarp-state) · Part of the [timewarp-state](/projects/timewarp-state/) family See [TimeWarp.State](/packages/timewarp.state/) for the full documentation of this family. --- --- title: TimeWarp.State.DevTools.Hosting description: Aspire hosting integration that adds the TimeWarp.State DevTools app and links it from the dashboard. type: package latest: 12.0.0-beta.13 stable: none repository: https://github.com/TimeWarpEngineering/timewarp-state --- Aspire hosting integration that adds the TimeWarp.State DevTools app and links it from the dashboard. | | | |---|---| | Latest prerelease | `12.0.0-beta.13` | | Stable release | none yet (prerelease only) | | Downloads | 0 | | Last published | 2026-10-13 | | Target frameworks | `net11.0` | ## Install ```sh dotnet add package TimeWarp.State.DevTools.Hosting --prerelease ``` [NuGet](https://www.nuget.org/packages/TimeWarp.State.DevTools.Hosting) · [Source](https://github.com/TimeWarpEngineering/timewarp-state) · Part of the [timewarp-state](/projects/timewarp-state/) family See [TimeWarp.State](/packages/timewarp.state/) for the full documentation of this family. --- --- title: timewarp-state description: The timewarp-state package family type: project repository: https://github.com/TimeWarpEngineering/timewarp-state --- 7 packages published from [timewarp-state](https://github.com/TimeWarpEngineering/timewarp-state). State management for .NET. Blazor components, JavaScript interop, and render subscriptions are in TimeWarp.State.Blazor. | Package | Latest | Downloads | Description | |---|---|---|---| | [TimeWarp.State](/packages/timewarp.state/) ⭐ | `12.0.0-beta.13` | 33,499 | State management for .NET. Blazor components, JavaScript interop, and render subscriptions are in TimeWarp.State.Blazor. | | [TimeWarp.State.Blazor](/packages/timewarp.state.blazor/) | `12.0.0-beta.13` | 0 | Blazor components, JavaScript interop, and render subscriptions for TimeWarp.State. | | [TimeWarp.State.DevTools.Export](/packages/timewarp.state.devtools.export/) | `12.0.0-beta.13` | 0 | Dev-only exporter that copies TimeWarp.State activity spans to the DevTools inspector. Not a production dependency. | | [TimeWarp.State.DevTools.Hosting](/packages/timewarp.state.devtools.hosting/) | `12.0.0-beta.13` | 0 | Aspire hosting integration that adds the TimeWarp.State DevTools app and links it from the dashboard. | | [TimeWarp.State.Plus](/packages/timewarp.state.plus/) | `12.0.0-beta.13` | 26,234 | TimeWarp.State.Plus extends TimeWarp.State and TimeWarp.State.Blazor with routing, persistence, and action tracking. | | [TimeWarp.State.Policies](/packages/timewarp.state.policies/) | `12.0.0-beta.13` | 9,800 | Policies for TimeWarp State management library | | [TimeWarp.State.Telemetry](/packages/timewarp.state.telemetry/) | `12.0.0-beta.13` | 34 | OpenTelemetry instrumentation for the TimeWarp.State mediator pipeline: action spans, timing, and opt-in AOT-safe state snapshots. | [Source on GitHub](https://github.com/TimeWarpEngineering/timewarp-state) --- --- title: timewarp-nuru description: The timewarp-nuru package family type: project repository: https://github.com/TimeWarpEngineering/timewarp-nuru --- 5 packages published from [timewarp-nuru](https://github.com/TimeWarpEngineering/timewarp-nuru). Route-based CLI framework for .NET - batteries included with telemetry, REPL, and shell completion | Package | Latest | Downloads | Description | |---|---|---|---| | [TimeWarp.Nuru](/packages/timewarp.nuru/) ⭐ | `3.0.0` | 28,668 | Route-based CLI framework for .NET - batteries included with telemetry, REPL, and shell completion | | [TimeWarp.Nuru.Analyzers](/packages/timewarp.nuru.analyzers/) | `3.0.0` | 15,916 | Roslyn analyzers for TimeWarp.Nuru route pattern validation | | [TimeWarp.Nuru.DevCli](/packages/timewarp.nuru.devcli/) | `3.0.0` | 3,298 | Reusable dev-cli endpoints for TimeWarp repositories - clean, self-install, check-version | | [TimeWarp.Nuru.Mcp](/packages/timewarp.nuru.mcp/) | `3.0.0-beta.76` | 14,602 | MCP server for TimeWarp.Nuru providing route validation, syntax documentation, example code, and handler generation for AI-assisted CLI development. | | [TimeWarp.Nuru.Search](/packages/timewarp.nuru.search/) | `3.0.0` | 1,397 | CLI search tool for indexing and searching Nuru CLI endpoints across multiple CLIs | [Source on GitHub](https://github.com/TimeWarpEngineering/timewarp-nuru) --- --- title: timewarp-mediator description: The timewarp-mediator package family type: project repository: https://github.com/TimeWarpEngineering/timewarp-mediator --- 4 packages published from [timewarp-mediator](https://github.com/TimeWarpEngineering/timewarp-mediator). Reflection-based mediator (MediatR fork): AddMediator() registers request/response, notifications, streams, and pipeline behaviors over Microsoft.Extensions.DependencyInjection by assembly scan. The s… | Package | Latest | Downloads | Description | |---|---|---|---| | [TimeWarp.Mediator](/packages/timewarp.mediator/) ⭐ | `14.0.0` | 14,585 | Reflection-based mediator (MediatR fork): AddMediator() registers request/response, notifications, streams, and pipeline behaviors over Microsoft.Extensions.DependencyInjection by assembly scan. The s… | | [TimeWarp.Mediator.Analyzers](/packages/timewarp.mediator.analyzers/) | `14.0.0` | 344 | Roslyn analyzers for TimeWarp.Mediator message graphs: TWM001 (request with no handler), TWM002 (duplicate handler), TWM003 (scope mismatch), TWM004 (wrong-scope send). Already bundled in TimeWarp.Med… | | [TimeWarp.Mediator.Contracts](/packages/timewarp.mediator.contracts/) | `14.0.0` | 14,817 | Contract-only package for TimeWarp.Mediator: IRequest, ICommand, IQuery, INotification, IStreamRequest, their handler and pipeline-behavior interfaces, ISender/IPublisher/IMediator, and the scope/modu… | | [TimeWarp.Mediator.Generators](/packages/timewarp.mediator.generators/) | `14.0.0` | 370 | Source generator for TimeWarp.Mediator: builds the message graph at compile time and emits a sealed, reflection-free, AOT-friendly IMediator plus per-scope ISender/IPublisher named pip… | [Source on GitHub](https://github.com/TimeWarpEngineering/timewarp-mediator) --- --- title: timewarp-architecture description: The timewarp-architecture package family type: project repository: https://github.com/TimeWarpEngineering/timewarp-architecture --- 12 packages published from [timewarp-architecture](https://github.com/TimeWarpEngineering/timewarp-architecture). TimeWarp Architecture Templates | Package | Latest | Downloads | Description | |---|---|---|---| | [TimeWarp.Architecture](/packages/timewarp.architecture/) ⭐ | `2.0.0-beta.19` | 17,879 | TimeWarp Architecture Templates | | [TimeWarp.402](/packages/timewarp.402/) | `2.0.0-beta.19` | 329 | Internet-native x402 payment (challenge, verify, settle, credits) for TimeWarp applications. | | [TimeWarp.Architecture.Analyzers](/packages/timewarp.architecture.analyzers/) | `2.0.0-beta.19` | 985 | Roslyn convention analyzers for TimeWarp Architecture (TWA0002–0016, TWA0020–0024). Analyzer-only package; safe to reference from every project including contracts. | | [TimeWarp.Architecture.Attributes](/packages/timewarp.architecture.attributes/) | `2.0.0-beta.19` | 924 | Runtime marker attributes for TimeWarp Architecture generators (e.g. [ApiEndpoint], [assembly: ApiEndpointsEmbedded]) and convention opt-outs ([TypeStemIdentifier]). Public library — not a private dep… | | [TimeWarp.Architecture.Generators](/packages/timewarp.architecture.generators/) | `2.0.0-beta.19` | 978 | Roslyn source generators and diagnostics for TimeWarp Architecture (FastEndpoint, Page, StateAccess, mock-factory registry, TypedId, ingress route prefixes) — TWA0001 and TWA0017/0018/0019. Analyzer-o… | | [TimeWarp.Foundation.Application](/packages/timewarp.foundation.application/) | `2.0.0-beta.19` | 1,296 | Application-layer abstractions and TimeWarp.Mediator pipeline behaviors for the TimeWarp foundation layer. | | [TimeWarp.Foundation.Contracts](/packages/timewarp.foundation.contracts/) | `2.0.0-beta.19` | 1,324 | Shared contracts, request/response markers, route/auth/query source generator, and common types for the TimeWarp foundation layer. | | [TimeWarp.Foundation.Domain](/packages/timewarp.foundation.domain/) | `2.0.0-beta.19` | 1,451 | Domain primitives (Enumeration, Entity, IAggregateRoot) for the TimeWarp foundation layer. Dependency-free. | | [TimeWarp.Foundation.Infrastructure](/packages/timewarp.foundation.infrastructure/) | `2.0.0-beta.19` | 1,217 | Infrastructure services (date-time, current-user) and aggregate EF persistence (AggregateDbContext) for the TimeWarp foundation layer. | | [TimeWarp.Foundation.Server](/packages/timewarp.foundation.server/) | `2.0.0-beta.19` | 1,134 | ASP.NET server building blocks (modules, base endpoints, CORS, service discovery) for the TimeWarp foundation layer. | | [TimeWarp.Identity](/packages/timewarp.identity/) | `2.0.0-beta.19` | 766 | Principal identity (passkeys, agent keys, Entra-linked credentials, sessions/tokens, trust tiers) for TimeWarp applications. | | [TimeWarp.Modules](/packages/timewarp.modules/) | `2.0.0-beta.19` | 1,350 | Lightweight IModule composition abstraction used by the TimeWarp foundation layer. | [Source on GitHub](https://github.com/TimeWarpEngineering/timewarp-architecture) --- --- title: timewarp-amuru description: The timewarp-amuru package family type: project repository: https://github.com/TimeWarpEngineering/timewarp-amuru --- 3 packages published from [timewarp-amuru](https://github.com/TimeWarpEngineering/timewarp-amuru). Fluent API for elegant C# scripting with pipeline support | Package | Latest | Downloads | Description | |---|---|---|---| | [TimeWarp.Amuru](/packages/timewarp.amuru/) ⭐ | `2.0.0` | 12,696 | Fluent API for elegant C# scripting with pipeline support | | [TimeWarp.Amuru.Tools](/packages/timewarp.amuru.tools/) | `2.0.0` | 1,716 | Fluent builders for common CLI tools (dotnet, git, fzf) plus TimeWarp repo services, built on TimeWarp.Amuru | | [TimeWarp.Cli](/packages/timewarp.cli/) | `0.6.0-rc9` | 3,527 | Fluent API for elegant C# scripting with pipeline support | [Source on GitHub](https://github.com/TimeWarpEngineering/timewarp-amuru) --- --- title: timewarp-terminal description: The timewarp-terminal package family type: project repository: https://github.com/TimeWarpEngineering/timewarp-terminal --- 2 packages published from [timewarp-terminal](https://github.com/TimeWarpEngineering/timewarp-terminal). Terminal abstractions and widgets for console applications - IConsole, ITerminal, panels, tables, rules, and ANSI color support | Package | Latest | Downloads | Description | |---|---|---|---| | [TimeWarp.Terminal](/packages/timewarp.terminal/) ⭐ | `1.0.2` | 10,442 | Terminal abstractions and widgets for console applications - IConsole, ITerminal, panels, tables, rules, and ANSI color support | | [TimeWarp.Terminal.Layout](/packages/timewarp.terminal.layout/) | `1.0.2` | 83 | Flexbox-composed terminal layouts for TimeWarp.Terminal widgets | [Source on GitHub](https://github.com/TimeWarpEngineering/timewarp-terminal) --- --- title: timewarp-jaribu description: The timewarp-jaribu package family type: project repository: https://github.com/TimeWarpEngineering/timewarp-jaribu --- 2 packages published from [timewarp-jaribu](https://github.com/TimeWarpEngineering/timewarp-jaribu). Lightweight testing helpers for single-file C# programs and scripts. Jaribu (Swahili: test/trial) provides TestRunner pattern and assertion helpers for executable .cs files. | Package | Latest | Downloads | Description | |---|---|---|---| | [TimeWarp.Jaribu](/packages/timewarp.jaribu/) ⭐ | `1.0.0-beta.15` | 4,449 | Lightweight testing helpers for single-file C# programs and scripts. Jaribu (Swahili: test/trial) provides TestRunner pattern and assertion helpers for executable .cs files. | | [TimeWarp.Jaribu.TestingPlatform](/packages/timewarp.jaribu.testingplatform/) | `1.0.0-beta.15` | 948 | Microsoft.Testing.Platform adapter for TimeWarp.Jaribu test framework | [Source on GitHub](https://github.com/TimeWarpEngineering/timewarp-jaribu) --- --- title: Packages description: All TimeWarp Engineering NuGet packages, grouped by source repository. type: index --- 48 NuGet packages, generated from the [NuGet catalog](https://www.nuget.org/profiles/TimeWarp.Enterprises). Machine-readable catalog: [index.json](/packages/index.json). ## [timewarp-state](/projects/timewarp-state/) - [TimeWarp.State](/packages/timewarp.state/) `12.0.0-beta.13` — State management for .NET. Blazor components, JavaScript interop, and render subscriptions are in TimeWarp.State.Blazor. - [TimeWarp.State.Blazor](/packages/timewarp.state.blazor/) `12.0.0-beta.13` — Blazor components, JavaScript interop, and render subscriptions for TimeWarp.State. - [TimeWarp.State.DevTools.Export](/packages/timewarp.state.devtools.export/) `12.0.0-beta.13` — Dev-only exporter that copies TimeWarp.State activity spans to the DevTools inspector. Not a production dependency. - [TimeWarp.State.DevTools.Hosting](/packages/timewarp.state.devtools.hosting/) `12.0.0-beta.13` — Aspire hosting integration that adds the TimeWarp.State DevTools app and links it from the dashboard. - [TimeWarp.State.Plus](/packages/timewarp.state.plus/) `12.0.0-beta.13` — TimeWarp.State.Plus extends TimeWarp.State and TimeWarp.State.Blazor with routing, persistence, and action tracking. - [TimeWarp.State.Policies](/packages/timewarp.state.policies/) `12.0.0-beta.13` — Policies for TimeWarp State management library - [TimeWarp.State.Telemetry](/packages/timewarp.state.telemetry/) `12.0.0-beta.13` — OpenTelemetry instrumentation for the TimeWarp.State mediator pipeline: action spans, timing, and opt-in AOT-safe state snapshots. ## [timewarp-nuru](/projects/timewarp-nuru/) - [TimeWarp.Nuru](/packages/timewarp.nuru/) `3.0.0` — Route-based CLI framework for .NET - batteries included with telemetry, REPL, and shell completion - [TimeWarp.Nuru.Analyzers](/packages/timewarp.nuru.analyzers/) `3.0.0` — Roslyn analyzers for TimeWarp.Nuru route pattern validation - [TimeWarp.Nuru.DevCli](/packages/timewarp.nuru.devcli/) `3.0.0` — Reusable dev-cli endpoints for TimeWarp repositories - clean, self-install, check-version - [TimeWarp.Nuru.Mcp](/packages/timewarp.nuru.mcp/) `3.0.0-beta.76` — MCP server for TimeWarp.Nuru providing route validation, syntax documentation, example code, and handler generation for AI-assisted CLI development. - [TimeWarp.Nuru.Search](/packages/timewarp.nuru.search/) `3.0.0` — CLI search tool for indexing and searching Nuru CLI endpoints across multiple CLIs ## [timewarp-mediator](/projects/timewarp-mediator/) - [TimeWarp.Mediator](/packages/timewarp.mediator/) `14.0.0` — Reflection-based mediator (MediatR fork): AddMediator() registers request/response, notifications, streams, and pipeline behaviors over Microsoft.Extensions.DependencyInjection by assembly scan. The s… - [TimeWarp.Mediator.Analyzers](/packages/timewarp.mediator.analyzers/) `14.0.0` — Roslyn analyzers for TimeWarp.Mediator message graphs: TWM001 (request with no handler), TWM002 (duplicate handler), TWM003 (scope mismatch), TWM004 (wrong-scope send). Already bundled in TimeWarp.Med… - [TimeWarp.Mediator.Contracts](/packages/timewarp.mediator.contracts/) `14.0.0` — Contract-only package for TimeWarp.Mediator: IRequest, ICommand, IQuery, INotification, IStreamRequest, their handler and pipeline-behavior interfaces, ISender/IPublisher/IMediator, and the scope/modu… - [TimeWarp.Mediator.Generators](/packages/timewarp.mediator.generators/) `14.0.0` — Source generator for TimeWarp.Mediator: builds the message graph at compile time and emits a sealed, reflection-free, AOT-friendly IMediator plus per-scope ISender/IPublisher named pip… ## [timewarp-architecture](/projects/timewarp-architecture/) - [TimeWarp.Architecture](/packages/timewarp.architecture/) `2.0.0-beta.19` — TimeWarp Architecture Templates - [TimeWarp.402](/packages/timewarp.402/) `2.0.0-beta.19` — Internet-native x402 payment (challenge, verify, settle, credits) for TimeWarp applications. - [TimeWarp.Architecture.Analyzers](/packages/timewarp.architecture.analyzers/) `2.0.0-beta.19` — Roslyn convention analyzers for TimeWarp Architecture (TWA0002–0016, TWA0020–0024). Analyzer-only package; safe to reference from every project including contracts. - [TimeWarp.Architecture.Attributes](/packages/timewarp.architecture.attributes/) `2.0.0-beta.19` — Runtime marker attributes for TimeWarp Architecture generators (e.g. [ApiEndpoint], [assembly: ApiEndpointsEmbedded]) and convention opt-outs ([TypeStemIdentifier]). Public library — not a private dep… - [TimeWarp.Architecture.Generators](/packages/timewarp.architecture.generators/) `2.0.0-beta.19` — Roslyn source generators and diagnostics for TimeWarp Architecture (FastEndpoint, Page, StateAccess, mock-factory registry, TypedId, ingress route prefixes) — TWA0001 and TWA0017/0018/0019. Analyzer-o… - [TimeWarp.Foundation.Application](/packages/timewarp.foundation.application/) `2.0.0-beta.19` — Application-layer abstractions and TimeWarp.Mediator pipeline behaviors for the TimeWarp foundation layer. - [TimeWarp.Foundation.Contracts](/packages/timewarp.foundation.contracts/) `2.0.0-beta.19` — Shared contracts, request/response markers, route/auth/query source generator, and common types for the TimeWarp foundation layer. - [TimeWarp.Foundation.Domain](/packages/timewarp.foundation.domain/) `2.0.0-beta.19` — Domain primitives (Enumeration, Entity, IAggregateRoot) for the TimeWarp foundation layer. Dependency-free. - [TimeWarp.Foundation.Infrastructure](/packages/timewarp.foundation.infrastructure/) `2.0.0-beta.19` — Infrastructure services (date-time, current-user) and aggregate EF persistence (AggregateDbContext) for the TimeWarp foundation layer. - [TimeWarp.Foundation.Server](/packages/timewarp.foundation.server/) `2.0.0-beta.19` — ASP.NET server building blocks (modules, base endpoints, CORS, service discovery) for the TimeWarp foundation layer. - [TimeWarp.Identity](/packages/timewarp.identity/) `2.0.0-beta.19` — Principal identity (passkeys, agent keys, Entra-linked credentials, sessions/tokens, trust tiers) for TimeWarp applications. - [TimeWarp.Modules](/packages/timewarp.modules/) `2.0.0-beta.19` — Lightweight IModule composition abstraction used by the TimeWarp foundation layer. ## timewarp-simple-icons - [timewarp-simple-icons](/packages/timewarp-simple-icons/) `16.35.0` — All of the simple-icons wrapped as Blazor components. ## [timewarp-amuru](/projects/timewarp-amuru/) - [TimeWarp.Amuru](/packages/timewarp.amuru/) `2.0.0` — Fluent API for elegant C# scripting with pipeline support - [TimeWarp.Amuru.Tools](/packages/timewarp.amuru.tools/) `2.0.0` — Fluent builders for common CLI tools (dotnet, git, fzf) plus TimeWarp repo services, built on TimeWarp.Amuru - [TimeWarp.Cli](/packages/timewarp.cli/) `0.6.0-rc9` — Fluent API for elegant C# scripting with pipeline support ## [timewarp-terminal](/projects/timewarp-terminal/) - [TimeWarp.Terminal](/packages/timewarp.terminal/) `1.0.2` — Terminal abstractions and widgets for console applications - IConsole, ITerminal, panels, tables, rules, and ANSI color support - [TimeWarp.Terminal.Layout](/packages/timewarp.terminal.layout/) `1.0.2` — Flexbox-composed terminal layouts for TimeWarp.Terminal widgets ## timewarp-build-tasks - [TimeWarp.Build.Tasks](/packages/timewarp.build.tasks/) `1.0.0` — MSBuild tasks for TimeWarp projects including git metadata injection and build automation ## timewarp-builder - [TimeWarp.Builder](/packages/timewarp.builder/) `1.0.0` — Fluent builder interfaces and scope extensions for TimeWarp projects ## timewarp-fixie - [TimeWarp.Fixie](/packages/timewarp.fixie/) `3.1.0+9.0.300` — The TimeWarp Fixie testing convention ## [timewarp-jaribu](/projects/timewarp-jaribu/) - [TimeWarp.Jaribu](/packages/timewarp.jaribu/) `1.0.0-beta.15` — Lightweight testing helpers for single-file C# programs and scripts. Jaribu (Swahili: test/trial) provides TestRunner pattern and assertion helpers for executable .cs files. - [TimeWarp.Jaribu.TestingPlatform](/packages/timewarp.jaribu.testingplatform/) `1.0.0-beta.15` — Microsoft.Testing.Platform adapter for TimeWarp.Jaribu test framework ## timewarp-heroicons - [timewarp-heroicons](/packages/timewarp-heroicons/) `2.2.0` — All of the Tailwind HeroIcons wrapped as Blazor components. ## timewarp-source-generators - [TimeWarp.SourceGenerators](/packages/timewarp.sourcegenerators/) `1.0.0-beta.11` — Package Description ## timewarp-multiavatar - [TimeWarp.Multiavatar](/packages/timewarp.multiavatar/) `1.0.0-beta.13` — A .NET library for generating unique, deterministic avatars from any text input. Creates beautiful SVG avatars with 48 billion unique variations based on SHA256 hashing. ## timewarp-options-validation - [TimeWarp.OptionsValidation](/packages/timewarp.optionsvalidation/) `1.0.0-beta.5` — Integrates FluentValidation with Microsoft.Extensions.Options for configuration validation at startup. ## timewarp-quickbooks - [TimeWarp.QuickBooks](/packages/timewarp.quickbooks/) `1.0.0-beta.3` — QuickBooks Online API integration with OAuth authentication and data access capabilities. ## timewarp-components - [TimeWarp.Components](/packages/timewarp.components/) `1.0.0-beta.2` — Style-agnostic Blazor base components (DisplayComponent/ParentComponent, IAttributeComponent/IParentComponent) and CssBuilder. No state dependency. ## timewarp-flexbox - [TimeWarp.Flexbox](/packages/timewarp.flexbox/) `1.0.0` — A pure C# implementation of the Flexbox layout algorithm for .NET applications ## CLI tools - [TimeWarpRooTools](/packages/timewarprootools/) `1.0.0-beta.2` — TimeWarp Roo Code Tools - [TimeWarp.Skills](/packages/timewarp.skills/) `1.0.0-beta.23` — CLI for managing agent skill sources and syncing them to harness skill directories. --- --- title: amuru description: Use TimeWarp.Amuru for process execution instead of System.Diagnostics.Process type: skill repository: https://github.com/TimeWarpEngineering/timewarp-amuru --- Use TimeWarp.Amuru for process execution instead of System.Diagnostics.Process Maintained in [timewarp-amuru](https://github.com/TimeWarpEngineering/timewarp-amuru) · Canonical file: [SKILL.md](/skills/amuru/SKILL.md) ## Install With [TimeWarp.Skills](/packages/timewarp.skills/): ```sh dnx TimeWarp.Skills -- add amuru https://timewarp.software/ ``` Add a harness target and `skills sync` (see the [TimeWarp.Skills](/packages/timewarp.skills/) page). Or copy the [SKILL.md](/skills/amuru/SKILL.md) into your agent's skills directory. --- # Amuru Process Execution > Agent guide for the TimeWarp.Amuru command contract (`CommandOutput`, default validation `None`). `AGENTS.md` and the library source win if this file drifts. The 2.0 release notes, including breaking changes, are in `documentation/release-notes/2.0.0.md`. **ALWAYS use `TimeWarp.Amuru` for process execution in .NET.** Do NOT use `System.Diagnostics.Process.Start` directly. ## Package In a runfile: ```csharp #:package TimeWarp.Amuru #:package TimeWarp.Amuru.Tools ``` `Shell`, `CommandOutput`, `CommandMock`, `ScriptContext`, and `CliConfiguration` are `TimeWarp.Amuru`. `DotNet`, `Git`, and `Fzf` are `TimeWarp.Amuru.Tools`. Both use the `TimeWarp.Amuru` namespace. Or via Central Package Management in `Directory.Packages.props`: ```xml ``` Find available versions: ```bash dotnet package search TimeWarp.Amuru --exact-match --take 5 ``` ## Core API: Shell.Builder All process execution starts with `Shell.Builder(executable)` and uses a fluent builder pattern. ### Execution Modes ```csharp // RunAsync - streams output to console, returns exit code int exitCode = await Shell.Builder("dotnet").WithArguments("build").RunAsync(); // CaptureAsync - captures output silently, returns CommandOutput CommandOutput output = await Shell.Builder("git").WithArguments("status").CaptureAsync(); // RunAndCaptureAsync - streams to console AND captures output CommandOutput output = await Shell.Builder("dotnet").WithArguments("test").RunAndCaptureAsync(); // PassthroughAsync - interactive stream piping (not a real TTY). Returns CommandOutput. // Stdout/Stderr are empty because the streams go to the terminal. CommandOutput passthrough = await Shell.Builder("fzf").PassthroughAsync(); // TtyPassthroughAsync - real TTY inheritance for TUI apps (vim, nano). Returns CommandOutput. // Never throws on a non-zero exit, even with WithZeroExitCodeValidation. CommandOutput tty = await Shell.Builder("vim").WithArguments("file.txt").TtyPassthroughAsync(); ``` ### CommandOutput Properties ```csharp CommandOutput output = await Shell.Builder("git").WithArguments("log").CaptureAsync(); output.ExitCode // int - process exit code (CommandResult.NeverRanExitCode / -1 if it never ran) output.Success // bool - true if ExitCode == 0 output.TimedOut // bool - true when the command exceeded WithTimeout (exit 124) output.RunTime // TimeSpan - zero for mocks and commands that never ran output.Stdout // string - captured stdout (lazy, thread-safe) output.Stderr // string - captured stderr (lazy, thread-safe) output.Combined // string - interleaved stdout+stderr (lazy, thread-safe) output.OutputLines // IReadOnlyList - timestamped lines output.GetLines() // string[] - combined output lines output.GetStdoutLines() // string[] - stdout lines only output.GetStderrLines() // string[] - stderr lines only output.ToSummary() // string - one-line summary output.ToDetailedString() // string - multi-line details ``` ### Builder Configuration ```csharp await Shell.Builder("myapp") .WithArguments("arg1", "arg2") // Add arguments .WithWorkingDirectory("/path/to/dir") // Set working directory .WithEnvironmentVariable("KEY", "value") // Set env var .WithStandardInput("input text") // Pipe string to stdin .WithNoValidation() // Explicit default: non-zero exit is not thrown .WithTimeout(TimeSpan.FromSeconds(30)) // Per-command limit. Null means no timeout .RunAsync(cancellationToken); // All methods accept CancellationToken ``` ### Streaming Output ```csharp // Stream stdout lines as they arrive await foreach (string line in Shell.Builder("tail").WithArguments("-f", "log.txt").StreamStdoutAsync()) { Console.WriteLine(line); } // Stream stderr lines await foreach (string line in builder.StreamStderrAsync()) { } // Stream combined (OutputLine has .Text, .IsError, .Timestamp) await foreach (OutputLine line in builder.StreamCombinedAsync()) { } // Stream to file await Shell.Builder("curl").WithArguments("-s", url).StreamToFileAsync("output.json"); ``` ### Pipelines ```csharp // Chain commands with .Pipe() CommandOutput output = await Shell.Builder("find").WithArguments(".", "-name", "*.cs") .Pipe("grep", "async") .Pipe("sort") .CaptureAsync(); // Pipe through fzf for selection string selected = await Shell.Builder("git").WithArguments("branch", "--list") .Build() .SelectWithFzf(fzf => fzf.WithHeader("Select branch")) .SelectAsync(); ``` ## DotNet Commands Typed builders for `dotnet` CLI subcommands with IntelliSense-friendly options. ```csharp // Build await DotNet.Build("MyProject.csproj") .WithConfiguration("Release") .WithNoRestore() .WithProperty("WarningLevel", "0") .RunAsync(); // Publish await DotNet.Publish("MyProject.csproj") .WithConfiguration("Release") .WithSelfContained() .WithSingleFile() .WithTrimmed() .WithRuntime("linux-x64") .RunAsync(); // Other subcommands: DotNet.Clean(), DotNet.Restore(), DotNet.Run(), // DotNet.Test(), DotNet.Watch(), DotNet.Pack(), DotNet.New() // Query dotnet info CommandOutput sdks = await DotNet.WithListSdks().CaptureAsync(); CommandOutput version = await DotNet.WithVersion().CaptureAsync(); ``` ## Git Commands High-level Git operations with typed results. ```csharp // Find repo root. Synchronous only. string? root = Git.FindRoot(); string repositoryPath = root ?? Directory.GetCurrentDirectory(); // Branch operations GitBranchUpdateResult result = await Git.UpdateBranchAsync("main", repositoryPath); // result.Success, result.BranchPath, result.ErrorMessage GitDefaultBranchResult defaultBranch = await Git.GetDefaultBranchAsync(repositoryPath); // defaultBranch.Success, defaultBranch.BranchName, defaultBranch.ErrorMessage GitCommitCountResult ahead = await Git.GetCommitsAheadOfDefaultBranchAsync(repositoryPath); // ahead.Success, ahead.Count, ahead.ErrorMessage GitFetchResult fetched = await Git.FetchAsync(repositoryPath); // fetched.Success, fetched.ErrorMessage string? repoName = await Git.GetRepositoryNameAsync(repositoryPath); // Worktree operations bool isWorktree = Git.IsWorktree(repositoryPath); string? worktreePath = await Git.GetWorktreePathAsync("main", repositoryPath); GitWorktreeListResult listed = await Git.WorktreeListPorcelainAsync(repositoryPath); // listed.Success, listed.Porcelain, listed.ErrorMessage // For other git commands, use Shell.Builder CommandOutput log = await Shell.Builder("git").WithArguments("log", "--oneline", "-10").CaptureAsync(); ``` ## Fzf (Fuzzy Finder) Interactive selection with fzf. ```csharp // Select from items string selected = await Fzf.Builder() .FromInput("option1", "option2", "option3") .WithHeader("Pick one") .SelectAsync(); // Select from command output string selected = await Fzf.Builder() .FromCommand("find . -name '*.cs'") .WithPreview("cat {}") .SelectAsync(); // Pipe any command through fzf string file = await Shell.Builder("git").WithArguments("ls-files") .Build() .SelectWithFzf() .SelectAsync(); ``` ## ScriptContext For runfiles, get the runfile location and manage working directory. ```csharp using ScriptContext context = ScriptContext.FromEntryPoint(changeToScriptDirectory: true); // context.ScriptDirectory - directory containing the script // context.ScriptFilePath - full path to the script file // Dispose restores the original working directory ``` ## Testing / Mocking Mock command execution in tests without dependency injection. ```csharp using IDisposable scope = CommandMock.Enable(); // Setup mock responses CommandMock.Setup("git", "status") .Returns(stdout: "On branch main", exitCode: 0); CommandMock.Setup("dotnet", "build") .ReturnsError(stderr: "Build failed", exitCode: 1); CommandMock.Setup("slow-command") .Delays(TimeSpan.FromSeconds(2)) .Returns("done"); CommandMock.Setup("hung-command").TimesOut(); // TimedOut, exit 124, same shape as a real timeout // Execute code under test - it will use mocked responses CommandOutput result = await Shell.Builder("git").WithArguments("status").CaptureAsync(); // Verify calls were made CommandMock.VerifyCalled("git", "status"); int count = CommandMock.CallCount("git", "status"); ``` ## CLI Configuration Override command paths (useful for testing or custom installations). ```csharp CliConfiguration.SetCommandPath("git", "/usr/local/bin/git"); CliConfiguration.ClearCommandPath("git"); CliConfiguration.Reset(); ``` ## Error Handling Default validation is `None`. A non-zero exit is reported on `CommandOutput.ExitCode` and `Success`. It is not thrown. `WithNoValidation()` states that default explicitly. `WithZeroExitCodeValidation()` opts into throwing. A command that never ran reports `CommandResult.NeverRanExitCode` (`-1`), not success. `WithTimeout(TimeSpan)` on `ShellBuilder`, `CommandOptions`, or `DotNetBuilder` limits that command. On expiry the graceful signal is sent (SIGINT / Ctrl+C), then the process tree is killed after `WithTimeoutGracePeriod` (default 5 seconds). Default validation sets `CommandOutput.TimedOut` and exit `CommandResult.TimeoutExitCode` (124) and does not throw. Strict validation throws `TimeoutException`. Cancelling the caller's token still throws `OperationCanceledException` and does not set `TimedOut`. Windows non-console children do not receive SIGINT, so the grace period ends in the kill. See `documentation/developer/reference/command-execution.md`. `TtyPassthroughAsync` is the exception: it never throws on a non-zero exit or a timeout, even when zero-exit validation is set. Inspect `ExitCode` / `Success` / `TimedOut`. ```csharp CommandOutput output = await Shell.Builder("might-fail").CaptureAsync(); if (!output.Success) { // output.ExitCode and output.Stderr describe the failure. Nothing was thrown. } CommandOutput strict = await Shell.Builder("must-succeed") .WithZeroExitCodeValidation() .CaptureAsync(); ``` ## Documentation Command contract (`CommandOutput`, default validation `None`). This skill matches `AGENTS.md`. If they diverge, the library source wins: - **Local**: Repository root (this is the source of truth for Amuru) - **GitHub**: https://github.com/TimeWarpEngineering/timewarp-amuru --- --- title: flexbox description: TimeWarp.Flexbox library - compute CSS flexbox layouts (positions and sizes) in pure C# with no UI framework; a Native AOT-safe port of Facebook's Yoga engine. Use for laying out boxes/nodes in canvases, terminals, games, PDF/image generation, or custom renderers - anywhere you need flex-direction, flex-grow, wrap, gap, align/justify, percentages, or absolute positioning computed for you. type: skill repository: https://github.com/TimeWarpEngineering/timewarp-flexbox --- TimeWarp.Flexbox library - compute CSS flexbox layouts (positions and sizes) in pure C# with no UI framework; a Native AOT-safe port of Facebook's Yoga engine. Use for laying out boxes/nodes in canvases, terminals, games, PDF/image generation, or custom renderers - anywhere you need flex-direction, flex-grow, wrap, gap, align/justify, percentages, or absolute positioning computed for you. Maintained in [timewarp-flexbox](https://github.com/TimeWarpEngineering/timewarp-flexbox) · Canonical file: [SKILL.md](/skills/flexbox/SKILL.md) ## Install With [TimeWarp.Skills](/packages/timewarp.skills/): ```sh dnx TimeWarp.Skills -- add flexbox https://timewarp.software/ ``` Add a harness target and `skills sync` (see the [TimeWarp.Skills](/packages/timewarp.skills/) page). Or copy the [SKILL.md](/skills/flexbox/SKILL.md) into your agent's skills directory. --- # TimeWarp.Flexbox Pure C# flexbox layout engine — build a tree of nodes, set CSS-flexbox styles, and read back computed pixel positions and sizes. No UI framework involved. **Repository:** https://github.com/TimeWarpEngineering/timewarp-flexbox **Package:** `TimeWarp.Flexbox` Behavior is a from-scratch port of Facebook's Yoga engine, verified against Yoga's own conformance suite (530 generated tests, LTR and RTL). Zero runtime dependencies; fully Native AOT and trimming compatible. ## When to Use What | Need | Use | |------|-----| | A layout container | `new Node()` + `node.Style.FlexDirection = ...` | | Fixed size | `Style.SetDimension(Dimension.Width, StyleSizeLength.Points(100))` | | Percentage of parent | `StyleSizeLength.Percent(50)` | | Share leftover space | `Style.FlexGrow = 1` | | Spacing between items | `Style.SetGap(Gutter.All, StyleLength.Points(10))` | | Margins / padding / borders | `Style.SetMargin/SetPadding/SetBorder(Edge.All, StyleLength.Points(8))` | | Pin to a corner/edge | `Style.PositionType = PositionType.Absolute` + `Style.SetPosition(Edge.Right, ...)` | | Text or other content-sized leaf | `node.SetMeasureFunc(...)` | | Compute the layout | `root.CalculateLayout()` (or `CalculateLayout.Calculate(root, availW, availH, dir)`) | | Read results | `node.Layout.GetPosition(PhysicalEdge.Left)` / `GetDimension(Dimension.Width)` | | Web-CSS defaults instead of Yoga defaults | `new Node(new Config { UseWebDefaults = true })` | ## Core Model Five steps, always the same shape: ```csharp using TimeWarp.Flexbox; // 1. Build a node tree Node root = new(); root.Style.FlexDirection = FlexDirection.Row; root.Style.SetDimension(Dimension.Width, StyleSizeLength.Points(300)); root.Style.SetDimension(Dimension.Height, StyleSizeLength.Points(200)); Node left = new(); left.Style.FlexGrow = 1; root.InsertChild(left, 0); // 2. children attach via InsertChild(child, index) Node right = new(); right.Style.FlexGrow = 2; root.InsertChild(right, 1); // 3. Calculate (float.NaN = unconstrained available space) CalculateLayout.Calculate(root, float.NaN, float.NaN, Direction.LTR); // 4. Read computed values from node.Layout Console.WriteLine($"left: x={left.Layout.GetPosition(PhysicalEdge.Left)} width={left.Layout.GetDimension(Dimension.Width)}"); Console.WriteLine($"right: x={right.Layout.GetPosition(PhysicalEdge.Left)} width={right.Layout.GetDimension(Dimension.Width)}"); // left: x=0 width=100 // right: x=100 width=200 // 5. Change styles and re-Calculate any time — style writes dirty the tree automatically ``` Positions are **relative to the parent**. For absolute page coordinates, accumulate ancestors' positions (see Reading Results below). ## CSS-to-C# Mapping | CSS | TimeWarp.Flexbox | |-----|------------------| | `width: 100px` | `Style.SetDimension(Dimension.Width, StyleSizeLength.Points(100))` | | `height: 50%` | `Style.SetDimension(Dimension.Height, StyleSizeLength.Percent(50))` | | `width: auto` | `StyleSizeLength.Auto` (also `.MaxContent`, `.FitContent`, `.Stretch`) | | `min-width` / `max-width` | `Style.SetMinDimension` / `Style.SetMaxDimension` | | `flex-direction: row` | `Style.FlexDirection = FlexDirection.Row` (`Column`, `RowReverse`, `ColumnReverse`) | | `flex-wrap: wrap` | `Style.FlexWrap = Wrap.Wrap` (`NoWrap`, `WrapReverse`) | | `flex-grow: 1` | `Style.FlexGrow = 1` | | `flex-shrink: 1` | `Style.FlexShrink = 1` | | `flex-basis: 100px` | `Style.FlexBasis = StyleSizeLength.Points(100)` | | `justify-content: space-between` | `Style.JustifyContent = Justify.SpaceBetween` (`FlexStart`, `Center`, `FlexEnd`, `SpaceAround`, `SpaceEvenly`) | | `align-items: center` | `Style.AlignItems = Align.Center` (`FlexStart`, `FlexEnd`, `Stretch`, `Baseline`) | | `align-self` / `align-content` | `Style.AlignSelf` / `Style.AlignContent` (same `Align` enum) | | `gap: 10px` | `Style.SetGap(Gutter.All, StyleLength.Points(10))` (`Gutter.Row`, `Gutter.Column`) | | `margin: 8px` | `Style.SetMargin(Edge.All, StyleLength.Points(8))` (per-edge: `Edge.Left/Top/Right/Bottom/Start/End/Horizontal/Vertical`) | | `margin-left: auto` | `Style.SetMargin(Edge.Left, StyleLength.Auto)` | | `padding` / `border-width` | `Style.SetPadding` / `Style.SetBorder` (same Edge pattern) | | `position: absolute; right: 20px` | `Style.PositionType = PositionType.Absolute; Style.SetPosition(Edge.Right, StyleLength.Points(20))` | | `display: none` | `Style.Display = Display.None` | | `overflow: hidden` | `Style.Overflow = Overflow.Hidden` | | `box-sizing` | `Style.BoxSizing = BoxSizing.BorderBox` (default) or `ContentBox` | | `aspect-ratio: 16/9` | `Style.AspectRatio = 16f / 9f` | | `direction: rtl` | pass `Direction.RTL` to `Calculate` (or `Style.Direction` per subtree) | Two length types — do not mix them up: - **`StyleSizeLength`** for dimensions and flex-basis (supports `Auto`, `MaxContent`, `FitContent`, `Stretch`). - **`StyleLength`** for edges and gaps (margin, padding, border, position, gap; supports `Auto` for margins/positions). ## Defaults Are Yoga's, Not Web CSS This is the #1 source of surprises: | Property | TimeWarp.Flexbox / Yoga default | Web CSS default | |----------|--------------------------------|-----------------| | `flex-direction` | **Column** | row | | `flex-shrink` | **0** | 1 | | `align-content` | **flex-start** | stretch | | `position` | relative | static | | `box-sizing` | border-box | content-box | For web-style behavior, construct nodes with a web-defaults config: ```csharp Config config = new() { UseWebDefaults = true }; Node root = new(config); // pass the same config to every node in the tree ``` ## Reading Results ```csharp float x = node.Layout.GetPosition(PhysicalEdge.Left); // relative to parent float y = node.Layout.GetPosition(PhysicalEdge.Top); float w = node.Layout.GetDimension(Dimension.Width); float h = node.Layout.GetDimension(Dimension.Height); ``` Positions are parent-relative. Accumulate for absolute coordinates: ```csharp static (float X, float Y) AbsolutePosition(Node node) { float x = 0, y = 0; for (Node? n = node; n is not null; n = n.Owner) { x += n.Layout.GetPosition(PhysicalEdge.Left); y += n.Layout.GetPosition(PhysicalEdge.Top); } return (x, y); } ``` ## Recipes All outputs below are the actual values produced by the engine. ### App shell: sidebar + header/main/footer ```csharp Node shell = new(); shell.Style.FlexDirection = FlexDirection.Row; shell.Style.SetDimension(Dimension.Width, StyleSizeLength.Points(420)); shell.Style.SetDimension(Dimension.Height, StyleSizeLength.Points(200)); shell.Style.SetPadding(Edge.All, StyleLength.Points(8)); shell.Style.SetGap(Gutter.All, StyleLength.Points(8)); Node sidebar = new(); sidebar.Style.SetDimension(Dimension.Width, StyleSizeLength.Points(100)); shell.InsertChild(sidebar, 0); Node content = new(); content.Style.FlexGrow = 1; // fill remaining width content.Style.FlexDirection = FlexDirection.Column; content.Style.SetGap(Gutter.All, StyleLength.Points(8)); shell.InsertChild(content, 1); Node header = new(); header.Style.SetDimension(Dimension.Height, StyleSizeLength.Points(48)); content.InsertChild(header, 0); Node main = new(); main.Style.FlexGrow = 1; // fill remaining height content.InsertChild(main, 1); Node footer = new(); footer.Style.SetDimension(Dimension.Height, StyleSizeLength.Points(32)); content.InsertChild(footer, 2); CalculateLayout.Calculate(shell, float.NaN, float.NaN, Direction.LTR); // sidebar: x=8 w=100 h=184 (stretched to fill cross axis inside padding) // content: x=116 w=296 // main: y=56 h=88 (relative to content; absolute = (116, 64)) ``` ### Wrapping card grid with gap ```csharp Node grid = new(); grid.Style.FlexDirection = FlexDirection.Row; grid.Style.FlexWrap = Wrap.Wrap; grid.Style.SetGap(Gutter.All, StyleLength.Points(10)); grid.Style.SetDimension(Dimension.Width, StyleSizeLength.Points(250)); grid.Style.SetDimension(Dimension.Height, StyleSizeLength.Points(200)); for (int i = 0; i < 3; i++) { Node card = new(); card.Style.SetDimension(Dimension.Width, StyleSizeLength.Points(120)); card.Style.SetDimension(Dimension.Height, StyleSizeLength.Points(60)); grid.InsertChild(card, i); } CalculateLayout.Calculate(grid, float.NaN, float.NaN, Direction.LTR); // card0: (0, 0) card1: (130, 0) card2: (0, 70) <- wrapped, gap applied both axes ``` ### Corner overlay via absolute insets ```csharp Node overlay = new(); overlay.Style.PositionType = PositionType.Absolute; overlay.Style.SetPosition(Edge.Right, StyleLength.Points(20)); overlay.Style.SetPosition(Edge.Bottom, StyleLength.Points(16)); overlay.Style.SetDimension(Dimension.Width, StyleSizeLength.Points(120)); overlay.Style.SetDimension(Dimension.Height, StyleSizeLength.Points(48)); root.InsertChild(overlay, root.Children.Count); // inside a 420x160 root: overlay at (280, 96) ``` ### RTL ```csharp CalculateLayout.Calculate(root, float.NaN, float.NaN, Direction.RTL); // A 200-wide row of two 30x30 children flows right-to-left: // child0 x=170, child1 x=140 ``` ### Content-measured leaf (text, images) For leaves whose size depends on content, attach a measure function. It is called with the available space and a `MeasureMode` per axis: ```csharp Node text = new(); text.SetMeasureFunc((node, width, widthMode, height, heightMode) => { // widthMode/heightMode: Undefined (size to content), AtMost (fit within), // Exactly (value is fixed - your result for that axis is ignored) float measuredWidth = Math.Min(80, width); return new YGSize(measuredWidth, 20); }); container.InsertChild(text, 0); // In a 100x100 container: measure is called once with (100, Exactly, 100, AtMost) // -> text ends up w=100 (Exactly wins over the measured 80), h=20 (AtMost honors it) ``` Nodes with a measure function cannot have children (asserted). ### Incremental re-layout Style writes mark the tree dirty automatically; just call `Calculate` again. Unchanged subtrees hit the internal measurement cache. ```csharp // two flexGrow:1 children in a 200-wide row -> a=100, b=100 b.Style.FlexGrow = 3; CalculateLayout.Calculate(root, float.NaN, float.NaN, Direction.LTR); // now a=50, b=150 ``` ## Pitfalls - **A child belongs to one parent.** `InsertChild` takes ownership; inserting a node that already has an owner throws `YogaAssertException` ("Child already has a owner, it must be removed first."). Call `parent.RemoveChild(child)` first — removal resets the child's layout and clears its owner. - **`float.NaN` means "undefined/unconstrained"** for available space and any optional float. Check with `Comparison.IsUndefined(value)`, not `== NaN`. - **`StyleSizeLength` vs `StyleLength`**: dimensions/flex-basis take the former, edges/gaps the latter. The compiler catches it, but pick the right factory. - **Positions are parent-relative** — accumulate up the `Owner` chain for absolute coordinates. - **One `Config` per tree**: nodes constructed with different `UseWebDefaults` values cannot be mixed after construction (asserted on `SetConfig`). - The whole API is `float`-based; use `f` literals or implicit int conversions. ## Installation ```bash dotnet add package TimeWarp.Flexbox ``` The package is on nuget.org and ships XML docs. Targets `net10.0`, zero dependencies, `IsAotCompatible`. ## Further Reference - `samples/layout-demo/layout-demo.cs` in the repo renders layouts as ASCII boxes in the terminal, or (with `--html`) as a page comparing engine output against the browser's native flexbox side by side. - `test/timewarp-flexbox-tests/Generated/` contains Yoga's conformance suite ported to C# — a searchable catalog of expected values for any flexbox scenario. - Defaults, enums, and the full style surface: `source/timewarp-flexbox/Style/Style.cs` and `Enums/YGEnums.cs`. --- --- title: terminal description: TimeWarp.Terminal library - console abstractions (IConsole, ITerminal), widgets (panels, tables, rules), ANSI colors, hyperlinks, and Unicode width handling for testable C# console apps type: skill repository: https://github.com/TimeWarpEngineering/timewarp-terminal --- TimeWarp.Terminal library - console abstractions (IConsole, ITerminal), widgets (panels, tables, rules), ANSI colors, hyperlinks, and Unicode width handling for testable C# console apps Maintained in [timewarp-terminal](https://github.com/TimeWarpEngineering/timewarp-terminal) · Canonical file: [SKILL.md](/skills/terminal/SKILL.md) ## Install With [TimeWarp.Skills](/packages/timewarp.skills/): ```sh dnx TimeWarp.Skills -- add terminal https://timewarp.software/ ``` Add a harness target and `skills sync` (see the [TimeWarp.Skills](/packages/timewarp.skills/) page). Or copy the [SKILL.md](/skills/terminal/SKILL.md) into your agent's skills directory. --- # TimeWarp.Terminal Console abstractions and widgets for testable C# applications. **Repository:** https://github.com/TimeWarpEngineering/timewarp-terminal **Package:** `TimeWarp.Terminal` (widgets). Companion: `TimeWarp.Terminal.Layout` (flexbox composition). For detailed API documentation, fetch the README from the repository. ## When to Use What | Need | Use | |------|-----| | Basic testable I/O | `IConsole` | | Rich output (colors, widgets, hyperlinks) | `ITerminal` | | Quick utility script, easy Console migration | `Terminal` static class | | Unit testing | `TestTerminal` or `TestConsole` | | Measure terminal display width | `UnicodeWidth` | | Strip/measure ANSI strings | `AnsiStringUtils` | | Side-by-side panels / dashboard rows | Companion package `TimeWarp.Terminal.Layout` — `WriteLayout` | ## Installation ```bash dotnet add package TimeWarp.Terminal ``` ## Core Pattern: Dependency Injection ```csharp // Production services.AddSingleton(TimeWarpTerminal.Default); // Testing services.AddSingleton(new TestTerminal()); ``` ## Quick Examples ### Basic Output ```csharp using TimeWarp.Terminal; // Static API (Console replacement) Terminal.WriteLine("Hello".Green()); Terminal.WriteLine("Warning".Yellow().Bold()); // Instance API (testable) — all Write methods return ITerminal for fluent chaining ITerminal terminal = TimeWarpTerminal.Default; terminal .WriteLine("Hello".Cyan()) .WriteRule("Section") .WriteLine("World".Green()); ``` ### Widgets All widgets use the builder pattern. Constructors for `Table`, `Panel`, and `Rule` are internal — always use the builder or `Action` overloads. ```csharp // Panel — simple terminal.WritePanel("Content here"); // Panel — with header parameter terminal.WritePanel("Content here", "Title"); // Panel with builder terminal.WritePanel(panel => panel .Header("Configuration") .Content("Setting: value") .Border(BorderStyle.Rounded) .Padding(2, 1)); // Table terminal.WriteTable(table => table .AddColumn("Name") .AddColumn("Status", Alignment.Right) .AddRow("API", "Online".Green()) .AddRow("DB", "Offline".Red()) .Border(BorderStyle.Rounded)); // Standalone builder (when you need the Table object) Table table = new TableBuilder() .AddColumn("Name") .AddRow("foo") .Border(BorderStyle.Rounded) .Build(); terminal.WriteTable(table); // Rule (section divider) terminal.WriteRule("Section Title".Cyan()); // Rule with style terminal.WriteRule("Configuration", style: LineStyle.Doubled); // Rule with builder terminal.WriteRule(rule => rule .Title("Configuration") .Style(LineStyle.Doubled) .Color(AnsiColors.Cyan)); ``` ### Layout (companion package) `TimeWarp.Terminal.Layout` composes existing widgets into flexbox rows/columns. It is **not** a dependency of `TimeWarp.Terminal`. Types live in the `TimeWarp.Terminal` namespace (`WriteLayout`, `LayoutBuilder`, `Layout`). ```bash dotnet add package TimeWarp.Terminal.Layout ``` ```csharp using TimeWarp.Terminal; using TimeWarp.Flexbox; terminal.WriteLayout(layout => layout .Direction(FlexDirection.Row) .Gap(2) .Item(i => i.Grow(1), panel => panel.Header("Build").Content(buildSummary)) .Item(i => i.Grow(2), table => table.AddColumns("Test", "Result").AddRow("unit", "pass"))); terminal.WriteLayout(layout => layout .Direction(FlexDirection.Column) .Row(r => r.Item(statusPanel).Item(versionPanel)) .Row(r => r.Item(i => i.Grow(1), logTable))); ``` Static facade: `TerminalLayout.WriteLayout(...)`. Sizing uses `WindowWidth`. Color overloads gate on `SupportsColor`. Items never collapse to width 0. ### Hyperlinks ```csharp // String extension — creates OSC 8 hyperlink string link = "Click here".Link("https://example.com"); // With styling string styledLink = "Docs".Link("https://docs.example.com").Blue().Underline(); // Terminal extension methods (gracefully degrade if unsupported) terminal.WriteLink("https://example.com", "Click here"); // no newline terminal.WriteLinkLine("https://example.com", "Visit site"); // with newline // Static API (same graceful degradation via SupportsHyperlinks) Terminal.WriteLink("https://example.com", "Click here"); Terminal.WriteLinkLine("https://example.com", "Visit site"); // Low-level — parameter order matches WriteLink: (url, displayText) string osc8 = AnsiHyperlinks.CreateLink("https://example.com", "text"); ``` ### Colors and Styles ```csharp // Colors: Black, Red, Green, Yellow, Blue, Magenta, Cyan, White, Gray // Bright variants: BrightRed, BrightGreen, etc. // Styles: Bold(), Dim(), Italic(), Underline(), Strikethrough() // Background: OnRed(), OnGreen(), OnYellow(), etc. terminal.WriteLine("Success".Green().Bold()); terminal.WriteLine("Error".Red().OnWhite()); // ConsoleColor overloads on static API and WritePanel/WriteTable // (Write, WriteLine, and WriteErrorLine all have fg and fg+bg overloads) Terminal.WriteLine("colored", ConsoleColor.Green); Terminal.WriteLine("colored", ConsoleColor.Red, ConsoleColor.White); ``` ConsoleColor overloads and widget color parameters automatically degrade to plain text when `SupportsColor` is false (redirected output, non-empty `NO_COLOR`, or `TERM=dumb`). Embedded ANSI from string extensions like `.Green()` is the caller's responsibility. ### Format Culture Format overloads (`Terminal.Write("{0:N2}", value)` etc.) use the current culture, matching `System.Console`. Set `Terminal.FormatProvider = CultureInfo.InvariantCulture` for deterministic output; `null` (default) resolves `CurrentCulture` per call. Inside `TestTerminalContext.Use`, that assignment is async-local (parallel-safe); outside a context it is process-global. ### Unicode Width Calculates terminal display width accounting for emoji, CJK, fullwidth forms, and zero-width characters. Uses exact Emoji_Presentation=Yes code points from Unicode 16.0. ```csharp UnicodeWidth.GetTextWidth("Hello"); // 5 (ASCII) UnicodeWidth.GetTextWidth("📍"); // 2 (emoji) UnicodeWidth.GetTextWidth("漢字"); // 4 (CJK) UnicodeWidth.GetTextWidth("📍 Location"); // 11 (mixed) UnicodeWidth.GetTextWidth("🇺🇸"); // 2 (flag - multi-codepoint cluster) UnicodeWidth.GetTextWidth("☁️"); // 2 (text char + VS16) UnicodeWidth.GetRuneWidth(new Rune('A')); // 1 UnicodeWidth.GetRuneWidth(new Rune('漢')); // 2 UnicodeWidth.GetRuneWidth(new Rune(0x200D)); // 0 (ZWJ) ``` ### Testing ```csharp // Create test terminal with scripted input using TestTerminal terminal = new("yes\n"); // Run code under test MyCommand command = new(terminal); command.Execute(); // Verify output Assert.Contains("expected text", terminal.Output); Assert.Contains("error message", terminal.ErrorOutput); ``` ### Static Terminal Testing Use `TestTerminalContext.Use` — it is async-context isolated (safe for parallel tests, never mutates the global) and restores automatically on dispose: ```csharp using TestTerminal terminal = new(); using IDisposable scope = TestTerminalContext.Use(terminal); Terminal.WriteLine("test"); Assert.Contains("test", terminal.Output); ``` For strictly serial tests, direct `Terminal.Instance = testTerminal` assignment also works, but you must restore the original instance yourself. ## Key Interfaces **IConsole:** `Write` -> `IConsole`, `WriteLine` -> `IConsole`, `WriteLineAsync` -> `Task`, `WriteErrorLine` -> `IConsole`, `WriteErrorLineAsync` -> `Task`, `ReadLine` **ITerminal extends IConsole:** Overrides `Write` -> `ITerminal`, `WriteLine` -> `ITerminal`, `WriteErrorLine` -> `ITerminal`. Adds `ReadKey()` / `ReadKey(bool)` (key-by-key input lives here, not on `IConsole`), `SetCursorPosition`, `GetCursorPosition`, `WindowWidth`/`WindowHeight`/`BufferWidth`/`BufferHeight` (get-only; `TestTerminal` exposes setters for test configuration), `CancelKeyPress`, `IsInteractive`, `SupportsColor`, `SupportsHyperlinks`, `Clear` All Write methods return the interface for fluent chaining: ```csharp terminal .WriteLine("Build Output") .WriteRule("Results") .WriteTable(t => t .AddColumn("Test") .AddColumn("Status") .AddRow("Unit", "PASSED".Green())) .WriteRule() .WriteLine("Done!"); ``` ## Widget Builder API Widget constructors are internal. Always use builders. **PanelBuilder:** `.Header()`, `.Content(string?)`, `.Border()`, `.BorderColor()`, `.Padding()`, `.PaddingHorizontal()`, `.PaddingVertical()`, `.Width()`, `.WordWrap()`, `.Build()` **TableBuilder:** `.AddColumn(name)`, `.AddColumn(name, alignment)`, `.AddColumn(TableColumn)`, `.AddColumns(params string[])`, `.AddColumns(params TableColumn[])`, `.AddRow(params)`, `.Border()`, `.BorderColor()`, `.HideHeaders()`, `.ShowRowSeparators()`, `.Expand()`, `.Build()` **RuleBuilder:** `.Title()`, `.Style()`, `.Color()`, `.Width()`, `.Build()` ### WritePanel Overloads ```csharp // Simple content terminal.WritePanel("Content"); terminal.WritePanel("Content", BorderStyle.Rounded); // With header parameter terminal.WritePanel("Content", "Header"); terminal.WritePanel("Content", "Header", BorderStyle.Doubled); // With colors terminal.WritePanel("Content", "Header", BorderStyle.Rounded, ConsoleColor.Green, ConsoleColor.Black); // Builder pattern terminal.WritePanel(p => p.Header("Title").Content("Body").Border(BorderStyle.Rounded)); // Pre-built panel terminal.WritePanel(panel); ``` ### TableColumn Properties | Property | Type | Default | Description | |----------|------|---------|-------------| | `Header` | `string` | `""` | Column header text (supports ANSI colors) | | `Alignment` | `Alignment` | `Left` | Horizontal alignment (`Left`, `Right`, `Center`) | | `MinWidth` | `int?` | `null` | Column won't shrink below this width; the layout floor is `max(4, MinWidth)` | | `MaxWidth` | `int?` | `null` | Content exceeding this is truncated with ellipsis | | `TruncateMode` | `TruncateMode` | `End` | Where to place ellipsis when truncating | | `HeaderColor` | `string?` | `null` | ANSI color code for header text | | `Grow` | `bool` | `false` | When true, column expands to fill remaining terminal width after fixed columns are allocated. Multiple grow columns share remaining space evenly. | ### TruncateMode (Ellipsis Placement) | Mode | Result | Use case | |------|--------|----------| | `TruncateMode.End` | `"long text..."` | Default — shows beginning | | `TruncateMode.Start` | `"...long text"` | File paths — shows the meaningful end | | `TruncateMode.Middle` | `"long...text"` | Shows both start and end | #### Example: All three modes side-by-side ```csharp string longText = "This-is-a-very-long-text-that-will-be-truncated-differently"; terminal.WriteTable(t => t .AddColumn(new TableColumn("Mode") { MaxWidth = 8 }) .AddColumn(new TableColumn("End (default)") { MaxWidth = 25, TruncateMode = TruncateMode.End }) .AddColumn(new TableColumn("Start") { MaxWidth = 25, TruncateMode = TruncateMode.Start }) .AddColumn(new TableColumn("Middle") { MaxWidth = 25, TruncateMode = TruncateMode.Middle }) .AddRow("Result", longText, longText, longText) .Border(BorderStyle.Rounded)); ``` #### Example: File paths with TruncateMode.Start ```csharp terminal.WriteTable(t => t .AddColumn("Repository") .AddColumn(new TableColumn("Worktree Path") { TruncateMode = TruncateMode.Start }) .AddColumn("Branch") .AddRow("timewarp-nuru", "/home/user/worktrees/github.com/TimeWarpEngineering/timewarp-nuru/feature-branch-name", "feature-xyz") .Border(BorderStyle.Rounded)); // Path column shows: "...timewarp-nuru/feature-branch-name" ``` #### Example: Grow column for flexbox-style layouts Grow columns expand to fill remaining terminal width after fixed columns are allocated. Multiple grow columns share remaining space evenly. ```csharp // Single grow column fills remaining space terminal.WriteTable(t => t .AddColumn("ID") .AddColumn(new TableColumn("Description") { Grow = true }) .AddColumn("Status") .AddRow("1", "This description expands to fill available space", "Active") .AddRow("2", "Another long description that grows", "Pending") .Border(BorderStyle.Rounded)); // Multiple grow columns share remaining space evenly terminal.WriteTable(t => t .AddColumn("ID") .AddColumn(new TableColumn("Left") { Grow = true }) .AddColumn(new TableColumn("Right") { Grow = true }) .AddRow("1", "Left side content", "Right side content") .Border(BorderStyle.Rounded)); ``` #### Example: Column with MinWidth constraint ```csharp terminal.WriteTable(t => t .AddColumn("ID") .AddColumn(new TableColumn("Description") { MinWidth = 20 }) .AddRow("1", "This is a long description that would normally be truncated heavily")); ``` ### Table Expand/Grow Behavior - **Shrink** (always on): Proportionally reduces column widths to fit terminal. Wider columns shrink more aggressively. Respects `MinWidth` per column. - **Expand**: Distributes extra terminal width evenly across all columns. - **Grow** (column-level): When `Grow = true` on a column, it expands to fill remaining terminal width after fixed columns are allocated. Multiple grow columns share remaining space evenly. Takes precedence over Expand. **BorderStyle:** `Rounded`, `Square`, `Doubled`, `Heavy`, `None` **Alignment:** `Left`, `Right`, `Center` ## AnsiStringUtils Static utility class for ANSI-aware string operations. Handles CSI sequences and OSC 8 hyperlinks. ```csharp AnsiStringUtils.StripAnsiCodes("\x1b[32mGreen\x1b[0m"); // "Green" AnsiStringUtils.GetVisibleLength("\x1b[32mGreen\x1b[0m"); // 5 AnsiStringUtils.GetVisibleLength("📍 Location"); // 11 (uses UnicodeWidth) AnsiStringUtils.PadRightVisible("\x1b[32mHi\x1b[0m", 10); // pads to 10 visible chars AnsiStringUtils.PadLeftVisible("\x1b[32mHi\x1b[0m", 10); // left-pads to 10 AnsiStringUtils.CenterVisible("\x1b[32mHi\x1b[0m", 10); // centers to 10 AnsiStringUtils.WrapText("long text...", 40); // word-wrap, grapheme-aware ``` ## Common Pitfalls 1. **Don't use `new Table()`, `new Panel()`, `new Rule()`** - Constructors are internal. Use builders or `Action` extension methods. 2. **Don't mix Console and Terminal** - Pick one, stick with it 3. **Prefer `TestTerminalContext.Use` over swapping `Terminal.Instance`** - the scope is parallel-safe and restores automatically; direct swaps require manual restore and are serial-only 4. **`ConsoleColor` overloads and `WriteLink` self-gate** on `SupportsColor`/`SupportsHyperlinks` — but embedded ANSI from string extensions (`.Green()`, `BorderColor`) does not; check `SupportsColor` yourself before emitting those 5. **Use `UnicodeWidth.GetTextWidth()` not `.Length`** for terminal column calculations — `.Length` counts UTF-16 code units, not display columns --- --- title: tw-aggregate-pattern description: **TIMEWARP SKILL** — the golden aggregate-root pattern: typed id, `Entity` base, fail-closed `Create`, named mutations with no public setters, a private nested `Invariants` validator, and save-time enforcement via `DomainInvariantsGuard`/`AggregateDbContext`. Invoke before adding or reviewing an `IAggregateRoot`, or when TWA0011/TWA0012 fire. WHEN: add an aggregate, IAggregateRoot, aggregate root, TWA0011, TWA0012, Invariants validator, typed id. type: skill repository: https://github.com/TimeWarpEngineering/timewarp-architecture --- **TIMEWARP SKILL** — the golden aggregate-root pattern: typed id, `Entity` base, fail-closed `Create`, named mutations with no public setters, a private nested `Invariants` validator, and save-time enforcement via `DomainInvariantsGuard`/`AggregateDbContext`. Invoke before adding or reviewing an `IAggregateRoot`, or when TWA0011/TWA0012 fire. WHEN: add an aggregate, IAggregateRoot, aggregate root, TWA0011, TWA0012, Invariants validator, typed id. Maintained in [timewarp-architecture](https://github.com/TimeWarpEngineering/timewarp-architecture) · Canonical file: [SKILL.md](/skills/tw-aggregate-pattern/SKILL.md) ## Install With [TimeWarp.Skills](/packages/timewarp.skills/): ```sh dnx TimeWarp.Skills -- add tw-aggregate-pattern https://timewarp.software/ ``` Add a harness target and `skills sync` (see the [TimeWarp.Skills](/packages/timewarp.skills/) page). Or copy the [SKILL.md](/skills/tw-aggregate-pattern/SKILL.md) into your agent's skills directory. --- # Aggregate pattern (TWA0011/0012) An aggregate is a domain entity that is the consistency boundary for a set of invariants. Every aggregate root in this repository follows the same golden pattern. This skill is the pattern SSOT, including the persistence walkthrough (EF mapping → host registration → SaveChanges → tests). ## Detection — when to invoke | Signal | How to find it | |--------|----------------| | Adding a new `IAggregateRoot` | any domain type that owns its own consistency boundary | | `TWA0011` / `TWA0012` diagnostic | analyzer output names the aggregate type | | "Where does the invariants check run?" | save path, not construction | | Reviewing a `Create`/mutation method for a domain type | fail-closed construction check | ## The golden pattern - **Typed id.** The aggregate's id is a `[TypedId] readonly partial record struct` (e.g. `ProfileId`), never a raw `Guid`. See `web/features/profile/profile-id-domain.cs`. - **`Entity` base.** The aggregate inherits `TimeWarp.Foundation.Entities.Entity` (get-only typed `Id`, identity-based equality, a store-owned `Version` concurrency token) and implements the marker interface `IAggregateRoot`. - **Fail-closed construction.** A private constructor plus a static `Create(...)` factory with guard clauses — an aggregate can never exist half-initialized or with an obviously-invalid required field. - **Named mutations, no public setters.** State changes are intention-revealing methods (`Rename`, `SetLanguage`, ...), never `{ get; set; }`. - **Nested `Invariants` validator.** A `private sealed class Invariants : AbstractValidator` declares the aggregate's full rule set. It stays `private` so contract-validator auto-registration (`AddValidatorsFromAssemblyContaining`) never picks it up as a request validator. - **Save-time enforcement.** `DomainInvariantsGuard` discovers and runs the nested `Invariants` validator for every changed `IAggregateRoot` from `AggregateDbContext.SaveChanges(Async)` before the save proceeds. Host contexts (e.g. `PostgresDbContext`) inherit that base; they do not reimplement the hook. Guard clauses in `Create`/mutations and the save-time validator are **complementary, not redundant**: the former makes invalid states hard to construct, the latter makes them impossible to persist regardless of which code path produced them. Child-only mutations resolve to the owning root so invariants and `Version` still run. ## Placement An aggregate's domain type is `-domain.cs` in its owning slice, and its typed id is `-id-domain.cs` alongside it — both follow the `[-]-.cs` filename grammar for the `domain` layer. See `tw-feature-placement` for the full grammar, registry, and use-case-folder rules; this skill covers the aggregate's internal shape, not where the file lives. ## Enforcement map | Rule | Requires | Why | |------|----------|-----| | **TWA0011** | An `IAggregateRoot` must declare a nested `Invariants : AbstractValidator` | Fail-closed: no validator means `DomainInvariantsGuard` cannot check the aggregate at save time | | **TWA0012** | That nested `Invariants` must be `private` | Keeps it out of `AddValidatorsFromAssemblyContaining` auto-registration — it is a save-time domain check, not a request validator | ## Exemplar `web/features/profile/profile-domain.cs` + `profile-id-domain.cs` — read both before adding a new aggregate. Its EF mapping (`profile-entity-type-configuration-infrastructure.cs` — table/schema `profiles`, TypedId key conversion) is applied by `PostgresDbContext` via `ApplyConfigurationsFromAssembly`. `Version`'s `.IsConcurrencyToken()` is supplied for free by the `AggregateDbContext` `Version` convention — an aggregate's own mapping does not declare it. ## Persistence golden path (Postgres + EF) The template's default durable path is **Postgres-only state-store EF**. No SQL Server dual story, no event sourcing as the default, no in-app `EnsureCreated`. Hosts inherit `AggregateDbContext` so SaveChanges enforcement is not sealed inside one product context. Npgsql stays host-only. - **Schema-per-slice** on a single `PostgresDbContext` (`ToTable("orders", "orders")`). A second DbContext per module is an earned exception. - **EF migrations are the only schema path.** Committed migrations live under `source/container-apps/web/platform/postgres/migrations/`. Never invent schema at startup. - **Local / Aspire:** AppHost `AddEFMigrations` + `RunDatabaseUpdateOnStart` with **no wait edge** from web-server to the migration resource (both `WaitFor` and `WaitForCompletion` break restart or testing). On a fresh volume the app can briefly serve before migrate finishes; re-run on demand with the `ef-database-update` dashboard command. A **startup reader** waits until no migration is pending (`IPendingMigrationsProbe` / `EfPendingMigrationsProbe`, EF `GetPendingMigrationsAsync`) — not merely until its table exists, because a new column on an existing table fails the read too. A failing EF query logs Error inside EF before any catch runs, and a boot must log none. - **Inspect data locally:** in Development the Postgres resource carries `WithRepl()`, so the dashboard offers an authenticated psql shell (terminal dock) on the running server. - **Publish / deploy:** `PublishAsMigrationScript` / `PublishAsMigrationBundle`. - **Tests:** ephemeral DBs call `Database.Migrate()` / `MigrateAsync()`. Do not reuse AppHost `WithDataVolume` state across runs. - **Actors / outbox** are earned exceptions (Orleans grain-per-entity-ID over the same EF store for high-contention single-writer ids), not the default. ## Add an aggregate — walkthrough Prerequisites: the `postgres` template flag is on (default). ### 1. Domain Place `-domain.cs` and `-id-domain.cs` under `web/features//`. Follow **The golden pattern** above. Application code never writes `Version` — it is store-owned. ### 2. Infrastructure mapping Add `-entity-type-configuration-infrastructure.cs` in the same slice: | Concern | What to do | |---------|------------| | Table + schema | `ToTable("orders", "orders")` — schema-per-slice on the single host context | | Key | `HasKey(e => e.Id)` | | TypedId | `HasConversion(id => id.Value, v => OrderId.From(v))` | | Concurrency | nothing — `AggregateDbContext` configures `Version` for every `IAggregateRoot` | Do **not** call `.IsConcurrencyToken()` yourself on an aggregate mapping. ### 3. Host registration On `PostgresDbContext`: add `public DbSet Orders => Set();`, keep `base.OnModelCreating` and `ApplyConfigurationsFromAssembly`. Override `OnConfigureConventions` (not sealed `ConfigureConventions`) for TypedId conventions. Feature `*-infrastructure.cs` files compile into web-infrastructure — do not hand-register each `IEntityTypeConfiguration`. ### 4. Application Load → named mutation → `SaveChangesAsync`. Do **not** call `DomainInvariantsGuard` yourself. Invalid state fails closed before SQL. Concurrent writers surface as `DbUpdateConcurrencyException`. ### 5. Tests | Layer | What | |-------|------| | Domain unit | Create/guards/mutations (`profile-tests.cs`) | | Model mapping | Schema, TypedId, concurrency token (no live DB) | | SaveChanges hook | Version bump, child→root (`foundation-infrastructure-tests`) | | Postgres integration | `Database.Migrate`, round-trip, concurrent update on an ephemeral DB | ### 6. Store port vs direct DbContext | Use | When | |-----|------| | Direct `PostgresDbContext` / `DbSet` | Product aggregate owned by this host; Profile teaching path | | Port (`IPrincipalStore`, …) | Multi-backend seam; in-memory + EF must share snapshot-on-get and CAS semantics | Identity Principal/Credential are **not** `IAggregateRoot`. The store owns optimistic concurrency (`EntityVersion.Next` + `ConcurrencyConflictException`). Host mapping still sets `.IsConcurrencyToken()` as a DB race belt, but `AggregateDbContext` does not auto-increment `Version` for those types — that avoids a double-bump. ### 7. Schema evolution After editing the model or an `IEntityTypeConfiguration`: ```bash dev db add-migration ``` That wraps `dotnet tool restore` plus: ```bash dotnet ef migrations add \ --project source/container-apps/web/projects/web-infrastructure/web-infrastructure.csproj \ --startup-project source/container-apps/web/projects/web-server/web-server.csproj \ --context PostgresDbContext \ --output-dir ../../platform/postgres/migrations \ --namespace TimeWarp.Architecture.Persistence.Migrations ``` Do not kebab-rename EF scaffold files. Removing a mapped entity requires a migration that drops the unused tables — never an out-of-band DROP against `__EFMigrationsHistory`. ### Checklist - [ ] TypedId + `Entity` + `IAggregateRoot` + private `Invariants` - [ ] `IEntityTypeConfiguration` with schema and TypedId conversion (no `.IsConcurrencyToken()`) - [ ] `DbSet<>` + configurations discovered from assembly - [ ] Handler path: load → mutate → `SaveChangesAsync` - [ ] Domain unit tests + mapping and/or Postgres tests - [ ] Purpose/Design regions honest (TWA0004) ## Related skills and pointers - `tw-feature-placement` — filename grammar and layer membership (`[-]-.cs`, the `domain` layer, registry) - `tw-slice-isolation` — which slice an aggregate belongs to before placement - `AggregateDbContext` Design region — SaveChanges invariants, Version convention, child→root resolution (`source/foundation/foundation-infrastructure/persistence/aggregate-db-context.cs`) --- --- title: tw-blazor description: Razor file authoring — one @code at the top, markup, optional ``` # User interactions are actions Every user interaction in the SPA is a TimeWarp.State action. A component event handler (`OnClick`, `OnValidSubmit`, `@onkeydown`, `ValueChanged`, …) only dispatches generated ActionSet methods, and at most sequences several of them (`await CredentialsState.AddPasskey(); await CredentialsState.FetchCredentials();`), reading state between dispatches to decide the next. The work lives in the action's handler: - navigation — `RouteState.ChangeRoute(...)` for an in-app route; a handler that injects `NavigationManager` for a full-page load (`forceLoad: true`, e.g. a BFF challenge) or a destination only known after the work (post-sign-in return URL) - JS interop (`IJSRuntime`, JS modules, browser storage) - API calls (`IWebServerApiService` / `IApiServerApiService`, ceremony clients) - state changes Why: an action is the one seam that the Ctrl-K palette (every action, by derivation), the action catalog (`[CatalogAction]` — agent tools and palette metadata), State telemetry, and headless tests all see. A method on a page is invisible to all of them: it cannot be run from the palette, replayed, or dispatched in a test without a renderer. A button whose handler does the work itself is a feature nobody else can reach. Exempt — purely presentational, component-local UI state: hover, focus, scroll-into-view, whether a local panel or editor is open, and the text bound to an input (including resetting a form draft from state). Lifecycle work (`OnInitializedAsync` loads, a render-time redirect) is held to the same rule: dispatch an action (`RouteState.ChangeRoute` for an already-signed-in redirect, a handler with `forceLoad: true` for an auth-gate redirect). **Compiler-checked — TWA0026.** In SPA client code (Blazor WASM SDK), any member of a `ComponentBase` type — event handlers and lifecycle overrides alike — that calls one of these is reported: `NavigationManager.NavigateTo` / `NavigateToLogin` / `Refresh`; `IJSRuntime` / `IJSObjectReference` invokes; `IApiService` and its subtypes; `HttpClient` send/get/post/put/ delete/patch; session/local storage writes (`SetItem*`, `RemoveItem*`, `Clear*` — reads are fine); and any first-party type marked `[SideEffectService]` (ceremony clients, `*JsModule` helpers — mark new ones the same way). Handlers, services and static helpers are never flagged; that is where the work goes. A genuinely presentational JS call (focus, scroll, hotkey registration) opts out with `[DirectComponentSideEffect("reason")]` on the component (`@attribute` in the `.razor`) or member; an empty reason does not opt out and is reported as TWA0027. JavaScript can dispatch too: a plain-markup button whose JavaScript `onclick` calls `timeWarpState.DispatchRequest("", { … })` reaches the store with no C# handler (see the Counter demo, `source/features/counter.ts`). JavaScript dispatch is opt-in: allow the action in `Program.AllowJavaScriptDispatch` with `Allow(alias)`, where the alias is a `const` on the ActionSet (`IncrementCounterActionSet.JavaScriptAlias`), so the script never spells a CLR type name. Anything not allowed is rejected and nothing is sent. Use the `fluent-button` web component for that, not `FluentButton`, whose `OnClick` parameter claims the `onclick` attribute. Every `*ActionSet.Action` is a Ctrl-K command by derivation: the generated `ActionRoster` lists it, and the palette shows it when it takes no required constructor argument and the user is signed in. The label comes from the names (`AgentSurfaceState.OpenAskPanelActionSet` → "Agent surface: Open ask panel"). Nothing opts an action in. Plumbing (loads, resets, ceremony steps, the palette's own actions) opts out explicitly with `[CommandPaletteOptOut("reason")]` on the `Action` class; a blank reason does not opt out, and a guard test fails on one. A label known only at run time (an admin-set assistant name) comes from a registered `IActionDisplayOverride`, never from a literal baked into the convention. When an action is something an agent should run, or the palette needs better copy or a permission, tag it `[CatalogAction]` with a real `Description`, the same `Permissions` as the page that offers it, and `Visibility` (`Human`, `Agent`, `Both`). Its `DisplayName`, `Description`, `Visibility` and `Permissions` override the palette defaults (Human, no permissions, generated label); an Agent-only entry stays out of the palette. A derived command with no `[CatalogAction(Permissions = …)]` is offered to every signed-in user, so an action behind a permission must carry `[CatalogAction(Permissions = …)]` or opt out with `[CommandPaletteOptOut("reason")]`. An action that takes a URL or path re-validates it in the handler (for example `LoginPage.GetSafeReturnUrl`): the page is not the only caller. Reference: `features/identity/sign-in-state/` (ceremonies, challenge navigation, post-sign-in navigation) and `features/identity/credentials-state/credentials-state.link-microsoft-365.cs` (a cataloged full-page navigation) under `source/container-apps/web/projects/web-spa/`. # Server-owned availability When whether an action applies right now depends on a server rule (last credential, already linked, state of a record), the server decides and the client reads the answer. Never copy a server rule into the client. 1. **The server owns availability through typed flags.** Each item in a list carries a typed flag per action (`CredentialSummary.CanRevoke`, `CanRename`); a page-level action gets a flag on the page's response (`GetCredentials.Response.CanLinkMicrosoft365`). The read handler sets them from the same rule code the action's handler enforces. Use typed flags, not a list of allowed action names: the compiler checks every read, and there is no string vocabulary to keep in agreement. Flags default to `false`, so a missing flag shows no action. 2. **Item actions live on the page.** A row button dispatches its action directly with the row's item (`RevokeCredential(id)`), shown or enabled from the row's flag, and the page then refreshes the read. The endpoint still enforces the rule (for example a 409 for a stale click), so the flag is guidance for an honest client, not the security boundary. 3. **Parameters the user types get a form on the page,** next to the button (Rename's nickname field). There is no generic form system. 4. **Ctrl-K and other global entry points get navigation and parameter-free actions only.** An item action is reached by going to its page ("revoke a passkey" means opening Passkeys). A parameter-free action whose rule may not hold (Link Microsoft 365) can stay a general command: its own flow reports when it does not apply. Actions that need an item are cataloged with `Visibility = Agent`. 5. **Agents get the Ctrl-K commands whose visibility includes Agent, on every page, plus that page's button actions.** Human-only commands stay out. A page-bound command is executable on its page and, off that page, returns a navigate offer instead of running. Item actions that are not palette commands stay on their page. There is no server-enumerated list of every action on every item. Why: a client copy of a server rule drifts and races (the button shows, the server answers 409), and every surface that wants the rule needs its own copy. A flag is the server's answer for this caller and this snapshot, on the data it describes, so the list and its availability never come from different snapshots. Enumerating every action for every item instead (actions × items) floods global surfaces like Ctrl-K and needs string agreement between server and client for no benefit the page does not already have. Use a flag only where availability needs a server-owned rule. Purely local actions (counter, theme, toggles, navigation, modals) need none, and static permission checks use `[CatalogAction(Permissions = …)]` plus `AuthorizeView` or the catalog's permission filter. Reference: `features/identity/get-credentials/` and `credential-rules-application.cs` (server) under `source/container-apps/web/`; `features/application/pages/SettingsPage.razor` and `features/identity/components/CredentialList.razor` (client) under `web-spa/`. # Agentic UI and WebMCP One catalog-to-tools mapping drives both the in-app model and an external browser agent. - `CatalogAgentToolSet.SelectAsync` reads `CommandPaletteRoster` (the Ctrl-K filter). A command whose visibility includes Agent is a tool on every page. Human-only commands are never tools. - The agent knows the whole app, not only the page on screen. `site_map` (read-only, never approval-wrapped) returns every destination the person's navigation menu shows: title, URL, menu group, icon and the `[Page]` Description, plus Sign in while signed out. `navigate` takes one of those URLs (a URL enum) and refuses anything else; it goes through `RouteState.ChangeRoute` like the palette and asks for approval in Ask before editing. Both read `NavigationDestinations`, the list NavMenu and Ctrl-K render, so the four surfaces cannot drift; a guard test fails if a route literal or `typeof(…Page)` appears in the agent code. Ask's instructions carry the same site map, so it answers "where is X" from Home with a page link. - A page's own executable actions come from its declaration: `[Page(…, AgentActions = [typeof(CredentialsState.AddPasskeyActionSet.Action), …])]`. The generator emits `PageRegistry.ActionScopes` (every route template of each such page), and `PageAgentScope` matches the current path against them and decides which palette commands only execute on their page. There is no hand-written route list. An anonymous principal gets `navigate` and `site_map` only. - Read-only tools are an explicit allow-list of catalog names in `CatalogAgentApproval` (never a name-prefix rule). Every other tool is wrapped in `ApprovalRequiredAIFunction`. WebMCP uses the same split: the shell's confirmation bar (`AgentSurfaceState`) gates dispatch, one call at a time, correlated by call id; navigation cancels a pending page-bound call. A tool that is not page-bound is not cancelled only because the path changed. Both drivers re-select tools for the current principal and route when a tool runs. A global tool stays offered. A page-only tool is refused off its page. A page-bound palette tool off its page returns a navigate offer and does not run. Approval does not grant a permission the principal lacks. - The ask UI is the derived Ctrl-K `AgentSurface.OpenAskPanel` command (signed in) and the top-bar "Ask {AssistantName}" button (always shown). `AssistantName` is the admin-set `SiteSettings` name (default Akili), read anonymously through `GetAssistantIdentity` with its Multiavatar. Every assistant label (button, Ctrl-K row via `AskAssistantDisplayOverride`, panel header, greeting, feedback titles) and the instructions' first line read `AgentSurfaceState.AssistantName`; never hard-code "Ask" or "Ask AI". It opens the `AgentAsk` side panel in `TimeWarpPage`'s FluentLayout aside (`UIAgent` over a `FunctionInvokingChatClient` whose inner client is the browser relay). The page reflows beside the 450px panel. Below 880px, and when expanded, the panel covers the viewport. While Ask is open it owns the aside column; a page `Aside` shows only when Ask is closed. web-server holds `XAI:ApiKey` and forwards completions to xAI. When the key is missing, the panel shows "AI not configured" and: ```pwsh dotnet user-secrets set "XAI:ApiKey" "" --project source/container-apps/web/projects/web-server/web-server.csproj ``` The template registers the relay, not a key. WebMCP does not need a client. - WebMCP registers the same tools (including `site_map` and `navigate`), plus `page_context`, through `document.modelContext.registerTool` (falling back to `navigator.modelContext`, then `provideContext`). A missing API registers nothing. Both paths execute with `ActionCatalogEntry.Execute`. Endpoints keep `[EndpointAuthorize]`. - Page facts live in `PageAgentContext` on every route: path, title, purpose (the `[Page]` Description), a bounded text summary of the page body, and the offered tool names. A state that owns the page's `AgentActions` adds its own facts by implementing `IAgentPageFacts` (ids, server flags, and the records a replace-whole command must echo, including a Version token); there are no per-route cases. Components dispatch `SyncWebMcp` and `ResolveApproval`. They do not call the JS module. Reference: `web-spa/features/application/agent/` and `web-spa/components/WebMcpAgentSurface.razor`. # Action handlers and loading 1. A handler does one thing. It never sends/dispatches another action (no `await XState.Y()` inside `Handle` / `HandleSuccess` / `HandleError`). Pages and components sequence actions. 2. Loading UI comes from the shared `Section` component (`web-spa/components/composites/Section.razor`, port of COPIC `CopicSection`) driven by `ActionTrackingState.IsAnyActive(LoadingActionType)`; no hand-written loading markup. Grids may bind `FluentDataGrid Loading=IsLoading` to `IsAnyActive(FetchX)` instead. Reference: `source/container-apps/web/projects/web-spa/features/style-guide/pages/StyleGuidePage.razor` (Section card). Applied on PrincipalsPage, RolesListPage, RoleDetailPage, and the other former `Loading…` pages. # Server-sorted FluentDataGrid A list that the server pages must also be sorted by the server. Sorting one page in the browser shows the wrong order across pages. The pattern is grid sort → State action → `Query.SortBy`: 1. The query contract carries `SortBy` (a closed enum of the sortable columns) and `SortDescending`, with a default that matches the old fixed order. Stores sort the whole match set before `Skip`/`Take` and end with an id tiebreaker. 2. The state holds `SortBy` / `SortDescending`. A `SetSort` action changes them and resets `Page` to 1. The fetch handler copies them onto the query. 3. The grid gets `Items="@State.Items?.AsQueryable()"` (the current page) and `RefreshItems`. With `RefreshItems` set, the grid does not sort or page `Items` itself. `RefreshItems` maps the primary sort column (`ColumnId` = the enum name) and direction. When they differ from state, it dispatches `SetSort` and then the fetch. Otherwise it returns, so the first render and new rows dispatch nothing. 4. Each sortable column sets `Sortable="true"` and a `SortBy` `GridSort` (the grid needs one to mark a column sortable, but never runs it). `IsDefaultSortColumn` and `InitialSortDirection` follow state, so a re-created grid shows the stored sort. 5. `Loading` binds to `IsAnyActive(typeof(FetchX.Action))`. The grid's `Section` has no `LoadingActionType`: `Section` swaps its content for a spinner, which would destroy the grid. 6. Enum and date cells use `TemplateColumn` (`@context.Kind`). `PropertyColumn` renders enums lowercased. 7. Narrow widths: wrap the grid in `DataGridFrame` and size columns with `DisplayMode="DataGridDisplayMode.Grid"` plus `GridTemplateColumns` of `minmax` tracks. The primary column (the one with the row link) gets `minmax(14rem, 2fr)`; the others get smaller minimums and `fr` shares. No column sets `Width`: fixed widths leave an unsized column the leftover, which is zero at a narrow viewport or with the Ask panel open. Below the minimum total, the grid scrolls inside the frame and header text ends in an ellipsis. The integration test `DataGridFrameGuard` enforces this for every `FluentDataGrid`. Reference: `web-spa/features/admin/feedback/pages/FeedbackAdminListPage.razor` with `ListFeedback.Query` and `FeedbackAdminState.SetSort`; `web-spa/components/composites/DataGridFrame.razor`. # Operation outcomes No page, card, or feature component renders its own `FluentMessageBar` for an operation outcome (success or failure) — the shell's single notification region owns that (`tw-blazor-layout`, "The shell owns the notification region"). Components and handlers only *report* outcomes: - A component reports directly with the generated state methods `AddNotification(intent, title, body)` for a success/info message it composes itself, or `ReportProblem(problem)` when it already holds a `SharedProblemDetails`. - A handler never dispatches another action; it publishes `OutcomeNotification(intent, title, body)` or `ProblemDetailsNotification(problem)` instead. `DefaultApiHandler` already publishes `ProblemDetailsNotification` on failure, so most failure paths need no extra code — only the success sentence is yours to add. - One shape: `Intent`, `Title`, optional `Body`. For a `SharedProblemDetails`, `Title` is the problem's `Title` and `Body` is its `Detail` — never a generic "Error"/"Success" title, and never `Title: Detail` glued into one string. Success bars carry the operation's own sentence ("Passkey added."). - Identical messages (same `Intent`, `Title`, `Body`) replace the existing bar instead of stacking. - Field-level validation is a different class — it stays next to the field (`ValidationMessage` via Blazilla), never in the notification region. - Static, contextual guidance that isn't an outcome (an inline Info/Warning such as "Add a passkey to continue") may stay inline. The analyzer `TWA0025` flags an `Error`/`Success` `FluentMessageBar` outside the shell's host; opt out with `[PageLocalMessageBar("reason")]` on the component when a case is genuinely local. Reference: `source/container-apps/web/projects/web-spa/components/MessageBars.razor` (host) and `features/notification/notification-state/` (state). # Actions, navigation, and forms Actions are `FluentButton` with a style-guide appearance (Primary / Outline / Subtle / Transparent; danger via `--twe-danger`). Navigation is `FluentAnchor`; the menu is `NavMenu` over the page registry. Persisting a model is `EditForm` + `FluentButton` submit (RoleForm). Never raw `