feat: add clineignore plugin#223
Open
saoudrizwan wants to merge 2 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a
clineignoreplugin: the plugin successor to the built-in.clineignoresupport that only ever existed in the legacy VS Code extension (ClineIgnoreController) and was never migrated to the SDK/CLI. With.clineignorenow marked as deprecated in the docs (cline/cline#12410), this gives users a real replacement they can install withcline plugin install clineignore.It reads a
.clineignorefile at the workspace root (standard.gitignoresyntax via theignorenpm package, the same library the legacy controller used) and registers abeforeToolhook that:read_files/editor/apply_patchcalls when any requested path matches an ignore patternrun_commandscalls when a file-reading command (cat,less,more,head,tail,grep,awk,sed, plus the PowerShell equivalentsget-content,gc,type,select-string,sls) targets an ignored pathIt also registers a system prompt rule (when
.clineignoreexists at session start) so the model knows blocked paths are intentional and that it should work around them or ask the user, mirroring theclineIgnoreInstructionsprompt section the legacy extension injected.Legacy parity decisions
I went through the legacy implementation enforcement point by enforcement point and deliberately kept its semantics where they were defensible:
!include <file>directive support (pulls extra pattern files, resolved relative to the workspace root; missing includes silently skipped).clineignorefile itself is always treated as ignoredvalidateAccessclineIgnoreErrorresponse ("Access to X is blocked by the .clineignore file...") so models behave the same way they did against the legacy extension|,||,&&, and;so each pipeline/sequence segment gets its base command checked (legacy only looked at the first token of the whole string, sols && cat .envslipped through)Instead of legacy's chokidar watcher, the ignore file is re-stat'd per hook call and the parsed matcher is cached by mtime+size. Same live-reload user experience (editing
.clineignoretakes effect immediately, mid session), no watcher lifecycle to manage, and plugins have no host-provided file watching API anyway.Deliberately descoped from v1: filtering ignored files out of
search_codebaseresults. The search tool returns a preformatted string per query, so filtering means fragile string parsing in anafterToolhook. The README documents this as a known hole. Also not covered, same as legacy: shell redirection/subshells/xargs, and quote-aware tokenization. The README is explicit that this is context hygiene, not a security boundary, which matches the reasoning in the deprecation docs commit.The sandbox interop bug (debugging journey)
The first version passed a 22-case smoke test under plain
bun runand typechecked against published@cline/core, then silently failed to block anything in a real installed session. No error anywhere: the fail-opencatchin the loader swallowed it, andconsole.warnfrom sandboxed plugins goes nowhere.Debugging recipe that found it: instrument the installed copy under
.cline/plugins/_installed/.../package/index.tswithappendFileSyncprobes (module scope,setup, hook body, catch blocks) and rerun the session. That showed the plugin loaded,setupgot the right workspace root,beforeToolfired... and the matcher constructor threw(0 , _ignore.default) is not a function.Root cause: the plugin sandbox's transpiled module interop delivers the
ignorepackage (dual CJS/ESM) as a namespace object{ default: factory, isPathValid }where the transpiled default-import access expects the factory itself. Under plain bun the same import IS the factory, which is exactly why unit tests can't catch this class of bug. Fix is a runtime unwrap:Anyone writing a sandboxed plugin with a CJS/dual-package dependency will hit this same landmine; worth keeping in mind for other plugins in this repo.
One more behavior found only in the live run: a batched
read_filescall mixing blocked and allowed paths skips the whole call (beforeTool skip is all-or-nothing), so the reason string now tells the model to re-request allowed files in a separate call, which the model did correctly on the next turn.How to test
Verified:
npm run validatepasses,tsc --noEmitagainst published@cline/coretypes, a 22-case smoke suite driving the hook directly (ignored/allowed/outside-workspace paths,!include, structured + string + pipeline command inputs, live reload after editing.clineignore, no-op when no ignore file exists), and the full CLI e2e above on cline 3.0.46 (both the failing before-fix run and the passing after-fix run).Marketplace entry: cline/marketplace PR adds
registry/plugins/clineignore. Follow-up for cline/cline: point the.clineignoredeprecation docs at this plugin instead of thegitignore-read-files-guardexample. Note the new VS Code/JetBrains extension can't run SDK plugins yet, so this replacement currently covers CLI/SDK/Kanban only.