diff --git a/.github/workflows/release-skills.yml b/.github/workflows/release-skills.yml index 57e1573..3cd55bd 100644 --- a/.github/workflows/release-skills.yml +++ b/.github/workflows/release-skills.yml @@ -5,6 +5,11 @@ on: branches: [main] paths: ['skills/**'] workflow_dispatch: + inputs: + ref: + description: "Branch or tag to release from (must be main)" + required: false + default: main permissions: contents: write @@ -17,6 +22,14 @@ jobs: skipped: ${{ steps.changelog.outputs.skipped }} version: ${{ steps.changelog.outputs.version }} steps: + - name: Require main branch + if: github.event_name == 'workflow_dispatch' + run: | + if [ "${{ github.ref_name }}" != "main" ]; then + echo "Releases must be run from the main branch (got '${{ github.ref_name }}')." + exit 1 + fi + - uses: actions/checkout@v4 with: token: ${{ secrets.IDEE_GH_TOKEN }} @@ -28,6 +41,9 @@ jobs: - run: npm ci + - name: Validate skills + run: npm run validate:skills + - name: Conventional Changelog Action id: changelog uses: TriPSs/conventional-changelog-action@v5 diff --git a/.github/workflows/validate-skills.yml b/.github/workflows/validate-skills.yml index 51d83f2..0e9f492 100644 --- a/.github/workflows/validate-skills.yml +++ b/.github/workflows/validate-skills.yml @@ -2,7 +2,13 @@ name: Validate Skills on: pull_request: - paths: ['skills/**'] + paths: + - 'skills/**' + - 'scripts/validate-skills.ts' + - 'package.json' + - 'package-lock.json' + - '.nvmrc' + - '.github/workflows/validate-skills.yml' jobs: validate: @@ -18,4 +24,13 @@ jobs: - run: npm ci - - run: npm run validate:skills -- --changed --base=origin/${{ github.base_ref }} + # Run against only changed skills when skills files are touched; fall back + # to full corpus validation when only tooling files changed, so validator + # regressions against existing skills are caught in the same PR. + - name: Validate skills + run: | + if git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -q '^skills/'; then + npm run validate:skills -- --changed --base=origin/${{ github.base_ref }} + else + npm run validate:skills + fi diff --git a/scripts/validate-skills.ts b/scripts/validate-skills.ts index 57f80fe..dff6e8e 100644 --- a/scripts/validate-skills.ts +++ b/scripts/validate-skills.ts @@ -207,7 +207,9 @@ const CONTENT_CHECKS: ContentCheck[] = [ /** * Returns the deduplicated list of top-level skill directory names that have - * changed relative to `base` (e.g. `origin/main`). + * changed relative to `base` (e.g. `origin/main`) and still exist on disk. + * Deleted skill directories are intentionally excluded — removing a skill is + * valid and requires no structural validation. */ function getChangedSkillDirs(base: string): string[] { const output = execSync(`git diff --name-only ${base}...HEAD`, { encoding: "utf8" }) @@ -219,7 +221,7 @@ function getChangedSkillDirs(base: string): string[] { .map((f) => f.split("/")[1]) .filter(Boolean) ), - ] + ].filter((dir) => fs.existsSync(path.join(SKILLS_DIR, dir))) } /**