ai-guard-plugins 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,42 @@
1
+ # Publish to npm via Trusted Publishing (OIDC)
2
+ # ──────────────────────────────────────────────
3
+ # Publishes to npm when a version tag is pushed (pairs with release.yml).
4
+ # Uses OIDC-based trusted publishing — no NPM_TOKEN secret needed.
5
+ #
6
+ # Setup (one-time):
7
+ # 1. Go to https://www.npmjs.com/package/ai-guard-plugins/access
8
+ # 2. Under "Trusted Publishers", add:
9
+ # - Repository owner: YosefHayim
10
+ # - Repository name: ai-guard-plugins
11
+ # - Workflow filename: publish.yml
12
+ # - Environment: (leave empty)
13
+
14
+ name: Publish Package
15
+
16
+ on:
17
+ push:
18
+ tags:
19
+ - "v*.*.*"
20
+
21
+ permissions:
22
+ id-token: write
23
+ contents: read
24
+
25
+ jobs:
26
+ publish:
27
+ runs-on: ubuntu-latest
28
+ steps:
29
+ - name: Checkout code
30
+ uses: actions/checkout@v4
31
+
32
+ - name: Setup Node.js
33
+ uses: actions/setup-node@v4
34
+ with:
35
+ node-version: "22"
36
+ registry-url: "https://registry.npmjs.org"
37
+
38
+ - name: Update npm for trusted publishing support
39
+ run: npm install -g npm@latest
40
+
41
+ - name: Publish to npm
42
+ run: npm publish --access public --provenance
@@ -0,0 +1,156 @@
1
+ # Automated Release Workflow
2
+ # ─────────────────────────
3
+ # Bumps version, creates Git tag, and publishes a GitHub Release
4
+ # when a PR is merged into `main` or a commit is pushed directly.
5
+ #
6
+ # Version bump is determined by PR labels (or defaults to patch for direct pushes):
7
+ # - `major` → breaking changes (1.0.0 → 2.0.0)
8
+ # - `minor` → new features (1.0.0 → 1.1.0)
9
+ # - `patch` → bug fixes (1.0.0 → 1.0.1) [default]
10
+ # - `no-release` → skip entirely
11
+ #
12
+ # The tag push triggers publish.yml for npm publishing.
13
+
14
+ name: Release
15
+
16
+ on:
17
+ push:
18
+ branches: [main]
19
+ pull_request:
20
+ types: [closed]
21
+ branches: [main]
22
+
23
+ concurrency:
24
+ group: release
25
+ cancel-in-progress: false
26
+
27
+ jobs:
28
+ release:
29
+ if: >
30
+ (github.event_name == 'push' && !startsWith(github.event.head_commit.message, 'chore(release):')) ||
31
+ (github.event_name == 'pull_request' && github.event.pull_request.merged == true &&
32
+ !contains(github.event.pull_request.labels.*.name, 'no-release'))
33
+ runs-on: ubuntu-latest
34
+ permissions:
35
+ contents: write
36
+
37
+ steps:
38
+ - name: Checkout
39
+ uses: actions/checkout@v4
40
+ with:
41
+ ref: main
42
+ fetch-depth: 0
43
+ token: ${{ secrets.GITHUB_TOKEN }}
44
+
45
+ - name: Setup Node.js
46
+ uses: actions/setup-node@v4
47
+ with:
48
+ node-version: 22
49
+
50
+ - name: Configure Git
51
+ run: |
52
+ git config user.name "github-actions[bot]"
53
+ git config user.email "github-actions[bot]@users.noreply.github.com"
54
+
55
+ - name: Check if release needed
56
+ id: skip_check
57
+ run: |
58
+ if git describe --exact-match HEAD >/dev/null 2>&1; then
59
+ echo "HEAD is already tagged — skipping release"
60
+ echo "skip=true" >> "$GITHUB_OUTPUT"
61
+ else
62
+ echo "skip=false" >> "$GITHUB_OUTPUT"
63
+ fi
64
+
65
+ - name: Get release description
66
+ if: steps.skip_check.outputs.skip != 'true'
67
+ id: desc
68
+ run: |
69
+ if [ "${{ github.event_name }}" = "push" ]; then
70
+ echo "title=$(git log -1 --pretty=format:'%s')" >> "$GITHUB_OUTPUT"
71
+ else
72
+ echo "title=${{ github.event.pull_request.title }}" >> "$GITHUB_OUTPUT"
73
+ fi
74
+
75
+ - name: Determine version bump
76
+ if: steps.skip_check.outputs.skip != 'true'
77
+ id: bump
78
+ env:
79
+ LABELS: ${{ toJson(github.event.pull_request.labels.*.name) }}
80
+ run: |
81
+ if [ "${{ github.event_name }}" = "push" ]; then
82
+ echo "type=patch" >> "$GITHUB_OUTPUT"
83
+ elif echo "$LABELS" | grep -q '"major"'; then
84
+ echo "type=major" >> "$GITHUB_OUTPUT"
85
+ elif echo "$LABELS" | grep -q '"minor"'; then
86
+ echo "type=minor" >> "$GITHUB_OUTPUT"
87
+ else
88
+ echo "type=patch" >> "$GITHUB_OUTPUT"
89
+ fi
90
+
91
+ - name: Bump version in package.json
92
+ if: steps.skip_check.outputs.skip != 'true'
93
+ id: version
94
+ run: |
95
+ if ! node -e "const p = require('./package.json'); if (!p.version) process.exit(1);" 2>/dev/null; then
96
+ echo "No version found in package.json — initializing to 0.1.0"
97
+ npm pkg set version=0.1.0
98
+ fi
99
+ NEW_VERSION=$(npm version ${{ steps.bump.outputs.type }} --no-git-tag-version)
100
+ echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
101
+ echo "Bumped to $NEW_VERSION (${{ steps.bump.outputs.type }})"
102
+
103
+ - name: Build release notes from commits
104
+ if: steps.skip_check.outputs.skip != 'true'
105
+ id: notes
106
+ env:
107
+ PR_TITLE: ${{ github.event.pull_request.title }}
108
+ PR_NUMBER: ${{ github.event.pull_request.number }}
109
+ PR_URL: ${{ github.event.pull_request.html_url }}
110
+ BUMP_TYPE: ${{ steps.bump.outputs.type }}
111
+ run: |
112
+ PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
113
+ if [ -n "$PREV_TAG" ]; then
114
+ COMMITS=$(git log "$PREV_TAG"..HEAD --pretty=format:"- %s (%h)" --no-merges)
115
+ else
116
+ COMMITS=$(git log --pretty=format:"- %s (%h)" --no-merges -20)
117
+ fi
118
+ {
119
+ echo "body<<RELEASE_EOF"
120
+ echo "## What Changed"
121
+ echo ""
122
+ if [ "${{ github.event_name }}" = "push" ]; then
123
+ echo "**Direct push to ${GITHUB_REF_NAME}**"
124
+ else
125
+ echo "**PR:** [#${PR_NUMBER} — ${PR_TITLE}](${PR_URL})"
126
+ fi
127
+ echo "**Bump:** \`${BUMP_TYPE}\`"
128
+ echo ""
129
+ echo "### Commits"
130
+ echo ""
131
+ echo "$COMMITS"
132
+ echo ""
133
+ echo "RELEASE_EOF"
134
+ } >> "$GITHUB_OUTPUT"
135
+
136
+ - name: Commit version bump and create tag
137
+ if: steps.skip_check.outputs.skip != 'true'
138
+ run: |
139
+ git add package.json
140
+ git commit -m "chore(release): ${{ steps.version.outputs.version }}"
141
+ git tag -a "${{ steps.version.outputs.version }}" \
142
+ -m "Release ${{ steps.version.outputs.version }} — ${{ steps.desc.outputs.title }}"
143
+ git push origin main --follow-tags
144
+
145
+ - name: Create GitHub Release
146
+ if: steps.skip_check.outputs.skip != 'true'
147
+ env:
148
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
149
+ TAG: ${{ steps.version.outputs.version }}
150
+ run: |
151
+ gh release create "$TAG" \
152
+ --title "$TAG — ${{ steps.desc.outputs.title }}" \
153
+ --notes "${{ steps.notes.outputs.body }}" \
154
+ --latest
155
+
156
+ # npm publish is handled by publish.yml (triggered by the tag created above)
@@ -0,0 +1,56 @@
1
+ # Contributing to ai-guard-plugins
2
+
3
+ Thanks for your interest in contributing! Every plugin in this repo was born from a real pain point during AI-assisted development. If you've hit a scenario that should be caught, we want it here.
4
+
5
+ ## Adding a New Plugin
6
+
7
+ 1. **Fork** and create a branch from `main`
8
+ 2. Create your plugin in `plugins/your-plugin-name.ts`
9
+ 3. Follow the existing plugin patterns:
10
+
11
+ ```typescript
12
+ import type { Plugin } from '@opencode-ai/plugin';
13
+
14
+ export const YourPluginName: Plugin = async () => {
15
+ return {
16
+ // Intercept before tool execution
17
+ 'tool.execute.before': async (input, output) => { },
18
+
19
+ // React after tool execution
20
+ 'tool.execute.after': async (input, output) => { },
21
+
22
+ // Listen to session events
23
+ event: async ({ event }) => { },
24
+ };
25
+ };
26
+ ```
27
+
28
+ 4. Update `README.md` with:
29
+ - Plugin name and one-line description
30
+ - Table of real scenarios that led to its creation
31
+ - Any dependencies required
32
+ 5. Add the plugin to `install.yaml` choices
33
+ 6. Submit a PR with a clear description
34
+
35
+ ## Plugin Guidelines
36
+
37
+ - **Solve a real problem.** Every plugin must include the scenarios that motivated it.
38
+ - **Zero dependencies preferred.** If you need an external tool, document it clearly.
39
+ - **No `any` types.** Use proper TypeScript types throughout.
40
+ - **Fail gracefully.** Plugins should never crash the host agent. Use try/catch where appropriate.
41
+ - **Log clearly.** Use `console.warn` or `console.error` with a prefix like `[your-plugin]`.
42
+ - **Don't block unnecessarily.** Only `throw` to block a tool call when the violation is clear-cut.
43
+
44
+ ## Reporting Issues
45
+
46
+ Found a false positive? A scenario that should be caught but isn't? Open an issue with:
47
+
48
+ 1. The plugin name
49
+ 2. What happened (expected vs actual)
50
+ 3. Steps to reproduce
51
+
52
+ ## Code Style
53
+
54
+ - TypeScript with strict types
55
+ - No `as any`, `@ts-ignore`, or `@ts-expect-error`
56
+ - Biome for formatting (run `npx biome check --fix` before committing)
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Yosef Hayim Sabag
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,247 @@
1
+ # ai-guard-plugins
2
+
3
+ > Production-hardened plugins for [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [OpenCode](https://opencode.ai), [Cline](https://cline.bot), [Cursor](https://cursor.com), & [Kilo Code](https://kilocode.ai) — battle-tested hooks from real AI-assisted development that catch costly mistakes before they happen.
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+ [![Plugins](https://img.shields.io/badge/Plugins-6-blue.svg)](#plugins)
7
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)
8
+
9
+ ---
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ # Download and inspect before running
15
+ curl -fsSL https://raw.githubusercontent.com/YosefHayim/ai-guard-plugins/main/install.sh -o /tmp/ai-guard-install.sh
16
+ less /tmp/ai-guard-install.sh # inspect first
17
+ bash /tmp/ai-guard-install.sh
18
+
19
+ # Specify platform explicitly
20
+ AI_GUARD_PLATFORM=opencode bash /tmp/ai-guard-install.sh
21
+ AI_GUARD_PLATFORM=claude bash /tmp/ai-guard-install.sh
22
+ AI_GUARD_PLATFORM=cline bash /tmp/ai-guard-install.sh
23
+ AI_GUARD_PLATFORM=cursor bash /tmp/ai-guard-install.sh
24
+ AI_GUARD_PLATFORM=kilo bash /tmp/ai-guard-install.sh
25
+
26
+ # Pin to a specific version
27
+ INSTALL_VERSION=v1.0.0 bash /tmp/ai-guard-install.sh
28
+ ```
29
+
30
+ Or pick what you need with the interactive wizard ([grimoire-wizard](https://github.com/YosefHayim/grimoire) required):
31
+
32
+ ```bash
33
+ npx grimoire-wizard run https://raw.githubusercontent.com/YosefHayim/ai-guard-plugins/main/install.yaml
34
+ ```
35
+
36
+ ---
37
+
38
+ ## Why This Exists
39
+
40
+ AI coding assistants are powerful but reckless. Left unchecked, they will:
41
+
42
+ - **Freeze for 10+ minutes** retrying a billing error that will never resolve
43
+ - **Burn your entire context window** on a 50K-char paste they could have summarized
44
+ - **Silently duplicate** code that already exists two directories over
45
+ - **Add `as any`** to "fix" a type error instead of solving it
46
+ - **Create TODO placeholders** they promise to fill in "later" (they won't)
47
+ - **Repeat the same mistakes** across sessions because they have no memory
48
+
49
+ These plugins are the guardrails. They intercept, warn, block, and learn — so you don't have to babysit.
50
+
51
+ ---
52
+
53
+ ## Plugins
54
+
55
+ ### 💳 billing-guard
56
+
57
+ **Catches billing errors before infinite retry freezes.**
58
+
59
+ When an API provider runs out of credits or has no payment method, the agent enters a retry loop that never resolves — burning tokens and your time. This plugin intercepts billing-related error responses and immediately interrupts with a clear message.
60
+
61
+ | Scenario | What happened | Time wasted |
62
+ |----------|--------------|-------------|
63
+ | OpenAI billing inactive | Agent retried 4x then froze | 12 minutes |
64
+ | Cloudflare quota exceeded | Infinite generation loop | 8 minutes |
65
+ | Gemini invalid API key | Burned context on retries | 15 minutes |
66
+
67
+ **Patterns detected:** `No payment method`, `account is not active`, `billing details`, `quota exceeded`, `insufficient funds`, `plan expired`, `subscription inactive`
68
+
69
+ ---
70
+
71
+ ### 🧹 auto-lint-fix
72
+
73
+ **Auto-formats code after every write/edit.**
74
+
75
+ Every time the agent writes or edits a TypeScript/JavaScript file, Biome runs `check --fix --unsafe` immediately. No more commit-time lint failures or wasted tool calls on "fix formatting."
76
+
77
+ | Scenario | What happened |
78
+ |----------|--------------|
79
+ | Pre-commit hook rejects commit | Agent loses flow, wastes 2 tool calls fixing formatting |
80
+ | Inconsistent style across files | Accumulated drift in multi-file changes |
81
+ | Agent "fixes" lint manually | Extra tool call that Biome handles instantly |
82
+
83
+ **Requires:** [Biome](https://biomejs.dev/) installed (path configurable in plugin)
84
+
85
+ ---
86
+
87
+ ### 📦 auto-summarize-input
88
+
89
+ **Compresses large inputs to save context window tokens.**
90
+
91
+ When pasted input exceeds 10,000 characters, this plugin auto-summarizes via Claude Haiku — keeping all code snippets, file paths, error messages, and requirements verbatim while stripping redundancy.
92
+
93
+ | Scenario | Input size | After compression | Savings |
94
+ |----------|-----------|-------------------|---------|
95
+ | Full error log paste | 52K chars | 8K chars | 85% |
96
+ | Stack trace with repeats | 28K chars | 4K chars | 86% |
97
+ | Requirements doc | 35K chars | 9K chars | 74% |
98
+
99
+ **Requires:** Active Anthropic API key (uses Claude Haiku)
100
+
101
+ ---
102
+
103
+ ### 🧠 capture-insights
104
+
105
+ **Learns from recurring mistakes across sessions.**
106
+
107
+ Monitors session messages for recurring patterns — DRY violations, type safety bypasses, scope creep, circular dependencies, security issues. Logs insights to a persistent JSONL file with counts, timestamps, and project associations. Auto-squeezes to keep the top 15 most frequent insights.
108
+
109
+ | Pattern tracked | Example trigger |
110
+ |----------------|----------------|
111
+ | DRY violation | "already exists", "duplicat" |
112
+ | Type safety bypass | `as any`, `ts-ignore` |
113
+ | Scope creep | "refactor…minimal", "scope creep" |
114
+ | Circular dependency | "circular import" |
115
+ | Security | "secret", "credential", "token leak" |
116
+
117
+ **Persistent memory** across sessions — the more you use it, the smarter it gets.
118
+
119
+ ---
120
+
121
+ ### 📏 cursorrules-enforcer
122
+
123
+ **Enforces project coding standards on every file write.**
124
+
125
+ Intercepts all write/edit operations and blocks violations with clear error messages. No more "I'll fix it later" from the agent.
126
+
127
+ | Rule | What it blocks |
128
+ |------|---------------|
129
+ | Type cast | `as any`, `as unknown` |
130
+ | TS suppression | `@ts-ignore`, `@ts-expect-error` |
131
+ | CommonJS | `require()` in ESM projects |
132
+ | Placeholders | `TODO`, `FIXME`, `HACK`, `// later` |
133
+ | Naming | Underscore-prefixed variables and files |
134
+ | Index logic | Business logic in index/barrel files |
135
+ | Re-exports | Excessive re-exports in non-index files |
136
+
137
+ ---
138
+
139
+ ### 🔍 dry-guard
140
+
141
+ **Warns before creating files that duplicate existing code.**
142
+
143
+ When the agent creates a new file, this plugin searches the project for similar filenames (token matching), existing files in the target directory, and export/symbol collisions. Warns the agent to consider extending existing code.
144
+
145
+ | Scenario | What it caught |
146
+ |----------|---------------|
147
+ | `utils/format-date.ts` | `utils/dates.ts` already had the same function |
148
+ | New component in `components/` | 3 similar components already existed |
149
+ | `UserService` export | Symbol already exported from `services/auth.ts` |
150
+
151
+ ---
152
+
153
+ ## Manual Install
154
+
155
+ ### OpenCode
156
+
157
+ ```bash
158
+ # All plugins
159
+ cp plugins/*.ts ~/.config/opencode/plugins/
160
+
161
+ # Single plugin
162
+ cp plugins/billing-guard.ts ~/.config/opencode/plugins/
163
+ ```
164
+
165
+ ### Claude Code
166
+
167
+ ```bash
168
+ # All plugins
169
+ cp plugins/*.ts ~/.claude/plugins/
170
+
171
+ # Single plugin
172
+ cp plugins/billing-guard.ts ~/.claude/plugins/
173
+ ```
174
+
175
+ Restart your AI coding assistant after installing.
176
+
177
+ ---
178
+
179
+ ## Requirements
180
+
181
+ | Plugin | Dependency |
182
+ |--------|-----------|
183
+ | auto-lint-fix | [Biome](https://biomejs.dev/) installed |
184
+ | auto-summarize-input | Active Anthropic API key |
185
+ | All others | None — zero dependencies |
186
+
187
+ ---
188
+
189
+ ## Contributing
190
+
191
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
192
+
193
+ ## License
194
+
195
+ [MIT](LICENSE)
196
+
197
+ ### Cline
198
+
199
+ ```bash
200
+ # All hooks
201
+ cp plugins/cline/hooks/* ~/.clinerules/hooks/
202
+ chmod +x ~/.clinerules/hooks/*
203
+
204
+ # Single hook
205
+ cp plugins/cline/hooks/PreToolUse ~/.clinerules/hooks/
206
+ chmod +x ~/.clinerules/hooks/PreToolUse
207
+ ```
208
+
209
+ **Requires:** [jq](https://jqlang.github.io/jq/) installed
210
+
211
+ ### Cursor
212
+
213
+ ```bash
214
+ # All rules
215
+ cp plugins/cursor/rules/*.mdc .cursor/rules/
216
+
217
+ # Single rule
218
+ cp plugins/cursor/rules/code-standards.mdc .cursor/rules/
219
+ ```
220
+
221
+ ### Kilo Code
222
+
223
+ ```bash
224
+ # All rules
225
+ cp plugins/kilo/rules/*.md .kilo/rules/
226
+
227
+ # Single rule
228
+ cp plugins/kilo/rules/code-standards.md .kilo/rules/
229
+ ```
230
+
231
+ ---
232
+
233
+ ## Platform Support Matrix
234
+
235
+ | Plugin | OpenCode | Claude Code | Cline | Cursor | Kilo Code |
236
+ |--------|----------|-------------|-------|--------|-----------|
237
+ | billing-guard | TypeScript plugin | TypeScript plugin | Bash hook (PreToolUse + PostToolUse) | Advisory rule (.mdc) | Advisory rule (.md) |
238
+ | auto-lint-fix | TypeScript plugin | TypeScript plugin | Bash hook (PostToolUse) | Advisory rule (.mdc) | Advisory rule (.md) |
239
+ | auto-summarize-input | TypeScript plugin | TypeScript plugin | Bash hook (UserPromptSubmit) | Advisory rule (.mdc) | Advisory rule (.md) |
240
+ | capture-insights | TypeScript plugin | TypeScript plugin | Bash hook (TaskComplete) | Advisory rule (.mdc) | Advisory rule (.md) |
241
+ | cursorrules-enforcer | TypeScript plugin | TypeScript plugin | Bash hook (PreToolUse) | Advisory rule (.mdc) | Advisory rule (.md) |
242
+ | dry-guard | TypeScript plugin | TypeScript plugin | Bash hook (PreToolUse) | Advisory rule (.mdc) | Advisory rule (.md) |
243
+
244
+ **Enforcement levels:**
245
+ - **TypeScript plugins** (OpenCode/Claude Code): Programmatic — intercepts and blocks violations at runtime
246
+ - **Bash hooks** (Cline): Programmatic — executable scripts that cancel or warn via JSON contract
247
+ - **Advisory rules** (Cursor/Kilo): Instructional — AI follows rules as system prompt guidance (no programmatic enforcement)
package/install.sh ADDED
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ VERSION="${INSTALL_VERSION:-main}"
5
+ REPO_RAW="https://raw.githubusercontent.com/YosefHayim/ai-guard-plugins/${VERSION}/plugins"
6
+ PLUGINS=(billing-guard auto-lint-fix auto-summarize-input capture-insights cursorrules-enforcer dry-guard)
7
+
8
+ CLINE_HOOKS=(PreToolUse PostToolUse UserPromptSubmit TaskComplete)
9
+ CURSOR_RULES=(billing-guard dry-guard code-standards auto-lint-fix auto-summarize-input capture-insights)
10
+ KILO_RULES=(billing-guard dry-guard code-standards auto-lint-fix auto-summarize-input capture-insights)
11
+
12
+ detect_platform() {
13
+ if [ -n "${AI_GUARD_PLATFORM:-}" ]; then
14
+ case "$AI_GUARD_PLATFORM" in
15
+ opencode) echo "opencode" ;;
16
+ claude) echo "claude" ;;
17
+ cline) echo "cline" ;;
18
+ cursor) echo "cursor" ;;
19
+ kilo) echo "kilo" ;;
20
+ *) echo "Unknown platform: $AI_GUARD_PLATFORM (use 'opencode', 'claude', 'cline', 'cursor', or 'kilo')" >&2; exit 1 ;;
21
+ esac
22
+ return
23
+ fi
24
+
25
+ if [ -d "$HOME/.config/opencode/plugins" ]; then
26
+ echo "opencode"
27
+ elif [ -d "$HOME/.claude/plugins" ] || [ -d "$HOME/.claude" ]; then
28
+ echo "claude"
29
+ elif [ -d "$HOME/.cline" ] || [ -d "$HOME/.clinerules" ]; then
30
+ echo "cline"
31
+ elif [ -d "$HOME/.cursor" ]; then
32
+ echo "cursor"
33
+ elif [ -d "$HOME/.kilo" ] || [ -d "$HOME/.kilocode" ]; then
34
+ echo "kilo"
35
+ else
36
+ echo ""
37
+ fi
38
+ }
39
+
40
+ PLATFORM=$(detect_platform)
41
+
42
+ if [ -z "$PLATFORM" ]; then
43
+ echo "Could not detect platform. Set AI_GUARD_PLATFORM to one of:"
44
+ echo ""
45
+ echo " AI_GUARD_PLATFORM=opencode bash install.sh"
46
+ echo " AI_GUARD_PLATFORM=claude bash install.sh"
47
+ echo " AI_GUARD_PLATFORM=cline bash install.sh"
48
+ echo " AI_GUARD_PLATFORM=cursor bash install.sh"
49
+ echo " AI_GUARD_PLATFORM=kilo bash install.sh"
50
+ exit 1
51
+ fi
52
+
53
+ install_opencode_claude() {
54
+ local dest="$1"
55
+ mkdir -p "$dest"
56
+ echo "Installing AI Guard Plugins (${VERSION}) to: $dest"
57
+ echo ""
58
+ for plugin in "${PLUGINS[@]}"; do
59
+ echo " Downloading ${plugin}.ts..."
60
+ curl -fsSL "${REPO_RAW}/${plugin}.ts" -o "${dest}/${plugin}.ts"
61
+ done
62
+ echo ""
63
+ echo "Done! ${#PLUGINS[@]} plugins installed to ${dest}"
64
+ }
65
+
66
+ install_cline() {
67
+ local dest="$1"
68
+ mkdir -p "$dest"
69
+ echo "Installing AI Guard Hooks for Cline (${VERSION}) to: $dest"
70
+ echo ""
71
+ for hook in "${CLINE_HOOKS[@]}"; do
72
+ echo " Downloading ${hook}..."
73
+ curl -fsSL "${REPO_RAW}/cline/hooks/${hook}" -o "${dest}/${hook}"
74
+ chmod +x "${dest}/${hook}"
75
+ done
76
+ echo ""
77
+ echo "Done! ${#CLINE_HOOKS[@]} hooks installed to ${dest}"
78
+ echo "Requires: jq (https://jqlang.github.io/jq/)"
79
+ }
80
+
81
+ install_cursor() {
82
+ local dest="$1"
83
+ mkdir -p "$dest"
84
+ echo "Installing AI Guard Rules for Cursor (${VERSION}) to: $dest"
85
+ echo ""
86
+ for rule in "${CURSOR_RULES[@]}"; do
87
+ echo " Downloading ${rule}.mdc..."
88
+ curl -fsSL "${REPO_RAW}/cursor/rules/${rule}.mdc" -o "${dest}/${rule}.mdc"
89
+ done
90
+ echo ""
91
+ echo "Done! ${#CURSOR_RULES[@]} rules installed to ${dest}"
92
+ }
93
+
94
+ install_kilo() {
95
+ local dest="$1"
96
+ mkdir -p "$dest"
97
+ echo "Installing AI Guard Rules for Kilo Code (${VERSION}) to: $dest"
98
+ echo ""
99
+ for rule in "${KILO_RULES[@]}"; do
100
+ echo " Downloading ${rule}.md..."
101
+ curl -fsSL "${REPO_RAW}/kilo/rules/${rule}.md" -o "${dest}/${rule}.md"
102
+ done
103
+ echo ""
104
+ echo "Done! ${#KILO_RULES[@]} rules installed to ${dest}"
105
+ }
106
+
107
+ case "$PLATFORM" in
108
+ opencode)
109
+ install_opencode_claude "$HOME/.config/opencode/plugins"
110
+ ;;
111
+ claude)
112
+ install_opencode_claude "$HOME/.claude/plugins"
113
+ ;;
114
+ cline)
115
+ install_cline "$HOME/.clinerules/hooks"
116
+ ;;
117
+ cursor)
118
+ install_cursor "$HOME/.cursor/rules"
119
+ ;;
120
+ kilo)
121
+ if [ -d "$HOME/.kilocode" ] && [ ! -d "$HOME/.kilo" ]; then
122
+ install_kilo "$HOME/.kilocode/rules"
123
+ else
124
+ install_kilo "$HOME/.kilo/rules"
125
+ fi
126
+ ;;
127
+ esac
128
+
129
+ echo "Restart your AI coding assistant to activate them."