feat: operator digest bottom-left + closable, bump v1.3.0#238
feat: operator digest bottom-left + closable, bump v1.3.0#238charlesrhoward merged 3 commits intomainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Digest panel overlaps AgentCard at same position
- I made the digest panel shift right while an agent is selected so it no longer overlaps the bottom-left AgentCard.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a4fa37212f
ℹ️ 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".
| {digestOpen ? ( | ||
| <div | ||
| style={{ | ||
| maxHeight: 'calc(100vh - 56px)', |
There was a problem hiding this comment.
Use container-relative max height for digest panel
maxHeight: 'calc(100vh - 56px)' makes the digest panel height follow the browser viewport instead of the HUD container. HUD is mounted inside the resizable office CollapsibleSection (ScenePanel), so when that panel is shorter than the viewport this can disable the intended internal scrolling and push the top of the digest out of the visible panel area. Use a container-relative limit (for example 100%-based sizing) so the digest remains scrollable within the office panel.
Useful? React with 👍 / 👎.
Repositions the Daily operator digest panel from top-right to bottom-left of the office view. Adds close/reopen toggle — panel shows a compact ☰ button when dismissed. Bumps version to 1.3.0. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Digest panel shifts right (left: 332px) when AgentCard is visible to prevent bottom-left overlap. Switches maxHeight from 100vh to 100% so scrolling respects the HUD container, not the viewport. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
d6f56ea to
79fc5bd
Compare
Adds pnpm.overrides for picomatch >=4.0.4 to patch transitive high-severity ReDoS via vscode-langservers-extracted and @electron/rebuild > node-gyp > tinyglobby. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Percentage maxHeight ineffective on non-positioned inner div
- Moved the max-height and overflow styles to the absolutely positioned bottom digest container so viewport-relative height constraint and scrolling work again.
Preview (4afc2b8399)
diff --git a/package.json b/package.json
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "agent-observer",
- "version": "1.2.10",
+ "version": "1.3.0",
"description": "Agent Office — 3D observability for AI agents",
"main": "./out/main/index.js",
"scripts": {
@@ -47,7 +47,8 @@
"tar": ">=7.5.11",
"minimatch": ">=10.2.3",
"rollup": ">=4.59.0",
- "flatted": ">=3.4.2"
+ "flatted": ">=3.4.2",
+ "picomatch": ">=4.0.4"
}
},
"dependencies": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -12,6 +12,7 @@
minimatch: '>=10.2.3'
rollup: '>=4.59.0'
flatted: '>=3.4.2'
+ picomatch: '>=4.0.4'
importers:
@@ -3371,7 +3372,7 @@
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
engines: {node: '>=12.0.0'}
peerDependencies:
- picomatch: ^3 || ^4
+ picomatch: '>=4.0.4'
peerDependenciesMeta:
picomatch:
optional: true
@@ -4897,12 +4898,8 @@
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
- picomatch@2.3.1:
- resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
- engines: {node: '>=8.6'}
-
- picomatch@4.0.3:
- resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
+ picomatch@4.0.4:
+ resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
engines: {node: '>=12'}
pkce-challenge@5.0.1:
@@ -9545,9 +9542,9 @@
dependencies:
pend: 1.2.0
- fdir@6.5.0(picomatch@4.0.3):
+ fdir@6.5.0(picomatch@4.0.4):
optionalDependencies:
- picomatch: 4.0.3
+ picomatch: 4.0.4
fetch-blob@3.2.0:
dependencies:
@@ -9729,7 +9726,7 @@
mdast-util-mdx: 3.0.0
mdast-util-to-markdown: 2.1.2
picocolors: 1.1.1
- picomatch: 4.0.3
+ picomatch: 4.0.4
tinyexec: 1.0.4
tinyglobby: 0.2.15
unified: 11.0.5
@@ -11012,7 +11009,7 @@
micromatch@4.0.8:
dependencies:
braces: 3.0.3
- picomatch: 2.3.1
+ picomatch: 4.0.4
mime-db@1.52.0: {}
@@ -11397,10 +11394,8 @@
picocolors@1.1.1: {}
- picomatch@2.3.1: {}
+ picomatch@4.0.4: {}
- picomatch@4.0.3: {}
-
pkce-challenge@5.0.1: {}
platform@1.3.6: {}
@@ -12357,8 +12352,8 @@
tinyglobby@0.2.15:
dependencies:
- fdir: 6.5.0(picomatch@4.0.3)
- picomatch: 4.0.3
+ fdir: 6.5.0(picomatch@4.0.4)
+ picomatch: 4.0.4
tinygradient@1.1.5:
dependencies:
@@ -12653,8 +12648,8 @@
vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.2):
dependencies:
esbuild: 0.25.12
- fdir: 6.5.0(picomatch@4.0.3)
- picomatch: 4.0.3
+ fdir: 6.5.0(picomatch@4.0.4)
+ picomatch: 4.0.4
postcss: 8.5.8
rollup: 4.59.1
tinyglobby: 0.2.15
@@ -12738,7 +12733,7 @@
dependencies:
'@vscode/l10n': 0.0.10
node-html-parser: 6.1.13
- picomatch: 2.3.1
+ picomatch: 4.0.4
vscode-languageserver-protocol: 3.17.5
vscode-languageserver-textdocument: 1.0.12
vscode-uri: 3.1.0
diff --git a/src/renderer/hud/HUD.tsx b/src/renderer/hud/HUD.tsx
--- a/src/renderer/hud/HUD.tsx
+++ b/src/renderer/hud/HUD.tsx
@@ -1,10 +1,15 @@
+import { useState } from 'react'
import { StatsBar } from './StatsBar'
import { AgentCard } from './AgentCard'
import { ToastStack } from './Toast'
import { CelebrationDeck } from './CelebrationDeck'
import { SoloOperatorPanel } from './SoloOperatorPanel'
+import { useAgentStore } from '../store/agents'
export function HUD() {
+ const [digestOpen, setDigestOpen] = useState(true)
+ const hasSelectedAgent = useAgentStore((s) => s.selectedAgentId !== null)
+
return (
<div className="absolute inset-0 pointer-events-none z-10">
{/* Top bar */}
@@ -12,7 +17,7 @@
<StatsBar />
</div>
- {/* Agent detail card */}
+ {/* Agent detail card — bottom-left when an agent is selected */}
<AgentCard />
{/* Right panel stack — scrollable at small heights */}
@@ -29,10 +34,46 @@
scrollbarColor: 'rgba(89,86,83,0.3) transparent',
}}
>
- <SoloOperatorPanel />
<CelebrationDeck />
</div>
+ {/* Bottom-left operator digest — offset right when AgentCard is visible */}
+ <div
+ className="absolute bottom-4 pointer-events-auto"
+ style={{
+ left: hasSelectedAgent ? 332 : 16,
+ maxHeight: 'calc(100% - 56px)',
+ overflowY: 'auto',
+ scrollbarWidth: 'thin',
+ scrollbarColor: 'rgba(89,86,83,0.3) transparent',
+ }}
+ >
+ {digestOpen ? (
+ <SoloOperatorPanel onClose={() => setDigestOpen(false)} />
+ ) : (
+ <button
+ type="button"
+ onClick={() => setDigestOpen(true)}
+ style={{
+ width: 36,
+ height: 36,
+ borderRadius: 10,
+ border: '1px solid rgba(89,86,83,0.25)',
+ background: 'linear-gradient(180deg, rgba(17,18,17,0.9), rgba(10,10,10,0.85))',
+ color: '#9A9692',
+ fontSize: 16,
+ cursor: 'pointer',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ }}
+ title="Open operator digest"
+ >
+ ☰
+ </button>
+ )}
+ </div>
+
{/* Toast notifications */}
<ToastStack />
</div>
diff --git a/src/renderer/hud/SoloOperatorPanel.tsx b/src/renderer/hud/SoloOperatorPanel.tsx
--- a/src/renderer/hud/SoloOperatorPanel.tsx
+++ b/src/renderer/hud/SoloOperatorPanel.tsx
@@ -3,7 +3,7 @@
import { useWorkspaceStore } from '../store/workspace'
import { deriveDailyDigest } from '../lib/soloDevCockpit'
-export function SoloOperatorPanel() {
+export function SoloOperatorPanel({ onClose }: { onClose?: () => void }) {
const runs = useRunHistoryStore((s) => s.runs)
const officeFocusMode = useRunHistoryStore((s) => s.officeFocusMode)
const setOfficeFocusMode = useRunHistoryStore((s) => s.setOfficeFocusMode)
@@ -32,13 +32,39 @@
background: 'linear-gradient(180deg, rgba(17,18,17,0.9), rgba(10,10,10,0.85))',
}}
>
- <div>
- <div style={{ color: '#74747C', fontSize: 10, fontWeight: 700, letterSpacing: 1 }}>
- OFFICE CONTROL
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
+ <div>
+ <div style={{ color: '#74747C', fontSize: 10, fontWeight: 700, letterSpacing: 1 }}>
+ OFFICE CONTROL
+ </div>
+ <div style={{ marginTop: 6, color: '#ECE7DE', fontSize: 16, fontWeight: 700 }}>
+ Daily operator digest
+ </div>
</div>
- <div style={{ marginTop: 6, color: '#ECE7DE', fontSize: 16, fontWeight: 700 }}>
- Daily operator digest
- </div>
+ {onClose && (
+ <button
+ type="button"
+ onClick={onClose}
+ style={{
+ width: 24,
+ height: 24,
+ borderRadius: 6,
+ border: '1px solid rgba(89,86,83,0.25)',
+ background: 'transparent',
+ color: '#74747C',
+ fontSize: 14,
+ lineHeight: 1,
+ cursor: 'pointer',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ flexShrink: 0,
+ }}
+ title="Close digest"
+ >
+ ✕
+ </button>
+ )}
</div>
<div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>| }} | ||
| > | ||
| <SoloOperatorPanel onClose={() => setDigestOpen(false)} /> | ||
| </div> |
There was a problem hiding this comment.
Percentage maxHeight ineffective on non-positioned inner div
Medium Severity
The inner wrapper div around SoloOperatorPanel has maxHeight: 'calc(100% - 56px)' with overflowY: 'auto', but its parent (the absolute bottom-4 div) has no explicit height — it's sized by content. Per CSS spec, a percentage max-height on a non-positioned child whose parent lacks an explicit height resolves to none, so scrolling never activates. Previously, the panel lived inside an absolutely positioned div that itself carried maxHeight, which worked because percentage values on absolutely positioned elements resolve against the containing block. This is a layout regression that can cause the panel to overflow the viewport on short screens.


Summary
Test plan
🤖 Generated with Claude Code
Note
Low Risk
Low risk UI/layout change plus dependency override/lockfile update; main risk is minor HUD positioning/regression on different screen sizes.
Overview
Moves the
SoloOperatorPanel(Daily operator digest) out of the top-right stack into a bottom-left dock inHUD, adds a close/reopen toggle (✕ to dismiss, ☰ button to restore), and offsets it whenAgentCardis visible.Updates
SoloOperatorPanelto accept an optionalonClosecallback and render a close button when provided.Bumps
package.jsonversion to1.3.0and adds a pnpm override to pinpicomatch(>=4.0.4), with correspondingpnpm-lock.yamlupdates.Written by Cursor Bugbot for commit b124386. This will update automatically on new commits. Configure here.