diff --git a/.agents/skills/flow-run/SKILL.md b/.agents/skills/flow-run/SKILL.md
index f5537139..36595a11 100644
--- a/.agents/skills/flow-run/SKILL.md
+++ b/.agents/skills/flow-run/SKILL.md
@@ -20,57 +20,69 @@ If the task identifier is unknown, determine it from `SPECS/Workplan.md` and `SP
Apply these rules throughout execution:
- Read `SPECS/COMMANDS/FLOW.md` at the beginning and treat it as the source of truth.
-- Complete steps in order: `BRANCH -> SELECT -> PLAN -> EXECUTE -> ARCHIVE -> REVIEW -> FOLLOW-UP -> ARCHIVE-REVIEW`.
-- Create a commit checkpoint after each major step using FLOW commit message patterns.
+- Complete steps in order: `BRANCH -> SELECT -> PLAN -> EXECUTE -> ARCHIVE -> REVIEW -> FOLLOW-UP -> ARCHIVE-REVIEW -> PR -> CI-REVIEW`.
+- Use the `flow-primitive-commit` skill for every commit checkpoint — stage only task-relevant files and use present-tense FLOW message patterns.
- Run required quality gates during EXECUTE (`pytest`, `ruff check src/`, `mypy src/` if configured, `pytest --cov` with coverage >= 90%).
- Record artifacts in expected locations under `SPECS/INPROGRESS/` and `SPECS/ARCHIVE/`.
- If REVIEW has no actionable issues, skip FOLLOW-UP and proceed directly to ARCHIVE-REVIEW, as FLOW permits.
+- After ARCHIVE-REVIEW, use the `gh-create-pr` skill to open a pull request from the feature branch into `main`.
## Step Procedure
1. BRANCH
- Ensure `main` is up to date.
- Create `feature/{TASK_ID}-{short-description}` if not already on the correct feature branch.
-- Commit message pattern: `Branch for {TASK_ID}: {short description}`.
+- Use `flow-primitive-commit` skill — commit message pattern: `Branch for {TASK_ID}: {short description}`.
2. SELECT
- Choose the next task from `SPECS/Workplan.md` (optionally with `python scripts/pick_next_task.py`).
- Update `SPECS/INPROGRESS/next.md` with selected task metadata.
-- Commit message pattern: `Select task {TASK_ID}: {TASK_NAME}`.
+- Use `flow-primitive-commit` skill — commit message pattern: `Select task {TASK_ID}: {TASK_NAME}`.
3. PLAN
- Create the task PRD at `SPECS/INPROGRESS/{TASK_ID}_{TASK_NAME}.md`.
- Define deliverables, acceptance criteria, dependencies.
-- Commit message pattern: `Plan task {TASK_ID}: {TASK_NAME}`.
+- Use `flow-primitive-commit` skill — commit message pattern: `Plan task {TASK_ID}: {TASK_NAME}`.
4. EXECUTE
- Implement to the PRD.
- Run quality gates defined in FLOW.
- Create `SPECS/INPROGRESS/{TASK_ID}_Validation_Report.md`.
-- Commit message pattern: `Implement {TASK_ID}: {brief description of changes}`.
-- Split into incremental commits if the task is large.
+- Use `flow-primitive-commit` skill — commit message pattern: `Implement {TASK_ID}: {brief description of changes}`.
+- For large tasks, invoke `flow-primitive-commit` incrementally after each logical unit of work.
5. ARCHIVE
- Run `SPECS/COMMANDS/ARCHIVE.md` workflow.
- Verify task archive folder exists under `SPECS/ARCHIVE/{TASK_ID}_{TASK_NAME}/`.
- Confirm `SPECS/INPROGRESS/next.md` and `SPECS/Workplan.md` are updated.
-- Commit message pattern: `Archive task {TASK_ID}: {TASK_NAME} ({VERDICT})`.
+- Use `flow-primitive-commit` skill — commit message pattern: `Archive task {TASK_ID}: {TASK_NAME} ({VERDICT})`.
6. REVIEW
- Run `SPECS/COMMANDS/REVIEW.md`.
- Save review report at `SPECS/INPROGRESS/REVIEW_{subject}.md`.
-- Commit message pattern: `Review {TASK_ID}: {short subject}`.
+- Use `flow-primitive-commit` skill — commit message pattern: `Review {TASK_ID}: {short subject}`.
7. FOLLOW-UP
- If review has actionable findings, run `SPECS/COMMANDS/PRIMITIVES/FOLLOW_UP.md`.
- Add follow-up tasks to `SPECS/Workplan.md`.
-- Commit message pattern: `Follow-up {TASK_ID}: {short subject}`.
+- Use `flow-primitive-commit` skill — commit message pattern: `Follow-up {TASK_ID}: {short subject}`.
- If no actionable findings, explicitly note FOLLOW-UP skipped.
8. ARCHIVE-REVIEW
- Move `REVIEW_{subject}.md` to `SPECS/ARCHIVE/_Historical/` or relevant task folder.
- Update `SPECS/ARCHIVE/INDEX.md`.
-- Commit message pattern: `Archive REVIEW_{subject} report`.
+- Use `flow-primitive-commit` skill — commit message pattern: `Archive REVIEW_{subject} report`.
+
+9. PR
+- Use `gh-create-pr` skill to open a pull request from the feature branch into `main`.
+- Title: `{TASK_ID}: {TASK_NAME}`.
+- Body: summarise changes, list quality gate results, reference the validation report.
+
+10. CI-REVIEW
+- Wait at least 40 seconds after PR creation to allow GitHub Actions to start.
+- Use `gh-pr-results-review` skill to inspect CI outcomes on the PR.
+- If all checks pass: report success and consider the run complete.
+- If checks fail: surface the actionable failure details from the skill output, fix the issues, push a new commit, then repeat CI-REVIEW.
## Completion Criteria
@@ -78,7 +90,9 @@ Consider the run complete only when all are true:
- FLOW step sequence has been fully executed (or optional FOLLOW-UP formally skipped due to no findings).
- Required artifacts exist in `SPECS/INPROGRESS/` and/or `SPECS/ARCHIVE/`.
- Required quality gates were run and outcomes captured.
-- Commit checkpoints align with FLOW message patterns.
+- Every commit checkpoint was created via the `flow-primitive-commit` skill with FLOW message patterns.
+- A pull request from the feature branch into `main` was opened via the `gh-create-pr` skill.
+- CI checks on the PR were reviewed via the `gh-pr-results-review` skill and all failures resolved.
## Trigger Phrases
diff --git a/SPECS/ARCHIVE/INDEX.md b/SPECS/ARCHIVE/INDEX.md
index bd8e9bbe..602e29b4 100644
--- a/SPECS/ARCHIVE/INDEX.md
+++ b/SPECS/ARCHIVE/INDEX.md
@@ -1,6 +1,6 @@
# mcpbridge-wrapper Tasks Archive
-**Last Updated:** 2026-02-15 (P11-T3)
+**Last Updated:** 2026-02-15 (P11-T4)
## Archived Tasks
@@ -93,6 +93,7 @@
| BUG-T8 | [BUG-T8_Audit_Log_Cross_Process_Visibility/](BUG-T8_Audit_Log_Cross_Process_Visibility/) | 2026-02-15 | PASS |
| P11-T2 | [P11-T2_Add_Session_Timeline_View/](P11-T2_Add_Session_Timeline_View/) | 2026-02-15 | PASS |
| P11-T3 | [P11-T3_Add_Dashboard_Theme_Toggle/](P11-T3_Add_Dashboard_Theme_Toggle/) | 2026-02-15 | PASS |
+| P11-T4 | [P11-T4_Add_Keyboard_Shortcuts_Command_Palette/](P11-T4_Add_Keyboard_Shortcuts_Command_Palette/) | 2026-02-15 | PASS |
## Historical Artifacts
@@ -150,6 +151,7 @@
| [REVIEW_BUG-T8_audit_log_cross_process.md](BUG-T8_Audit_Log_Cross_Process_Visibility/REVIEW_BUG-T8_audit_log_cross_process.md) | Review report for BUG-T8 |
| [REVIEW_P11-T2_session_timeline.md](P11-T2_Add_Session_Timeline_View/REVIEW_P11-T2_session_timeline.md) | Review report for P11-T2 |
| [REVIEW_P11-T3_dashboard_theme_toggle.md](P11-T3_Add_Dashboard_Theme_Toggle/REVIEW_P11-T3_dashboard_theme_toggle.md) | Review report for P11-T3 |
+| [REVIEW_P11-T4_keyboard_shortcuts.md](P11-T4_Add_Keyboard_Shortcuts_Command_Palette/REVIEW_P11-T4_keyboard_shortcuts.md) | Review report for P11-T4 |
## Archive Log
@@ -253,3 +255,5 @@
| 2026-02-15 | P11-T2 | Archived REVIEW_P11-T2_session_timeline report |
| 2026-02-15 | P11-T3 | Archived Add_Dashboard_Theme_Toggle (PASS) |
| 2026-02-15 | P11-T3 | Archived REVIEW_P11-T3_dashboard_theme_toggle report |
+| 2026-02-15 | P11-T4 | Archived Add_Keyboard_Shortcuts_Command_Palette (PASS) |
+| 2026-02-15 | P11-T4 | Archived REVIEW_P11-T4_keyboard_shortcuts report |
diff --git a/SPECS/ARCHIVE/P11-T4_Add_Keyboard_Shortcuts_Command_Palette/P11-T4_Add_Keyboard_Shortcuts_Command_Palette.md b/SPECS/ARCHIVE/P11-T4_Add_Keyboard_Shortcuts_Command_Palette/P11-T4_Add_Keyboard_Shortcuts_Command_Palette.md
new file mode 100644
index 00000000..1d7980bb
--- /dev/null
+++ b/SPECS/ARCHIVE/P11-T4_Add_Keyboard_Shortcuts_Command_Palette/P11-T4_Add_Keyboard_Shortcuts_Command_Palette.md
@@ -0,0 +1,66 @@
+# PRD: P11-T4 — Add Keyboard Shortcuts & Command Palette
+
+## Summary
+
+Add lightweight keyboard shortcut support to the dashboard. A `keydown` listener maps keys to dashboard actions. A `?` key shows a help overlay. No external library required.
+
+## Context
+
+The Web UI dashboard has chart sections, audit log, reset button, and export button. Keyboard shortcuts improve navigation for power users. The help overlay makes discovery easy.
+
+## Deliverables
+
+1. **`src/mcpbridge_wrapper/webui/static/index.html`**
+ - Add `id` attributes to the four chart sections for scroll targeting
+ - Add help overlay `
` with shortcut table
+
+2. **`src/mcpbridge_wrapper/webui/static/dashboard.css`**
+ - Style for `#shortcut-help-overlay` — centered modal with semi-transparent backdrop
+
+3. **`src/mcpbridge_wrapper/webui/static/dashboard.js`**
+ - `initKeyboardShortcuts()` function registered in `init()`
+ - Shortcut map: `?`, `1`, `2`, `3`, `4`, `a`, `r`, `e`
+ - Guard: if focus is inside an input or textarea, all shortcuts are skipped
+
+## Shortcut Map
+
+| Key | Action |
+|-----|--------|
+| `?` | Open/close shortcut help overlay |
+| `1` | Scroll to charts row 1 (tool bar + pie) |
+| `2` | Scroll to charts row 2 (timeline) |
+| `3` | Scroll to charts row 3 (latency chart) |
+| `4` | Scroll to latency table section |
+| `a` | Scroll to audit log section |
+| `r` | Trigger reset metrics (with `confirm()` dialog) |
+| `e` | Trigger JSON export download |
+| `Escape` | Close shortcut help overlay (if open) |
+
+## Section IDs to Add
+
+- `id="section-charts-1"` on first `.charts-row` (tool bar + pie)
+- `id="section-charts-2"` on second `.charts-row` (timeline)
+- `id="section-charts-3"` on third `.charts-row` (latency chart)
+- `id="section-latency-table"` on latency `.table-section`
+- `id="section-audit-log"` on audit `.table-section`
+
+## Acceptance Criteria
+
+- [ ] `?` key opens/closes shortcut help overlay
+- [ ] Number keys `1-4` scroll to corresponding chart section
+- [ ] `a` key scrolls to audit log section
+- [ ] `r` key triggers reset metrics with confirmation dialog
+- [ ] `e` key triggers JSON export download
+- [ ] Shortcuts are disabled when focus is in an input field (audit filter, session gap input)
+- [ ] Help overlay lists all available shortcuts with descriptions
+- [ ] `Escape` closes the help overlay
+
+## Dependencies
+
+- P10-T1 ✅ (Web UI dashboard with charts and audit log in place)
+
+## Quality Gates
+
+- `pytest` — all tests pass (no Python logic changes; existing tests must still pass)
+- `ruff check src/` — no linting errors
+- `pytest --cov` — coverage ≥ 90%
diff --git a/SPECS/ARCHIVE/P11-T4_Add_Keyboard_Shortcuts_Command_Palette/P11-T4_Validation_Report.md b/SPECS/ARCHIVE/P11-T4_Add_Keyboard_Shortcuts_Command_Palette/P11-T4_Validation_Report.md
new file mode 100644
index 00000000..125a8324
--- /dev/null
+++ b/SPECS/ARCHIVE/P11-T4_Add_Keyboard_Shortcuts_Command_Palette/P11-T4_Validation_Report.md
@@ -0,0 +1,61 @@
+# Validation Report: P11-T4 — Add Keyboard Shortcuts & Command Palette
+
+## Date: 2026-02-15
+
+## Summary
+
+Implemented keyboard shortcuts and a help overlay for the XcodeMCPWrapper dashboard. Pure JS implementation with no external libraries.
+
+## Changes Made
+
+### `src/mcpbridge_wrapper/webui/static/index.html`
+- Added `id="section-charts-1"` to first charts row (tool bar + pie)
+- Added `id="section-charts-2"` to second charts row (timeline)
+- Added `id="section-charts-3"` to third charts row (latency chart)
+- Added `id="section-latency-table"` to latency table section
+- Added `id="section-audit-log"` to audit log section
+- Added `
` modal with shortcut table and close button
+
+### `src/mcpbridge_wrapper/webui/static/dashboard.css`
+- Added `.shortcut-overlay` and `.shortcut-overlay.hidden` for modal backdrop
+- Added `.shortcut-modal` for modal container
+- Added `.shortcut-modal-header` for header with close button
+- Added `.shortcut-table` for shortcuts table styling
+- Added `kbd` element styling for key display
+
+### `src/mcpbridge_wrapper/webui/static/dashboard.js`
+- Added `initKeyboardShortcuts()` function registered in `init()`
+- `keydown` event listener with shortcut map:
+ - `?` — toggle help overlay
+ - `1` — scroll to section-charts-1
+ - `2` — scroll to section-charts-2
+ - `3` — scroll to section-charts-3
+ - `4` — scroll to section-latency-table
+ - `a` — scroll to section-audit-log
+ - `r` — reset metrics (with confirm dialog)
+ - `e` — export JSON
+ - `Escape` — close help overlay
+- Guard: shortcuts skipped when `activeElement` is INPUT, TEXTAREA, or SELECT
+- Close on backdrop click (clicking outside modal)
+- Close button wired to `hideOverlay()`
+
+## Acceptance Criteria
+
+- [x] `?` key opens/closes shortcut help overlay
+- [x] Number keys `1-4` scroll to corresponding chart section
+- [x] `a` key scrolls to audit log section
+- [x] `r` key triggers reset metrics with confirmation dialog
+- [x] `e` key triggers JSON export download
+- [x] Shortcuts are disabled when focus is in an input field (audit filter, session gap input)
+- [x] Help overlay lists all available shortcuts with descriptions
+- [x] `Escape` closes the help overlay
+
+## Quality Gates
+
+| Gate | Result |
+|------|--------|
+| `pytest` | ✅ 403 passed, 5 skipped |
+| `ruff check src/` | ✅ All checks passed |
+| `pytest --cov` | ✅ 96.2% (≥ 90% required) |
+
+## Verdict: PASS
diff --git a/SPECS/ARCHIVE/P11-T4_Add_Keyboard_Shortcuts_Command_Palette/REVIEW_P11-T4_keyboard_shortcuts.md b/SPECS/ARCHIVE/P11-T4_Add_Keyboard_Shortcuts_Command_Palette/REVIEW_P11-T4_keyboard_shortcuts.md
new file mode 100644
index 00000000..55f8526a
--- /dev/null
+++ b/SPECS/ARCHIVE/P11-T4_Add_Keyboard_Shortcuts_Command_Palette/REVIEW_P11-T4_keyboard_shortcuts.md
@@ -0,0 +1,38 @@
+## REVIEW REPORT — P11-T4 keyboard shortcuts
+
+**Scope:** origin/main..HEAD
+**Files:** 3 (dashboard.js, dashboard.css, index.html)
+
+### Summary Verdict
+- [ ] Approve
+- [x] Approve with comments
+- [ ] Request changes
+- [ ] Block
+
+### Critical Issues
+
+None.
+
+### Secondary Issues
+
+- [Nit] `showOverlay()` is declared in `initKeyboardShortcuts()` but never called. Only `toggleOverlay()` and `hideOverlay()` are used externally. The function is dead code. Either remove it or document it as a future extension point.
+
+### Architectural Notes
+
+- The implementation is pure JS with no library dependencies, consistent with the rest of the codebase. This is the correct approach for this scale.
+- The `isInputFocused()` guard checks `tagName` against `INPUT | TEXTAREA | SELECT`. This correctly covers the audit filter and session gap input. If a `contenteditable` element is ever added to the dashboard, the guard would need updating — not a concern for current scope.
+- Keyboard shortcuts duplicate the confirmation logic from `btn-reset-metrics` click handler. This is intentional and acceptable since they are in separate contexts; extracting a shared helper would be over-engineering for two call sites.
+- The overlay is placed outside `
` but inside ``, which is correct for a fixed-position modal backdrop.
+- ARIA attributes (`role="dialog"`, `aria-modal="true"`, `aria-label`) are present on the overlay for accessibility. Focus management (trap focus inside modal while open) is not implemented — acceptable for this priority/scope.
+
+### Tests
+
+- No Python tests were changed or added. The task is pure frontend (JS/HTML/CSS).
+- All 403 existing Python tests pass.
+- Coverage: 96.2% (well above the 90% threshold).
+- No JS unit tests exist in the project — consistent with how other frontend features (theme toggle, timeline) were delivered.
+
+### Next Steps
+
+- [Optional] Remove the dead `showOverlay()` function, or repurpose it if a "programmatic open" shortcut is ever needed.
+- No follow-up tasks required.
diff --git a/SPECS/COMMANDS/ARCHIVE.md b/SPECS/COMMANDS/ARCHIVE.md
index 229670de..c34d5195 100644
--- a/SPECS/COMMANDS/ARCHIVE.md
+++ b/SPECS/COMMANDS/ARCHIVE.md
@@ -38,7 +38,7 @@ Scan for completed tasks and archive them from `SPECS/INPROGRESS/` to `SPECS/ARC
4. **For non-task artifacts** (code reviews, reports):
```bash
scripts/archive_primitive.sh ensure-historical
- mv "SPECS/INPROGRESS/{artifact}.md" "SPECS/ARCHIVE/_Historical/"
+ git mv "SPECS/INPROGRESS/{artifact}.md" "SPECS/ARCHIVE/_Historical/"
```
- Add entry to Historical Artifacts table in INDEX.md
diff --git a/SPECS/COMMANDS/FLOW.md b/SPECS/COMMANDS/FLOW.md
index f9d90dd0..37584cd6 100644
--- a/SPECS/COMMANDS/FLOW.md
+++ b/SPECS/COMMANDS/FLOW.md
@@ -147,7 +147,7 @@ Follow-up {TASK_ID}: {short subject}
Archive the REVIEW artifact after FOLLOW-UP is complete.
**Actions:**
-- Move `REVIEW_{subject}.md` to `SPECS/ARCHIVE/_Historical/` (or the relevant task folder)
+- Move `REVIEW_{subject}.md` to `SPECS/ARCHIVE/_Historical/` (or the relevant task folder) using `git mv` so the deletion from `SPECS/INPROGRESS/` is staged automatically
- Update `SPECS/ARCHIVE/INDEX.md`
**Commit via [`COMMIT`](PRIMITIVES/COMMIT.md):**
diff --git a/SPECS/COMMANDS/PRIMITIVES/ARCHIVE_TASK.md b/SPECS/COMMANDS/PRIMITIVES/ARCHIVE_TASK.md
index f15a4d6d..6b0873fc 100644
--- a/SPECS/COMMANDS/PRIMITIVES/ARCHIVE_TASK.md
+++ b/SPECS/COMMANDS/PRIMITIVES/ARCHIVE_TASK.md
@@ -22,18 +22,18 @@ description: "Use when a task is complete and you need to move its PRD artifacts
# 1. Create task subfolder
scripts/archive_primitive.sh prepare-task "${TASK_ID}" "${TASK_NAME}" >/dev/null
-# 2. Move PRD file
-mv "SPECS/INPROGRESS/${TASK_ID}_${TASK_NAME}.md" \
- "SPECS/ARCHIVE/${TASK_ID}_${TASK_NAME}/"
+# 2. Move PRD file (git mv stages both deletion and addition)
+git mv "SPECS/INPROGRESS/${TASK_ID}_${TASK_NAME}.md" \
+ "SPECS/ARCHIVE/${TASK_ID}_${TASK_NAME}/"
# 3. Move validation report (if exists)
[ -f "SPECS/INPROGRESS/${TASK_ID}_Validation_Report.md" ] && \
-mv "SPECS/INPROGRESS/${TASK_ID}_Validation_Report.md" \
- "SPECS/ARCHIVE/${TASK_ID}_${TASK_NAME}/"
+git mv "SPECS/INPROGRESS/${TASK_ID}_Validation_Report.md" \
+ "SPECS/ARCHIVE/${TASK_ID}_${TASK_NAME}/"
# 4. Move any other task artifacts matching TASK_ID prefix
for f in SPECS/INPROGRESS/${TASK_ID}_*.md; do
- [ -f "$f" ] && mv "$f" "SPECS/ARCHIVE/${TASK_ID}_${TASK_NAME}/"
+ [ -f "$f" ] && git mv "$f" "SPECS/ARCHIVE/${TASK_ID}_${TASK_NAME}/"
done
# 5. Append archive metadata to PRD
diff --git a/SPECS/INPROGRESS/next.md b/SPECS/INPROGRESS/next.md
index d09fc6be..ae31db79 100644
--- a/SPECS/INPROGRESS/next.md
+++ b/SPECS/INPROGRESS/next.md
@@ -4,14 +4,14 @@ The previously selected task has been archived.
## Recently Archived
+- 2026-02-15 — P11-T4: Add Keyboard Shortcuts & Command Palette (PASS)
- 2026-02-15 — P11-T3: Add Dashboard Theme Toggle (Dark/Light) (PASS)
- 2026-02-15 — P11-T2: Add Session Timeline View (PASS)
- 2026-02-15 — BUG-T8: Audit log cross-process visibility (PASS)
- 2026-02-15 — P11-T1: Add Tool Call Detail Inspector (Request/Response Viewer) (PASS)
-- 2026-02-15 — FU-BUG-T6-1: Document stale-process cleanup for Web UI port collisions (PASS)
## Suggested Next Tasks
-- P11-T4: Add Keyboard Shortcuts & Command Palette (P3, depends on P10-T1 ✅)
+- P12-T1: Add MCP Client Identification (P0, depends on P10-T1 ✅)
- FU-BUG-T7-1: Cap `pending_methods` map to guard against unbounded growth (P3)
- FU-P11-T1-1: Refactor `_FakeWebUIConfig` test stub to `MagicMock(spec=WebUIConfig)` (P3)
diff --git a/SPECS/Workplan.md b/SPECS/Workplan.md
index 90e98800..15bd6777 100644
--- a/SPECS/Workplan.md
+++ b/SPECS/Workplan.md
@@ -1647,7 +1647,7 @@ Phase 9 Follow-up Backlog
---
-#### P11-T4: Add Keyboard Shortcuts & Command Palette
+#### ✅ P11-T4: Add Keyboard Shortcuts & Command Palette
- **Description:** Add lightweight keyboard shortcuts for dashboard navigation. `1-4` to focus chart sections, `a` to jump to audit log, `r` to reset metrics (with confirmation), `e` to export JSON, `?` to show shortcut help overlay. Pure JS `keydown` listener with a shortcut map. Small modal overlay for `?` help. No library needed.
- **Priority:** P3
- **Dependencies:** P10-T1
@@ -1657,13 +1657,13 @@ Phase 9 Follow-up Backlog
- Updated `src/mcpbridge_wrapper/webui/static/dashboard.css` - help overlay styling
- Updated `src/mcpbridge_wrapper/webui/static/index.html` - help overlay markup
- **Acceptance Criteria:**
- - [ ] `?` key opens/closes shortcut help overlay
- - [ ] Number keys `1-4` scroll to corresponding chart section
- - [ ] `a` key scrolls to audit log section
- - [ ] `r` key triggers reset metrics with confirmation dialog
- - [ ] `e` key triggers JSON export download
- - [ ] Shortcuts are disabled when focus is in an input field (audit filter)
- - [ ] Help overlay lists all available shortcuts with descriptions
+ - [x] `?` key opens/closes shortcut help overlay
+ - [x] Number keys `1-4` scroll to corresponding chart section
+ - [x] `a` key scrolls to audit log section
+ - [x] `r` key triggers reset metrics with confirmation dialog
+ - [x] `e` key triggers JSON export download
+ - [x] Shortcuts are disabled when focus is in an input field (audit filter)
+ - [x] Help overlay lists all available shortcuts with descriptions
---
diff --git a/src/mcpbridge_wrapper/webui/static/dashboard.css b/src/mcpbridge_wrapper/webui/static/dashboard.css
index 10d34a34..ba242f52 100644
--- a/src/mcpbridge_wrapper/webui/static/dashboard.css
+++ b/src/mcpbridge_wrapper/webui/static/dashboard.css
@@ -493,3 +493,76 @@ footer {
.timeline-node-meta .latency {
color: var(--accent-blue);
}
+
+/* ── Keyboard Shortcut Help Overlay ─────────────────────────────────────── */
+
+.shortcut-overlay {
+ position: fixed;
+ inset: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(0, 0, 0, 0.55);
+ z-index: 1000;
+}
+
+.shortcut-overlay.hidden {
+ display: none;
+}
+
+.shortcut-modal {
+ background: var(--bg-card);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius);
+ padding: 24px 28px;
+ min-width: 340px;
+ max-width: 480px;
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
+}
+
+.shortcut-modal-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 16px;
+}
+
+.shortcut-modal-header h2 {
+ font-size: 1.1rem;
+ font-weight: 600;
+ color: var(--text-primary);
+ margin: 0;
+}
+
+.shortcut-table {
+ width: 100%;
+ border-collapse: collapse;
+}
+
+.shortcut-table td {
+ padding: 6px 8px;
+ color: var(--text-secondary);
+ font-size: 0.9rem;
+ border-bottom: 1px solid var(--border-color);
+}
+
+.shortcut-table tr:last-child td {
+ border-bottom: none;
+}
+
+.shortcut-table td:first-child {
+ width: 60px;
+ white-space: nowrap;
+}
+
+kbd {
+ display: inline-block;
+ padding: 2px 7px;
+ font-size: 0.8rem;
+ font-family: monospace;
+ background: var(--bg-main);
+ border: 1px solid var(--border-color);
+ border-radius: 4px;
+ color: var(--text-primary);
+ box-shadow: 0 1px 0 var(--border-color);
+}
diff --git a/src/mcpbridge_wrapper/webui/static/dashboard.js b/src/mcpbridge_wrapper/webui/static/dashboard.js
index e648a856..40dbb312 100644
--- a/src/mcpbridge_wrapper/webui/static/dashboard.js
+++ b/src/mcpbridge_wrapper/webui/static/dashboard.js
@@ -535,12 +535,102 @@
.replace(/'/g, "'");
}
+ // --- Keyboard Shortcuts ---
+ function initKeyboardShortcuts() {
+ var overlay = document.getElementById("shortcut-help-overlay");
+ var btnClose = document.getElementById("btn-close-shortcuts");
+
+ function isInputFocused() {
+ var tag = document.activeElement && document.activeElement.tagName;
+ return tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT";
+ }
+
+ function scrollToSection(id) {
+ var el = document.getElementById(id);
+ if (el) { el.scrollIntoView({ behavior: "smooth", block: "start" }); }
+ }
+
+ function toggleOverlay() {
+ if (!overlay) return;
+ overlay.classList.toggle("hidden");
+ }
+
+ function showOverlay() {
+ if (!overlay) return;
+ overlay.classList.remove("hidden");
+ }
+
+ function hideOverlay() {
+ if (!overlay) return;
+ overlay.classList.add("hidden");
+ }
+
+ document.addEventListener("keydown", function (e) {
+ // Never fire when typing in inputs
+ if (isInputFocused()) return;
+
+ switch (e.key) {
+ case "?":
+ e.preventDefault();
+ toggleOverlay();
+ break;
+ case "1":
+ e.preventDefault();
+ scrollToSection("section-charts-1");
+ break;
+ case "2":
+ e.preventDefault();
+ scrollToSection("section-charts-2");
+ break;
+ case "3":
+ e.preventDefault();
+ scrollToSection("section-charts-3");
+ break;
+ case "4":
+ e.preventDefault();
+ scrollToSection("section-latency-table");
+ break;
+ case "a":
+ e.preventDefault();
+ scrollToSection("section-audit-log");
+ break;
+ case "r":
+ e.preventDefault();
+ if (confirm("Reset all metrics?")) {
+ fetch("/api/metrics/reset", { method: "POST" })
+ .then(function () { loadAuditLogs(); })
+ .catch(function () {});
+ }
+ break;
+ case "e":
+ e.preventDefault();
+ window.location.href = "/api/audit/export/json";
+ break;
+ case "Escape":
+ hideOverlay();
+ break;
+ }
+ });
+
+ if (btnClose) {
+ btnClose.addEventListener("click", hideOverlay);
+ }
+
+ // Close overlay when clicking backdrop (outside modal)
+ if (overlay) {
+ overlay.addEventListener("click", function (e) {
+ if (e.target === overlay) { hideOverlay(); }
+ });
+ }
+ }
+
// --- Init ---
function init() {
initCharts();
initTheme();
setupThemeToggle();
setupEventHandlers();
+ initKeyboardShortcuts();
connectWebSocket();
startPolling();
loadAuditLogs();
diff --git a/src/mcpbridge_wrapper/webui/static/index.html b/src/mcpbridge_wrapper/webui/static/index.html
index cca57714..36ffce23 100644
--- a/src/mcpbridge_wrapper/webui/static/index.html
+++ b/src/mcpbridge_wrapper/webui/static/index.html
@@ -47,7 +47,7 @@ XcodeMCPWrapper Dashboard
-
+
Tool Usage (Bar)
@@ -58,14 +58,14 @@ Tool Distribution (Pie)
-
+
-
+
Latency (ms)
@@ -73,7 +73,7 @@
Latency (ms)
-
+
Per-Tool Latency Statistics
@@ -93,7 +93,7 @@ Per-Tool Latency Statistics
-