Skip to content

Commit aae1ab2

Browse files
committed
fix(dashboard): color compartment strip by importance; show real project dir
Compartment timeline strip: replace the per-sequence rainbow hue with the compartment's importance band color (critical=red, high=amber, medium=blue, low/minimal=gray) — matching the row pills — so the strip reads as an importance heat-map instead of a meaningless gradient. Session list project label: OpenCode buckets git sessions that had no remote or commit at creation under the `global` project (worktree "/", empty name), so the list rendered "/" (basename of the worktree) even though the session ran in a real repo. Resolve both the display label and the project identity from the session's own `s.directory` column (falling back to the project worktree only for legacy rows with no directory) — which also matches the identity the plugin keys memories under. SUBCONSCIOUS et al. now show their real directory name.
1 parent 14d483e commit aae1ab2

2 files changed

Lines changed: 47 additions & 14 deletions

File tree

packages/dashboard/src-tauri/src/db.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3156,9 +3156,15 @@ pub fn list_opencode_sessions(filter: &SessionFilter) -> Vec<SessionRow> {
31563156
// joining/grouping the 300k+ row `message` table per call was the dominant
31573157
// cost (a multi-hundred-ms scan that froze the UI on every History entry).
31583158
// `session.time_updated` is the session's own last-activity timestamp.
3159+
// Select the session's OWN directory, not just the joined project's
3160+
// worktree: OpenCode buckets git sessions that had no remote/commit at
3161+
// creation under the `global` project (worktree "/", empty name), so
3162+
// `p.worktree` is "/" and basename("/") renders as "/". `s.directory` always
3163+
// holds the real cwd. We resolve identity from it too — which also matches
3164+
// what the plugin keys memories under (plugin identity = session.directory).
31593165
let Ok(mut stmt) = conn.prepare(
31603166
"SELECT s.id, COALESCE(s.title, ''), COALESCE(p.name, ''), COALESCE(p.worktree, ''),
3161-
s.time_updated AS last_activity
3167+
COALESCE(s.directory, ''), s.time_updated AS last_activity
31623168
FROM session s
31633169
LEFT JOIN project p ON p.id = s.project_id",
31643170
) else {
@@ -3177,19 +3183,27 @@ pub fn list_opencode_sessions(filter: &SessionFilter) -> Vec<SessionRow> {
31773183
let title: String = row.get(1)?;
31783184
let project_name: String = row.get(2)?;
31793185
let worktree: String = row.get(3)?;
3180-
let last_activity_ms: i64 = row.get(4)?;
3181-
let identity = resolve_project_identity(&worktree);
3186+
let directory: String = row.get(4)?;
3187+
let last_activity_ms: i64 = row.get(5)?;
3188+
// Prefer the session's real directory; fall back to the project worktree
3189+
// only when the session row has no directory (legacy rows).
3190+
let effective_dir = if directory.is_empty() { &worktree } else { &directory };
3191+
let identity = resolve_project_identity(effective_dir);
31823192
let is_subagent = subagent_map.get(&session_id).copied().unwrap_or(false);
3193+
// Friendly label: the named project wins; otherwise the directory's
3194+
// basename. Never show a bare "/" (the global-project worktree) when the
3195+
// session actually ran in a real directory.
3196+
let project_display = if !project_name.is_empty() {
3197+
project_name
3198+
} else {
3199+
basename(effective_dir)
3200+
};
31833201
Ok(SessionRow {
31843202
harness: Harness::Opencode,
31853203
session_id,
31863204
title,
31873205
project_identity: identity,
3188-
project_display: if project_name.is_empty() {
3189-
basename(&worktree)
3190-
} else {
3191-
project_name
3192-
},
3206+
project_display,
31933207
last_activity_ms,
31943208
is_subagent,
31953209
})

packages/dashboard/src/components/SessionViewer/SessionViewer.tsx

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,27 @@ function importanceInfo(importance: number): {
7373
};
7474
}
7575

76+
/**
77+
* Importance band → the same CSS color the row pills use, so the timeline strip
78+
* encodes importance (red=critical, amber=high, blue=medium, gray=low) instead
79+
* of a meaningless per-sequence rainbow. `dim` recedes low-importance segments.
80+
*/
81+
function importanceBarColor(importance: number, expanded: boolean): string {
82+
const { pillColor } = importanceInfo(importance);
83+
const base =
84+
pillColor === "red"
85+
? "var(--red)"
86+
: pillColor === "amber"
87+
? "var(--amber)"
88+
: pillColor === "blue"
89+
? "var(--accent)"
90+
: "var(--text-muted)";
91+
// Slightly mute unexpanded segments so the expanded one (and high-importance
92+
// warm colors) read as the focal points; gray bands recede the most.
93+
const mix = expanded ? 100 : pillColor === "gray" ? 55 : 78;
94+
return `color-mix(in srgb, ${base} ${mix}%, var(--bg-card))`;
95+
}
96+
7697
/**
7798
* Split a v2 `episode_type` (possibly comma-joined, e.g. "design,bug,refactor")
7899
* into trimmed non-empty tags for badge rendering.
@@ -995,13 +1016,11 @@ export default function SessionViewer() {
9951016
{(comp) => {
9961017
const range = comp.end_message - comp.start_message;
9971018
const width = () => Math.max(0.5, (range / totalRange()) * 100);
998-
// Saturation tracks v2 importance: high-importance (sticky,
999-
// slow-decay) compartments stay vivid; low-importance ones
1000-
// recede toward gray. Clamped so every segment stays visible.
1019+
// Color encodes v2 IMPORTANCE (decay rate), not sequence:
1020+
// critical→red, high→amber, medium→blue, low/minimal→gray, so
1021+
// the strip reads as a heat-map of which compartments matter.
10011022
const isExpanded = () => expandedCompartment() === comp.id;
10021023
const imp = Number.isFinite(comp.importance) ? comp.importance : 50;
1003-
const sat = Math.max(15, (isExpanded() ? 40 : 20) + (imp / 100) * 45);
1004-
const light = Math.max(28, (isExpanded() ? 55 : 45) - (imp / 100) * 12);
10051024
const info = importanceInfo(imp);
10061025
const titleSuffix = ` · imp ${imp} ${info.label}${comp.legacy ? " · legacy" : ""}`;
10071026
return (
@@ -1010,7 +1029,7 @@ export default function SessionViewer() {
10101029
class="timeline-segment"
10111030
style={{
10121031
width: `${width()}%`,
1013-
background: `hsl(${(comp.sequence * 37) % 360}, ${sat}%, ${light}%)`,
1032+
background: importanceBarColor(imp, isExpanded()),
10141033
outline: isExpanded() ? "2px solid var(--accent)" : "none",
10151034
border: "none",
10161035
padding: 0,

0 commit comments

Comments
 (0)