Skip to content

Commit 406f805

Browse files
committed
feat(terminal): add integrated Claude terminal support
Change-Id: I973687af9592634125ab87088b64b943cdd388bd Signed-off-by: Thomas Kosiewski <[email protected]>
1 parent dd4f4c1 commit 406f805

20 files changed

+1137
-195
lines changed

.github/workflows/claude-review.yaml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Claude Code Review
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize] # Runs on new PRs and updates
6+
7+
permissions: {}
8+
9+
jobs:
10+
code-review:
11+
runs-on: ubuntu-latest
12+
steps:
13+
# Check out the code to allow git diff operations
14+
- name: Checkout code
15+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
16+
with:
17+
fetch-depth: 0 # Fetch full history for accurate diffs
18+
persist-credentials: false
19+
20+
- name: Run Code Review with Claude
21+
id: code-review
22+
uses: anthropics/claude-code-action@8b9d5bb25a638c9aa5103496c0139d99b4936d42 # beta
23+
with:
24+
# Define the review focus areas
25+
prompt: "Review the PR changes. Focus on code quality, potential bugs, and performance issues. Suggest improvements where appropriate."
26+
27+
# Limited tools for safer review operations
28+
allowed_tools: >-
29+
[
30+
"Bash(git diff --name-only HEAD~1)",
31+
"Bash(git diff HEAD~1)",
32+
"View",
33+
"GlobTool",
34+
"GrepTool"
35+
]
36+
37+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

.github/workflows/claude.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@ jobs:
2323
id-token: write
2424
steps:
2525
- name: Checkout repository
26-
uses: actions/checkout@v4
26+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
2727
with:
2828
fetch-depth: 1
29+
persist-credentials: false
2930

3031
- name: Run Claude Code
3132
id: claude
32-
uses: anthropics/claude-code-action@beta
33+
uses: anthropics/claude-code-action@8b9d5bb25a638c9aa5103496c0139d99b4936d42 # beta
3334
with:
3435
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

.github/workflows/test.yml

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ on:
66
pull_request:
77
branches: [main]
88

9+
permissions: {}
10+
911
jobs:
1012
unit-tests:
1113
runs-on: ubuntu-latest
@@ -14,21 +16,23 @@ jobs:
1416
neovim-version: ["stable", "nightly"]
1517

1618
steps:
17-
- uses: actions/checkout@v3
19+
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
20+
with:
21+
persist-credentials: false
1822

1923
- name: Setup Neovim
20-
uses: rhysd/action-setup-vim@v1
24+
uses: rhysd/action-setup-vim@8e931b9954b19d4203d5caa5ff5521f3bc21dcc7 # v1.4.2
2125
with:
2226
neovim: true
2327
version: ${{ matrix.neovim-version }}
2428

2529
- name: Setup Lua
26-
uses: leafo/gh-actions-lua@v10
30+
uses: leafo/gh-actions-lua@ea0ae38dcce88ab752b6ece373af78c41205b6cb # v10
2731
with:
2832
luaVersion: "5.1"
2933

3034
- name: Setup Luarocks
31-
uses: leafo/gh-actions-luarocks@v4
35+
uses: leafo/gh-actions-luarocks@70d2def2964e973ce42dbf91b2900dd97cbaf78f # v4
3236

3337
- name: Install dependencies
3438
run: |
@@ -52,7 +56,7 @@ jobs:
5256
luacov-console -r lcov > lcov.info
5357
5458
- name: Upload coverage report
55-
uses: codecov/codecov-action@v3
59+
uses: codecov/codecov-action@c16abc29c95fcf9174b58eb7e1abf4c866893bc8 # v4
5660
with:
5761
files: ./tests/lcov.info
5862
fail_ci_if_error: false
@@ -65,18 +69,20 @@ jobs:
6569
neovim-version: ["stable"]
6670

6771
steps:
68-
- uses: actions/checkout@v3
72+
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
73+
with:
74+
persist-credentials: false
6975

7076
- name: Setup Neovim
71-
uses: rhysd/action-setup-vim@v1
77+
uses: rhysd/action-setup-vim@8e931b9954b19d4203d5caa5ff5521f3bc21dcc7 # v1.4.2
7278
with:
7379
neovim: true
7480
version: ${{ matrix.neovim-version }}
7581

7682
- name: Install test dependencies
7783
run: |
7884
git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim
79-
ln -s $(pwd) ~/.local/share/nvim/site/pack/vendor/start/claudecode.nvim
85+
ln -s "$(pwd)" ~/.local/share/nvim/site/pack/vendor/start/claudecode.nvim
8086
8187
- name: Run integration tests
8288
run: |

ARCHITECTURE.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,32 @@ The plugin monitors text selections in Neovim:
7777
- Formats selection data according to MCP protocol
7878
- Sends updates to Claude via WebSocket
7979

