Skip to content

Commit 9fb0766

Browse files
committed
adds AI assited code summary
1 parent c0f37af commit 9fb0766

13 files changed

Lines changed: 761 additions & 12 deletions

.agents/summary/architecture.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Architecture — askCode.nvim
2+
3+
## Layer Diagram
4+
5+
```mermaid
6+
graph TD
7+
A["plugin/askCode.lua<br/>(Neovim commands + keymaps)"]
8+
B["lua/askCode/init.lua<br/>(orchestrator + state)"]
9+
C["lua/askCode/config.lua"]
10+
D["lua/askCode/ui.lua"]
11+
E["lua/askCode/runner.lua"]
12+
F["lua/askCode/utils.lua"]
13+
G["lua/askCode/agents/init.lua<br/>(registry)"]
14+
H["agents/gemini.lua"]
15+
I["agents/kiro.lua"]
16+
J["agents/opencode.lua"]
17+
18+
A --> B
19+
B --> C
20+
B --> D
21+
B --> E
22+
B --> F
23+
B --> G
24+
G --> H
25+
G --> I
26+
G --> J
27+
```
28+
29+
## Module Responsibilities
30+
31+
| Module | Role |
32+
|---|---|
33+
| `plugin/askCode.lua` | Defines `:AskCode`, `:AskCodeReplace`, `:AskCodeConfig` commands and `<Plug>` keymaps |
34+
| `init.lua` | Holds conversation `state`, builds prompts, wires async callbacks |
35+
| `config.lua` | Stores and merges config; exposes dot-notation get/set |
36+
| `ui.lua` | Creates float/split windows, handles `q`/`Q` keymaps |
37+
| `runner.lua` | Thin `vim.fn.jobstart` wrapper with `stdin = "null"` default |
38+
| `utils.lua` | File I/O, buffer reads, replacement parsing, debug logging |
39+
| `agents/*` | Each agent implements `prepare_command` + `parse_response` |
40+
41+
## Conversation State Machine
42+
43+
```mermaid
44+
stateDiagram-v2
45+
[*] --> Idle
46+
Idle --> Loading : AskCode (new)
47+
Loading --> Displaying : on_exit fires
48+
Displaying --> Loading : AskCode (follow-up)
49+
Displaying --> Idle : q (close window)
50+
Idle --> Replacing : AskCodeReplace
51+
Replacing --> Idle : q (cancel)
52+
Replacing --> Idle : Q (apply)
53+
```
54+
55+
## Key Design Decisions
56+
57+
- **Async via jobstart**: all CLI calls use `vim.fn.jobstart` with `stdout_buffered = true`; `on_exit` delivers the full response at once.
58+
- **`stdin = "null"`**: runner sets stdin to `/dev/null` by default so interactive CLIs don't block waiting for input.
59+
- **History as temp file**: conversation history is written to `vim.fn.tempname()` and re-sent in full on every follow-up, keeping state simple.
60+
- **`vim.schedule()` for UI**: all `update_window` calls are deferred to avoid crossing the async boundary.
61+
- **Config merging with `"keep"`**: `vim.tbl_deep_extend("keep", changes, current)` — user-supplied values always win over defaults.

