Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 0 additions & 30 deletions .appveyor.yml

This file was deleted.

29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI

on:
pull_request:
push:
branches: [main]
paths-ignore:
- 'README.md'
- 'agent-context/**'

jobs:
build-and-test:
runs-on: windows-latest

steps:
- uses: actions/checkout@v4

- uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'

- name: Restore Cake tool
run: dotnet tool restore

- name: Cake bootstrap
run: dotnet cake build.cake --bootstrap --target=Test --buildNumber=${{ github.run_number }} --branch="${{ github.ref_name }}" --buildPath="${{ github.workspace }}"

- name: Build and test
run: dotnet cake build.cake --target=Test --buildNumber=${{ github.run_number }} --branch="${{ github.ref_name }}" --buildPath="${{ github.workspace }}"
28 changes: 28 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Release

on:
push:
branches: [main]
paths-ignore:
- 'README.md'
- 'agent-context/**'

jobs:
build-test-publish:
runs-on: windows-latest

steps:
- uses: actions/checkout@v4

- uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'

- name: Restore Cake tool
run: dotnet tool restore

- name: Cake bootstrap
run: dotnet cake build.cake --bootstrap --buildNumber=${{ github.run_number }} --branch="${{ github.ref_name }}" --buildPath="${{ github.workspace }}" --gitHubApiKey="${{ secrets.RELEASE_GITHUB_API_KEY }}" --nuGetApiKey="${{ secrets.NUGET_API_KEY }}"

- name: Build, test, and publish
run: dotnet cake build.cake --buildNumber=${{ github.run_number }} --branch="${{ github.ref_name }}" --buildPath="${{ github.workspace }}" --gitHubApiKey="${{ secrets.RELEASE_GITHUB_API_KEY }}" --nuGetApiKey="${{ secrets.NUGET_API_KEY }}"
11 changes: 11 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# AGENTS.md

## Agent skills

### Issue tracker

Issues and specs live as markdown files under `.scratch/<feature-slug>/`. See `docs/agents/issue-tracker.md`.

### Domain docs

Single-context: `CONTEXT.md` + `docs/adr/` at repo root (created lazily by `/domain-modeling`). See `docs/agents/domain.md`.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ A C# source generator that generates enums for all font codepoint files are cont
Each resulting enum can be used for strongly-typed references to the byte value of specific glyphs in the associated font.

