Skip to content

feat(web): add slash command for quick access to Skills/Projects/Agents - #104

Merged
AruNi-01 merged 3 commits into
mainfrom
atmos/issue-102-zapdos
May 11, 2026
Merged

AruNi-01 merged 3 commits into
mainfrom
atmos/issue-102-zapdos

Conversation

@AruNi-01

@AruNi-01 AruNi-01 commented May 10, 2026 •

Copy link
Copy Markdown
Owner

Summary

Add / command support in WelcomePage PromptComposer to quickly access Skills, Projects, and Code Agents. Users can now type / in the composer input to see a searchable dropdown with:

  • Skills: Filterable list of available skills with scope badges (Global/Project)
  • Projects: Filterable list of projects
  • Code Agents: Filterable list of available code agents

Additionally, color-coded chips in the input editor for visual distinction:

  • GitHub PR/Issue: muted background
  • File mentions: blue background
  • Skill mentions: yellow background

The slash popover supports keyboard navigation (Arrow Up/Down, Enter) and "Show more" functionality for sections with more than 3 items.

Related Issue

Closes #102

Type of Change

  • New feature

Validation

  • just lint
  • just test
  • just fmt
  • TypeScript typecheck (bun typecheck)

Checklist

  • I updated documentation if behavior changed
  • I added/updated tests where appropriate
  • I followed repository conventions and AGENTS.md guidance

Generated with Devin


Summary by cubic

Adds a “/” quick command in the Welcome page composer for fast access to Skills, Projects, and Code Agents, with a searchable, keyboard-friendly popover. Implements the quick-access workflow requested in Linear #102.

  • New Features

    • “/” opens a searchable popover with Skills (Global/Project badges), Projects, and Code Agents; supports Arrow Up/Down, Enter, and “Show more”.
    • Adds color-coded chips in the editor: PR/Issue (muted), Files (blue), Skills (yellow with puzzle icon). Introduces /skill: token support.
  • Bug Fixes

    • Slash popover now closes after selecting a project or agent; Esc cancels.
    • Correctly replaces the active / or @ token by using caret-scoped offsets, preventing wrong-segment replacements when duplicate queries exist.
    • Settings: move “Shortcuts” above “About”.

Written for commit 4501f96. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Slash-command support to insert skills and select projects/code agents from the editor
    • Interactive slash popover with keyboard navigation and expandable sections for discovery
  • Updates

    • Reordered Settings sidebar menu sections (shortcuts now before about)
  • Documentation

    • Added guideline: ask users when requirements are uncertain rather than assuming

Review Change Stack

AruNi-01 and others added 2 commits May 11, 2026 00:37
- Add `/` command in WelcomePage PromptComposer to quickly access Skills, Projects, and Code Agents
- Add color-coded chips in input: GitHub PR/Issue (muted), files (blue), skills (yellow)
- Fix slash popover not closing after agent/project selection
- Adjust Settings sections order (Shortcuts before About)
- Add puzzle.svg icon for skill chips

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Replace incorrect puzzle icon with the correct Lucide puzzle icon shape.
Convert from stroke-based to fill-based for CSS mask compatibility.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@vercel

vercel Bot commented May 10, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
atmos-landing Ready Ready Preview, Comment May 11, 2026 3:35am

@coderabbitai

coderabbitai Bot commented May 10, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: eae51d68-c68e-4006-a0e1-883643041bce

📥 Commits

Reviewing files that changed from the base of the PR and between 64a10a0 and 4501f96.

📒 Files selected for processing (1)
  • apps/web/src/components/welcome/PromptComposer.tsx

📝 Walkthrough

Walkthrough

This PR adds a "/" command to the workspace composer: PromptComposer gains slash contracts, token parsing/serialization and caret-range helpers, and WelcomePage implements a Fuse-searchable slash popover (Skills, Projects, Code Agents) with keyboard navigation and selection wiring back into the composer.

Changes

Slash Command for Skills, Projects, and Code Agents

