Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4256dac
Heaps of stuff
MelbourneDeveloper Mar 16, 2026
6986969
Add CurlGenerator and SectionScanner to Napper.Core for LSP
MelbourneDeveloper Mar 16, 2026
c83aadc
Apply Fantomas formatting to LSP and Core files
MelbourneDeveloper Mar 16, 2026
f2eabe5
Tests
MelbourneDeveloper Mar 16, 2026
6dfebc0
Formatting
MelbourneDeveloper Mar 16, 2026
5293743
Stuff
MelbourneDeveloper Mar 17, 2026
b2a691f
Stuff
MelbourneDeveloper Mar 17, 2026
a78f678
Merge branch 'main' into AgentSwarmBigBang
MelbourneDeveloper Mar 17, 2026
9e534d2
Installation stuff
MelbourneDeveloper Mar 17, 2026
d2a30bc
All the stuff
MelbourneDeveloper Mar 24, 2026
73bad1f
Switch to make
MelbourneDeveloper Mar 24, 2026
4f8292c
Format
MelbourneDeveloper Mar 24, 2026
e61e3cb
Fixes
MelbourneDeveloper Mar 24, 2026
a3cdee3
Fixed
MelbourneDeveloper Mar 24, 2026
11d49cb
Fix tests
MelbourneDeveloper Mar 24, 2026
7b85baf
fs tests
MelbourneDeveloper Mar 24, 2026
8fdc209
CLI resolution: prefer bundled binary, add debug logging
MelbourneDeveloper Mar 24, 2026
305fb10
Fix CI: Prettier, Fantomas formatting; fix Rust test race condition
MelbourneDeveloper Mar 25, 2026
8a74e81
Fix CI: Rust fmt, TS max-lines lint, F# CLI binary discovery
MelbourneDeveloper Mar 25, 2026
7b98aec
Fixes
MelbourneDeveloper Mar 26, 2026
9f9d952
Fixes
MelbourneDeveloper Mar 26, 2026
8cd6fb5
Test fixes
MelbourneDeveloper Mar 26, 2026
7b65024
coverage
MelbourneDeveloper Mar 26, 2026
3b0aec3
Fix CI: add LSP tests to Makefile, skip subprocess coverage threshold
MelbourneDeveloper Mar 26, 2026
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
72 changes: 72 additions & 0 deletions .claude/skills/fix-ci/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
name: fix-ci
description: Fetches the latest GitHub Actions logs for the current branch's PR, analyzes all failures, and fixes them. Use when CI is red, a PR has failing checks, or the user says "fix ci". Requires an open PR for the current branch.
argument-hint: "[optional job name to focus on]"
allowed-tools: Read, Grep, Glob, Edit, Write, Bash
---

# Fix CI

Diagnose and fix all GitHub Actions failures for the current branch's PR.

## Step 1: Validate branch has a PR

```bash
BRANCH=$(git branch --show-current)
PR_JSON=$(gh pr list --head "$BRANCH" --state open --json number,title,url --limit 1)
```

If the JSON array is empty, **stop immediately**:
> No open PR found for branch `$BRANCH`. Create a PR first.

Otherwise extract the PR number and continue.

## Step 2: Fetch failed logs

```bash
PR_NUMBER=$(echo "$PR_JSON" | jq -r '.[0].number')
gh pr checks "$PR_NUMBER"
RUN_ID=$(gh run list --branch "$BRANCH" --limit 1 --json databaseId --jq '.[0].databaseId')
gh run view "$RUN_ID"
gh run view "$RUN_ID" --log-failed
```

Read **every line** of `--log-failed` output. For each failure note the exact file, line, and error message.

If `$ARGUMENTS` specifies a job name, prioritize that job but still report all failures.

## Step 3: Categorize and fix

Work through failures in this order:

1. **Formatting** — run auto-formatters first to clear noise
2. **Compilation errors** — must compile before lint/test
3. **Lint violations** — fix the code pattern
4. **Runtime / test failures** — fix source code to satisfy the test

### Hard constraints

- **NEVER modify test files** — fix the source code, not the tests
- **NEVER add suppressions** (`#[allow(...)]`, `// eslint-disable`, `#pragma warning disable`)
- **NEVER use `any` in TypeScript** to silence type errors
- **NEVER delete or ignore failing tests**
- **NEVER remove assertions**

## Step 4: Loop `make ci` until green

```bash
make ci
```

If it fails: read output, fix the issue (same constraints as Step 3), run again. **Keep looping until a full pass is clean.**

If stuck on the same failure after 5 attempts, ask the user for help.

## Step 5: Commit/Push

Once `make ci` passes:

1. Commit, but DO NOT MARK THE COMMIT WITH YOU AS AN AUTHOR!!!
2. Push
3. Monitor until completion or failure
4. Upon failure, go back to the start of this document
13 changes: 13 additions & 0 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"fantomas": {
"version": "7.0.5",
"commands": [
"fantomas"
],
"rollForward": false
}
}
}
37 changes: 37 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
root = true

[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.{fs,fsx}]
indent_size = 4

# F# compiler diagnostics — all unused things are errors
dotnet_diagnostic.FS1182.severity = error

# Opt-in warnings elevated to errors
dotnet_diagnostic.FS3388.severity = error
dotnet_diagnostic.FS3389.severity = error
dotnet_diagnostic.FS3390.severity = error
dotnet_diagnostic.FS3391.severity = error
dotnet_diagnostic.FS3395.severity = error
dotnet_diagnostic.FS3559.severity = error
dotnet_diagnostic.FS3560.severity = error
dotnet_diagnostic.FS3582.severity = error

[*.ts]
indent_size = 2

[*.json]
indent_size = 2

[*.{yml,yaml}]
indent_size = 2

[*.rs]
indent_size = 4
208 changes: 203 additions & 5 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,33 @@ jobs:
runs-on: ubuntu-latest
defaults:
run:
working-directory: src/Nap.VsCode
working-directory: src/Napper.VsCode
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: src/Napper.VsCode/package-lock.json

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

- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.fsproj') }}
restore-keys: ${{ runner.os }}-nuget-

- name: Install dependencies
run: npm ci

- name: Format check
run: npm run format:check

- name: Lint
run: npm run lint

Expand All @@ -34,15 +46,38 @@ jobs:
- name: Unit tests with coverage
run: npm run test:unit

- name: Add CLI to PATH
run: echo "${{ github.workspace }}/src/Napper.VsCode/bin" >> "$GITHUB_PATH"

- name: E2E tests
run: xvfb-run --auto-servernum npm test

- name: Extract TypeScript coverage percentage
id: ts-coverage
run: |
COVERAGE=$(npx c8 report --reporter text 2>/dev/null | grep 'All files' | awk '{print $4}' || echo "0")
echo "coverage=$COVERAGE" >> "$GITHUB_OUTPUT"

- name: Check TypeScript coverage threshold
run: |
ACTUAL="${{ steps.ts-coverage.outputs.coverage }}"
THRESHOLD="${{ vars.TS_COVERAGE_THRESHOLD }}"
echo "TypeScript coverage: ${ACTUAL}% (threshold: ${THRESHOLD}%)"
if [ -z "$THRESHOLD" ] || [ "$THRESHOLD" = "0" ]; then
echo "No threshold set — skipping"
exit 0
fi
if (( $(echo "$ACTUAL < $THRESHOLD" | bc -l) )); then
echo "::error::TypeScript coverage ${ACTUAL}% is below threshold ${THRESHOLD}%"
exit 1
fi

- name: Upload TypeScript coverage
if: always()
uses: actions/upload-artifact@v4
with:
name: typescript-coverage
path: coverage/typescript/report/
path: src/Napper.VsCode/coverage/

test-fsharp:
name: F# Build & Tests
Expand All @@ -54,17 +89,73 @@ jobs:
with:
dotnet-version: "10.0.x"

- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.fsproj') }}
restore-keys: ${{ runner.os }}-nuget-

- name: Install ReportGenerator
run: dotnet tool install --global dotnet-reportgenerator-globaltool

- name: Install dotnet-script
run: dotnet tool install -g dotnet-script

- name: Build
run: dotnet build --nologo
- name: Restore tools
run: dotnet tool restore

- name: Format check (Fantomas)
run: dotnet fantomas --check src/

- name: Restore
run: dotnet restore

- name: Build (warnings are errors)
run: dotnet build --no-restore --nologo -warnaserror

- name: Test with coverage
run: bash scripts/test-fsharp.sh
run: make test-fsharp

- name: Extract Napper.Core coverage percentage
id: napcore-coverage
run: |
COVERAGE=$(grep -oP 'Line coverage: \K[0-9.]+' coverage/fsharp/report/Summary.txt || echo "0")
echo "coverage=$COVERAGE" >> "$GITHUB_OUTPUT"

- name: Check Napper.Core coverage threshold
run: |
ACTUAL="${{ steps.napcore-coverage.outputs.coverage }}"
THRESHOLD="${{ vars.FSHARP_COVERAGE_THRESHOLD }}"
echo "Napper.Core coverage: ${ACTUAL}% (threshold: ${THRESHOLD}%)"
if [ -z "$THRESHOLD" ] || [ "$THRESHOLD" = "0" ]; then
echo "No threshold set — skipping"
exit 0
fi
if (( $(echo "$ACTUAL < $THRESHOLD" | bc -l) )); then
echo "::error::Napper.Core coverage ${ACTUAL}% is below threshold ${THRESHOLD}%"
exit 1
fi