.agents/summary/codebase_info.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Codebase Info — askCode.nvim
2+
3+
## Project Overview
4+
5+
A Neovim plugin that connects to CLI-based AI assistants (Gemini, Kiro, OpenCode) and lets users ask context-aware questions about selected code from within the editor. Responses appear in floating windows or splits, asynchronously.
6+
7+
## Technology Stack
8+
9+
- **Language**: Lua (Neovim plugin API)
10+
- **Runtime**: Neovim ≥ 0.9.0
11+
- **Test framework**: mini.nvim (MiniTest)
12+
- **CI**: GitHub Actions (LuaRocks publish, release-please)
13+
14+
## Directory Layout
15+
16+
```
17+
lua/askCode/ ← all plugin logic
18+
├── init.lua ← public API + conversation state
19+
├── config.lua ← dot-notation config system
20+
├── runner.lua ← vim.fn.jobstart wrapper
21+
├── ui.lua ← window/buffer management
22+
├── utils.lua ← file I/O, buffer reads, replacement parsing, debug log
23+
└── agents/
24+
├── init.lua ← agent registry
25+
├── gemini.lua ← Gemini CLI integration
26+
├── kiro.lua ← Kiro CLI integration
27+
└── opencode.lua ← OpenCode CLI integration
28+
plugin/askCode.lua ← Neovim commands + <Plug> keymaps (entry point)
29+
tests/ ← MiniTest suite (one file per module)
30+
scripts/minimal_init.lua ← headless Neovim init for tests
31+
.agents/summary/ ← AI agent documentation
32+
CODE-STANDARDS.md ← coding standards and architecture reference
33+
```
34+
35+
## Supported Agents
36+
37+
| Key | CLI binary | Transport |
38+
|---|---|---|
39+
| `gemini` | `gemini` | stdin pipe, JSON output |
40+
| `kiro` | `kiro-cli` | stdin pipe, stderr output |
41+
| `opencode` | `opencode` | temp file arg, `--format json` |

