Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0fcd6ad
fix(hooks): stop Copilot from ever asserting a permissionDecision on …
KuSh Jul 25, 2026
b754b85
fix(hooks): drop redundant camelCase preToolUse entry from Copilot ho…
KuSh Jul 26, 2026
1ebc271
fix(hooks): recognize VS Code Copilot Chat's run_in_terminal tool name
KuSh Jul 26, 2026
1253d15
docs(hooks): clarify CopilotCli schema is now legacy/host-specific, n…
KuSh Jul 26, 2026
2cb3908
docs(hooks): confirm PascalCase Bash mapping already covers Windows p…
KuSh Jul 27, 2026
fc8054e
feat(rewrite): rewrite each line of multi-line Bash blocks
revopsrocks Jul 24, 2026
ac5febe
fix(rewrite): bail on swallowed newlines and cross-line arithmetic
revopsrocks Jul 24, 2026
93aab9a
fix(rewrite): harden line-independence checks from second review round
revopsrocks Jul 24, 2026
d171449
fix(rewrite): narrow multiline passthrough bails from #3188 review
aeppling Jul 30, 2026
3c8892f
fix(rewrite): keep rewriting quoted multi-line strings as one command
aeppling Jul 30, 2026
b09da2d
fix(rewrite): bail on cross-line [[ ]], share quote-state walker
aeppling Aug 1, 2026
8722378
Merge pull request #3212 from rtk-ai/fix/copilot-parity-omit-permissi…
KuSh Aug 2, 2026
3044911
Merge pull request #3319 from rtk-ai/feat/rewrite-multiline-blocks
aeppling Aug 3, 2026
d480f1e
feat(hooks): add transparent hook support for Mistral Vibe CLI
xavierpestel-ai Aug 4, 2026
1847b07
fix(vibe): address PR review — exit code contract, tests, telemetry, …
xavierpestel-ai Aug 5, 2026
94ae76b
docs(vibe): add hooks/vibe/README.md and link from Directory Structure
xavierpestel-ai Aug 5, 2026
0430df4
refactor(vibe): drop defensive-only comment on Host::Vibe arm
xavierpestel-ai Aug 5, 2026
d1f7139
fix(hooks): self-heal stale dual-schema Copilot hook config
aeppling Aug 5, 2026
db31da9
fix(hooks): heal only rtk's own legacy camelCase entry, keep user config
aeppling Aug 5, 2026
f676ad7
test(hooks): end-to-end matrix for Copilot self-heal safety
aeppling Aug 5, 2026
157b0ac
refacto(copilot): rm migration tests
aeppling Aug 5, 2026
99841dc
chore(hooks): suppress semgrep on temp-file cleanup
aeppling Aug 5, 2026
4ff41bd
ci(semgrep): suppress filesystem-deletion warnings on Vibe uninstall …
xavierpestel-ai Aug 5, 2026
9dae4d7
refactor(vibe): address second-round nits from @aeppling
xavierpestel-ai Aug 5, 2026
de1f568
Merge pull request #3391 from xavierpestel-ai/feat/vibe-hook-support
aeppling Aug 6, 2026
9936b2b
Merge pull request #3449 from rtk-ai/feat/copilot-hook-self-heal
aeppling Aug 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/contributing/TECHNICAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ Start here, then drill down into each README for file-level details.
|-----------|-------|-------------------------------|
| [`hooks/`](../hooks/README.md) | _(parent)_ | **All JSON formats**, rewrite registry overview, exit code contract, override controls |
| [`claude/`](../hooks/claude/README.md) | Claude Code | Shell hook mechanism, `PreToolUse` JSON, test script |
| [`copilot/`](../hooks/copilot/README.md) | GitHub Copilot | Rust binary hook, VS Code Chat vs Copilot CLI dual format |
| [`copilot/`](../hooks/copilot/README.md) | GitHub Copilot | Rust binary hook, single `PreToolUse` schema shared by VS Code Chat and Copilot CLI |
| [`cursor/`](../hooks/cursor/README.md) | Cursor IDE | Shell hook, empty JSON response requirement |
| [`cline/`](../hooks/cline/README.md) | Cline / Roo Code | Rules file (prompt-level, no programmatic hook) |
| [`windsurf/`](../hooks/windsurf/README.md) | Windsurf / Cascade | Rules file (workspace-scoped) |
Expand All @@ -331,7 +331,7 @@ RTK supports the following LLM agents through hook integrations:
|-------|-----------|-----------|---------------------|
| Claude Code | Shell hook | `PreToolUse` in `settings.json` | Yes (`updatedInput`) |
| GitHub Copilot (VS Code) | Rust binary | `rtk hook copilot` reads JSON | Yes (`updatedInput`) |
| GitHub Copilot CLI | Rust binary | `rtk hook copilot` reads JSON | No (deny + suggestion) |
| GitHub Copilot CLI | Rust binary | `rtk hook copilot` reads JSON | Yes (`updatedInput`) |
| Cursor | Rust binary | `rtk hook cursor` reads JSON | Yes (`updated_input`) |
| Gemini CLI | Rust binary | `rtk hook gemini` reads JSON | Yes (`hookSpecificOutput`) |
| Cline/Roo Code | Rules file | Prompt-level guidance | N/A (prompt) |
Expand Down
6 changes: 4 additions & 2 deletions docs/guide/getting-started/supported-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Agent runs "cargo test"
|-------|-----------------|---------------------------|
| Claude Code | Shell hook (`PreToolUse`) | Yes |
| VS Code Copilot Chat | Shell hook (`PreToolUse`) | Yes |
| GitHub Copilot CLI | Shell hook (`preToolUse` `modifiedArgs`) | Yes |
| GitHub Copilot CLI | Shell hook (`PreToolUse`) | Yes |
| Cursor | Shell hook (`preToolUse`) | Yes |
| Gemini CLI | Rust binary (`BeforeTool`) | Yes |
| OpenCode | TypeScript plugin (`tool.execute.before`) | Yes |
Expand Down Expand Up @@ -74,7 +74,9 @@ rtk init --copilot # project-scoped (.github/hooks/)
rtk init --global --copilot # user-scoped (~/.copilot/hooks/, respects $COPILOT_HOME)
```

Project-scoped writes `.github/hooks/rtk-rewrite.json` (both hosts get transparent rewrite — VS Code Chat via `updatedInput`, Copilot CLI via `modifiedArgs`) plus the RTK block in `.github/copilot-instructions.md`. User-scoped writes the same hook config to `~/.copilot/hooks/rtk-rewrite.json` and the RTK block to `~/.copilot/copilot-instructions.md` (both respect `$COPILOT_HOME` if set).
Project-scoped writes `.github/hooks/rtk-rewrite.json` — a single `PreToolUse` entry shared by both hosts, each getting transparent rewrite via `updatedInput` — plus the RTK block in `.github/copilot-instructions.md`. User-scoped writes the same hook config to `~/.copilot/hooks/rtk-rewrite.json` and the RTK block to `~/.copilot/copilot-instructions.md` (both respect `$COPILOT_HOME` if set).

Earlier `rtk` versions also registered a second, camelCase `preToolUse` entry for Copilot CLI's native schema. Copilot CLI treats `PreToolUse`/`preToolUse` as independent hooks and runs both sequentially for the same tool call — a redundant process spawn with no behavioral benefit, since Copilot CLI honors the single `PreToolUse` schema on its own. Re-run `rtk init --copilot` (or `--global --copilot`) to upgrade an existing install to the single-hook config.

Uninstall:

Expand Down
20 changes: 20 additions & 0 deletions src/discover/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ pub fn tokenize(input: &str) -> Vec<ParsedToken> {
tokenize_inner(input, false)
}

/// Like [`tokenize`] but emits a `\n` operator token for each newline that
/// sits outside quotes. Newlines inside quoted strings stay part of their
/// argument, so callers can use the emitted offsets as safe line-split points.
pub fn tokenize_with_newlines(input: &str) -> Vec<ParsedToken> {
tokenize_inner(input, true)
}

fn tokenize_inner(input: &str, emit_newline: bool) -> Vec<ParsedToken> {
let mut tokens = Vec::new();
let mut current = String::new();
Expand Down Expand Up @@ -1342,4 +1349,17 @@ mod tests {
assert!(split_for_permissions("").is_empty());
assert!(split_for_permissions(" ").is_empty());
}

#[test]
fn test_tokenize_with_newlines_emits_operator_outside_quotes_only() {
let newline_ops = |input: &str| {
tokenize_with_newlines(input)
.iter()
.filter(|t| t.kind == TokenKind::Operator && t.value == "\n")
.count()
};
assert_eq!(newline_ops("git status\ngit log"), 1);
assert_eq!(newline_ops("echo 'line1\nline2'"), 0);
assert_eq!(newline_ops("git status\r\ngit log"), 2);
}
}
Loading
Loading