feat: add SessionLifecycleStatus component with bottom-overlay layout

- New SessionLifecycleStatus.vue: shows current hook lifecycle event
  with color-coded dot, event name, and detail text. Auto-detects
  mock vs real mode (falls back to demo cycle when no real data).
- Wrap lifecycle + UserInput + status-bar in .bottom-overlay container
  to eliminate fragile hardcoded pixel offsets in FloatingTranscriptDebug.
- Remove old agent-status-indicator square dot from status bar.
- Add lastHookEvent/lastHookDetail to client AgentSessionState type.
- Simplify idle-mode CSS: single .bottom-overlay rule replaces three
  separate show/hide rules for user-input, status-bar, lifecycle-ribbon.
This commit is contained in:
2026-02-21 03:29:15 -06:00
parent 2aec892f62
commit 07783f2aea
4 changed files with 285 additions and 89 deletions

View File

@@ -970,29 +970,15 @@ onBeforeUnmount(() => {
pointer-events: none !important;
}
/* Idle: slide user-input down and fade out (only if empty) */
.aero-win:not(.chrome-visible) .content :deep(.user-input) {
/* Idle: slide bottom-overlay down and fade out */
.aero-win:not(.chrome-visible) .content :deep(.bottom-overlay) {
opacity: 0 !important;
transform: translateY(100%) !important;
pointer-events: none !important;
}
/* Keep user-input visible when textarea has text */
.aero-win:not(.chrome-visible) .content :deep(.user-input:has(.input-field:not(:placeholder-shown))) {
opacity: 1 !important;
transform: none !important;
pointer-events: auto !important;
}
/* Idle: hide status bar */
.aero-win:not(.chrome-visible) .content :deep(.status-bar) {
opacity: 0 !important;
transform: translateY(100%) !important;
pointer-events: none !important;
}
/* Keep status-bar visible when input has text */
.aero-win:not(.chrome-visible) .content :deep(.status-bar:has(~ .user-input .input-field:not(:placeholder-shown))) {
/* Keep bottom-overlay visible when textarea has text */
.aero-win:not(.chrome-visible) .content :deep(.bottom-overlay:has(.input-field:not(:placeholder-shown))) {
opacity: 1 !important;
transform: none !important;
pointer-events: auto !important;
@@ -1022,11 +1008,7 @@ onBeforeUnmount(() => {
transition: opacity 0.35s ease, transform 0.35s ease !important;
}
.content :deep(.user-input) {
transition: opacity 0.35s ease, transform 0.35s ease !important;
}
.content :deep(.status-bar) {
.content :deep(.bottom-overlay) {
transition: opacity 0.35s ease, transform 0.35s ease !important;
}
@@ -1321,16 +1303,23 @@ onBeforeUnmount(() => {
}
/* Status bar: absolute overlay at very bottom */
.content :deep(.status-bar) {
/* Bottom overlay: absolute container for lifecycle + input + status */
.content :deep(.bottom-overlay) {
position: absolute !important;
bottom: 0 !important;
left: 0 !important;
right: 0 !important;
z-index: 4 !important;
background: rgba(0, 6, 18, 0.6) !important;
z-index: 3 !important;
display: flex !important;
flex-direction: column !important;
background: rgba(0, 6, 18, 0.5) !important;
backdrop-filter: blur(8px) !important;
-webkit-backdrop-filter: blur(8px) !important;
border-top: 1px solid rgba(255, 255, 255, 0.06) !important;
}
.content :deep(.status-bar) {
background: transparent !important;
border-top: 1px solid rgba(255, 255, 255, 0.04) !important;
border-bottom: none !important;
padding: 0.15rem 0.5rem !important;
@@ -1368,20 +1357,19 @@ onBeforeUnmount(() => {
color: rgba(255,255,255,0.2) !important;
}
/* UserInput: absolute overlay above status bar */
/* UserInput: inside bottom-overlay, no absolute positioning needed */
.content :deep(.user-input) {
position: absolute !important;
bottom: 20px !important;
left: 0 !important;
right: 0 !important;
z-index: 3 !important;
background: rgba(0, 6, 18, 0.5) !important;
backdrop-filter: blur(8px) !important;
-webkit-backdrop-filter: blur(8px) !important;
border-top: 1px solid rgba(255, 255, 255, 0.06) !important;
background: transparent !important;
border-top: 1px solid rgba(255, 255, 255, 0.04) !important;
padding: 0.3rem 0.5rem !important;
}
/* Lifecycle ribbon: inside bottom-overlay, flows naturally above user-input */
.content :deep(.lifecycle-ribbon) {
background: transparent !important;
pointer-events: none !important;
}
/* Dark overlay on input-container so text is readable */
.content :deep(.input-container) {
background: rgba(0, 6, 18, 0.8) !important;