Layer / File(s) Summary
Exported Type & Callback Contracts
apps/web/src/components/welcome/PromptComposer.tsx
MentionRef extended with a skill variant; new SlashTriggerContext exported (caretRect, query, slashOffset); ComposerHandle adds applySlashAtRange(); ComposerCallbacks adds onSlashTrigger/onSlashCancel.
Token Serialization & Rendering
apps/web/src/components/welcome/PromptComposer.tsx
TOKEN_REGEX extended to recognize /skill:<absolutePath>; buildChipNode renders skill chips with mask icon and yellow styling; serializeRange and readSlashContextFromSelection compute slashOffset and query.
PromptComposer Implementation
apps/web/src/components/welcome/PromptComposer.tsx
insertMention and applyMentionAtRange updated to emit /skill:<absolutePath> tokens for skills and correct file tokens; new applySlashAtRange replaces the /<query> slice with the resolved mention and advances caret.
PromptComposer Input & Keyboard Events
apps/web/src/components/welcome/PromptComposer.tsx
handleKeyDown measures caret and dispatches onSlashTrigger on /; Escape cancels slash and at suggestions; handleInput reads slash context and triggers/cancels accordingly.
WelcomePage State & Dependencies Setup
apps/web/src/components/welcome/WelcomePage.tsx
Adds Puzzle icon and imports skillsApi/skill types; initializes slashPopover, debounced query, expansion toggles, skills state, and keyboard navigation refs.
Skills Loading & Initialization
apps/web/src/components/welcome/WelcomePage.tsx
Mount effect loads global and project-scoped skills via skillsApi.list, filters by scope, and stores them in state with error handling.
Search & Filtering Infrastructure
apps/web/src/components/welcome/WelcomePage.tsx
Debounced 300ms slash query effect; builds Fuse indexes for skills and projects; computes availableAgents/filteredAgents; filters results by query.
Selection Callbacks & Item Composition
apps/web/src/components/welcome/WelcomePage.tsx
Skill/project/agent selection handlers apply composer changes or switch context; visibleSlashItems composes three sections with per-section "show more" entries and active-index management.
PromptComposer Callback Wiring
apps/web/src/components/welcome/WelcomePage.tsx
Wires onSlashTrigger to set slashPopover (caretRect, slashOffset, query) and onSlashCancel to clear popover and expansion toggles.
Slash Popover Portal UI
apps/web/src/components/welcome/WelcomePage.tsx
Portal renders grouped selectable lists for Skills/Projects/Code Agents with loading/empty states, per-section "show more", "Hidden" counts row, and keyboard-scrollable item refs.
Supporting Documentation & Config
AGENTS.md, apps/web/src/components/dialogs/SettingsModal.tsx
Adds behavioral guideline requiring the agent to ask users when requirements are uncertain; reorders settings sidebar entries so shortcuts appears before about.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant PromptComposer
  participant WelcomePage
  participant skillsApi
  participant Editor

  User->>PromptComposer: press "/" key
  PromptComposer->>PromptComposer: readSlashContextFromSelection -> SlashTriggerContext(caretRect, query, slashOffset)
  PromptComposer->>WelcomePage: onSlashTrigger(SlashTriggerContext)
  WelcomePage->>skillsApi: list() / Fuse search (on query)
  skillsApi-->>WelcomePage: skills list
  WelcomePage->>WelcomePage: filter via Fuse -> visibleSlashItems
  User->>WelcomePage: navigate/select item (Enter)
  WelcomePage->>PromptComposer: applySlashAtRange(slashOffset, queryLength, mention)
  PromptComposer->>Editor: replace /query with /skill:<path> token and move caret
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • AruNi-01/atmos#48: Modifies SettingsModal.tsx and SETTINGS_SECTIONS; overlaps with the sidebar ordering change here.

Poem

A rabbit hops and types a slash,
Skills, projects, agents in a flash 🐰✨
Fuse finds matches, arrows guide the way,
Enter inserts chips — the composer saves the day,
Caret leaps forward, the quick workflow stays brash.

🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature added: slash command support for quick access to Skills, Projects, and Agents in the web interface.
Linked Issues check ✅ Passed The PR implements all coding requirements from issue #102: slash command with Skills/Projects/Agents sections, keyboard navigation, filtering, color-coded chips, and existing framework reuse.
Out of Scope Changes check ✅ Passed AGENTS.md guideline addition and SettingsModal section reordering are minor supporting changes; all modifications directly support the slash command feature and issue #102.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch atmos/issue-102-zapdos

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.

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/web/src/components/welcome/PromptComposer.tsx">

<violation number="1" location="apps/web/src/components/welcome/PromptComposer.tsx:358">
P2: `readSlashContextFromSelection` can compute `slashOffset` for the wrong occurrence when the same `/<query>` exists later in the text, causing `applySlashAtRange` to replace the wrong segment.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread apps/web/src/components/welcome/PromptComposer.tsx 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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/components/welcome/WelcomePage.tsx (1)

150-157: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

/skill: chips are never resolved before submission.

resolvePromptPlaceholders does not map /skill:<absolutePath> to its path, so the backend receives the token string instead of the intended skill path.

Suggested fix
 function resolvePromptPlaceholders(text: string, atts: ComposerAttachment[]): string {
   return text
     .replace(/@(?:issue|pr)#\d+/g, () => ".atmos/context/requirement.md")
     .replace(/@file:([^\s]+)/g, (_match, relativePath: string) => relativePath)
+    .replace(/\/skill:([^\s]+)/g, (_match, absolutePath: string) => absolutePath)
     .replace(/\[`#img-`(\d+)\]/g, (match, n: string) => {
       const att = atts.find((a) => a.number === Number(n));
       return att ? `.atmos/attachments/${att.filename}` : match;
     });
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/welcome/WelcomePage.tsx` around lines 150 - 157, The
resolvePromptPlaceholders function currently leaves /skill:<absolutePath> tokens
untouched; add a replacement step in resolvePromptPlaceholders (alongside the
existing .replace chains) that matches /skill:([^\s]+) and returns the captured
path (the first capture group) so the token is replaced with the actual skill
path before submission; reference resolvePromptPlaceholders to locate where to
insert the .replace and ensure the regex is global and returns the captured path
string.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/components/welcome/PromptComposer.tsx`:
- Around line 122-123: The span.className mutation currently appends hardcoded
blue classes ("border-blue-500/30 bg-blue-500/10 text-blue-600
dark:text-blue-400") (and the similar hardcoded yellow/blue classes around lines
~137-138) which breaks theme adaptation; replace those literal color utility
classes with semantic theme tokens (e.g. use border-border, bg-background or a
semantic chip/bg and text-primary/text-muted-foreground with appropriate opacity
tokens) so chips use the app's CSS variables; update the span.className
concatenation and any other places (search for the other hardcoded class usage
near where iconProps is created and the lines flagged) to use those semantic
class names instead of hardcoded palette classes.
- Around line 348-353: The slash trigger currently matches any "/" in
beforeDomText (domAtIndex = lastIndexOf("/")) and aborts if any space exists in
the remainder, which both picks up URLs/paths and forbids commands with args
(e.g., "/project my-app"). Change the parsing in PromptComposer.tsx so you find
a "/" that is either at the start or preceded by whitespace (check
charAt(domAtIndex - 1) or use a regex like /(^|\s)\/.../), then allow spaces
after the slash by extracting the command token only (e.g., let raw =
beforeDomText.slice(domAtIndex + 1); let command = raw.split(/\s/)[0]) instead
of returning null on /\s/. Use these variables (domAtIndex, beforeDomText,
query/raw/command) to implement the stricter trigger detection and permissive
argument handling.

In `@apps/web/src/components/welcome/WelcomePage.tsx`:
- Around line 847-857: The selectSlashProject callback closes the popover and
sets the project but doesn't remove the typed "/<query>" from the
PromptComposer; update selectSlashProject to also call the PromptComposer's
clearSlashAtRange handler (via the composer ref) after closing the popover and
before/after setProjectId so the slash fragment is consumed, making sure to
null-check the composer ref/handler; apply the same change to the analogous
selectSlashAgent handler so both actions clear the slash text from the composer
input.
- Around line 715-727: The current filtering uses the raw debouncedSlashQuery
for every section (see filteredSkills, filteredProjects and the similar
filteredAgents block) and doesn't support subcommand scopes like "/skills" or
"/project"; update the logic to parse the debouncedSlashQuery for a scope prefix
(e.g., detect "/skills", "/project" or "/agent"), strip that prefix to produce
the actual search term, and then: for each memoized filter (filteredSkills,
filteredProjects, filteredAgents) only run the Fuse search when the scope is
either "all" or matches that section; otherwise return the original unfiltered
array (or an empty array if you prefer hiding non-target sections). Also ensure
the UI rendering respects scope !== "all" by showing only the targeted section
when a scope is present.
- Around line 879-881: The explicit any on the slash nav entry (the property
"item?: any" in the inline type that also has "section?: 'skills' | 'projects' |
'agents'") is causing the lint failure; replace it with a concrete interface
(e.g., define an interface SlashNavItem { /* fields used by the component such
as id: string; title: string; description?: string; ... */ } and then change
"item?: any" to "item?: SlashNavItem") or, if the shape is not yet known, use
"unknown" and narrow it where accessed with type guards; update any usages of
"item" to match the new type (or add type guards/casts) so the component
compiles without `@typescript-eslint/no-explicit-any` errors.

---

Outside diff comments:
In `@apps/web/src/components/welcome/WelcomePage.tsx`:
- Around line 150-157: The resolvePromptPlaceholders function currently leaves
/skill:<absolutePath> tokens untouched; add a replacement step in
resolvePromptPlaceholders (alongside the existing .replace chains) that matches
/skill:([^\s]+) and returns the captured path (the first capture group) so the
token is replaced with the actual skill path before submission; reference
resolvePromptPlaceholders to locate where to insert the .replace and ensure the
regex is global and returns the captured path string.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7ebdeedc-5821-465d-bb41-d4b807e983b6

📥 Commits

Reviewing files that changed from the base of the PR and between eb9e456 and 64a10a0.

⛔ Files ignored due to path filters (1)
  • apps/web/public/icons/puzzle.svg is excluded by !**/*.svg
📒 Files selected for processing (4)
  • AGENTS.md
  • apps/web/src/components/dialogs/SettingsModal.tsx
  • apps/web/src/components/welcome/PromptComposer.tsx
  • apps/web/src/components/welcome/WelcomePage.tsx

Comment on lines +122 to 123
span.className += " border-blue-500/30 bg-blue-500/10 text-blue-600 dark:text-blue-400";
const iconProps = getFileIconProps({ name: filename, isDir, className: "size-3.5" });

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.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Use semantic theme tokens instead of hardcoded blue/yellow classes for chips.

Line 122 and Line 137 hardcode palette values, which makes theme adaptation brittle.

As per coding guidelines: "ALWAYS use semantic CSS variables (bg-background, text-muted-foreground, border-border) instead of hardcoded colors for theme adaptation".

Also applies to: 137-138

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/welcome/PromptComposer.tsx` around lines 122 - 123,
The span.className mutation currently appends hardcoded blue classes
("border-blue-500/30 bg-blue-500/10 text-blue-600 dark:text-blue-400") (and the
similar hardcoded yellow/blue classes around lines ~137-138) which breaks theme
adaptation; replace those literal color utility classes with semantic theme
tokens (e.g. use border-border, bg-background or a semantic chip/bg and
text-primary/text-muted-foreground with appropriate opacity tokens) so chips use
the app's CSS variables; update the span.className concatenation and any other
places (search for the other hardcoded class usage near where iconProps is
created and the lines flagged) to use those semantic class names instead of
hardcoded palette classes.

Comment on lines +348 to +353
const domAtIndex = beforeDomText.lastIndexOf("/");
if (domAtIndex < 0) return null;

const query = beforeDomText.slice(domAtIndex + 1);
if (/\s/.test(query)) return null;

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Slash trigger parsing is too broad and too strict at the same time.

Line 348 triggers on any / (including URLs/paths), and Line 352 cancels as soon as a space appears, which blocks command patterns like /project my-app.

Suggested fix
   const beforeDomText = beforeRange.toString();
   const domAtIndex = beforeDomText.lastIndexOf("/");
   if (domAtIndex < 0) return null;
+  // Only treat "/" as a command trigger at start-of-text or after whitespace.
+  if (domAtIndex > 0 && !/\s/.test(beforeDomText[domAtIndex - 1] ?? "")) return null;

   const query = beforeDomText.slice(domAtIndex + 1);
-  if (/\s/.test(query)) return null;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const domAtIndex = beforeDomText.lastIndexOf("/");
if (domAtIndex < 0) return null;
const query = beforeDomText.slice(domAtIndex + 1);
if (/\s/.test(query)) return null;
const domAtIndex = beforeDomText.lastIndexOf("/");
if (domAtIndex < 0) return null;
// Only treat "/" as a command trigger at start-of-text or after whitespace.
if (domAtIndex > 0 && !/\s/.test(beforeDomText[domAtIndex - 1] ?? "")) return null;
const query = beforeDomText.slice(domAtIndex + 1);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/welcome/PromptComposer.tsx` around lines 348 - 353,
The slash trigger currently matches any "/" in beforeDomText (domAtIndex =
lastIndexOf("/")) and aborts if any space exists in the remainder, which both
picks up URLs/paths and forbids commands with args (e.g., "/project my-app").
Change the parsing in PromptComposer.tsx so you find a "/" that is either at the
start or preceded by whitespace (check charAt(domAtIndex - 1) or use a regex
like /(^|\s)\/.../), then allow spaces after the slash by extracting the command
token only (e.g., let raw = beforeDomText.slice(domAtIndex + 1); let command =
raw.split(/\s/)[0]) instead of returning null on /\s/. Use these variables
(domAtIndex, beforeDomText, query/raw/command) to implement the stricter trigger
detection and permissive argument handling.

Comment on lines +715 to +727
const filteredSkills = React.useMemo(() => {
const query = debouncedSlashQuery;
if (!query) return skills;
const results = skillsFuse.search(query);
return results.map((r) => r.item);
}, [debouncedSlashQuery, skills, skillsFuse]);

const filteredProjects = React.useMemo(() => {
const query = debouncedSlashQuery;
if (!query) return projects;
const results = projectsFuse.search(query);
return results.map((r) => r.item);
}, [debouncedSlashQuery, projects, projectsFuse]);

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.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Subcommand targeting (/skills, /project, /agent) is not implemented yet.

All sections are filtered by the same raw query; this misses the issue objective requiring command-scoped filtering.

Suggested direction
+function parseSlashQuery(q: string): { scope: "all" | "skills" | "projects" | "agents"; term: string } {
+  const m = q.trim().match(/^(skills?|project|agent)\b\s*(.*)$/i);
+  if (!m) return { scope: "all", term: q.trim() };
+  const scopeMap = { skill: "skills", skills: "skills", project: "projects", agent: "agents" } as const;
+  return { scope: scopeMap[m[1].toLowerCase() as keyof typeof scopeMap] ?? "all", term: m[2] ?? "" };
+}

Then filter/render only the targeted section when scope !== "all".

Also applies to: 770-775

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/welcome/WelcomePage.tsx` around lines 715 - 727, The
current filtering uses the raw debouncedSlashQuery for every section (see
filteredSkills, filteredProjects and the similar filteredAgents block) and
doesn't support subcommand scopes like "/skills" or "/project"; update the logic
to parse the debouncedSlashQuery for a scope prefix (e.g., detect "/skills",
"/project" or "/agent"), strip that prefix to produce the actual search term,
and then: for each memoized filter (filteredSkills, filteredProjects,
filteredAgents) only run the Fuse search when the scope is either "all" or
matches that section; otherwise return the original unfiltered array (or an
empty array if you prefer hiding non-target sections). Also ensure the UI
rendering respects scope !== "all" by showing only the targeted section when a
scope is present.

Comment on lines +847 to +857
const selectSlashProject = React.useCallback(
(project: { id: string }) => {
const popover = slashPopover;
if (!popover) return;
// Close popover immediately to prevent re-opening from side effects
setSlashPopover(null);
// Then switch project
setProjectId(project.id);
},
[slashPopover],
);

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.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Selecting Project/Agent from slash menu should also consume the typed /<query> fragment.

Currently it closes the popover and switches project/agent, but the command text remains in the composer input.

Suggested direction
 const selectSlashProject = React.useCallback(
   (project: { id: string }) => {
     const popover = slashPopover;
     if (!popover) return;
+    composerRef.current?.clearSlashAtRange?.(popover.slashOffset, popover.query.length);
     setSlashPopover(null);
     setProjectId(project.id);
   },
   [slashPopover],
 );

You’d need the corresponding clearSlashAtRange handle method in PromptComposer.

Also applies to: 859-869

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/welcome/WelcomePage.tsx` around lines 847 - 857, The
selectSlashProject callback closes the popover and sets the project but doesn't
remove the typed "/<query>" from the PromptComposer; update selectSlashProject
to also call the PromptComposer's clearSlashAtRange handler (via the composer
ref) after closing the popover and before/after setProjectId so the slash
fragment is consumed, making sure to null-check the composer ref/handler; apply
the same change to the analogous selectSlashAgent handler so both actions clear
the slash text from the composer input.

Comment on lines +879 to +881
item?: any;
section?: "skills" | "projects" | "agents";
}> = [];

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace any in slash nav item typing (CI is already failing on this line).

Line 879 violates @typescript-eslint/no-explicit-any and matches the lint failure.

Suggested fix
-    const items: Array<{
-      type: "skill" | "project" | "agent" | "show-more";
-      item?: any;
-      section?: "skills" | "projects" | "agents";
-    }> = [];
+    type SlashNavItem =
+      | { type: "skill"; item: SkillInfo }
+      | { type: "project"; item: { id: string; name: string } }
+      | { type: "agent"; item: AgentMenuOption }
+      | { type: "show-more"; section: "skills" | "projects" | "agents" };
+    const items: SlashNavItem[] = [];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
item?: any;
section?: "skills" | "projects" | "agents";
}> = [];
type SlashNavItem =
| { type: "skill"; item: SkillInfo }
| { type: "project"; item: { id: string; name: string } }
| { type: "agent"; item: AgentMenuOption }
| { type: "show-more"; section: "skills" | "projects" | "agents" };
const items: SlashNavItem[] = [];
🧰 Tools
🪛 GitHub Actions: CI - Web / 2_Lint.txt

[error] 879-879: @typescript-eslint/no-explicit-any: Unexpected any. Specify a different type.

🪛 GitHub Actions: CI - Web / Lint

[error] 879-879: @typescript-eslint/no-explicit-any: Unexpected any. Specify a different type

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/welcome/WelcomePage.tsx` around lines 879 - 881, The
explicit any on the slash nav entry (the property "item?: any" in the inline
type that also has "section?: 'skills' | 'projects' | 'agents'") is causing the
lint failure; replace it with a concrete interface (e.g., define an interface
SlashNavItem { /* fields used by the component such as id: string; title:
string; description?: string; ... */ } and then change "item?: any" to "item?:
SlashNavItem") or, if the shape is not yet known, use "unknown" and narrow it
where accessed with type guards; update any usages of "item" to match the new
type (or add type guards/casts) so the component compiles without
`@typescript-eslint/no-explicit-any` errors.

…ized text

Previously, readSlashContextFromSelection and readAtContextFromSelection
computed offsets by searching the entire serialized text for the last
occurrence of "/<query>" or "@<query>". If the same query appeared later
in the document, this could point to the wrong occurrence, causing
applySlashAtRange/applyMentionAtRange to replace the wrong segment.

Fix: serialize only the content up to the caret and find the trigger
character within that truncated text, ensuring the offset matches the
active selection.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

This branch was successfully deployed

1 active deployment
Preview — 4501f96a Deployed May 11, 2026 by vercel[bot]
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.

Add / command in new workspace composer for Skills, Projects, and Code Agents

1 participant