# Links
[![Build status](https://ci.appveyor.com/api/projects/status/2lgs7mbehdvls38q?svg=true)](https://ci.appveyor.com/project/tpwalke2/codepointenumgenerator)
[![Build status](https://github.com/tpwalke2/CodePointEnumGenerator/actions/workflows/ci.yml/badge.svg)](https://github.com/tpwalke2/CodePointEnumGenerator/actions/workflows/ci.yml)

[![NuGet](https://img.shields.io/nuget/v/CodePointEnumGenerator.svg)](https://www.nuget.org/packages/CodePointEnumGenerator/)

Expand Down
25 changes: 25 additions & 0 deletions agent-context/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# CodePointEnumGenerator — Agent Context

Roslyn incremental source generator (C#, `netstandard2.0`). Reads font `.codepoints` files marked as `AdditionalFiles` and emits one strongly-typed enum per file mapping glyph names to hex byte values. Packed and shipped as a NuGet analyzer package. Built with Cake, CI on GitHub Actions, releases via GitHub + NuGet.

## Context docs

| Doc | Covers |
|---|---|
| `context/architecture.md` | Stack, layout, generator pipeline, helpers, `.codepoints` format |
| `context/testing.md` | xunit test layout, `GeneratorTestFactory` harness, how to run tests |
| `context/build-and-release.md` | Cake pipeline, GitHub Actions CI, versioning, GitHub/NuGet release flow |

## Existing human docs
Root `README.md` — package usage snippet, troubleshooting, build pipeline requirements.

## Document Scopes

| Document | Codebase paths watched |
|---|---|
| `context/architecture.md` | `CodePointEnumGenerator/`, `CodePointEnumGenerator.csproj`, `CodePointEnumGenerator.sln` |
| `context/testing.md` | `CodePointEnumGenerator.Tests/` |
| `context/build-and-release.md` | `build.cake`, `build/`, `bootstrap.ps1`, `.github/workflows/`, `.config/dotnet-tools.json` |

---
*Last updated: 2026-09-20 | Verified against: 6b6c9cc*
55 changes: 55 additions & 0 deletions agent-context/context/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Architecture

## What this is
Roslyn incremental source generator. Scans project `AdditionalFiles` ending in `.codepoints`, emits one C# enum per file mapping glyph names to hex byte values (for strongly-typed font glyph references).

## Tech stack

| Layer | Technology |
|---|---|
| Generator project | `netstandard2.0`, C# 14, `Microsoft.CodeAnalysis.CSharp` 5.9.0 |
| Test project | `net10.0`, xunit 2.9.3, `Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit` |
| Build | Cake (`build.cake` + `build/*.cake`), driven by `bootstrap.ps1` |
| CI | GitHub Actions (`.github/workflows/ci.yml`, `release.yml`), `windows-latest` |
| Packaging | NuGet (`CodePointEnumGenerator` package), GitHub Releases on publish |

## Top-level layout

| Path | Purpose |
|---|---|
| `CodePointEnumGenerator/` | The generator itself, packed as analyzer |
| `CodePointEnumGenerator/CodePointEnumGenerator.cs` | `IIncrementalGenerator` entry point |
| `CodePointEnumGenerator/Helpers/` | Pure helper logic (name parsing, code emission, number-to-words) |
| `CodePointEnumGenerator.Tests/` | xunit tests against generator and helpers |
| `build/` | Cake build scripts (config, paths, build/test/publish operations, GitHub API models) |
| `build.cake` | Cake entry: Clean → Build → Test → Publish tasks |
| `bootstrap.ps1` | Restores `dotnet tool` (cake.tool) and runs `build.cake` |
| `output/artifacts/` | Packed `.nupkg` output |
| `.config/dotnet-tools.json` | Pins `cake.tool` 3.0.0 |

## Generator pipeline (`CodePointEnumGenerator/CodePointEnumGenerator.cs`)

1. `GetCodePointFiles` filters `context.AdditionalTextsProvider` to paths ending `.codepoints`.
2. For each file, project a tuple:
- `Name` = `AdditionalTextExtensions.GetEnumFileName()` — filename minus `.codepoints`, minus `-`.
- `Content` = file text run through `StringExtensions.GetEnumValues()` — parses `name value` lines into `(enumEntryName, hexValue)` tuples, deduping names by suffixing a counter.
- `Namespace` = `StringExtensions.ToNamespace()` — derives a namespace from the file's folder path (skips drive letter, starts at first segment containing a `.`).
3. `context.RegisterSourceOutput` emits `{Name}.g.cs` via `CodeGeneration.BuildEnumFileContents`, which renders `namespace {ns}; public enum {Name} { ENTRY = 0xVALUE, ... }`.

## Helpers (`CodePointEnumGenerator/Helpers/`)

| File | Responsibility |
|---|---|
| `AdditionalTextExtensions.cs` | `GetEnumFileName()` — derive enum type name from file path |
| `StringExtensions.cs` | `ToNamespace()`, `ToEnumEntry()` (name → PascalCase enum member, numeric prefixes spelled out via `EnglishNumberToWordsConverter`), `GetEnumValues()` (parse `.codepoints` file contents) |
| `CodeGeneration.cs` | `BuildEnumFileContents()` — renders the final enum source text |
| `EnglishNumberToWordsConverter.cs` | Internal; spells out numeric enum-name prefixes (e.g. `1_foo` → `OneFoo`). Adapted from Humanizer |

## `.codepoints` file format
Plain text, one glyph per line: `<name> <hex-value>` (space-separated, exactly 2 tokens). Names run through `ToEnumEntry`: leading digits spelled as words, `_`-separated words PascalCased and concatenated.

## Consumer usage
Consuming projects reference the package with `OutputItemType="Analyzer"` and mark `.codepoints` files with build action `AdditionalFiles`. See root `README.md` for the exact snippet and troubleshooting steps.

---
*Last updated: 2026-09-20 | Verified against: 6b6c9cc*
35 changes: 35 additions & 0 deletions agent-context/context/build-and-release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Build & Release

## Local build
`bootstrap.ps1` restores the `dotnet tool` manifest (`.config/dotnet-tools.json`, pins `cake.tool` 3.0.0) then runs `dotnet cake build.cake` twice (bootstrap pass, then real run), passing `buildNumber`, `branch`, `buildPath`, `gitHubApiKey`, `nuGetApiKey`. Checks `$LASTEXITCODE` after each step and exits non-zero on failure — `gitHubApiKey`/`nuGetApiKey` may be omitted for non-release builds (see below).

## Cake pipeline (`build.cake` + `build/*.cake`)
Tasks, in dependency order: `Clean` → `Build` → `Test` → `Publish` → `Default`.

| Script | Role |
|---|---|
| `build/BuildConfig.cake` | CLI argument binding (`Cake.ArgumentBinder`) — target, buildNumber, branch, buildPath, API keys, verbose, maxDegreeOfParallelism, currentVersion |
| `build/BuildPaths.cake` | Resolves `output/`, `output/deploy/`, `output/deploy/test-results/`, `output/artifacts/` |
| `build/Utilities.cake` | `GetVersion` (`{CurrentRelease}.{BuildNumber}`), `ParallelInvoke`, `FlushDns` |
| `build/BuildOperations.cake` | `DoBuild` — parallel clean of Debug/Release, restore, `DotNetBuild` (Debug config) |
| `build/TestProject.cake` | `TestProject` record (path + target framework) |
| `build/TestOperations.cake` | `DoTest` — `dotnet test` per project, `trx` logger, into `output/deploy/test-results` |
| `build/PublishOperations.cake` | `DoPublish` — only runs `IsRelease(branch)` (branch == `main`); packs, creates a GitHub release (`Release-{version}` tag), uploads the `.nupkg` asset, pushes to NuGet |
| `build/GitHubApiModels.cake` | Request/response DTOs for the GitHub Releases REST API |

Version = `CurrentRelease` (default `1.0.0`) + `.` + `buildNumber` argument, unless `currentVersion` is overridden.

## CI (`.github/workflows/`)
Two GitHub Actions workflows, both `windows-latest` (Cake's `FlushDns` NuGet-publish workaround needs Windows), both ignore changes to `README.md` and `agent-context/**`:
- `ci.yml` — triggers on `pull_request` (any target) and `push` to `main`. Runs `dotnet tool restore` + both Cake steps directly (bypassing `bootstrap.ps1`, so a failed step fails the job natively). No secrets passed; `Publish` no-ops via `IsRelease(branch)`.
- `release.yml` — triggers on `push` to `main` only (no `pull_request`, no tags — avoids retriggering off the tag it creates). Same steps, plus `RELEASE_GITHUB_API_KEY`/`NUGET_API_KEY` repo secrets and `buildNumber=${{ github.run_number }}`.

AppVeyor is retired (`.appveyor.yml` removed).

## Release requirements
- GitHub PAT with read/write on Contents (release creation + asset upload), stored as the `RELEASE_GITHUB_API_KEY` repo secret.
- NuGet API key (push to `https://api.nuget.org/v3/index.json`), stored as the `NUGET_API_KEY` repo secret. Plan is to move to NuGet Trusted Publishing later.
- Every release on `main` creates a `Release-{version}` GitHub tag/release with auto-generated notes, and publishes the same `.nupkg` to NuGet.

---
*Last updated: 2026-09-20 | Verified against: 6b6c9cc*
29 changes: 29 additions & 0 deletions agent-context/context/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Testing

## Framework
xunit 2.9.3 in `CodePointEnumGenerator.Tests`, targets `net10.0` (generator itself targets `netstandard2.0`). Test project references the generator via `ProjectReference`.

## Layout

| File | Covers |
|---|---|
| `CodePointEnumGeneratorTests.cs` | End-to-end: runs the generator via `GeneratorTestFactory` and checks emitted enum source |
| `GeneratorTestFactory.cs` | Test harness — builds a `CSharpCompilation`, runs `CodePointEnumGenerator` through `CSharpGeneratorDriver` against fake `AdditionalText` files, returns compilation/diagnostics/run-result |
| `AdditionalFile.cs` | Minimal `AdditionalText` implementation for feeding fake `.codepoints` content into the driver |
| `Helpers/GetEnumFileNameTests.cs` | `AdditionalTextExtensions.GetEnumFileName()` |
| `Helpers/GetEnumValuesTests.cs` | `StringExtensions.GetEnumValues()` |
| `Helpers/ToEnumEntryTests.cs` | `StringExtensions.ToEnumEntry()` |
| `Helpers/ToNamespaceTests.cs` | `StringExtensions.ToNamespace()` |

## Running the generator in tests
`GeneratorTestFactory.RunGenerator(source, additionalFiles...)`:
- Parses `source` as a syntax tree, compiles against `object` + the generator assembly.
- Pre-verifies diagnostics, ignoring a fixed set of expected errors (`CS0012`, `CS0616`, `CS0246`, `CS0103` — incomplete-reference noise from the minimal test compilation).
- Wraps each `(path, contents)` tuple as an `AdditionalFile` and runs `CodePointEnumGenerator` through `CSharpGeneratorDriver.RunGeneratorsAndUpdateCompilation`.
- Returns `(Compilation, (DiagnosticsBefore, DiagnosticsAfter), GeneratorDriverRunResult)` for assertions.

## Running tests
Via Cake: `Task("Test")` in `build.cake` runs `dotnet test` (framework `net10.0`, `trx` logger) against every `*Tests.csproj`, in parallel (`build/TestOperations.cake`, `build/TestProject.cake`). Locally: `dotnet test` from repo root or the test project directly.

---
*Last updated: 2026-09-20 | Verified against: 6b6c9cc*
14 changes: 14 additions & 0 deletions agent-context/reviews/copilot-review-2026-09-20.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# .github/workflows/ci.yml:25-29

- On pushes to main, this workflow still runs the default Cake target, which reaches Publish; because this job passes no API keys, DoGitHubRelease/DoNuGetPublish throw and the CI job fails (while the release workflow is running in parallel). Run the Test target for both commands here, or otherwise exclude main from this workflow.

# agent-context/README.md:1-3

- This overview still says CI runs on AppVeyor, but this PR deletes .appveyor.yml and adds GitHub Actions workflows. Agents using this context will be directed to the retired CI system; update the sentence to describe GitHub Actions.
- This issue also appears in the following locations of the same file:
- line 11
- line 22

# agent-context/context/architecture.md:10-13

- The architecture snapshot still identifies AppVeyor and .appveyor.yml as the CI implementation, but that file is removed and CI is now in .github/workflows/. Update this current-state row so the architecture documentation does not direct readers to a nonexistent pipeline.
6 changes: 5 additions & 1 deletion bootstrap.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ param (
[System.String]$nuGetApiKey)

dotnet tool restore
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

dotnet cake build.cake --bootstrap --buildNumber=$buildNumber --branch="$branch" --buildPath="$buildPath" --gitHubApiKey="$gitHubApiKey" --nuGetApiKey="$nuGetApiKey"
dotnet cake build.cake --buildNumber=$buildNumber --branch="$branch" --buildPath="$buildPath" --gitHubApiKey="$gitHubApiKey" --nuGetApiKey="$nuGetApiKey"
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

dotnet cake build.cake --buildNumber=$buildNumber --branch="$branch" --buildPath="$buildPath" --gitHubApiKey="$gitHubApiKey" --nuGetApiKey="$nuGetApiKey"
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
8 changes: 4 additions & 4 deletions build/BuildConfig.cake
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ public class BuildConfig

[StringArgument(
"nuGetApiKey",
Description = "The API key for interacting with NuGet.",
Required = true
Description = "The API key for interacting with NuGet. Only required when publishing a release.",
DefaultValue = ""
)]
public string NuGetApiKey { get; set; }

[StringArgument(
"gitHubApiKey",
Description = "The API key for interacting with GitHub.",
Required = true
Description = "The API key for interacting with GitHub. Only required when publishing a release.",
DefaultValue = ""
)]
public string GitHubApiKey { get; set; }

Expand Down
51 changes: 51 additions & 0 deletions docs/agents/domain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Domain Docs

How the engineering skills should consume this repo's domain documentation when exploring the codebase.

## Before exploring, read these

- **`CONTEXT.md`** at the repo root, or
- **`CONTEXT-MAP.md`** at the repo root if it exists — it points at one `CONTEXT.md` per context. Read each one relevant to the topic.
- **`docs/adr/`** — read ADRs that touch the area you're about to work in. In multi-context repos, also check `src/<context>/docs/adr/` for context-scoped decisions.

If any of these files don't exist, **proceed silently**. Don't flag their absence; don't suggest creating them upfront. The `/domain-modeling` skill (reached via `/grill-with-docs` and `/improve-codebase-architecture`) creates them lazily when terms or decisions actually get resolved.

## File structure

Single-context repo (most repos):

```
/
├── CONTEXT.md
├── docs/adr/
│ ├── 0001-event-sourced-orders.md
│ └── 0002-postgres-for-write-model.md
└── src/
```

Multi-context repo (presence of `CONTEXT-MAP.md` at the root):

```
/
├── CONTEXT-MAP.md
├── docs/adr/ ← system-wide decisions
└── src/
├── ordering/
│ ├── CONTEXT.md
│ └── docs/adr/ ← context-specific decisions
└── billing/
├── CONTEXT.md
└── docs/adr/
```

## Use the glossary's vocabulary

When your output names a domain concept (in an issue title, a refactor proposal, a hypothesis, a test name), use the term as defined in `CONTEXT.md`. Don't drift to synonyms the glossary explicitly avoids.

If the concept you need isn't in the glossary yet, that's a signal — either you're inventing language the project doesn't use (reconsider) or there's a real gap (note it for `/domain-modeling`).

## Flag ADR conflicts

If your output contradicts an existing ADR, surface it explicitly rather than silently overriding:

> _Contradicts ADR-0007 (event-sourced orders) — but worth reopening because…_
30 changes: 30 additions & 0 deletions docs/agents/issue-tracker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Issue tracker: Local Markdown

Issues and specs for this repo live as markdown files in `.scratch/`.

## Conventions

- One feature per directory: `.scratch/<feature-slug>/`
- The spec is `.scratch/<feature-slug>/spec.md`
- Implementation issues are one file per ticket at `.scratch/<feature-slug>/issues/<NN>-<slug>.md`, numbered from `01` — never a single combined tickets file
- Triage state is recorded as a `Status:` line near the top of each issue file (see `triage-labels.md` for the role strings)
- Comments and conversation history append to the bottom of the file under a `## Comments` heading

## When a skill says "publish to the issue tracker"

Create a new file under `.scratch/<feature-slug>/` (creating the directory if needed).

## When a skill says "fetch the relevant ticket"

Read the file at the referenced path. The user will normally pass the path or the issue number directly.

## Wayfinding operations

Used by `/wayfinder`. The **map** is a file with one **child** file per ticket.

- **Map**: `.scratch/<effort>/map.md` — the Notes / Decisions-so-far / Fog body.
- **Child ticket**: `.scratch/<effort>/issues/NN-<slug>.md`, numbered from `01`, with the question in the body. A `Type:` line records the ticket type (`research`/`prototype`/`grilling`/`task`); a `Status:` line records `claimed`/`resolved`.
- **Blocking**: a `Blocked by: NN, NN` line near the top. A ticket is unblocked when every file it lists is `resolved`.
- **Frontier**: scan `.scratch/<effort>/issues/` for files that are open, unblocked, and unclaimed; first by number wins.
- **Claim**: set `Status: claimed` and save before any work.
- **Resolve**: append the answer under an `## Answer` heading, set `Status: resolved`, then append a context pointer (gist + link) to the map's Decisions-so-far in `map.md`.
Loading