Skip to content

feat: Commands system enhancements - #396

Merged
ilyabo merged 6 commits into
mainfrom
cursor/commands-system-enhancements-ce9e
Feb 27, 2026
Merged

ilyabo merged 6 commits into
mainfrom
cursor/commands-system-enhancements-ce9e

Conversation

@ilyabo

@ilyabo ilyabo commented Feb 27, 2026 •

Copy link
Copy Markdown
Collaborator

Adds command keystroke support and a middleware pipeline, along with expanded test coverage and documentation, to enhance command system usability and extensibility.


Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features

    • Command middleware support and invocation lifecycle events (start, success, failure, error)
    • Keystroke-based command configuration and display in the palette
  • Documentation

    • Added comprehensive Commands guide and a Commands entry in the Developer Guide sidebar
  • Improvements

    • Improved command palette keyboard handling, keystroke deduplication, and visible keystroke labels
    • New UI keystroke for setting room title
  • Tests

    • Added comprehensive command/keystroke and telemetry tests

@cursor

cursor Bot commented Feb 27, 2026

Copy link
Copy Markdown

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@coderabbitai

coderabbitai Bot commented Feb 27, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@cursor[bot] has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 24 minutes and 35 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between e874e0b and 76a4827.

📒 Files selected for processing (2)
  • packages/room-store/__tests__/CommandSlice.test.ts
  • packages/room-store/src/CommandSlice.ts
📝 Walkthrough

Walkthrough

Adds keystroke-aggregated command handling, a middleware pipeline with lifecycle events and telemetry hooks, updates the command palette to use keystrokes, wires createCommandProps through room-shell, expands public exports/types, updates docs, and adds tests for the new invocation flow. (≤50 words)

Changes

Cohort / File(s) Summary
Documentation
docs/.vitepress/config.ts, docs/commands.md, docs/whats-new.md
Adds a "Commands" sidebar entry and extensive documentation for command registration, keystrokes, middleware, telemetry, and release notes.
Command System Core
packages/room-store/src/CommandSlice.ts, packages/room-store/src/index.ts, packages/room-store/__tests__/CommandSlice.test.ts
Introduces keystroke types/aggregation (getCommandKeystrokes), middleware pipeline and lifecycle events (start/success/failure/error), safe telemetry callback invocation, updated command descriptors (keystrokes + shortcut), and tests covering keystrokes, middleware order, and telemetry.
Command Palette UI
packages/room-shell/src/RoomShellCommandPalette.tsx
Replaces direct shortcut usage with centralized keystroke mapping, normalizes keyboard events, adds keystroke display and palette-toggle handling, de-duplicates keystrokes, and adds helper utilities and editable-target filtering.
Room Shell Integration
packages/room-shell/src/RoomShellSlice.ts, packages/room-shell/src/index.ts
Accepts and forwards createCommandProps (CreateCommandSliceProps) into command slice creation and assigns a UI keystroke to room.set-title.
Public Re-exports
packages/room-shell/src/index.ts, packages/room-store/src/index.ts
Adds/exports getCommandKeystrokes, CreateCommandSliceProps, RoomCommandKeystrokes, lifecycle event types, and middleware-related types to the public API surface.
SQL Editor
packages/sql-editor/src/SqlEditorSlice.tsx
Renames command UI field from shortcut to keystrokes for the "Run current query" command to align with the keystroke model.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant Palette as Command Palette
    participant Store as Command Slice
    participant Middleware as Middleware Stack
    participant Cmd as Command Execute
    participant Telemetry as Telemetry Callbacks

    User->>Palette: Press keystroke
    Palette->>Palette: normalizeKeyboardEventKeystroke()
    Palette->>Palette: check palette toggle keystroke
    Palette->>Store: lookup command via keystrokeCommandMap
    Store->>Telemetry: onCommandInvokeStart(...)
    Store->>Middleware: runCommandExecutionMiddleware(command, input, context)
    Middleware->>Cmd: invoke command.execute(input, context)
    Cmd-->>Middleware: result / throw error
    Middleware->>Store: return result or propagate error
    alt Success
        Store->>Telemetry: onCommandInvokeSuccess(..., duration)
    else Failure
        Store->>Telemetry: onCommandInvokeFailure(..., duration)
    else Error
        Store->>Telemetry: onCommandInvokeError(..., duration)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Poem