.agents/summary/components.md

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Components — askCode.nvim
2+
3+
## init.lua — Orchestrator
4+
5+
Public API and conversation state. Start here for any feature work.
6+
7+
| Function | Signature | Description |
8+
|---|---|---|
9+
| `setup` | `(cfg?)` | Merges user config with defaults |
10+
| `get_config` | `(key?)` | Returns config value or full config |
11+
| `set_config` | `(key, value)` | Sets config value at runtime |
12+
| `ask` | `(question, mode)` | Starts a new conversation; closes any existing one |
13+
| `follow_up` | `(question)` | Appends to active conversation |
14+
| `ask_replace` | `(question, mode)` | Visual-mode only; shows editable replacement window |
15+
| `ask_or_follow_up` | `(question, mode)` | Dispatches to `ask` or `follow_up` based on state |
16+
17+
**State** (module-local):
18+
- `history_file` — path to temp file holding conversation history
19+
- `win_id`, `buf_id` — current response window
20+
- `display_content` — accumulated display text
21+
22+
## config.lua — Configuration
23+
24+
Dot-notation config system. All keys defined in `M.default`.
25+
26+
| Function | Description |
27+
|---|---|
28+
| `merge_with_default(changes)` | Deep-merges changes using `"keep"` strategy |
29+
| `get(key?)` | Returns value at dot-path, or full config if nil |
30+
| `set(key, value)` | Sets value; auto-converts strings to bool/number |
31+
| `reset_config()` | Restores `M.current_config` to `M.default` |
32+
| `get_all_keys()` | Returns all dot-separated keys (used for tab completion) |
33+
34+
## runner.lua — Job Execution
35+
36+
Thin wrapper around `vim.fn.jobstart`.
37+
38+
| Function | Signature | Description |
39+
|---|---|
40+
| `run_command` | `(cmd, on_stdout, opts?)` | Starts async job; `stdin` defaults to `"null"` |
41+
42+
`opts` fields: `on_stderr`, `on_exit`, `stdout_buffered`, `stdin`.
43+
44+
## ui.lua — Window Management
45+
46+
| Function | Signature | Description |
47+
|---|---|
48+
| `show_window` | `(content, on_close, editable?, on_apply?)` | Creates float/split; wires `q`/`Q` keymaps |
49+
| `update_window` | `(win_id, buf_id, content, cursor_line?, replacement?)` | Replaces buffer content via `vim.schedule` |
50+
51+
Window type is read from `config.current_config.window.type` (`"float"`, `"vertical"`, `"horizontal"`).
52+
53+
## utils.lua — Utilities
54+
55+
| Function | Description |
56+
|---|---|
57+
| `log(msg)` | Emits `vim.notify` at DEBUG level when `config.debug` is true |
58+
| `get_buffer_content(mode)` | Returns visual selection or full buffer as string |
59+
| `read_file(path)` | Reads file to string |
60+
| `write_file(path, content)` | Overwrites file |
61+
| `append_file(path, content)` | Appends to file |
62+
| `delete_file(path)` | Removes file |
63+
| `parse_replacement_response(response)` | Extracts `<REPLACE>…</REPLACE>` block |
64+
| `apply_replacement(content, selection_info)` | Writes lines back to buffer |
65+
66+
## agents/init.lua — Registry
67+
68+
Maps agent name strings to modules. Add new agents here.
69+
70+
```lua
71+
M.agents = {
72+
gemini = require("askCode.agents.gemini"),
73+
kiro = require("askCode.agents.kiro"),
74+
opencode = require("askCode.agents.opencode"),
75+
}
76+
```
77+
78+
## agents/gemini.lua
79+
80+
| Function | Description |
81+
|---|---|
82+
| `prepare_command(prompt)` | `echo <shellescape(prompt)> \| gemini --output-format json` |
83+
| `parse_response(json)` | Decodes JSON, returns `decoded.response` |
84+
85+
## agents/kiro.lua
86+
87+
| Function | Description |
88+
|---|---|
89+
| `prepare_command(prompt)` | `echo <shellescape(prompt)> \| kiro-cli chat --no-interactive 2>&1` |
90+
| `parse_response(str)` | Strips ANSI codes, extracts content after `>` prompt indicator |
91+
92+
Note: kiro writes its response to stderr; `init.lua` wires `on_stderr` only for this agent.
93+
94+
## agents/opencode.lua
95+
96+
| Function | Description |
97+
|---|---|
98+
| `prepare_command(prompt)` | Writes prompt to temp file; runs `opencode run --format json "$(cat <tmpfile>)"` |
99+
| `parse_response(str)` | Parses newline-delimited JSON events; concatenates all `"text"` type parts |
100+
101+
Uses temp file to avoid shell quoting issues with multiline prompts. `--format json` ensures the process exits cleanly.
102+
103+
## plugin/askCode.lua — Entry Point
104+
105+
Defines three user commands and two `<Plug>` keymaps:
106+
107+
| Command | Args | Description |
108+
|---|---|---|
109+
| `:AskCode` | `[question]` | Ask or follow up; prompts if no args |
110+
| `:AskCodeReplace` | `[request]` | Replacement mode (visual only) |
111+
| `:AskCodeConfig` | `<key> [value]` | Get or set config at runtime |
112+
113+
`<Plug>(AskCodeExplain)` and `<Plug>(AskCodeAddDocstring)` are pre-built prompt shortcuts.

