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
bde4060
Build(deps): bump the github-actions group with 3 updates
dependabot[bot] Oct 29, 2026
c62a9ab
Build(deps): bump the cargo group with 3 updates
dependabot[bot] Oct 29, 2026
d69762c
Merge remote-tracking branch 'origin/dependabot/cargo/cargo-f442d548c…
MelbourneDeveloper Oct 31, 2026
6dbb64e
Merge remote-tracking branch 'origin/dependabot/github_actions/github…
MelbourneDeveloper Oct 31, 2026
185befe
TypeScript 7, oxlint at error, .NET latest-all analyzers, normalized …
MelbourneDeveloper Oct 31, 2026
0e5a445
Publishing pipeline: release, CodeQL and Dependabot auto-merge workfl…
MelbourneDeveloper Oct 31, 2026
2ba13af
Release-only regime: zizmor + npm lockfile vuln gates, npm audit, reg…
MelbourneDeveloper Oct 31, 2026
eb5d0b7
oxlint fixes across TS packages, options-only poll API, punchier skills
MelbourneDeveloper Oct 31, 2026
dedc5db
Crate size survey and hierarchy-based crate consolidation proposal
MelbourneDeveloper Oct 31, 2026
66e84ec
lsp-profiler-ui: clear oxlint down to 7 residuals without changing co…
MelbourneDeveloper Oct 31, 2026
3126e2c
Crate consolidation plan: 12 crates to 5 by dependency layer
MelbourneDeveloper Oct 31, 2026
ad6afba
Consolidate 12 crates into 5 (4 published) by dependency layer
MelbourneDeveloper Oct 31, 2026
04768c4
Plan: tick cargo package and unrepresentable fix; Apple asserts APFS …
MelbourneDeveloper Oct 31, 2026
12faf69
Merge @nimblesite/lspkit-debug into @nimblesite/lsp-profiler-ui as sr…
MelbourneDeveloper Oct 31, 2026
e3297ff
lsp-profiler-ui: clear the last oxlint residuals with async fs; fold …
MelbourneDeveloper Oct 31, 2026
05eb361
Supply chain: 7-day Dependabot cooldown; lift glob/minimatch past GHS…
MelbourneDeveloper Oct 31, 2026
8fb07f5
Plan: tick make ci green on PR #37 Linux CI
MelbourneDeveloper Oct 31, 2026
585bc07
release-setup: steps only, one npm package, yank the six absorbed crates
MelbourneDeveloper Oct 31, 2026
dec7c25
Split registry bootstrap into crates and npm scripts; crates script a…
MelbourneDeveloper Oct 31, 2026
6875655
bootstrap-npm attaches the npm Trusted Publisher; release setup delet…
MelbourneDeveloper Oct 31, 2026
1412293
Release setup: drop completed steps
MelbourneDeveloper Oct 31, 2026
2e58e6e
Bootstrap: generate wire models in the shared export so the npm build…
MelbourneDeveloper Oct 31, 2026
8717ede
bootstrap-npm: a failed trust lookup fails the script instead of read…
MelbourneDeveloper Oct 31, 2026
24bb5c1
Release setup: npm Trusted Publisher and 2FA done
MelbourneDeveloper Oct 31, 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
123 changes: 23 additions & 100 deletions .agents/skills/ci-prep/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,113 +7,36 @@ argument-hint: "[--failing] [optional job name to focus on]"

# CI Prep

Prepare the current state for CI. If CI is already failing, fetch and analyze the logs first.
Run what CI runs, locally, and fix it until green.

## Arguments
## If `--failing`: read the logs first

- `--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).
- Find the PR: `gh pr list --head "$(git branch --show-current)" --state open --json number --limit 1`. None → stop and say so.
- `gh pr checks <n>`, then `gh run view <run-id> --log-failed` for the latest run.
- Read every failed line. Note file, line and error. A job-name argument sets priority, but report everything.

If `--failing` is NOT passed, skip directly to **Step 2**.
## Read the workflow

## Step 1 — Fetch failed CI logs (only when `--failing`)
- Read `.github/workflows/ci.yml` end to end (plus `release.yml` for release work). Extract the commands it actually runs, in order. Never assume.
- Note env vars, matrices and conditionals. Flag any target beyond the standard `make` set.
- In `release.yml`, flag as blockers: checking out `main` instead of the tag SHA, any git commit/push/tag mutation, version-bump commits after tagging, `sed` version stamping.

You MUST do this before any other work.
## Run and fix

```bash
BRANCH=$(git branch --show-current)
PR_JSON=$(gh pr list --head "$BRANCH" --state open --json number,title,url --limit 1)
```
- Run each CI command as CI does, in order. On failure: fix, re-run, then move on.
- Priority: `make fmt` → build → `make lint` → `make test`.
- Skip infra-only steps (checkout, toolchain setup, caching, uploads).

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

Otherwise fetch the logs:
- Edit tests to pass, delete or skip tests, or remove assertions.
- Suppress lints (`#[allow]`, `oxlint-disable`, `#pragma warning disable`).
- Add `unsafe`, `unwrap`, `expect`, `panic!` or `todo!`.
- Lower `coverage-thresholds.json` or weaken any gate.
- Commit or push.

