Skip to content

feat: operator digest bottom-left + closable, bump v1.3.0#238

Merged
charlesrhoward merged 3 commits intomainfrom
chore/nextjs-16.2
Mar 26, 2026
Merged

feat: operator digest bottom-left + closable, bump v1.3.0#238
charlesrhoward merged 3 commits intomainfrom
chore/nextjs-16.2

Conversation

@charlesrhoward
Copy link
Copy Markdown
Contributor

@charlesrhoward charlesrhoward commented Mar 26, 2026

Summary

  • Move Daily operator digest panel from top-right to bottom-left of the office view
  • Add close/reopen toggle — panel shows a compact ☰ button when dismissed, ✕ to close
  • Update Next.js to 16.2
  • Bump version to 1.3.0

Test plan

  • Verify digest panel renders in bottom-left corner
  • Click ✕ to close — confirm panel hides and ☰ button appears
  • Click ☰ to reopen — confirm full panel returns
  • Verify CelebrationDeck still renders in top-right
  • Desktop smoke test passes

🤖 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 in HUD, adds a close/reopen toggle (✕ to dismiss, ☰ button to restore), and offsets it when AgentCard is visible.

Updates SoloOperatorPanel to accept an optional onClose callback and render a close button when provided.

Bumps package.json version to 1.3.0 and adds a pnpm override to pin picomatch (>=4.0.4), with corresponding pnpm-lock.yaml updates.

Written by Cursor Bugbot for commit b124386. This will update automatically on new commits. Configure here.

@charlesrhoward charlesrhoward enabled auto-merge (squash) March 26, 2026 16:18
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 26, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agent-space-web Ready Ready Preview, Comment Mar 26, 2026 4:38pm

Request Review

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread src/renderer/hud/HUD.tsx
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread src/renderer/hud/HUD.tsx Outdated
{digestOpen ? (
<div
style={{
maxHeight: 'calc(100vh - 56px)',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

charlesrhoward and others added 2 commits March 26, 2026 09:26
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>
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>
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

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' }}>

Comment thread src/renderer/hud/HUD.tsx
}}
>
<SoloOperatorPanel onClose={() => setDigestOpen(false)} />
</div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Additional Locations (1)
Fix in Cursor Fix in Web

@charlesrhoward charlesrhoward merged commit 73b5430 into main Mar 26, 2026
7 checks passed
@charlesrhoward charlesrhoward deleted the chore/nextjs-16.2 branch March 26, 2026 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant