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
13 changes: 13 additions & 0 deletions .agents/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# AgentPMO integration

AgentPMO is cloned separately at `../AgentPMOWorkflow`. The installed templates come from [Nimblesite/AgentPMOWorkflow](https://github.com/Nimblesite/AgentPMOWorkflow/tree/372ce7fafc82305d60be901892d965c7cbe0ce3c), revision `372ce7fafc82305d60be901892d965c7cbe0ce3c`. The upstream MIT notice is retained in `skills/AGENTPMO-LICENSE`.

All seven template skills are in `skills/`: `fix-bug`, `ci-prep`, `submit-pr`, `upgrade-packages`, `code-dedup`, `spec-check`, and `website-audit`. Their workflows are preserved with repository context added; package-upgrade examples are limited to NuGet and npm. The root `AGENTS.md` maps upstream Makefile commands to this repository's existing commands.

The light setup adds CodeQL for C#, website JavaScript, and Actions, and AgentPMO's grouped Dependabot staging model. The existing CI pipeline is retained as `.github/workflows/ci.yml`, with cancellation of superseded runs and an explicit F# test step.

Dependabot's sweep uses the trusted base workflow and only handles same-repository PRs authored and triggered by Dependabot. It checks out the staging branch, merges Git data, and never executes files from the incoming PR. Updates reach `main` through a separately reviewed consolidation PR.

Full standards enforcement, dashboard scheduling, extra developer tools, coverage-policy changes, repository restructuring, and release-workflow changes are outside this light integration. Existing application code and tests are unchanged.

To update the integration later, compare these files with the pinned upstream templates and retain this scope; do not run the full setup or standards-enforcement workflow automatically.
21 changes: 21 additions & 0 deletions .agents/skills/AGENTPMO-LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Nimblesite

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
124 changes: 124 additions & 0 deletions .agents/skills/ci-prep/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
---
name: ci-prep
description: Prepares the current branch for CI by running the exact same steps locally and fixing issues. If CI is already failing, fetches the GH Actions logs first to diagnose. Use before pushing, when CI is red, or when the user says "fix ci".
---
<!-- agent-pmo:372ce7f -->

## RestClient.Net context

The CI entry point is `.github/workflows/ci.yml`; inspect its actual dotnet commands. Root `AGENTS.md` lists the local equivalents. Get Actions run IDs from `gh pr view <number> --json statusCheckRollup` when a branch-filtered run lookup returns nothing.

# CI Prep

Prepare the current state for CI. If CI is already failing, fetch and analyze the logs first.

## Arguments

- `--failing` — Indicates a GitHub Actions run is already failing. When present, you MUST execute **Step 1** before doing anything else.
- Any other argument is treated as a job name to focus on (but all failures are still reported).

If `--failing` is NOT passed, skip directly to **Step 2**.

## Step 1 — Fetch failed CI logs (only when `--failing`)

You MUST do this before any other work.

```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 fetch the 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 a job name argument was provided, prioritize that job but still report all failures.

## Step 2 — Analyze the CI workflow

1. Find the CI workflow file. Look in `.github/workflows/` for `ci.yml`, `build.yml`, `test.yml`, `checks.yml`, `main.yml`, `pull_request.yml`, or any workflow triggered on `pull_request` or `push`.
2. Read the workflow file completely. Parse every job and every step.
3. Extract the ordered list of commands the CI actually runs. In a spec-compliant repo this is `make lint → make test → make build` (REPO-STANDARDS-SPEC [MAKE-TARGETS]), but the actual CI may use `npm`, `cargo`, `dotnet`, raw shell commands, or anything else. Extract what is *actually there*.
4. Note any environment variables, matrix strategies, or conditional steps that affect execution.

**Do NOT assume the steps are `make lint`, `make test`, `make build`.** The actual CI may run different commands, in a different order. Extract what the CI *actually does*. If you find extra targets beyond the 7 in [MAKE-TARGETS] (e.g. `make fmt-check`, `make coverage-check`), flag them in your final report — they should be consolidated by the agent-pmo skill.

### Release workflow blocker scan

If `.github/workflows/release.yml` exists, scan it before broad local CI. These are critical blockers
and must be fixed before release work is considered CI-ready:

- Tag-triggered jobs checking out `ref: main` instead of the tagged SHA.
- Any `git commit`, `git push`, branch mutation, or tag mutation during release.
- Version bump commits after the tag already exists.
- Ad hoc `sed` version stamping of structured files instead of a first-class stamper/build input.
- Missing tests that pass a test version into the same stamper used by release.
- Native VSIX releases without Node `22.x`, `npx vsce package --target <vsceTarget>`, one VSIX per
target, target-suffixed filenames, and package-content verification.
- VS Code native-binary activation that reads or mutates PATH, uses package-manager/global installs
as normal startup sources, or copies bundled VSIX binaries after install.

## Step 3 — Run each CI step locally, in order

Work through failures in this priority 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

For each command extracted from the CI workflow:

1. Run the command exactly as CI would run it (adjusting only for local environment differences like not needing `actions/checkout`).
2. If the step fails, **stop and fix the issues** before continuing to the next step.
3. After fixing, re-run the same step to confirm it passes.
4. Move to the next step only after the current one succeeds.

### 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**

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

## Step 4 — Report

- List every step that was run and its result (pass/fail/fixed).
- If any step could not be fixed, report what failed and why.
- Confirm whether the branch is ready to push.

## Step 5 — Remote CI follow-up (only when `--failing`)

Once all CI steps pass locally:

1. Report the local fixes and exact commands that now pass.
2. Do not commit or push. The user owns source-control writes.
3. If the user pushes, monitor the new run until completion or failure.
4. Upon failure, go back to Step 1.

## Rules

- **Always read the CI workflow first.** Never assume what commands CI runs.
- Do not commit or push from this skill.
- Fix issues found in each step before moving to the next
- Never skip steps or suppress errors
- If the CI workflow has multiple jobs, run all of them (respecting dependency order)
- Skip steps that are CI-infrastructure-only (checkout, setup-node/python/rust actions, cache steps, artifact uploads) — focus on the actual build/test/lint commands

## Success criteria

- Every command that CI runs has been executed locally and passed
- All fixes are applied to the working tree
- The CI passes successfully (if you are correcting and existing failure)
98 changes: 98 additions & 0 deletions .agents/skills/code-dedup/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
---
name: code-dedup
description: Searches for duplicate code, duplicate tests, and dead code, then safely merges or removes them. Use when the user says "deduplicate", "find duplicates", "remove dead code", "DRY up", or "code dedup". Requires test coverage — refuses to touch untested code.
---
<!-- agent-pmo:372ce7f -->

## RestClient.Net context

This is a C# and F# library repository. Use the existing MSTest/F# suites and .NET analyzers for verification. The light integration does not install Deslop or introduce a new coverage policy; check whether the scanner and required coverage evidence are available before applying this skill. Resolve `make test`/`make lint` to the existing commands in root `AGENTS.md`.

# Code Dedup

Find duplicate code, duplicate tests, and dead code across the repo. Merge duplicates and delete dead code — but only when test coverage proves the change is safe.

## Prerequisites — hard gate

Stop and report if any of these fail:

1. **Tests green.** Run `make test` — it is fail-fast AND enforces the coverage threshold from `coverage-thresholds.json` (REPO-STANDARDS-SPEC [TEST-RULES]). Non-zero exit = stop. Never dedup a broken or under-covered codebase. Note the current coverage % — it is the floor and must not drop.
2. **Static typing.** Rust/Go/C#/F#/Dart/Java/Kotlin are typed by default. TypeScript needs `"strict": true`. Python needs Basilisk configured (REPO-STANDARDS-SPEC [LINT-PYTHON-BASILISK]). **Untyped JS or untyped Python: refuse** — print "No static type checking. Dedup without types is too risky. Add type checking first."
3. **deslop reachable** (see below), or the CLI fallback declared.

## Required tooling — deslop

This skill is driven by **deslop** (docs: https://deslop.live/docs/for-ai/). It is the duplicate scanner — do not substitute grep or eyeballing. **Supported languages: `csharp`, `rust`, `python`, `dart`.**

**The MCP server is PREFERRED.** Use it when available. Key tools:
- `mcp__deslop__top-offenders` — worst clusters first (primary input to Step 3).
- `mcp__deslop__report-query` — AND-filter by `bucket`, `path_contains`, `language`, `min_score`, `min_size`; paginate with `offset`/`limit`.
- `mcp__deslop__cluster-by-id` — full record for one cluster before merging.
- `mcp__deslop__report-for-file` / `report-for-range` — narrow to a file/range during merge planning.
- `mcp__deslop__find-similar` — call BEFORE writing any replacement. Reuse if `signals.fused ≥ 0.85` or bucket `identical`/`nearly_identical`; write new if `fused < 0.6` or empty; bias to reuse in between.
- `mcp__deslop__rescan` — refresh the index; call after each merge/deletion to confirm the cluster is gone.

**If the MCP server is unavailable, run the CLI instead** (same `.deslop.toml`, same report):
- `deslop .` — full workspace scan; reads `.deslop.toml`, writes `deslop-report.json`, exits 3 when duplication exceeds the stored threshold. **This is exactly the CI gate** — the threshold lives in `.deslop.toml`, never a CLI/YAML number ([CI-DESLOP]).
- `deslop . --no-fail-over` — same scan, but never fails on breach; local inspection only.

Parse **only `deslop-report.json`** (the `.txt`/`.html` outputs are for humans). Decision fields: `metrics.duplication_percent`, `metrics.threshold.breached`, `clusters[].weight` (sorted desc), `clusters[].signals.fused`, `clusters[].bucket`. Re-run `deslop .` after each change in place of `rescan`.

**Buckets** (act in this order): `identical` > `nearly_identical` > `loosely_similar` > `same_behavior`. `identical` is pure copy-paste and safest to merge. `same_behavior` needs human judgement — only on explicit request.

**Unsupported language** (not csharp/rust/python/dart): say so up front, label every finding `(no-deslop fallback)`, and use the language analyzer + symbol-level grep. Never pretend a structural scan ran.

**Rule:** every cluster you act on must be cited in the final report by its cluster ID, bucket, and score/`fused`. No anonymous "found some duplicates".

## Steps

```
Dedup Progress:
- [ ] Step 1: Prerequisites passed (tests green, coverage noted, typed, deslop MCP or CLI confirmed)
- [ ] Step 2: Dead code scan complete
- [ ] Step 3: Duplicate code scan complete via deslop
- [ ] Step 4: Duplicate test scan complete via deslop (filtered to test paths)
- [ ] Step 5: Changes applied — each merge preceded by find-similar, followed by rescan/re-run
- [ ] Step 6: Verification passed (tests green, coverage stable, deslop confirms targeted clusters gone)
```

### Step 1 — Inventory coverage
Confirm the green baseline from the prerequisites. Only files WITH coverage are candidates — leave untested files alone.

### Step 2 — Scan for dead code
Find code never called, imported, or referenced. Use the language's own signal first: Rust/Go compiler warnings, `make lint` analyzer output (C#/F#/Dart), TS `noUnusedLocals`, zero-import functions in Python. For each candidate, grep the whole codebase (tests, scripts, configs) — only dead if truly zero references. List with file:line. Do NOT delete yet.

### Step 3 — Scan for duplicate code (deslop)
1. MCP: `top-offenders`, then `report-query { bucket: "identical" }`, then `nearly_identical`, then `loosely_similar`. CLI: run `deslop .` and read clusters from `deslop-report.json`, worst `weight` first.
2. For each cluster you intend to act on, fetch the full record (`cluster-by-id` / the report entry) and read every occurrence at its byte ranges. deslop measures structure, not semantics — if occurrences differ on a subtle condition or default, leave them and note "false positive".
3. Record `{ cluster_id, bucket, score, occurrences[], decision, rationale }`. Do NOT merge yet.

### Step 4 — Scan for duplicate tests (deslop)
Same as Step 3, filtered to test paths: `report-query { path_contains: "test" }` (repeat for `spec`/`Tests`/`_test`), or filter `deslop-report.json` clusters by occurrence path. Keep the more thorough test (the integration/whole-app test wins if CLAUDE.md says so). Flag shared test fixtures/helpers as merge candidates rather than deletions.

### Step 5 — Apply changes (one at a time)
Cycle per change: **change → `make test` → check coverage → continue or revert.**

**5a. Dead code:** delete, then `make test`. Non-zero exit = revert.

**5b. Merge duplicate code:** pick ONE cluster (worst `identical` first). Call `find-similar` before writing the replacement — reuse an existing canonical if it returns one. Extract shared logic, update call sites, `make test`. Tests fail = revert (subtle semantic difference). Coverage drops = add tests first. Then `rescan` (or re-run `deslop .`) to confirm the cluster is gone and no new one appeared.

**5c. Duplicate tests:** delete the redundant test (keep the thorough one), `make test`. Coverage drop = revert (it covered something the other didn't). Confirm the cluster is gone.

### Step 6 — Final verification
1. `make lint` — linters + format check pass.
2. `make test` — green AND coverage ≥ the Step 1 floor.
3. Final `rescan` / `deslop .` — every cluster you acted on resolved, top-offender list shorter than at Step 3 start.
4. Report: every cluster ID acted on (bucket, score, occurrences merged/deleted), the new top-offenders list, and final coverage vs baseline.

## Rules

- **deslop is the scanner when supported** (csharp/rust/python/dart). MCP preferred, CLI acceptable. Cite every cluster by ID, bucket, and score. Unreachable MCP → use the CLI; never silently fall back to grep on a supported language.
- **Unsupported language = best-effort scan, declared up front** and labelled `(no-deslop fallback)`.
- **No coverage = do not touch.** You cannot safely dedup what you cannot verify.
- **Coverage must not drop.** The Step 1 floor is sacred — revert anything that lowers it.
- **Untyped JS/Python = refuse.** Types are the safety net.
- **One change at a time.** Never batch dedup changes before testing.
- **When in doubt, leave it.** False dedup is worse than duplication.
- **Preserve public API.** Internal refactoring only — no signature/export changes external code depends on.
- **Trivial duplication is fine.** Only dedup substantial shared logic (>10 lines) or 3+ copies.
Loading
Loading