Security
- Fix minimatch ReDoS vulnerability: Added npm
overridesinwebsite/package.jsonto forceminimatch@^10.2.1, resolving Dependabot alert #75 (ReDoS via repeated wildcards inserve-handler's transitiveminimatch@3.1.2dependency) - Update wasm-bindgen: Bumped
wasm-bindgenfrom 0.2.109 (yanked) to 0.2.110 along with related crates (js-sys,web-sys,wasm-bindgen-test, etc.)
Performance
- WASM conversion optimization: Refactored
WasmDiagnostic::from_diagnosticto take ownership ofDiagnosticand its fields, eliminating unnecessary string cloning when converting diagnostics to the WASM-compatible representation inagnix-wasm
Added
- LSP
pub(crate)testability refactor: Made internal modules (backend,code_actions,completion_provider,diagnostic_mapper,hover_provider,position,vscode_config) andBackendstruct fields/methodspub(crate)to enable crate-internal test access. AddedBackend::new_test()constructor (gated behind#[cfg(test)]) and 18 new tests intestability_tests.rsverifying that all promotedpub(crate)items are accessible from the crate root. No public API changes. - Improved frontmatter parsing test coverage: Added exhaustive unit tests for
frontmatter_value_byte_range,frontmatter_key_offset, andfrontmatter_key_line_byte_rangeinagnix-core. Covers unquoted/quoted values, comments, CRLF endings, indented keys, and malformed input. build_lenient()onLintConfigBuilder: New builder terminal that runs security-critical glob pattern validation (syntax, path traversal, absolute paths) while skipping semantic warnings such as unknown tool names and deprecated field warnings. Intended for embedders that accept future or unknown tool names without rebuilding.ConfigError::AbsolutePathPatternvariant added for absolute-path glob patterns (#475)- Expanded autofix coverage: Added
with_fix()autofix support to 38 additional validation rules across AGM, AMP, AS, CC-AG, CC-HK, CC-PL, CC-SK, CDX, COP, CUR, GM, KIRO, MCP, OC, PE, and REF categories, bringing total fixable rules from 59 to 97 (42% of all rules) - Kiro steering file validation: 4 new validation rules (KIRO-001 through KIRO-004) for
.kiro/steering/*.mdfiles - validates inclusion modes (always,fileMatch,manual,auto), required companion fields, glob pattern syntax, and empty file detection - Cross-platform and reference validation expansion: 5 new rules - XP-007 (AGENTS.md exceeds Codex CLI 32KB byte limit), REF-003 (duplicate @import detection), REF-004 (non-markdown @import warning), PE-005 (redundant LLM instructions), PE-006 (negative instructions without positive alternatives)
- Roo Code support: 6 new validation rules (ROO-001 through ROO-006) for
.roorules,.roomodes,.rooignore,.roo/rules/*.md,.roo/rules-{slug}/*.md, and.roo/mcp.jsonconfiguration files - Cursor expanded coverage: Added 7 new validation rules (CUR-010 through CUR-016) for
.cursor/hooks.json,.cursor/agents/**/*.md, and.cursor/environment.json, including stricter field validation and case-insensitive path detection. - Windsurf support: Added 4 validation rules (WS-001 through WS-004) for
.windsurf/rules/*.mdand.windsurf/workflows/*.mddirectories, plus legacy.windsurfrulesdetection. Includes file type detection, character limit enforcement (12,000), and empty file warnings. - Gemini CLI expanded coverage: Added 6 new validation rules (GM-004 through GM-009) for .gemini/settings.json hooks configuration, gemini-extension.json manifests, and .geminiignore files. Added 3 new file type detectors and validators.
- Codex CLI expanded validation: CDX-004 (unknown config keys), CDX-005 (
project_doc_max_bytesexceeds 65536 limit); updated CDX source_urls to official docs - OpenCode expanded validation: OC-004 (unknown config keys), OC-006 (remote instruction URL timeout warning), OC-007 (invalid agent definition), OC-008 (invalid permission configuration), OC-009 (variable substitution syntax validation)
agnix-wasmcrate: New WebAssembly bindings for the validation engine, enabling browser-based validation without a servervalidate_content()API: New pure function inagnix-corefor validating content strings without filesystem I/Ofilesystemfeature flag:agnix-corenow gates filesystem-dependent code (rayon,ignore,dirs) behind afilesystemfeature (enabled by default), allowing WASM compilation withdefault-features = falseagnix-corestd requirement documentation: Added crate-level documentation inlib.rs,Cargo.toml, andREADME.mdclarifying thatagnix-corerequiresstdunconditionally and that thefilesystemfeature flag does not enableno_stdsupport. Resolves downstream confusion for WASM consumers usingdefault-features = false(#485)- Web playground UI polish: Teal gradient background, staggered animations, panel shadows, focus glow, SVG icons, active preset state, empty state with checkmark, loading spinner,
prefers-reduced-motionsupport - Inline editor diagnostics: Red/yellow/teal wavy underlines via
@codemirror/lint, gutter markers, hover tooltips with rule ID and message - Auto-fix in playground: WASM now exposes
Fixdata; per-diagnostic "Fix" buttons and "Fix all" button apply replacements directly in the editor - New playground presets: AGENTS.md,
.claude/agents/reviewer.md,plugin.json; enriched.claude/settings.jsonhooks preset - Backend revalidation regression tests: Added coverage for
did_saveproject-trigger revalidation and stale generation guard behavior inagnix-lspbackend tests - Confidence-tiered autofix engine:
Fixmetadata now supports confidence, alternative groups, and dependencies; CLI adds--fix-unsafeand--show-fixes; core exposes confidence-basedFixApplyMode/FixApplyOptions - CI crate graph parity test: New workspace-level test validates that all
Cargo.tomlworkspace members are documented in CLAUDE.md, AGENTS.md, README.md, SPEC.md, and CONTRIBUTING.md - prevents architecture-doc drift resolve_validation_rootfile-input tests: 7 integration tests covering single-file validation mode - validates file-input path behavior, unknown file type handling, project-level rule scoping, and nonexistent file edge case (#450)ImportsValidatorconcurrency and multi-file cycle tests: 11 new tests covering thread-safety under concurrent validation, multi-file import cycles (3- and 4-file chains), depth boundary conditions at and belowMAX_IMPORT_DEPTH(complementing existing above-boundary coverage), diamond dependency graphs, and mixed valid/invalid import scenarios (#456)- UTF-8 boundary
_checkedFix constructors: Added 6 newFixconstructor variants (replace_checked,replace_with_confidence_checked,insert_checked,insert_with_confidence_checked,delete_checked,delete_with_confidence_checked) that acceptcontent: &strand validate UTF-8 char boundary alignment viadebug_assert!in debug builds - no-ops in release builds (#463) - LSP concurrent revalidation stress tests: 8 new stress tests covering concurrent document open/close cycles, rapid config changes dropping stale batches, concurrent changes to the same document, config change during active validation, concurrent project and per-file validation, high document count revalidation after a single config change, concurrent hover requests during active validation, and rapid project validation generation guard behavior (#458)
MAX_REGEX_INPUT_SIZEprecise boundary tests: 27 tests covering the exact 65536-byte limit for all 12 guarded regex functions acrossmarkdown.rs,prompt.rs, andcross_platform.rs- each function gets an at-limit (processed) and one-byte-over (rejected) test; also confirmsextract_importsandextract_markdown_linksare unrestricted (byte-scan/pulldown-cmark, not regex) (#457)
Changed
- API: Removed
#[non_exhaustive]fromValidationResultstruct - all fields are public and the attribute was unnecessarily preventing struct literal construction and exhaustive destructuring outside the crate (#487) CoreResulttype alias removed (breaking):CoreResult<T>has been removed from the public API. UseLintResult<T>(i.e.,Result<T, LintError>) instead.LintErroris a public alias forCoreError; both remain exported. (#477)__internalmodule feature-gated: The__internalmodule inagnix-coreis now behind the__internalCargo feature; it was previously unconditionally public which created semver obligations for internal items (#472)normalize_line_endingspromoted to stable public API: Accessible at the crate root (agnix_core::normalize_line_endings) without requiring the__internalfeature (#472)- Project-level validation extracted to
rules/project_level.rs: Extractedrun_project_level_checks,join_paths, and associated unit tests frompipeline.rsinto a newrules/project_level.rsmodule; adds 7 new unit tests for AGM-006, XP-004/005/006, and VER-001 behaviors (#474) build_unchecked()scoped to test/internal use:LintConfigBuilder::build_unchecked()is now gated behind#[cfg(any(test, feature = "__internal_unchecked"))]and marked#[doc(hidden)]. External embedders should migrate tobuild_lenient(). The__internal_uncheckedfeature inagnix-coreis available for integration tests that construct intentionally-invalid configs (#475)- Core refactor: Replaced the
DEFAULTSconst array inregistry.rswith 8 private categoryValidatorProviderstructs. Public API (ValidatorRegistry,ValidatorRegistryBuilder,with_defaults()) is unchanged; this is an internal reorganization only. validate_file/validate_file_with_registryreturn type (breaking): Both functions now returnLintResult<ValidationOutcome>instead ofLintResult<Vec<Diagnostic>>.ValidationOutcomeis a#[non_exhaustive]enum with three variants:Success(Vec<Diagnostic>)(validation ran),IoError(FileError)(filesystemfeature only - file could not be read), andSkipped(unknown file type, no validation performed). TheErrpath is now reserved exclusively for config-level errors. Useinto_diagnostics()for a quick migration path that matches the old flatVec<Diagnostic>behavior (#466)- Docs: Updated architecture references in README.md, SPEC.md, CLAUDE.md, and AGENTS.md to explicitly include the
agnix-wasmworkspace crate - Core refactor: Split oversized
crates/agnix-core/src/config.rsinto focused submodules (builder,rule_filter,schema,tests) while preserving the stableconfigAPI - LSP refactor: Split oversized
crates/agnix-lsp/src/backend.rsinto focused submodules (events,helpers,revalidation,tests) while preservingBackendbehavior and public exports named_validators()invariant documentation and debug guard: ExpandedValidatorProvider::named_validators()doc comment to document the name/factory invariant - eachSome(name)must equalfactory().name()or the disabled-validator mechanism silently misbehaves. Addeddebug_assert_eq!insideregister_named()to catch mismatches early in debug builds. Added 4 tests covering the debug panic, silent-skip, and slip-through failure modes (#501)- Targeted
#[allow(dead_code)]in parsers and schemas: Replaced blanket#![allow(dead_code)]module attributes inagnix-coreparsers and schemas modules with per-item allows on the specific fields and variants that require them. Narrows lint suppression scope, making future dead-code regressions visible at the item level. No public API changes (#484)
Performance
- ValidatorRegistry instance caching: Registry now stores pre-constructed
Box<dyn Validator>instances instead of factories, eliminating per-file validator re-instantiation.validators_for()returns&[Box<dyn Validator>](borrowed slice) instead ofVec<Box<dyn Validator>>. Addedtotal_validator_count()method;total_factory_count()is deprecated and will be removed in a future release. TheValidatortrait now requiresSend + Sync + 'staticbounds to allow safe sharing viaArc<ValidatorRegistry>(#460) - REF-002 link validation: Hoisted loop-invariant
canonicalize()call out of per-link loop invalidate_markdown_links()- eliminates N-1 redundant filesystem syscalls when validating N markdown links - ValidatorRegistry memory efficiency: Replaced
Stringwith&'static strfor validator names, eliminating per-validator heap allocations during registry construction. Addeddisable_validator_owned()variants for runtime string disabling with duplicate detection to prevent unnecessary memory leaks - Instruction file detection: Rewrote
is_instruction_file()to use allocation-free path component iteration andeq_ignore_ascii_case, eliminating 2 heap allocations per file during project validation walks - Parallel validation fold: Eliminated PathBuf clone on error path in parallel fold by moving the owned value into the diagnostic
- LSP lock-free config reads: Replaced
Arc<RwLock<Arc<LintConfig>>>withArc<ArcSwap<LintConfig>>in LSP backend, eliminating read lock contention on everydid_change/did_open/did_saveevent (#468) - Disabled-validator fast path: Added
named_validators()toValidatorProvidertrait (default impl wrapsvalidators()withNonenames). Providers that override it withSome(name)allowValidatorRegistryBuilderto skip the factory call entirely for disabled validators, avoiding the allocation. Built-in validators use the fast path automatically (#461) LintConfigcheap cloning: IntroducedArc<ConfigData>inner struct to hold all serializable fields. Cloning aLintConfig(e.g., invalidate_project/validate_project_with_registryparallel dispatch) now bumps anArcrefcount instead of deep-copyingVec<String>fields and nested structs. Mutations useArc::make_mutfor copy-on-write semantics, so the allocation only occurs when theArcis actually shared (#467)
Fixed
resolve_validation_rootsilent fallback removed: Passing a nonexistent path tovalidate_project()orvalidate_project_with_registry()now returnsErr(CoreError::Validation(ValidationError::RootNotFound { path }))immediately instead of silently falling back to the current working directory. The CLI exits with code 1 and prints"Validation root not found: <path>"to stderr. AddedValidationError::RootNotFoundvariant and extendedCoreError::path()to cover it (#483)- LSP document version tracking: The LSP backend now tracks document versions reported by the client (
did_open,did_change) and includes them in allpublish_diagnosticscalls. Editors that inspect diagnostic version tags (e.g., for stale-result suppression) now receive accurate version numbers instead ofNone. Version and content updates are atomized under a single lock acquisition so readers never observe a state where content and version are out of sync. Emptydid_changenotifications (no content changes) also correctly advance the tracked version per the LSP spec (#478) - Frontmatter leading newline stripped:
split_frontmatter()no longer includes the newline that follows the opening---delimiter in the extracted frontmatter string. Downstream validators (AgentValidator,AmpValidator,KiroSteeringValidator) have been updated to compute correct 1-based line numbers; diagnostic line numbers for AMP-001, CC-AG-007, and KIRO-001 through KIRO-004 are now accurate (#482) - Empty-frontmatter panic guard:
split_frontmatter()now usesstr::get()instead of direct slice indexing when extracting frontmatter content, preventing an index-out-of-bounds panic on files with an opening---delimiter but no content (#482) - Predictable UUID Generation for Telemetry: Replaced the custom, insecure random number generator with a cryptographically secure pseudo-random number generator (CSPRNG) using the
uuidcrate. Ensures telemetry installation IDs are unpredictable and unique. ImportsValidatorpoisoned-lock recovery:ImportsValidatornow emits alint::cache-poisonWarningdiagnostic (with i18n message and suggestion in en/es/zh-CN) when the sharedImportCacheRwLockis poisoned by a prior validator panic, rather than panicking or silently dropping data. Validation continues with the recovered cache state. Deduplicated withpush_unique_diagnosticto avoid one diagnostic per import. Includes 4 new tests covering detection, deduplication, continued import validation, and recursive-tree deduplication (#481)Fixconstructor range assertions: Addeddebug_assert!(start <= end)toFix::replace,Fix::replace_with_confidence,Fix::delete, andFix::delete_with_confidenceto catch inverted byte ranges in debug builds (#463)- CRLF line ending normalization:
normalize_line_endings()is now applied at all pipeline entry points (validate_file_with_type,validate_content,run_project_level_checks) and in the fix engine (apply_fixes_with_fs_options). Windows files with CRLF endings produce identical diagnostics and byte-accurate auto-fixes as their LF equivalents. Files written by--fixuse LF endings (#480) validate_file_with_registrydisabled-validator gap:config.rules().disabled_validatorswas silently ignored in thevalidate_file_with_typepath (used byvalidate_file_with_registryandvalidate_project_with_registry). Validators now respectdisabled_validatorsat runtime in all code paths, consistent withvalidate_content()(#469)- REF-001: Corrected metadata to reflect universal applicability across all tools (not claude-code specific), changed source_type to community, and added agentskills.io reference
- CC-HK-001: Added
TeammateIdleandTaskCompletedas valid hook event names - CC-AG-004: Added
delegateas a valid permission mode for Claude Code agents - CC-HK-002: Expanded PROMPT_EVENTS to include all 8 officially supported events (Stop, SubagentStop, PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, UserPromptSubmit, TaskCompleted) per Claude Code documentation, fixing false positives for prompt/agent hooks on previously-valid events
- Playground editor not initializing:
loadingstate was missing from CodeMirroruseEffectdependency array, so the editor never mounted after WASM loaded - Blue flash on playground load: Changed editor pane background from
--ag-code-bgto neutral--ag-surface-raised - Autofix dependency/group edge cases: Dependency checks now consider only structurally applicable fixes, and grouped alternatives now fall back correctly when an earlier candidate is eliminated
- MCP-008: Updated default MCP protocol version from
2025-06-18to2025-11-25to align with the latest specification - CC-HK-003: Downgraded from Error to Info level - matcher field is optional for tool events, not required; omitting it matches all tools (best practice hint, not an error)
- SARIF artifact URIs: Now uses git repository root as base path instead of current working directory, ensuring correct IDE file navigation for SARIF output. Falls back to CWD when scan path is not inside a git repository (#488)
- CI: Added
defaults.run.shell: bashandset -euo pipefailto all 9 workflow files for consistent shell behavior and early error detection;GITHUB_OUTPUTredirects inrelease.ymlare now consistently quoted (#465) - CI: Moved
VSCE_PATfrom CLI argument to environment variable in VS Code extension publish step, preventing secret exposure in process list (#464) - MCP server error codes:
validate_fileandvalidate_projecttools now returninvalid_params(JSON-RPC -32602) instead ofinternal_error(-32603) for user-supplied path validation failures, correctly distinguishing client errors from server faults. Renamed internalmake_errorhelper tomake_internal_errorfor clarity (#462) - MCP
toolsinput schema:ToolsInputnow uses a manualJsonSchemaimpl that emitsanyOfwith the array variant first andinline_schema = true, so MCP clients see the array-preferredanyOfdirectly at each property site instead of a$refto$defs. Removed the standaloneschemars0.8 dependency; tests now usermcp::schemars(v1) directly (#479) - Invalid glob pattern diagnostics: Invalid
[files]glob patterns in.agnix.tomlare now surfaced asWarningdiagnostics (ruleconfig::glob) in the validation output instead of writing to stderr.markdown.rspanic recovery paths also no longer write to stderr; they return empty results silently with a source comment (#459)