Skip to content

feat(jetbrains): show verbatim skill commands and skill name in permission prompt - #12724

Merged
bagatao-anaconda merged 4 commits into
mainfrom
feat/execute-cmds-in-skill-context-jetbrains
Jul 31, 2026
Merged

feat(jetbrains): show verbatim skill commands and skill name in permission prompt#12724
bagatao-anaconda merged 4 commits into
mainfrom
feat/execute-cmds-in-skill-context-jetbrains

Conversation

@bagatao-anaconda

@bagatao-anaconda bagatao-anaconda commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Issue

https://docs.google.com/document/d/1eXKc_A9f_mVuc3LiniP3gbLWm7Ic_cPe58z1Tq_ZlzY/

Context

Skills can embed shell commands in a SKILL.md using !`command` syntax, gated by a single up-front approval that lists every command — shipped in the CLI/TUI backend in #12604 (merged to main).

That PR already wired JetBrains' extension-host reply plumbing so approvals work (the interactive: true flag satisfies the server's non-interactive-reply refusal for skill-shell batches), but never updated the permission card to display the batch distinctly — a skill-shell request rendered as a generic bash permission, showing the backend's decomposed authorization patterns rather than the verbatim commands that execute.

This PR is the JetBrains counterpart to the VS Code fix in #12606: it makes the card show exactly what will run and which skill triggered it, matching the CLI TUI.

Implementation

The backend already sends metadata.skillShell, metadata.skill, and metadata.commands (verbatim, per-placeholder) on the permission request; this data already flows into the JetBrains backend's flat metadata map, so the change is display-layer only across shared/backend/frontend.

  • ChatDto/KiloCliDataParser: extract metadata.commands into a new skillCommands: List<String> field on PermissionRequestDto — the flat Map<String, String> metadata can't carry a JSON array, so it needs its own typed field, extracted via a JsonObject?.skillCommands() helper matching the file's existing path()/ruleDecisions() convention.
  • SessionController/Permission: thread skillCommands through to the view model.
  • PermissionView.show(): for a skill-shell bash ask, render the header as Run shell commands from skill "<name>"? and the body as the verbatim skillCommands list — not the decomposed patterns, which strip cd prefixes and split pipelines and so can differ from what actually executes. The sibling external_directory ask (same metadata, when a command touches a directory outside the project) keeps its normal directory-pattern rendering; only the title carries the skill attribution for that one.
  • Escaping: commands are run through a new escapeControl, covering both ASCII control chars and the bidi/format Unicode range (U+200E/F, U+2028/29, U+202A–E, U+2066–9) — mirrors displayCommand in the CLI (packages/opencode/src/kilocode/skills/display.ts) so a command can't repaint the card or use Trojan-Source reordering to make the displayed text lie about what runs.
  • Rule toggles: explicitly suppressed for a skill-shell batch (rules.update(if (skillShell) emptyList() else ...)), rather than relying on today's incidental empty ruleDecisions — future-proofs against a backend change that starts sending rule candidates alongside skillShell metadata.

packages/kilo-jetbrains/ is entirely Kilo-owned, so no kilocode_change markers are involved.

How to Test

Manual/local verification

