Conversation
Add support for Kilo Code CLI (terminal-based AI coding agent, fork of OpenCode). Reads data from ~/.local/share/kilo/storage/ with per-file message layout. - New KiloCliAnalyzer with full Analyzer trait implementation - Separate from existing KiloCode VS Code extension analyzer - Uses kilo_cli_ prefix for unique global hashes - Resolves model names from assistant modelID and nested user model.modelID - 18 new tests (14 unit + 4 integration)
📝 WalkthroughWalkthroughA new Kilo CLI analyzer (KiloCliAnalyzer) and a shared OpenCode-format analyzer (OpenCodeFormatAnalyzer) are added, with module exports, tests, and registration in main. README text updated to clarify Kilo Code offering. Application enum gains a KiloCli variant. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Analyzer Framework
participant Analyzer as KiloCliAnalyzer
participant OpenCode as OpenCodeFormatAnalyzer
participant FS as File System
participant Parser as JSON Parser
participant Stats as Stats Aggregator
Client->>Analyzer: get_data_glob_patterns()
Analyzer->>OpenCode: display_name / get_data_glob_patterns()
OpenCode-->>Analyzer: glob patterns
Analyzer-->>Client: patterns
Client->>Analyzer: discover_data_sources()
Analyzer->>OpenCode: discover_data_sources()
OpenCode->>FS: glob for files
FS-->>OpenCode: file paths
OpenCode-->>Analyzer: DataSource list
Analyzer-->>Client: DataSource vector
Client->>Analyzer: parse_sources_parallel(sources)
Analyzer->>OpenCode: parse_sources_parallel_with_paths(sources)
OpenCode->>FS: read files
FS-->>Parser: file contents
Parser->>Parser: deserialize to Message/Session/Project
Parser->>OpenCode: ConversationMessage[]
OpenCode->>Stats: aggregate tokens/costs
Stats-->>OpenCode: AgenticCodingToolStats
OpenCode-->>Analyzer: messages / stats
Analyzer-->>Client: messages / stats
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@src/analyzers/kilo_cli.rs`:
- Around line 30-36: The data_dir and storage_root functions currently hardcode
"~/.local/share/kilo/storage" which is incorrect; update both to compute the
Kilo CLI data directory using platform-appropriate APIs (e.g., use
dirs::config_dir() or dirs::home_dir() to build a path to ".kilocode") so
data_dir returns the message storage path under "~/.kilocode/" and storage_root
returns the root "~/.kilocode/" directory; modify the implementations of
data_dir() and storage_root() to derive the base via dirs::config_dir() (falling
back to dirs::home_dir()) and then join ".kilocode" (and "message" for data_dir)
to satisfy cross-platform requirements.
- Around line 512-529: parse_source currently reloads projects and sessions
every call by calling Self::storage_root(), load_projects and load_sessions;
change this to reuse a preloaded context instead—either add cached fields to the
analyzer struct (e.g., projects: HashMap<...>, sessions: HashMap<...>) and
initialize them once from storage_root(), or add a new helper
parse_source_with_context(&self, source: &DataSource, projects: &ProjectsType,
sessions: &SessionsType, part_root: &Path) and update the single-file watcher
path to call that helper (matching how parse_sources_parallel_with_paths already
reuses context). Ensure you stop calling load_projects/load_sessions inside
parse_source and use the provided/cached projects and sessions and the existing
storage_root/part_root values.
🧹 Nitpick comments (3)
src/analyzers/tests/kilo_cli.rs (1)
26-31:#[tokio::test]is unnecessary here —get_stats_with_sourcesis synchronous.The function being tested isn't async, so a plain
#[test]suffices. The async runtime adds overhead for no benefit.Suggested fix
-#[tokio::test] -async fn test_kilo_cli_get_stats_empty_sources() { +#[test] +fn test_kilo_cli_get_stats_empty_sources() { let analyzer = KiloCliAnalyzer::new(); let result = analyzer.get_stats_with_sources(vec![]); assert!(result.is_ok()); assert!(result.unwrap().messages.is_empty()); }src/analyzers/kilo_cli.rs (2)
340-356: Onlyreadandglobtool types update specific file stats.Other common tool types (e.g.,
write,edit,bash/shell) are counted as generictool_callsbut don't populatefiles_edited,files_added,terminal_commands, etc. This is fine for an initial implementation but worth tracking as a follow-up to get richer file operation metrics.Would you like me to open an issue to track expanding tool-type coverage (write, edit, bash, etc.) for richer file operation stats?
386-427: Thetool_calls = 1assignment is intentional and already documented.This pattern appears identically in both
opencode.rsandkilo_cli.rs, with the same condition and comment: "Ensure tool_calls is at least 1 when we had a model call." It represents a deliberate design decision to count bare model inferences (messages with tokens but no actual tool invocations) as a single "tool call" for metric purposes. The current comment adequately explains the intent, so no changes are required.
|
@coderabbitai Review. |
|
✅ Actions performedReview triggered.
|
|
Should this code not be refactored to just lift the common code out into a dedicated struct? Or support both from same file. Since it's a fork of same client. |
…odule Kilo CLI is a fork of OpenCode and both use the identical on-disk format (one JSON file per message, per-session directories). The two analyzer implementations were ~93% duplicated (~1,464 lines of near-identical code). Extract all shared types, helpers, and the Analyzer trait implementation into a new opencode_common module parameterised by an OpenCodeFormatConfig (display name, Application variant, hash prefix, storage sub-directory). Both OpenCodeAnalyzer and KiloCliAnalyzer are now thin newtype wrappers that delegate to OpenCodeFormatAnalyzer with their respective configs. Before: opencode.rs (681 lines) + kilo_cli.rs (867 lines) = 1548 lines After: opencode_common.rs (949) + opencode.rs (66) + kilo_cli.rs (66) = 1081 lines All 215 tests pass, clippy clean, fmt clean, docs build. Addresses review feedback from Sewer56 on PR #118.
|
(Extra Note: |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/analyzers/opencode_common.rs (1)
486-491: Roles other than"user"silently map toMessageRole::Assistant.If the on-disk format ever introduces a third role (e.g.
"system"or"tool"), it would be silently counted as an assistant message. This is fine for the current schema but worth a brief comment or a log/trace for unexpected values.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/analyzers/opencode_common.rs` around lines 486 - 491, The current conversion of msg.role to MessageRole (the role: if msg.role == "user" { MessageRole::User } else { MessageRole::Assistant }) silently treats any non-"user" value as Assistant; change this to an explicit match on msg.role (e.g. "user" => MessageRole::User, "assistant" => MessageRole::Assistant, _ => { trace or warn the unexpected msg.role value and then map to a sensible default }) so unexpected roles are logged/traced rather than silently accepted; update the code around the role field creation where msg.role and MessageRole are used and add a brief comment noting why unknown roles are logged and the chosen fallback.src/analyzers/kilo_cli.rs (1)
12-66: Consider a macro to eliminate the duplicated delegation boilerplate.Both
KiloCliAnalyzerandOpenCodeAnalyzerhave identical 40-lineimpl Analyzerblocks that purely delegate toself.0. A small declarative macro could generate these wrappers from just the struct name and config, reducing the chance of the two drifting apart if theAnalyzertrait gains new methods.💡 Example macro sketch
macro_rules! opencode_format_analyzer { ($name:ident, $config:expr) => { pub struct $name(OpenCodeFormatAnalyzer); impl $name { pub fn new() -> Self { Self(OpenCodeFormatAnalyzer::new($config)) } } #[async_trait] impl Analyzer for $name { fn display_name(&self) -> &'static str { self.0.display_name() } fn get_data_glob_patterns(&self) -> Vec<String> { self.0.get_data_glob_patterns() } // ... remaining methods ... fn contribution_strategy(&self) -> ContributionStrategy { self.0.contribution_strategy() } } }; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/analyzers/kilo_cli.rs` around lines 12 - 66, The impl block for KiloCliAnalyzer duplicates a long delegation boilerplate to OpenCodeFormatAnalyzer; create a declarative macro (e.g., opencode_format_analyzer!) that takes the wrapper name and OpenCodeFormatConfig and generates the pub struct $name(OpenCodeFormatAnalyzer), the new() ctor, and the entire #[async_trait] impl Analyzer delegating each method to self.0 (covering display_name, get_data_glob_patterns, discover_data_sources, is_available, parse_source, parse_sources_parallel_with_paths, parse_sources_parallel, get_stats_with_sources, get_watch_directories, is_valid_data_path, and contribution_strategy), then replace the current KiloCliAnalyzer (and the similar OpenCodeAnalyzer) definitions with invocations of that macro to eliminate the duplicated code while preserving async_trait and signatures.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/analyzers/kilo_cli.rs`:
- Around line 12-66: The impl block for KiloCliAnalyzer duplicates a long
delegation boilerplate to OpenCodeFormatAnalyzer; create a declarative macro
(e.g., opencode_format_analyzer!) that takes the wrapper name and
OpenCodeFormatConfig and generates the pub struct $name(OpenCodeFormatAnalyzer),
the new() ctor, and the entire #[async_trait] impl Analyzer delegating each
method to self.0 (covering display_name, get_data_glob_patterns,
discover_data_sources, is_available, parse_source,
parse_sources_parallel_with_paths, parse_sources_parallel,
get_stats_with_sources, get_watch_directories, is_valid_data_path, and
contribution_strategy), then replace the current KiloCliAnalyzer (and the
similar OpenCodeAnalyzer) definitions with invocations of that macro to
eliminate the duplicated code while preserving async_trait and signatures.
In `@src/analyzers/opencode_common.rs`:
- Around line 486-491: The current conversion of msg.role to MessageRole (the
role: if msg.role == "user" { MessageRole::User } else { MessageRole::Assistant
}) silently treats any non-"user" value as Assistant; change this to an explicit
match on msg.role (e.g. "user" => MessageRole::User, "assistant" =>
MessageRole::Assistant, _ => { trace or warn the unexpected msg.role value and
then map to a sensible default }) so unexpected roles are logged/traced rather
than silently accepted; update the code around the role field creation where
msg.role and MessageRole are used and add a brief comment noting why unknown
roles are logged and the chosen fallback.
Add support for Kilo Code CLI (terminal-based AI coding agent, fork of OpenCode). Reads data from ~/.local/share/kilo/storage/ with per-file message layout.
Closes #117.
Summary by CodeRabbit
New Features
Documentation
Tests