🐰
I hopped through keys both bright and neat,
Mapped every Mod and Alt and beat.
Middleware hummed, telemetry tapped,
Keystrokes lined up, commands unwrapped—
A bunny's patch where shortcuts meet.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Commands system enhancements' accurately summarizes the main change—a comprehensive enhancement to the command system with keystroke support and middleware pipeline.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cursor/commands-system-enhancements-ce9e

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ilyabo ilyabo changed the title Commands system enhancements feat: Commands system enhancements Feb 27, 2026
@ilyabo
ilyabo marked this pull request as ready for review February 27, 2026 09:58

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/commands.md`:
- Around line 62-69: The example middleware uses await inside a non-async arrow
function; change the anonymous middleware signature to an async function so
await next() is valid (e.g., make the arrow function async (command, input,
context, next) => { const result = await next(); return result; }); ensure the
symbols mentioned (next and result) remain and the function signature reflects
async to match the later example.

In `@packages/room-store/src/CommandSlice.ts`:
- Around line 389-404: The code unconditionally calls
invokeCommandSliceCallback(props?.onCommandInvokeSuccess, ...) even when
normalizeCommandExecuteResult(command.id, rawResult) yields a failure object;
change the flow in CommandSlice.ts so that after computing normalizedResult you
check normalizedResult.success (or equivalent flag) and only call
invokeCommandSliceCallback with props?.onCommandInvokeSuccess when success ===
true; when success === false, call the failure callback
(props?.onCommandInvokeFailure or the appropriate failure handler) with the same
payload (command, input, context, result, durationMs) and use
get().room.captureException for error reporting—update the branches around
normalizeCommandExecuteResult and invokeCommandSliceCallback to reflect this
conditional dispatch.
- Around line 687-694: The invokeMiddleware chain currently hands middleware a
raw async next() allowing multiple calls; wrap the next callback returned to
each middleware with a local "called" guard so calling next() more than once
throws an error (or returns a rejected promise) to prevent duplicate execution.
In practice, inside invokeMiddleware(index) capture currentMiddleware and supply
it a wrapped next that checks a boolean flag (e.g., called) and sets it before
invoking invokeMiddleware(index+1), throwing/rejecting if called is already
true; keep the existing fallback to command.execute(context, input) when no
middleware remains. This change touches invokeMiddleware, currentMiddleware,
middleware, command.execute and the next() callback passed into middleware.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a11f612 and 41cbd64.

📒 Files selected for processing (9)
  • docs/.vitepress/config.ts
  • docs/commands.md
  • packages/room-shell/src/RoomShellCommandPalette.tsx
  • packages/room-shell/src/RoomShellSlice.ts
  • packages/room-shell/src/index.ts
  • packages/room-store/__tests__/CommandSlice.test.ts
  • packages/room-store/src/CommandSlice.ts
  • packages/room-store/src/index.ts
  • packages/sql-editor/src/SqlEditorSlice.tsx

Comment thread docs/commands.md
Comment thread packages/room-store/src/CommandSlice.ts
Comment thread packages/room-store/src/CommandSlice.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/room-store/src/CommandSlice.ts (1)

364-371: Emit lifecycle callbacks for disabled-command early exits.

Disabled commands currently return before lifecycle callbacks are emitted, so these failed invocations are invisible to telemetry subscribers.

💡 Suggested adjustment
+          const invocationStartEvent: RoomCommandInvokeStartEvent<RS> = {
+            command,
+            input,
+            context: executionContext,
+          };
+          const invocationStartedAt = Date.now();
+          invokeCommandSliceCallback(
+            props?.onCommandInvokeStart,
+            invocationStartEvent,
+            get().room.captureException,
+          );
+
           if (!resolveCommandEnabled(command, executionContext)) {
-            return {
+            const disabledResult: RoomCommandResult = {
               success: false,
               commandId: command.id,
               code: 'command-disabled',
               error: `Command "${command.name}" is currently disabled.`,
             };
+            invokeCommandSliceCallback(
+              props?.onCommandInvokeFailure,
+              {
+                ...invocationStartEvent,
+                result: disabledResult,
+                durationMs: Date.now() - invocationStartedAt,
+              },
+              get().room.captureException,
+            );
+            return disabledResult;
           }
-
-          const invocationStartEvent: RoomCommandInvokeStartEvent<RS> = {
-            command,
-            input,
-            context: executionContext,
-          };
-          const invocationStartedAt = Date.now();
-          invokeCommandSliceCallback(
-            props?.onCommandInvokeStart,
-            invocationStartEvent,
-            get().room.captureException,
-          );

Also applies to: 373-383

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/room-store/src/CommandSlice.ts` around lines 364 - 371, The
early-return when resolveCommandEnabled(command, executionContext) is false
should still fire the same lifecycle callbacks as other failure paths: before
returning the { success: false, commandId: command.id, code: 'command-disabled',
... } result, invoke the lifecycle/telemetry emission used elsewhere in this
file for failed invocations (the same pattern used in the other early-exit
branches around lines 373-383) and pass the command id, name, executionContext
and the error payload (code 'command-disabled' and the message) so telemetry
subscribers receive the disabled-command event.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/room-store/src/CommandSlice.ts`:
- Around line 594-601: The loop over keystrokes currently calls keystroke.trim()
assuming every element is a string; guard against malformed/non-string elements
by checking typeof keystroke === 'string' before calling trim (or use
String(keystroke).trim() if you want to coerce), skip empty results, and then
add the normalized value to deduplicated; apply the same defensive change to the
other identical block that operates on keystrokes (the block referenced around
symbols keystroke, keystrokes, deduplicated).

---

Nitpick comments:
In `@packages/room-store/src/CommandSlice.ts`:
- Around line 364-371: The early-return when resolveCommandEnabled(command,
executionContext) is false should still fire the same lifecycle callbacks as
other failure paths: before returning the { success: false, commandId:
command.id, code: 'command-disabled', ... } result, invoke the
lifecycle/telemetry emission used elsewhere in this file for failed invocations
(the same pattern used in the other early-exit branches around lines 373-383)
and pass the command id, name, executionContext and the error payload (code
'command-disabled' and the message) so telemetry subscribers receive the
disabled-command event.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 41cbd64 and 9d9f112.

📒 Files selected for processing (5)
  • docs/commands.md
  • packages/room-shell/src/index.ts
  • packages/room-store/__tests__/CommandSlice.test.ts
  • packages/room-store/src/CommandSlice.ts
  • packages/room-store/src/index.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/room-store/tests/CommandSlice.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/commands.md

Comment thread packages/room-store/src/CommandSlice.ts
@ilyabo
ilyabo merged commit 4585f80 into main Feb 27, 2026
3 checks passed
@ilyabo
ilyabo deleted the cursor/commands-system-enhancements-ce9e branch February 27, 2026 15:24
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.

2 participants