From 8e90f6f1b60a07f42114ccd03cd397ddb784507d Mon Sep 17 00:00:00 2001 From: Bryan Finster Date: Fri, 4 Sep 2026 09:50:25 -0500 Subject: [PATCH 1/3] docs: make CLAUDE.md more concise --- .claude/CLAUDE.md | 36 ++---- CLAUDE.md | 176 +++++++++++--------------- plugins/dev-team/CLAUDE.md | 12 +- plugins/marketplace-dev/CLAUDE.md | 19 +-- plugins/security-assessment/CLAUDE.md | 48 +++---- 5 files changed, 108 insertions(+), 183 deletions(-) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index ca0237e6e..a6921e57c 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -4,34 +4,14 @@ When the user types `/graphify`, use the installed graphify skill or instruction # Index trust protocol -Guidance for using the Repowise/graphify indexes below. **This section is -repo-owned and lives ABOVE the `REPOWISE:START` marker on purpose.** An -earlier version of it sat inside the auto-generated block, and `repowise init` -silently dropped it when Repowise 0.45.0 regenerated that block with a leaner -template — 52 lines deleted, no warning, no diff anyone was watching. Anything -inside those markers belongs to the generator and can vanish on any re-index; -guidance we depend on has to live out here. Do not move it back down. - -- **`verified: true` means the bytes were checked against the live tree.** - Never follow it with a Read of the same lines. -- **`symbol_bodies`, `quotes`, and `code_rationale` entries are live source.** - Use them instead of opening the file. -- **The only re-read triggers** are `bounds: "approximate"`, - `_meta.stale_warning`, `search_method: "bm25"`, and `confidence: "low"`. - `index_behind: true` alone is informational — the served content is - unaffected by the drift. -- **Not valid reasons to re-read:** "just to be safe"; "to see full context" - (use the skeleton or a range read); "the file might have changed" - (`verified` already checked). These are the failure mode this section - exists to name — each one converts a served, verified answer back into a - full-file Read and spends the context the index was there to save. -- **Pre-edit, not instead-of-edit.** These tools decide *which* files to read - and edit. Claude Code requires a raw Read of any file you will Edit, and - that Read is correct and expected. -- **For exhaustive literal sweeps** (rename every call site) plain `Grep` is - unbeatable — use it. Reach for `get_context(include=["callers"])` when you - want the `callers_total` / `callers_truncated` honesty signal instead of a - maybe-incomplete grep. +Guidance for the Repowise/graphify indexes below. **Repo-owned, lives ABOVE the `REPOWISE:START` marker on purpose** — content inside those markers belongs to the generator and can vanish on any re-index. Do not move it back down. + +- **`verified: true`** means the bytes were checked against the live tree — never re-Read those lines. +- **`symbol_bodies`, `quotes`, `code_rationale`** are live source — use them instead of opening the file. +- **Re-read only on:** `bounds: "approximate"`, `_meta.stale_warning`, `search_method: "bm25"`, or `confidence: "low"`. `index_behind: true` alone is informational. +- **Not valid reasons to re-read:** "just to be safe", "to see full context" (use the skeleton or a range read), "the file might have changed" (`verified` already checked). +- **Pre-edit, not instead-of-edit.** These tools decide *which* files to read/edit; a raw Read before any Edit is still required. +- **For exhaustive literal sweeps** (rename every call site), plain `Grep` is unbeatable. Use `get_context(include=["callers"])` when you want the `callers_total`/`callers_truncated` honesty signal instead of a maybe-incomplete grep. ## Codebase Intelligence for agentic-dev-team (Repowise) diff --git a/CLAUDE.md b/CLAUDE.md index 4f9135a6b..4240e4d4c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,22 +2,37 @@ This is the marketplace repository for the dev-team Claude Code plugin. +## General +Unless asked to behave otherwise, always give concise responses and scrifice grammar for the sake of concision. Ask clarifying questions when needed and offer your best guess at available interpretations/answers for those questions when possible. + +### Be RUTHLESSLY concise — this is the rule I break most often +Default to a few sentences. If the answer is "yes", say "yes" and stop. + +- **Answer the question asked. Nothing else.** No adjacent findings, no "while I was looking I noticed", no caveats I didn't ask for. Sit on it until I ask. +- **One thing at a time.** Never hand me a numbered list of 3+ considerations, options, or trade-offs unless I asked for options. Pick one, recommend it, move on. +- **No teaching.** Skip the mechanism, the background, the "why this matters". State the conclusion. I'll ask why if I care. +- **No tables, no headers, no bold-label paragraphs** for a simple answer. Prose or a couple of lines. +- **Cut every parenthetical, every "worth noting", every "the real finding is".** +- Corrections: one sentence, no post-mortem. + +Length is the tell: if a reply is over ~10 lines and I didn't ask for depth, it's wrong. Detail I have to skim to find the answer is worse than no answer. + ## Working Rules -- **Always work on a branch.** Never commit directly to `main`. Every change — including documentation-only changes, gitignore tweaks, and one-line fixes — lands via a feature branch and a pull request. If a commit accidentally lands on `main` locally, reset `main` to `origin/main` and move the commit to a branch before pushing. Release commits authored by release-please are the only exception; they arrive as their own PR. -- **Always pull `origin main` before starting work.** Run `git fetch origin main` at the start of every session and before branching, then cut new branches from `origin/main` directly (e.g. `git switch -c origin/main`) — never from a local `main` you haven't fast-forwarded. If your feature branch already exists and `origin/main` has moved, merge or rebase the fresh `origin/main` into it before continuing — don't let a branch drift behind `main` across a long-running session. -- **Squash-merge strategy.** `main` is protected by a ruleset that forbids force-pushes. Use squash-merge for all PRs to keep `main` history clean: `gh pr merge --squash`. Signed commits are not required. -- **Documentation-only PRs auto-merge.** When the diff touches only `*.md` files (plus `.gitignore`, `LICENSE`, or other non-shipping metadata) and changes no code, agent, skill, or hook, arm auto-merge at PR-open time: `gh pr merge --auto --squash`. Required checks still run; the PR lands the moment they pass. Any PR that touches code, agents, skills, hooks, eval fixtures, or marketplace manifests requires explicit human merge. -- **Deterministic tools over inference — never dispatch a skill or agent for work a tool can decide.** If a question has a mechanical answer, the mechanism must produce it: a compiler, a test suite, a type checker, a linter, a parser, a schema validator, `git` itself. Agents and skills are for judgement — design trade-offs, review of intent, prose — not for facts a program can compute. This is a correctness rule, not a cost rule: a model's answer to a mechanical question is a *guess that looks like a result*, and it fails silently, in the confident direction. Prefer, in order: (1) run the real thing and read its output; (2) a deterministic script over its artifacts; (3) a model, only for what is left. Two rules follow from it, both learned the expensive way: - - **Verify a runtime property by exercising it at runtime.** Static approximations of a runtime question rot into false assurance. The Python floor gate began as a hand-maintained denylist of post-3.8 APIs (the floor was 3.8 at the time); it reported the shipped tree clean while `hooks/lib/cost_meter.py` used PEP 584's `dict | dict`, which 3.8 rejects. A one-time manual run of the full suite on a real 3.8 interpreter — not something the gate itself did — found it in nine failing tests. The gate that replaced the denylist was, at first, still only a byte-compile + import pass (`.github/workflows/plugin-tests.yml` → "Python 3.10 floor", `scripts/import_probe_shipped.py`; see [`tests/repo/test_python_floor.py`](tests/repo/test_python_floor.py)) — real progress over a hand-maintained list, but still one layer short of "exercising it at runtime": compiling and importing a module proves it *parses* and *loads*, not that every function *body* runs clean, so a runtime-only API used only inside a function (`asyncio.to_thread` in `orchestrator.py`, issue #1650) stayed invisible to it regardless of which version the floor was pinned to. `chk_python_floor` now closes that gap too, actually running a curated test slice over the shipped tree under the resolved 3.10 interpreter via `uv run --python`, not just compiling and importing it. That slice is declared once, as `FLOOR_TEST_SLICE` in [`tests/repo/test_python_floor.py`](tests/repo/test_python_floor.py), and held equal to `chk_python_floor`'s actual pytest arguments in both directions — deliberately not re-enumerated here, because a copy of the list in prose is exactly what went stale when the coverage-discovery modules joined the slice (#1826) and nothing held this file to it. The floor itself later moved to 3.10 once the original OS-availability rationale expired ([ADR 0031](docs/adr/0031-raise-shipped-python-floor-to-3-10.md)) — the gate's mechanism (the interpreter, not a list) is what survived that move unchanged. - - **A gate that cannot fail is worse than no gate.** It reads as a guarantee and delivers none. `engines.node` sat at `>=24` while this project's own containers ran Node 22, so `npm ci` failed, `node_modules` never installed, husky's hooks went inert, and `scripts/ci-local.sh` skipped eslint *while still printing "All local CI checks passed."* When you add a gate, make it fail on purpose once before you trust it. - - **A gate bounds only the case it can observe — say what the other end is.** The floor gate above asks "does this still run on the OLDEST supported interpreter", which is a real question and answers only itself. For a long time nothing asked about the newest: `content-guard-tests` runs on the runner image's *implicit* system `python3` (~3.12 on ubuntu-24.04, with no `python-version` pin anywhere in `plugin-tests.yml`), so the suite's green read as "works on Python" when it meant "works on 3.10 and whatever the runner happens to ship." `main` was consequently red on 3.13+ with every check green: `coverage_discovery_js.py` detected a malformed `**` glob by catching `ValueError` from `Path.glob`, and CPython 3.13's pathlib rewrite stopped raising it, so the guard silently returned an empty result instead of a `discovery_error` (#1832, fixed in #1833). `chk_python_ceiling` / the `Python ceiling` job now names the other end (`PYTHON_CEILING` in `scripts/ci-local.sh` — one place, so a runner-image bump cannot move it silently), and runs the **full** pytest directory list rather than a curated slice like the floor job's. That choice is the point, not an optimization: when the regression landed, the offending test file was *not* in the floor slice, and it took a follow-up commit (#1836) to add the coverage-discovery modules to it — a curated list only covers what someone remembered to enumerate, and it lagged the very bug that motivated it. A ceiling gate on a slice would inherit that lag. Read its status honestly, though: it is currently listed in `exempt` in [`.github/required-status-checks.json`](.github/required-status-checks.json), so it reports on every PR but does **not** block a merge — advisory by choice, not because it is path-filtered or opt-in like the other exemptions. Treat a red ceiling run as blocking by convention, and see #1837 for the ruleset edit that would make that automatic. Two transferable pieces: when a library's *error* behavior is your guard, validate the property explicitly in your own code instead — an exception is a contract that can be withdrawn; and do not add a pinned interpreter to `content-guard-tests` via `actions/setup-python`, which is the known-wrong fix (a prior attempt put it ahead of the system `python3` for every other step in that job, breaking `chk_md_references` and silently degrading `chk_hook_units`'s pytest guard to "skipped" — use `uv`, which never touches `PATH`). - - **The observed end is a PLATFORM too, not only a version.** The two gates above bound the interpreter; nothing bounded the operating system, and every gate in this repo runs on `ubuntu-*` while every maintainer develops on macOS. `.husky/pre-push` created all five of its temp files with `mktemp -t PREFIX`, which GNU coreutils treats as a template honoring `$TMPDIR` and BSD/macOS treats as a literal prefix, ignoring `$TMPDIR` entirely (it resolves the per-user temp dir via `confstr(_CS_DARWIN_USER_TEMP_DIR)`). So the worktree-path snapshot landed where `tests/repo/test_pre_push_ref_guard.py` could not find it, two tests failed on every Mac, and — because `pre-push` runs the whole of `ci-local.sh` — **every local push from a Mac was blocked**, which is precisely the pressure that turns `--no-verify` into a habit and disables the local CI mirror wholesale. CI was green throughout (#1993). Portable form: `mktemp "${TMPDIR:-/tmp}/prefix-XXXXXX"`, with the `X`s **trailing** — BSD substitutes only a trailing run, so `foo-XXXXXX.log` yields that name verbatim and the *next* call dies with `EEXIST`; the #1993 fix fell into that second trap while removing the first, and both are now pinned by [`tests/repo/test_mktemp_portability.py`](tests/repo/test_mktemp_portability.py). Until a macOS CI leg exists (#1993), that grep is the only mechanism watching this end — so when a gate is green everywhere and broken in front of you, suspect the axis nothing runs on. - - **Review your own fix before calling it done — a green suite on code you just wrote is weak evidence.** Tests written alongside a fix encode the same mental model as the fix, so they inherit its blind spots. The #1833 brace-glob fix passed all 71 tests, 15 of them written specifically for it; `correctness-review` and `test-review`, dispatched independently at the diff, both caught that brace balance was tracked only from the first `{` onward — so `apps/}x{a,b}` expanded to globs matching nothing, reintroducing the exact silent-zero failure the fix existed to remove. The parametrized case that *looked* like it covered this passed only because of an unrelated unclosed trailing brace. The same pass found two more real defects (an empty alternative failing the whole workspace, and per-alternative `**` checking letting `{**/x,**/y,**/z}` slip past the cost guard). This is judgement, not mechanism, so no gate enforces it: dispatch the review agents at your own diff from the top-level session, and verify each finding by reproducing it before fixing. -- **A mechanical finding reported twice becomes a check.** When a review agent reports the same mechanically-checkable finding class for the **second** time — and the check is expressible as a deterministic script — convert it into a `CHECKS` entry in [`plugins/dev-team/skills/code-review/scripts/repo_invariants.py`](plugins/dev-team/skills/code-review/scripts/repo_invariants.py) **in the same PR that fixes the finding**. This is the ratchet that keeps the rule above from depending on memory. The mechanism has existed since #1608 precisely so mechanically-checkable repo facts stop being re-derived once per agent per round — #1629 found at least 4 of 8 follow-up review rounds were triggered by defect classes these checks catch — but until now growth of `CHECKS` depended on someone remembering to grow it. The trigger is deliberately the *second* report, not the first: one occurrence may be a one-off, two is a class, and converting at two makes the cost a single bounded conversion instead of an unbounded stream of re-derivations. Worked example: the "every module under a skill's `scripts/` dir is named in that skill's docs" invariant shipped covering `mutation-testing` alone (#1600, where four separate agents rediscovered it); when the same class turned up in `skills/code-review/scripts/` (#1981), the hardcoded single-skill check became a registry covering both rather than a copied second function. -- **Prefer Python over bash, repo-wide, unless bash is strictly required.** This applies everywhere in the repo, not just shipped plugin code — new tests under `tests/`, new `scripts/*`, new CI helpers. Write `.py` (stdlib-only for anything under `plugins/dev-team/`) by default. Bash is acceptable only when the thing under test genuinely is a shell script, or for the unavoidable pre-Python bootstrap shim (`install.sh`'s two-line trampoline). New `.bats` files are a review finding, not a style choice — see [ADR 0014](docs/adr/0014-python-for-cross-os-scripts.md) and [ADR 0015](docs/adr/0015-bash-removal-complete.md). If you find yourself adding a `.bats` file, port the assertions to `test_*.py` instead — see `### Script authoring — Python only` below for the mechanical pattern. -- **Specs and plans are GitHub issues here, not files.** When developing this repo (GitHub-connected — the normal case), a spec becomes an **epic issue** and each plan slice a **sub-issue** of that epic — create them by default, don't leave local drafts. Fall back to untracked files only when there is no GitHub connection: the spec at `docs/specs//spec.md` and its plans under a `docs/specs//plans/` subdirectory (never a root-level `plans/`). This governs development of *this* plugin only — it is not shipped skill behavior imposed on people who use the plugin on their own projects. -- **PRs close the issues they address.** Every PR body carries a closing keyword — `Closes #N` for each sub-issue the PR resolves, and `Part of #` (non-closing) for the epic — so merging the PR closes its slices. GitHub does **not** auto-close a parent/epic issue as a side effect of every sub-issue closing (it only tracks completion percentage); the `epic-auto-close` workflow (`.github/workflows/epic-auto-close.yml`, #987) is what closes the epic once its last sub-issue closes. +- **Always work on a branch.** Never commit directly to `main`. Every change lands via a feature branch and PR. Release-please's own commits are the only exception. If a commit lands on `main` locally by accident, reset `main` to `origin/main` and move the commit to a branch before pushing. +- **Pull `origin main` before starting work.** `git fetch origin main` at session start and before branching; branch from `origin/main` directly (`git switch -c origin/main`). If your branch already exists and `origin/main` moved, merge/rebase it in before continuing. +- **Squash-merge all PRs**: `gh pr merge --squash`. `main` forbids force-pushes. +- **Docs-only PRs auto-merge.** If the diff touches only `*.md`/`.gitignore`/`LICENSE` and no code/agent/skill/hook, arm auto-merge at open: `gh pr merge --auto --squash`. Anything else needs explicit human merge. +- **Deterministic tools over inference.** Never dispatch a skill or agent for work a tool can decide — a compiler, test suite, linter, parser, schema validator, or `git` answers a mechanical question directly; a model's answer to one is a guess that fails silently. Prefer, in order: (1) run the real thing, (2) a deterministic script over its output, (3) a model, only for what's left. + - Verify runtime properties by exercising them at runtime — byte-compile/import checks prove a module parses, not that it runs. `chk_python_floor` runs a real test slice (`FLOOR_TEST_SLICE` in [`tests/repo/test_python_floor.py`](tests/repo/test_python_floor.py)); don't duplicate that list elsewhere. + - A gate that cannot fail is worse than no gate — make a new gate fail on purpose once before trusting it. + - Name what a gate does *not* cover. `chk_python_floor` bounds the oldest supported interpreter; `chk_python_ceiling` (`PYTHON_CEILING` in `scripts/ci-local.sh`) bounds the newest and runs the full pytest directory list, not a curated slice. It's `exempt` in [`.github/required-status-checks.json`](.github/required-status-checks.json) (advisory) — treat a red run as blocking anyway. + - Gates are platform-bound too. Every gate here runs on `ubuntu-*`; every maintainer develops on macOS — watch for GNU/BSD divergence (e.g. `mktemp -t` behaves differently). Portable form: `mktemp "${TMPDIR:-/tmp}/prefix-XXXXXX"` with the `X`s trailing. + - Review your own fix before calling it done. Dispatch review agents (`correctness-review`, `test-review`) at your own diff from the top-level session and verify each finding by reproducing it. +- **A mechanical finding reported twice becomes a check.** On the second report of the same mechanically-checkable finding, add a `CHECKS` entry to [`repo_invariants.py`](plugins/dev-team/skills/code-review/scripts/repo_invariants.py) in the same PR that fixes it. +- **Prefer Python over bash, repo-wide.** Stdlib-only `.py` under `plugins/dev-team/`. Bash only for a genuine shell-script target or the unavoidable bootstrap shim. New `.bats` files are a review finding — port to `test_*.py` (see [ADR 0014](docs/adr/0014-python-for-cross-os-scripts.md), [ADR 0015](docs/adr/0015-bash-removal-complete.md)). +- **Specs and plans are GitHub issues, not files.** A spec becomes an epic issue, each plan slice a sub-issue — create them by default. Fall back to `docs/specs//{spec.md,plans/}` only with no GitHub connection. +- **PRs close the issues they address.** `Closes #N` per sub-issue, `Part of #` for the epic. The `epic-auto-close` workflow closes the epic once its last sub-issue closes — GitHub itself won't. ## Repository Structure @@ -38,13 +53,11 @@ plugins/dev-team/ # The plugin source docs/ # Cross-plugin dev documentation (roadmaps, spikes) plans/ # Transient working plans — deleted after implementation evals/ # Agent eval fixtures (not shipped) -reports/ # Legacy review reports (not shipped, pre-.dev-team-reports/) — new reports land in .dev-team-reports/ +reports/ # Legacy review reports (not shipped) — new reports land in .dev-team-reports/ ``` -Two guides explain how the marketplace works: - -- [`docs/marketplace-builder-plugin-playbook.md`](docs/marketplace-builder-plugin-playbook.md) — how to build a plugin that scaffolds/audits/maintains marketplace monorepos (shipping hygiene, portability, testing, release/catalog sync). -- [`docs/using-plugin-skills-in-the-web-environment.md`](docs/using-plugin-skills-in-the-web-environment.md) — how to use a plugin's skills from a Claude Code web session. +- [`docs/marketplace-builder-plugin-playbook.md`](docs/marketplace-builder-plugin-playbook.md) — how to build a plugin for this marketplace pattern. +- [`docs/using-plugin-skills-in-the-web-environment.md`](docs/using-plugin-skills-in-the-web-environment.md) — using a plugin's skills from a Claude Code web session. ## Developing the Plugin @@ -52,33 +65,25 @@ Edit files directly in `plugins/dev-team/`. All plugin components (agents, skill ### Prerequisites -The local gates (`scripts/ci-local.sh`, run by the `pre-push` hook) need these tools on every dev machine: - -- CLI: `jq`, `python3`, `uv` (macOS: `brew install jq python3 uv`; `uv` otherwise via `curl -LsSf https://astral.sh/uv/install.sh | sh`). `shellcheck` still lints repo-root shell (`scripts/audit-rules-vs-prompts.sh`, etc.) and the `plugins/security-assessment/` plugin; the `plugins/dev-team/` plugin itself is now Python. It is deliberately NOT in that install line: it is version-PINNED as `SHELLCHECK_VERSION` in `scripts/ci-local.sh`, which fetches that exact release into `~/.cache/agentic-dev-team/` on first use, because a package manager gives whatever it happens to ship — Homebrew's 0.11.0 and Ubuntu's 0.9.0 disagree on real findings, and CI used to install the latter while developers ran the former. `uv` provisions the Python 3.10 floor interpreter and runs the floor-interpreter test slice (`chk_python_floor` in `scripts/ci-local.sh`) — the default pre-push gate fails outright without it, not just the `Python 3.10 floor` CI job. -- Python modules: install the declared dev dependencies once with `python3 -m pip install -r requirements-dev.txt` (PyYAML for a few content-guard tests that shell out to Python; pytest for every content-guard suite and the plugin's own unit tests; semgrep for the security-assessment suites; httpx for the red-team harness smoke test). On a PEP 668 "externally-managed-environment" interpreter (e.g. Homebrew Python on macOS), a bare `pip install` is rejected outright — `dev-setup.sh` handles this itself, retrying `--user` then `--break-system-packages` and only printing success if one of the three actually succeeds; the failure is never silently swallowed. Prefer a project `.venv/` if you'd rather not use `--break-system-packages` system-wide. -- Graphify (optional, code knowledge graph): `uv tool install graphifyy` (or `pipx install graphifyy`). Its native Claude wiring is committed once — the `## graphify` section at the end of this file, `.claude/skills/graphify/`, and the PreToolUse nudge hooks in `.claude/settings.json`. `dev-setup.sh` installs graphify and runs `graphify hook install` (never `graphify install --project`, which rewrites this curated file); graphify targets `.husky/post-commit` + `.husky/post-checkout` here because git hooks route through husky, and those embed a machine-specific Python path so they're gitignored and regenerated per-clone. Build the graph on demand with `graphify extract .` (writes `graphify-out/graph.json`, gitignored). Codegraph stays a personal, user-level MCP — not committed. When to use which: **codegraph** for fast structural queries while editing (callers/impact); **graphify** for architecture/onboarding across code + docs + infra. +`scripts/ci-local.sh` (run by the `pre-push` hook) needs on every dev machine: -**One-shot setup:** `bash scripts/dev-setup.sh` validates this toolchain and installs anything missing (Homebrew on macOS, apt-get on Debian/Ubuntu, then the `requirements-dev.txt` deps). Safe to re-run. +- `jq`, `python3`, `uv` (`brew install jq python3 uv`, or `uv` via `curl -LsSf https://astral.sh/uv/install.sh | sh`). +- `shellcheck`, version-pinned as `SHELLCHECK_VERSION` in `scripts/ci-local.sh` (fetched to `~/.cache/agentic-dev-team/` on first use — not from a package manager). +- Python deps: `python3 -m pip install -r requirements-dev.txt`. On a PEP 668 "externally-managed" interpreter, use a project `.venv/`, or let `dev-setup.sh` retry `--user`/`--break-system-packages` for you. +- Graphify (optional): `uv tool install graphifyy`, then `dev-setup.sh` runs `graphify hook install` (never `graphify install --project`, which overwrites this file). Build the graph on demand with `graphify extract .`. Use **codegraph** for structural queries while editing; **graphify** for architecture/onboarding across code+docs+infra. -`ci-local.sh` checks these up front and exits with an actionable message (pointing at `dev-setup.sh`) if any are missing. +**One-shot setup:** `bash scripts/dev-setup.sh` (safe to re-run). `ci-local.sh` itself checks these and points at `dev-setup.sh` if anything's missing. -**Profiling the gate:** set `CI_LOCAL_TIMING=1` to append a timing section — each check's individual wall-clock (in declared order, regardless of completion order under the parallel pool) plus the total run wall-clock, followed by an uncolored machine-parseable block (`labelseconds`) for scripting. It is off by default and changes nothing when unset; a `--changed-only`-skipped check reads `skipped`, never `0.00s`. Use it to find the slowest gates before optimizing (issue #1118). +**Profiling the gate:** `CI_LOCAL_TIMING=1` appends per-check and total wall-clock timing. -**The pre-push pytest gate spans more than `plugins/dev-team/tests`.** `ci-local.sh`'s unit-test step runs pytest over `plugins/dev-team/tests tests/repo tests/agents tests/commands tests/docs tests/knowledge tests/stack_aware tests/skills tests/scripts tests/hooks` (with `-n auto --dist loadgroup`; two csharp-stryker files `--ignore`d). Editing agent/skill markdown can break repo-level content-guards that live **outside** `plugins/dev-team/tests` — e.g. `tests/skills/test_code_review_frontend_dispatch.py` asserts specific agent names appear verbatim in `code-review/SKILL.md`, and `tests/repo` runs `check_md_references.py` (a backticked cross-skill path must be file-relative, e.g. `../code-review/SKILL.md`). `tests/hooks/` (repo-root, distinct from `plugins/dev-team/tests/hooks/`) joined this list in #1475 after two of its tests — pinning `hooks.json`'s dispatch-matcher registration — went silently red for a full ADR migration (ADR 0026) because this directory wasn't in the gate; the stryker/pitest/mutmut *adapter* tests that actually shell out to those tools live in `plugins/dev-team/tests/hooks/` (already covered by `plugins/dev-team/tests` above) — this directory only hosts the static fixture files those adapter tests read (`tests/hooks/fixtures/`, `tests/hooks/fake-bin/`), so `tests/hooks/` itself is fast and portable. Before pushing plugin-content changes, run that **full dir list** — not just the plugin subdir — plus `python3 scripts/check_md_references.py` and `python3 plugins/dev-team/hooks/lib/build_knowledge_index.py`, or the `pre-push` hook / CI will catch what a plugin-only run missed. +**The pre-push pytest gate spans more than `plugins/dev-team/tests`.** It runs `plugins/dev-team/tests tests/repo tests/agents tests/commands tests/docs tests/knowledge tests/stack_aware tests/skills tests/scripts tests/hooks`. Editing agent/skill markdown can break repo-level content-guards outside `plugins/dev-team/tests` — always run the full dir list, plus `python3 scripts/check_md_references.py` and `python3 plugins/dev-team/hooks/lib/build_knowledge_index.py`, before pushing plugin-content changes. -### The inner loop — three speeds, not two +### The inner loop -Before #2002/#2005 the loop had two speeds: run one file, or run the whole -9,469-test directory list. "What does this change affect?" was answered by a -guess, and per the deterministic-tools rule that is a mechanical question a -program should compute. +"What does this change affect" is a mechanical question a program should answer, not a guess: -1. **`--lf` / `--ff`** — free, built into pytest, no map and no dependency. - `--lf` re-runs only last run's failures; `--ff` runs them first, then the - rest. This is the right tool for the tight red→green loop and costs nothing - to adopt. -2. **Impact selection** — `scripts/impact_tests.py` answers "given that - something changed, which tests reach it" from a per-test coverage map: +1. **`--lf` / `--ff`** — pytest built-ins, free. `--lf` re-runs last run's failures; `--ff` runs them first. +2. **Impact selection** — `scripts/impact_tests.py` maps changed files to the tests that reach them via `pytest-cov`'s `--cov-context=test`: ```bash python3 scripts/impact_tests.py build --out .cache/impact-map.json -- \ @@ -88,103 +93,66 @@ program should compute. --changed-from-git | xargs python3 -m pytest -q ``` - Built on `pytest-cov`'s `--cov-context=test` — already a dev dependency — - rather than adding `pytest-testmon`. Measured on this checkout: a - `hooks/telemetry.py` edit selects **28 tests in 0.6s** against 9,493 in - ~80s. Building the map costs one full instrumented run (~4 min). - - **It never narrows on a guess.** `select` exits **2** — meaning *run the - full suite* — when the map is missing or malformed, when a changed file is - absent from the map (a new or uncovered file has unknown reach), or when a - changed file is itself a test. Treat any non-zero exit as the full suite, - never as an empty selection. The map is a snapshot: rebuild it after adding - tests or source files. -3. **The full directory list** — still what `pre-push` and CI run, and still - the answer whenever selection refuses. - -`scripts/ci_tree_cache.py` (#2002) sits underneath all three and answers a -different question — "has anything changed at all" — skipping `chk_hook_units` -outright when the working tree is byte-identical to the one it last passed on. -`CI_LOCAL_NO_TREE_CACHE=1` forces a run. + `select` exits **2** (run the full suite) whenever it can't be sure — missing/malformed map, an unmapped changed file, or a changed test file. Rebuild the map after adding tests or source files. +3. **The full directory list** — what `pre-push` and CI run, and the fallback whenever selection refuses. -### Worktrees — run `npm ci` first +`scripts/ci_tree_cache.py` skips `chk_hook_units` outright when the working tree is byte-identical to one that already passed; `CI_LOCAL_NO_TREE_CACHE=1` forces a run. -Run `npm ci` as the first step in any new worktree, before committing. An unprovisioned worktree has no `.husky/_`/`node_modules`, so git hooks silently don't run; `scripts/ci-local.sh` and CI backstop what the hooks would have caught. +### Worktrees — run `npm ci` first -**Self-healing SessionStart hooks (issue #1469).** `.claude/settings.json` registers two additional, time-boxed, fail-open `SessionStart` hooks alongside `install-dev-team.sh`: `.claude/ensure_npm_ci.py` runs `npm ci` automatically when `node_modules/.bin/husky` is missing (the exact gap above), and `.claude/ensure_code_graph_tools.py` builds the CodeGraph/Repowise/Graphify index for any of those tools that's already installed but not yet indexed in this checkout — it never installs a missing CLI (that stays an explicit `/project-init`/`/setup` opt-in). Both are best-effort: a fresh worktree still benefits from the manual `npm ci` above if a hook's time-box or environment prevents it from completing. The two hooks share their subprocess/path-resolution plumbing via `.claude/lib/session_start_common.py`, mirroring the `plugins/dev-team/hooks/lib/` and `scripts/lib/` shared-helper convention. +Run `npm ci` as the first step in any new worktree. An unprovisioned worktree has no `node_modules`, so git hooks silently don't run — `ci-local.sh`/CI backstop it. `SessionStart` hooks (`.claude/ensure_npm_ci.py`, `.claude/ensure_code_graph_tools.py`) do this automatically on a best-effort basis. ### Script authoring — Python only -**Every shipped script under `plugins/dev-team/` is Python 3.10+ using stdlib only.** See [ADR 0014](docs/adr/0014-python-for-cross-os-scripts.md) (the decision), [ADR 0015](docs/adr/0015-bash-removal-complete.md) (the completion), and [ADR 0031](docs/adr/0031-raise-shipped-python-floor-to-3-10.md) (the floor's move off EOL 3.8). Concretely: +Every shipped script under `plugins/dev-team/` is Python 3.10+, stdlib only (see [ADR 0014](docs/adr/0014-python-for-cross-os-scripts.md), [ADR 0015](docs/adr/0015-bash-removal-complete.md), [ADR 0031](docs/adr/0031-raise-shipped-python-floor-to-3-10.md)): -- **All shipped hooks + scripts are `.py` files.** The only `.sh` in `plugins/dev-team/` are the two pre-Python bootstrap shims, which cannot themselves be Python because they run before an interpreter is guaranteed on PATH: `install.sh` (the `install.py` trampoline) and `hooks/py.sh` (resolves a real Python 3 across `python3`/`py -3`/`python`/`$DEV_TEAM_PYTHON` so hooks and `/version` work on Windows, where `python3` is often absent — see #1078). Every other shipped invocation routes through `py.sh`, not a bare `python3`. -- **Stdlib only.** No `pip install`, no `requirements.txt` for shipped code. `subprocess`, `signal`, `pathlib`, `argparse`, `json`, `hashlib`, `re` cover the vast majority of shell-script territory portably. -- **Cross-OS by default.** Python runs natively on macOS, Linux, and Windows — no more Git Bash requirement for plugin hooks. When probing OS-specific paths (DOTNET_ROOT, tool install locations), use runtime probes (`subprocess`, `pathlib`) rather than hard-coding macOS or Linux paths. -- **Tests are pytest.** New tests land as `test_*.py` under the plugin's `tests/` tree. +- All shipped hooks/scripts are `.py`. The only `.sh` are the two pre-Python bootstrap shims (`install.sh`, `hooks/py.sh`) that must run before an interpreter is guaranteed on PATH. +- Stdlib only — no `pip install`, no `requirements.txt` for shipped code. +- Probe OS-specific paths at runtime rather than hard-coding them. +- Tests are pytest, `test_*.py` under the plugin's `tests/` tree. -Repo-root `scripts/*.sh` (`ci-local.sh`, `dev-setup.sh`, `cost-regression-check.sh`, the various `assemble-docs.sh`/`eval-changed.sh`/`run-full-eval.sh` helpers) are OUT of this rule's scope — they orchestrate developer tooling around the plugin, not the plugin itself, and are not shipped downstream. Convert them opportunistically when you touch them. +Repo-root `scripts/*.sh` are out of scope — they orchestrate dev tooling, not shipped code. ### Testing locally -Register the local checkout as a marketplace, then install from it into a test project: - ```bash claude plugin marketplace add /path/to/agentic-dev-team claude plugin install --scope project dev-team@bfinster -# Or from the published marketplace (GitHub): -# claude plugin marketplace add bdfinst/agentic-dev-team -# claude plugin install dev-team@bfinster ``` ### Adding agents, skills, or hooks -- **Agent**: Add a `.md` file to `plugins/dev-team/agents/` -- **Agent-loaded skill**: Add a `SKILL.md` under `plugins/dev-team/skills//` -- **User-invocable skill** (slash command): Add a `SKILL.md` under `plugins/dev-team/skills//` with `user-invocable: true` in frontmatter -- **Hook**: Add a `.py` file to `plugins/dev-team/hooks/` and register it in `plugins/dev-team/settings.json` - -After changes, run `/agent-audit` to verify structural compliance. +- **Agent**: `.md` file in `plugins/dev-team/agents/` +- **Agent-loaded skill**: `SKILL.md` under `plugins/dev-team/skills//` +- **User-invocable skill**: same, with `user-invocable: true` in frontmatter +- **Hook**: `.py` file in `plugins/dev-team/hooks/`, registered in `plugins/dev-team/settings.json` -[`plugins/dev-team/docs/developer-notes.md`](plugins/dev-team/docs/developer-notes.md) is the maintainer-facing entry point: an index of the plugin-development docs plus the playbook for adding a new static-analysis language. +Run `/agent-audit` after changes. See [`plugins/dev-team/docs/developer-notes.md`](plugins/dev-team/docs/developer-notes.md) for the full maintainer index. ### Testing hook changes before release -**A hook edit in this checkout does not affect a live session until it ships.** Real hook invocations — PreToolUse/PostToolUse hooks like `agent_dispatch_ledger.py`, `pre_commit_review.py`, the guards — run from the **installed plugin cache** (`~/.claude/plugins/cache/bfinster/dev-team//hooks/`), not from `plugins/dev-team/hooks/` in your working tree. `settings.json` registers each hook by a plugin-root-relative path (`sh hooks/py.sh hooks/.py`), and that root resolves to the cache copy for the running session. So a hook fix cannot be validated by the very session you fix it in — it only takes effect after the change ships in a release and the cache updates (`/dev-team:upgrade`). This bit issue #1500: a fix to the dispatch-ledger's `subject_type` matching (PR #1498) could not record a single `agent_dispatch_ledger` "record" event during the session that authored it, because that session was still running the pre-fix cached hook. Validate hook changes one of two ways instead: +A hook edit in this checkout doesn't affect a live session until it ships — real hook invocations run from the **installed plugin cache**, not your working tree. Validate one of two ways: -1. **Unit-test the hook directly (fast, deterministic, no live session — the primary path).** Every shipped hook is invoked as a subprocess with a crafted stdin payload by a `test_*.py` under `plugins/dev-team/tests/hooks/` (plus the repo-level gate/contract tests under `tests/hooks/` and `tests/repo/`). This runs the code **in your working tree**, so it reflects your edit immediately. Any hook whose behavior is only observable through a live Agent/tool dispatch (e.g. the ledger → `.review-passed` corroboration chain) must carry module-level coverage of that end-to-end path, so a fix is verifiable here rather than only after release. Run e.g. `python3 -m pytest plugins/dev-team/tests/hooks tests/hooks tests/repo -q`. +1. **Unit-test the hook directly (primary path).** `python3 -m pytest plugins/dev-team/tests/hooks tests/hooks tests/repo -q` runs the code in your working tree immediately. +2. **End-to-end against a live session.** Re-run `claude plugin install` to refresh the cache, then confirm the hook's side effect in a fresh session (e.g. a line in `.claude/metrics/boundary-events.jsonl`). -2. **End-to-end against a live session (when you must exercise the real dispatch path).** Install the plugin from the local checkout marketplace into a throwaway project (see [Testing locally](#testing-locally) for the two `claude plugin` commands). **`claude plugin install` copies the checkout into the versioned cache**, so it is a snapshot, not a live link — **re-run the install after every hook edit** to refresh the cache, then start a fresh session in the test project. Confirm the hook fired by inspecting its side effect — for the dispatch ledger, a `"decision":"record"` line in `.claude/metrics/boundary-events.jsonl` after a real review dispatch. - -Prefer path 1; reach for path 2 only when the behavior genuinely cannot be reproduced by invoking the hook module directly. +Prefer path 1; use path 2 only when the behavior can't be reproduced by invoking the hook module directly. ### Releasing -Releases are managed by release-please. Push conventional commits to main: - -- `feat:` → minor version bump -- `fix:` → patch version bump -- `feat!:` or `BREAKING CHANGE` → major version bump +Release-please manages releases from conventional commits (`feat:` minor, `fix:` patch, `feat!:`/`BREAKING CHANGE` major) — merging its release PR cuts a GitHub Release. -A release PR is opened automatically. Merging it creates a GitHub Release with a version tag. - -**PR titles must be conventional.** This repo squash-merges PRs (see [Working Rules](#working-rules)). Squash-merge creates a single commit on `main` using the PR title, so **the PR title must follow the conventional format** for release-please to read it correctly. - -- Format PR titles as `(): ` — e.g., `feat(agents): add concurrent-request-review agent`, `fix(skills): resolve circular path references`. -- Scope is optional; type is required (`feat`, `fix`, `chore`, `docs`, `refactor`, etc.). -- If a release is silently missed, recover with a follow-up commit carrying a `Release-As: X.Y.Z` footer. +**PR titles must be conventional** (`(): `) since squash-merge uses the PR title as the commit message. If a release is silently missed, recover with a follow-up commit carrying `Release-As: X.Y.Z`. ## Cloud sessions (claude.ai/code) -For running this repo in a Claude Code web/cloud session — installing the plugin via the Setup script, the SessionStart fallback, and the file-based fallback — see the `cloud-setup` skill (`.claude/skills/cloud-setup/SKILL.md`) or [`docs/cloud-setup.md`](docs/cloud-setup.md). +See the `cloud-setup` skill or [`docs/cloud-setup.md`](docs/cloud-setup.md) for running this repo in a Claude Code web/cloud session. ## graphify -This project has a knowledge graph at graphify-out/ with god nodes, community structure, and cross-file relationships. - -Rules: +Knowledge graph at `graphify-out/`. -- For codebase questions — architecture, symbol relationships, cross-file structure, "how does X work" — first run `graphify query ""` when graphify-out/graph.json exists. Use `graphify path "" ""` for relationships and `graphify explain ""` for focused concepts. These return a scoped subgraph, usually much smaller than GRAPH_REPORT.md or raw grep output. -- If graphify-out/wiki/index.md exists, use it for broad navigation instead of raw source browsing. -- Read graphify-out/GRAPH_REPORT.md only for broad architecture review or when query/path/explain do not surface enough context. -- After modifying code, run `graphify update .` to keep the graph current (AST-only, no API cost). -- graphify is for understanding source, not for metadata lookups. Skip it — plain `grep`/`find`/`ls`/`Read` is fine — for: package manifests and lockfiles (`package.json`, `package-lock.json`, `yarn.lock`, `requirements.txt`, etc.), `node_modules`/`dist`/`build`/`coverage` contents, VCS metadata (`.git/`), bare directory listings, and single-file line/count lookups. The `PreToolUse` nudge hooks in `.claude/settings.json` enforce this same exclusion list so the reminder only fires on genuine source exploration. +- For architecture/symbol/cross-file questions, run `graphify query ""`, `graphify path "" ""`, or `graphify explain ""` first. +- Use `graphify-out/wiki/index.md` for broad navigation; `graphify-out/GRAPH_REPORT.md` only when those don't surface enough. +- After modifying code, run `graphify update .`. +- Skip graphify for manifests/lockfiles, `node_modules`/`dist`/`build`/`coverage`, `.git/`, directory listings, and single-file lookups — plain `grep`/`find`/`ls`/`Read` is fine there. diff --git a/plugins/dev-team/CLAUDE.md b/plugins/dev-team/CLAUDE.md index 93edae700..cd042b107 100644 --- a/plugins/dev-team/CLAUDE.md +++ b/plugins/dev-team/CLAUDE.md @@ -24,11 +24,11 @@ Every change must reduce friction: **fewer missteps, less rework, lower token co ## Core Principles -1. **Selective Agent Loading**: Load only necessary agents. Target < 10,000 tokens simple tasks. -2. **Context Ceiling**: `min(40% of window, 350K)` — see [Context Management](docs/context-management.md). Enforced by `hooks/context_ceiling_guard.py`. -3. **Persona-Driven Behavior**: Specs in `.claude/agents/`. Build concurrency `DEV_TEAM_MAX_PARALLEL_BUILDS`: unset → `1` (sequential); set `--jobs`/env to opt into fan-out, capped by wave width. -4. **Human-in-the-Loop**: Autonomous agents, human oversight. -5. **Dynamic Configuration**: Config changes → `.claude/metrics/config-changelog.jsonl`. +1. **Selective Agent Loading**: load only necessary agents; target < 10,000 tokens for simple tasks. +2. **Context Ceiling**: `min(40% of window, 350K)` — see [Context Management](docs/context-management.md); enforced by `hooks/context_ceiling_guard.py`. +3. **Persona-Driven Behavior**: specs in `.claude/agents/`. Build concurrency via `DEV_TEAM_MAX_PARALLEL_BUILDS`: unset → sequential (`1`); set `--jobs`/env to opt into fan-out, capped by wave width. +4. **Human-in-the-Loop**: autonomous agents, human oversight. +5. **Dynamic Configuration**: config changes → `.claude/metrics/config-changelog.jsonl`. 6. **ATDD + Code-First Small Batches** (sole build cadence — Rec 3, docs/experiments/RECOMMENDATIONS.md): no code without a `/plan` scenario. 7. **Python for cross-OS scripts**: shipped hooks/scripts are Python 3.10+ stdlib-only (ADR 0014, 0015, 0031). @@ -79,7 +79,7 @@ Required for high-impact decisions. Full protocol: **[Human Oversight Protocol]( All agents apply the **[Quality Gate Pipeline](skills/quality-gate-pipeline/SKILL.md)**. Ethics and audit logging: **[Governance & Compliance](skills/governance-compliance/SKILL.md)**. -**Quality ownership.** Agents own the quality *state* — green means the whole suite, not just the diff. Red signals must be fixed or triaged, never stepped over. +**Quality ownership.** Green means the whole suite, not the diff; fix or triage red — never step over it. Hooks: `pre_tool_guard.py` blocks sensitive path writes; `destructive_guard.py` warns on destructive commands; `context_ceiling_guard.py` enforces the context ceiling (see above). diff --git a/plugins/marketplace-dev/CLAUDE.md b/plugins/marketplace-dev/CLAUDE.md index b600975f2..a17732a74 100644 --- a/plugins/marketplace-dev/CLAUDE.md +++ b/plugins/marketplace-dev/CLAUDE.md @@ -1,18 +1,8 @@ # marketplace-dev — build, audit, and maintain Claude Code plugins -`marketplace-dev` gives plugin authors the scaffolding, audit, and self-maintenance -infrastructure the `dev-team` plugin developed internally — as reusable, installable -tooling. It targets three workflows: **creating a new plugin** from scratch, -**improving an existing plugin's** architecture and quality, and **establishing a -new marketplace** with correct structure from the start. +Reusable scaffolding, audit, and self-maintenance tooling extracted from `dev-team`'s internal development — for **creating a new plugin**, **improving an existing plugin**, or **establishing a new marketplace**. No hard runtime dependency on `dev-team`. -It encodes the conventions in -[`docs/marketplace-builder-plugin-playbook.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/docs/marketplace-builder-plugin-playbook.md) -— directory layout, agent/skill frontmatter contracts, the markdown-vs-script -decision framework, and the eval-fixture pattern — as scaffolding skills, a -structural review agent, and a single shared knowledge file. - -`marketplace-dev` has **no hard runtime dependency on `dev-team`**. +Encodes the conventions in [`docs/marketplace-builder-plugin-playbook.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/docs/marketplace-builder-plugin-playbook.md) — directory layout, agent/skill frontmatter contracts, markdown-vs-script decisions, eval-fixture pattern — as scaffolding skills, a structural review agent, and one shared knowledge file. ## Slash commands @@ -31,10 +21,7 @@ structural review agent, and a single shared knowledge file. ## Agent -- **`plugin-best-practices-review`** — read-only, JSON output, structural findings. - Checks agent type appropriateness (markdown vs script), frontmatter compliance, - eval-coverage presence, and body line-count budgets. It does **not** evaluate - detection-logic quality — that belongs to the plugin's own `agent-eval`. +- **`plugin-best-practices-review`** — read-only, JSON output. Checks agent type (markdown vs script), frontmatter compliance, eval-coverage presence, body line-count budgets. Does **not** evaluate detection-logic quality — that's the plugin's own `agent-eval`. ## Knowledge diff --git a/plugins/security-assessment/CLAUDE.md b/plugins/security-assessment/CLAUDE.md index 6e446e5e3..b429b8bf1 100644 --- a/plugins/security-assessment/CLAUDE.md +++ b/plugins/security-assessment/CLAUDE.md @@ -2,11 +2,11 @@ Deep security assessment and adversarial ML red-team capability. Companion to `dev-team`, which provides the reusable primitives (codebase-recon, ACCEPTED-RISKS convention, versioned security-primitives-contract, SARIF-first tool orchestration). -This plugin is **opinionated**: its hooks default ON, its red-team harness accepts only self-owned targets by default, and its orchestration enforces a fixed pipeline order. If you want primitives without the assessment machinery, install only `dev-team`. +This plugin is **opinionated**: hooks default ON, the red-team harness accepts only self-owned targets by default, and orchestration enforces a fixed pipeline order. Want primitives without the assessment machinery? Install only `dev-team`. ## Structure Contract -This plugin mirrors `plugins/dev-team/` one-for-one; `harness/` is a first-class top-level directory for executable application code. The rule: "same schema where the directory applies; omitted directories documented here with rationale." +Mirrors `plugins/dev-team/` one-for-one, plus `harness/` — a top-level dir for executable application code. | Directory | Mirrors dev-team? | Rationale if omitted | |---|---|---| @@ -21,7 +21,7 @@ This plugin mirrors `plugins/dev-team/` one-for-one; `harness/` is a first-class ## Hooks default ON (this plugin only) -The PostToolUse auto-scan hook fires on Edit/Write of matched file types. It is registered in THIS plugin's `settings.json` — NOT in `dev-team`. Default severity threshold: `error` only. Set `verbose_hooks: true` in `settings.local.json` to surface warnings too. +The PostToolUse auto-scan hook fires on Edit/Write of matched file types. Registered in THIS plugin's `settings.json`, not `dev-team`'s. Default severity threshold: `error` only; set `verbose_hooks: true` in `settings.local.json` to surface warnings too. Opt-out: add this snippet to your `settings.local.json`: @@ -39,13 +39,13 @@ Opt-out: add this snippet to your `settings.local.json`: ## SARIF-first tool orchestration -Findings flow through the shared SARIF parser in `plugins/dev-team/skills/static-analysis-integration` and normalize to the unified finding envelope v1.0 defined in `plugins/dev-team/knowledge/security-primitives-contract.md`. This plugin ships seven **custom semgrep rulesets** (`knowledge/semgrep-rules/{crypto-anti-patterns,datastore-patterns,fraud-domain,llm-safety,messaging-patterns,ml-patterns,serialization-patterns}.yaml`) alongside invocations of the usual community rulesets (`p/security-audit`, `p/owasp-top-ten`, etc.). +Findings flow through the shared SARIF parser in `plugins/dev-team/skills/static-analysis-integration` and normalize to the unified finding envelope v1.0 in `plugins/dev-team/knowledge/security-primitives-contract.md`. Ships seven **custom semgrep rulesets** (`knowledge/semgrep-rules/{crypto-anti-patterns,datastore-patterns,fraud-domain,llm-safety,messaging-patterns,ml-patterns,serialization-patterns}.yaml`) alongside the usual community rulesets (`p/security-audit`, `p/owasp-top-ten`, etc.). ## LLM-safety coverage bound (verbatim, required) static coverage via llm-safety.yaml is intentionally narrow — it catches pattern-visible issues but is NOT a substitute for runtime LLM safety testing -Runtime LLM-safety testing tools (`garak`, `rebuff`, `PyRIT`) are deferred to the red-team harness (Phase C). The static ruleset handles hardcoded LLM keys, insecure model loading (ONNX/pickle deserialization), and prompt-template string injection; it cannot cover adversarial inputs or emergent model behavior. +Runtime LLM-safety tools (`garak`, `rebuff`, `PyRIT`) are deferred to the red-team harness (Phase C). The static ruleset handles hardcoded LLM keys, insecure model loading (ONNX/pickle deserialization), and prompt-template string injection — not adversarial inputs or emergent model behavior. ## Red-team target scope @@ -58,7 +58,7 @@ The refusal message includes a one-line example of `authorization.md` format. Th ## Adapter Maintenance Policy -See `plugins/dev-team/skills/static-analysis-integration/SKILL.md`. The companion plugin's custom adapters (e.g. actionlint's JSON→SARIF wrapper, the five bespoke-JSON adapters from Step 3b) follow the same policy: `maintainers:` list with minimum 2 names, tier-2 CI on installed binaries, 14-day escalation, three-release deprecation path. +Custom adapters (actionlint's JSON→SARIF wrapper, the 5 bespoke-JSON adapters) follow `static-analysis-integration/SKILL.md`'s policy: `maintainers:` (min 2), tier-2 CI, 14-day escalation, 3-release deprecation. ## Ruleset Maintenance Policy @@ -85,19 +85,19 @@ See `install.sh`. It performs four checks: **Agents** (13, effort: high): -- `fp-reduction` (effort: high) — 6-stage FP-reduction rubric (Stage 0 devil's advocate + Stages 1–5); disposition register with confidence field -- `business-logic-domain-review` (effort: high) — fraud-domain anti-patterns -- `deep-code-reasoning` (effort: high) — RECON surface-scoped freeform vulnerability reasoning; novel context-dependent issues beyond static rules -- `authorization-logic-review` (effort: high) — top-down authorization architecture review; policy declaration vs. enforcement gaps, multi-tenancy isolation -- `recon-driven-scan` (effort: high) — bridges RECON narrative claims to concrete file:line evidence; finds patterns SAST cannot express (inverted-boolean TLS defaults, RCE shapes via expression libraries, header-driven SQL, body-trusted IDOR) -- `cross-repo-synthesizer` (effort: high) — named attack chains across repos -- `exec-report-generator` (effort: high) — publication-ready executive report with Confidence column -- `redteam-recon-analyzer` (effort: high) — interpretation of probe 01 -- `redteam-evasion-analyzer` (effort: high) — interpretation of probes 03/04/05 -- `redteam-extraction-analyzer` (effort: high) — interpretation of probe 07 -- `redteam-report-generator` (effort: high) — final red-team report synthesis -- `tool-finding-narrative-annotator` (effort: high) — 4-domain narrative synthesis -- `compliance-edge-annotator` (effort: high) — LLM edge judgment for ambiguous mappings +- `fp-reduction` — 6-stage FP-reduction rubric (Stage 0 devil's advocate + Stages 1–5); disposition register with confidence field +- `business-logic-domain-review` — fraud-domain anti-patterns +- `deep-code-reasoning` — RECON surface-scoped freeform vulnerability reasoning; novel context-dependent issues beyond static rules +- `authorization-logic-review` — top-down authorization architecture review; policy declaration vs. enforcement gaps, multi-tenancy isolation +- `recon-driven-scan` — bridges RECON narrative claims to concrete file:line evidence; finds patterns SAST cannot express (inverted-boolean TLS defaults, RCE shapes via expression libraries, header-driven SQL, body-trusted IDOR) +- `cross-repo-synthesizer` — named attack chains across repos +- `exec-report-generator` — publication-ready executive report with Confidence column +- `redteam-recon-analyzer` — interpretation of probe 01 +- `redteam-evasion-analyzer` — interpretation of probes 03/04/05 +- `redteam-extraction-analyzer` — interpretation of probe 07 +- `redteam-report-generator` — final red-team report synthesis +- `tool-finding-narrative-annotator` — 4-domain narrative synthesis +- `compliance-edge-annotator` — LLM edge judgment for ambiguous mappings **Skills** (3): @@ -105,14 +105,6 @@ See `install.sh`. It performs four checks: - `compliance-mapping` — pattern-table first with LLM edge annotation - `security-assessment-pipeline` — declarative phase graph for `/security-assessment` -**Commands** (5): - -- `/security-assessment ` — full static-analysis pipeline -- `/cross-repo-analysis ` — cross-repo attack-chain analysis -- `/redteam-model ` — adversarial ML red-team -- `/export-pdf ` — PDF export -- `/upgrade` — plugin update + auto-update opt-in - **Hooks** (3): - `PreToolUse:Bash` → `redteam-guard.sh` (blocks direct orchestrator invocation) @@ -138,8 +130,6 @@ See `install.sh`. It performs four checks: - 8 probes: `redteam/probes/probe_{01..08}_*.py` - `tools/{service-comm-parser,shared-cred-hash-match}.py` -See `plans/security-review-companion-plugin.md` for the step-by-step history. - ## Not in this plugin - The primitives contract itself (`security-primitives-contract.md`) — lives in `dev-team/knowledge/` From a7a72b6e155fc614386a5e005d96ba9aced2910e Mon Sep 17 00:00:00 2001 From: Bryan Finster Date: Fri, 4 Sep 2026 10:23:34 -0500 Subject: [PATCH 2/3] chore: update deps --- package-lock.json | 1781 +++++++++++++++------------------------- package.json | 21 +- scripts/update_deps.py | 74 ++ 3 files changed, 747 insertions(+), 1129 deletions(-) create mode 100755 scripts/update_deps.py diff --git a/package-lock.json b/package-lock.json index c3b7f17c2..f7dd1adde 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,18 +8,18 @@ "name": "agentic-dev-team", "version": "0.0.0", "devDependencies": { - "@commitlint/cli": "^21.0.2", - "@commitlint/config-conventional": "^21.0.2", - "@eslint/js": "^9.0.0", - "commitlint": "^21.1.0", - "eslint": "^9.0.0", - "husky": "^9.1.0", - "lint-staged": "^17.0.7", - "typescript": "^5.4.0", - "typescript-eslint": "^8.0.0" + "@commitlint/cli": "^21.2.2", + "@commitlint/config-conventional": "^21.2.2", + "@eslint/js": "^10.0.1", + "commitlint": "^21.2.2", + "eslint": "^10.10.0", + "husky": "^9.1.7", + "lint-staged": "^17.4.1", + "typescript": "^6.0.3", + "typescript-eslint": "^8.69.0" }, "engines": { - "node": ">=24" + "node": ">=22" } }, "node_modules/@babel/code-frame": { @@ -47,19 +47,43 @@ "node": ">=6.9.0" } }, + "node_modules/@cacheable/memory": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz", + "integrity": "sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cacheable/utils": "^2.5.0", + "@keyv/bigmap": "^1.3.1", + "hookified": "^1.15.1", + "keyv": "^5.6.0" + } + }, + "node_modules/@cacheable/utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.5.0.tgz", + "integrity": "sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hashery": "^1.5.1", + "keyv": "^5.6.0" + } + }, "node_modules/@commitlint/cli": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-21.1.0.tgz", - "integrity": "sha512-CVwY6TxGv5naEaWxBdgNHko1xgL95Mb4WcIqp9iik33H0ctVqRv6YtekCntayhEP0T/apuiGvHu5HcCwFuVxEA==", + "version": "21.2.2", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-21.2.2.tgz", + "integrity": "sha512-a+6hQxIxnpdvSvS2apvttPNbEliYsVC3PqFYDiiB2kjbwIsQsj1urvQ4Tkf70pKYozPalKAuRQmm/GHwndduqA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-conventional": "^21.1.0", - "@commitlint/format": "^21.1.0", - "@commitlint/lint": "^21.1.0", - "@commitlint/load": "^21.1.0", - "@commitlint/read": "^21.1.0", - "@commitlint/types": "^21.1.0", + "@commitlint/config-conventional": "^21.2.2", + "@commitlint/format": "^21.2.2", + "@commitlint/lint": "^21.2.2", + "@commitlint/load": "^21.2.2", + "@commitlint/read": "^21.2.1", + "@commitlint/types": "^21.2.0", "tinyexec": "^1.0.0", "yargs": "^18.0.0" }, @@ -71,65 +95,41 @@ } }, "node_modules/@commitlint/config-conventional": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-21.1.0.tgz", - "integrity": "sha512-BIFl8xM+3SLy3jrblUC3wmQLCVbLty+++6o859BDCmybVrQdXmIWO+dlkGIbv/M2bBoC55wGuh0zGiw3TPjL1g==", + "version": "21.2.2", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-21.2.2.tgz", + "integrity": "sha512-NxA37SZviusFUEYOQZ5hNnZ1h7O/KiemPkxjOlpzKJNnWxThiwc6/SaZhaPa8fyLvfRBAywhQhJJk8XESHWlpQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.1.0", - "conventional-changelog-conventionalcommits": "^9.2.0" + "@commitlint/types": "^21.2.0", + "conventional-changelog-conventionalcommits": "^10.0.0" }, "engines": { "node": ">=22.12.0" } }, "node_modules/@commitlint/config-validator": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-21.1.0.tgz", - "integrity": "sha512-gHczt1xqQSwfNqBmOI3HjejtTljkiBEUneExMmTBLD0WwTC78lAqDvNMyydbySt3DhpH0F9oX7Vvuks6s5XPFw==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-21.2.0.tgz", + "integrity": "sha512-t7AzNHAKeIdo/3NRGwzpufKHsKkPHmFs/56N2Fnsh0/r0rGtnQzTxk6vnFgjaGr4hdSQKNB50/KAhR9Yk4LJKA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.1.0", + "@commitlint/types": "^21.2.0", "ajv": "^8.11.0" }, "engines": { "node": ">=22.12.0" } }, - "node_modules/@commitlint/config-validator/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@commitlint/config-validator/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, "node_modules/@commitlint/ensure": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-21.1.0.tgz", - "integrity": "sha512-/S8Mo3Q1NtQUYDQjDmyQVPxfIwtnxq+guzMOkuGk8OSdwlzanm1WB9wDPIuuzlbMDDnBNbiAuBEUCcCNlfjrTQ==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-21.2.0.tgz", + "integrity": "sha512-76IF9vDNS13lAzEEik9eKwzt8f9hYhWiwVXZ2AnyLCz5/f511FsEQ3pw1X3/zSQpdRLQU7i5qDMVKyXi1GWjSg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.1.0", + "@commitlint/types": "^21.2.0", "es-toolkit": "^1.46.0" }, "engines": { @@ -147,13 +147,13 @@ } }, "node_modules/@commitlint/format": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-21.1.0.tgz", - "integrity": "sha512-ySymqKYBfjNrQ5N4W/l1iF2ISW1W7Eu/Oi/wRxlri31N0yjNyzUyUzQwyuZLDzTXIlMs4IZ7hIOfAZx8lO18gA==", + "version": "21.2.2", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-21.2.2.tgz", + "integrity": "sha512-v6fvxZSc/AvVMROlr3H34+1766bZSYApRUSCAMjWamStPjKMvZ8GdvVA5YW/VQNgbFTmcMz6OYmSTJEvIjPrfA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.1.0", + "@commitlint/types": "^21.2.0", "picocolors": "^1.1.1" }, "engines": { @@ -161,13 +161,13 @@ } }, "node_modules/@commitlint/is-ignored": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-21.1.0.tgz", - "integrity": "sha512-RoRh1/YI+fYH+aid5lMQ2UD0vZ3p3Vf1KeUWT1ir3H/p/7T/6SFv1OiXLgLwUT8dP72EVWeEIyOfkiSWLZYVvw==", + "version": "21.2.2", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-21.2.2.tgz", + "integrity": "sha512-9UoKNgfFE3LU7FrzierCvk3CdDfMDeVGC86qZiT/n0TIjfq/dmZ9MHuXd45OTNRa26ZanmJRxEtmiXk/lEJihg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.1.0", + "@commitlint/types": "^21.2.0", "semver": "^7.6.0" }, "engines": { @@ -175,32 +175,32 @@ } }, "node_modules/@commitlint/lint": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-21.1.0.tgz", - "integrity": "sha512-0DbfVVUjAWBfixW6v7CXXWVxMcj6Ukf/oB7O8NAbouP3jxmqUaC4eVQphxl3B3M0ii3cCQiR3sRAYxICwU2gAA==", + "version": "21.2.2", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-21.2.2.tgz", + "integrity": "sha512-Fy8JxEBzdmsYWFude/61GxXu5O+wEymwiRK2z9GL9R8mCsXphCoGxAFc5iHn5mjlfcSrhiiONE+ksf4KOjnaPg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/is-ignored": "^21.1.0", - "@commitlint/parse": "^21.1.0", - "@commitlint/rules": "^21.1.0", - "@commitlint/types": "^21.1.0" + "@commitlint/is-ignored": "^21.2.2", + "@commitlint/parse": "^21.2.2", + "@commitlint/rules": "^21.2.2", + "@commitlint/types": "^21.2.0" }, "engines": { "node": ">=22.12.0" } }, "node_modules/@commitlint/load": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-21.1.0.tgz", - "integrity": "sha512-juiClVEcoreNB0TNVkseO2EmNcpEs/Yhnmgbnm/hQAKBFRynKwIaoNIljXkx/3yvZcMO0EE8I2XOEI7d5KZG8Q==", + "version": "21.2.2", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-21.2.2.tgz", + "integrity": "sha512-0Tt6wDPX167cjKC5D4zhm0+20wJJG+TN/TKovMOspfSe78rOnKX+MNzlVNiu6HyQPZChPJ8QBH31MVt6Bb8fCg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^21.1.0", + "@commitlint/config-validator": "^21.2.0", "@commitlint/execute-rule": "^21.0.1", - "@commitlint/resolve-extends": "^21.1.0", - "@commitlint/types": "^21.1.0", + "@commitlint/resolve-extends": "^21.2.2", + "@commitlint/types": "^21.2.0", "cosmiconfig": "^9.0.1", "cosmiconfig-typescript-loader": "^6.1.0", "es-toolkit": "^1.46.0", @@ -212,9 +212,9 @@ } }, "node_modules/@commitlint/message": { - "version": "21.0.2", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-21.0.2.tgz", - "integrity": "sha512-5n4aqHGD/FNnom/D5L8i7cYtV+xjuXcBL832C3w9VglEsZzIsoHpJsvxzJ7cgiOsOdc/2jU4t5+7qMHh7GBX3g==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-21.2.0.tgz", + "integrity": "sha512-YxGoiXD/HXNXLJPrQwE5poXa+XH0CBEm+mdvbHQP0g6MV/dmJyUFCzPNzZbxL93GvZ70TmtTK0Z0/IBpAqHv8g==", "dev": true, "license": "MIT", "engines": { @@ -222,30 +222,30 @@ } }, "node_modules/@commitlint/parse": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-21.1.0.tgz", - "integrity": "sha512-HdAqbbjQS8eEtbR74Ysg2VNmbvAfeWLVYMkip/lHibNrtjRsC/97XAYN3/H5P0pEJtDfyTb3iLs8x6y0eu4OYA==", + "version": "21.2.2", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-21.2.2.tgz", + "integrity": "sha512-MEkobPfvRp+z06Wro8HMG1BDGHzZmj82A1LH1nWeG3ipHpg/x4m6v3wEDvMBIKjRFUnfR3nBeFs3MVCr7UdAmg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.1.0", - "conventional-changelog-angular": "^8.2.0", - "conventional-commits-parser": "^6.3.0" + "@commitlint/types": "^21.2.0", + "conventional-changelog-angular": "^9.0.0", + "conventional-commits-parser": "^7.0.0" }, "engines": { "node": ">=22.12.0" } }, "node_modules/@commitlint/read": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-21.1.0.tgz", - "integrity": "sha512-ID7m79aw8d0dMlxuXHD2QGxEX3Fhl/mUPA80WwEW5VgeOpUHNahhwWJefDdoBDVZcDfbHuf429NrcK0gxQsQjA==", + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-21.2.1.tgz", + "integrity": "sha512-hUW7EJQnNTL0vPOmVMNK4CrnrNBN0nN+JJHReFkdHO5y4iyHeEmTBwuC15OCqUTjxWo7idnH1LftfpWVIaPWIA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/top-level": "^21.0.2", - "@commitlint/types": "^21.1.0", - "git-raw-commits": "^5.0.0", + "@commitlint/top-level": "^21.2.0", + "@commitlint/types": "^21.2.0", + "@conventional-changelog/git-client": "^3.0.0", "tinyexec": "^1.0.0" }, "engines": { @@ -253,14 +253,14 @@ } }, "node_modules/@commitlint/resolve-extends": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-21.1.0.tgz", - "integrity": "sha512-SANYkxJDfMl3TvnyALWHEaiF5nc6FFaOnh7VvfxjT4X2vD4i2gVHhmfMm1fsrBwDRX98/XyM1XDo5sAd/KXcyQ==", + "version": "21.2.2", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-21.2.2.tgz", + "integrity": "sha512-RPkJ/IFi7sMUUVbZLqwWFtWw/zRDcfFsmrPSiTMrt5wb7AdxOr86EGQFvmGzef5QKV5IPBWWCujqVTw1RWX44A==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^21.1.0", - "@commitlint/types": "^21.1.0", + "@commitlint/config-validator": "^21.2.0", + "@commitlint/types": "^21.2.0", "es-toolkit": "^1.46.0", "global-directory": "^5.0.0", "resolve-from": "^5.0.0" @@ -269,27 +269,17 @@ "node": ">=22.12.0" } }, - "node_modules/@commitlint/resolve-extends/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/@commitlint/rules": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-21.1.0.tgz", - "integrity": "sha512-fOPEYSmKn1ZJptjLmCEjJfYqz0PUYr8ng6VY2ZW26sB7KtENR90CmAXHEmScBbOIZip+d/+OwqK12DFBuHTqsQ==", + "version": "21.2.2", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-21.2.2.tgz", + "integrity": "sha512-eplQzyYkBjYB1HyyRj8hkcK11Y9DU9nuBz7uOKEd6NpE9NGDytLFCAnlRE+OoiK/5sHEJsaz2RGhuWBvYzIbNA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/ensure": "^21.1.0", - "@commitlint/message": "^21.0.2", + "@commitlint/ensure": "^21.2.0", + "@commitlint/message": "^21.2.0", "@commitlint/to-lines": "^21.0.1", - "@commitlint/types": "^21.1.0" + "@commitlint/types": "^21.2.0" }, "engines": { "node": ">=22.12.0" @@ -306,9 +296,9 @@ } }, "node_modules/@commitlint/top-level": { - "version": "21.0.2", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-21.0.2.tgz", - "integrity": "sha512-s9KKM+e+mXgFeIh4n7KmOGAVT3mkJ3Fp1bBYHIK5pjeUwlEMzp/tZfb5u0Poa680AsQTXMEMRxZi1vQ9m2X5ug==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-21.2.0.tgz", + "integrity": "sha512-Y5gmQ+KxzqCrBFJfLvFEPvvwD3LDiNZoTT2yeFBm96M8qhmqSzQc5DvX3rheAaAMjyIvMXOCLS/mWfdpONsjyQ==", "dev": true, "license": "MIT", "dependencies": { @@ -319,13 +309,13 @@ } }, "node_modules/@commitlint/types": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-21.1.0.tgz", - "integrity": "sha512-YodnnnH1Cp+08nP8HGNJAIuB6L3/vdCTHVRTfF8Ik/wRCLOTsU9zwv3yO1cSPQRDa9CLYtE+UJ2K67r7CwMSFw==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-21.2.0.tgz", + "integrity": "sha512-7zVFCDB2reMvJH5dmbKnOQPjZEvjdJTH8jc0U/PIPU1r3/+vf5pD1HlfitV2MWsWXrvu7u39iY1lyLUPOaN0Gw==", "dev": true, "license": "MIT", "dependencies": { - "conventional-commits-parser": "^6.3.0", + "conventional-commits-parser": "^7.0.0", "picocolors": "^1.1.1" }, "engines": { @@ -333,22 +323,22 @@ } }, "node_modules/@conventional-changelog/git-client": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.7.0.tgz", - "integrity": "sha512-j7A8/LBEQ+3rugMzPXoKYzyUPpw/0CBQCyvtTR7Lmu4olG4yRC/Tfkq79Mr3yuPs0SUitlO2HwGP3gitMJnRFw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-3.1.2.tgz", + "integrity": "sha512-jZqwnJwf7nboIlAcw/mkOjVa6DexCcUOgT2oOQgkoi3z9vR8tGFkcMy2BFcYwjhL9sYcDDXkRQDayiDieCoW7A==", "dev": true, "license": "MIT", "dependencies": { - "@simple-libs/child-process-utils": "^1.0.0", - "@simple-libs/stream-utils": "^1.2.0", + "@simple-libs/child-process-utils": "^2.0.0", + "@simple-libs/stream-utils": "^2.0.0", "semver": "^7.5.2" }, "engines": { - "node": ">=18" + "node": ">=22" }, "peerDependencies": { - "conventional-commits-filter": "^5.0.0", - "conventional-commits-parser": "^6.4.0" + "conventional-commits-filter": "^6.0.1", + "conventional-commits-parser": "^7.1.2" }, "peerDependenciesMeta": { "conventional-commits-filter": { @@ -359,6 +349,16 @@ } } }, + "node_modules/@conventional-changelog/template": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@conventional-changelog/template/-/template-1.4.0.tgz", + "integrity": "sha512-aalGyl7dbB5PArRebDIX43ZvBlXrYm9uWzGJ26t+4SzJVPsOuvfILGGbw5X4yX7i50YEmJ8zvbiWnqH/AAnZqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", @@ -402,105 +402,89 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", - "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.7", + "@eslint/object-schema": "^3.0.5", "debug": "^4.3.1", - "minimatch": "^3.1.5" + "minimatch": "^10.2.4" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz", + "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.17.0" + "@eslint/core": "^1.2.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", - "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.14.0", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.3.0", - "minimatch": "^3.1.5", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/js": { - "version": "9.39.5", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", - "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", "dev": true, "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.3.tgz", + "integrity": "sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.17.0", + "@eslint/core": "^1.2.1", "levn": "^0.4.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@humanfs/core": { @@ -569,35 +553,66 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@keyv/bigmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz", + "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hashery": "^1.4.0", + "hookified": "^1.15.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "keyv": "^5.6.0" + } + }, + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", + "dev": true, + "license": "MIT" + }, "node_modules/@simple-libs/child-process-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@simple-libs/child-process-utils/-/child-process-utils-1.0.2.tgz", - "integrity": "sha512-/4R8QKnd/8agJynkNdJmNw2MBxuFTRcNFnE5Sg/G+jkSsV8/UBgULMzhizWWW42p8L5H7flImV2ATi79Ove2Tw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@simple-libs/child-process-utils/-/child-process-utils-2.0.0.tgz", + "integrity": "sha512-dvNoRKLijXnD0XoJAz94pbNuB5GQgDr55UhpSPhffDkTT0Cmcqh9jSCOtwfT2d4H6MI9E7c4SgtMuJXZ6F3c6A==", "dev": true, "license": "MIT", "dependencies": { - "@simple-libs/stream-utils": "^1.2.0" + "@simple-libs/stream-utils": "^2.0.0" }, "engines": { - "node": ">=18" + "node": ">=22" }, "funding": { "url": "https://ko-fi.com/dangreen" } }, "node_modules/@simple-libs/stream-utils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@simple-libs/stream-utils/-/stream-utils-1.2.0.tgz", - "integrity": "sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@simple-libs/stream-utils/-/stream-utils-2.0.0.tgz", + "integrity": "sha512-fCTuZK4QBa+39Oz9l4OGfJfz+GpwCp3AqO7Zch3to99xHPgstVsRFpeQ8LNd2o1Gv8raL2mCFwiaHh7bFSp5DQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=22" }, "funding": { "url": "https://ko-fi.com/dangreen" } }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", @@ -613,9 +628,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.0.0.tgz", - "integrity": "sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA==", + "version": "26.4.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.1.tgz", + "integrity": "sha512-k97ENvZWtvA6yqz5/FS6a7duDgOPEeOQOc2iKS/nY6mX6qJUKtLnWzQS+Xj6tXweyj6ZcTAK2Qecetnvi9nCLA==", "dev": true, "license": "MIT", "peer": true, @@ -623,21 +638,15 @@ "undici-types": "~8.3.0" } }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.1.tgz", - "integrity": "sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.69.0.tgz", + "integrity": "sha512-ewfspqWvSxKSOaplqAUNbaSFO0eB6w1EtQ+esfYFRm3614Ty4uNtExkcbgd6nWsXphbqKyf9ZYdbZdv2xEoWEQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/type-utils": "8.60.1", - "@typescript-eslint/utils": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.5.0" + "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/visitor-keys": "8.69.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -645,58 +654,31 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.60.1", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.1.tgz", - "integrity": "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==", + "node_modules/@typescript-eslint/types": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.69.0.tgz", + "integrity": "sha512-K3VrubUPhlo9VDBS6QdI8YB5j7ClpqLRdefcz6PFrhnwicehBweqQ9Evhl4l+FYz0HdDmMqIiSX0aldGRYtDCA==", "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", - "debug": "^4.4.3" - }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", - "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.69.0.tgz", + "integrity": "sha512-+rmdgPA+EXkNgKYvHvFfhrs35utXbwaC5PGpDquSXcoXQDKUA5UjV0LmTucG/4JXkM31BTu4TilHtrN8IVBe8w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.60.1", - "@typescript-eslint/types": "^8.60.1", - "debug": "^4.4.3" + "@typescript-eslint/types": "8.69.0", + "eslint-visitor-keys": "^5.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -704,114 +686,82 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", - "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1" + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=0.4.0" } }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", - "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.1.tgz", - "integrity": "sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==", + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1", - "@typescript-eslint/utils": "8.60.1", - "debug": "^4.4.3", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", - "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", - "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/argue-cli": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/argue-cli/-/argue-cli-3.2.0.tgz", + "integrity": "sha512-VipTB0gXgGIFO2Rg9yEVN5wLt2AurJcZqDbgmYSwPwsykhLrQhs240/bfceev4w68lI8JshoOJIk9uW7tFzROw==", "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.60.1", - "@typescript-eslint/tsconfig-utils": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=22" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" + "url": "https://ko-fi.com/dangreen" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", @@ -821,10 +771,10 @@ "node": "18 || 20 || >=22" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", - "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", + "node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "license": "MIT", "dependencies": { @@ -834,264 +784,40 @@ "node": "20 || >=22" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "node_modules/cacheable": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz", + "integrity": "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "@cacheable/memory": "^2.2.0", + "@cacheable/utils": "^2.5.0", + "hookified": "^1.15.0", + "keyv": "^5.6.0", + "qified": "^0.10.1" } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz", - "integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==", + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" + "node": ">=6" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", - "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@typescript-eslint/types": "8.60.1", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/acorn": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", - "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", - "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", - "dev": true, - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", - "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "slice-ansi": "^8.0.0", - "string-width": "^8.2.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cliui": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", - "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { "node": ">=20" @@ -1146,35 +872,15 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, "node_modules/commitlint": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/commitlint/-/commitlint-21.1.0.tgz", - "integrity": "sha512-zhOptGgfRqtw+uEPYENa3Uaz5fe94SJ4sKf4yh6ODGr8LZin0aOxTIwiyyDaTP2xp3EQ6JInZMspGXPRfjaFsg==", + "version": "21.2.2", + "resolved": "https://registry.npmjs.org/commitlint/-/commitlint-21.2.2.tgz", + "integrity": "sha512-Nu6NYufjRe9QPvFssAE7JjeAzrTpVWlYYNC1alXGj4UjmQiT+8Lt/XiWq///JSuI2QIzQ4oTl4+H/Z6rteM+kg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/cli": "^21.1.0", - "@commitlint/types": "^21.1.0" + "@commitlint/cli": "^21.2.2", + "@commitlint/types": "^21.2.0" }, "bin": { "commitlint": "cli.js" @@ -1183,65 +889,47 @@ "node": ">=22.12.0" } }, - "node_modules/compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-ify": "^1.0.0", - "dot-prop": "^5.1.0" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, "node_modules/conventional-changelog-angular": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.3.1.tgz", - "integrity": "sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-9.4.0.tgz", + "integrity": "sha512-HdxRxuS8bBXVIuo4V82gvSwAXT0vYQUizrjs/izmPg5JdDstr8v8I5hduGL3iQbG+o310dUDxC4+LetuS5hu9w==", "dev": true, "license": "ISC", "dependencies": { - "compare-func": "^2.0.0" + "@conventional-changelog/template": "^1.4.0" }, "engines": { - "node": ">=18" + "node": ">=22" } }, "node_modules/conventional-changelog-conventionalcommits": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.3.1.tgz", - "integrity": "sha512-dTYtpIacRpcZgrvBYvBfArMmK2xvIpv2TaxM0/ZI5CBtNUzvF2x0t15HsbRABWprS6UPmvj+PzHVjSx4qAVKyw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-10.4.0.tgz", + "integrity": "sha512-Rriac6ZrAlVm6cy9Bz4NSp+WMHpwNXoPIYex+HjCgduAVUSbnew29DQjQw0C4g9u3HtSYzGiGY+pdBXAZo+4aA==", "dev": true, "license": "ISC", "dependencies": { - "compare-func": "^2.0.0" + "@conventional-changelog/template": "^1.4.0" }, "engines": { - "node": ">=18" + "node": ">=22" } }, "node_modules/conventional-commits-parser": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.4.0.tgz", - "integrity": "sha512-tvRg7FIBNlyPzjdG8wWRlPHQJJHI7DylhtRGeU9Lq+JuoPh5BKpPRX83ZdLrvXuOSu5Eo/e7SzOQhU4Hd2Miuw==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-7.1.2.tgz", + "integrity": "sha512-O+x4N2yH+ijvqWlIyTHsXTAP+algNWgGbjY2duCe8w2vUMvUB95cLRslCPfTMQyLAKlet3bhZTdu6ozn4M+QJQ==", "dev": true, "license": "MIT", "dependencies": { - "@simple-libs/stream-utils": "^1.2.0", - "meow": "^13.0.0" + "@simple-libs/stream-utils": "^2.0.0", + "argue-cli": "^3.1.0" }, "bin": { "conventional-commits-parser": "dist/cli/index.js" }, "engines": { - "node": ">=18" + "node": ">=22" } }, "node_modules/cosmiconfig": { @@ -1329,19 +1017,6 @@ "dev": true, "license": "MIT" }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/emoji-regex": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", @@ -1359,19 +1034,6 @@ "node": ">=6" } }, - "node_modules/environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", @@ -1383,14 +1045,16 @@ } }, "node_modules/es-toolkit": { - "version": "1.48.1", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.48.1.tgz", - "integrity": "sha512-wfnXlwd5I75eXRtdD2vuEs50xHHESECDsGD7yiQnfFVNoa5522NwXEbmgo98LfiukSQHs+mBM7/YG3qKJB9/mQ==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.52.0.tgz", + "integrity": "sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA==", "dev": true, "license": "MIT", "workspaces": [ "docs", - "benchmarks" + "benchmarks", + "tests/types", + "tests/browser-compat" ] }, "node_modules/escalade": { @@ -1417,44 +1081,43 @@ } }, "node_modules/eslint": { - "version": "9.39.5", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", - "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.10.0.tgz", + "integrity": "sha512-NPXn6r5zl4uET1DAVPaOwzX3rut4c0wcmw3dWJAfOsTM5+TogXo0DDjz8pwm/hL8cyVNpHqeK4JpN0NjnyFFNw==", "dev": true, "license": "MIT", + "workspaces": [ + "packages/*" + ], "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.2", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.6", - "@eslint/js": "9.39.5", - "@eslint/plugin-kit": "^0.4.1", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.7.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", - "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", + "file-entry-cache": "11.1.5 || >11.1.6 <12", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.5", + "minimatch": "^10.2.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -1462,7 +1125,7 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://eslint.org/donate" @@ -1477,48 +1140,74 @@ } }, "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.15.0", + "acorn": "^8.16.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" + "eslint-visitor-keys": "^5.0.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" @@ -1570,13 +1259,6 @@ "node": ">=0.10.0" } }, - "node_modules/eventemitter3": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "dev": true, - "license": "MIT" - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1599,9 +1281,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", - "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", + "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", "dev": true, "funding": [ { @@ -1634,16 +1316,13 @@ } }, "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz", + "integrity": "sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" + "flat-cache": "^6.1.23" } }, "node_modules/find-up": { @@ -1664,23 +1343,21 @@ } }, "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "version": "6.1.23", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz", + "integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==", "dev": true, "license": "MIT", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" + "cacheable": "^2.5.0", + "flatted": "^3.4.2", + "hookified": "^1.15.0" } }, "node_modules/flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", "dev": true, "license": "ISC" }, @@ -1707,23 +1384,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/git-raw-commits": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-5.0.1.tgz", - "integrity": "sha512-Y+csSm2GD/PCSh6Isd/WiMjNAydu0VBiG9J7EdQsNA5P9uXvLayqjmTsNlK5Gs9IhblFZqOU0yid5Il5JPoLiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@conventional-changelog/git-client": "^2.6.0", - "meow": "^13.0.0" - }, - "bin": { - "git-raw-commits": "src/cli.js" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -1753,28 +1413,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "node_modules/hashery": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz", + "integrity": "sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=18" + "dependencies": { + "hookified": "^1.15.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=20" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/hookified": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz", + "integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, "node_modules/husky": { "version": "9.1.7", @@ -1819,6 +1476,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -1856,22 +1523,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -1885,16 +1536,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -1933,9 +1574,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "dev": true, "funding": [ { @@ -1955,13 +1596,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -1970,9 +1604,9 @@ "license": "MIT" }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, "license": "MIT" }, @@ -1984,13 +1618,13 @@ "license": "MIT" }, "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", "dev": true, "license": "MIT", "dependencies": { - "json-buffer": "3.0.1" + "@keyv/serialize": "^1.1.1" } }, "node_modules/levn": { @@ -2015,16 +1649,15 @@ "license": "MIT" }, "node_modules/lint-staged": { - "version": "17.0.7", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-17.0.7.tgz", - "integrity": "sha512-JrSobt+tW3rH8IOMi8tDZd3foorM5yPEkLD/V2NxobgHrFfHWGee4MOLVuZeScgxftEwbHrPHIFA/ZL+nUJeuA==", + "version": "17.4.1", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-17.4.1.tgz", + "integrity": "sha512-FmJeudcalbSfg1du+JCfvi5vS6Qt08KgbfLWiHinbef+2JJwUZwAWVoaO1AcJVUTWPfk0t30PMQNwPAeCzYQ+Q==", "dev": true, "license": "MIT", "dependencies": { - "listr2": "^10.2.1", - "picomatch": "^4.0.4", + "picomatch": "^4.0.7", "string-argv": "^0.3.2", - "tinyexec": "^1.2.4" + "tinyexec": "^1.3.0" }, "bin": { "lint-staged": "bin/lint-staged.js" @@ -2039,23 +1672,6 @@ "yaml": "^2.9.0" } }, - "node_modules/listr2": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-10.2.1.tgz", - "integrity": "sha512-7I5knELsJKTUjXG+A6BkKAiGkW1i25fNa/xlUl9hFtk15WbE9jndA89xu5FzQKrY5llajE1hfZZFMILXkDHk/Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "cli-truncate": "^5.2.0", - "eventemitter3": "^5.0.4", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^10.0.0" - }, - "engines": { - "node": ">=22.13.0" - } - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -2072,136 +1688,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/log-update": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", - "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^7.0.0", - "cli-cursor": "^5.0.0", - "slice-ansi": "^7.1.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", - "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" + "brace-expansion": "^5.0.8" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/meow": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", - "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" + "node": "18 || 20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/ms": { @@ -2218,22 +1718,6 @@ "dev": true, "license": "MIT" }, - "node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -2344,9 +1828,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -2376,6 +1860,26 @@ "node": ">=6" } }, + "node_modules/qified": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/qified/-/qified-0.10.1.tgz", + "integrity": "sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hookified": "^2.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/qified/node_modules/hookified": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-2.2.0.tgz", + "integrity": "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==", + "dev": true, + "license": "MIT" + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -2387,43 +1891,19 @@ } }, "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "license": "MIT", - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" - }, "node_modules/semver": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.2.tgz", - "integrity": "sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, "license": "ISC", "bin": { @@ -2456,49 +1936,6 @@ "node": ">=8" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/slice-ansi": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", - "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.3", - "is-fullwidth-code-point": "^5.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/string-argv": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", @@ -2509,23 +1946,6 @@ "node": ">=0.6.19" } }, - "node_modules/string-width": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", - "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.5.0", - "strip-ansi": "^7.1.2" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/strip-ansi": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", @@ -2542,36 +1962,10 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/tinyexec": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", - "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", "dev": true, "license": "MIT", "engines": { @@ -2622,9 +2016,9 @@ } }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -2636,16 +2030,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.1.tgz", - "integrity": "sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==", + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.69.0.tgz", + "integrity": "sha512-B3MltX0VqjUBNEe3b3sSuiRbfa6XrfHFtBiPamjT5AsW/dfq+y+bc0wyuS9DxAS1LyzCxRp2+rxzpLUvqM2BvA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.60.1", - "@typescript-eslint/parser": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1", - "@typescript-eslint/utils": "8.60.1" + "@typescript-eslint/eslint-plugin": "8.69.0", + "@typescript-eslint/parser": "8.69.0", + "@typescript-eslint/typescript-estree": "8.69.0", + "@typescript-eslint/utils": "8.69.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2659,6 +2053,186 @@ "typescript": ">=4.8.4 <6.1.0" } }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.69.0.tgz", + "integrity": "sha512-t5jQTKPIgVW1PE6dR6H6Qz5gm8zjMlX5/2gRaOGd9eO6V7J+tQc6iWKukEe7dY8u9HyYasQ0yfF0/FSSTEO2gA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.69.0", + "@typescript-eslint/type-utils": "8.69.0", + "@typescript-eslint/utils": "8.69.0", + "@typescript-eslint/visitor-keys": "8.69.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.69.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.69.0.tgz", + "integrity": "sha512-ZfoJAVg3JZndQEpEl9petVlxau3lRuElc4HRMuAlLCf8to04/iHz692RUSNmXKDjEuJmIL+KZ2/BsOcBc16dsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/typescript-estree": "8.69.0", + "@typescript-eslint/utils": "8.69.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.69.0.tgz", + "integrity": "sha512-l4b0DhWioGg6Gt2ebGlvfkFMOjRsauxtsnDRwUSRX1qHq3HdTfQHV8wW9zEXeciai6HfeaKOedQn2Zoofx3WBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.69.0", + "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/typescript-estree": "8.69.0", + "@typescript-eslint/visitor-keys": "8.69.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.69.0.tgz", + "integrity": "sha512-AdFkgqck3Vudb/kWnxlyafU/4aBhHrbQ9locP2N4psXTy5mOBg0SHJumnLvx7r6g1gV4DKvUFwV2nJZBoqOD8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.69.0", + "@typescript-eslint/tsconfig-utils": "8.69.0", + "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/visitor-keys": "8.69.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.69.0.tgz", + "integrity": "sha512-yi4obFrHMmnsesWehHbkg9zMA7Jt8cXT+mKM08G999pH1yT6nqgsHx7MYm0uY1wAj8CqiBXYRJ7WAT0QdQHQXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.69.0", + "@typescript-eslint/types": "^8.69.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.69.0.tgz", + "integrity": "sha512-xNqK7YTDZsLniQMV/4rpFR8Z5JlqeRvVjuG1YgF/mdPVH84HSD19L8CczMA0qg2RfwEV231GHH3VnToJDo4MfQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "8.69.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.69.0.tgz", + "integrity": "sha512-tUbx60BBqQa31kXF5MCsOOLL5E/WzUuxIn7YpAvq+eaUlqvk8/NXnXMBNAdLCr0icjkzem7iUA5QqWHe/hJ1aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.69.0", + "@typescript-eslint/types": "8.69.0", + "@typescript-eslint/typescript-estree": "8.69.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/ignore": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.8.tgz", + "integrity": "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/undici-types": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", @@ -2703,37 +2277,6 @@ "node": ">=0.10.0" } }, - "node_modules/wrap-ansi": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-10.0.0.tgz", - "integrity": "sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.3", - "string-width": "^8.2.0", - "strip-ansi": "^7.1.2" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 8efc86aa0..3938a0c0b 100644 --- a/package.json +++ b/package.json @@ -9,22 +9,23 @@ "lint": "eslint", "lint:fix": "eslint --fix", "prepare": "husky", - "test:ci": "bash scripts/ci-local.sh" + "test:ci": "bash scripts/ci-local.sh", + "update": "python3 scripts/update_deps.py" }, "lint-staged": { "*.{js,jsx,mjs,cjs,ts,tsx}": "eslint --fix", "*.py": "python3 -m ruff check --fix" }, "devDependencies": { - "@commitlint/cli": "^21.0.2", - "@commitlint/config-conventional": "^21.0.2", - "@eslint/js": "^9.0.0", - "commitlint": "^21.1.0", - "eslint": "^9.0.0", - "husky": "^9.1.0", - "lint-staged": "^17.0.7", - "typescript": "^5.4.0", - "typescript-eslint": "^8.0.0" + "@commitlint/cli": "^21.2.2", + "@commitlint/config-conventional": "^21.2.2", + "@eslint/js": "^10.0.1", + "commitlint": "^21.2.2", + "eslint": "^10.10.0", + "husky": "^9.1.7", + "lint-staged": "^17.4.1", + "typescript": "^6.0.3", + "typescript-eslint": "^8.69.0" }, "engines": { "node": ">=22" diff --git a/scripts/update_deps.py b/scripts/update_deps.py new file mode 100755 index 000000000..06c1d0b00 --- /dev/null +++ b/scripts/update_deps.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +"""update_deps.py — recursively update every real package.json in the repo. + +Runs `npx npm-check-updates -u --peer` + `npm install` in the directory of every +package.json found under the repo root, skipping node_modules and eval/test +fixture trees (evals/, tests/, any `fixtures` directory). Those fixtures are +fixed test data, not live dependencies — bumping them would change what a +benchmark or content-guard test measures, not just its tooling. + +The root package.json's `update` script shells out to this so a single +`npm run update` keeps every real Node project in the repo current, not just +the root. + +Usage: + python3 scripts/update_deps.py [--dry-run] +""" + +import argparse +import subprocess +import sys +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parent.parent +EXCLUDED_DIR_NAMES = {"node_modules", "evals", "tests", "fixtures"} + + +def find_package_json_dirs() -> list[Path]: + dirs = [] + for path in sorted(REPO_ROOT.rglob("package.json")): + rel_parts = path.relative_to(REPO_ROOT).parts + if EXCLUDED_DIR_NAMES.intersection(rel_parts): + continue + dirs.append(path.parent) + return dirs + + +def update_one(directory: Path, dry_run: bool) -> bool: + label = directory.relative_to(REPO_ROOT) + print(f"==> {label if label != Path('.') else '.'}") + if dry_run: + return True + # --peer: without it, ncu bumps typescript past typescript-eslint's peer + # ceiling (<6.1.0) every run, so it never stays pinned. + ncu = subprocess.run(["npx", "npm-check-updates", "-u", "--peer"], cwd=directory, check=False) + if ncu.returncode != 0: + return False + install = subprocess.run(["npm", "install"], cwd=directory, check=False) + return install.returncode == 0 + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--dry-run", action="store_true", help="List target directories without updating" + ) + args = parser.parse_args() + + targets = find_package_json_dirs() + if not targets: + print("No package.json files found outside excluded directories.") + return 0 + + failed = [d for d in targets if not update_one(d, args.dry_run)] + + if failed: + print("\nFailed to update:", file=sys.stderr) + for directory in failed: + print(f" {directory.relative_to(REPO_ROOT)}", file=sys.stderr) + return 1 + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From 5d73b3ff672d4e3a57de1b4238d3b32d23e81a60 Mon Sep 17 00:00:00 2001 From: Bryan Finster Date: Fri, 4 Sep 2026 10:48:20 -0500 Subject: [PATCH 3/3] chore: update deps --- plugins/dev-team/CLAUDE.md | 2 +- plugins/security-assessment/CLAUDE.md | 8 + scripts/update_deps.py | 64 ++++++-- tests/scripts/test_update_deps.py | 225 ++++++++++++++++++++++++++ 4 files changed, 284 insertions(+), 15 deletions(-) create mode 100644 tests/scripts/test_update_deps.py diff --git a/plugins/dev-team/CLAUDE.md b/plugins/dev-team/CLAUDE.md index cd042b107..b15dced7e 100644 --- a/plugins/dev-team/CLAUDE.md +++ b/plugins/dev-team/CLAUDE.md @@ -26,7 +26,7 @@ Every change must reduce friction: **fewer missteps, less rework, lower token co 1. **Selective Agent Loading**: load only necessary agents; target < 10,000 tokens for simple tasks. 2. **Context Ceiling**: `min(40% of window, 350K)` — see [Context Management](docs/context-management.md); enforced by `hooks/context_ceiling_guard.py`. -3. **Persona-Driven Behavior**: specs in `.claude/agents/`. Build concurrency via `DEV_TEAM_MAX_PARALLEL_BUILDS`: unset → sequential (`1`); set `--jobs`/env to opt into fan-out, capped by wave width. +3. **Persona-Driven Behavior**: specs in `.claude/agents/`. Build concurrency via `DEV_TEAM_MAX_PARALLEL_BUILDS`: unset → `1` (sequential); set `--jobs`/env to opt into fan-out, capped by wave width. 4. **Human-in-the-Loop**: autonomous agents, human oversight. 5. **Dynamic Configuration**: config changes → `.claude/metrics/config-changelog.jsonl`. 6. **ATDD + Code-First Small Batches** (sole build cadence — Rec 3, docs/experiments/RECOMMENDATIONS.md): no code without a `/plan` scenario. diff --git a/plugins/security-assessment/CLAUDE.md b/plugins/security-assessment/CLAUDE.md index b429b8bf1..e4a2d3c23 100644 --- a/plugins/security-assessment/CLAUDE.md +++ b/plugins/security-assessment/CLAUDE.md @@ -105,6 +105,14 @@ See `install.sh`. It performs four checks: - `compliance-mapping` — pattern-table first with LLM edge annotation - `security-assessment-pipeline` — declarative phase graph for `/security-assessment` +**Commands** (5): + +- `/security-assessment ` — full static-analysis pipeline +- `/cross-repo-analysis ` — cross-repo attack-chain analysis +- `/redteam-model ` — adversarial ML red-team +- `/export-pdf ` — PDF export +- `/upgrade` — plugin update + auto-update opt-in + **Hooks** (3): - `PreToolUse:Bash` → `redteam-guard.sh` (blocks direct orchestrator invocation) diff --git a/scripts/update_deps.py b/scripts/update_deps.py index 06c1d0b00..af94df007 100755 --- a/scripts/update_deps.py +++ b/scripts/update_deps.py @@ -1,11 +1,15 @@ #!/usr/bin/env python3 -"""update_deps.py — recursively update every real package.json in the repo. - -Runs `npx npm-check-updates -u --peer` + `npm install` in the directory of every -package.json found under the repo root, skipping node_modules and eval/test -fixture trees (evals/, tests/, any `fixtures` directory). Those fixtures are -fixed test data, not live dependencies — bumping them would change what a -benchmark or content-guard test measures, not just its tooling. +"""update_deps.py — recursively update package.json files outside excluded trees. + +Runs a pinned `npx npm-check-updates@ -u --peer --cooldown 3d` + +`npm install` in the directory of every package.json found under the repo +root, skipping +node_modules (any depth) and fixture trees (any depth) plus everything under +top-level evals/ and tests/. Those fixtures are fixed test data, not live +dependencies — bumping them would change what a benchmark or content-guard +test measures, not just its tooling. Only the root package.json is a live +target today; the walk exists so a second real Node project is picked up +automatically if one is ever added outside those excluded trees. The root package.json's `update` script shells out to this so a single `npm run update` keeps every real Node project in the repo current, not just @@ -21,31 +25,63 @@ from pathlib import Path REPO_ROOT = Path(__file__).resolve().parent.parent -EXCLUDED_DIR_NAMES = {"node_modules", "evals", "tests", "fixtures"} + +# evals/ and tests/ are only excluded as a top-level segment — a real Node +# project nested under some other tree happens to be named "tests" should +# still be updated. node_modules and fixtures are excluded at any depth. +TOP_LEVEL_EXCLUDED_DIRS = {"evals", "tests"} +ANY_DEPTH_EXCLUDED_DIRS = {"node_modules", "fixtures"} + +SUBPROCESS_TIMEOUT_SECONDS = 600 # npm install can be slow; still needs a ceiling + +# Pinned so `npx` never floats to whatever the registry serves that day — +# bump deliberately, as its own reviewed edit. Not a devDependency: ncu would +# then propose updating itself past this environment's node engine ceiling +# on every run, and --peer only checks OTHER packages' peer constraints, not +# a package's own "engines" field. +NCU_VERSION = "22.2.9" def find_package_json_dirs() -> list[Path]: dirs = [] for path in sorted(REPO_ROOT.rglob("package.json")): rel_parts = path.relative_to(REPO_ROOT).parts - if EXCLUDED_DIR_NAMES.intersection(rel_parts): + if rel_parts[0] in TOP_LEVEL_EXCLUDED_DIRS: + continue + if ANY_DEPTH_EXCLUDED_DIRS.intersection(rel_parts): continue dirs.append(path.parent) return dirs +def _run(cmd: list[str], directory: Path) -> bool: + """Run cmd in directory, never raising — a missing binary or a hang both + surface as a plain failure so the caller's failed-directory list and exit + code stay accurate instead of an uncaught exception aborting every + directory after this one.""" + try: + result = subprocess.run( + cmd, cwd=directory, check=False, timeout=SUBPROCESS_TIMEOUT_SECONDS + ) + except (OSError, subprocess.TimeoutExpired) as exc: + print(f" {' '.join(cmd)} failed: {exc}", file=sys.stderr) + return False + return result.returncode == 0 + + def update_one(directory: Path, dry_run: bool) -> bool: label = directory.relative_to(REPO_ROOT) print(f"==> {label if label != Path('.') else '.'}") if dry_run: return True # --peer: without it, ncu bumps typescript past typescript-eslint's peer - # ceiling (<6.1.0) every run, so it never stays pinned. - ncu = subprocess.run(["npx", "npm-check-updates", "-u", "--peer"], cwd=directory, check=False) - if ncu.returncode != 0: + # ceiling (<6.1.0, per its published peerDependencies) every run, so it + # never stays pinned. --cooldown: skip versions published too recently to + # have seen any real-world scrutiny. + ncu_cmd = ["npx", "--yes", f"npm-check-updates@{NCU_VERSION}", "-u", "--peer", "--cooldown", "3d"] + if not _run(ncu_cmd, directory): return False - install = subprocess.run(["npm", "install"], cwd=directory, check=False) - return install.returncode == 0 + return _run(["npm", "install"], directory) def main() -> int: diff --git a/tests/scripts/test_update_deps.py b/tests/scripts/test_update_deps.py new file mode 100644 index 000000000..2b73775ae --- /dev/null +++ b/tests/scripts/test_update_deps.py @@ -0,0 +1,225 @@ +"""Tests for scripts/update_deps.py — recursive package.json discovery and +per-directory `npx npm-check-updates` + `npm install` runner. + +find_package_json_dirs' exclusion logic is the risky part: node_modules/ +fixtures are excluded at any depth, but evals/tests are anchored to the +top-level segment only (a real Node project nested under some other tree +that happens to be named "tests" must still be updated). The tests below +exercise both the anchored and depth-agnostic sides, plus the exact-segment +(not substring) matching that makes "testservice" distinct from "tests". + +_run must never raise — a missing npx/npm binary or a hang both have to +surface as a plain False so main()'s failed-directory list and exit code +stay accurate, rather than an uncaught exception aborting every directory +after the one that failed. +""" + +from __future__ import annotations + +import subprocess +import sys + +import pytest + +from _repo_root import REPO_ROOT + +sys.path.insert(0, str(REPO_ROOT / "scripts")) + +import update_deps + + +@pytest.fixture +def repo_root(tmp_path, monkeypatch): + monkeypatch.setattr(update_deps, "REPO_ROOT", tmp_path) + return tmp_path + + +def _touch_package_json(directory) -> None: + directory.mkdir(parents=True, exist_ok=True) + (directory / "package.json").write_text("{}\n", encoding="utf-8") + + +# --------------------------------------------------------------------------- +# find_package_json_dirs +# --------------------------------------------------------------------------- + + +def test_root_level_package_json_is_included(repo_root): + _touch_package_json(repo_root) + assert update_deps.find_package_json_dirs() == [repo_root] + + +def test_no_package_json_anywhere_returns_empty_list(repo_root): + assert update_deps.find_package_json_dirs() == [] + + +def test_node_modules_excluded_at_any_depth(repo_root): + _touch_package_json(repo_root) + _touch_package_json(repo_root / "node_modules" / "some-dep") + _touch_package_json(repo_root / "packages" / "app" / "node_modules" / "nested-dep") + assert update_deps.find_package_json_dirs() == [repo_root] + + +def test_fixtures_excluded_at_any_depth(repo_root): + _touch_package_json(repo_root) + _touch_package_json(repo_root / "plugins" / "x" / "fixtures" / "sample") + assert update_deps.find_package_json_dirs() == [repo_root] + + +def test_top_level_evals_and_tests_excluded(repo_root): + _touch_package_json(repo_root) + _touch_package_json(repo_root / "evals" / "some-benchmark") + _touch_package_json(repo_root / "tests" / "some-fixture") + assert update_deps.find_package_json_dirs() == [repo_root] + + +def test_tests_dir_not_anchored_at_top_level_is_not_excluded(repo_root): + """A real Node project nested under some other tree, merely named + "tests", is not an eval/test fixture and must still be updated — only + a TOP-LEVEL evals/tests segment is excluded.""" + nested = repo_root / "packages" / "app" / "tests" + _touch_package_json(nested) + assert update_deps.find_package_json_dirs() == [nested] + + +def test_exact_segment_match_not_substring(repo_root): + """"testservice" and "my-fixtures-lib" must not be excluded merely for + containing "tests"/"fixtures" as a substring — exclusion is by exact + path-segment name.""" + testservice = repo_root / "testservice" + fixtures_lib = repo_root / "my-fixtures-lib" + _touch_package_json(testservice) + _touch_package_json(fixtures_lib) + assert update_deps.find_package_json_dirs() == sorted([testservice, fixtures_lib]) + + +def test_results_are_sorted(repo_root): + b_dir = repo_root / "packages" / "b" + a_dir = repo_root / "packages" / "a" + _touch_package_json(b_dir) + _touch_package_json(a_dir) + assert update_deps.find_package_json_dirs() == [a_dir, b_dir] + + +# --------------------------------------------------------------------------- +# _run — never raises +# --------------------------------------------------------------------------- + + +def test_run_returns_true_on_success(tmp_path, monkeypatch): + monkeypatch.setattr( + subprocess, "run", lambda *a, **k: subprocess.CompletedProcess([], returncode=0) + ) + assert update_deps._run(["true"], tmp_path) is True + + +def test_run_returns_false_on_nonzero_exit(tmp_path, monkeypatch): + monkeypatch.setattr( + subprocess, "run", lambda *a, **k: subprocess.CompletedProcess([], returncode=1) + ) + assert update_deps._run(["false"], tmp_path) is False + + +def test_run_returns_false_on_missing_binary(tmp_path, monkeypatch): + def _raise(*args, **kwargs): + raise FileNotFoundError("no such file or directory: npx") + + monkeypatch.setattr(subprocess, "run", _raise) + assert update_deps._run(["npx", "whatever"], tmp_path) is False + + +def test_run_returns_false_on_timeout(tmp_path, monkeypatch): + def _raise(*args, **kwargs): + raise subprocess.TimeoutExpired(cmd=["npm", "install"], timeout=600) + + monkeypatch.setattr(subprocess, "run", _raise) + assert update_deps._run(["npm", "install"], tmp_path) is False + + +# --------------------------------------------------------------------------- +# update_one +# --------------------------------------------------------------------------- + + +def test_update_one_dry_run_never_invokes_subprocess(tmp_path, monkeypatch): + monkeypatch.setattr(update_deps, "REPO_ROOT", tmp_path) + calls = [] + monkeypatch.setattr(subprocess, "run", lambda *a, **k: calls.append(a)) + assert update_deps.update_one(tmp_path, dry_run=True) is True + assert calls == [] + + +def test_update_one_skips_install_when_ncu_fails(tmp_path, monkeypatch): + monkeypatch.setattr(update_deps, "REPO_ROOT", tmp_path) + commands_run = [] + + def _fake_run(cmd, **kwargs): + commands_run.append(cmd) + is_ncu = "npm-check-updates" in cmd[2] if len(cmd) > 2 else False + return subprocess.CompletedProcess(cmd, returncode=1 if is_ncu else 0) + + monkeypatch.setattr(subprocess, "run", _fake_run) + assert update_deps.update_one(tmp_path, dry_run=False) is False + assert len(commands_run) == 1 # npm install never ran + + +def test_update_one_true_when_both_succeed(tmp_path, monkeypatch): + monkeypatch.setattr(update_deps, "REPO_ROOT", tmp_path) + monkeypatch.setattr( + subprocess, "run", lambda *a, **k: subprocess.CompletedProcess([], returncode=0) + ) + assert update_deps.update_one(tmp_path, dry_run=False) is True + + +def test_update_one_false_when_install_fails_after_ncu_succeeds(tmp_path, monkeypatch): + monkeypatch.setattr(update_deps, "REPO_ROOT", tmp_path) + + def _fake_run(cmd, **kwargs): + is_install = cmd[:2] == ["npm", "install"] + return subprocess.CompletedProcess(cmd, returncode=1 if is_install else 0) + + monkeypatch.setattr(subprocess, "run", _fake_run) + assert update_deps.update_one(tmp_path, dry_run=False) is False + + +# --------------------------------------------------------------------------- +# main +# --------------------------------------------------------------------------- + + +def test_main_reports_no_targets(repo_root, monkeypatch, capsys): + monkeypatch.setattr(sys, "argv", ["update_deps.py"]) + assert update_deps.main() == 0 + assert "No package.json files found" in capsys.readouterr().out + + +def test_main_dry_run_never_invokes_subprocess(repo_root, monkeypatch): + _touch_package_json(repo_root) + calls = [] + monkeypatch.setattr(subprocess, "run", lambda *a, **k: calls.append(a)) + monkeypatch.setattr(sys, "argv", ["update_deps.py", "--dry-run"]) + assert update_deps.main() == 0 + assert calls == [] + + +def test_main_aggregates_failures_and_exits_nonzero(repo_root, monkeypatch, capsys): + _touch_package_json(repo_root / "a") + _touch_package_json(repo_root / "b") + monkeypatch.setattr( + subprocess, "run", lambda *a, **k: subprocess.CompletedProcess([], returncode=1) + ) + monkeypatch.setattr(sys, "argv", ["update_deps.py"]) + exit_code = update_deps.main() + assert exit_code == 1 + err = capsys.readouterr().err + assert "Failed to update:" in err + assert "a" in err and "b" in err + + +def test_main_exit_zero_when_all_succeed(repo_root, monkeypatch): + _touch_package_json(repo_root) + monkeypatch.setattr( + subprocess, "run", lambda *a, **k: subprocess.CompletedProcess([], returncode=0) + ) + monkeypatch.setattr(sys, "argv", ["update_deps.py"]) + assert update_deps.main() == 0