Conversation
- Probe Codex skills and Claude slash commands during provider checks - Surface discovered items in server snapshots and composer UI
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Ref assignments moved to useEffect cause stale reads
- Moved the three ref assignments (composerMenuOpenRef, composerMenuItemsRef, activeComposerMenuItemRef) back to synchronous render phase by removing the useEffect wrapper, ensuring event handlers always read current values.
- ✅ Fixed: Exported
probeCodexAccountfunction is now unused- Removed the dead probeCodexAccount function from codexAppServer.ts since it has no remaining imports anywhere in the codebase.
Or push these changes by commenting:
@cursor push 2d23dae3cc
Preview (2d23dae3cc)
diff --git a/apps/server/src/provider/codexAppServer.ts b/apps/server/src/provider/codexAppServer.ts
--- a/apps/server/src/provider/codexAppServer.ts
+++ b/apps/server/src/provider/codexAppServer.ts
@@ -244,16 +244,3 @@
});
});
}
-
-export async function probeCodexAccount(input: {
- readonly binaryPath: string;
- readonly homePath?: string;
- readonly signal?: AbortSignal;
-}): Promise<CodexAccountSnapshot> {
- return (
- await probeCodexDiscovery({
- ...input,
- cwd: process.cwd(),
- })
- ).account;
-}
diff --git a/apps/web/src/components/chat/ChatComposer.tsx b/apps/web/src/components/chat/ChatComposer.tsx
--- a/apps/web/src/components/chat/ChatComposer.tsx
+++ b/apps/web/src/components/chat/ChatComposer.tsx
@@ -820,11 +820,9 @@
[composerHighlightedItemId, composerMenuItems],
);
- useEffect(() => {
- composerMenuOpenRef.current = composerMenuOpen;
- composerMenuItemsRef.current = composerMenuItems;
- activeComposerMenuItemRef.current = activeComposerMenuItem;
- }, [activeComposerMenuItem, composerMenuItems, composerMenuOpen]);
+ composerMenuOpenRef.current = composerMenuOpen;
+ composerMenuItemsRef.current = composerMenuItems;
+ activeComposerMenuItemRef.current = activeComposerMenuItem;
const nonPersistedComposerImageIdSet = useMemo(
() => new Set(nonPersistedComposerImageIds),You can send follow-ups to the cloud agent here.
ApprovabilityVerdict: Needs human review This PR introduces a significant new feature: provider skill and slash command discovery. It adds new user-facing capabilities including skill autocomplete via $ syntax, skill pills in the composer, provider slash commands in the command menu, and supporting search/ranking infrastructure. New features of this scope warrant human review to validate the design and integration. You can customize Macroscope's approvability policy. Learn more. |
- Map provider slash command hints into the shared contract - Surface provider command metadata in the chat composer
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: skills/list failure rejects entire account probe
- Changed the skills/list error handler to gracefully fall back to an empty skills array instead of calling fail(), so account probing remains resilient when skills/list is unsupported or errors.
Or push these changes by commenting:
@cursor push 26dfbbe0ac
Preview (26dfbbe0ac)
diff --git a/apps/server/src/provider/codexAppServer.ts b/apps/server/src/provider/codexAppServer.ts
--- a/apps/server/src/provider/codexAppServer.ts
+++ b/apps/server/src/provider/codexAppServer.ts
@@ -205,12 +205,7 @@
if (response.id === 2) {
const errorMessage = readErrorMessage(response);
- if (errorMessage) {
- fail(new Error(`skills/list failed: ${errorMessage}`));
- return;
- }
-
- skills = parseCodexSkillsResult(response.result, input.cwd);
+ skills = errorMessage ? [] : parseCodexSkillsResult(response.result, input.cwd);
maybeResolve();
return;
}You can send follow-ups to the cloud agent here.
…tire probe When skills/list returns an error (e.g. on older Codex CLI versions that don't support it), fall back to an empty skills array instead of calling fail() which would reject the entire discovery promise and break account probing.
Co-authored-by: codex <codex@users.noreply.github.com>
- Restore serialized composer skill node state - Sync skill labels before paint to avoid stale UI - Keep composer menu refs current during render
…tire probe When skills/list returns an error (e.g. on older Codex CLI versions that don't support it), fall back to an empty skills array instead of calling fail() which would reject the entire discovery promise and break account probing. Applied via @cursor push command
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Inconsistent field lookup for
displayNamevsshortDescription- Updated
displayNamelookup to checkskill?.displayNamefirst, falling back todisplay?.displayName, matching the same pattern used forshortDescription.
- Updated
Or push these changes by commenting:
@cursor push 6b028d659a
Preview (6b028d659a)
diff --git a/apps/server/src/provider/codexAppServer.ts b/apps/server/src/provider/codexAppServer.ts
--- a/apps/server/src/provider/codexAppServer.ts
+++ b/apps/server/src/provider/codexAppServer.ts
@@ -64,8 +64,11 @@
? { description: nonEmptyTrimmed(skill?.description) }
: {}),
...(nonEmptyTrimmed(skill?.scope) ? { scope: nonEmptyTrimmed(skill?.scope) } : {}),
- ...(nonEmptyTrimmed(display?.displayName)
- ? { displayName: nonEmptyTrimmed(display?.displayName) }
+ ...(nonEmptyTrimmed(skill?.displayName) || nonEmptyTrimmed(display?.displayName)
+ ? {
+ displayName:
+ nonEmptyTrimmed(skill?.displayName) ?? nonEmptyTrimmed(display?.displayName),
+ }
: {}),
...(nonEmptyTrimmed(skill?.shortDescription) || nonEmptyTrimmed(display?.shortDescription)
? {You can send follow-ups to the cloud agent here.
- Introduced a new scoring mechanism for workspace entries that prioritizes exact basename matches over broader path matches. - Updated the search logic to utilize shared ranking functions for improved performance and maintainability. - Added a test case to validate the new ranking behavior for exact matches in workspace entries. - Removed deprecated functions related to scoring and ranking to streamline the codebase.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Callback recreated on every keystroke causing unnecessary re-renders
- Replaced the
promptstate variable withpromptRef.currentin thesetPromptFromTraitscallback and removedpromptfrom the dependency array, restoring the stable ref-based pattern that prevents callback recreation on every keystroke.
- Replaced the
Or push these changes by commenting:
@cursor push aadef2980e
Preview (aadef2980e)
diff --git a/apps/web/src/components/chat/ChatComposer.tsx b/apps/web/src/components/chat/ChatComposer.tsx
--- a/apps/web/src/components/chat/ChatComposer.tsx
+++ b/apps/web/src/components/chat/ChatComposer.tsx
@@ -868,7 +868,8 @@
// ------------------------------------------------------------------
const setPromptFromTraits = useCallback(
(nextPrompt: string) => {
- if (nextPrompt === prompt) {
+ const currentPrompt = promptRef.current;
+ if (nextPrompt === currentPrompt) {
scheduleComposerFocus();
return;
}
@@ -879,7 +880,7 @@
setComposerTrigger(detectComposerTrigger(nextPrompt, nextPrompt.length));
scheduleComposerFocus();
},
- [composerDraftTarget, prompt, promptRef, scheduleComposerFocus, setComposerDraftPrompt],
+ [composerDraftTarget, promptRef, scheduleComposerFocus, setComposerDraftPrompt],
);
const providerTraitsMenuContent = renderProviderTraitsMenuContent({You can send follow-ups to the cloud agent here.
Co-authored-by: codex <codex@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Double-lowercasing in shared scoring utility is redundant
- Removed the redundant
.trim().toLowerCase()calls insidescoreQueryMatchsince all callers already pass pre-normalized inputs, replacing them with a direct destructure and a JSDoc contract documenting the pre-normalization requirement.
- Removed the redundant
Or push these changes by commenting:
@cursor push 20f5a4b15c
Preview (20f5a4b15c)
diff --git a/packages/shared/src/searchRanking.ts b/packages/shared/src/searchRanking.ts
--- a/packages/shared/src/searchRanking.ts
+++ b/packages/shared/src/searchRanking.ts
@@ -77,6 +77,12 @@
return bestIndex;
}
+/**
+ * Scores how well `value` matches `query` using tiered match strategies.
+ *
+ * **Expects pre-normalized inputs**: both `value` and `query` must already be
+ * trimmed and lowercased (e.g. via {@link normalizeSearchQuery}).
+ */
export function scoreQueryMatch(input: {
value: string;
query: string;
@@ -87,8 +93,7 @@
fuzzyBase?: number;
boundaryMarkers?: readonly string[];
}): number | null {
- const value = input.value.trim().toLowerCase();
- const query = input.query.trim().toLowerCase();
+ const { value, query } = input;
if (!value || !query) {
return null;You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit b0488e2. Configure here.
All callers already pass pre-normalized (trimmed and lowercased) inputs, so the internal .trim().toLowerCase() calls were redundant O(n) string operations allocating unnecessary copies on every candidate per keystroke. Replace with a destructured read and a JSDoc contract stating that inputs must be pre-normalized.
Co-authored-by: codex <codex@users.noreply.github.com>
All callers already pass pre-normalized (trimmed and lowercased) inputs, so the internal .trim().toLowerCase() calls were redundant O(n) string operations allocating unnecessary copies on every candidate per keystroke. Replace with a destructured read and a JSDoc contract stating that inputs must be pre-normalized. Applied via @cursor push command


Summary
ServiceMap/makeUnsafepatterns for consistency.Testing
bun fmt,bun lint,bun typecheck, andbun run testNote
Medium Risk
Extends the
ServerProvidercontract and provider health/probing flows to carry new capability metadata, and updates chat composer parsing/rendering and menu ranking logic; regressions could affect provider snapshots or composer input behavior across clients.Overview
Provider snapshots now include capability metadata:
ServerProvidergainsslashCommandsandskillsarrays (with decoding defaults for backward compatibility), andbuildServerProviderpopulates them.Server-side probing is extended to fill these fields: Claude’s SDK init probe now collects and dedupes slash commands (and caches the combined probe), while Codex switches from account-only probing to
probeCodexDiscoveryvia the app-server JSON-RPC to return both account info and per-CWD skills.The web composer UI now surfaces provider capabilities: it adds
$skilltoken detection/rendering (LexicalComposerSkillNodechips with tooltip descriptions), expands slash-command completion to include provider commands, adds skill search/completion, and refactors menu highlighting + ranking using a new sharedsearchRankingutility (also reused for workspace entry ranking). Tests and fixtures are updated accordingly.Reviewed by Cursor Bugbot for commit 016dbfd. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add provider skill discovery and skill/slash-command support in the composer
ServerProviderSkillandServerProviderSlashCommandschemas to the contracts layer; both default to empty arrays when decoding legacy snapshots.probeCodexDiscoveryAPI to return discovered skills alongside account info, and parses Claude Agent SDK initialization commands into normalized slash commands.ComposerSkillNodeLexical node that renders inline skill chips with tooltips, and extendssplitPromptTextIntoComposerSegmentsto parse$<name>tokens asskillsegments./<command>and$<skill>insertion on selection.searchRankingpackage (scoreQueryMatch,insertRankedSearchResult, etc.) used by workspace entry search, skill search, and slash command search.ComposerPromptEditornow requires askillsprop; any caller that does not pass it will get a type error.Macroscope summarized 016dbfd.