diff --git a/frontend/src/components/dashboard/AgentModal.vue b/frontend/src/components/dashboard/AgentModal.vue
index 8dbf87f..4f551fc 100644
--- a/frontend/src/components/dashboard/AgentModal.vue
+++ b/frontend/src/components/dashboard/AgentModal.vue
@@ -25,11 +25,11 @@ defineEmits<{
{{ agent.name }}
{{ agent.role }}
+
+
+
-
-
-
@@ -41,7 +41,34 @@ defineEmits<{
Current Task
- {{ agent.currentTask }}
+
+ {{ agent.currentTask }}
+
+
+
+
+
+
+
+
+
+ Live Thinking
+
+
+
+ {{ msg.time }}
+ {{ msg.text }}
+
+
+ Waiting for thought stream...
+
+
+
@@ -69,32 +96,8 @@ defineEmits<{
class="work-step"
>
- {{ step }}
-
-
-
-
-
-
- Live Thinking
-
-
-
- {{ msg.time }}
- {{ msg.text }}
-
-
-
-
-
-
- Waiting for thought stream...
-
+
{{ step.time }}
+
{{ step.text }}
@@ -102,15 +105,6 @@ defineEmits<{
@@ -197,21 +191,25 @@ defineEmits<{
font-weight: 500;
}
.agent-link-btn {
- display: grid;
- place-items: center;
- width: 32px;
- height: 32px;
- border: 1px solid rgba(255, 255, 255, 0.08);
- border-radius: 8px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 24px;
+ height: 24px;
+ margin-left: 4px;
+ border: none;
+ border-radius: 6px;
background: transparent;
color: #6b7385;
+ opacity: 0.4;
cursor: pointer;
- transition: all 0.2s;
+ transition: opacity 0.2s;
flex-shrink: 0;
text-decoration: none;
+ vertical-align: middle;
}
.agent-link-btn:hover {
- border-color: var(--agent-color);
+ opacity: 1;
color: var(--agent-color);
}
@@ -258,6 +256,9 @@ defineEmits<{
font-size: 12px;
color: #e8eaf0;
line-height: 1.4;
+ display: flex;
+ align-items: center;
+ gap: 8px;
}
/* Progress */
@@ -306,20 +307,30 @@ defineEmits<{
.thinking-dots {
display: inline-flex;
gap: 6px;
- margin-left: 8px;
flex-shrink: 0;
- animation: spin-dots 2s linear infinite;
}
.thinking-dot {
width: 7px;
height: 7px;
border-radius: 50%;
}
-.thinking-dot.blue { background: #3b82f6; box-shadow: 0 0 8px #3b82f6; }
-.thinking-dot.violet { background: #8b7cf6; box-shadow: 0 0 8px #8b7cf6; }
-@keyframes spin-dots {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
+.thinking-dot.blue {
+ background: #3b82f6;
+ box-shadow: 0 0 8px #3b82f6;
+ animation: pulse-dot-blue 1.2s ease-in-out infinite;
+}
+.thinking-dot.violet {
+ background: #8b7cf6;
+ box-shadow: 0 0 8px #8b7cf6;
+ animation: pulse-dot-violet 1.8s ease-in-out infinite 0.3s;
+}
+@keyframes pulse-dot-blue {
+ 0%, 100% { opacity: 0.4; transform: scale(0.7); }
+ 50% { opacity: 1; transform: scale(1.3); }
+}
+@keyframes pulse-dot-violet {
+ 0%, 100% { opacity: 0.3; transform: scale(0.6); }
+ 50% { opacity: 1; transform: scale(1.4); }
}
.thinking-stream {
@@ -383,6 +394,13 @@ defineEmits<{
color: #7e8799;
line-height: 1.35;
}
+.step-time {
+ font-size: 8.5px;
+ color: #6b7385;
+ flex-shrink: 0;
+ font-variant-numeric: tabular-nums;
+ min-width: 36px;
+}
/* Footer */
.modal-footer {
diff --git a/frontend/src/composables/useDashboardData.ts b/frontend/src/composables/useDashboardData.ts
index 4a60d58..dc07307 100644
--- a/frontend/src/composables/useDashboardData.ts
+++ b/frontend/src/composables/useDashboardData.ts
@@ -13,7 +13,7 @@ export interface AgentNodeData {
workload: number // 0-100
active: boolean
runtimeSeconds: number
- workingFeed: string[]
+ workingFeed: Array<{ time: string; text: string }>
thinkingStream?: Array<{ time: string; text: string }>
}
@@ -114,10 +114,10 @@ export function useDashboardData() {
active: true,
runtimeSeconds: 28800,
workingFeed: [
- 'Analyzed user feedback on Dashboard',
- 'Delegated card redesign to Developer',
- 'Verifying full-width layout deployment',
- 'Reviewing AgentModal integration',
+ { time: '22:38', text: 'Analyzed user feedback on Dashboard' },
+ { time: '22:36', text: 'Delegated card redesign to Developer' },
+ { time: '22:34', text: 'Verifying full-width layout deployment' },
+ { time: '22:32', text: 'Reviewing AgentModal integration' },
],
thinkingStream: [
{ time: '22:24', text: 'Analysing constraint: full-width layout' },
@@ -139,10 +139,10 @@ export function useDashboardData() {
active: true,
runtimeSeconds: 3600,
workingFeed: [
- 'Created DungeonController',
- 'Defined dungeon schema',
- 'Implementing room generation algorithm',
- 'Writing unit tests for RoomFactory',
+ { time: '22:30', text: 'Created DungeonController' },
+ { time: '22:28', text: 'Defined dungeon schema' },
+ { time: '22:26', text: 'Implementing room generation algorithm' },
+ { time: '22:24', text: 'Writing unit tests for RoomFactory' },
],
thinkingStream: [
{ time: '22:22', text: 'Parsing dungeon spec from Iris' },
@@ -164,10 +164,10 @@ export function useDashboardData() {
active: false,
runtimeSeconds: 1800,
workingFeed: [
- 'Analyzed Docker layer cache',
- 'Optimized COPY order in Dockerfile',
- 'Added .dockerignore for node_modules',
- 'Testing incremental builds',
+ { time: '22:20', text: 'Analyzed Docker layer cache' },
+ { time: '22:18', text: 'Optimized COPY order in Dockerfile' },
+ { time: '22:16', text: 'Added .dockerignore for node_modules' },
+ { time: '22:14', text: 'Testing incremental builds' },
],
thinkingStream: [
{ time: '22:20', text: 'Checking build cache hit rates' },
@@ -189,9 +189,9 @@ export function useDashboardData() {
active: true,
runtimeSeconds: 2700,
workingFeed: [
- 'Evaluated WebSocket vs SSE vs WebRTC',
- 'Documented SignalR limitations',
- 'Prototyping WebSocket fallback',
+ { time: '22:18', text: 'Evaluated WebSocket vs SSE vs WebRTC' },
+ { time: '22:17', text: 'Documented SignalR limitations' },
+ { time: '22:16', text: 'Prototyping WebSocket fallback' },
],
thinkingStream: [
{ time: '22:18', text: 'Cross-referencing WebSocket latency benchmarks' },
@@ -213,10 +213,10 @@ export function useDashboardData() {
active: false,
runtimeSeconds: 900,
workingFeed: [
- 'Reviewed DungeonController.cs',
- 'Found 3 minor style issues',
- 'Approved RoomValidator',
- 'Running integration tests',
+ { time: '22:15', text: 'Reviewed DungeonController.cs' },
+ { time: '22:14', text: 'Found 3 minor style issues' },
+ { time: '22:13', text: 'Approved RoomValidator' },
+ { time: '22:12', text: 'Running integration tests' },
],
thinkingStream: [
{ time: '22:15', text: 'Analyzing DungeonController PR diff' },