64 Commits

  • Merge pull request #2241 from itkdm/feat/add-vue-ecosystem
    feat: add Vue ecosystem review support (vue-reviewer agent, /vue-review command, vue-patterns skill). Duplicate rules/vue/* kept from #2250; catalog counts reconciled.
  • fix: prevent IOC scanner false positives on hook filenames and scan .cursor configs (#2245)
    * fix: prevent IOC scanner false positives on hook filenames and scan .cursor configs
    
    The supply-chain IOC scanner matched CRITICAL_TEXT_INDICATORS with plain
    substring search, so legitimate hook filenames that merely end with a known
    payload name (e.g. the stock Cursor hook before-shell-execution.js vs the
    payload execution.js) were flagged as CRITICAL. Indicator matching now
    requires a non-filename character before the match.
    
    Also add .cursor/ to the special config paths so Cursor hooks.json files
    (a known persistence vector already listed in PERSISTENCE_FILENAMES) are
    actually inspected in normal checkouts - previously they were only scanned
    by accident when the repo path happened to contain /.claude/.
    
    * test: cover underscore-prefixed filenames in IOC boundary suppression
    
    Make explicit that '_' is treated as a filename word character, so
    snake_case hook names like post_execution.js are intentionally not
    flagged by the execution.js indicator (real payload references appear
    after '/', quotes, or whitespace).
  • Add React language track with agents, skills, rules, and commands (#2024)
    * feat(rules): add rules/react/ track
    
    Five rule files mirroring per-language convention (coding-style,
    hooks, patterns, security, testing). Each has `paths:` glob
    frontmatter for auto-activation when editing matching files.
    
    - coding-style.md: file extensions, naming, JSX, RSC boundary
    - hooks.md: React hooks (NOT Claude Code hooks) — rules-of-hooks,
      dep arrays, cleanup, memoization, React 19 additions
    - patterns.md: container/presentational split, state location
      decision tree, Suspense + error boundaries, forms, data fetching
    - security.md: dangerouslySetInnerHTML, unsafe URL schemes,
      server-action validation, env-var leaks, CSP
    - testing.md: RTL queries, userEvent, async, MSW, axe, anti-patterns
    
    Each file extends typescript/* and common/* rules.
    
    * feat(skills): add react-patterns, react-testing, react-performance
    
    Three new skills under skills/ following the SKILL.md convention.
    
    - react-patterns: React 18/19 idioms — hooks discipline, state
      location decision tree, server/client component boundary,
      Suspense + error boundaries, form actions (React 19), data
      fetching matrix, composition recipes, accessibility-first.
    - react-testing: React Testing Library + Vitest/Jest, query
      priority order, userEvent, MSW network mocking, axe a11y
      assertions, RTL vs Playwright CT boundary, TDD workflow.
    - react-performance: 70-rule performance ruleset adapted from
      Vercel Labs react-best-practices (MIT) across 8 priority
      categories — waterfalls, bundle size, server-side, client
      fetch, re-render, rendering, JS micro, advanced patterns.
      Includes Lighthouse / Web Vitals mapping and attribution to
      upstream.
    
    Cross-links between the three skills and out to frontend-patterns,
    accessibility, e2e-testing, tdd-workflow.
    
    * feat(agents): add react-reviewer and react-build-resolver
    
    Two new agents covering React-specific code review and build error
    resolution, plus matching .kiro/ mirrors and a routing pointer
    edit on typescript-reviewer.
    
    - react-reviewer: slim React-only lanes (hooks rules,
      dangerouslySetInnerHTML, unsafe URL schemes, key prop, state
      mutation, derived-state-in-effect, server/client component
      boundary, accessibility, render performance, Server Action
      validation, env-var leaks). Explicitly delegates generic
      TypeScript/async/Node concerns to typescript-reviewer. Both
      agents should be invoked together on .tsx/.jsx PRs.
    - react-build-resolver: React build/bundler/runtime hydration
      failures across Vite, webpack, Next.js, CRA, Parcel, esbuild,
      Bun, Rsbuild. Handles JSX/TSX compile errors, tsconfig fixes,
      Next.js App Router server/client boundary errors, hydration
      mismatches, duplicated React copies, Tailwind/PostCSS pipeline.
    - .kiro/agents/react-reviewer.json + react-build-resolver.json:
      Kiro IDE format mirrors following the per-language precedent.
    - typescript-reviewer: routing pointer added to its MEDIUM React
      block — defers to /react-review for React-specific concerns
      while keeping its block as fallback for repos that only invoke
      typescript-reviewer.
    
    All agents carry the standard Prompt Defense Baseline stanza.
    
    * feat(commands): add /react-review /react-build /react-test
    
    Three new slash commands invoking the React agents.
    
    - /react-review: invokes react-reviewer. Documents the routing
      rule with typescript-reviewer — both should run together on
      TSX/JSX PRs. Lists CRITICAL/HIGH/MEDIUM rule categories and
      the automated checks (eslint with react-hooks + jsx-a11y,
      tsc --noEmit, npm audit).
    - /react-build: invokes react-build-resolver. Documents bundler
      detection, common failure patterns, fix strategy, and stop
      conditions.
    - /react-test: enforces TDD with React Testing Library + Vitest
      or Jest, behavior-focused queries, userEvent + MSW patterns,
      axe accessibility assertions, coverage targets.
    
    Each command file has the required description: frontmatter and
    follows the per-language command convention (cpp-test, go-test,
    kotlin-test, etc.).
    
    * chore: wire react track into manifests and stack mappings
    
    - agent.yaml: add react-patterns, react-performance, react-testing
      to the skills array; add react-build, react-review, react-test to
      the commands array (alphabetically inserted to satisfy the
      ci/agent-yaml-surface sync test).
    - config/project-stack-mappings.json: extend the `react` stack
      entry — add "react" to rules array (was ["common","typescript",
      "web"]); add react-patterns, react-performance, react-testing,
      accessibility to the skills array.
    - docs/COMMAND-REGISTRY.json: bump totalCommands 75 -> 78; add
      three new entries (react-build, react-review, react-test) with
      primaryAgents / allAgents / skills wiring. react-review's
      allAgents includes typescript-reviewer to reflect the dual-agent
      routing convention.
    - CLAUDE.md: add Skills-table row mapping *.tsx / *.jsx /
      components/** to react-patterns + react-testing skills and
      the /react-review, /react-build, /react-test commands.
    
    * chore(catalog): sync counts to 62 agents / 78 commands / 235 skills
    
    Auto-generated via `node scripts/ci/catalog.js --write --text`
    after the react track additions:
    
    - 2 new agents: react-reviewer, react-build-resolver (60 -> 62)
    - 3 new commands: react-build, react-review, react-test (75 -> 78)
    - 3 new skills: react-patterns, react-performance, react-testing
      (232 -> 235)
    
    Files updated by the catalog sync:
    - .claude-plugin/plugin.json description string
    - .claude-plugin/marketplace.json plugin description
    - README.md quick-start summary, project tree, feature parity tables
    - README.zh-CN.md quick-start summary
    - AGENTS.md project structure summary
    - docs/zh-CN/README.md parity table
    - docs/zh-CN/AGENTS.md project structure summary
    
    All counts now match the filesystem catalog (verified by
    ci/catalog.test.js).
    
    * feat(kiro): add react agent markdown companions to JSON entries
    
    * feat(kiro): add react skills into manifests
    
    * fix(ci): sync catalog counts, registry, and package files for react track
    
    - .claude-plugin/{plugin,marketplace}.json: bump description counts to 62/235/78
    - docs/COMMAND-REGISTRY.json: regenerate to include quality-gate and react commands
    - package.json: add skills/react-{patterns,performance,testing}/ to files allowlist so npm-publish-surface aligns with install-modules manifest
    
    * fix(react): address PR #2024 review feedback
    
    Critical:
    - Remove undefined/.claude/session-aliases.json containing __proto__ prototype-pollution
      fixture committed by accident in a7333c14
    
    High:
    - agents/react-build-resolver.md: replace brittle `test -o $(grep -l ...)` and
      `test -a -n $(grep ...)` detection with explicit `{ ... || grep -q ...; }` so
      bundler detection no longer breaks when grep returns empty
    - agents/react-build-resolver.md: drop hardcoded `npm i react@^19 react-dom@^19`
      remediation; replace with version-agnostic pair-upgrade note that honors the
      project's installed major (17/18/19) — surgical fix principle
    - commands/react-review.md: guard `tsc --noEmit -p tsconfig.json` with
      `[ -f tsconfig.json ] &&` so the review skips cleanly on JS-only projects
    
    Medium:
    - rules/react/security.md: correct the React-18-blocks-javascript-URL claim
      (React only warns in dev; production navigation is not blocked)
    - rules/react/security.md: correct CRA env-var exposure row (CRA exposes
      REACT_APP_*, NODE_ENV, PUBLIC_URL — not 'all' variables)
    - skills/react-testing/SKILL.md: instantiate QueryClient once outside the
      wrapper closure so React Query cache survives re-renders (flaky-test fix)
    - skills/react-testing/SKILL.md: restore console.error spy with mockRestore()
      in a try/finally so the mock does not leak across tests
    - commands/react-test.md: switch outer example-session fence to 4 backticks
      so the inner ```tsx/```bash blocks don't prematurely terminate it
    
    * fix(kiro): mirror react-build-resolver react 19 conditional remediation
    
    Discussion r3272907106 flagged the kiro json variant still carrying the hardcoded
    'npm i react@^19 react-dom@^19' line that the .md companion already dropped.
    Replace with the same conditional, version-agnostic guidance so both variants
    stay in sync.
    
    * fix(react): bump react-build example session fence to 4 backticks
    
    Discussion r3272907144 flagged the same nested-fence issue in
    commands/react-build.md that we fixed earlier in commands/react-test.md.
    The outer triple-backtick text block was being prematurely terminated by
    the inner bash/tsx fences inside the Example Session.
    
    * fix(react): bump react-review example usage fence to 4 backticks
    
    Discussion r3272907201 flagged the same nested-fence issue in
    commands/react-review.md. The outer triple-backtick text block was
    being prematurely terminated by the inner tsx/ts fences inside the
    Example Usage transcript.
    
    * fix(docs): clarify commands row as legacy shims in feature parity table
    
    Discussion r3272912003: README comparison table said 'PASS: 78 commands'
    while the install-section and quick-start prose use 'legacy command shims'.
    Aligned the comparison-table cell to 'PASS: 78 commands (legacy shims)' so
    the count word survives the catalog-validator regex while making the legacy
    nature explicit.
    
    Widened the catalog comparison-table commands regex to tolerate an optional
    parenthetical after the count word, so both the existing 'X commands' and
    the new 'X commands (legacy shims)' phrasings validate without breaking
    older READMEs/translations.
    
    * Update rules/react/security.md
    
    Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
    
    * fix(react): guard tsc in react-build-resolver diagnostic commands
    
    Discussion r3288910205: the agent prompt instructed an unconditional
    'tsc --noEmit -p tsconfig.json', which adds noise (or hard-fails) on
    JavaScript-only projects with no tsconfig.json or no installed TypeScript.
    
    Replaced with 'test -f tsconfig.json && npx --yes tsc --noEmit -p tsconfig.json'
    in both variants:
    - agents/react-build-resolver.md
    - .kiro/agents/react-build-resolver.json (prompt string mirrored)
    
    Mirrors the same guard already applied to commands/react-review.md in de135f61.
    
    * fix(react): pin tsc resolution to local install in build resolver
    
    Discussion r3289054157: previous fix used 'npx --yes tsc' which auto-installs
    the latest TypeScript from npm when none is local, producing version drift
    and non-reproducible typecheck results across machines.
    
    Switched to 'npx --no-install tsc' in both variants so the diagnostic uses
    only the project's pinned TypeScript and fails fast if it isn't installed:
    - agents/react-build-resolver.md
    - .kiro/agents/react-build-resolver.json (prompt string mirrored)
    
    * feat(counts): resolve counts for agents, skills...
    
    * fix(ci): regen command registry for golang-testing entry
    
    Removes stale kotlin-patterns entry to satisfy command-registry:check.
    
    * fix: keep local Claude settings out of React track PR
    
    ---------
    
    Co-authored-by: AlexisLeDain <a.ledain@docoon.com>
    Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
    Co-authored-by: Affaan Mustafa <affaan@dcube.ai>
  • fix(ci): cover other widely-cited invisible code points in check-unicode-safety
    Extend `isDangerousInvisibleCodePoint` with five additional code
    points / ranges that are routinely cited in invisible-character
    smuggling references but were not in the previous denylist:
    
    - **U+180E** MONGOLIAN VOWEL SEPARATOR. Formerly classified as a
      space separator (Zs) until Unicode 6.3 reclassified it as Cf
      (Format control). Renders as zero-width; widely abused for
      homograph attacks and prompt smuggling.
    
    - **U+115F** HANGUL CHOSEONG FILLER and **U+1160** HANGUL JUNGSEONG
      FILLER. Zero-width fillers used in Korean text shaping. Both are
      cited as common LLM-injection vectors in Korean / multilingual
      threat models.
    
    - **U+2061–U+2064** invisible math operators (FUNCTION APPLICATION,
      INVISIBLE TIMES, INVISIBLE SEPARATOR, INVISIBLE PLUS). Zero-width
      and only meaningful inside math typesetting. No legitimate
      Markdown or source code uses them.
    
    - **U+3164** HANGUL FILLER. Reported in real-world Discord and
      Twitter smuggling incidents; not used in legitimate Korean text.
    
    Reproduced before this commit: a file containing any one of these
    code points passed `check-unicode-safety.js` silently.
    
    After this commit each one is reported as
    `dangerous-invisible U+<HEX>` and `--write` mode strips it.
    
    Verified by writing 8 single-character probe files
    (`probe-0x180E.md`, `probe-0x115F.md`, …) and confirming exit=1 with
    each violation listed.
    
    ECC repo self-scan reports only the pre-existing `U+2605` BLACK
    STAR warnings (unchanged) and exits with the same status (no new
    in-repo violations introduced). Existing 5 unicode-safety tests
    still pass; `yarn lint` clean.
    
    Regression coverage for both the previous commit's Tag block fix
    and this commit's additions lands in the next commit.
  • fix(ci): cover Unicode Tag block (U+E0000–U+E007F) in check-unicode-safety
    `isDangerousInvisibleCodePoint` enumerated seven ranges of invisible/
    bidi/variation-selector code points but omitted the Unicode Tag block
    (U+E0000–U+E007F). Tag characters were proposed for language tagging
    in Unicode 3.1 and have been deprecated since Unicode 5.1, so no
    legitimate text uses them. They are the canonical vector for
    "ASCII Smuggling" / "Tag Smuggling" LLM prompt injection: an attacker
    hides instructions inside an ASCII-looking string, the model reads
    the tag bytes, the human reviewer sees nothing. Demonstrated against
    multiple LLM assistants during 2024–2025.
    
    `check-unicode-safety.js` is the repo's last line of defence before
    contributor content reaches agent context; the same script also runs
    in `--write` auto-sanitize mode on `.md` / `.mdx` / `.txt`. Today it
    silently passes tag-block characters through unchanged in both
    detection mode and `--write` mode.
    
    Reproduced before this commit:
    
      $ mkdir -p /tmp/uni-test && node -e "
          const fs = require('fs');
          const hidden = [...Array(5)].map((_,i) =>
            String.fromCodePoint(0xE0041 + i)).join('');
          fs.writeFileSync('/tmp/uni-test/innocent.md',
            '# Title\\n\\nBenign text' + hidden + ' more.\\n');"
    
      $ ECC_UNICODE_SCAN_ROOT=/tmp/uni-test \
          node scripts/ci/check-unicode-safety.js
      Unicode safety check passed.
      $ echo $?
      0
    
    Expected: tag-block characters reported as `dangerous-invisible`
    violations (exit 1) and stripped under `--write`.
    Actual: validator passes, `--write` leaves the bytes intact.
    
    Fix: extend the denylist with one new range
    `(codePoint >= 0xE0000 && codePoint <= 0xE007F)`. The change is
    purely additive; the existing seven ranges are untouched.
    
    After this commit the same reproduction returns:
    
      $ ECC_UNICODE_SCAN_ROOT=/tmp/uni-test \
          node scripts/ci/check-unicode-safety.js
      Unicode safety violations detected:
      innocent.md:3:12 dangerous-invisible U+E0041
      innocent.md:3:14 dangerous-invisible U+E0042
      innocent.md:3:16 dangerous-invisible U+E0043
      innocent.md:3:18 dangerous-invisible U+E0044
      innocent.md:3:20 dangerous-invisible U+E0045
      exit=1
    
    `--write` mode also strips the bytes (verified: file length 47 → 42
    after sanitize, regex `/[\u{E0000}-\u{E007F}]/u` no longer matches).
    
    Existing 5 unicode-safety tests still pass; `yarn lint` clean. The
    ECC repo's own self-scan (`node scripts/ci/check-unicode-safety.js`
    with no `ECC_UNICODE_SCAN_ROOT`) reports the same warnings as before
    this commit and exits with the same status (no regressions on
    in-repo content).
    
    A handful of other widely-cited invisible code points are missing
    from the denylist (`U+180E`, `U+115F`, `U+1160`, `U+2061–U+2064`,
    `U+3164`); those are addressed in the next commit so each fix
    remains independently reviewable. Regression coverage for both
    fixes lands two commits later.
  • fix(ci): match quoted write-all + dedupe duplicate checkout violations
    Two round-1 review findings, fixed together because they touch the
    same regex/loop region of `findViolations`:
    
    1. **cubic P0 — quoted write-all bypass**.
       `WRITE_ALL_PATTERN` was `/^\s*permissions:\s*write-all\b/m`, which
       does not match the perfectly valid YAML forms
       `permissions: "write-all"` and `permissions: 'write-all'`. A
       workflow that quoted the shorthand slipped right through the
       persist-credentials gate the previous commit was supposed to close.
    
       Reproduced before this commit:
         $ cat /tmp/q.yml
         name: bad
         on: [push]
         permissions: "write-all"
         jobs:
           do:
             runs-on: ubuntu-latest
             steps:
               - uses: actions/checkout@v4
         $ ECC_WORKFLOWS_DIR=/tmp node scripts/ci/validate-workflow-security.js
         Validated workflow security for 1 workflow files
         exit=0
    
       Fix: tighten the regex to
         /^\s*permissions:\s*["']?write-all["']?\s*$/m
       which accepts the bare, double-quoted, and single-quoted YAML forms
       while still anchoring on the `permissions:` key. The trailing `\s*$`
       prevents accidentally matching keys whose value happens to start
       with `write-all` (e.g. some future literal `write-all-something`).
    
    2. **greptile P2 — duplicate violation when both patterns match**.
       A `ref: refs/pull/${{ github.event.pull_request.head.sha }}/merge`
       value matches both the `pull_request_target` rule's
       `expressionPattern` (the `head.sha` interpolation) and its
       `refPattern` (the `refs/pull/` literal). Each push generates an
       ERROR line with the same description and just a different
       `expression:` echo, so the reviewer sees the same violation twice.
    
       Fix: track `stepFlagged` inside the per-step loop and skip the
       `refPattern` fallback once any `expressionPattern` match has already
       produced a violation for this step. The `refPattern` is a fallback
       for ref-only forms (`refs/pull/123/head`, `${{ env.X }}` whose
       resolved value is a PR ref); when the more specific expression
       already fires, the fallback is redundant by definition.
    
    After both fixes, the round-1 reproductions resolve cleanly:
    
      $ # quoted form now blocks
      $ ECC_WORKFLOWS_DIR=/tmp/q1/.github/workflows node scripts/ci/validate-workflow-security.js
      ERROR: quoted.yml:8 - workflows with write permissions must disable checkout credential persistence
      exit=1
    
      $ # combined head.sha + refs/pull now prints one ERROR, not two
      $ ECC_WORKFLOWS_DIR=/tmp/q2/.github/workflows node scripts/ci/validate-workflow-security.js
      ERROR: dup.yml:10 - pull_request_target must not checkout an untrusted pull_request head ref/repository
        Unsafe expression: ${{ github.event.pull_request.head.sha }}
      exit=1
    
    Test additions land in the next commit.
  • fix(ci): flag refs/pull checkouts under pull_request_target
    The `pull_request_target` rule's `expressionPattern` matches only
    the canonical `github.event.pull_request.head.{ref,sha,repo.full_name}`
    interpolations. It does not match the second canonical form of
    the same exploit — fetching `refs/pull/<N>/{head,merge}` directly:
    
      - uses: actions/checkout@v4
        with:
          ref: refs/pull/${{ github.event.pull_request.number }}/merge
    
    The merge-ref variant is what GitHub's own security guidance calls
    out as the highest-severity privilege-escalation pattern under
    `pull_request_target`: it materialises the PR's merge commit
    (attacker code spliced with base), executes inside a workflow that
    has full repo-scoped tokens, and gives the attacker the chance to
    exfiltrate secrets or push to default branches. `refs/pull/N/head`
    is functionally equivalent — same source, same trust boundary.
    
    Reproduced on `main` before this commit:
    
      $ cat /tmp/bad.yml
      name: bad
      on: { pull_request_target: { types: [opened] } }
      permissions: { contents: read }
      jobs:
        do:
          runs-on: ubuntu-latest
          steps:
            - uses: actions/checkout@v4
              with:
                ref: refs/pull/${{ github.event.pull_request.number }}/merge
                persist-credentials: false
            - run: npm ci --ignore-scripts
    
      $ ECC_WORKFLOWS_DIR=/tmp node scripts/ci/validate-workflow-security.js
      Validated workflow security for 1 workflow files
      $ echo $?
      0
    
    Expected: violation flagging the refs/pull checkout under pull_request_target.
    Actual: passes silently.
    
    Fix: add a `refPattern` to the `pull_request_target` rule:
    
        /^\s*ref:\s*['"]?[^'"\n]*refs\/(?:remotes\/)?pull\/[^'"\n\s]+/m
    
    and apply it per checkout step inside the existing
    event-gated loop. The pattern matches the ref VALUE so it catches
    all interpolation shapes — `refs/pull/123/head`,
    `refs/pull/${{ github.event.pull_request.number }}/merge`,
    `${{ env.FOO }}/refs/pull/N/head` — without enumerating the
    possible interpolations themselves.
    
    Scoping: the rule is already gated on the workflow containing
    `pull_request_target:`, so non-privileged `pull_request` workflows
    that legitimately check out a PR ref are not affected.
    
    After this commit the reproduction above exits 1 with:
    
      ERROR: bad.yml:10 - pull_request_target must not checkout an untrusted pull_request head ref/repository
    
    Three new regression tests in `tests/ci/validate-workflow-security.test.js`:
      - rejects pull_request_target + refs/pull/<N>/merge
      - rejects pull_request_target + hardcoded refs/pull/<N>/head
      - allows pull_request_target with no `with.ref:` (base-ref checkout —
        the safe pattern from GitHub's own guidance)
    
    Test count: 17 → 20 in this file; full `yarn test` still green.
    
    Together with the previous commit, this closes the two
    independent `validate-workflow-security.js` bypasses I found.
  • fix(ci): treat 'permissions: write-all' as a write-permission gate
    `WRITE_PERMISSION_PATTERN` in `validate-workflow-security.js`
    enumerates named GitHub Actions scopes (`contents: write`,
    `issues: write`, etc.) to decide whether a workflow needs to:
      - disable `persist-credentials` on `actions/checkout`
      - pass `--ignore-scripts` to `npm ci`
    
    The pattern misses the top-level shorthand `permissions:
    write-all`, which is the strictly broader form — it grants every
    named scope write access in a single line. As a result, a
    workflow that opts into write-all currently slips both gates.
    
    Reproduced on `main` before this commit:
    
      $ cat /tmp/bad.yml
      name: bad
      on: [push]
      permissions: write-all
      jobs:
        do:
          runs-on: ubuntu-latest
          steps:
            - uses: actions/checkout@v4
            - run: npm ci
    
      $ ECC_WORKFLOWS_DIR=/tmp node scripts/ci/validate-workflow-security.js
      Validated workflow security for 1 workflow files
      $ echo $?
      0
    
    Expected: at least two violations (missing `persist-credentials:
    false`, missing `--ignore-scripts`).
    Actual: passes silently.
    
    Fix: add a sibling pattern `WRITE_ALL_PATTERN` that matches
    `^\s*permissions:\s*write-all\b` and OR it with
    `WRITE_PERMISSION_PATTERN` at the single gate. Both top-level
    and job-level `permissions:` blocks satisfy the `^\s*` prefix.
    
    After this commit the reproduction above exits 1 with:
    
      ERROR: bad.yml:8 - workflows with write permissions must disable checkout credential persistence
      ERROR: bad.yml:9 - workflows with write permissions must install npm dependencies with --ignore-scripts
    
    Three new regression tests in `tests/ci/validate-workflow-security.test.js`:
      - rejects write-all + credential-persisting checkout
      - rejects write-all + `npm ci` without `--ignore-scripts`
      - allows write-all when both gates are satisfied (no over-block)
    
    Test count: 14 → 17 in this file; full `yarn test` still green.
    
    A separate `refs/pull/N/merge` bypass under `pull_request_target`
    exists in the same validator and is fixed in the next commit.
  • 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: add supply-chain incident response playbook
    Add a repo-level supply-chain incident response playbook for npm/GitHub Actions package-registry incidents, anchored on the May 2026 TanStack compromise and prior Shai-Hulud-style npm incidents.
    
    - add `docs/security/supply-chain-incident-response.md` with exposure checks, immediate response steps, workflow rules, publication rules, and escalation triggers
    - link the playbook from `SECURITY.md`
    - reject `pull_request_target` workflows that restore or save shared dependency caches
    - add a regression test for the new `pull_request_target + actions/cache` guardrail
    
    Validation:
    - node tests/ci/validate-workflow-security.test.js (12 passed, 0 failed)
    - node scripts/ci/validate-workflow-security.js (validated 7 workflow files)
    - npx markdownlint-cli 'SECURITY.md' 'docs/security/supply-chain-incident-response.md'
    - npx markdownlint-cli '**/*.md' --ignore node_modules
    - git diff --check
    - node tests/run-all.js (2377 passed, 0 failed)
    - GitHub CI for #1848 green across Ubuntu, Windows, and macOS
    
    No release, tag, npm publish, plugin tag, marketplace submission, or announcement was performed.
  • ci: require npm audit signature checks
    Require npm registry signature verification wherever workflow npm audit checks run.
    
    - add npm audit signatures to CI Security Scan and maintenance security audit jobs
    - teach the workflow security validator to reject npm audit without signature verification
    - keep the repair and Copilot prompt tests portable across Windows path/case and CRLF frontmatter behavior
    
    Validation:
    - node tests/run-all.js (2376 passed, 0 failed)
    - CI current-head matrix green on #1846
  • feat: add GitHub Copilot prompt support
    Adds GitHub Copilot VS Code instruction and prompt files for ECC workflows, with VS Code prompt frontmatter/settings aligned to current docs and tests covering the surface.
    
    Co-authored-by: Girish Kanjiyani <girish.kanjiyani5040@gmail.com>
    Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
  • ci: harden workflow install boundaries
    - run non-test workflow installs with npm ci --ignore-scripts where lifecycle scripts are not needed\n- reject plain npm ci in workflows with write permissions\n- reject actions/cache in id-token: write workflows to reduce OIDC publish cache-poisoning risk
  • 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: harden CI validators
    Ports personal-path validator hardening and quoted checkout detection onto current main.
  • 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: unblock unicode safety CI lint (#1017)
    * fix: unblock unicode safety CI lint
    
    * fix: unblock shared CI regressions
  • fix(ci): enforce catalog count integrity (#525)
    * fix(ci): enforce catalog count integrity
    
    * test: harden catalog structure parsing