Add feature gap analysis ranked by impact and complexity#2
Add feature gap analysis ranked by impact and complexity#2
Conversation
Comprehensive review of all 9 crates, 22 CLI commands, integration tests, and CI workflows identifying 20 missing user-facing features and 17 developer experience improvements, ranked by impact-to- complexity ratio. https://claude.ai/code/session_0187huoj4CkapNVruuuEKn3L
…nforcement Addresses the top 10 items from the feature gap analysis ranked by impact-to-complexity ratio: 1. CI workflow — add .github/workflows/ci.yml running cargo test, clippy, fmt 2. `claw reflog` — expose existing reflog infrastructure via CLI 3. `claw tag` — create, list, and delete immutable release markers 4. `claw clone` — top-level alias for `claw sync clone` 5. `claw completions` — generate bash/zsh/fish/powershell completions 6. Colorized diff — ANSI color for unified diffs when stdout is a terminal 7. Sensitive-path enforcement — policy evaluator now checks `sensitive_paths` globs against revision evidence and requires capsule review proof 8. `--json` on all list commands — intent list, change list, branch list, policy list, and reflog now support --json for scripting 9. `claw stash` — save/pop/list/drop for shelving uncommitted work 10. `claw workstream` — create/show/list/push/pop for managing change stacks All 86 existing tests continue to pass. https://claude.ai/code/session_0187huoj4CkapNVruuuEKn3L
Summary of ChangesHello @Shree-git, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the Highlights
Changelog
Ignored Files
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This is an impressive pull request that not only provides a thorough feature gap analysis but also implements a significant number of the identified features. The new commands like stash, tag, reflog, and completions are excellent additions that greatly improve the developer experience. The implementation of sensitive path policy enforcement and colorized diffs are also valuable enhancements. The code is generally well-structured and follows good Rust practices. I've left a few minor suggestions for improving code consistency and robustness in some of the new commands. Overall, this is a fantastic contribution that significantly moves the project forward.
| let (max_ref, max_id) = stash_refs | ||
| .iter() | ||
| .max_by_key(|(name, _)| { | ||
| name.strip_prefix("stash/") | ||
| .and_then(|s| s.parse::<usize>().ok()) | ||
| .unwrap_or(0) | ||
| }) | ||
| .unwrap(); |
There was a problem hiding this comment.
The current logic for finding the latest stash entry could behave unexpectedly if a stash ref exists that doesn't follow the stash/{index} pattern (e.g., stash/my-work). Such a ref would be parsed as index 0, potentially causing stash pop to act on the wrong entry. To make this more robust, it would be better to filter out any refs that don't parse as an index.
| let (max_ref, max_id) = stash_refs | |
| .iter() | |
| .max_by_key(|(name, _)| { | |
| name.strip_prefix("stash/") | |
| .and_then(|s| s.parse::<usize>().ok()) | |
| .unwrap_or(0) | |
| }) | |
| .unwrap(); | |
| let (max_ref, max_id) = stash_refs | |
| .iter() | |
| .filter_map(|(name, id)| { | |
| name.strip_prefix("stash/") | |
| .and_then(|s| s.parse::<usize>().ok()) | |
| .map(|idx| (idx, name.as_str(), *id)) | |
| }) | |
| .max_by_key(|(idx, _, _)| *idx) | |
| .map(|(_, name, id)| (name, id)) | |
| .unwrap(); |
| for op in ops { | ||
| output.push_str(&format!(" {} @{}: ", op.op_type, op.address)); | ||
| if let Some(old) = &op.old_data { | ||
| output.push_str(&format!("old={:?} ", String::from_utf8_lossy(old))); | ||
| if color { | ||
| output.push_str(&format!( | ||
| "{RED}old={:?}{RESET} ", | ||
| String::from_utf8_lossy(old) | ||
| )); | ||
| } else { | ||
| output.push_str(&format!("old={:?} ", String::from_utf8_lossy(old))); | ||
| } | ||
| } | ||
| if let Some(new) = &op.new_data { | ||
| output.push_str(&format!("new={:?}", String::from_utf8_lossy(new))); | ||
| if color { | ||
| output.push_str(&format!( | ||
| "{GREEN}new={:?}{RESET}", | ||
| String::from_utf8_lossy(new) | ||
| )); | ||
| } else { | ||
| output.push_str(&format!("new={:?}", String::from_utf8_lossy(new))); | ||
| } | ||
| } | ||
| output.push('\n'); | ||
| } |
There was a problem hiding this comment.
There's some code duplication in how the "old" and "new" data lines are formatted for both color and non-color output. You can reduce this duplication by formatting the string first and then conditionally wrapping it with ANSI color codes.
for op in ops {
output.push_str(&format!(" {} @{}: ", op.op_type, op.address));
if let Some(old) = &op.old_data {
let s = format!("old={:?} ", String::from_utf8_lossy(old));
if color {
output.push_str(&format!("{RED}{s}{RESET}"));
} else {
output.push_str(&s);
}
}
if let Some(new) = &op.new_data {
let s = format!("new={:?}", String::from_utf8_lossy(new));
if color {
output.push_str(&format!("{GREEN}{s}{RESET}"));
} else {
output.push_str(&s);
}
}
output.push('\n');
}There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b71d21a5f1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // If no touched paths recorded, we can't enforce — skip | ||
| if touched_paths.is_empty() { | ||
| return Ok(()); |
There was a problem hiding this comment.
Derive sensitive-path matches from actual revision changes
This check only looks for touched: markers inside revision.policy_evidence and then returns early when none are present, which effectively disables sensitive_paths enforcement for normal revisions. In this codebase, revisions created by commands like snapshot currently set policy_evidence to an empty vec, so edits to sensitive files will pass policy evaluation without requiring sensitive-path-review evidence.
Useful? React with 👍 / 👎.
| let stash_refs = store.list_refs("stash/")?; | ||
| let next_index = stash_refs.len(); | ||
| let stash_ref = format!("stash/{}", next_index); |
There was a problem hiding this comment.
Compute new stash ref from highest existing index
Using stash_refs.len() to choose the next stash slot reuses existing names after any non-top drop (for example, stash/0 and stash/2 yields len=2, so the next save writes stash/2). Because set_ref overwrites the target, saving a stash in that state silently replaces an older stash entry and loses recoverable work.
Useful? React with 👍 / 👎.
| // Restore stashed tree to working directory | ||
| worktree::materialize_tree(&store, &stash_tree, &root)?; |
There was a problem hiding this comment.
Block stash pop when the worktree has local changes
This restores the stashed tree directly into the working directory without checking for uncommitted edits, so claw stash pop can overwrite tracked files and discard current work. The repository already protects destructive tree rewrites in checkout unless forced, so this unconditional materialization makes stash pop unexpectedly destructive in common workflows.
Useful? React with 👍 / 👎.
Comprehensive review of all 9 crates, 22 CLI commands, integration
tests, and CI workflows identifying 20 missing user-facing features
and 17 developer experience improvements, ranked by impact-to-
complexity ratio.
https://claude.ai/code/session_0187huoj4CkapNVruuuEKn3L