Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
63c351f
docs: add review workspace product plan
matej21 Aug 14, 2026
9ba2ef9
feat(review): add review workspace contracts
matej21 Aug 15, 2026
6bca407
feat(review): add syntax and review model crates
matej21 Aug 15, 2026
6943704
feat(git): add exact review comparisons
matej21 Aug 15, 2026
7cf95cf
feat(syntax): add bounded analysis controls
matej21 Aug 15, 2026
1045e31
feat(syntax): extract Rust review facts
matej21 Aug 15, 2026
3f353a4
feat(syntax): extract TypeScript review facts
matej21 Aug 15, 2026
69a4001
feat(review): classify changed files by role
matej21 Aug 15, 2026
7187085
fix(review): support one-sided symbol changes
matej21 Aug 15, 2026
ae11992
feat(review): compare changed code structure
matej21 Aug 15, 2026
1e14b40
feat(review): compare direct call changes
matej21 Aug 15, 2026
039aa1e
feat(core): bound command bus output
matej21 Aug 15, 2026
2ea68c5
feat(git): bound exact review commands
matej21 Aug 15, 2026
78e23ca
feat(review): add daemon review actions
matej21 Aug 15, 2026
efb5c3a
feat(review): represent pending analysis files
matej21 Aug 15, 2026
cbc59f8
feat(review): include call changes in structure
matej21 Aug 15, 2026
7a91fd2
feat(review): add typed review provider
matej21 Aug 15, 2026
1fbefaf
feat(review): summarize omitted structure files
matej21 Aug 15, 2026
9b2ba0c
feat(git): type review source limits
matej21 Aug 15, 2026
94cf414
feat(syntax): bound retained review facts
matej21 Aug 15, 2026
5f867af
feat(syntax): bound TypeScript review facts
matej21 Aug 15, 2026
aeaaa71
feat(syntax): bound Rust review facts
matej21 Aug 15, 2026
71aac94
feat(review): control structural comparison work
matej21 Aug 15, 2026
9c24cc8
feat(review): add exact source responses
matej21 Aug 15, 2026
75027cd
feat(review): execute bounded daemon analysis
matej21 Aug 15, 2026
a2f8cd8
feat(review): route exact source actions
matej21 Aug 15, 2026
0020c0a
feat(review): load exact sources remotely
matej21 Aug 15, 2026
86e3bb3
feat(review): serve exact source contents
matej21 Aug 15, 2026
3703115
feat(review): coordinate immutable review data
matej21 Aug 15, 2026
fd81340
feat(review): add structured review lenses
matej21 Aug 15, 2026
43c3fed
feat(review): navigate structured evidence
matej21 Aug 15, 2026
5a6889f
fix(review): keep integration types compact
matej21 Aug 15, 2026
3563394
fix(review): pair binary additions and deletions
matej21 Aug 17, 2026
5b6fd9d
docs(review): add review workspace UI specification
matej21 Aug 17, 2026
703609c
refactor(review): replace lens tabs with the review_ui shell seam
matej21 Aug 17, 2026
d35cf95
feat(review): render the analysis status pill and details popover
matej21 Aug 17, 2026
7f35440
feat(review): add the review keyboard model, footer hints and help ov…
matej21 Aug 17, 2026
818e30b
fix(review): occlude the status popover backdrop and align its wording
matej21 Aug 17, 2026
a3debc5
feat(review): rank the review model from git facts and structure
matej21 Aug 17, 2026
642814f
fix(review): harden review key dispatch modifiers and focus handling
matej21 Aug 17, 2026
7e3a14c
feat(review): add the file header, symbol bar, details and outline po…
matej21 Aug 17, 2026
b8e4154
feat(review): render the Overview with volume, facts and Start here
matej21 Aug 17, 2026
f73456b
fix(review): gate body reasons on body changes and index structure lo…
matej21 Aug 17, 2026
3e47de1
feat(review): add the Files tree and Attention list navigator
matej21 Aug 17, 2026
180775d
feat(review): expand the commit ledger under the Commits fact
matej21 Aug 17, 2026
f3388d0
fix(review): anchor the status pill right, stop handled keys, reveal …
matej21 Aug 17, 2026
39b337d
style(review): rustfmt the review UI
matej21 Aug 17, 2026
cefe805
fix(review): keep the Overview free of zero cells and widened filters
matej21 Aug 17, 2026
55a5771
fix(review): make the symbol bar follow the diff viewport
matej21 Aug 17, 2026
f25a2c4
fix(review): make navigator group headers navigable and ids stable
matej21 Aug 17, 2026
a768d32
fix(review): drop duplicated path header, role badge and coverage caveat
matej21 Aug 17, 2026
14f16d1
fix(review): cancel identical repeated calls in the call diff
matej21 Aug 17, 2026
c05a4de
fix(review): reveal the navigator cursor once and tidy its rows
matej21 Aug 17, 2026
3e626f7
fix(review): step symbols without reloading the file
matej21 Aug 17, 2026
fb22609
feat(review): make symbol details always say something, compactly
matej21 Aug 17, 2026
cb859a4
fix(review): let the outline popover scroll
matej21 Aug 17, 2026
0471a45
style(review): keep the overview compact on wide windows
matej21 Aug 17, 2026
a90ea42
style(review): give the overview two columns
matej21 Aug 17, 2026
7e7b071
refactor(review): share the call wording
matej21 Aug 17, 2026
7b3282d
fix(review): count repeated calls instead of listing them
matej21 Aug 17, 2026
a4c1010
feat(review): inline the change outline in the file tree
matej21 Aug 17, 2026
3d8ef86
style(review): make the tree's depth visible
matej21 Aug 17, 2026
43020e9
fix(review): nest members under the symbol they changed with
matej21 Aug 17, 2026
69b6116
feat(review): count tests written inside the file they test
matej21 Aug 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = [".", "crates/okena-mobile-ffi", "crates/okena-core", "crates/okena-transport", "crates/okena-git", "crates/okena-views-git", "crates/okena-views-services", "crates/okena-views-sidebar", "crates/okena-views-terminal", "crates/okena-terminal", "crates/okena-layout", "crates/okena-state", "crates/okena-hooks", "crates/okena-workspace", "crates/okena-ui", "crates/okena-usage", "crates/okena-files", "crates/okena-markdown", "crates/okena-extensions", "crates/okena-ext-claude", "crates/okena-ext-codex", "crates/okena-ext-github", "crates/okena-ext-updater", "crates/okena-services", "crates/okena-remote-client", "crates/okena-remote-server", "crates/okena-views-remote", "crates/okena-theme", "crates/okena-cli", "crates/okena-app-core", "crates/okena-app", "crates/okena-daemon-core", "crates/okena-daemon", "crates/okena-tui"]
members = [".", "crates/okena-mobile-ffi", "crates/okena-core", "crates/okena-transport", "crates/okena-git", "crates/okena-syntax", "crates/okena-review", "crates/okena-views-git", "crates/okena-views-services", "crates/okena-views-sidebar", "crates/okena-views-terminal", "crates/okena-terminal", "crates/okena-layout", "crates/okena-state", "crates/okena-hooks", "crates/okena-workspace", "crates/okena-ui", "crates/okena-usage", "crates/okena-files", "crates/okena-markdown", "crates/okena-extensions", "crates/okena-ext-claude", "crates/okena-ext-codex", "crates/okena-ext-github", "crates/okena-ext-updater", "crates/okena-services", "crates/okena-remote-client", "crates/okena-remote-server", "crates/okena-views-remote", "crates/okena-theme", "crates/okena-cli", "crates/okena-app-core", "crates/okena-app", "crates/okena-daemon-core", "crates/okena-daemon", "crates/okena-tui"]
resolver = "2"

