feat(bd-k1p): Add Focus Mode UI controls
Implemented Focus Mode functionality with the following features: - Added keybindings: p (pin/unpin worker), P (pin/unpin bead), F (toggle focus) - Visual indicators (📌) for pinned workers and beads - Dimmed display for non-pinned items when Focus Mode is enabled - Updated footer to show Focus Mode status and pinned items - Updated help overlay with Focus Mode documentation - Added setFocusMode methods to WorkerGrid and ActivityStream components 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
a5879fd249
commit
73f8eb2616
5 changed files with 175 additions and 9 deletions
|
|
@ -1,5 +1,5 @@
|
|||
{"id":"bd-102","title":"Add unit tests for DependencyDag component","description":"Create unit tests for src/tui/components/DependencyDag.ts and dagUtils.ts. Test DAG rendering, node positioning, edge drawing, and interaction handling.","status":"in_progress","priority":3,"issue_type":"task","assignee":"coder","created_at":"2026-03-04T03:02:12.152465132Z","created_by":"coder","updated_at":"2026-03-04T03:57:31.214667470Z","source_repo":".","compaction_level":0,"original_size":0}
|
||||
{"id":"bd-122","title":"Parse conversation events from NEEDLE logs","description":"Extend parser.ts to recognize and parse conversation-related events from NEEDLE logs. Extract: user prompts, assistant responses, thinking blocks, tool calls with arguments/results. Store in ConversationEvent type.","status":"open","priority":3,"issue_type":"task","created_at":"2026-03-04T03:05:10.414540897Z","created_by":"coder","updated_at":"2026-03-04T03:05:10.414540897Z","source_repo":".","compaction_level":0,"original_size":0}
|
||||
{"id":"bd-102","title":"Add unit tests for DependencyDag component","description":"Create unit tests for src/tui/components/DependencyDag.ts and dagUtils.ts. Test DAG rendering, node positioning, edge drawing, and interaction handling.","status":"closed","priority":3,"issue_type":"task","assignee":"coder","created_at":"2026-03-04T03:02:12.152465132Z","created_by":"coder","updated_at":"2026-03-04T04:10:25.328580820Z","closed_at":"2026-03-04T04:10:25.309762645Z","close_reason":"done","source_repo":".","compaction_level":0,"original_size":0}
|
||||
{"id":"bd-122","title":"Parse conversation events from NEEDLE logs","description":"Extend parser.ts to recognize and parse conversation-related events from NEEDLE logs. Extract: user prompts, assistant responses, thinking blocks, tool calls with arguments/results. Store in ConversationEvent type.","status":"in_progress","priority":3,"issue_type":"task","assignee":"coder","created_at":"2026-03-04T03:05:10.414540897Z","created_by":"coder","updated_at":"2026-03-04T04:11:05.705618330Z","source_repo":".","compaction_level":0,"original_size":0}
|
||||
{"id":"bd-123","title":"ALERT: Worker claude-code-glm-5-alpha has no work available","description":"# Worker Starvation Alert\n\nWorker **claude-code-glm-5-alpha** has exhausted all priorities and found zero work.\n\nThis is considered an error state - there should always be more work.\n\n## Worker State\n\n- **Executor:** claude-code-glm-5\n- **Model:** glm-5\n- **Workspace:** /home/coder/FABRIC\n- **Root Boundary:** /home/coder/FABRIC\n- **Last completion:** \n- **Beads completed:** 0\n- **Claim success rate:** %\n- **Uptime:** 16700s (h)\n- **Consecutive empty iterations:** 5\n\n## Priorities Exhausted\n\n1. ✗ Local workspace (bottoms-up): No beads in /home/coder/FABRIC or subfolders\n2. ✗ Parent exploration: No suitable workspaces found\n3. ✓ Maintenance: Completed (cleaned orphaned claims/locks)\n4. ✗ Gap analysis: false - No gaps found or created\n5. ✗ HUMAN alternatives: true - No HUMAN beads found to unblock\n\n## Discovered Workspaces\n\nTotal: 1\n\n- /home/coder/FABRIC\n\n## Required Actions\n\n1. Review discovery roots: Are all project folders being scanned?\n2. Check if projects need new features/tasks\n3. Review ROADMAP.md files across projects\n4. Enable gap analysis if disabled: `--enable-gap-analysis`\n5. Enable HUMAN alternatives if disabled\n6. Create manual beads to bootstrap work\n\n---\n*This alert was created automatically by Priority 6*","status":"closed","priority":0,"issue_type":"human","created_at":"2026-03-03T09:01:50.527254677Z","created_by":"coder","updated_at":"2026-03-03T09:04:19.266904698Z","closed_at":"2026-03-03T09:04:19.266841038Z","source_repo":".","compaction_level":0,"original_size":0,"comments":[{"id":12,"issue_id":"bd-123","author":"Jed Arden","text":"Alternative analysis: Work IS available (22 beads in ready-queue.json). This HUMAN bead is a false positive - workers should read ready-queue.json directly. Propose closure.","created_at":"2026-03-03T09:04:19Z"}]}
|
||||
{"id":"bd-129","title":"Add blessed TUI tests for ActivityStream component","description":"Add unit tests for src/tui/components/ActivityStream.ts using blessed testing patterns.","status":"closed","priority":3,"issue_type":"task","assignee":"coder","created_at":"2026-03-03T14:28:18.913405189Z","created_by":"coder","updated_at":"2026-03-03T15:31:25.719997480Z","closed_at":"2026-03-03T15:31:25.690904382Z","close_reason":"completed","source_repo":".","compaction_level":0,"original_size":0,"labels":["phase-2","testing","tui"]}
|
||||
{"id":"bd-13y","title":"ALERT: Worker claude-code-glm-5-alpha has no work available","description":"# Worker Starvation Alert\n\nWorker **claude-code-glm-5-alpha** has exhausted all priorities and found zero work.\n\nThis is considered an error state - there should always be more work.\n\n## Worker State\n\n- **Executor:** claude-code-glm-5\n- **Model:** glm-5\n- **Workspace:** /home/coder/FABRIC\n- **Root Boundary:** /home/coder/FABRIC\n- **Last completion:** \n- **Beads completed:** 0\n- **Claim success rate:** %\n- **Uptime:** 17238s (h)\n- **Consecutive empty iterations:** 5\n\n## Priorities Exhausted\n\n1. ✗ Local workspace (bottoms-up): No beads in /home/coder/FABRIC or subfolders\n2. ✗ Parent exploration: No suitable workspaces found\n3. ✓ Maintenance: Completed (cleaned orphaned claims/locks)\n4. ✗ Gap analysis: false - No gaps found or created\n5. ✗ HUMAN alternatives: true - No HUMAN beads found to unblock\n\n## Discovered Workspaces\n\nTotal: 1\n\n- /home/coder/FABRIC\n\n## Required Actions\n\n1. Review discovery roots: Are all project folders being scanned?\n2. Check if projects need new features/tasks\n3. Review ROADMAP.md files across projects\n4. Enable gap analysis if disabled: `--enable-gap-analysis`\n5. Enable HUMAN alternatives if disabled\n6. Create manual beads to bootstrap work\n\n---\n*This alert was created automatically by Priority 6*","status":"closed","priority":0,"issue_type":"human","created_at":"2026-03-03T09:10:48.326406226Z","created_by":"coder","updated_at":"2026-03-03T09:15:00.935446905Z","closed_at":"2026-03-03T09:15:00.935230202Z","source_repo":".","compaction_level":0,"original_size":0}
|
||||
|
|
@ -123,7 +123,7 @@
|
|||
{"id":"bd-fi7","title":"ALERT: Worker claude-code-glm-5-alpha has no work available","description":"# Worker Starvation Alert\n\nWorker **claude-code-glm-5-alpha** has exhausted all priorities and found zero work.\n\nThis is considered an error state - there should always be more work.\n\n## Worker State\n\n- **Executor:** claude-code-glm-5\n- **Model:** glm-5\n- **Workspace:** /home/coder/FABRIC\n- **Root Boundary:** /home/coder/FABRIC\n- **Last completion:** \n- **Beads completed:** 0\n- **Claim success rate:** %\n- **Uptime:** 24009s (h)\n- **Consecutive empty iterations:** 5\n\n## Priorities Exhausted\n\n1. ✗ Local workspace (bottoms-up): No beads in /home/coder/FABRIC or subfolders\n2. ✗ Parent exploration: No suitable workspaces found\n3. ✓ Maintenance: Completed (cleaned orphaned claims/locks)\n4. ✗ Gap analysis: false - No gaps found or created\n5. ✗ HUMAN alternatives: true - No HUMAN beads found to unblock\n\n## Discovered Workspaces\n\nTotal: 1\n\n- /home/coder/FABRIC\n\n## Required Actions\n\n1. Review discovery roots: Are all project folders being scanned?\n2. Check if projects need new features/tasks\n3. Review ROADMAP.md files across projects\n4. Enable gap analysis if disabled: `--enable-gap-analysis`\n5. Enable HUMAN alternatives if disabled\n6. Create manual beads to bootstrap work\n\n---\n*This alert was created automatically by Priority 6*","status":"closed","priority":0,"issue_type":"human","assignee":"coder","created_at":"2026-03-03T11:03:39.335046006Z","created_by":"coder","updated_at":"2026-03-03T11:04:19.485393573Z","closed_at":"2026-03-03T11:04:19.482736466Z","close_reason":"FALSE POSITIVE: ready-queue.json has 22 beads available. Worker discovery failed to check ready-queue.json before escalating to HUMAN bead. Same pattern as bd-2c8, bd-yw5, bd-1k7, etc.","source_repo":".","compaction_level":0,"original_size":0}
|
||||
{"id":"bd-fpf","title":"ALERT: Worker claude-code-glm-5-alpha has no work available","description":"# Worker Starvation Alert\n\nWorker **claude-code-glm-5-alpha** has exhausted all priorities and found zero work.\n\nThis is considered an error state - there should always be more work.\n\n## Worker State\n\n- **Executor:** claude-code-glm-5\n- **Model:** glm-5\n- **Workspace:** /home/coder/FABRIC\n- **Root Boundary:** /home/coder/FABRIC\n- **Last completion:** \n- **Beads completed:** 0\n- **Claim success rate:** %\n- **Uptime:** 21704s (h)\n- **Consecutive empty iterations:** 5\n\n## Priorities Exhausted\n\n1. ✗ Local workspace (bottoms-up): No beads in /home/coder/FABRIC or subfolders\n2. ✗ Parent exploration: No suitable workspaces found\n3. ✓ Maintenance: Completed (cleaned orphaned claims/locks)\n4. ✗ Gap analysis: false - No gaps found or created\n5. ✗ HUMAN alternatives: true - No HUMAN beads found to unblock\n\n## Discovered Workspaces\n\nTotal: 1\n\n- /home/coder/FABRIC\n\n## Required Actions\n\n1. Review discovery roots: Are all project folders being scanned?\n2. Check if projects need new features/tasks\n3. Review ROADMAP.md files across projects\n4. Enable gap analysis if disabled: `--enable-gap-analysis`\n5. Enable HUMAN alternatives if disabled\n6. Create manual beads to bootstrap work\n\n---\n*This alert was created automatically by Priority 6*","status":"closed","priority":0,"issue_type":"human","created_at":"2026-03-03T10:25:15.013726473Z","created_by":"coder","updated_at":"2026-03-03T10:26:46.789814780Z","closed_at":"2026-03-03T10:26:20.140101495Z","source_repo":".","compaction_level":0,"original_size":0,"comments":[{"id":27,"issue_id":"bd-fpf","author":"Jed Arden","text":"FALSE_POSITIVE: Worker failed to check ready-queue.json. Ready queue has 22 available beads. Closing per MEMORY.md pattern.","created_at":"2026-03-03T10:26:46Z"}]}
|
||||
{"id":"bd-jod","title":"ALERT: Worker claude-code-glm-5-bravo has no work available","description":"# Worker Starvation Alert\n\nWorker **claude-code-glm-5-bravo** has exhausted all priorities and found zero work.\n\nThis is considered an error state - there should always be more work.\n\n## Worker State\n\n- **Executor:** claude-code-glm-5\n- **Model:** glm-5\n- **Workspace:** /home/coder/FABRIC\n- **Root Boundary:** /home/coder/FABRIC\n- **Last completion:** \n- **Beads completed:** 0\n- **Claim success rate:** %\n- **Uptime:** 28580s (h)\n- **Consecutive empty iterations:** 5\n\n## Priorities Exhausted\n\n1. ✗ Local workspace (bottoms-up): No beads in /home/coder/FABRIC or subfolders\n2. ✗ Parent exploration: No suitable workspaces found\n3. ✓ Maintenance: Completed (cleaned orphaned claims/locks)\n4. ✗ Gap analysis: false - No gaps found or created\n5. ✗ HUMAN alternatives: true - No HUMAN beads found to unblock\n\n## Discovered Workspaces\n\nTotal: 1\n\n- /home/coder/FABRIC\n\n## Required Actions\n\n1. Review discovery roots: Are all project folders being scanned?\n2. Check if projects need new features/tasks\n3. Review ROADMAP.md files across projects\n4. Enable gap analysis if disabled: `--enable-gap-analysis`\n5. Enable HUMAN alternatives if disabled\n6. Create manual beads to bootstrap work\n\n---\n*This alert was created automatically by Priority 6*","status":"closed","priority":0,"issue_type":"human","assignee":"coder","created_at":"2026-03-03T12:19:52.916988738Z","created_by":"coder","updated_at":"2026-03-03T12:21:10.794758741Z","closed_at":"2026-03-03T12:21:10.788522717Z","close_reason":"FALSE POSITIVE: Worker starvation alert is incorrect. Ready-queue.json shows 22 available beads with work including: bd-2zt (ALT-001), bd-2r0 (P3-007), bd-2qm (P3-003), bd-1a2 (parser tests), bd-2en (store tests). Workers should claim from ready-queue.json directly.","source_repo":".","compaction_level":0,"original_size":0}
|
||||
{"id":"bd-k1p","title":"Add Focus Mode UI controls","description":"Add Focus Mode keybindings: p to pin/unpin worker, P to pin/unpin bead, F to toggle focus. Visual indicator for pinned items, dimmed display for non-pinned.","status":"open","priority":3,"issue_type":"task","created_at":"2026-03-04T03:06:37.599761897Z","created_by":"coder","updated_at":"2026-03-04T03:07:10.740989876Z","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-k1p","depends_on_id":"bd-qt4","type":"blocks","created_at":"2026-03-04T03:07:10.740878918Z","created_by":"coder"}]}
|
||||
{"id":"bd-k1p","title":"Add Focus Mode UI controls","description":"Add Focus Mode keybindings: p to pin/unpin worker, P to pin/unpin bead, F to toggle focus. Visual indicator for pinned items, dimmed display for non-pinned.","status":"in_progress","priority":3,"issue_type":"task","assignee":"coder","created_at":"2026-03-04T03:06:37.599761897Z","created_by":"coder","updated_at":"2026-03-04T04:09:50.596654259Z","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-k1p","depends_on_id":"bd-qt4","type":"blocks","created_at":"2026-03-04T03:07:10.740878918Z","created_by":"coder"}]}
|
||||
{"id":"bd-lj9","title":"ALERT: Worker claude-code-glm-5-bravo has no work available","description":"# Worker Starvation Alert\n\nWorker **claude-code-glm-5-bravo** has exhausted all priorities and found zero work.\n\nThis is considered an error state - there should always be more work.\n\n## Worker State\n\n- **Executor:** claude-code-glm-5\n- **Model:** glm-5\n- **Workspace:** /home/coder/FABRIC\n- **Root Boundary:** /home/coder/FABRIC\n- **Last completion:** \n- **Beads completed:** 0\n- **Claim success rate:** %\n- **Uptime:** 20887s (h)\n- **Consecutive empty iterations:** 5\n\n## Priorities Exhausted\n\n1. ✗ Local workspace (bottoms-up): No beads in /home/coder/FABRIC or subfolders\n2. ✗ Parent exploration: No suitable workspaces found\n3. ✓ Maintenance: Completed (cleaned orphaned claims/locks)\n4. ✗ Gap analysis: false - No gaps found or created\n5. ✗ HUMAN alternatives: true - No HUMAN beads found to unblock\n\n## Discovered Workspaces\n\nTotal: 1\n\n- /home/coder/FABRIC\n\n## Required Actions\n\n1. Review discovery roots: Are all project folders being scanned?\n2. Check if projects need new features/tasks\n3. Review ROADMAP.md files across projects\n4. Enable gap analysis if disabled: `--enable-gap-analysis`\n5. Enable HUMAN alternatives if disabled\n6. Create manual beads to bootstrap work\n\n---\n*This alert was created automatically by Priority 6*","status":"closed","priority":0,"issue_type":"human","created_at":"2026-03-03T10:11:39.654754002Z","created_by":"coder","updated_at":"2026-03-03T10:14:47.575272726Z","closed_at":"2026-03-03T10:14:47.575071208Z","source_repo":".","compaction_level":0,"original_size":0,"comments":[{"id":25,"issue_id":"bd-lj9","author":"Jed Arden","text":"FALSE POSITIVE: 22 beads available in ready-queue.json","created_at":"2026-03-03T10:14:41Z"}]}
|
||||
{"id":"bd-mn8","title":"ALERT: Worker claude-code-glm-5-alpha has no work available","description":"# Worker Starvation Alert\n\nWorker **claude-code-glm-5-alpha** has exhausted all priorities and found zero work.\n\nThis is considered an error state - there should always be more work.\n\n## Worker State\n\n- **Executor:** claude-code-glm-5\n- **Model:** glm-5\n- **Workspace:** /home/coder/FABRIC\n- **Root Boundary:** /home/coder/FABRIC\n- **Last completion:** \n- **Beads completed:** 0\n- **Claim success rate:** %\n- **Uptime:** 25832s (h)\n- **Consecutive empty iterations:** 5\n\n## Priorities Exhausted\n\n1. ✗ Local workspace (bottoms-up): No beads in /home/coder/FABRIC or subfolders\n2. ✗ Parent exploration: No suitable workspaces found\n3. ✓ Maintenance: Completed (cleaned orphaned claims/locks)\n4. ✗ Gap analysis: false - No gaps found or created\n5. ✗ HUMAN alternatives: true - No HUMAN beads found to unblock\n\n## Discovered Workspaces\n\nTotal: 1\n\n- /home/coder/FABRIC\n\n## Required Actions\n\n1. Review discovery roots: Are all project folders being scanned?\n2. Check if projects need new features/tasks\n3. Review ROADMAP.md files across projects\n4. Enable gap analysis if disabled: `--enable-gap-analysis`\n5. Enable HUMAN alternatives if disabled\n6. Create manual beads to bootstrap work\n\n---\n*This alert was created automatically by Priority 6*","status":"closed","priority":0,"issue_type":"human","assignee":"coder","created_at":"2026-03-03T11:34:02.591107993Z","created_by":"coder","updated_at":"2026-03-03T11:35:08.093925253Z","closed_at":"2026-03-03T11:35:08.089565268Z","close_reason":"FALSE POSITIVE: Worker starvation alert was incorrect. Ready-queue.json contains 22 available beads (bd-2zt, bd-2ed, bd-1mq, etc.). Worker discovery logic should check ready-queue.json before creating HUMAN beads. See MEMORY.md for resolution pattern.","source_repo":".","compaction_level":0,"original_size":0}
|
||||
{"id":"bd-msa","title":"Implement worker analytics aggregation","description":"Create module to aggregate worker performance metrics: beads per hour, average completion time, error rate, cost per bead, idle percentage. Store time-series data.","status":"in_progress","priority":4,"issue_type":"task","assignee":"coder","created_at":"2026-03-04T03:06:04.671550741Z","created_by":"coder","updated_at":"2026-03-04T03:40:24.300691642Z","source_repo":".","compaction_level":0,"original_size":0}
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ vi.mock('./components/WorkerGrid.js', () => {
|
|||
getSelected = vi.fn(() => null);
|
||||
focus = vi.fn();
|
||||
getElement = vi.fn(() => ({ hide: vi.fn(), show: vi.fn(), screen: { render: vi.fn() } }));
|
||||
setFocusMode = vi.fn();
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
@ -96,6 +97,7 @@ vi.mock('./components/ActivityStream.js', () => {
|
|||
focus = vi.fn();
|
||||
getElement = vi.fn(() => ({ hide: vi.fn(), show: vi.fn(), screen: { render: vi.fn() } }));
|
||||
getIsPaused = vi.fn(() => false);
|
||||
setFocusMode = vi.fn();
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
|
|||
126
src/tui/app.ts
126
src/tui/app.ts
|
|
@ -38,6 +38,11 @@ export class FabricTuiApp {
|
|||
// View mode
|
||||
private viewMode: 'default' | 'heatmap' | 'dag' | 'replay' | 'errors' = 'default';
|
||||
|
||||
// Focus mode state
|
||||
private focusModeEnabled = false;
|
||||
private pinnedWorkerId?: string;
|
||||
private pinnedBeadId?: string;
|
||||
|
||||
// UI Components
|
||||
private headerBox!: blessed.Widgets.BoxElement;
|
||||
private workerGrid!: WorkerGrid;
|
||||
|
|
@ -185,13 +190,41 @@ export class FabricTuiApp {
|
|||
left: 0,
|
||||
right: 0,
|
||||
height: 1,
|
||||
content: ' [Tab] Switch [j/k] Scroll [/] Search [H] Heatmap [D] DAG [E] Errors [?] Help [q] Quit',
|
||||
content: this.getFooterContent(),
|
||||
style: {
|
||||
fg: colors.muted,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get footer content based on current state
|
||||
*/
|
||||
private getFooterContent(): string {
|
||||
if (this.viewMode === 'default') {
|
||||
let content = ' [Tab] Switch [j/k] Scroll [/] Search [H] Heatmap [D] DAG [E] Errors';
|
||||
|
||||
// Show focus mode status
|
||||
if (this.focusModeEnabled) {
|
||||
content += ' {green-fg}[FOCUS MODE]{/}';
|
||||
if (this.pinnedWorkerId) {
|
||||
content += ` Worker:${this.pinnedWorkerId.slice(0, 8)}`;
|
||||
}
|
||||
if (this.pinnedBeadId) {
|
||||
content += ` Bead:${this.pinnedBeadId}`;
|
||||
}
|
||||
}
|
||||
|
||||
content += ' [p]Pin Worker [P]Pin Bead [F]Focus';
|
||||
content += ' [?] Help [q] Quit';
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
// Return default content for other views
|
||||
return ' [Tab] Switch [j/k] Scroll [/] Search [H] Heatmap [D] DAG [E] Errors [?] Help [q] Quit';
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind keyboard shortcuts
|
||||
*/
|
||||
|
|
@ -259,6 +292,19 @@ export class FabricTuiApp {
|
|||
this.setViewMode('default');
|
||||
}
|
||||
});
|
||||
|
||||
// Focus mode keybindings
|
||||
this.screen.key(['p'], () => {
|
||||
this.toggleWorkerPin();
|
||||
});
|
||||
|
||||
this.screen.key(['P'], () => {
|
||||
this.toggleBeadPin();
|
||||
});
|
||||
|
||||
this.screen.key(['F'], () => {
|
||||
this.toggleFocusMode();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -431,7 +477,7 @@ export class FabricTuiApp {
|
|||
|
||||
// Update header
|
||||
this.headerBox.setContent(' FABRIC - Worker Activity Monitor');
|
||||
this.footerBox.setContent(' [Tab] Switch [j/k] Scroll [/] Search [H] Heatmap [D] DAG [E] Errors [?] Help [q] Quit');
|
||||
this.footerBox.setContent(this.getFooterContent());
|
||||
}
|
||||
|
||||
this.screen.render();
|
||||
|
|
@ -447,6 +493,9 @@ export class FabricTuiApp {
|
|||
const stateText = state === 'playing' ? 'PLAYING' : state === 'paused' ? 'PAUSED' : state === 'ended' ? 'ENDED' : 'READY';
|
||||
this.footerBox.setContent(` [${stateText}] [Space] Play/Pause [←/→] Step [↑/↓] Speed(${speed}x) [Home/End] Jump [r] Reset [Esc] Back [q] Quit`);
|
||||
this.screen.render();
|
||||
} else {
|
||||
this.footerBox.setContent(this.getFooterContent());
|
||||
this.screen.render();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -460,6 +509,67 @@ export class FabricTuiApp {
|
|||
this.workerDetail.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle worker pin
|
||||
*/
|
||||
private toggleWorkerPin(): void {
|
||||
if (this.viewMode !== 'default') return;
|
||||
|
||||
const selected = this.workerGrid.getSelected();
|
||||
if (!selected) return;
|
||||
|
||||
if (this.pinnedWorkerId === selected.id) {
|
||||
// Unpin worker
|
||||
this.pinnedWorkerId = undefined;
|
||||
} else {
|
||||
// Pin worker
|
||||
this.pinnedWorkerId = selected.id;
|
||||
}
|
||||
|
||||
this.updateFooter();
|
||||
this.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle bead pin
|
||||
*/
|
||||
private toggleBeadPin(): void {
|
||||
if (this.viewMode !== 'default') return;
|
||||
|
||||
const selected = this.workerGrid.getSelected();
|
||||
if (!selected || !selected.lastEvent?.bead) return;
|
||||
|
||||
const beadId = selected.lastEvent.bead;
|
||||
if (this.pinnedBeadId === beadId) {
|
||||
// Unpin bead
|
||||
this.pinnedBeadId = undefined;
|
||||
} else {
|
||||
// Pin bead
|
||||
this.pinnedBeadId = beadId;
|
||||
}
|
||||
|
||||
this.updateFooter();
|
||||
this.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle focus mode
|
||||
*/
|
||||
private toggleFocusMode(): void {
|
||||
if (this.viewMode !== 'default') return;
|
||||
|
||||
this.focusModeEnabled = !this.focusModeEnabled;
|
||||
|
||||
// If disabling focus mode, clear pins
|
||||
if (!this.focusModeEnabled) {
|
||||
this.pinnedWorkerId = undefined;
|
||||
this.pinnedBeadId = undefined;
|
||||
}
|
||||
|
||||
this.updateFooter();
|
||||
this.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle help overlay
|
||||
*/
|
||||
|
|
@ -489,11 +599,15 @@ Actions:
|
|||
/ - Search
|
||||
f - Filter
|
||||
r - Refresh
|
||||
p - Pause scroll
|
||||
H - Toggle file heatmap
|
||||
D - Toggle dependency DAG
|
||||
R - Toggle session replay
|
||||
|
||||
Focus Mode:
|
||||
F - Toggle focus mode
|
||||
p - Pin/unpin selected worker
|
||||
P - Pin/unpin bead (from selected worker)
|
||||
|
||||
Heatmap View:
|
||||
s - Cycle sort mode
|
||||
c - Toggle collisions only
|
||||
|
|
@ -541,6 +655,8 @@ General:
|
|||
private renderWorkers(): void {
|
||||
const workers = this.store.getWorkers();
|
||||
this.workerGrid.updateWorkers(workers);
|
||||
this.workerGrid.setFocusMode(this.focusModeEnabled, this.pinnedWorkerId);
|
||||
this.activityStream.setFocusMode(this.focusModeEnabled, this.pinnedBeadId, this.pinnedWorkerId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -550,6 +666,10 @@ General:
|
|||
this.activityStream.addEvent(event);
|
||||
this.renderWorkers();
|
||||
|
||||
// Update focus mode state after rendering
|
||||
this.workerGrid.setFocusMode(this.focusModeEnabled, this.pinnedWorkerId);
|
||||
this.activityStream.setFocusMode(this.focusModeEnabled, this.pinnedBeadId, this.pinnedWorkerId);
|
||||
|
||||
// Update heatmap if visible
|
||||
if (this.viewMode === 'heatmap') {
|
||||
this.fileHeatmap.updateData(
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ export class ActivityStream {
|
|||
private filter: ActivityFilter = {};
|
||||
private maxLines: number;
|
||||
private isPaused = false;
|
||||
private focusModeEnabled = false;
|
||||
private pinnedBeadId?: string;
|
||||
private pinnedWorkerId?: string;
|
||||
|
||||
constructor(options: ActivityStreamOptions) {
|
||||
this.maxLines = options.maxLines || 500;
|
||||
|
|
@ -105,11 +108,23 @@ export class ActivityStream {
|
|||
if (event.tool) {
|
||||
msg = `[${event.tool}] ${msg}`;
|
||||
}
|
||||
|
||||
// Check if this event is pinned
|
||||
const isBeadPinned = this.pinnedBeadId && event.bead === this.pinnedBeadId;
|
||||
const isWorkerPinned = this.pinnedWorkerId && event.worker === this.pinnedWorkerId;
|
||||
const isPinned = isBeadPinned || isWorkerPinned;
|
||||
const pinIndicator = isPinned ? '{yellow-fg}📌{/}' : '';
|
||||
|
||||
if (event.bead) {
|
||||
msg = `{blue-fg}${event.bead}{/} ${msg}`;
|
||||
msg = `{blue-fg}${event.bead}{/} ${pinIndicator}${msg}`;
|
||||
}
|
||||
|
||||
return `{gray-fg}${time}{/} {bold}${workerShort}{/} {${levelColor}-fg}${event.level.toUpperCase()}{/} ${msg}`;
|
||||
// Dim non-pinned events when in focus mode
|
||||
const shouldDim = this.focusModeEnabled && (this.pinnedBeadId || this.pinnedWorkerId) && !isPinned;
|
||||
const dimPrefix = shouldDim ? '{gray-fg}' : '';
|
||||
const dimSuffix = shouldDim ? '{/}' : '';
|
||||
|
||||
return `${dimPrefix}{gray-fg}${time}{/} {bold}${workerShort}{/} {${levelColor}-fg}${event.level.toUpperCase()}{/} ${msg}${dimSuffix}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -262,6 +277,16 @@ export class ActivityStream {
|
|||
getFilteredEventsCount(): number {
|
||||
return this.events.filter(e => this.passesFilter(e)).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set focus mode state
|
||||
*/
|
||||
setFocusMode(enabled: boolean, pinnedBeadId?: string, pinnedWorkerId?: string): void {
|
||||
this.focusModeEnabled = enabled;
|
||||
this.pinnedBeadId = pinnedBeadId;
|
||||
this.pinnedWorkerId = pinnedWorkerId;
|
||||
this.reRender();
|
||||
}
|
||||
}
|
||||
|
||||
export default ActivityStream;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ export class WorkerGrid {
|
|||
private box: blessed.Widgets.BoxElement;
|
||||
private workers: WorkerInfo[] = [];
|
||||
private selectedIndex = 0;
|
||||
private focusModeEnabled = false;
|
||||
private pinnedWorkerId?: string;
|
||||
|
||||
constructor(options: WorkerGridOptions) {
|
||||
this.box = blessed.box({
|
||||
|
|
@ -114,7 +116,15 @@ export class WorkerGrid {
|
|||
const collisionIndicator = this.getCollisionIndicator(worker);
|
||||
|
||||
const selectedMarker = isSelected ? '>' : ' ';
|
||||
return `${selectedMarker} {${color}-fg}${icon}{/} {bold}${workerId}{/} {gray-fg}${currentTask}{/} ${taskDesc} {blue-fg}${duration}{/} ${collisionIndicator}`;
|
||||
const isPinned = this.pinnedWorkerId === worker.id;
|
||||
const pinIndicator = isPinned ? '{yellow-fg}📌{/}' : '';
|
||||
|
||||
// Dim non-pinned workers when in focus mode
|
||||
const shouldDim = this.focusModeEnabled && this.pinnedWorkerId && !isPinned;
|
||||
const dimPrefix = shouldDim ? '{gray-fg}' : '';
|
||||
const dimSuffix = shouldDim ? '{/}' : '';
|
||||
|
||||
return `${dimPrefix}${selectedMarker} {${color}-fg}${icon}{/} {bold}${workerId}{/} ${pinIndicator} {gray-fg}${currentTask}{/} ${taskDesc} {blue-fg}${duration}{/} ${collisionIndicator}${dimSuffix}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -199,6 +209,15 @@ export class WorkerGrid {
|
|||
getElement(): blessed.Widgets.BoxElement {
|
||||
return this.box;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set focus mode state
|
||||
*/
|
||||
setFocusMode(enabled: boolean, pinnedWorkerId?: string): void {
|
||||
this.focusModeEnabled = enabled;
|
||||
this.pinnedWorkerId = pinnedWorkerId;
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
||||
export default WorkerGrid;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue