Skip to content

fix(parser): handle nested command tags in skill bodies (#1340)#1411

Open
averymkeller83-hub wants to merge 1 commit into
slopus:mainfrom
averymkeller83-hub:fix/skill-body-nested-command-tags
Open

fix(parser): handle nested command tags in skill bodies (#1340)#1411
averymkeller83-hub wants to merge 1 commit into
slopus:mainfrom
averymkeller83-hub:fix/skill-body-nested-command-tags

Conversation

@averymkeller83-hub

Copy link
Copy Markdown

Summary

  • Fixes UX: Skill instruction content visible in chat when invoking skills #1340: when a slash-command's skill body contains literal <command-message> / <command-name> examples in its markdown, the SDK wrapper ends up with nested closing tags, and the parser falls through to kind: 'text' — rendering the entire skill body as plain text in the chat.
  • Two changes in parseLocalCommandMessage.ts:
    1. COMMAND_MESSAGE_RE becomes greedy so the whole outer block (including any nested example tags) is consumed in one pass.
    2. <command-message> blocks are stripped before the name/args extractors run, so a nested <command-name>/compact</command-name> example inside the wrapper can't be mistaken for the real command name.
  • Adds one regression test reproducing the /go skill scenario from the issue.

Why both changes are needed

Either fix alone is insufficient:

  • Greedy alone → stripping is fixed, but text.match(COMMAND_NAME_RE) still finds the first <command-name> tag in the original input, which is the nested example (/compact) rather than the outer wrapper's real command (/go).
  • Reorder alone → without greedy, the lazy match still stops at the inner closer, leaving the outer </command-message> behind.

The community comment on #1340 caught the lazy/greedy half but missed the extraction-order half; this PR addresses both.

Test plan

  • pnpm vitest run sources/components/parseLocalCommandMessage.spec.ts — 15/15 tests pass (14 existing + 1 new regression test).
  • pnpm typecheck — clean.
  • All existing test cases (caveat, no-arg, with-args, empty-args, mixed-content, plain-text, echo detection) still pass — no behavior change for non-nested inputs.

🧙 Built with WOZCODE

When a slash-command's skill body contains literal `<command-message>` or
`<command-name>` examples in its markdown, the SDK wrapper ends up with
nested closing tags. The old lazy `<command-message>...</command-message>`
match stopped at the inner closer, leaving the outer tail behind, so the
parser fell through to `kind: 'text'` and rendered the entire skill body
as plain text in the chat.

Two changes:
1. Make `COMMAND_MESSAGE_RE` greedy so it consumes the whole outer block
   (including any nested example tags) in one pass.
2. Strip `<command-message>` blocks first, before extracting the command
   name and args. Previously, a nested `<command-name>/compact</command-name>`
   example inside the wrapper would be picked up by the extractor as the
   command name, instead of the outer wrapper's real `<command-name>/go</command-name>`.

Adds a regression test covering the /go skill scenario from the issue.

Fixes slopus#1340

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
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.

UX: Skill instruction content visible in chat when invoking skills

1 participant