[workspace.package]
Expand Down
6 changes: 6 additions & 0 deletions crates/okena-app-core/src/workspace/actions/execute/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,12 @@ pub fn execute_action(
mode,
ignore_whitespace,
} => git::diff(ws, project_id, mode, ignore_whitespace),
ActionRequest::ReviewInventory { .. }
| ActionRequest::ReviewDiff { .. }
| ActionRequest::ReviewSource { .. }
| ActionRequest::ReviewStructure { .. } => ActionResult::Err(
"internal error: review actions require the daemon executor".to_string(),
),
ActionRequest::GitBranches { project_id } => git::branches(ws, project_id),
ActionRequest::GitListPullRequests { project_id, limit } => {
git::list_pull_requests(ws, project_id, limit)
Expand Down
98 changes: 98 additions & 0 deletions crates/okena-app/src/action_dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,31 @@ fn strip_remote_ids(action: ActionRequest, connection_id: &str) -> ActionRequest
mode,
ignore_whitespace,
},
ActionRequest::ReviewInventory { project_id, mode } => ActionRequest::ReviewInventory {
project_id: s(&project_id),
mode,
},
ActionRequest::ReviewDiff {
project_id,
request,
} => ActionRequest::ReviewDiff {
project_id: s(&project_id),
request,
},
ActionRequest::ReviewSource {
project_id,
request,
} => ActionRequest::ReviewSource {
project_id: s(&project_id),
request,
},
ActionRequest::ReviewStructure {
project_id,
request,
} => ActionRequest::ReviewStructure {
project_id: s(&project_id),
request,
},
ActionRequest::GitBranches { project_id } => ActionRequest::GitBranches {
project_id: s(&project_id),
},
Expand Down Expand Up @@ -1255,6 +1280,42 @@ mod tests {
use super::*;
use crate::workspace::state::SplitDirection;

fn review_diff_request() -> okena_core::review::ReviewDiffRequest {
let requested_base = "1".repeat(40);
let merge_base = "2".repeat(40);
let head = "3".repeat(40);
let identity = format!("branch:merge-base:{requested_base}:{head}:{merge_base}");
serde_json::from_value(serde_json::json!({
"comparison": {
"requested": {
"branch_compare": {
"base": "origin/main",
"head": "feature/review"
}
},
"requested_base_oid": requested_base,
"requested_head_oid": head,
"strategy": "merge_base_to_head",
"base": { "kind": "commit", "oid": merge_base },
"head": { "kind": "commit", "oid": head },
"merge_base_oid": merge_base,
"identity": identity
},
"ignore_whitespace": false
}))
.unwrap()
}

fn review_source_request() -> okena_core::review::ReviewSourceRequest {
let comparison = review_diff_request().comparison;
okena_core::review::ReviewSourceRequest::new(
comparison.into_resolved(),
Some("src/old.rs".to_string()),
Some("src/new.rs".to_string()),
)
.unwrap()
}

#[test]
fn rows_map_visual_split_axis_back_to_canonical_axis() {
let action = canonicalize_layout_action(
Expand Down Expand Up @@ -1305,4 +1366,41 @@ mod tests {
"worktree (feature/fallback)"
);
}

#[test]
fn review_actions_strip_only_the_remote_project_prefix() {
let project_id = "remote:connection-1:project-1".to_string();
let request = review_diff_request();
let source_request = review_source_request();
let actions = [
ActionRequest::ReviewInventory {
project_id: project_id.clone(),
mode: okena_core::types::DiffMode::BranchCompare {
base: "origin/main".to_string(),
head: "feature/review".to_string(),
},
},
ActionRequest::ReviewDiff {
project_id: project_id.clone(),
request: request.clone(),
},
ActionRequest::ReviewSource {
project_id: project_id.clone(),
request: Box::new(source_request),
},
ActionRequest::ReviewStructure {
project_id,
request,
},
];

for action in actions {
let original = serde_json::to_value(&action).unwrap();
let value = serde_json::to_value(strip_remote_ids(action, "connection-1")).unwrap();
assert_eq!(value["project_id"], "project-1");
if original.get("request").is_some() {
assert_eq!(value["request"], original["request"]);
}
}
}
}
2 changes: 1 addition & 1 deletion crates/okena-app/src/views/overlay_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@ impl OverlayManager {
this.close_modal(cx);
}
SessionManagerEvent::Action(action) => {
cx.emit(OverlayManagerEvent::SessionAction(action.clone()));
cx.emit(OverlayManagerEvent::SessionAction(action.as_ref().clone()));
// Load/import close the manager (state swaps); save/export
// are quick fire-and-forget — close in all cases.
this.close_modal(cx);
Expand Down
22 changes: 12 additions & 10 deletions crates/okena-app/src/views/overlays/session_manager/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ impl SessionManager {
// The daemon owns the authoritative workspace (local ids) + session
// files; saving from the client mirror would persist prefixed-id garbage.
// Dispatch SaveSession and let the daemon write its own data.
cx.emit(SessionManagerEvent::Action(ActionRequest::SaveSession {
name,
}));
cx.emit(SessionManagerEvent::Action(Box::new(
ActionRequest::SaveSession { name },
)));
self.new_session_input.update(cx, |input, cx| {
input.set_value("", cx);
});
Expand All @@ -71,9 +71,11 @@ impl SessionManager {
pub(super) fn load_session(&mut self, name: &str, cx: &mut Context<Self>) {
// The daemon loads its own session file + swaps state; the new workspace
// mirrors back via snapshot.
cx.emit(SessionManagerEvent::Action(ActionRequest::LoadSession {
name: name.to_string(),
}));
cx.emit(SessionManagerEvent::Action(Box::new(
ActionRequest::LoadSession {
name: name.to_string(),
},
)));
self.error_message = None;
}

Expand Down Expand Up @@ -194,9 +196,9 @@ impl SessionManager {
}

// Export the DAEMON's authoritative workspace (not the client mirror).
cx.emit(SessionManagerEvent::Action(
cx.emit(SessionManagerEvent::Action(Box::new(
ActionRequest::ExportWorkspace { path },
));
)));
self.error_message = None;
cx.notify();
}
Expand All @@ -210,9 +212,9 @@ impl SessionManager {
}

// The daemon imports the file + swaps state; the result mirrors back.
cx.emit(SessionManagerEvent::Action(
cx.emit(SessionManagerEvent::Action(Box::new(
ActionRequest::ImportWorkspace { path },
));
)));
self.error_message = None;
cx.notify();
}
Expand Down
2 changes: 1 addition & 1 deletion crates/okena-app/src/views/overlays/session_manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ pub enum SessionManagerEvent {
/// A ready-to-dispatch session/workspace action for the host to route to the
/// local daemon (load/save/import/export). The daemon owns session files and
/// the authoritative workspace, so these never touch the client's mirror.
Action(okena_core::api::ActionRequest),
Action(Box<okena_core::api::ActionRequest>),
}

impl EventEmitter<SessionManagerEvent> for SessionManager {}
Expand Down
Loading
Loading