Skip to content

feat(app): add $ trigger for skills in desktop prompt - #51496

Open
shirishpothi wants to merge 2 commits into
anomalyco:devfrom
shirishpothi:feat-desktop-dollar-skill-trigger
Open

shirishpothi wants to merge 2 commits into
anomalyco:devfrom
shirishpothi:feat-desktop-dollar-skill-trigger

Conversation

@shirishpothi

@shirishpothi shirishpothi commented Sep 26, 2026 •

Copy link
Copy Markdown

Issue for this PR

Related to #20982, #48022, #50664

No open PR adds a $ skill trigger for desktop/web. Verified with search: only TUI $skill PR is #29217, CLI @skill is #50430, desktop skill-slash alignment is #48023.

Type of change

  • New feature

What does this PR do?

Adds $ as an additive skill trigger in the desktop/web prompt composer. Typing $ + lowercase name opens a skill-only popover backed by skill.list; selecting replaces just the $token at the cursor with /skill , reusing the existing command submit path. @ stays for files/agents, / stays for commands. $HOME, $1, and currency amounts do not trigger, and $ is disabled in shell mode.

CLI run keeps @skill (see #50430) since $ conflicts with shell env expansion.

Follow-ups not in scope: live refresh on skill updates, V2-protocol skill sync (returns empty until #48022 lands).

How did you verify your code works?

  • bun test src/v2/components/prompt-input/machine.test.ts in packages/session-ui — 16 pass, including $ insert, bare $, mid-line suffix preservation, shell-mode guard, and $HOME/$1 ignore cases.
  • bun build syntax check on changed session-ui modules; app files reviewed against existing addPart range-edit pattern (full typecheck needs repo install).

Screenshots / recordings

UI reuses the existing command popover, no new visual component. Manual desktop check pending.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Copilot AI lite review requested due to automatic review settings September 26, 2026 13:28
@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Unresolved moderate findings affect filtering, prompt preservation, matching, and shell-mode behavior.

Review effort: Lite
Findings: 6 Medium severity

Open (6)
What changed in this PR

Adds $skill autocomplete to desktop/web prompt composers, inserting selected skills as /skill commands.

Changes:

  • Detects lowercase $skill tokens.
  • Reuses command-popover selection and submission flows.
  • Adds tests for insertion and ignored tokens.
File Review summary
packages/​session-ui/​src/​v2/​components/​prompt-input/​machine.ts Moderate findings: filter suggestions to skills, preserve suffixes using the cursor range, and disable $ detection in shell mode.
packages/​session-ui/​src/​v2/​components/​prompt-input/​machine.test.ts Adds coverage for skill insertion and ignored dollar expressions.
packages/​app/​src/​components/​prompt-input.tsx Moderate findings: filter to skills, preserve existing prompt parts and suffixes, and correct the trigger matcher’s hyphen range.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

.current()
.map((part) => ("content" in part ? part.content : ""))
.join("")
const dollarToken = currentText.match(/(^|\s)\$[a-z][a-zA-Z0-9-_]*$/)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed — hyphen moved to the end of the class ([a-zA-Z0-9_-]) in all four matchers, and bare $ is now supported via an optional group that still rejects $HOME/``/currency.

Comment on lines +727 to +731
const dollarToken = currentText.match(/(^|\s)\$[a-z][a-zA-Z0-9-_]*$/)
if (dollarToken && !menu) {
const tokenStart = currentText.lastIndexOf("$")
const prefix = currentText.slice(0, tokenStart)
const text = `${prefix}/${cmd.trigger} `

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed — skill selection now replaces only the `` range at the editor cursor (setRangeEdge start/end) instead of matching the full draft, so trailing text is preserved.

Comment on lines +731 to +733
const text = `${prefix}/${cmd.trigger} `
setEditorText(text)
prompt.set([{ type: "text", content: text, start: 0, end: text.length }, ...images], text.length)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed — selection does a DOM-range replacement of the `` and re-parses via handleInput, so existing @ file/agent pills and attachments are retained. The draft-reconstruction path is removed.

Comment on lines +1021 to +1023
} else if (skillMatch) {
slashOnInput(skillMatch[1] ?? "")
setStore({ popover: "slash", slashMenu: false, slashMenuQuery: "" })

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed - $ popover now uses a dedicated skillCommands list sourced from skill.list (app.skills), separate from the / slash commands. Selecting inserts /skill text which submits via the existing command path.

Comment on lines +105 to +110
const skill = value.slice(0, cursor ?? value.length).match(/(?:^|\s)\$([a-z][a-zA-Z0-9-_]*)$/)
if (skill) {
const query = skill[1] ?? ""
return changed({ ...state, popover: { type: "command-inline", query }, focus: "editor" }, [
...setText,
{ type: "popover.filter", popover: "command", query },

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed - V2 machine has a dedicated skill-inline popover routed to a separate skills accessor (skill-only suggestions), so $ never filters or inserts ordinary commands.

Comment on lines +192 to +194
: current.match(/(?:^|\s)\$[a-z][a-zA-Z0-9-_]*$/)
? replaceTrigger(current, "$", `${item.label} `)
: replaceTrigger(current, "/", `${item.label} `),

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed - replaceSkillTrigger replaces the $ token using persisted.cursor and appends the trailing suffix, with a non-destructive fallback. Covered by a mid-line cursor test.

This branch has not been deployed

No deployments
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