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.
- package/.github/workflows/publish.yml +42 -0
- package/.github/workflows/release.yml +156 -0
- package/CONTRIBUTING.md +56 -0
- package/LICENSE +21 -0
- package/README.md +247 -0
- package/install.sh +129 -0
- package/install.yaml +49 -0
- package/llms.txt +33 -0
- package/package.json +24 -0
- package/plugins/auto-lint-fix.ts +39 -0
- package/plugins/auto-summarize-input.ts +45 -0
- package/plugins/billing-guard.ts +101 -0
- package/plugins/capture-insights.ts +215 -0
- package/plugins/cline/hooks/PostToolUse +73 -0
- package/plugins/cline/hooks/PreToolUse +200 -0
- package/plugins/cline/hooks/TaskComplete +134 -0
- package/plugins/cline/hooks/UserPromptSubmit +29 -0
- package/plugins/cursor/rules/auto-lint-fix.mdc +21 -0
- package/plugins/cursor/rules/auto-summarize-input.mdc +17 -0
- package/plugins/cursor/rules/billing-guard.mdc +26 -0
- package/plugins/cursor/rules/capture-insights.mdc +32 -0
- package/plugins/cursor/rules/code-standards.mdc +77 -0
- package/plugins/cursor/rules/dry-guard.mdc +31 -0
- package/plugins/cursorrules-enforcer.ts +124 -0
- package/plugins/dry-guard.ts +107 -0
- package/plugins/kilo/rules/auto-lint-fix.md +15 -0
- package/plugins/kilo/rules/auto-summarize-input.md +12 -0
- package/plugins/kilo/rules/billing-guard.md +21 -0
- package/plugins/kilo/rules/capture-insights.md +27 -0
- package/plugins/kilo/rules/code-standards.md +71 -0
- package/plugins/kilo/rules/dry-guard.md +25 -0
|
@@ -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)
|
package/CONTRIBUTING.md
ADDED
|
@@ -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)
|
|
6
|
+
[](#plugins)
|
|
7
|
+
[](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."
|