80-
### 5. Environment Integration
80+
### 5. Terminal Integration
81+
82+
The plugin provides a dedicated terminal interface for Claude Code CLI:
83+
84+
- Uses [folke/snacks.nvim](https://github.com/folke/snacks.nvim) for terminal management
85+
- Creates a vertical split terminal with customizable size and position
86+
- Supports focus, toggle, and close operations
87+
- Maintains terminal state across operations
88+
- Automatically cleans up on window close
89+
90+
```
91+
┌─────────────┐ ┌─────────────────┐ ┌─────────────┐
92+
│ │ │ │ │ │
93+
│ Neovim │◄───┤ Claude Terminal │◄───┤ Claude CLI │
94+
│ Buffers │ │ (Snacks.nvim) │ │ │
95+
└─────────────┘ └─────────────────┘ └─────────────┘
96+
```
97+
98+
### 6. Environment Integration
8199

82100
The plugin manages the environment for Claude CLI:
83101

84102
- Sets required environment variables:
85103
- `CLAUDE_CODE_SSE_PORT`: The WebSocket server port
86104
- `ENABLE_IDE_INTEGRATION`: Enabled flag
87-
- Provides terminal integration for launching Claude
105+
- Provides configuration for the terminal command
88106

89107
## Message Flow
90108

@@ -141,6 +159,7 @@ lua/claudecode/
141159
│ ├── editor.lua # Editor information tools
142160
│ └── selection.lua # Selection management tools
143161
├── selection.lua # Selection tracking
162+
├── terminal.lua # Terminal management (uses Snacks.nvim)
144163
├── environment.lua # Environment variable management
145164
└── util.lua # Utility functions
146165
```
@@ -170,6 +189,7 @@ tests/
170189
├── unit/
171190
│ ├── config_spec.lua
172191
│ ├── server_spec.lua
192+
│ ├── terminal_spec.lua
173193
│ └── tools_spec.lua
174194
├── component/
175195
│ ├── server_spec.lua

README.md

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,19 @@ A Neovim plugin that integrates with Claude Code CLI to provide a seamless AI co
1212
- 🔍 Selection tracking to provide context to Claude
1313
- 🛠️ Integration with Neovim's buffer and window management
1414
- 📝 Support for file operations and diagnostics
15-
- 🖥️ Terminal integration for launching Claude with proper environment
15+
- 🖥️ Interactive vertical split terminal for Claude sessions (via `folke/snacks.nvim`)
1616
- 🔒 Automatic cleanup on exit - server shutdown and lockfile removal
1717

1818
## Requirements
1919

2020
- Neovim >= 0.8.0
2121
- Claude Code CLI installed and in your PATH
2222
- Lua >= 5.1
23+
- **Required for terminal integration:** [folke/snacks.nvim](https://github.com/folke/snacks.nvim) - Terminal management plugin
2324
- Optional: plenary.nvim for additional utilities
2425

26+
Note: The terminal feature requires Snacks.nvim to be installed and available. If not available, the terminal commands will display an error message, but the core Claude Code integration will still function.
27+
2528
## Installation
2629

2730
### Using [lazy.nvim](https://github.com/folke/lazy.nvim)
@@ -31,8 +34,11 @@ A Neovim plugin that integrates with Claude Code CLI to provide a seamless AI co
3134
"ThomasK33/claudecode.nvim",
3235
dependencies = {
3336
"nvim-lua/plenary.nvim",
37+
"folke/snacks.nvim", -- Added dependency
3438
},
3539
config = function()
40+
-- Ensure snacks is loaded if you want to use the terminal immediately
41+
-- require("snacks") -- Or handle this in your init.lua
3642
require("claudecode").setup({
3743
-- Optional configuration
3844
})
@@ -45,7 +51,10 @@ A Neovim plugin that integrates with Claude Code CLI to provide a seamless AI co
4551
```lua
4652
use {
4753
"ThomasK33/claudecode.nvim",
48-
requires = { "nvim-lua/plenary.nvim" },
54+
requires = {
55+
"nvim-lua/plenary.nvim",
56+
"folke/snacks.nvim", -- Added dependency
57+
},
4958
config = function()
5059
require("claudecode").setup({
5160
-- Optional configuration
@@ -64,13 +73,28 @@ return {
6473
"ThomasK33/claudecode.nvim",
6574
dependencies = {
6675
"nvim-lua/plenary.nvim",
76+
"folke/snacks.nvim", -- Added dependency
6777
},
6878
opts = {
69-
-- Optional configuration
79+
-- Optional configuration for claudecode main
80+
-- Example:
81+
-- terminal_cmd = "claude --magic-flag",
82+
83+
-- Configuration for the interactive terminal can also be nested here:
84+
terminal = {
85+
split_side = "left", -- "left" or "right"
86+
split_width_percentage = 0.4, -- 0.0 to 1.0
87+
},
7088
},
89+
-- The main require("claudecode").setup(opts) will handle passing
90+
-- opts.terminal to the terminal module's setup.
91+
config = true, -- or function(_, opts) require("claudecode").setup(opts) end
7192
keys = {
7293
{ "<leader>cc", "<cmd>ClaudeCodeStart<cr>", desc = "Start Claude Code" },
7394
{ "<leader>cs", "<cmd>ClaudeCodeSend<cr>", desc = "Send to Claude Code" },
95+
{ "<leader>ct", "<cmd>ClaudeCode<cr>", desc = "Toggle Claude Terminal" },
96+
{ "<leader>co", "<cmd>ClaudeCodeOpen<cr>", desc = "Open Claude Terminal" },
97+
{ "<leader>cx", "<cmd>ClaudeCodeClose<cr>", desc = "Close Claude Terminal" },
7498
},
7599
},
76100
}
@@ -87,16 +111,27 @@ return {
87111
name = "claudecode.nvim",
88112
dependencies = {
89113
"nvim-lua/plenary.nvim",
114+
"folke/snacks.nvim", -- Added dependency
90115
},
91116
dev = true,
92117
opts = {
93-
-- Development configuration
118+
-- Development configuration for claudecode main
94119
log_level = "debug",
95120
auto_start = true, -- Optional: auto-start the server
121+
122+
-- Example terminal configuration for dev:
123+
terminal = {
124+
split_side = "right",
125+
split_width_percentage = 0.25,
126+
},
96127
},
128+
config = true,
97129
keys = {
98130
{ "<leader>cc", "<cmd>ClaudeCodeStart<cr>", desc = "Start Claude Code" },
99131
{ "<leader>cs", "<cmd>ClaudeCodeSend<cr>", desc = "Send to Claude Code" },
132+
{ "<leader>ct", "<cmd>ClaudeCode<cr>", desc = "Toggle Claude Terminal" },
133+
{ "<leader>co", "<cmd>ClaudeCodeOpen<cr>", desc = "Open Claude Terminal" },
134+
{ "<leader>cx", "<cmd>ClaudeCodeClose<cr>", desc = "Close Claude Terminal" },
100135
},
101136
},
102137
}
@@ -120,13 +155,24 @@ require("claudecode").setup({
120155
auto_start = false,
121156

122157
-- Custom terminal command to use when launching Claude
123-
terminal_cmd = nil, -- e.g., "toggleterm"
158+
-- This command is used by the new interactive terminal feature.
159+
-- If nil or empty, it defaults to "claude".
160+
terminal_cmd = nil, -- e.g., "my_claude_wrapper_script" or "claude --project-foo"
124161

125162
-- Log level (trace, debug, info, warn, error)
126163
log_level = "info",
127164

128165
-- Enable sending selection updates to Claude
129166
track_selection = true,
167+
168+
-- Configuration for the interactive terminal (passed to claudecode.terminal.setup by the main setup function)
169+
terminal = {
170+
-- Side for the vertical split ('left' or 'right')
171+
split_side = "right", -- Default
172+
173+
-- Width of the terminal as a percentage of total editor width (0.0 to 1.0)
174+
split_width_percentage = 0.30, -- Default
175+
}
130176
})
131177
```
132178

@@ -154,6 +200,9 @@ require("claudecode").setup({
154200
- `:ClaudeCodeStop` - Stop the server
155201
- `:ClaudeCodeStatus` - Show connection status
156202
- `:ClaudeCodeSend` - Send current selection to Claude
203+
- `:ClaudeCode` - Toggle the Claude Code interactive terminal window
204+
- `:ClaudeCodeOpen` - Open (or focus) the Claude Code terminal window
205+
- `:ClaudeCodeClose` - Close the Claude Code terminal window
157206

158207
## Keymaps
159208

@@ -162,6 +211,10 @@ No default keymaps are provided. Add your own in your configuration:
162211
```lua
163212
vim.keymap.set("n", "<leader>cc", "<cmd>ClaudeCodeStart<cr>", { desc = "Start Claude Code" })
164213
vim.keymap.set({"n", "v"}, "<leader>cs", "<cmd>ClaudeCodeSend<cr>", { desc = "Send to Claude Code" })
214+
+vim.keymap.set("n", "<leader>ct", "<cmd>ClaudeCode<cr>", { desc = "Toggle Claude Terminal" })
215+
+-- Or more specific maps:
216+
+-- vim.keymap.set("n", "<leader>co", "<cmd>ClaudeCodeOpen<cr>", { desc = "Open Claude Terminal" })
217+
+-- vim.keymap.set("n", "<leader>cx", "<cmd>ClaudeCodeClose<cr>", { desc = "Close Claude Terminal" })
165218
```
166219

167220
## Architecture

flake.nix

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@
2121
nixpkgs-fmt.enable = true; # Nix formatter
2222
prettier.enable = true; # Markdown/YAML/JSON formatter
2323
shfmt.enable = true; # Shell formatter
24+
actionlint.enable = true; # GitHub Actions linter
25+
zizmor.enable = true; # GitHub Actions security analyzer
26+
shellcheck.enable = true; # Shell script analyzer
2427
};
28+
settings.formatter.shellcheck.options = [ "--exclude=SC1091,SC2016" ];
2529
};
2630
in
2731
{

0 commit comments

Comments
 (0)