Skip to content

feat: add Cline (cline.bot VS Code extension) preset and hook installer#1301

Open
Krishnachaitanyakc wants to merge 3 commits into
git-ai-project:mainfrom
Krishnachaitanyakc:feat/cline-support-538
Open

feat: add Cline (cline.bot VS Code extension) preset and hook installer#1301
Krishnachaitanyakc wants to merge 3 commits into
git-ai-project:mainfrom
Krishnachaitanyakc:feat/cline-support-538

Conversation

@Krishnachaitanyakc
Copy link
Copy Markdown
Contributor

@Krishnachaitanyakc Krishnachaitanyakc commented May 7, 2026

Summary

Adds first-class support for the Cline VS Code extensionsaoudrizwan.claude-dev — against the post-rewrite agent-preset framework. Closes #538.

Cline's hook system is unusual: hooks are not declared in a config file, but as extensionless executable scripts dropped into a global hooks directory (upstream docs). The script's filename IS the registration. Cline ships only as a VS Code extension (no standalone CLI).

Preset (presets/cline.rs)

  • Pure parser implementing AgentPreset::parse. Handles PreToolUse / PostToolUse for write_to_file, replace_in_file, and execute_command.
  • Strict event handling: lifecycle events (TaskStart, TaskResume, TaskCancel, TaskComplete, UserPromptSubmit, PreCompact) return PresetError rather than fabricating a phantom file-edit checkpoint.
  • Workspace-relative path resolution: parameters.path is resolved against workspaceRoots[0]; absolute paths pass through unchanged.
  • Model extraction tolerates both shapes: prefer the documented model.slug, fall back to a bare-string model, default to "unknown" when missing.
  • transcript_source: None for v1 — Cline holds conversation state in the VS Code webview, not in a documented on-disk format. A dedicated reader can land in a follow-up.

Installer (mdm/agents/cline.rs)

  • Drops extensionless executable shell scripts at ~/Documents/Cline/Hooks/PreToolUse and PostToolUse (or .ps1 files on Windows). Cline's hook system uses the filename itself as registration — no JSON/TOML/YAML config to merge.
  • Sets the executable bit on Unix (mode | 0o755).
  • Each script carries a marker comment plus the embedded git-ai checkpoint cline invocation; recognition for idempotency and uninstall requires both signals — so a sibling preset's marker-tagged file (e.g. accidentally invoking checkpoint claude) is not matched as ours.
  • Refuses to overwrite a user-defined script at the PreToolUse or PostToolUse path, surfacing a warning and continuing with the other event.
  • Idempotent. Uninstall removes only managed scripts and preserves user-owned files in the same directory.
  • process_names() returns an empty vec because Cline ships only as a VS Code extension; we use Hooks-dir existence as the install signal.

Tool classification (bash_tool.rs)

  • New Agent::Cline variant: write_to_file / replace_in_fileFileEdit, execute_commandBash, all else Skip.

Wiring

  • presets/mod.rs::resolve_preset accepts cline.
  • mdm/agents/mod.rs::get_all_installers includes ClineInstaller.
  • git_ai_handlers help text lists cline.
  • AI_AUTHOR_NAMES and is_known_checkpoint_preset learn cline.

Note on the upstream Cline discussion

The issue references cline/cline#9351, which is the issue-author's request for Cline to integrate WITH git-ai. That discussion has not been picked up by Cline's maintainers and is unrelated to our integration direction (we install hooks INTO Cline's documented hook system, no upstream changes required).

