test(P01): harness wiring — coverage, timeouts, markers, turbo pipeline, leak fixes (REQ-7-001)

- pytest-cov + [tool.coverage] config (95% branch, term-missing every run); c8
  wired around tsx --test in web (95.9%) + cli (76.9%) — no runner swap (D-052)
- markers fast/real_server/userns under --strict-markers (D-053); real_server ×5
  uvicorn suites + userns ×2 files + 1 test (test_manager real-unshare catch);
  test_sandbox_agent unmarked per G-105 (plain stdlib process), outlier timeout(120)
- pytest-timeout signal method: 60s global, 180s via conftest collection hook for
  marked tiers; BOTH tiers probe-proven (60.07s / 180.07s)
- FAST=1 fast subset: 621 passed, 49 deselected, 55.4s bare (MH-M2 <60s holds);
  FAST implies NO_COV per verifier GAP-1 fix
- CLI fresh-clone E2E env-gated (CLI_E2E=1, D-055): visible skip, opt-in green
  (902s aggregate step budget); path-invocation silent return → visible skip
- web#test turbo task + root test/web:test/web:test:cov/cli:test:cov/cli:test:e2e/
  ai:test:fast scripts; pnpm test runs 3/3 workspaces (3m)
- leak fixes: AI_PROVIDER via monkeypatch (probe-proven restore),
  seed_verified_identity check-first + IntegrityError-only, test_engine.py:428
  Path.read_text (P3 item done early)
- PLAN.md count discipline: baseline 670/53/64 (671→670 collection fact; 61→64
  v0.5.7 hotfix tests); Task 1-1-04 no-split decision recorded (6.8s combined)

