Skip to content

Commit 3e2601f

Browse files
committed
feat: add AGENTS.md and improve config validation with diff cleanup enhancements
Change-Id: Id68772addfdfaa614de2f9c7896257f6b7234868 Signed-off-by: Thomas Kosiewski <tk@coder.com>
1 parent 3e66fd9 commit 3e2601f

File tree

3 files changed

+74
-9
lines changed

3 files changed

+74
-9
lines changed

AGENTS.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Repository Guidelines
2+
3+
## Project Structure & Module Organization
4+
5+
- `lua/claudecode/`: Core plugin modules (`init.lua`, `config.lua`, `diff.lua`, `terminal/`, `server/`, `tools/`, `logger.lua`, etc.).
6+
- `plugin/`: Lightweight loader that guards startup and optional auto-setup.
7+
- `tests/`: Busted test suite (`unit/`, `integration/`, `helpers/`, `mocks/`).
8+
- `fixtures/`: Minimal Neovim configs for manual and integration testing.
9+
- `scripts/`: Development helpers; `dev-config.lua` aids local testing.
10+
11+
## Build, Test, and Development Commands
12+
13+
- `make check`: Syntax checks + `luacheck` on `lua/` and `tests/`.
14+
- `make format`: Format with StyLua (via Nix `nix fmt` in this repo).
15+
- `make test`: Run Busted tests with coverage (outputs `luacov.stats.out`).
16+
- `make clean`: Remove coverage artifacts.
17+
Examples:
18+
- Run all tests: `make test`
19+
- Run one file: `busted -v tests/unit/terminal_spec.lua`
20+
21+
## Coding Style & Naming Conventions
22+
23+
- Lua: 2‑space indent, 120‑column width, double quotes preferred.
24+
- Formatting: StyLua configured in `.stylua.toml` (require-sort enabled).
25+
- Linting: `luacheck` with settings in `.luacheckrc` (uses `luajit+busted` std).
26+
- Modules/files: lower_snake_case; return a module table `M` with documented functions (EmmyLua annotations encouraged).
27+
- Avoid one-letter names; prefer explicit, testable functions.
28+
29+
## Testing Guidelines
30+
31+
- Frameworks: Busted + Luassert; Plenary used where Neovim APIs are needed.
32+
- File naming: `*_spec.lua` or `*_test.lua` under `tests/unit` or `tests/integration`.
33+
- Mocks/helpers: place in `tests/mocks` and `tests/helpers`; prefer pure‑Lua mocks.
34+
- Coverage: keep high signal; exercise server, tools, diff, and terminal paths.
35+
- Quick tip: prefer `make test` (it sets `LUA_PATH` and coverage flags).
36+
37+
## Commit & Pull Request Guidelines
38+
39+
- Commits: Use Conventional Commits (e.g., `feat:`, `fix:`, `docs:`, `test:`, `chore:`). Keep messages imperative and scoped.
40+
- PRs: include a clear description, linked issues, repro steps, and tests. Update docs (`README.md`, `ARCHITECTURE.md`, or `DEVELOPMENT.md`) when behavior changes.
41+
- Pre-flight: run `make format`, `make check`, and `make test`. Attach screenshots or terminal recordings for UX-visible changes (diff flows, terminal behavior).
42+
43+
## Security & Configuration Tips
44+
45+
- Do not commit secrets or local paths; prefer environment variables. The plugin honors `CLAUDE_CONFIG_DIR` for lock files.
46+
- Local CLI paths (e.g., `opts.terminal_cmd`) should be configured in user config, not hardcoded in repo files.

lua/claudecode/config.lua

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,10 @@ function M.validate(config)
8989
assert(is_valid_log_level, "log_level must be one of: " .. table.concat(valid_log_levels, ", "))
9090

9191
assert(type(config.track_selection) == "boolean", "track_selection must be a boolean")
92-
assert(type(config.focus_after_send) == "boolean", "focus_after_send must be a boolean")
92+
-- Allow absence in direct validate() calls; apply() supplies default
93+
if config.focus_after_send ~= nil then
94+
assert(type(config.focus_after_send) == "boolean", "focus_after_send must be a boolean")
95+
end
9396

9497
assert(
9598
type(config.visual_demotion_delay_ms) == "number" and config.visual_demotion_delay_ms >= 0,
@@ -131,7 +134,9 @@ function M.validate(config)
131134
if config.diff_opts.on_new_file_reject ~= nil then
132135
assert(
133136
type(config.diff_opts.on_new_file_reject) == "string"
134-
and (config.diff_opts.on_new_file_reject == "keep_empty" or config.diff_opts.on_new_file_reject == "close_window"),
137+
and (
138+
config.diff_opts.on_new_file_reject == "keep_empty" or config.diff_opts.on_new_file_reject == "close_window"
139+
),
135140
"diff_opts.on_new_file_reject must be 'keep_empty' or 'close_window'"
136141
)
137142
end

lua/claudecode/diff.lua

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -814,11 +814,20 @@ function M._resolve_diff_as_rejected(tab_name)
814814
diff_data.status = "rejected"
815815
diff_data.result_content = result
816816

817-
-- Do not perform UI cleanup here; wait for explicit close_tab tool call.
818817
-- Resume the coroutine with the result (for deferred response system)
819818
if diff_data.resolution_callback then
820819
diff_data.resolution_callback(result)
821820
end
821+
822+
-- For new-file diffs in the current tab, when configured to keep the empty placeholder,
823+
-- we eagerly clean up the diff UI and state. This preserves any reused empty buffer.
824+
local keep_behavior = nil
825+
if config and config.diff_opts then
826+
keep_behavior = config.diff_opts.on_new_file_reject
827+
end
828+
if diff_data.is_new_file and keep_behavior == "keep_empty" and not diff_data.created_new_tab then
829+
M._cleanup_diff_state(tab_name, "diff rejected (keep_empty)")
830+
end
822831
end
823832

824833
---Register autocmds for a specific diff
@@ -930,14 +939,19 @@ function M._create_diff_view_from_window(
930939
original_window = choice.original_win
931940
end
932941

933-
-- For new files, we create an empty buffer for the original side
934-
if is_new_file then
935-
original_buffer_created_by_plugin = true
942+
-- For new files, prefer reusing an existing empty buffer in the chosen window
943+
local original_buffer
944+
if is_new_file and choice.reused_buf and vim.api.nvim_buf_is_valid(choice.reused_buf) then
945+
original_buffer = choice.reused_buf
946+
original_buffer_created_by_plugin = false
947+
else
948+
if is_new_file then
949+
original_buffer_created_by_plugin = true
950+
end
951+
-- Load the original-side buffer into the chosen window
952+
original_buffer = load_original_buffer(original_window, old_file_path, is_new_file, existing_buffer)
936953
end
937954

938-
-- Load the original-side buffer into the chosen window
939-
local original_buffer = load_original_buffer(original_window, old_file_path, is_new_file, existing_buffer)
940-
941955
-- Set up the proposed buffer and finalize the diff layout
942956
local new_win = setup_new_buffer(
943957
original_window,

0 commit comments

Comments
 (0)