42 Commits

  • feat: add command registry and coverage checks (#1906)
    Salvages the useful parts of #1897 without generated .caliber state or stale counts.
    
    - adds a deterministic command registry generator and drift check
    - commits the current command registry for 75 commands
    - validates the rc.1 README catalog summary against live counts
    - adds a single Ubuntu Node 20 coverage job instead of running coverage in every matrix cell
    
    Co-authored-by: jodunk <jodunk@users.noreply.github.com>
  • docs: salvage focused stale PR contributions
    - add Vite and Redis pattern skills from closed stale PRs
    
    - add frontend-slides support assets
    
    - port skill-comply runner fixes and LLM prompt/provider regressions
    
    - harden agent frontmatter validation and sync catalog counts
  • fix: sync skill frontmatter and catalog counts
    Adds missing skill frontmatter, normalizes strict YAML metadata, syncs README catalog counts, and extends catalog validation for README/plugin/marketplace count drift.
  • fix(ci): flag SKILL.md frontmatter defects in validate-skills (#1669)
    * fix(ci): flag SKILL.md frontmatter defects in validate-skills
    
    Issue #1663 reported two SKILL.md frontmatter defects (missing `name:`
    on skill-stocktake; literal block-scalar `description: |-` on
    openclaw-persona-forge) that PR #1664 addresses at the data level.
    
    This change is complementary: it extends `scripts/ci/validate-skills.js`
    to catch the same class of defect statically going forward, so the
    frontmatter-vs-renderer problems do not silently reappear as new skills
    land.
    
    ## Checks added
    - Frontmatter must declare a `name:` field.
    - Frontmatter `description:` must not use a literal block scalar
      (`|` / `|-` / `|+`) — these preserve internal newlines and break
      flat-table renderers keyed off `description`. Folded (`>`) and inline
      strings are accepted.
    
    ## Behavior
    - Frontmatter findings default to WARN (exit 0) so this PR does not
      break CI while the two known offenders are still on main. Pass
      `--strict` or set `CI_STRICT_SKILLS=1` to promote them to ERROR
      (exit 1). Structural findings (missing / empty SKILL.md) remain
      errors as before.
    - Today against main, the validator reports exactly two warnings —
      the same two files called out in #1663 — and exits 0. When #1664
      lands, the validator reports zero warnings, at which point strict
      mode can be enabled in CI.
    
    ## Parser notes
    - Bespoke frontmatter parser mirrors the style of `validate-agents.js`
      (tolerant of UTF-8 BOM and CRLF; no new npm dependency).
    - Block-scalar continuation lines are skipped so keys inside a block
      scalar are not mistaken for top-level keys.
    - Hidden directories (`.something/`) under skills/ are now skipped.
    
    ## Tests
    Adds five focused tests to `tests/ci/validators.test.js`:
    - warns when frontmatter is missing `name` (default mode)
    - errors when frontmatter is missing `name` (--strict mode)
    - warns on literal block-scalar description (|-)
    - accepts folded (>) and inline descriptions under --strict
    - skips hidden directories under skills/
    
    ## Docs
    Adds two bullets to the `Skill Checklist` in CONTRIBUTING.md covering
    the two rules now surfaced by the validator.
    
    Refs #1663. Complements (does not compete with) #1664.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    
    * fix(ci): harden SKILL.md frontmatter checks after bot review
    
    Address findings from CodeRabbit, Greptile, and cubic on #1669:
    
    - Guard empty or whitespace-only `name:` values. Previously
      `name:    ` silently passed because the presence check only
      tested key-set membership; now inspectFrontmatter captures
      trimmed values and validate flags an explicit 'name is empty'
      WARN/ERROR.
    - Broaden block-scalar detection to cover YAML 1.2 indent
      indicators (`|2`, `|-2`, `>2-`) and trailing comments
      (`|-  # note`). The old regex required a bare `|`/`>` with
      optional `+`/`-`, which let valid-but-disallowed forms slip
      through.
    - Update CONTRIBUTING.md checklist to list `|+` alongside `|`
      and `|-` for parity with the validator.
    - Extend runSkillsValidator to accept env overrides and add four
      regression tests: empty name, |+ description, |-2 + comment, and
      CI_STRICT_SKILLS=1.
    
    * fix(ci): address round-2 review on validate-skills frontmatter
    
    - Tighten extractFrontmatter closing delimiter to require a newline or
      end-of-file after the closing `---`, so body lines beginning with
      `---text` are not parsed as frontmatter (CodeRabbit).
    - Strip both trailing and comment-only values in inspectFrontmatter, so
      `name: # todo` is surfaced as empty rather than silently passing
      (cubic P2).
    - Extract validateSkillDir helper so the per-directory validation
      block moves out of validateSkills, keeping both functions under the
      50-line guideline (CodeRabbit nit).
    - Hoist runSkillsValidator to module scope in the test harness and
      share the spawnSync import with execFileSync so the helper stops
      re-requiring child_process on every invocation (CodeRabbit nit).
    - Add regression tests: comment-only `name:` values must fail strict
      mode; `---trailing` body lines must not be parsed as frontmatter.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    
    * Update tests/ci/validators.test.js
    
    Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
  • fix(tests): resolve Windows CI test failures (#701)
    * fix(tests): skip bash tests on Windows and fix USERPROFILE in resolve-ecc-root
    
    - hooks.test.js: add SKIP_BASH guard for 8 bash-dependent tests
      (detect-project.sh, observe.sh) while keeping 207 Node.js tests running
    - resolve-ecc-root.test.js: add USERPROFILE to env overrides in 2
      INLINE_RESOLVE tests so os.homedir() resolves correctly on Windows
    
    Generated with [Claude Code](https://claude.ai/code)
    via [Happy](https://happy.engineering)
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    Co-Authored-By: Happy <yesreply@happy.engineering>
    
    * fix(tests): handle BOM in shebang stripping and skip worktree tests on Windows
    
    - validators.test.js: replace regex stripShebang with character-code
      approach that handles UTF-8 BOM before shebang line
    - detect-project-worktree.test.js: skip entire file on Windows since
      tests invoke bash scripts directly
    
    Generated with [Claude Code](https://claude.ai/code)
    via [Happy](https://happy.engineering)
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    Co-Authored-By: Happy <yesreply@happy.engineering>
    
    ---------
    
    Co-authored-by: Claude <noreply@anthropic.com>
    Co-authored-by: Happy <yesreply@happy.engineering>
  • fix: resolve Windows CI failures and markdown lint (#667)
    - Replace node -e with temp file execution in validator tests to avoid
      Windows shebang parsing failures (node -e cannot handle scripts that
      originally contained #!/usr/bin/env node shebangs)
    - Remove duplicate blank line in skills/rust-patterns/SKILL.md (MD012)
  • fix(ci): enforce catalog count integrity (#525)
    * fix(ci): enforce catalog count integrity
    
    * test: harden catalog structure parsing
  • test: cover session-end message.role path, getExecCommand non-string args, and legacy hooks format
    Round 80: Three previously untested conditional branches:
    - session-end.js: entry.message?.role === 'user' third OR condition
      (fires when type is not 'user' but message.role is)
    - package-manager.js: getExecCommand with truthy non-string args
      (typeof check short-circuits, value still appended via ternary)
    - validate-hooks.js: legacy array format parsing path (lines 115-135)
      with 'Hook N' error labels instead of 'EventType[N]'
  • test: cover countInFile/grepFile string patterns and validate-commands warnings suffix
    Round 79 — untested conditional branches in utils.js and validate-commands.js:
    - countInFile: exercise typeof pattern === 'string' branch with valid string
    - grepFile: exercise string pattern branch (not RegExp)
    - validate-commands: verify (N warnings) suffix in output when warnCount > 0
  • test: cover getSessionStats file-path read, hasContent field, and wrapped hooks format
    Round 78 — shifted from catch blocks to untested conditional branches:
    - getSessionStats: exercise looksLikePath → getSessionContent path (real .tmp file)
    - getAllSessions: verify hasContent true/false for non-empty vs empty files
    - validate-hooks: test wrapped { hooks: { PreToolUse: [...] } } production format
  • test: cover evaluate-session/suggest-compact main().catch and validate-hooks JSON parse
    - evaluate-session: main().catch when HOME is non-directory (ENOTDIR)
    - suggest-compact: main().catch double-failure when TMPDIR is non-directory
    - validate-hooks: invalid JSON in hooks.json triggers error exit
    
    Total tests: 831 → 834
  • test: cover cleanupAliases save failure, setAlias save failure, and validate-commands statSync catch
    Round 73: Add 3 tests for genuine untested code paths:
    - session-aliases cleanupAliases returns failure when save blocked after removing aliases
    - session-aliases setAlias returns failure when save blocked on new alias creation
    - validate-commands silently skips broken symlinks in skill directory scanning
  • test: cover setProjectPM save failure, deleteAlias save failure, hooks async/timeout validation
    Round 72: Add 4 tests for untested code paths (818 → 822):
    - package-manager.js: setProjectPackageManager wraps writeFile errors (lines 275-279)
    - session-aliases.js: deleteAlias returns failure when saveAliases fails (line 299)
    - validate-hooks.js: rejects non-boolean async field (line 28-31)
    - validate-hooks.js: rejects negative timeout value (lines 32-35)
  • test: add 3 tests for untested fallback/skip/failure paths (Round 70)
    - session-end.js: entry.name/entry.input fallback in direct tool_use entries
    - validate-commands.js: "would create:" regex alternation skip line
    - session-aliases.js: updateAliasTitle save failure with read-only dir
  • test: add 3 tests for evaluate-session regex, empty rules/skills dirs (Round 65)
    - evaluate-session.js: verify regex whitespace tolerance around colon
      matches "type" : "user" (with spaces), not just compact JSON
    - validate-rules.js: empty directory with no .md files yields Validated 0
    - validate-skills.js: directory with only files, no subdirectories yields
      Validated 0
    
    Total: 800 tests, all passing
  • test: add 3 CI validator tests for untested code paths (Round 63)
    - validate-hooks: object-format matcher missing matcher field (line 97-100)
    - validate-commands: readFileSync catch block for unreadable .md files (lines 56-62)
    - validate-commands: empty commands directory with no .md files (Validated 0)
    
    Total: 794 tests, all passing
  • test: add inline backtick ref, workflow whitespace, and code-only rule tests
    Round 52: Adds 3 CI validator tests — validates command refs
    inside inline backticks are checked (not stripped like fenced
    blocks), workflow arrows with irregular whitespace pass, and
    rule files containing only fenced code blocks are accepted.
  • test: add 17 tests for validators, hooks, and edge cases (Round 32)
    Coverage improvements:
    - validate-agents: empty frontmatter block, no-content frontmatter,
      partial frontmatter, mixed valid/invalid agents
    - validate-rules: directory with .md name (stat.isFile check),
      deeply nested subdirectory rules
    - validate-commands: 3-agent workflow chain, broken middle agent
    - post-edit-typecheck: spaces in paths, shell metacharacters, .tsx
    - check-console-log: git failure passthrough, large stdin
    - post-edit-console-warn: console.error only, null tool_input
    - session-end: empty transcript, whitespace-only transcript
    
    Total tests: 686 → 703
  • fix: use local-time Date constructor in session-manager to prevent timezone day shift
    new Date('YYYY-MM-DD') creates UTC midnight, which in negative UTC offset
    timezones (e.g., Hawaii) causes getDate() to return the previous day.
    Replaced with new Date(year, month - 1, day) for correct local-time behavior.
    
    Added 15 tests: session-manager datetime verification and edge cases (7),
    package-manager getCommandPattern special characters (4), and
    validators model/skill-reference validation (4). Tests: 651 → 666.
  • fix: reject empty/invalid array commands in hooks validator, add 19 tests
    validate-hooks.js: Empty arrays [] and arrays with non-string elements
    (e.g., [123, null]) passed command validation due to JS truthiness of
    empty arrays (![] === false). Added explicit length and element type
    checks.
    
    19 new tests covering: non-array event type values, null/string matcher
    entries, string/number top-level data, empty string/array commands,
    non-string array elements, non-string type field, non-number timeout,
    timeout boundary (0), unwrapped hooks format, legacy format error paths,
    empty agent directory, whitespace-only command files, valid skill refs,
    mixed valid/invalid rules and skills.
  • fix: reject whitespace-only command/field values in CI validators, add 10 tests
    validate-hooks.js: whitespace-only command strings now fail validation
    validate-agents.js: whitespace-only model/tools values now fail validation
  • fix: greedy regex in validate-commands captures all refs per line, add 18 tests
    The command cross-reference regex /^.*`\/(...)`.*$/gm only captured the
    LAST command ref per line due to greedy .* consuming earlier refs.
    Replaced with line-by-line processing using non-anchored regex to
    capture ALL command references.
    
    New tests:
    - 4 validate-commands multi-ref-per-line tests (regression)
    - 8 evaluate-session threshold boundary tests (new file)
    - 6 session-aliases edge case tests (cleanup, rename, path matching)
  • fix: add missing validation in renameAlias, add 6 tests
    renameAlias was missing length (>128), reserved name, and empty string
    validation that setAlias enforced. This inconsistency allowed renaming
    aliases to reserved names like 'list' or 'delete'.
    
    Also adds tests for:
    - renameAlias empty string, reserved name, and length limit
    - validate-skills whitespace-only SKILL.md rejection
    - validate-rules whitespace-only file and recursive subdirectory scan
  • fix: use valid model name in colon-in-values frontmatter test
    The test was using 'claude-sonnet-4-5-20250929' which isn't in VALID_MODELS
    (haiku/sonnet/opus). Use 'sonnet' with a description field containing
    colons to properly test colon handling in frontmatter values.
  • test: add 6 tests for command validation and session content verification
    - validate-commands: creates: line skipping, valid cross-refs, unclosed
      code blocks, valid workflow diagrams
    - session-end: backtick escaping in session files, tools/files in output
  • test: add regression tests for empty frontmatter field rejection
    Add 2 tests verifying validate-agents correctly rejects agents with
    empty model and empty tools values in YAML frontmatter.
  • fix: remove unused imports in test files (ESLint)
    - validators.test.js: remove unused execSync (only execFileSync used)
    - skill-create-output.test.js: remove unused path module
  • test: add cross-reference validation tests for validate-commands
    - Add runValidatorWithDirs() helper for multi-constant overrides
    - Test broken command references (e.g., /nonexistent-cmd)
    - Test broken agent path references (e.g., agents/fake-agent.md)
    - Test fenced code block exclusion (refs inside ``` are skipped)
    - Test broken workflow agent references (e.g., planner -> ghost-agent)
    - Total tests: 261 → 287 (+26)
  • fix: 3 bugs fixed, stdin encoding hardened, 37 CI validator tests added
    Bug fixes:
    - utils.js: glob-to-regex conversion now escapes all regex special chars
      (+, ^, $, |, (), {}, [], \) before converting * and ? wildcards
    - validate-hooks.js: escape sequence processing order corrected —
      \\\\ now processed before \\n and \\t to prevent double-processing
    - 6 hooks: added process.stdin.setEncoding('utf8') to prevent
      multi-byte UTF-8 character corruption at chunk boundaries
      (check-console-log, post-edit-format, post-edit-typecheck,
      post-edit-console-warn, session-end, evaluate-session)
    
    New tests (37):
    - CI validator test suite (tests/ci/validators.test.js):
      - validate-agents: 9 tests (real project, frontmatter parsing,
        BOM/CRLF, colons in values, missing fields, non-md skip)
      - validate-hooks: 13 tests (real project, invalid JSON, invalid
        event types, missing fields, async/timeout validation, inline JS
        syntax, array commands, legacy format)
      - validate-skills: 6 tests (real project, missing SKILL.md, empty
        files, non-directory entries)
      - validate-commands: 5 tests (real project, empty files, non-md skip)
      - validate-rules: 4 tests (real project, empty files)
    
    Total test count: 228 (up from 191)