- name: Extract DotHttp coverage percentage
id: dothttp-coverage
run: |
COVERAGE=$(grep -oP 'Line coverage: \K[0-9.]+' coverage/dothttp/report/Summary.txt || echo "0")
echo "coverage=$COVERAGE" >> "$GITHUB_OUTPUT"

- name: Check DotHttp coverage threshold
run: |
ACTUAL="${{ steps.dothttp-coverage.outputs.coverage }}"
THRESHOLD="${{ vars.DOTHTTP_COVERAGE_THRESHOLD }}"
echo "DotHttp coverage: ${ACTUAL}% (threshold: ${THRESHOLD}%)"
if [ -z "$THRESHOLD" ] || [ "$THRESHOLD" = "0" ]; then
echo "No threshold set — skipping"
exit 0
fi
if (( $(echo "$ACTUAL < $THRESHOLD" | bc -l) )); then
echo "::error::DotHttp coverage ${ACTUAL}% is below threshold ${THRESHOLD}%"
exit 1
fi

- name: Upload F# coverage
if: always()
Expand All @@ -73,6 +164,111 @@ jobs:
name: fsharp-coverage
path: coverage/fsharp/report/

- name: Upload DotHttp coverage
if: always()
uses: actions/upload-artifact@v4
with:
name: dothttp-coverage
path: coverage/dothttp/report/

- name: Extract Napper.Lsp coverage percentage
id: lsp-coverage
run: |
if [ -f coverage/lsp/report/Summary.txt ]; then
COVERAGE=$(grep -oP 'Line coverage: \K[0-9.]+' coverage/lsp/report/Summary.txt || echo "0")
else
COVERAGE="0"
fi
echo "coverage=$COVERAGE" >> "$GITHUB_OUTPUT"

- name: Check Napper.Lsp coverage threshold
run: |
ACTUAL="${{ steps.lsp-coverage.outputs.coverage }}"
THRESHOLD="${{ vars.LSP_COVERAGE_THRESHOLD }}"
echo "Napper.Lsp coverage: ${ACTUAL}% (threshold: ${THRESHOLD}%)"
if [ -z "$THRESHOLD" ] || [ "$THRESHOLD" = "0" ]; then
echo "No threshold set — skipping"
exit 0
fi
if [ "$ACTUAL" = "0" ] && grep -q 'Assemblies: 0' coverage/lsp/report/Summary.txt 2>/dev/null; then
echo "LSP tests are integration tests (subprocess) — skipping coverage threshold"
exit 0
fi
if (( $(echo "$ACTUAL < $THRESHOLD" | bc -l) )); then
echo "::error::Napper.Lsp coverage ${ACTUAL}% is below threshold ${THRESHOLD}%"
exit 1
fi

- name: Upload Napper.Lsp coverage
if: always()
uses: actions/upload-artifact@v4
with:
name: lsp-coverage
path: coverage/lsp/report/

test-rust:
name: Rust Build & Tests
runs-on: ubuntu-latest
defaults:
run:
working-directory: src/Napper.Zed
steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt

- name: Cache Cargo registry and build
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
src/Napper.Zed/target
key: ${{ runner.os }}-cargo-${{ hashFiles('src/Napper.Zed/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-

- name: Format check
run: cargo fmt -- --check

- name: Clippy
run: cargo clippy

- name: Install cargo-tarpaulin
run: cargo install cargo-tarpaulin

- name: Test with coverage
run: cargo tarpaulin --out xml html --output-dir ../../coverage/rust/report --skip-clean

- name: Extract Rust coverage percentage
id: rust-coverage
run: |
COVERAGE=$(grep -oP 'line-rate="\K[0-9.]+' ../../coverage/rust/report/cobertura.xml 2>/dev/null || echo "0")
COVERAGE_PCT=$(echo "$COVERAGE * 100" | bc -l | xargs printf "%.2f")
echo "coverage=$COVERAGE_PCT" >> "$GITHUB_OUTPUT"

- name: Check Rust coverage threshold
run: |
ACTUAL="${{ steps.rust-coverage.outputs.coverage }}"
THRESHOLD="${{ vars.RUST_COVERAGE_THRESHOLD }}"
echo "Rust coverage: ${ACTUAL}% (threshold: ${THRESHOLD}%)"
if [ -z "$THRESHOLD" ] || [ "$THRESHOLD" = "0" ]; then
echo "No threshold set — skipping"
exit 0
fi
if (( $(echo "$ACTUAL < $THRESHOLD" | bc -l) )); then
echo "::error::Rust coverage ${ACTUAL}% is below threshold ${THRESHOLD}%"
exit 1
fi

- name: Upload Rust coverage
if: always()
uses: actions/upload-artifact@v4
with:
name: rust-coverage
path: coverage/rust/report/

build-website:
name: Website Build
runs-on: ubuntu-latest
Expand All @@ -85,6 +281,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: website/package-lock.json

- name: Install dependencies
run: npm ci
Expand Down
Loading
Loading