feat(marketplace): list shotkit in the starter-series catalog (#55) #133
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| workflow_call: | |
| permissions: | |
| contents: read | |
| jobs: | |
| ci: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # 22 = engines.node floor + the version we publish against. | |
| # 24 = current Active LTS — verify ahead so the eventual bump is free. | |
| node-version: [22, 24] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Scan for secrets | |
| # Only run once across the matrix — gitleaks reads the repo, not Node. | |
| if: matrix.node-version == 22 | |
| env: | |
| # Bump together; checksum from | |
| # https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_checksums.txt | |
| GITLEAKS_VERSION: 8.30.1 | |
| GITLEAKS_SHA256: 551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb | |
| run: | | |
| set -euo pipefail | |
| curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" -o /tmp/gitleaks.tgz | |
| echo "${GITLEAKS_SHA256} /tmp/gitleaks.tgz" | sha256sum -c - | |
| tar xz -C /tmp -f /tmp/gitleaks.tgz | |
| /tmp/gitleaks detect --source . --verbose --redact | |
| - name: Check for large files | |
| if: matrix.node-version == 22 | |
| run: | | |
| LARGE=$(find . -not -path './.git/*' -not -path './node_modules/*' -type f -size +5M) | |
| if [ -n "$LARGE" ]; then | |
| echo "::error::Large files detected (>5 MB):" | |
| echo "$LARGE" | |
| exit 1 | |
| fi | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ matrix.node-version }} | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci --ignore-scripts | |
| - name: Verify package-lock.json is in sync with package.json | |
| if: matrix.node-version == 22 | |
| run: | | |
| # Common Dependabot footgun: package.json edited without a matching | |
| # lockfile update (or vice versa). `npm install --package-lock-only` | |
| # rewrites package-lock.json from package.json without touching | |
| # node_modules; if it produces a diff, the two were out of sync. | |
| npm install --package-lock-only --ignore-scripts | |
| if ! git diff --exit-code -- package-lock.json; then | |
| echo "::error::package-lock.json is out of sync with package.json." | |
| echo "Run 'npm install' locally and commit the updated lockfile." | |
| exit 1 | |
| fi | |
| - name: Check licenses | |
| if: matrix.node-version == 22 | |
| run: npx --yes license-checker --failOn "GPL-2.0;GPL-3.0;AGPL-3.0" | |
| - name: Verify EN/KO docs heading parity | |
| if: matrix.node-version == 22 | |
| # Cheap structural check: same number of "## " sections in README.md | |
| # and README.ko.md, same in docs/graduation-from-vibe-coding{,.ko}.md. | |
| # We count only "^## " (h2 with space) to avoid matching shell | |
| # comments inside ```bash``` blocks. Doesn't validate translation | |
| # quality — just catches one-sided additions, which is the most | |
| # common drift mode. | |
| run: | | |
| set -euo pipefail | |
| check_parity() { | |
| local en="$1" ko="$2" | |
| local en_n ko_n | |
| en_n=$(grep -cE '^## ' "$en" || true) | |
| ko_n=$(grep -cE '^## ' "$ko" || true) | |
| if [ "$en_n" != "$ko_n" ]; then | |
| echo "::error file=$ko::Heading count drift: $en has $en_n h2 sections, $ko has $ko_n. One side added or removed a section." | |
| return 1 | |
| fi | |
| echo " $en ↔ $ko: $en_n h2 sections (parity OK)" | |
| } | |
| check_parity README.md README.ko.md | |
| check_parity docs/graduation-from-vibe-coding.md docs/graduation-from-vibe-coding.ko.md | |
| - name: Security audit | |
| # `moderate` (not `high`) because package.json#overrides patches the | |
| # transitive hono / ip-address / @hono/node-server moderates that the | |
| # MCP SDK's HTTP-transport branch pulls in. Without the overrides, | |
| # this step would false-positive on transitives we never import. | |
| run: npm audit --audit-level=moderate | |
| - name: Build (tsc — also typechecks) | |
| run: npm run build | |
| - name: Unit tests | |
| run: npm test | |
| - name: Verify CLI bin exists | |
| run: test -f dist/index.js | |
| - name: Scaffold smoke test | |
| run: | | |
| # Verify templates.ts references valid repo names (no typos) | |
| node --input-type=module -e " | |
| import('./dist/templates.js').then(m => { | |
| const ids = m.templates.map(t => t.id); | |
| if (new Set(ids).size !== ids.length) { | |
| console.error('Duplicate template ids'); | |
| process.exit(1); | |
| } | |
| for (const t of m.templates) { | |
| if (!t.repo || !t.repo.includes('/')) { | |
| console.error('Invalid repo:', t.id); | |
| process.exit(1); | |
| } | |
| } | |
| console.log('Templates OK:', ids.length); | |
| }); | |
| " |