---ci---
phase: 1
milestone: v0.7
status: execute
---/ci---
This commit is contained in:
CIAgent
2026-09-26 17:40:05 +00:00
parent 9692712e63
commit 02d324b896
23 changed files with 663 additions and 78 deletions
+4 -4
View File
@@ -1,9 +1,9 @@
{
"phase": 0,
"stage": "complete",
"phase": 1,
"stage": "verify",
"milestone": "v0.7",
"milestone_name": "test-harness-review",
"phase_role": "pre_execution",
"phase_role": "execution",
"attempts": 0,
"updated_at": "2026-09-26T16:00:00Z"
"updated_at": "2026-09-26T16:40:00Z"
}
+11 -9
View File
@@ -23,13 +23,15 @@
**Environment facts (unchanged):** python 3.11.2 (venv at apps/ai-service/.venv, pip-only — A-009), node v24.15.0, pnpm 12.3.4, SQLite shared `Settings().db_path` (`~/.nextcraft/data/nextcraft.db`), tests NEVER call the cloud (mock providers + httpx MockTransport), secrets env-only (D-014), runtime state under `~/.nextcraft/` (D-039).
**Baseline (probe-verified census, 2026-09-26):** 785 tests all green — pytest 671 (64 files), web node:test 53 (7 files), CLI node:test 61 (11 files). Zero coverage tooling. Zero framework timeouts (ad-hoc 20-30s polling deadlines + a 600s CLI bootstrap step). Zero markers despite a real three-tier split (fast-unit / real-uvicorn / real-userns). Web tests OUTSIDE the turbo pipeline. 1,716 warnings per pytest run. 81 inert `# noqa`, 5 orphaned eslint-disable comments, no ESLint at all (turbo lint is a no-op for 5 of 6 packages), 27 inert `# type: ignore`, no Python type checker, recharts@2.15.4 deprecated direct dep, version drift (hardcoded `FastAPI(version="0.3.0")` vs pyproject "0.2.0" vs shipped line).
**Baseline (probe-verified census, 2026-09-26, counts re-verified at P1 execution):** 785 tests all green — pytest 670 (64 files; census counted 671 — collection at P1 execution says 670, the correct number), web node:test 53 (7 files), CLI node:test 64 (11 files; census counted 61 — the v0.5.7 hotfix `cda6ab1` landed 3 deploy-stale-checkout tests on census day, after the count was taken). Zero coverage tooling. Zero framework timeouts (ad-hoc 20-30s polling deadlines + a 600s CLI bootstrap step). Zero markers despite a real three-tier split (fast-unit / real-uvicorn / real-userns). Web tests OUTSIDE the turbo pipeline. 1,716 warnings per pytest run. 81 inert `# noqa`, 5 orphaned eslint-disable comments, no ESLint at all (turbo lint is a no-op for 5 of 6 packages), 27 inert `# type: ignore`, no Python type checker, recharts@2.15.4 deprecated direct dep, version drift (hardcoded `FastAPI(version="0.3.0")` vs pyproject "0.2.0" vs shipped line).
**Count discipline (binding, Task 1-2-05):** test counts shift when tests are cut (P2), env-gated (P1), or added; a count is a point-in-time fact. Every phase's ship notes and verification block MUST restate the CURRENT counts, measured at execution — never copy a stale number forward from an earlier phase. Where a count changes, the ship notes state the mechanism (e.g. "CLI 64 = 63 pass + 1 env-gated E2E skip").
**Verification hooks (every phase, release-blocking) — count discipline: each phase's ship MUST restate the current test counts (they shift after P2 cuts); the counts below are the P1 baseline.**
- `pnpm ai:test` — full pytest run (671 at baseline; fast subset via `pnpm ai:test:fast` = `-m "not real_server and not userns"`, seconds-scale)
- `pnpm web:test` — web `tsx --test` (53 at baseline) under c8; inside the turbo pipeline (`pnpm test` runs all three workspaces)
- `pnpm cli:test` — CLI node:test (61 at baseline, fresh-clone E2E env-gated out); `pnpm cli:test:e2e` = opt-in real 900s path
- `pnpm ai:test` — full pytest run (670 at baseline; fast subset via `pnpm ai:test:fast` = `-m "not real_server and not userns"` = 621 tests, 49 deselected; measured at P1 execution: ~56s fast / ~174s full)
- `pnpm web:test` — web `tsx --test` (53 at baseline); `pnpm web:test:cov` = the same run under c8 (coverage is additive, default `test` script unchanged); inside the turbo pipeline (`pnpm test` runs all three workspaces)
- `pnpm cli:test` — CLI node:test (64 at baseline: 63 pass + 1 visible env-gated E2E skip; census counted 61 pre-v0.5.7-hotfix — the deploy-stale-checkout tests `cda6ab1` landed after the census); `pnpm cli:test:cov` = the same run under c8; `pnpm cli:test:e2e` = opt-in real 900s path
- Coverage reports — pytest-cov report (ai-service) + c8 reporters (web/cli), exposed as script targets
- `pnpm ai:lint` — ruff check (RUF100 joins the select set in P4)
- `pnpm typecheck` — 5 tsc projects; mypy joins via `ai:typecheck` in P5
@@ -47,9 +49,9 @@
### Wave 1-1: coverage + timeout + markers (backend-engineer)
- **Task 1-1-01** (backend-engineer): pytest-cov added to dev deps + `[tool.coverage]` config in `apps/ai-service/pyproject.toml` (source = `ai_service`, sensible branch/report settings); `scripts/test.sh` gains a coverage flag; `pnpm ai:test` produces a coverage report every run. c8 for web/cli around the existing `tsx --test` (D-052 — no runner swap, no vitest): c8 devDep in `apps/web` + `apps/cli`, wired into their test scripts (or a `test:cov` script), reporters configured per workspace.
- **Task 1-1-02** (backend-engineer): markers `fast` / `real_server` / `userns` registered in `[tool.pytest.ini_options]` under `--strict-markers` (D-053). **Unmarked tests default to fast** — zero churn on ~600 unit tests. Mark `real_server` on the real-uvicorn suites: `tests/api/test_e2e_credential_flow.py`, `tests/api/test_telemetry_ingest.py`, `tests/telemetry/test_durability.py`, `tests/sandbox/test_telemetry_wiring.py`, `tests/variants/test_environments.py` (+ any suite the census's definition catches at execution — a real uvicorn/process spin-up). Mark `userns` on the real-namespace suites: `tests/sandbox/test_isolation.py`, `tests/sandbox/test_resource_limits.py`, the sandbox-agent tests (`tests/sandbox/test_sandbox_agent.py`). Canonical fast run = `-m "not real_server and not userns"` aliased as `ai:test:fast` (root script + `scripts/test.sh` flag). **Grill G-105:** marker assignment is verified against each suite's actual mechanism at execution — real_server iff the test spins a real uvicorn/process, userns iff it enters a real unshare namespace. Census correction: `tests/sandbox/test_sandbox_agent.py` requires NO namespace (its docstring: plain stdlib process, in-process threads) — it gets NO tier marker; its 20s-deadline outlier (:542) gets `@pytest.mark.timeout` per D-054's outlier mechanism. P1 records a timing baseline (full-run + fast-subset wall times at the 671/53/61 counts) in the ship notes — measured numbers replace "seconds-scale" claims (MH-M2's <60s stays the ceiling). The hang probe proves BOTH tiers: a fast probe dies at 60s AND a marked probe dies at 180s — the collection-hook override is proven, not assumed.
- **Task 1-1-02** (backend-engineer): markers `fast` / `real_server` / `userns` registered in `[tool.pytest.ini_options]` under `--strict-markers` (D-053). **Unmarked tests default to fast** — zero churn on ~600 unit tests. Mark `real_server` on the real-uvicorn suites: `tests/api/test_e2e_credential_flow.py`, `tests/api/test_telemetry_ingest.py`, `tests/telemetry/test_durability.py`, `tests/sandbox/test_telemetry_wiring.py`, `tests/variants/test_environments.py` (+ any suite the census's definition catches at execution — a real uvicorn/process spin-up). Mark `userns` on the real-namespace suites: `tests/sandbox/test_isolation.py`, `tests/sandbox/test_resource_limits.py`, the sandbox-agent tests (`tests/sandbox/test_sandbox_agent.py`). Canonical fast run = `-m "not real_server and not userns"` aliased as `ai:test:fast` (root script + `scripts/test.sh` flag). **Grill G-105:** marker assignment is verified against each suite's actual mechanism at execution — real_server iff the test spins a real uvicorn/process, userns iff it enters a real unshare namespace. Census correction: `tests/sandbox/test_sandbox_agent.py` requires NO namespace (its docstring: plain stdlib process, in-process threads) — it gets NO tier marker; its 20s-deadline outlier (:542) gets `@pytest.mark.timeout` per D-054's outlier mechanism. P1 records a timing baseline (full-run + fast-subset wall times at the 670/53/64 counts) in the ship notes — measured numbers replace "seconds-scale" claims (MH-M2's <60s stays the ceiling). The hang probe proves BOTH tiers: a fast probe dies at 60s AND a marked probe dies at 180s — the collection-hook override is proven, not assumed.
- **Task 1-1-03** (backend-engineer): pytest-timeout — `signal` method, **60s global** (comfortably above the 20-30s polling loops), **180s override for `real_server`/`userns`-marked tests via a conftest collection hook** (D-054); `@pytest.mark.timeout` available for known outliers. Linux-only target makes SIGALRM safe and accurate; the thread method can't cancel blocked calls.
- **Task 1-1-04** (backend-engineer): CLI integration-suite split — the install-script/daemon/doctor.integration CLI suites join the slow lane the same opt-in way as the E2E (mechanism per execution: env-gate or script file-selection), keeping default `cli:test` fast; the fresh-clone E2E is definitively env-gated (Task 1-2-02).
- **Task 1-1-04** (backend-engineer): CLI integration-suite split — the install-script/daemon/doctor.integration CLI suites join the slow lane the same opt-in way as the E2E (mechanism per execution: env-gate or script file-selection), keeping default `cli:test` fast; the fresh-clone E2E is definitively env-gated (Task 1-2-02). **EXECUTION DECISION (P1):** measured the three suites at 6.8s combined — default `cli:test` totals 7.0s; no split required (recorded per the task's own mechanism clause). The E2E alone is env-gated; the rest stay in the default lane.
### Wave 1-2: turbo/scripts wiring + leak fixes (frontend-engineer + backend-engineer)
@@ -57,9 +59,9 @@
- **Task 1-2-02** (frontend-engineer): CLI fresh-clone E2E env-gated per D-055 — the 600s real bootstrap is KEPT (the real path is the value), excluded from default `cli:test` unless `CLI_E2E=1`, exposed as `cli:test:e2e` with a 900s per-test budget (600 + slack).
- **Task 1-2-03** (backend-engineer): conftest leak fixes — `tests/conftest.py:80` mutates `os.environ["AI_PROVIDER"]` without restore: fix via monkeypatch (or explicit restore in teardown) so no test run leaks provider state into the process env; `seed_verified_identity`'s blanket `except Exception: pass` (conftest.py:74-75) narrowed to the expected idempotency exception type (or logged) — a swallowed seeding failure must never masquerade as a seeded store.
- **Task 1-2-04** (frontend-engineer): path-invocation silent skip fixed — `apps/cli/tests/path-invocation.test.ts:14` returns early (passes silently when the binary is missing): report `t.skip` properly so the skip is visible in the run summary, never a silent green.
- **Task 1-2-05** (lead-developer): PLAN.md verification counts corrected and the count-discipline rule documented — every phase's verification block states the current counts (P1 baseline: 671 py / 53 web / 61 CLI; the census already caught this plan file drifting once — never again).
- **Task 1-2-05** (lead-developer): PLAN.md verification counts corrected and the count-discipline rule documented — every phase's verification block states the current counts (P1 baseline: 670 py / 53 web / 64 CLI; the census already caught this plan file drifting once — never again).
**Verification hooks P1:** all suites green at current counts (671 / 53 / 61); `pnpm ai:test:fast` completes seconds-scale; coverage reports produced in all three workspaces; a deliberately-hanging probe test proves the 60s timeout fires (then removed); `pnpm test` (turbo) runs web+cli+ai; `pnpm typecheck` (5 tsc) + `pnpm ai:lint` + `pnpm build` green. Warnings still present — they die in P3.
**Verification hooks P1:** all suites green at current counts (670 py / 53 web / 64 CLI = 63 pass + 1 visible E2E skip); `pnpm ai:test:fast` completes seconds-scale (measured ~56s); coverage reports produced in all three workspaces; a deliberately-hanging probe test proves the 60s timeout fires (then removed); `pnpm test` (turbo) runs web+cli+ai; `pnpm typecheck` (5 tsc) + `pnpm ai:lint` + `pnpm build` green. Warnings still present — they die in P3.
---
@@ -166,7 +168,7 @@
- **MH-1c**: pytest-timeout `signal` method live — 60s global, 180s for marked suites via the conftest collection hook; proven by a deliberate hang probe (removed after the proof).
- **MH-1d**: CLI fresh-clone E2E env-gated (D-055) — default `cli:test` excludes it; `CLI_E2E=1` + `cli:test:e2e` runs the real 600s bootstrap under a 900s budget.
- **MH-1e**: Web tests inside the turbo pipeline — `web#test` task in turbo.json; root `test` + `web:test` scripts; `pnpm test` runs all three workspaces.
- **MH-1f**: Leak/skip hygiene — `AI_PROVIDER` env mutation restored (no post-run env leak, provable), `seed_verified_identity` swallow narrowed to the expected exception (or logged), path-invocation reports `t.skip` visibly (never a silent green), PLAN.md verification counts corrected (671/53/61 baseline) with the per-phase count-discipline rule in force.
- **MH-1f**: Leak/skip hygiene — `AI_PROVIDER` env mutation restored (no post-run env leak, provable), `seed_verified_identity` swallow narrowed to the expected exception (or logged), path-invocation reports `t.skip` visibly (never a silent green), PLAN.md verification counts corrected (670/53/64 baseline) with the per-phase count-discipline rule in force.
### Phase 2
+1
View File
@@ -44,6 +44,7 @@ yarn-error.log*
# Test coverage
coverage/
.coverage
.nyc_output/
# Python tooling caches
+26
View File
@@ -30,6 +30,8 @@ dependencies = [
dev = [
"pytest>=9.1,<10",
"pytest-asyncio>=1.4,<2",
"pytest-cov>=7.1,<8",
"pytest-timeout>=2.4,<3",
"ruff>=0.14",
]
@@ -39,6 +41,30 @@ include = ["ai_service*"]
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
# P1 harness wiring (D-053/D-054): strict markers + a 60s global timeout.
# `timeout` also ships its own marker (`pytest.mark.timeout`); the 180s
# override for real_server/userns tests is applied by the collection hook
# in tests/conftest.py — marker-level values beat this global default.
markers = [
"fast: in-process unit test (default tier — unmarked tests are fast)",
"real_server: spins a real uvicorn server process",
"userns: enters a real unshare user namespace",
]
addopts = "--strict-markers --timeout=60 --timeout-method=signal"
[tool.coverage.run]
source = ["ai_service"] # tests/ excluded by construction — only the package is measured
branch = true
[tool.coverage.report]
# exclude_also APPENDS to coverage.py's built-ins (which already cover
# `pragma: no cover` and `if TYPE_CHECKING:`); these add the __main__
# entry-point guard (none in ai_service today — future-proof).
exclude_also = [
"if __name__ == [\"']__main__[\"']:",
"if TYPE_CHECKING:",
"pragma: no cover",
]
[tool.ruff]
line-length = 100
+25 -1
View File
@@ -1,5 +1,12 @@
#!/usr/bin/env bash
# Test runner: pytest via venv — mock provider only, zero network calls.
#
# P1 harness wiring (Task 1-1-01/1-1-02):
# default full suite WITH coverage (term + missing lines)
# NO_COV=1 coverage off (bare pytest flags, no --cov args)
# FAST=1 fast subset only: -m "not real_server and not userns"
#
# Extra args pass through: `bash scripts/test.sh tests/api -k foo`.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
APP_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
@@ -11,4 +18,21 @@ if [ ! -x "$VENV/bin/pytest" ]; then
fi
cd "$APP_DIR"
exec "$VENV/bin/pytest" -q "$@"
# Assemble args; pytest arg order: later options win, so user-passed "$@"
# always overrides the wiring below.
ARGS=("-q")
if [ "${FAST:-0}" = "1" ]; then
# Fast subset: exclude the real-server and user-namespace tiers.
# The fast loop is the dev loop — coverage evidence comes from the full run.
ARGS+=("-m" "not real_server and not userns")
NO_COV=1
fi
if [ "${NO_COV:-0}" = "1" ]; then
# Opt-out: bare run, no coverage tooling at all.
ARGS+=()
else
ARGS+=("--cov=ai_service" "--cov-report=term-missing")
fi
exec "$VENV/bin/pytest" "${ARGS[@]}" "$@"
@@ -31,6 +31,11 @@ from ai_service.variants.store import SQLiteVariantStore
from ai_service.voice.defense_store import SQLiteDefenseStore
from tests.sandbox.test_isolation import USERSNS_AVAILABLE
# P1 tier marker (Task 1-1-02): this suite boots a REAL uvicorn server
# (uvicorn.Server + serve loop, below) — real_server tier, 180s timeout
# via the conftest collection hook.
pytestmark = [pytest.mark.real_server]
COACHING_JSON = json.dumps(
{
"summary": "Strong iteration.",
@@ -46,6 +46,12 @@ LEARNER = "learner-9"
TASK = "task-9"
_BASE_TS = datetime(2026, 9, 11, 12, 0, 0, tzinfo=UTC)
# P1 tier marker (Task 1-1-02): the queue-overflow leak-regression test
# boots a REAL uvicorn server (TestClient teardown would hide the leak) —
# real_server tier, 180s timeout via the conftest collection hook.
# The rest of the suite is in-process TestClient-only.
pytestmark = [pytest.mark.real_server]
KNOWN_KINDS = ("command", "file_diff", "run_result", "test_result", "activity")
#: Shared test token — minted into every test URL, verified by the endpoint
+35 -6
View File
@@ -1,6 +1,5 @@
"""Test suite — conftest: mock provider only, zero network (enforced)."""
import os
import shutil
import tempfile
from pathlib import Path
@@ -18,6 +17,21 @@ from ai_service.main import create_app
_HOME_ROOT = Path.home() / ".nextcraft" / "test-sandboxes"
# P1 harness wiring (D-054, Task 1-1-02): real-server and user-namespace
# tests legitimately poll 20-30s under full-suite load (uvicorn boot waits,
# namespace spawn/reap, telemetry round-trips). The 60s global timeout
# would clobber them; this hook widens ONLY the marked items to 180s.
# Marker-level timeouts beat the global default, so the override is
# structural, not config-ordering luck.
_SLOW_TIER_TIMEOUT_S = 180
def pytest_collection_modifyitems(config, items) -> None:
for item in items:
if item.get_closest_marker("real_server") or item.get_closest_marker("userns"):
item.add_marker(pytest.mark.timeout(_SLOW_TIER_TIMEOUT_S))
@pytest.fixture()
def sandbox_dir(tmp_path: Path) -> Path:
"""Per-test sandbox workdir root on a bind-mount-safe filesystem."""
@@ -52,16 +66,27 @@ def seed_verified_identity(store, learner_ids=SUITE_LEARNERS) -> None:
A-304: records carry mock=True — the seed never masquerades as
production verification.
Idempotency is check-first (not exception-swallowed): a learner whose
seed record already exists (shared store) is skipped via get(); the
duplicate-id IntegrityError is the ONLY tolerated failure — any other
exception propagates, so a broken seeding can never masquerade as a
seeded store (P1 Task 1-2-03, MH-1f).
"""
from datetime import UTC, datetime
from sqlalchemy.exc import IntegrityError
from ai_service.identity.store import IdentityRecord
for lid in learner_ids:
seed_id = f"seed-{lid}"
if store.get(seed_id) is not None:
continue # already seeded (shared store)
try:
store.insert(
IdentityRecord(
id=f"seed-{lid}",
id=seed_id,
learner_id=lid,
status="verified",
provider="mock",
@@ -71,13 +96,17 @@ def seed_verified_identity(store, learner_ids=SUITE_LEARNERS) -> None:
verified_at=datetime.now(UTC),
)
)
except Exception:
pass # already seeded (shared store)
except IntegrityError:
# Concurrent seeding won the insert race for this id — the
# record exists, which is all this fixture guarantees.
continue
@pytest.fixture()
def settings(tmp_path: Path) -> Settings:
os.environ["AI_PROVIDER"] = "mock"
def settings(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Settings:
# P1 leak fix (Task 1-2-03, MH-1f): monkeypatch restores AI_PROVIDER on
# teardown — the run never leaks provider state into the process env.
monkeypatch.setenv("AI_PROVIDER", "mock")
# Hermetic stores (v0.3.6): db_path/sandbox_dir default to ~/.nextcraft —
# tests must never read or write real state; pin to the pytest tmp dir.
return Settings(
+1 -1
View File
@@ -425,7 +425,7 @@ class TestBoundary:
import ai_service.grading.engine as engine_mod
code = open(engine_mod.__file__).read()
code = Path(engine_mod.__file__).read_text()
assert "fastapi" not in code
assert "from ..api" not in code and "from ..api." not in code
# the one sanctioned agents import is the module-direct structured defense
@@ -49,6 +49,11 @@ requires_userns = pytest.mark.skipif(
reason="unshare/unprivileged user namespaces unavailable on this host",
)
# P1 tier marker (Task 1-1-02): every test here enters a REAL unshare
# user namespace via backend.spawn — userns tier, 180s timeout via the
# conftest collection hook.
pytestmark = [pytest.mark.userns]
# --- fixtures ------------------------------------------------------------------
@@ -292,6 +292,8 @@ async def test_start_reaps_markerless_and_malformed_workdirs(
@requires_userns
@pytest.mark.userns # P1 (G-105): REAL unshare namespace — the only non-stub
# test in this suite; the rest are in-process StubBackend unit tests.
async def test_real_unshare_backend_create_exec_destroy(tmp_path: Path) -> None:
"""End-to-end on a capable host: create → exec echo → destroy."""
# NOT under /tmp: the in-namespace tmpfs shadows host /tmp, hiding a
@@ -64,6 +64,11 @@ requires_userns = pytest.mark.skipif(
reason="unshare/unprivileged user namespaces unavailable on this host",
)
# P1 tier marker (Task 1-1-02): every test here exercises REAL unshare
# user-namespace sandboxes under rlimits — userns tier, 180s timeout via
# the conftest collection hook.
pytestmark = [pytest.mark.userns]
# Tight limits for these probes — much smaller than production defaults so the
# enforcement is observable in bounded time.
@@ -509,6 +509,7 @@ class TestSpoolOnDisconnect:
class TestReconnectFlush:
@pytest.mark.timeout(120) # P1 (D-054 outlier): 20s poll deadline + load headroom
def test_reconnect_flushes_spool_in_order_no_loss(
self, tmp_path: Path, fake_server: FakeWSServer, held_link: KillableProxy
) -> None:
@@ -30,6 +30,11 @@ from ai_service.telemetry.store import SQLiteTraceStore
from .test_isolation import USERSNS_AVAILABLE
# P1 tier marker (Task 1-1-02): the e2e wiring test boots a REAL uvicorn
# server the in-namespace capture agent dials over loopback — real_server
# tier, 180s timeout via the conftest collection hook.
pytestmark = [pytest.mark.real_server]
def _userns_probe() -> None:
if not USERSNS_AVAILABLE:
@@ -30,6 +30,11 @@ from ai_service.telemetry.tokens import IngestToken
from ..sandbox.test_isolation import USERSNS_AVAILABLE
# P1 tier marker (Task 1-1-02): both tests boot a REAL uvicorn ingest +
# REAL namespace sandboxes behind a killable TCP proxy — real_server
# tier, 180s timeout via the conftest collection hook.
pytestmark = [pytest.mark.real_server]
def _userns_probe() -> None:
if not USERSNS_AVAILABLE:
@@ -30,6 +30,12 @@ from ai_service.variants.templates import TEMPLATES, validate_simple_argv
from ..conftest import SUITE_LEARNERS, seed_verified_identity
# P1 tier marker (Task 1-1-02): test_design_kind_e2e_real_server (below)
# boots a REAL uvicorn server + REAL namespace sandbox — real_server
# tier, 180s timeout via the conftest collection hook. The remaining
# classes here are in-process TestClient-only.
pytestmark = [pytest.mark.real_server]
DESIGN_LEARNER = "pilot-learner" # verified 18+ via the suite seed
+4 -1
View File
@@ -9,6 +9,8 @@
"scripts": {
"dev": "tsx src/index.ts",
"test": "tsx --test tests/*.test.ts",
"test:cov": "c8 --include=src/** --reporter=text --reporter=text-summary tsx --test tests/*.test.ts",
"test:e2e": "CLI_E2E=1 tsx --test tests/fresh-clone-e2e.test.ts",
"typecheck": "tsc --noEmit",
"build": "tsc -p tsconfig.build.json",
"build:binary": "node scripts/build-binary.mjs"
@@ -17,6 +19,7 @@
"@types/node": "^24.0.0",
"tsx": "^4.23.0",
"typescript": "^5.7.2",
"esbuild": "0.28.2"
"esbuild": "0.28.2",
"c8": "^10.1.3"
}
}
+65 -53
View File
@@ -9,64 +9,76 @@ import { fileURLToPath } from "node:url";
const cliDir = join(dirname(fileURLToPath(import.meta.url)), "..");
const repoRoot = join(cliDir, "..", "..");
test("fresh-clone E2E: clone -> doctor -> bootstrap -> verify (happy path, transcript)", async () => {
const work = mkdtempSync(join(tmpdir(), "nc-e2e-"));
const cloneDir = join(work, "nextcraft");
// P1 harness wiring (D-055, Task 1-2-02): the real 600s fresh-clone bootstrap
// is opt-in — it never runs inside the default `cli:test` suite. Setting
// CLI_E2E=1 (or `pnpm cli:test:e2e`) runs it; without the gate the test
// reports a VISIBLE skip with the reason, never a silent green.
test(
"fresh-clone E2E: clone -> doctor -> bootstrap -> verify (happy path, transcript)",
{
skip: process.env.CLI_E2E
? false
: "env-gated: set CLI_E2E=1 (pnpm cli:test:e2e) to run the real 600s bootstrap",
},
async () => {
const work = mkdtempSync(join(tmpdir(), "nc-e2e-"));
const cloneDir = join(work, "nextcraft");
const clone = spawnSync(
"git",
["clone", "--quiet", "--no-hardlinks", repoRoot, cloneDir],
{ encoding: "utf8", timeout: 120000 },
);
assert.equal(clone.status, 0, `clone failed: ${clone.stderr}`);
const clone = spawnSync(
"git",
["clone", "--quiet", "--no-hardlinks", repoRoot, cloneDir],
{ encoding: "utf8", timeout: 120000 },
);
assert.equal(clone.status, 0, `clone failed: ${clone.stderr}`);
const binary = join(repoRoot, "apps", "cli", "dist", "nextcraft-linux-x64");
const cli = existsSync(binary)
? binary
: join(cliDir, "node_modules", ".bin", "tsx");
const binary = join(repoRoot, "apps", "cli", "dist", "nextcraft-linux-x64");
const cli = existsSync(binary)
? binary
: join(cliDir, "node_modules", ".bin", "tsx");
const transcript: string[] = [];
const step = (name: string, args: string[], expect: number, timeoutMs: number) => {
const { NODE_TEST_CONTEXT, ...restEnv } = process.env as Record<string, string | undefined>;
const env = {
...restEnv,
PATH: [join(process.env.HOME ?? "/home", ".local/bin"), process.env.PATH].filter(Boolean).join(":"),
NEXTCRAFT_VERSION: "v-e2e",
} as Record<string, string | undefined>;
const run = spawnSync(cli, existsSync(binary) ? args : [join(cliDir, "src", "index.ts"), ...args], {
cwd: cloneDir,
encoding: "utf8",
timeout: timeoutMs,
env,
});
transcript.push(`$ nextcraft ${args.join(" ")} -> exit ${run.status}`);
if (run.status !== expect) {
transcript.push(run.stdout, run.stderr);
assert.fail(
`${name} exited ${run.status} (expected ${expect})\nTRANSCRIPT:\n${transcript.join("\n")}\nstderr: ${run.stderr}`,
);
}
return run.stdout + run.stderr;
};
const transcript: string[] = [];
const step = (name: string, args: string[], expect: number, timeoutMs: number) => {
const { NODE_TEST_CONTEXT, ...restEnv } = process.env as Record<string, string | undefined>;
const env = {
...restEnv,
PATH: [join(process.env.HOME ?? "/home", ".local/bin"), process.env.PATH].filter(Boolean).join(":"),
NEXTCRAFT_VERSION: "v-e2e",
} as Record<string, string | undefined>;
const run = spawnSync(cli, existsSync(binary) ? args : [join(cliDir, "src", "index.ts"), ...args], {
cwd: cloneDir,
encoding: "utf8",
timeout: timeoutMs,
env,
});
transcript.push(`$ nextcraft ${args.join(" ")} -> exit ${run.status}`);
if (run.status !== expect) {
transcript.push(run.stdout, run.stderr);
assert.fail(
`${name} exited ${run.status} (expected ${expect})\nTRANSCRIPT:\n${transcript.join("\n")}\nstderr: ${run.stderr}`,
);
}
return run.stdout + run.stderr;
};
const doctorOut = step("doctor", ["doctor"], 0, 60000);
assert.ok(doctorOut.includes("node"), "doctor mentions node");
assert.ok(doctorOut.includes("pnpm"), "doctor mentions pnpm");
const doctorOut = step("doctor", ["doctor"], 0, 60000);
assert.ok(doctorOut.includes("node"), "doctor mentions node");
assert.ok(doctorOut.includes("pnpm"), "doctor mentions pnpm");
step("bootstrap", ["bootstrap"], 0, 600000);
step("bootstrap", ["bootstrap"], 0, 600000);
const verifyOut = step("verify", ["verify"], 0, 120000);
assert.ok(verifyOut.includes("venv"), "verify covers venv");
assert.ok(existsSync(join(cloneDir, "apps", "ai-service", ".env")), ".env created in clone");
assert.ok(existsSync(join(cloneDir, "apps", "ai-service", ".venv")), "venv created in clone");
assert.ok(
existsSync(join(cloneDir, "node_modules", ".pnpm")),
"workspace node_modules present",
);
const verifyOut = step("verify", ["verify"], 0, 120000);
assert.ok(verifyOut.includes("venv"), "verify covers venv");
assert.ok(existsSync(join(cloneDir, "apps", "ai-service", ".env")), ".env created in clone");
assert.ok(existsSync(join(cloneDir, "apps", "ai-service", ".venv")), "venv created in clone");
assert.ok(
existsSync(join(cloneDir, "node_modules", ".pnpm")),
"workspace node_modules present",
);
const envExample = readFileSync(join(repoRoot, "apps", "ai-service", ".env.example"), "utf8");
const envClone = readFileSync(join(cloneDir, "apps", "ai-service", ".env"), "utf8");
assert.equal(envClone, envExample, ".env content matches template");
const envExample = readFileSync(join(repoRoot, "apps", "ai-service", ".env.example"), "utf8");
const envClone = readFileSync(join(cloneDir, "apps", "ai-service", ".env"), "utf8");
assert.equal(envClone, envExample, ".env content matches template");
console.log("E2E TRANSCRIPT:\n" + transcript.join("\n"));
});
console.log("E2E TRANSCRIPT:\n" + transcript.join("\n"));
},
);
+1 -2
View File
@@ -10,8 +10,7 @@ const cliDir = join(dirname(fileURLToPath(import.meta.url)), "..");
const repoRoot = join(cliDir, "..", "..");
const binary = join(repoRoot, "apps", "cli", "dist", "nextcraft-linux-x64");
test("PATH bare-word invocation: installed binary speaks (SEA regression, v0.3.4 bug)", () => {
if (!existsSync(binary)) return; // built by cli:build:binary; covered in ship flow
test("PATH bare-word invocation: installed binary speaks (SEA regression, v0.3.4 bug)", { skip: existsSync(binary) ? false : `built binary missing: ${binary} (run cli:build:binary)` }, () => {
const binDir = mkdtempSync(join(tmpdir(), "nc-pathword-"));
cpSync(binary, join(binDir, "nextcraft"));
const env = {
+3 -1
View File
@@ -10,7 +10,8 @@
"typecheck": "tsc --noEmit",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"test": "tsx --test tests/*.test.ts"
"test": "tsx --test tests/*.test.ts",
"test:cov": "c8 --include=lib/** --include=hooks/** --include=components/marketplace/** --reporter=text --reporter=text-summary tsx --test tests/*.test.ts"
},
"dependencies": {
"@nextcraft/mock-data": "workspace:*",
@@ -32,6 +33,7 @@
"@types/node": "20.17.6",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"c8": "^10.1.3",
"storybook": "^10.6.0",
"tailwindcss": "^4.0.0",
"typescript": "^5.7.2",
+6
View File
@@ -14,8 +14,14 @@
"ai:test": "turbo run test --filter=@nextcraft/ai-service",
"ai:bootstrap": "turbo run bootstrap --filter=@nextcraft/ai-service",
"ai:lint": "turbo run lint --filter=@nextcraft/ai-service",
"ai:test:fast": "cd apps/ai-service && FAST=1 bash scripts/test.sh",
"cli:dev": "pnpm --filter @nextcraft/cli dev",
"test": "turbo run test",
"web:test": "pnpm --filter web test",
"web:test:cov": "pnpm --filter web test:cov",
"cli:test": "pnpm --filter @nextcraft/cli test",
"cli:test:cov": "pnpm --filter @nextcraft/cli test:cov",
"cli:test:e2e": "pnpm --filter @nextcraft/cli test:e2e",
"cli:typecheck": "pnpm --filter @nextcraft/cli typecheck",
"cli:build": "pnpm --filter @nextcraft/cli build"
},
+437
View File
@@ -123,6 +123,9 @@ importers:
'@types/node':
specifier: ^24.0.0
version: 24.13.4
c8:
specifier: ^10.1.3
version: 10.1.3
esbuild:
specifier: 0.28.2
version: 0.28.2
@@ -187,6 +190,9 @@ importers:
'@types/react-dom':
specifier: ^19.0.0
version: 19.3.0(@types/react@19.3.0)
c8:
specifier: ^10.1.3
version: 10.1.3
storybook:
specifier: ^10.6.0
version: 10.6.0(@types/react@19.3.0)(react@19.3.0)
@@ -821,6 +827,10 @@ packages:
resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==}
engines: {node: '>=6.9.0'}
'@bcoe/v8-coverage@1.0.2':
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
engines: {node: '>=18'}
'@emnapi/core@1.11.0':
resolution: {integrity: sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q==}
@@ -1160,6 +1170,14 @@ packages:
cpu: [x64]
os: [win32]
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
'@istanbuljs/schema@0.1.6':
resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==}
engines: {node: '>=8'}
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
@@ -1480,6 +1498,10 @@ packages:
cpu: [x64]
os: [win32]
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
'@pmmmwh/react-refresh-webpack-plugin@0.5.17':
resolution: {integrity: sha512-tXDyE1/jzFsHXjhRZQ3hMl0IVhYe5qula43LDWIhVfjp9G/nT5OQY5AORVOrkEGAUltBJOfOWeETbmhm6kHhuQ==}
engines: {node: '>= 10.13'}
@@ -1913,6 +1935,9 @@ packages:
'@types/html-minifier-terser@6.1.0':
resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==}
'@types/istanbul-lib-coverage@2.0.6':
resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@@ -2093,6 +2118,10 @@ packages:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
ansi-regex@6.3.0:
resolution: {integrity: sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==}
engines: {node: '>=12'}
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
@@ -2101,6 +2130,10 @@ packages:
resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
engines: {node: '>=10'}
ansi-styles@6.2.3:
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
engines: {node: '>=12'}
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@@ -2159,6 +2192,10 @@ packages:
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
balanced-match@4.0.4:
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
engines: {node: 18 || 20 || >=22}
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@@ -2182,6 +2219,13 @@ packages:
brace-expansion@1.1.18:
resolution: {integrity: sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==}
brace-expansion@2.1.7:
resolution: {integrity: sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==}
brace-expansion@5.0.12:
resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==}
engines: {node: 20 || >=22}
braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
@@ -2230,6 +2274,16 @@ packages:
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
engines: {node: '>=18'}
c8@10.1.3:
resolution: {integrity: sha512-LvcyrOAaOnrrlMpW22n690PUvxiq4Uf9WMhQwNJ9vgagkL/ph1+D4uvjvDA5XCbykrc0sx+ay6pVi9YZ1GnhyA==}
engines: {node: '>=18'}
hasBin: true
peerDependencies:
monocart-coverage-reports: ^2
peerDependenciesMeta:
monocart-coverage-reports:
optional: true
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
@@ -2297,6 +2351,10 @@ packages:
client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
cliui@8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'}
clsx@2.1.1:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'}
@@ -2376,6 +2434,10 @@ packages:
create-hmac@1.1.7:
resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==}
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
crypto-browserify@3.12.1:
resolution: {integrity: sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==}
engines: {node: '>= 0.10'}
@@ -2601,12 +2663,21 @@ packages:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
electron-to-chromium@1.5.425:
resolution: {integrity: sha512-QvPtl41EUOnuT1HBvMKgxXRIaHNcagBPs50u7VULzhZXaGfqTbZyE16LQsctZ/RQHlGu+FOWeDTR4mY6YbeF1g==}
elliptic@6.6.1:
resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
emojis-list@3.0.0:
resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
engines: {node: '>= 4'}
@@ -2720,6 +2791,10 @@ packages:
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
engines: {node: '>=8'}
find-up@5.0.0:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
find-up@6.3.0:
resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -2735,6 +2810,10 @@ packages:
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
engines: {node: '>= 0.4'}
foreground-child@3.3.1:
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
engines: {node: '>=14'}
fork-ts-checker-webpack-plugin@9.1.0:
resolution: {integrity: sha512-mpafl89VFPJmhnJ1ssH+8wmM2b50n+Rew5x42NeI2U78aRWgtkEtGmctp7iT16UjquJTjorEmIfESj3DxdW84Q==}
engines: {node: '>=14.21.3'}
@@ -2768,6 +2847,10 @@ packages:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'}
get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
@@ -2776,6 +2859,11 @@ packages:
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
engines: {node: '>= 0.4'}
glob@10.5.0:
resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==}
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
hasBin: true
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
@@ -2827,6 +2915,9 @@ packages:
html-entities@2.6.0:
resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==}
html-escaper@2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
html-minifier-terser@6.1.0:
resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==}
engines: {node: '>=12'}
@@ -2902,6 +2993,10 @@ packages:
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
hasBin: true
is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
is-generator-function@1.1.2:
resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==}
engines: {node: '>= 0.4'}
@@ -2937,6 +3032,24 @@ packages:
isarray@2.0.5:
resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
istanbul-lib-coverage@3.2.2:
resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
engines: {node: '>=8'}
istanbul-lib-report@3.0.1:
resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
engines: {node: '>=10'}
istanbul-reports@3.2.0:
resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==}
engines: {node: '>=8'}
jackspeak@3.4.3:
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
jest-worker@27.5.1:
resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}
engines: {node: '>= 10.13.0'}
@@ -3072,6 +3185,10 @@ packages:
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
engines: {node: '>=8'}
locate-path@6.0.0:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'}
locate-path@7.2.0:
resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -3095,6 +3212,9 @@ packages:
lower-case@2.0.2:
resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
@@ -3117,6 +3237,10 @@ packages:
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
engines: {node: '>=8'}
make-dir@4.0.0:
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
engines: {node: '>=10'}
map-or-similar@1.5.0:
resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==}
@@ -3167,9 +3291,17 @@ packages:
minimalistic-crypto-utils@1.0.1:
resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==}
minimatch@10.2.6:
resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==}
engines: {node: 18 || 20 || >=22}
minimatch@3.1.5:
resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==}
minimatch@9.0.9:
resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==}
engines: {node: '>=16 || 14 >=14.17'}
minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
@@ -3228,6 +3360,10 @@ packages:
uglify-js:
optional: true
minipass@7.1.3:
resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==}
engines: {node: '>=16 || 14 >=14.17'}
ms@2.0.0:
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
@@ -3331,6 +3467,10 @@ packages:
resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
engines: {node: '>=6'}
p-limit@3.1.0:
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
engines: {node: '>=10'}
p-limit@4.0.0:
resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -3339,6 +3479,10 @@ packages:
resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
engines: {node: '>=8'}
p-locate@5.0.0:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
p-locate@6.0.0:
resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -3347,6 +3491,9 @@ packages:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
package-json-from-dist@1.0.1:
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
pako@1.0.11:
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
@@ -3383,9 +3530,17 @@ packages:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
path-scurry@1.11.1:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'}
path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
@@ -3626,6 +3781,10 @@ packages:
renderkid@3.0.0:
resolution: {integrity: sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==}
require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
require-from-string@2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
@@ -3735,6 +3894,14 @@ packages:
'@types/node':
optional: true
shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
shebang-regex@3.0.0:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
side-channel-list@1.0.1:
resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==}
engines: {node: '>= 0.4'}
@@ -3751,6 +3918,10 @@ packages:
resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==}
engines: {node: '>= 0.4'}
signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
@@ -3793,6 +3964,14 @@ packages:
stream-parser@0.3.1:
resolution: {integrity: sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==}
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
string-width@5.1.2:
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
engines: {node: '>=12'}
string_decoder@1.1.1:
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
@@ -3803,6 +3982,10 @@ packages:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
strip-ansi@7.2.0:
resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==}
engines: {node: '>=12'}
strip-bom@3.0.0:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'}
@@ -3907,6 +4090,10 @@ packages:
engines: {node: '>=10'}
hasBin: true
test-exclude@7.0.2:
resolution: {integrity: sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==}
engines: {node: '>=18'}
timers-browserify@2.0.12:
resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==}
engines: {node: '>=0.6.0'}
@@ -4040,6 +4227,10 @@ packages:
deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).
hasBin: true
v8-to-istanbul@9.3.0:
resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==}
engines: {node: '>=10.12.0'}
victory-vendor@36.9.2:
resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==}
@@ -4083,6 +4274,19 @@ packages:
resolution: {integrity: sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==}
engines: {node: '>= 0.4'}
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
hasBin: true
wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
wrap-ansi@8.1.0:
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
engines: {node: '>=12'}
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
@@ -4106,9 +4310,25 @@ packages:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
yargs@17.7.3:
resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==}
engines: {node: '>=12'}
yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
yocto-queue@1.2.2:
resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==}
engines: {node: '>=12.20'}
@@ -4892,6 +5112,8 @@ snapshots:
'@babel/helper-string-parser': 7.29.7
'@babel/helper-validator-identifier': 7.29.7
'@bcoe/v8-coverage@1.0.2': {}
'@emnapi/core@1.11.0':
dependencies:
'@emnapi/wasi-threads': 1.2.2
@@ -5114,6 +5336,17 @@ snapshots:
'@img/sharp-win32-x64@0.35.4':
optional: true
'@isaacs/cliui@8.0.2':
dependencies:
string-width: 5.1.2
string-width-cjs: string-width@4.2.3
strip-ansi: 7.2.0
strip-ansi-cjs: strip-ansi@6.0.1
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
'@istanbuljs/schema@0.1.6': {}
'@jridgewell/gen-mapping@0.3.13':
dependencies:
'@jridgewell/sourcemap-codec': 1.6.0
@@ -5311,6 +5544,9 @@ snapshots:
'@oxc-resolver/binding-win32-x64-msvc@11.21.2':
optional: true
'@pkgjs/parseargs@0.11.0':
optional: true
'@pmmmwh/react-refresh-webpack-plugin@0.5.17(react-refresh@0.14.2)(type-fest@2.19.0)(webpack-hot-middleware@2.26.1)(webpack@5.110.3(clean-css@5.3.3)(esbuild@0.28.2)(html-minifier-terser@6.1.0)(lightningcss@1.32.0)(postcss@8.5.28)(sharp@0.35.4(@types/node@20.17.6)))':
dependencies:
ansi-html: 0.0.9
@@ -5867,6 +6103,8 @@ snapshots:
'@types/html-minifier-terser@6.1.0': {}
'@types/istanbul-lib-coverage@2.0.6': {}
'@types/json-schema@7.0.15': {}
'@types/mdx@2.0.14': {}
@@ -6098,12 +6336,16 @@ snapshots:
ansi-regex@5.0.1: {}
ansi-regex@6.3.0: {}
ansi-styles@4.3.0:
dependencies:
color-convert: 2.0.1
ansi-styles@5.2.0: {}
ansi-styles@6.2.3: {}
argparse@2.0.1: {}
aria-query@5.3.0:
@@ -6177,6 +6419,8 @@ snapshots:
balanced-match@1.0.2: {}
balanced-match@4.0.4: {}
base64-js@1.5.1: {}
baseline-browser-mapping@2.11.21: {}
@@ -6194,6 +6438,14 @@ snapshots:
balanced-match: 1.0.2
concat-map: 0.0.1
brace-expansion@2.1.7:
dependencies:
balanced-match: 1.0.2
brace-expansion@5.0.12:
dependencies:
balanced-match: 4.0.4
braces@3.0.3:
dependencies:
fill-range: 7.1.1
@@ -6267,6 +6519,20 @@ snapshots:
dependencies:
run-applescript: 7.1.0
c8@10.1.3:
dependencies:
'@bcoe/v8-coverage': 1.0.2
'@istanbuljs/schema': 0.1.6
find-up: 5.0.0
foreground-child: 3.3.1
istanbul-lib-coverage: 3.2.2
istanbul-lib-report: 3.0.1
istanbul-reports: 3.2.0
test-exclude: 7.0.2
v8-to-istanbul: 9.3.0
yargs: 17.7.3
yargs-parser: 21.1.1
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
@@ -6337,6 +6603,12 @@ snapshots:
client-only@0.0.1: {}
cliui@8.0.1:
dependencies:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
clsx@2.1.1: {}
color-convert@2.0.1:
@@ -6413,6 +6685,12 @@ snapshots:
safe-buffer: 5.2.1
sha.js: 2.4.12
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
crypto-browserify@3.12.1:
dependencies:
browserify-cipher: 1.0.1
@@ -6644,6 +6922,8 @@ snapshots:
es-errors: 1.3.0
gopd: 1.2.0
eastasianwidth@0.2.0: {}
electron-to-chromium@1.5.425: {}
elliptic@6.6.1:
@@ -6656,6 +6936,10 @@ snapshots:
minimalistic-assert: 1.0.1
minimalistic-crypto-utils: 1.0.1
emoji-regex@8.0.0: {}
emoji-regex@9.2.2: {}
emojis-list@3.0.0: {}
endent@2.1.0:
@@ -6775,6 +7059,11 @@ snapshots:
locate-path: 5.0.0
path-exists: 4.0.0
find-up@5.0.0:
dependencies:
locate-path: 6.0.0
path-exists: 4.0.0
find-up@6.3.0:
dependencies:
locate-path: 7.2.0
@@ -6792,6 +7081,11 @@ snapshots:
dependencies:
is-callable: 1.2.7
foreground-child@3.3.1:
dependencies:
cross-spawn: 7.0.6
signal-exit: 4.1.0
fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.110.3(clean-css@5.3.3)(esbuild@0.28.2)(html-minifier-terser@6.1.0)(lightningcss@1.32.0)(postcss@8.5.28)(sharp@0.35.4(@types/node@20.17.6))):
dependencies:
'@babel/code-frame': 7.29.7
@@ -6828,6 +7122,8 @@ snapshots:
gensync@1.0.0-beta.2: {}
get-caller-file@2.0.5: {}
get-intrinsic@1.3.0:
dependencies:
call-bind-apply-helpers: 1.0.2
@@ -6846,6 +7142,15 @@ snapshots:
dunder-proto: 1.0.1
es-object-atoms: 1.1.2
glob@10.5.0:
dependencies:
foreground-child: 3.3.1
jackspeak: 3.4.3
minimatch: 9.0.9
minipass: 7.1.3
package-json-from-dist: 1.0.1
path-scurry: 1.11.1
glob@7.2.3:
dependencies:
fs.realpath: 1.0.0
@@ -6902,6 +7207,8 @@ snapshots:
html-entities@2.6.0: {}
html-escaper@2.0.2: {}
html-minifier-terser@6.1.0:
dependencies:
camel-case: 4.1.2
@@ -6972,6 +7279,8 @@ snapshots:
is-docker@3.0.0: {}
is-fullwidth-code-point@3.0.0: {}
is-generator-function@1.1.2:
dependencies:
call-bound: 1.0.4
@@ -7010,6 +7319,27 @@ snapshots:
isarray@2.0.5: {}
isexe@2.0.0: {}
istanbul-lib-coverage@3.2.2: {}
istanbul-lib-report@3.0.1:
dependencies:
istanbul-lib-coverage: 3.2.2
make-dir: 4.0.0
supports-color: 7.2.0
istanbul-reports@3.2.0:
dependencies:
html-escaper: 2.0.2
istanbul-lib-report: 3.0.1
jackspeak@3.4.3:
dependencies:
'@isaacs/cliui': 8.0.2
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
jest-worker@27.5.1:
dependencies:
'@types/node': 20.17.6
@@ -7111,6 +7441,10 @@ snapshots:
dependencies:
p-locate: 4.1.0
locate-path@6.0.0:
dependencies:
p-locate: 5.0.0
locate-path@7.2.0:
dependencies:
p-locate: 6.0.0
@@ -7131,6 +7465,8 @@ snapshots:
dependencies:
tslib: 2.8.1
lru-cache@10.4.3: {}
lru-cache@5.1.1:
dependencies:
yallist: 3.1.1
@@ -7153,6 +7489,10 @@ snapshots:
dependencies:
semver: 6.3.1
make-dir@4.0.0:
dependencies:
semver: 7.8.5
map-or-similar@1.5.0: {}
math-intrinsics@1.1.0: {}
@@ -7197,10 +7537,18 @@ snapshots:
minimalistic-crypto-utils@1.0.1: {}
minimatch@10.2.6:
dependencies:
brace-expansion: 5.0.12
minimatch@3.1.5:
dependencies:
brace-expansion: 1.1.18
minimatch@9.0.9:
dependencies:
brace-expansion: 2.1.7
minimist@1.2.8: {}
minimizer-webpack-plugin@5.10.1(clean-css@5.3.3)(esbuild@0.28.2)(html-minifier-terser@6.1.0)(lightningcss@1.32.0)(postcss@8.5.28)(sharp@0.35.4(@types/node@20.17.6))(webpack@5.110.3(clean-css@5.3.3)(esbuild@0.28.2)(html-minifier-terser@6.1.0)(lightningcss@1.32.0)(postcss@8.5.28)(sharp@0.35.4(@types/node@20.17.6))):
@@ -7218,6 +7566,8 @@ snapshots:
postcss: 8.5.28
sharp: 0.35.4(@types/node@20.17.6)
minipass@7.1.3: {}
ms@2.0.0: {}
ms@2.1.3: {}
@@ -7386,6 +7736,10 @@ snapshots:
dependencies:
p-try: 2.2.0
p-limit@3.1.0:
dependencies:
yocto-queue: 0.1.0
p-limit@4.0.0:
dependencies:
yocto-queue: 1.2.2
@@ -7394,12 +7748,18 @@ snapshots:
dependencies:
p-limit: 2.3.0
p-locate@5.0.0:
dependencies:
p-limit: 3.1.0
p-locate@6.0.0:
dependencies:
p-limit: 4.0.0
p-try@2.2.0: {}
package-json-from-dist@1.0.1: {}
pako@1.0.11: {}
param-case@3.0.4:
@@ -7439,8 +7799,15 @@ snapshots:
path-is-absolute@1.0.1: {}
path-key@3.1.1: {}
path-parse@1.0.7: {}
path-scurry@1.11.1:
dependencies:
lru-cache: 10.4.3
minipass: 7.1.3
path-type@4.0.0: {}
pathval@2.0.1: {}
@@ -7723,6 +8090,8 @@ snapshots:
lodash: 4.18.1
strip-ansi: 6.0.1
require-directory@2.1.1: {}
require-from-string@2.0.2: {}
resolve-from@4.0.0: {}
@@ -7843,6 +8212,12 @@ snapshots:
'@types/node': 20.17.6
optional: true
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0
shebang-regex@3.0.0: {}
side-channel-list@1.0.1:
dependencies:
es-errors: 1.3.0
@@ -7871,6 +8246,8 @@ snapshots:
side-channel-map: 1.0.1
side-channel-weakmap: 1.0.2
signal-exit@4.1.0: {}
source-map-js@1.2.1: {}
source-map-support@0.5.21:
@@ -7928,6 +8305,18 @@ snapshots:
transitivePeerDependencies:
- supports-color
string-width@4.2.3:
dependencies:
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
string-width@5.1.2:
dependencies:
eastasianwidth: 0.2.0
emoji-regex: 9.2.2
strip-ansi: 7.2.0
string_decoder@1.1.1:
dependencies:
safe-buffer: 5.1.2
@@ -7940,6 +8329,10 @@ snapshots:
dependencies:
ansi-regex: 5.0.1
strip-ansi@7.2.0:
dependencies:
ansi-regex: 6.3.0
strip-bom@3.0.0: {}
strip-indent@3.0.0:
@@ -7998,6 +8391,12 @@ snapshots:
commander: 2.20.3
source-map-support: 0.5.21
test-exclude@7.0.2:
dependencies:
'@istanbuljs/schema': 0.1.6
glob: 10.5.0
minimatch: 10.2.6
timers-browserify@2.0.12:
dependencies:
setimmediate: 1.0.5
@@ -8121,6 +8520,12 @@ snapshots:
uuid@9.0.1: {}
v8-to-istanbul@9.3.0:
dependencies:
'@jridgewell/trace-mapping': 0.3.31
'@types/istanbul-lib-coverage': 2.0.6
convert-source-map: 2.0.0
victory-vendor@36.9.2:
dependencies:
'@types/d3-array': 3.2.2
@@ -8213,6 +8618,22 @@ snapshots:
gopd: 1.2.0
has-tostringtag: 1.0.2
which@2.0.2:
dependencies:
isexe: 2.0.0
wrap-ansi@7.0.0:
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi@8.1.0:
dependencies:
ansi-styles: 6.2.3
string-width: 5.1.2
strip-ansi: 7.2.0
wrappy@1.0.2: {}
ws@8.21.3: {}
@@ -8223,8 +8644,24 @@ snapshots:
xtend@4.0.2: {}
y18n@5.0.8: {}
yallist@3.1.1: {}
yargs-parser@21.1.1: {}
yargs@17.7.3:
dependencies:
cliui: 8.0.1
escalade: 3.2.0
get-caller-file: 2.0.5
require-directory: 2.1.1
string-width: 4.2.3
y18n: 5.0.8
yargs-parser: 21.1.1
yocto-queue@0.1.0: {}
yocto-queue@1.2.2: {}
zustand@4.5.7(@types/react@19.3.0)(react@19.3.0):
+4
View File
@@ -35,6 +35,10 @@
"cache": false,
"outputs": []
},
"web#test": {
"cache": false,
"outputs": []
},
"@nextcraft/cli#test": {
"cache": false,
"outputs": []