Verified locally by the author in a sandboxed IntelliJ instance (repo-CLI mode) using the git-status test skill:

  • The card shows Run shell commands from skill "git-status"? and lists both verbatim commands.
  • No "Auto-approve Rules" section appears.
  • Allow/Deny work correctly (the interactive: true reply from feat(tui): execute cmds in skill context #12604 is unaffected by this PR).

Reviewer test steps

  1. Set kilo.cli.pinned=false in packages/kilo-jetbrains/gradle.properties (this feature is unreleased — the pinned CLI predates it) and build the local CLI:
    cd packages/kilo-jetbrains
    ./gradlew :backend:buildRepoCli

@kilo-code-bot

kilo-code-bot Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 2
Issue Details (click to expand)

SUGGESTION

File Line Issue
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/permission/PermissionView.kt 126 Nameless skill-shell batch falls back to the generic "Permission required" header instead of skill-shell framing like the CLI's "Run these skill commands?"
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/permission/PermissionView.kt 135 Empty skillCommands renders a skill-shell header with no commands in the code slot
Files Reviewed (4 files, incremental)

Incremental review of 5577903a..e804131f.

  • KiloBundle_de.properties - 0 issues
  • KiloBundle_da.properties - 0 issues
  • KiloBundle_pl.properties - 0 issues
  • KiloBundle_bs.properties - 0 issues
Resolved / verified during review
  • Fixed: the mismatched-quote finding. All four locales now close with the correct typographic quote for their convention: de/da/bs use „{0}“ and pl uses „{0}”. Checked the remaining locales too — nl, ko, th, pt_BR, tr use matched ASCII pairs, fr/es/ru/uk/ar/no use matched guillemets, and ja/zh_* use matched corner brackets, so no locale is left with an unbalanced pair.
  • Fixed earlier: skill-name escaping — card.setHeader passes escapeControl(skill), so bidi/control characters in untrusted SKILL.md frontmatter cannot repaint or reorder the header attribution.
  • The two remaining suggestions were re-verified against current HEAD (e804131f) at PermissionView.kt:126 and PermissionView.kt:135; existing inline comments still resolve to those lines, so no duplicates were posted.
  • This commit is resource-string-only: no new listeners, subscriptions, editors, or disposables, so no new leak surface.

Fix these issues in Kilo Cloud

Previous Review Summary (commit 86e5507)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 86e5507)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 3
Issue Details (click to expand)

SUGGESTION

File Line Issue
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/permission/PermissionView.kt 126 Nameless skill-shell batch falls back to the generic "Permission required" header instead of a skill-shell fallback like the CLI's "Run these skill commands?"
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/permission/PermissionView.kt 135 Empty skillCommands hides the code slot entirely, showing a skill-shell header with no commands
packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle_de.properties 175 Mismatched quotation marks around {0} ( opened, ASCII " closed); same mismatch in _da, _pl, _bs
Files Reviewed (2 files, incremental)

Incremental review of 86e55070..5577903a.

  • PermissionView.kt - 0 new issues
  • PermissionViewTest.kt - 0 new issues
Notes / verified during review
  • The previously reported skill-name escaping gap is addressed at HEAD: card.setHeader now passes escapeControl(skill) (PermissionView.kt:125), so bidi/control characters in untrusted SKILL.md frontmatter can no longer reorder or repaint the header attribution. The new PermissionViewTest case asserts both that the escaped form reaches the header and that the raw U+202E does not, exercising the real view rather than a mock.
  • KiloBundle.message passes the escaped name as a MessageFormat argument, so the injected escape text is not reparsed as a pattern and cannot break the {0} substitution.
  • The three remaining findings above were re-verified against current HEAD (5577903a) and are unchanged; existing inline comments still resolve to those lines.
  • No new listeners, subscriptions, editors, or disposables in this commit, so no new leak surface. Editor retention/disposal is still covered by the existing retained-component tests.

Fix these issues in Kilo Cloud


Reviewed by claude-opus-5 · Input: 28 · Output: 4.6K · Cached: 728.1K

Review guidance: REVIEW.md from base branch main

// repaint the prompt or use Trojan-Source reordering to make the displayed text differ from
// what executes; newlines become a visible marker. Mirrors displayCommand in the CLI
// (packages/opencode/src/kilocode/skills/display.ts); keep the ranges in sync.
private fun escapeControl(command: String): String = buildString {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can we test this?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

There are already a couple of tests for this specifically (check these out), but I did a manual test too.

For the manual test, I added the following skill:

❯ cat escape-demo/SKILL.md
---
name: escape-demo
description: Demo skill to screenshot control/bidi character escaping in the permission card.
---
Result: !`printf 'safe-part-\u202ereversed-part'`

and ran the following command in Kilo IntelliJ:

Can you use the escape-demo skill?

Results are in the attached screenshot. The list of shell commands are indeed escaped in the approval prompt, confirming everything is working as expected 💪

escaped

@bagatao-anaconda bagatao-anaconda self-assigned this Jul 31, 2026
@bagatao-anaconda
bagatao-anaconda merged commit d95002c into main Jul 31, 2026
23 checks passed
@bagatao-anaconda
bagatao-anaconda deleted the feat/execute-cmds-in-skill-context-jetbrains branch July 31, 2026 13:35
t7tran pushed a commit to t7tran/kilocode that referenced this pull request Aug 14, 2026
…skill-context-jetbrains

feat(jetbrains): show verbatim skill commands and skill name in permission prompt
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