Test plan

  • cargo fmt --check clean
  • cargo clippy --all-targets -- -D warnings clean (no #[allow(...)] annotations added)
  • RUSTDOCFLAGS="-D warnings" cargo doc --no-deps clean
  • 13 preset unit tests (presets::cline::tests::*) — pre/post for each of the 3 supported tools, lifecycle event rejection (all 6), unsupported tool rejection (all 10 documented read-only/non-mutating tools), missing field errors (taskId, workspaceRoots), invalid JSON, absolute path passthrough, model extraction (object form, bare string form, default-to-unknown)
  • 15 installer unit tests (mdm::agents::cline::tests::*) — fresh install (s1), executable-bit set on Unix (s1b), idempotency (s2), updates outdated path (s3), dry-run (s4), creates Hooks dir (s5), refuses to overwrite user-defined scripts (s6); uninstall variants u1-u4; marker-recognition tests including a sibling-preset rejection (test_is_git_ai_cline_script_rejects_other_preset)
  • 9 integration tests (tests/integration/cline.rs) — preset routing for all 3 tool classes, lifecycle/tool rejection sweeps, 3 E2E flows asserting assert_lines_and_blame and session metadata
  • Full lib test suite passes locally on macOS in daemon mode

Open in Devin Review

Adds first-class support for Cline's hook protocol against the
post-rewrite agent-preset framework.

Preset (`presets/cline.rs`):
  - Pure parser implementing `AgentPreset::parse`. Handles
    `PreToolUse` / `PostToolUse` for `write_to_file`,
    `replace_in_file`, and `execute_command`.
  - Strict event handling: lifecycle events (`TaskStart`,
    `TaskResume`, `TaskCancel`, `TaskComplete`, `UserPromptSubmit`,
    `PreCompact`) return `PresetError` rather than fabricating a
    phantom file-edit checkpoint.
  - Workspace-relative path resolution: `parameters.path` is
    resolved against `workspaceRoots[0]`; absolute paths pass
    through unchanged.
  - Model extraction tolerates both shapes: prefer the documented
    `model.slug`, fall back to a bare-string `model`, default to
    `"unknown"` when missing.
  - `transcript_source: None`. Cline holds conversation state in
    the VS Code webview, not in a documented on-disk format; a
    dedicated reader can land in a follow-up.

Installer (`mdm/agents/cline.rs`):
  - Drops extensionless executable shell scripts at
    `~/Documents/Cline/Hooks/PreToolUse` and `PostToolUse` (or
    `.ps1` files on Windows). Cline's hook system uses the
    filename itself as the registration — no JSON/TOML/YAML
    config to merge.
  - Sets the executable bit on Unix (mode | 0o755).
  - Each script carries a marker comment plus the embedded
    `git-ai checkpoint cline` invocation; recognition for
    idempotency and uninstall requires both signals.
  - Refuses to overwrite a user-defined script at the PreToolUse
    or PostToolUse path, surfacing a warning and continuing with
    the other event.
  - Idempotent. Uninstall removes only managed scripts and
    preserves user-owned files in the same directory.
  - `process_names()` returns an empty vec because Cline ships
    only as a VS Code extension (`saoudrizwan.claude-dev`); we
    use Hooks-dir existence as the install signal.

Tool classification (`bash_tool.rs`):
  - New `Agent::Cline` variant. `write_to_file` /
    `replace_in_file` map to `FileEdit`, `execute_command` maps
    to `Bash`, all else `Skip`.

Wiring:
  - `presets/mod.rs::resolve_preset` accepts `cline`.
  - `mdm/agents/mod.rs::get_all_installers` includes
    `ClineInstaller`.
  - `git_ai_handlers` help text lists `cline`.
  - `tests/integration/repos/test_file.rs::AI_AUTHOR_NAMES` and
    `test_repo.rs::is_known_checkpoint_preset` learn `cline`.

Tests: 13 preset unit tests, 15 installer unit tests (including a
Unix-gated executable-bit check and a marker-rejection test for
sibling presets), 9 integration tests including 3 full E2E flows
asserting `assert_lines_and_blame`. `cargo fmt --check`,
`cargo clippy --all-targets -- -D warnings`,
`RUSTDOCFLAGS=\"-D warnings\" cargo doc --no-deps`, and the
relevant test suites all pass locally.

Closes git-ai-project#538
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment thread src/mdm/agents/cline.rs Outdated
Comment thread tests/integration/cline.rs Fixed
CodeQL flags the previous `panic!("...", &events[0])` patterns as
cleartext logging of sensitive information because the Debug
serialization of `ParsedHookEvent` includes `external_session_id`.

Drop the `{:?}` argument; the panic message itself already names
the expected variant, so this matches the existing convention used
by gemini, amp, opencode, etc.
Devin Review (PR git-ai-project#1301) flagged that `install_hooks_at` was calling
`fs::create_dir_all(hooks_dir)?` unconditionally, even under
`dry_run = true`. That created `~/Documents/Cline/Hooks/` on the
user's filesystem during what is supposed to be a no-op preview, and
left a side-effect that a subsequent `check_hooks` call would
interpret as "Cline is installed."

Move the `create_dir_all` inside `if !dry_run`, matching the existing
convention in `mdm/agents/opencode.rs`, `mdm/agents/pi.rs`,
`mdm/agents/amp.rs`, and `mdm/agents/github_copilot.rs`.

Strengthen the s4 dry-run test to assert the hooks dir itself is
also not created — that's the property Devin's report is really
about.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cline IDE support

3 participants