.agents/summary/data_models.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Data Models — askCode.nvim
2+
3+
## Config
4+
5+
```lua
6+
---@class Config
7+
---@field agent string -- active agent key ("gemini"|"kiro"|"opencode")
8+
---@field debug boolean -- enables debug logging (currently wired to utils.log)
9+
---@field quit_key string -- keymap to close response window
10+
---@field output_format string -- currently unused
11+
---@field window WindowConfig
12+
```
13+
14+
```lua
15+
---@class WindowConfig
16+
---@field type string -- "float"|"vertical"|"horizontal"
17+
---@field width_ratio number -- fraction of screen width
18+
---@field height_ratio number -- fraction of screen height
19+
---@field max_width number -- column cap
20+
---@field max_height number -- row cap
21+
```
22+
23+
## Conversation State
24+
25+
Module-local table in `init.lua`:
26+
27+
```lua
28+
state = {
29+
history_file = string|nil, -- path to temp file; nil when no active conversation
30+
win_id = number|nil, -- nvim window handle
31+
buf_id = number|nil, -- nvim buffer handle
32+
display_content = string, -- accumulated text shown in window
33+
}
34+
```
35+
36+
## History File Format
37+
38+
Plain text written to `vim.fn.tempname()`. Structure grows with each turn:
39+
40+
```
41+
<initial system prompt + buffer context>
42+
43+
--- USER ---
44+
<first question>
45+
46+
--- AGENT ---
47+
<first response>
48+
49+
--- USER ---
50+
<follow-up question>
51+
52+
--- AGENT ---
53+
<follow-up response>
54+
```
55+
56+
The entire file is re-sent as the prompt on every follow-up call.
57+
58+
## Selection Info
59+
60+
Passed from `ask_replace` to `utils.apply_replacement`:
61+
62+
```lua
63+
selection_info = {
64+
bufnr = number, -- buffer handle
65+
start_line = number, -- 1-based
66+
end_line = number, -- 1-based inclusive
67+
}
68+
```
69+
70+
## Agent Module Shape
71+
72+
```lua
73+
---@class Agent
74+
---@field config table
75+
---@field setup function -- (cfg: table)
76+
---@field prepare_command function -- (prompt: string) → string
77+
---@field parse_response function -- (raw: string) → string|nil
78+
---@field ask function -- (prompt: string) → string|nil
79+
```
80+
81+
## Replacement Parse Result
82+
83+
Returned by `utils.parse_replacement_response`:
84+
85+
```lua
86+
{
87+
replacement_content = string, -- code inside <REPLACE>…</REPLACE>
88+
explanation = string, -- everything outside the tags
89+
}
90+
```

.agents/summary/dependencies.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Dependencies — askCode.nvim
2+
3+
## Runtime Dependencies
4+
5+
### Neovim API (no external Lua deps)
6+
7+
| API | Used in | Purpose |
8+
|---|---|---|
9+
| `vim.fn.jobstart` | runner.lua | Async process execution |
10+
| `vim.fn.tempname` | init.lua, opencode.lua | Temp file paths |
11+
| `vim.fn.shellescape` | gemini.lua, kiro.lua | Shell argument escaping |
12+
| `vim.fn.json_decode` | gemini.lua, opencode.lua | JSON parsing |
13+
| `vim.api.nvim_open_win` | ui.lua | Floating window creation |
14+
| `vim.api.nvim_buf_set_lines` | ui.lua, utils.lua | Buffer content writes |
15+
| `vim.api.nvim_buf_get_lines` | utils.lua | Buffer content reads |
16+
| `vim.fn.getpos` | utils.lua | Visual selection boundaries |
17+
| `vim.schedule` | ui.lua | Defer UI updates across async boundary |
18+
| `vim.tbl_deep_extend` | config.lua, agents | Config/table merging |
19+
| `vim.notify` | throughout | User-facing messages and debug logs |
20+
| `vim.bo.filetype` | init.lua | Include filetype in prompt context |
21+
22+
### External CLI Tools (user must install)
23+
24+
| Agent key | Binary | Install |
25+
|---|---|---|
26+
| `gemini` | `gemini` | [gemini-cli](https://github.com/google-gemini/gemini-cli) |
27+
| `kiro` | `kiro-cli` | [kiro.dev](https://kiro.dev) |
28+
| `opencode` | `opencode` | [opencode.ai](https://opencode.ai) |
29+
30+
All binaries must be available in `$PATH` as seen by Neovim's environment (not just the shell profile).
31+
32+
## Test Dependencies
33+
34+
| Dependency | Source | Purpose |
35+
|---|---|---|
36+
| `mini.nvim` | cloned to `deps/mini.nvim` via `make deps/mini.nvim` | MiniTest framework |
37+
38+
Run `make deps/mini.nvim` before the first test run.
39+
40+
## CI
41+
42+
| Workflow | File | Trigger |
43+
|---|---|---|
44+
| LuaRocks publish | `.github/workflows/luarocks.yml` | Release |
45+
| Changelog + GitHub release | `.github/workflows/release-please.yml` | Push to main |

0 commit comments

Comments
 (0)