diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..1449925 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,25 @@ +version: 2 +updates: + # Keep the commit-SHA pins in .github/workflows current. + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + groups: + actions: + patterns: ["*"] + + - package-ecosystem: npm + directory: /skill-harness + schedule: + interval: weekly + groups: + # One PR per week for all harness dependencies; a failing suite is + # the signal that a bump needs a human. + harness: + patterns: ["*"] + ignore: + # The harness asserts against a byte-pinned validator bundle built for + # this zod major; a major bump is a deliberate re-vendor, not a bot PR. + - dependency-name: zod + update-types: ["version-update:semver-major"] diff --git a/.github/workflows/skill-harness.yml b/.github/workflows/skill-harness.yml new file mode 100644 index 0000000..8b4a47f --- /dev/null +++ b/.github/workflows/skill-harness.yml @@ -0,0 +1,80 @@ +# Skill-harness CI (see #33). Offline checks only: the live bench +# (`pnpm bench`) calls a model API and is deliberately not run here. +name: skill-harness + +on: + pull_request: + push: + branches: [main] + +# Read-only token. No step needs secrets or write access, so fork PRs run +# with the exact same grants as same-repo PRs. +permissions: + contents: read + +# One run per ref. A newer push to a PR cancels that PR's older run; pushes +# to main are never cancelled, so every main commit keeps its own verdict. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +defaults: + run: + working-directory: skill-harness + +jobs: + check: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + # The digest generator imports only node: builtins, so it runs on the + # runner's default Node before any toolchain setup. Putting it first + # means a stale digest is reported even if the install below fails. + - name: Schema digest is in sync + working-directory: . + run: node scripts/generate-schema-digest.mjs --check + + # pnpm version comes from `packageManager` in skill-harness/package.json. + # Do not add a `version:` input here: the action errors when both are + # set and disagree, and one source of truth is the point. + - uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10 + with: + package_json_file: skill-harness/package.json + + # Node version comes from `engines.node` in the same package.json. + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version-file: skill-harness/package.json + cache: pnpm + cache-dependency-path: skill-harness/pnpm-lock.yaml + + - name: Install (frozen lockfile) + id: install + run: pnpm install --frozen-lockfile + + # The checks below run independently once install succeeds, so a + # single run reports every failure rather than stopping at the first. + + # A frozen install must not want to rewrite the lockfile or the + # workspace file; if it does, the committed files are out of date. + - name: Lockfile is stable + if: ${{ !cancelled() && steps.install.conclusion == 'success' }} + working-directory: . + run: git diff --exit-code -- skill-harness/pnpm-lock.yaml skill-harness/pnpm-workspace.yaml + + - name: Test + if: ${{ !cancelled() && steps.install.conclusion == 'success' }} + run: pnpm test + + - name: Biome check + if: ${{ !cancelled() && steps.install.conclusion == 'success' }} + run: pnpm biome:check + + - name: Typecheck + if: ${{ !cancelled() && steps.install.conclusion == 'success' }} + run: pnpm typecheck diff --git a/CLAUDE.md b/CLAUDE.md index 59a6465..1cf7e17 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -22,7 +22,7 @@ If you add a second plugin to the marketplace later, the same rule applies: vers Production Claude Code caches only each skill's `SKILL.md` in the system prompt; a skill's `references/` directory is **not** auto-loaded for real users. Anything a policy/skill author needs at authoring time must live inline in `SKILL.md`, not in a sidecar file. -The `dtwo-gateway-config` skill's `### Schema Digest` (between `` / ``) is **generated** from `dtwo/skills/dtwo-gateway-config/schema-reference.json` — do not hand-edit it. Regenerate with `node scripts/generate-schema-digest.mjs`; `--check` fails if it's stale, and the `skill-harness` suite runs exactly that, so `pnpm test` is what enforces it. The vendored schema is a verbatim copy of the artifact the product repo's schema generator emits; refresh it by copying, never by editing in place. +The `dtwo-gateway-config` skill's `### Schema Digest` (between `` / ``) is **generated** from `dtwo/skills/dtwo-gateway-config/schema-reference.json` — do not hand-edit it. Regenerate with `node scripts/generate-schema-digest.mjs`; `--check` fails if it's stale; the `skill-harness` suite runs exactly that, and CI (`.github/workflows/skill-harness.yml`) runs both the `--check` and the suite on every push to `main` and every PR. The vendored schema is a verbatim copy of the artifact the product repo's schema generator emits; refresh it by copying, never by editing in place. ## Test locally before pushing @@ -35,6 +35,8 @@ The `dtwo-gateway-config` skill's `### Schema Digest` (between `