```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
```
## Report

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 at `.github/workflows/ci.yml`. (Also look for `release.yml` if release work is involved.)
2. Read the workflow file completely. Parse every job and every step.
3. Extract the ordered list of commands the CI actually runs. In this repo CI runs (per REPO-STANDARDS-SPEC [MAKE-TARGETS]): `make fmt CHECK=1 → make lint → make test → make build`. Extract what is *actually there* — never assume.
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`.** 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.

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

Work through failures in this priority order:

1. **Formatting** — `make fmt` to clear noise; `make fmt CHECK=1` to verify
2. **Compilation errors** — `cargo build --workspace` must succeed before lint/test
3. **Lint violations** — `make lint` (`cargo clippy ... -D warnings`); fix the underlying code
4. **Runtime / test failures** — `make test` (fail-fast + coverage + threshold); 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 `#[allow(clippy::...)]` or `#[allow(...)]` suppressions** — fix the underlying code per CLAUDE.md
- **NEVER add `unsafe`** to bypass borrow-checker errors
- **NEVER use `unwrap()` / `expect()` / `panic!` / `todo!`** to silence type or error-handling issues
- **NEVER delete or ignore failing tests**
- **NEVER remove assertions**
- **NEVER lower the coverage threshold** in `coverage-thresholds.json` to make `_coverage_check` pass

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, `dtolnay/rust-toolchain`, 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 an existing failure).
- Each step run and its result: pass, fail or fixed.
- Anything unfixed after 5 attempts, with the error and why.
- Whether the branch is ready to push. With `--failing`, list the exact commands that now pass; if the user pushes, watch the new run and loop back on failure.
107 changes: 17 additions & 90 deletions .agents/skills/code-dedup/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,102 +6,29 @@ description: Searches for duplicate code, duplicate tests, and dead code, then s

# Code Dedup

Carefully search for 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.
Merge duplicates and delete dead code, only where tests prove it's safe.

## Prerequisites — hard gate
## Gate

