diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index efdd399..59c8382 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: Postgres Best Practices CI +name: Skills CI on: push: @@ -23,7 +23,7 @@ jobs: run: npm run ci:check validate-and-build: - name: Validate and Build + name: Validate and Build Skills runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -33,22 +33,22 @@ jobs: node-version: '20' - name: Install dependencies - working-directory: packages/postgres-best-practices-build + working-directory: packages/skills-build run: npm install - - name: Validate rule files - working-directory: packages/postgres-best-practices-build + - name: Validate all skills + working-directory: packages/skills-build run: npm run validate - - name: Build AGENTS.md - working-directory: packages/postgres-best-practices-build + - name: Build all skills + working-directory: packages/skills-build run: npm run build - name: Check for uncommitted changes run: | - if [[ -n $(git status --porcelain skills/postgres-best-practices/AGENTS.md) ]]; then - echo "Error: AGENTS.md is not up to date" + if [[ -n $(git status --porcelain 'skills/*/AGENTS.md') ]]; then + echo "Error: AGENTS.md files are not up to date" echo "Run 'npm run build' and commit the changes" - git diff skills/postgres-best-practices/AGENTS.md + git diff skills/*/AGENTS.md exit 1 fi diff --git a/AGENTS.md b/AGENTS.md index 9f5eb59..4eacf6a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,120 +1,71 @@ # AGENTS.md -This file provides guidance to AI coding agents (Claude Code, Cursor, Copilot, -etc.) when working with code in this repository. +Guidance for AI coding agents working with this repository. -## Repository Overview - -A collection of Postgres best practices skills for AI coding agents, maintained -by Supabase. Skills are packaged instructions that extend agent capabilities for -database optimization. - -## Creating a New Rule - -### Directory Structure +## Repository Structure ``` skills/ - postgres-best-practices/ - SKILL.md # Required: skill definition + {skill-name}/ + metadata.json # Required: skill metadata AGENTS.md # Generated: compiled rules - metadata.json # Required: version and metadata rules/ - _template.md # Template for new rules - _sections.md # Section definitions - _contributing.md # Writing guidelines - {prefix}-{name}.md # Individual rule files + _sections.md # Required: section definitions + {prefix}-{name}.md # Rule files packages/ - postgres-best-practices-build/ - src/ # Build system source - package.json # NPM scripts + skills-build/ # Generic build system for all skills ``` -### Naming Conventions - -- **Rule files**: `{prefix}-{kebab-case-name}.md` (e.g., - `query-missing-indexes.md`) -- **Prefixes determine section**: `query-`, `conn-`, `schema-`, `lock-`, - `security-`, `data-`, `monitor-`, `advanced-` -- **Special files**: Prefixed with `_` (e.g., `_template.md`, `_sections.md`) - -### Rule File Format - -````markdown ---- -title: Clear, Action-Oriented Title -impact: CRITICAL|HIGH|MEDIUM-HIGH|MEDIUM|LOW-MEDIUM|LOW -impactDescription: Quantified benefit (e.g., "10-100x faster") -tags: relevant, keywords ---- - -## [Title] - -[1-2 sentence explanation] - -**Incorrect (description):** - -```sql --- Comment explaining what's wrong -[Bad SQL example] -``` - -**Correct (description):** - -```sql --- Comment explaining why this is better -[Good SQL example] -``` -```` - -### Best Practices for Context Efficiency - -Skills are loaded on-demand. To minimize context usage: - -- **Keep rules focused** - One optimization pattern per rule -- **Write specific titles** - Helps the agent know exactly when to apply -- **Use progressive disclosure** - Reference supporting files when needed -- **Self-contained examples** - Complete, runnable SQL -- **Quantify impact** - Include specific metrics (10x faster, 50% smaller) - -### Build System - -After creating or updating rules: +## Commands ```bash -cd packages/postgres-best-practices-build -npm install -npm run validate # Check rule format -npm run build # Generate AGENTS.md +npm run build # Build all skills +npm run build -- {skill-name} # Build specific skill +npm run validate # Validate all skills +npm run validate -- {skill-name} # Validate specific skill ``` -**Automatic Section Ordering**: The build system automatically reads section order -from `_sections.md`. To reorder sections (e.g., promoting Security from MEDIUM-HIGH -to CRITICAL priority), simply edit the section numbers in `_sections.md` and -rebuild. The section mapping is generated dynamically, so manual updates to -`config.ts` are no longer needed. +## Creating a New Skill -### Impact Levels +1. Create directory: `mkdir -p skills/{name}/rules` +2. Add `metadata.json` with version, organization, abstract +3. Add `rules/_sections.md` defining sections +4. Add rule files: `{prefix}-{rule-name}.md` +5. Run `npm run build` -| Level | Improvement | Examples | -| ----------- | ----------- | -------------------------------------- | -| CRITICAL | 10-100x | Missing indexes, connection exhaustion | -| HIGH | 5-20x | Wrong index types, poor partitioning | -| MEDIUM-HIGH | 2-5x | N+1 queries, RLS optimization | -| MEDIUM | 1.5-3x | Redundant indexes, stale statistics | -| LOW-MEDIUM | 1.2-2x | VACUUM tuning, config tweaks | -| LOW | Incremental | Advanced patterns, edge cases | +## Rule File Format -### File Prefix to Section Mapping +```markdown +--- +title: Action-Oriented Title +impact: CRITICAL|HIGH|MEDIUM-HIGH|MEDIUM|LOW-MEDIUM|LOW +impactDescription: Quantified benefit +tags: keywords +--- -| Prefix | Section | Priority | -| ----------- | ------------------------ | --------------- | -| `query-` | Query Performance | 1 (CRITICAL) | -| `conn-` | Connection Management | 2 (CRITICAL) | -| `security-` | Security & RLS | 3 (CRITICAL) | -| `schema-` | Schema Design | 4 (HIGH) | -| `lock-` | Concurrency & Locking | 5 (MEDIUM-HIGH) | -| `data-` | Data Access Patterns | 6 (MEDIUM) | -| `monitor-` | Monitoring & Diagnostics | 7 (LOW-MEDIUM) | -| `advanced-` | Advanced Features | 8 (LOW) | +## Title + +1-2 sentence explanation. + +**Incorrect:** +\`\`\`sql +-- bad example +\`\`\` + +**Correct:** +\`\`\`sql +-- good example +\`\`\` +``` + +## Impact Levels + +| Level | Improvement | Use For | +| ----------- | ----------------------------- | ---------------------------------------------------------- | +| CRITICAL | 10-100x or prevents failure | Security vulnerabilities, data loss, breaking changes | +| HIGH | 5-20x or major quality gain | Architecture decisions, core functionality, scalability | +| MEDIUM-HIGH | 2-5x or significant benefit | Design patterns, common anti-patterns, reliability | +| MEDIUM | 1.5-3x or noticeable gain | Optimization, best practices, maintainability | +| LOW-MEDIUM | 1.2-2x or minor benefit | Configuration, tooling, code organization | +| LOW | Incremental or edge cases | Advanced techniques, rare scenarios, polish | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 65e5824..2d7abfe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,10 +2,9 @@ Thank you for contributing to Supabase Agent Skills! Here's how to get started: -[1. Getting Started](#getting-started) [2. Issues](#issues) -[3. Pull Requests](#pull-requests) -[4. Contributing New Rules](#contributing-new-rules) -[5. Extending Existing Skills](#extending-existing-skills) +[1. Getting Started](#getting-started) | [2. Issues](#issues) | +[3. Pull Requests](#pull-requests) | [4. Contributing New Rules](#contributing-new-rules) | +[5. Creating a New Skill](#creating-a-new-skill) ## Getting Started @@ -49,6 +48,68 @@ npm run build # Generate AGENTS.md from rules Both commands must complete successfully. +## Contributing New Rules + +To add a rule to an existing skill: + +1. Navigate to `skills/{skill-name}/rules/` +2. Copy `_template.md` to `{prefix}-{your-rule-name}.md` +3. Fill in the frontmatter (title, impact, tags) +4. Write explanation and examples (Incorrect/Correct) +5. Run validation and build: + +```bash +npm run validate +npm run build +``` + +## Creating a New Skill + +To create an entirely new skill: + +### 1. Create the directory structure + +```bash +mkdir -p skills/my-skill/rules +``` + +### 2. Create metadata.json + +```json +{ + "version": "1.0.0", + "organization": "Your Org", + "date": "January 2026", + "abstract": "Brief description of this skill." +} +``` + +### 3. Create rules/_sections.md + +```markdown +## 1. First Category (first) +**Impact:** HIGH +**Description:** What this category covers. + +## 2. Second Category (second) +**Impact:** MEDIUM +**Description:** What this category covers. +``` + +### 4. Create rule files + +Name files as `{prefix}-{rule-name}.md` where prefix matches a section. + +Example: `first-example-rule.md` for section "First Category" + +### 5. Build + +```bash +npm run build +``` + +The build system auto-discovers skills. No configuration needed. + ## Questions or Feedback? - Open an Issue for bugs or suggestions diff --git a/package.json b/package.json index b84bb6c..434054e 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "license": "MIT", "description": "Official Supabase agent skills", "scripts": { - "build": "npm --prefix packages/postgres-best-practices-build run build", - "validate": "npm --prefix packages/postgres-best-practices-build run validate", + "build": "npm --prefix packages/skills-build run build", + "validate": "npm --prefix packages/skills-build run validate", "format": "biome format --write .", "format:check": "biome format .", "lint": "biome lint --write .", diff --git a/packages/postgres-best-practices-build/package-lock.json b/packages/postgres-best-practices-build/package-lock.json deleted file mode 100644 index f663c64..0000000 --- a/packages/postgres-best-practices-build/package-lock.json +++ /dev/null @@ -1,590 +0,0 @@ -{ - "name": "postgresql-best-practices-build", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "postgresql-best-practices-build", - "version": "1.0.0", - "devDependencies": { - "@types/node": "^20.10.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@types/node": { - "version": "20.19.30", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", - "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/esbuild": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-tsconfig": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", - "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/tsx": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.27.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - } - } -} diff --git a/packages/postgres-best-practices-build/src/config.ts b/packages/postgres-best-practices-build/src/config.ts deleted file mode 100644 index 33bc32c..0000000 --- a/packages/postgres-best-practices-build/src/config.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); - -// Build package directory -export const BUILD_DIR = join(__dirname, ".."); - -// Skill directory (relative to build package) -export const SKILL_DIR = join( - BUILD_DIR, - "../../skills/postgres-best-practices", -); - -// Rules directory -export const RULES_DIR = join(SKILL_DIR, "rules"); - -// Output files -export const AGENTS_OUTPUT = join(SKILL_DIR, "AGENTS.md"); -export const METADATA_FILE = join(SKILL_DIR, "metadata.json"); - -// Section prefix to number mapping (DEPRECATED) -// This is kept as a fallback, but the build system now generates -// the section map dynamically from _sections.md. -// To reorder sections, simply change the order in _sections.md. -export const SECTION_MAP: Record = { - query: 1, - conn: 2, - connection: 2, - security: 3, - schema: 4, - lock: 5, - data: 6, - monitor: 7, - advanced: 8, -}; - -// Valid impact levels in priority order -export const IMPACT_LEVELS = [ - "CRITICAL", - "HIGH", - "MEDIUM-HIGH", - "MEDIUM", - "LOW-MEDIUM", - "LOW", -] as const; diff --git a/packages/skills-build/package-lock.json b/packages/skills-build/package-lock.json new file mode 100644 index 0000000..4fe2371 --- /dev/null +++ b/packages/skills-build/package-lock.json @@ -0,0 +1,591 @@ +{ + "name": "skills-build", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "skills-build", + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "@types/node": "^20.10.0", + "tsx": "^4.7.0", + "typescript": "^5.3.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", + "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/packages/postgres-best-practices-build/package.json b/packages/skills-build/package.json similarity index 75% rename from packages/postgres-best-practices-build/package.json rename to packages/skills-build/package.json index b738a26..7585cad 100644 --- a/packages/postgres-best-practices-build/package.json +++ b/packages/skills-build/package.json @@ -1,10 +1,10 @@ { - "name": "postgres-best-practices-build", + "name": "skills-build", "version": "1.0.0", "type": "module", "author": "Supabase", "license": "MIT", - "description": "Build system for Supabase agent skills", + "description": "Generic build system for Supabase agent skills", "scripts": { "build": "tsx src/build.ts", "validate": "tsx src/validate.ts", diff --git a/packages/postgres-best-practices-build/src/build.ts b/packages/skills-build/src/build.ts similarity index 68% rename from packages/postgres-best-practices-build/src/build.ts rename to packages/skills-build/src/build.ts index f858c87..bcf5f3f 100644 --- a/packages/postgres-best-practices-build/src/build.ts +++ b/packages/skills-build/src/build.ts @@ -1,6 +1,11 @@ import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs"; import { basename, join } from "node:path"; -import { AGENTS_OUTPUT, METADATA_FILE, RULES_DIR } from "./config.js"; +import { + discoverSkills, + getSkillPaths, + type SkillPaths, + validateSkillExists, +} from "./config.js"; import { parseRuleFile } from "./parser.js"; import type { Metadata, Rule, Section } from "./types.js"; import { validateRuleFile } from "./validate.js"; @@ -8,11 +13,11 @@ import { validateRuleFile } from "./validate.js"; /** * Parse section definitions from _sections.md */ -function parseSections(): Section[] { - const sectionsFile = join(RULES_DIR, "_sections.md"); +function parseSections(rulesDir: string): Section[] { + const sectionsFile = join(rulesDir, "_sections.md"); if (!existsSync(sectionsFile)) { - console.warn("Warning: _sections.md not found, using default sections"); - return getDefaultSections(); + console.warn("Warning: _sections.md not found, using empty sections"); + return []; } const content = readFileSync(sectionsFile, "utf-8"); @@ -36,78 +41,14 @@ function parseSections(): Section[] { }); } - return sections.length > 0 ? sections : getDefaultSections(); -} - -/** - * Default sections if _sections.md is missing or unparseable - */ -function getDefaultSections(): Section[] { - return [ - { - number: 1, - title: "Query Performance", - prefix: "query", - impact: "CRITICAL", - description: "Slow queries, missing indexes, inefficient plans", - }, - { - number: 2, - title: "Connection Management", - prefix: "conn", - impact: "CRITICAL", - description: "Pooling, limits, serverless strategies", - }, - { - number: 3, - title: "Security & RLS", - prefix: "security", - impact: "CRITICAL", - description: "Row-Level Security, privileges, auth patterns", - }, - { - number: 4, - title: "Schema Design", - prefix: "schema", - impact: "HIGH", - description: "Table design, indexes, partitioning, data types", - }, - { - number: 5, - title: "Concurrency & Locking", - prefix: "lock", - impact: "MEDIUM-HIGH", - description: "Transactions, isolation, deadlocks", - }, - { - number: 6, - title: "Data Access Patterns", - prefix: "data", - impact: "MEDIUM", - description: "N+1 queries, batch operations, pagination", - }, - { - number: 7, - title: "Monitoring & Diagnostics", - prefix: "monitor", - impact: "LOW-MEDIUM", - description: "pg_stat_statements, EXPLAIN, metrics", - }, - { - number: 8, - title: "Advanced Features", - prefix: "advanced", - impact: "LOW", - description: "Full-text search, JSONB, extensions", - }, - ]; + return sections; } /** * Load metadata from metadata.json */ -function loadMetadata(): Metadata { - if (!existsSync(METADATA_FILE)) { +function loadMetadata(metadataFile: string, skillName: string): Metadata { + if (!existsSync(metadataFile)) { return { version: "1.0.0", organization: "Supabase", @@ -115,12 +56,12 @@ function loadMetadata(): Metadata { month: "long", year: "numeric", }), - abstract: "Postgres performance optimization guide for developers.", + abstract: `${skillName} guide for developers.`, references: [], }; } - return JSON.parse(readFileSync(METADATA_FILE, "utf-8")); + return JSON.parse(readFileSync(metadataFile, "utf-8")); } /** @@ -133,6 +74,16 @@ function toAnchor(text: string): string { .replace(/\s+/g, "-"); } +/** + * Convert skill name to title (e.g., "postgres-best-practices" -> "Postgres Best Practices") + */ +function skillNameToTitle(skillName: string): string { + return skillName + .split("-") + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(" "); +} + /** * Generate SECTION_MAP from parsed sections */ @@ -147,23 +98,34 @@ export function generateSectionMap( } /** - * Build AGENTS.md from all rule files + * Build AGENTS.md for a specific skill */ -function buildAgents(): void { - console.log("Building AGENTS.md...\n"); +function buildSkill(paths: SkillPaths): void { + console.log(`[${paths.name}] Building AGENTS.md...`); // Load metadata and sections - const metadata = loadMetadata(); - const sections = parseSections(); + const metadata = loadMetadata(paths.metadataFile, paths.name); + const sections = parseSections(paths.rulesDir); const sectionMap = generateSectionMap(sections); + const skillTitle = skillNameToTitle(paths.name); + + // Check if rules directory exists + if (!existsSync(paths.rulesDir)) { + console.log(` No rules directory found. Generating empty AGENTS.md.`); + writeFileSync( + paths.agentsOutput, + `# ${skillTitle}\n\nNo rules defined yet.\n`, + ); + return; + } // Get all rule files - const ruleFiles = readdirSync(RULES_DIR) + const ruleFiles = readdirSync(paths.rulesDir) .filter((f) => f.endsWith(".md") && !f.startsWith("_")) - .map((f) => join(RULES_DIR, f)); + .map((f) => join(paths.rulesDir, f)); if (ruleFiles.length === 0) { - console.log("No rule files found. Generating empty AGENTS.md template."); + console.log(` No rule files found. Generating empty AGENTS.md.`); } // Parse and validate all rules @@ -172,9 +134,9 @@ function buildAgents(): void { for (const file of ruleFiles) { const validation = validateRuleFile(file, sectionMap); if (!validation.valid) { - console.error(`Skipping invalid file ${basename(file)}:`); + console.error(` Skipping invalid file ${basename(file)}:`); for (const e of validation.errors) { - console.error(` - ${e}`); + console.error(` - ${e}`); } continue; } @@ -206,7 +168,7 @@ function buildAgents(): void { const output: string[] = []; // Header - output.push("# Postgres Best Practices\n"); + output.push(`# ${skillTitle}\n`); output.push(`**Version ${metadata.version}**`); output.push(`${metadata.organization}`); output.push(`${metadata.date}\n`); @@ -307,9 +269,9 @@ function buildAgents(): void { } // Write output - writeFileSync(AGENTS_OUTPUT, output.join("\n")); - console.log(`Generated: ${AGENTS_OUTPUT}`); - console.log(`Total rules: ${rules.length}`); + writeFileSync(paths.agentsOutput, output.join("\n")); + console.log(` Generated: ${paths.agentsOutput}`); + console.log(` Total rules: ${rules.length}`); } // Run build when executed directly @@ -318,7 +280,35 @@ const isMainModule = process.argv[1]?.endsWith("build.js"); if (isMainModule) { - buildAgents(); + const targetSkill = process.argv[2]; + + if (targetSkill) { + // Build specific skill + if (!validateSkillExists(targetSkill)) { + console.error(`Error: Skill "${targetSkill}" not found in skills/`); + const available = discoverSkills(); + if (available.length > 0) { + console.error(`Available skills: ${available.join(", ")}`); + } + process.exit(1); + } + buildSkill(getSkillPaths(targetSkill)); + } else { + // Build all skills + const skills = discoverSkills(); + if (skills.length === 0) { + console.log("No skills found in skills/ directory."); + process.exit(0); + } + + console.log(`Found ${skills.length} skill(s): ${skills.join(", ")}\n`); + for (const skill of skills) { + buildSkill(getSkillPaths(skill)); + console.log(""); + } + } + + console.log("✅ Done!"); } -export { buildAgents, parseSections }; +export { buildSkill, parseSections }; diff --git a/packages/skills-build/src/config.ts b/packages/skills-build/src/config.ts new file mode 100644 index 0000000..a807986 --- /dev/null +++ b/packages/skills-build/src/config.ts @@ -0,0 +1,59 @@ +import { existsSync, readdirSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +// Build package directory +export const BUILD_DIR = join(__dirname, ".."); + +// Skills root directory +export const SKILLS_ROOT = join(BUILD_DIR, "../../skills"); + +// Skill paths interface +export interface SkillPaths { + name: string; + skillDir: string; + rulesDir: string; + agentsOutput: string; + metadataFile: string; +} + +// Discover all valid skills (directories with metadata.json) +export function discoverSkills(): string[] { + if (!existsSync(SKILLS_ROOT)) return []; + + return readdirSync(SKILLS_ROOT, { withFileTypes: true }) + .filter((d) => d.isDirectory()) + .filter((d) => existsSync(join(SKILLS_ROOT, d.name, "metadata.json"))) + .map((d) => d.name); +} + +// Get paths for a specific skill +export function getSkillPaths(skillName: string): SkillPaths { + const skillDir = join(SKILLS_ROOT, skillName); + return { + name: skillName, + skillDir, + rulesDir: join(skillDir, "rules"), + agentsOutput: join(skillDir, "AGENTS.md"), + metadataFile: join(skillDir, "metadata.json"), + }; +} + +// Validate skill exists +export function validateSkillExists(skillName: string): boolean { + const paths = getSkillPaths(skillName); + return existsSync(paths.metadataFile); +} + +// Valid impact levels in priority order +export const IMPACT_LEVELS = [ + "CRITICAL", + "HIGH", + "MEDIUM-HIGH", + "MEDIUM", + "LOW-MEDIUM", + "LOW", +] as const; diff --git a/packages/postgres-best-practices-build/src/parser.ts b/packages/skills-build/src/parser.ts similarity index 100% rename from packages/postgres-best-practices-build/src/parser.ts rename to packages/skills-build/src/parser.ts diff --git a/packages/postgres-best-practices-build/src/types.ts b/packages/skills-build/src/types.ts similarity index 100% rename from packages/postgres-best-practices-build/src/types.ts rename to packages/skills-build/src/types.ts diff --git a/packages/postgres-best-practices-build/src/validate.ts b/packages/skills-build/src/validate.ts similarity index 62% rename from packages/postgres-best-practices-build/src/validate.ts rename to packages/skills-build/src/validate.ts index fa43909..db2f6a6 100644 --- a/packages/postgres-best-practices-build/src/validate.ts +++ b/packages/skills-build/src/validate.ts @@ -1,7 +1,13 @@ -import { readdirSync } from "node:fs"; +import { existsSync, readdirSync } from "node:fs"; import { basename, join } from "node:path"; import { generateSectionMap, parseSections } from "./build.js"; -import { IMPACT_LEVELS, RULES_DIR } from "./config.js"; +import { + discoverSkills, + getSkillPaths, + IMPACT_LEVELS, + type SkillPaths, + validateSkillExists, +} from "./config.js"; import { parseRuleFile } from "./parser.js"; import type { ValidationResult } from "./types.js"; @@ -38,14 +44,17 @@ function isGoodExample(label: string): boolean { export function validateRuleFile( filePath: string, sectionMap?: Record, + rulesDir?: string, ): ValidationResult { const errors: string[] = []; const warnings: string[] = []; // Generate section map if not provided - if (!sectionMap) { - const sections = parseSections(); + if (!sectionMap && rulesDir) { + const sections = parseSections(rulesDir); sectionMap = generateSectionMap(sections); + } else if (!sectionMap) { + sectionMap = {}; } const result = parseRuleFile(filePath, sectionMap); @@ -129,40 +138,64 @@ export function validateRuleFile( } /** - * Validate all rule files in the rules directory + * Validate all rule files for a skill */ -export function validateAllRules(): { - totalFiles: number; - validFiles: number; - invalidFiles: number; - results: Map; -} { - const results = new Map(); - let validFiles = 0; - let invalidFiles = 0; +function validateSkill(paths: SkillPaths): boolean { + console.log(`[${paths.name}] Validating...`); + + // Check if rules directory exists + if (!existsSync(paths.rulesDir)) { + console.log(` No rules directory found.`); + return true; + } + + // Get section map + const sections = parseSections(paths.rulesDir); + const sectionMap = generateSectionMap(sections); // Get all markdown files (excluding _ prefixed files) - const files = readdirSync(RULES_DIR) + const files = readdirSync(paths.rulesDir) .filter((f) => f.endsWith(".md") && !f.startsWith("_")) - .map((f) => join(RULES_DIR, f)); + .map((f) => join(paths.rulesDir, f)); + + if (files.length === 0) { + console.log(` No rule files found.`); + return true; + } + + let validFiles = 0; + let invalidFiles = 0; + let hasErrors = false; for (const file of files) { - const result = validateRuleFile(file); - results.set(basename(file), result); + const result = validateRuleFile(file, sectionMap, paths.rulesDir); + const filename = basename(file); if (result.valid) { validFiles++; } else { invalidFiles++; } + + if (!result.valid || result.warnings.length > 0) { + console.log(`\n ${filename}:`); + + for (const error of result.errors) { + console.log(` ERROR: ${error}`); + hasErrors = true; + } + + for (const warning of result.warnings) { + console.log(` WARNING: ${warning}`); + } + } } - return { - totalFiles: files.length, - validFiles, - invalidFiles, - results, - }; + console.log( + `\n Total: ${files.length} | Valid: ${validFiles} | Invalid: ${invalidFiles}`, + ); + + return !hasErrors; } // Run validation when executed directly @@ -171,44 +204,45 @@ const isMainModule = process.argv[1]?.endsWith("validate.js"); if (isMainModule) { - console.log("Validating Postgres best practices rules...\n"); + const targetSkill = process.argv[2]; - const { totalFiles, validFiles, invalidFiles, results } = validateAllRules(); - - if (totalFiles === 0) { - console.log("No rule files found (this is expected for initial setup)."); - console.log("Create rule files in: skills/postgres-best-practices/rules/"); - console.log("Use the _template.md as a starting point.\n"); - process.exit(0); - } - - let hasErrors = false; - - for (const [filename, result] of results) { - if (!result.valid || result.warnings.length > 0) { - console.log(`\n${filename}:`); - - for (const error of result.errors) { - console.log(` ERROR: ${error}`); - hasErrors = true; - } - - for (const warning of result.warnings) { - console.log(` WARNING: ${warning}`); + if (targetSkill) { + // Validate specific skill + if (!validateSkillExists(targetSkill)) { + console.error(`Error: Skill "${targetSkill}" not found in skills/`); + const available = discoverSkills(); + if (available.length > 0) { + console.error(`Available skills: ${available.join(", ")}`); } + process.exit(1); } - } - console.log(`\n${"=".repeat(50)}`); - console.log( - `Total: ${totalFiles} files | Valid: ${validFiles} | Invalid: ${invalidFiles}`, - ); - - if (hasErrors) { - console.log("\nValidation failed. Please fix the errors above."); - process.exit(1); + const valid = validateSkill(getSkillPaths(targetSkill)); + console.log(valid ? "\n✅ Validation passed!" : "\n❌ Validation failed."); + process.exit(valid ? 0 : 1); } else { - console.log("\nValidation passed!"); - process.exit(0); + // Validate all skills + const skills = discoverSkills(); + if (skills.length === 0) { + console.log("No skills found in skills/ directory."); + process.exit(0); + } + + console.log(`Found ${skills.length} skill(s): ${skills.join(", ")}\n`); + + let allValid = true; + for (const skill of skills) { + if (!validateSkill(getSkillPaths(skill))) { + allValid = false; + } + console.log(""); + } + + console.log( + allValid ? "✅ All validations passed!" : "❌ Some validations failed.", + ); + process.exit(allValid ? 0 : 1); } } + +export { validateSkill }; diff --git a/packages/postgres-best-practices-build/tsconfig.json b/packages/skills-build/tsconfig.json similarity index 100% rename from packages/postgres-best-practices-build/tsconfig.json rename to packages/skills-build/tsconfig.json diff --git a/skills/postgres-best-practices/README.md b/skills/postgres-best-practices/README.md index 474a26e..8b71afd 100644 --- a/skills/postgres-best-practices/README.md +++ b/skills/postgres-best-practices/README.md @@ -6,8 +6,7 @@ AI agents and LLMs. ## Quick Start ```bash -# Install dependencies -cd packages/postgres-best-practices-build +# From repository root npm install # Validate existing rules @@ -58,8 +57,8 @@ skills/postgres-best-practices/ ├── _contributing.md # Writing guidelines └── *.md # Individual rules -packages/postgres-best-practices-build/ -├── src/ # Build system source +packages/skills-build/ +├── src/ # Generic build system source ├── package.json # NPM scripts └── test-cases.json # [GENERATED] Test artifacts ```