Before touching ANY code, verify these conditions. If any fail, stop and report why.
- `make test` must be green (it's fail-fast and enforces `coverage-thresholds.json`). Red → stop.
- Record the coverage figure. That's the floor.
- Confirm workspace lints still deny `unsafe_code`, `missing_docs`, `unwrap_used`, `expect_used`, `panic`, `todo`.
- Untested files are off limits.

1. Run `make test` — all tests must pass. If tests fail, stop. Do not dedup a broken codebase.
2. `make test` is fail-fast AND enforces the coverage threshold from `coverage-thresholds.json`. If it exits non-zero, stop and fix it before deduping.
3. Rust is typed by default — proceed. (Workspace lints in `Cargo.toml` deny `unsafe_code`, `missing_docs`, and the clippy `unwrap_used` / `expect_used` / `panic` / `todo` / `unimplemented` / `unreachable` family — these guard rails are part of why dedup is safe here. Verify they are still active before starting.)
## Scan (list findings, change nothing yet)

## Steps
- **Duplicates:** Deslop `top-offenders`, then `find-similar` per hit (fused ≥ 0.85 is a candidate). Check across crates and packages; shared engine logic belongs behind `EngineApi` in `lspkit`.
- **Dead code:** `make lint` surfaces private dead code. For `pub` items, search every call site (tests, doc-tests, build scripts, configs). Dead only at zero references.
- **Duplicate tests:** the same assertions on the same path, or fixtures copied between crates. Keep the coarser E2E test.

Copy this checklist and track progress:
## Apply, one change at a time

```
Dedup Progress:
- [ ] Step 1: Prerequisites passed (tests green, coverage met, workspace lints active)
- [ ] Step 2: Dead code scan complete
- [ ] Step 3: Duplicate code scan complete
- [ ] Step 4: Duplicate test scan complete
- [ ] Step 5: Changes applied
- [ ] Step 6: Verification passed (tests green, coverage stable)
```

### Step 1 — Inventory test coverage

Before deciding what to touch, understand what is tested.

1. Run `make test` to confirm green baseline. It exits non-zero on any test failure OR coverage shortfall (REPO-STANDARDS-SPEC [TEST-RULES], [COVERAGE-THRESHOLDS-JSON]).
2. Note the current line coverage percentage from `_coverage_check` output — this is the floor. It must not drop.
3. Identify which crates / modules have coverage and which do not. Only files WITH coverage are candidates for dedup.

### Step 2 — Scan for dead code

Search for code that is never called, never imported, never referenced.

1. The Rust compiler already warns on dead code under the workspace lints (`dead_code = "deny"`, `unused_imports = "deny"`, `unused_variables = "deny"`). Run `make lint` and read every warning that survived denial — they will be hard errors.
2. For Rust public items (`pub fn`, `pub struct`, re-exports) the compiler will NOT flag them as dead. Run `cargo +nightly udeps` or grep the workspace for each `pub` item with zero call sites (including `tests/`, `examples/`, doc-tests, and downstream consumer references where known).
3. For each candidate: **grep the entire codebase** for references (including tests, doc tests in `///` comments, build scripts, configs). Only mark as dead if truly zero references.
4. List all dead code found with file paths and line numbers. Do NOT delete yet.

### Step 3 — Scan for duplicate code

Search for code blocks that do the same thing in multiple places.

1. Look for functions/methods with identical or near-identical logic.
2. Look for copy-pasted blocks (same structure, maybe different variable names).
3. Look for multiple implementations of the same algorithm or pattern.
4. Check across crate boundaries — duplicates often hide between `lspkit-server`, `lspkit-mcp`, `lspkit-live`, `lspkit-vfs`, etc. The `EngineApi` trait surface in `lspkit` is the canonical place for shared engine logic.
5. For each duplicate pair: note both locations, what they do, and how they differ (if at all).
6. List all duplicates found. Do NOT merge yet.

### Step 4 — Scan for duplicate tests

Search for tests that verify the same behavior.

1. Look for `#[test]` functions with identical assertions against the same code paths.
2. Look for test fixtures/helpers duplicated across `tests/` directories of different crates.
3. Look for integration tests that fully cover what a unit test (`mod tests { ... }`) also covers — keep the integration test per CLAUDE.md ("Coarse E2E only").
4. List all duplicate tests found. Do NOT delete yet.

### Step 5 — Apply changes (one at a time)

For each change, follow this cycle: **change → test → verify coverage → continue or revert**.

#### 5a. Remove dead code
- Delete dead code identified in Step 2.
- After each deletion: run `make test` (fail-fast + coverage + threshold all in one).
- If `make test` exits non-zero (test failure OR coverage drop): **revert immediately** and investigate.
- Dead code removal should never break tests or drop coverage.

#### 5b. Merge duplicate code
- For each duplicate pair: extract the shared logic into a single function/module — usually the `lspkit` façade crate, but lower-level helpers belong with the crate that owns the domain (`lspkit-vfs` for buffer ops, etc.).
- Update all call sites to use the shared version.
- After each merge: run `make test`.
- If tests fail: **revert immediately**. The duplicates may have subtle differences you missed.
- If coverage drops: the shared code must have equivalent test coverage. Add tests if needed before proceeding.

#### 5c. Remove duplicate tests
- Delete the redundant test (keep the more thorough one).
- After each deletion: run `make test`.
- If coverage drops below threshold, `make test` exits non-zero — **revert immediately**. The "duplicate" test was covering something the other wasn't.

### Step 6 — Final verification

1. Run `make lint` — clippy with `-D warnings` and the format check must pass.
2. Run `make test` — tests must pass AND coverage must remain ≥ the baseline from Step 1.
3. Report: what was removed, what was merged, final coverage vs baseline.

(Only the 7 standard targets exist — `make lint` and `make test` cover formatting and coverage checks respectively.)
- Change → `make test` → coverage ≥ floor? Keep it. Otherwise revert immediately.
- Merged code goes to the crate that owns the domain. Update every call site.
- When deleting a duplicate test, keep the more thorough one.

## Rules

- **No test coverage = do not touch.** If a file has no tests covering it, leave it alone entirely. You cannot safely dedup what you cannot verify.
- **Coverage must not drop.** If removing or merging code causes coverage to decrease, revert and investigate. The coverage floor from Step 1 is sacred.
- **One change at a time.** Make one dedup change, run tests, verify coverage. Never batch multiple dedup changes before testing.
- **When in doubt, leave it.** If two code blocks look similar but you're not 100% sure they're functionally identical, leave both. False dedup is worse than duplication.
- **Preserve public API surface.** Do not change `pub` function signatures, struct names, trait method names, or re-exports that downstream consumers (lql-lsp-rust, Basilisk, Deslop, SharpLsp) depend on. Internal refactoring only.
- **Three similar lines is fine.** Do not create abstractions for trivial duplication. The cure must not be worse than the disease. Only dedup when the shared logic is substantial (>10 lines) or when there are 3+ copies.
- Not sure two blocks behave identically? Leave both. A false merge is worse than duplication.
- Don't change public API (`pub` signatures, names, re-exports). SharpLsp, Deslop, Basilisk and lql-lsp-rust depend on it.
- Finish with `make lint` and `make test`. Report what was removed and merged, and coverage against the floor.
66 changes: 12 additions & 54 deletions .agents/skills/fix-bug/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,62 +6,20 @@ allowed-tools: Read, Grep, Glob, Edit, Write, Bash
---
<!-- agent-pmo:74cf183 -->

# Bug Fix Skill — Test-First Workflow
# Fix Bug: test first

You MUST follow this exact workflow. Do NOT skip steps. Do NOT fix the bug before writing a failing test.
No fix until a test fails because of the bug.

## Step 1: Understand the Bug

- Read the bug description: $ARGUMENTS
- Investigate the codebase to understand the relevant code
- Identify the root cause (or narrow down candidates)
- Summarize your understanding of the bug to the user before proceeding

## Step 2: Write a Failing Test

- Write a test that **directly exercises the buggy behavior**
- The test must assert the **correct/expected** behavior — so it FAILS against the current broken code
- The test name should clearly describe the bug (e.g., `test_orange_color_not_applied_to_head`)
- Use the project's existing test framework and conventions

## Step 3: Run the Test — Confirm It FAILS

- Run ONLY the new test (not the full suite)
- **Verify the test FAILS** and that it fails **because of the bug**, not for some other reason (typo, import error, wrong selector, etc.)
- If the test passes: your test does not capture the bug. Go back to Step 2
- If the test fails for the wrong reason: fix the test, not the code. Go back to Step 2
- **Repeat until the test fails specifically because of the bug**

## Step 4: Show Failure to User

- Show the user the test code and the failure output
- Explicitly ask: "This test fails because of the bug. Can you confirm this captures the issue before I fix it?"
- **STOP and WAIT for user acknowledgment before proceeding**
- Do NOT continue to Step 5 until the user confirms

## Step 5: Fix the Bug

- Make the **minimum change** needed to fix the bug
- Do not refactor, clean up, or "improve" surrounding code
- Do not change the test

## Step 6: Run the Test — Confirm It PASSES

- Run the new test again
- **Verify it PASSES**
- If it fails: go back to Step 5 and adjust the fix
- **Repeat until the test passes**

## Step 7: Run the Full Test Suite

- Run ALL tests to make sure nothing else broke
- If other tests fail: fix the regression without breaking the new test
- Report the final result to the user
- **Understand:** read the report ($ARGUMENTS) and the code, find the root cause, and state it in one line.
- **Write a failing test:** an E2E test that asserts the correct behavior, named after the bug, in the project's existing framework.
- **Prove it fails:** run only that test. It must fail *because of the bug*, not because of a typo or a bad import. If it passes or fails for the wrong reason, rewrite the test.
- **Show it:** report the test and the failure output, then keep going. Don't wait for confirmation.
- **Fix minimally:** the smallest change that fixes the bug. No refactors. Don't touch the test.
- **Prove it passes:** re-run the test, adjusting the fix until it's green.
- **Run everything:** `make test`. Fix regressions without weakening the new test.

## Rules

- NEVER fix the bug before the failing test is written and confirmed
- NEVER skip asking the user to acknowledge the test failure
- NEVER modify the test to make it pass — modify the source code
- If you cannot write a test for the bug, explain why and ask the user how to proceed
- Keep the fix minimal — one bug, one fix, one test
- Never edit the test to make it pass.
- One bug, one test, one fix.
- Can't write a test for it? Report why. Don't ship an untested fix.
Loading
Loading