Skip to content

feat(cli): install JetBrains stack plugins via customizations.jetbrains - #79

Draft
shejnowicz wants to merge 1 commit into
masterfrom
feat/jetbrains-stack-plugins
Draft

feat(cli): install JetBrains stack plugins via customizations.jetbrains#79
shejnowicz wants to merge 1 commit into
masterfrom
feat/jetbrains-stack-plugins

Conversation

@shejnowicz

Copy link
Copy Markdown
Collaborator

Summary

Symmetric counterpart for the JetBrains devcontainer path to how VS Code stacks already work: sandcat init --ide jetbrains --stacks scala now seeds customizations.jetbrains.plugins with ["org.intellij.scala"], so Gateway auto-installs the plugin into the backend IDE at first start. Today the array is emitted empty regardless of stack selection.

Motivation

Existing stack_extension() in cli/lib/stacks.bash maps scala → scalameta.metals (etc.) into customizations.vscode.extensions for the VS Code path. Nothing analogous exists for JetBrains — users need to open the plugin marketplace inside Gateway and install manually every time. The JetBrains devcontainer spec supports customizations.jetbrains.plugins natively (Gateway parses this block and installs listed marketplace IDs at backend start-up); we already emit the surrounding block via apply_ide_customizations — just with "plugins": [].

Changes

  • cli/lib/stacks.bash — new stack_jetbrains_plugin() lookup, mirroring stack_extension(). Only maps stacks with first-party or well-established plugins:

    • python → PythonCore
    • scala → org.intellij.scala
    • go → org.jetbrains.plugins.go (Ultimate/GoLand only)
    • ruby → org.jetbrains.plugins.ruby (Ultimate/RubyMine only)
    • zig → com.falsepattern.zigbrains (community)
    • node, java → empty (language support bundled in IntelliJ)
    • rust, dotnet → empty (RustRover / Rider are standalone IDEs; no first-party IntelliJ plugin)
      See the function docstring for edition caveats.
  • cli/lib/devcontainer.bash — new customize_devcontainer_plugins(), symmetric to the existing customize_devcontainer_extensions(). Rewrites the literal "plugins": [] emitted by apply_ide_customizations in place. No-op if no stack contributes a plugin.

  • cli/libexec/init/devcontainer — invoke customize_devcontainer_plugins after customize_devcontainer_json (so the JetBrains block exists) and only when --ide jetbrains with non-empty --stacks.

  • cli/test/init/jetbrains_plugins.bats — 6 new tests covering: single plugin, multiple plugins, bundled-only stack (no rewrite), no stacks (no rewrite), mixed bundled+non-bundled, no-op on vscode devcontainer.json.

Example

$ sandcat init --agent claude --ide jetbrains --stacks scala,python --name demo

Generates in .devcontainer/devcontainer.json:

"customizations": {
    "jetbrains": {
        "backend": "IntelliJ",
        "plugins": ["org.intellij.scala", "PythonCore"],
        "settings": {}
    }
}

Gateway installs both plugins into the IntelliJ backend on first start. Downloads go to plugins.jetbrains.com / downloads.marketplace.jetbrains.com, already in the JetBrains row of the default network allowlist (README §Network access rules).

Test plan

  • bats cli/test/init/ — 81 tests pass locally (6 new + 75 existing)
  • End-to-end: sandcat init --ide jetbrains --stacks scala on a fresh project, open in JetBrains Gateway, verify the Scala plugin appears installed in the backend's Plugins UI at first launch (not yet run — requires Gateway + Marketplace access)

Non-goals / notes for reviewer

  • No explicit --jetbrains-plugins flag. Users who want additional plugins beyond stack defaults edit .devcontainer/devcontainer.json directly. Same escape hatch as for the vscode extensions array today.
  • No plugin version pinning. Gateway resolves "latest compatible" for the backend IDE version. Matches VS Code side (extension versions also unpinned).
  • Ultimate-only plugins on Community backends silently skip. Gateway logs a warning but does not fail startup — matches Marketplace's own install semantics. Documented in the stack_jetbrains_plugin() docstring.
  • rust and dotnet intentionally return empty. Both moved to standalone JetBrains IDEs (RustRover, Rider) with no maintained IntelliJ plugin equivalent. Happy to re-add if there's a preferred community plugin to point at.

🤖 Generated with Claude Code

Adds stack_jetbrains_plugin() symmetric to the existing
stack_extension() lookup, plus customize_devcontainer_plugins()
that rewrites the empty "plugins": [] in the JetBrains
customizations block that customize_devcontainer_json emits.

When --ide jetbrains and --stacks scala,python is passed:

  "jetbrains": {
    "backend": "IntelliJ",
    "plugins": ["org.intellij.scala", "PythonCore"],
    "settings": {}
  }

Gateway installs these plugins into the backend IDE at start-up,
matching how VS Code auto-installs extensions from the vscode
customizations block. Stacks whose language support is bundled in
IntelliJ (java, node) or that don't have a first-party JetBrains
plugin (rust, dotnet) contribute nothing — the empty array stays.

Downloads hit plugins.jetbrains.com and
downloads.marketplace.jetbrains.com, already listed in the JetBrains
row of the default network allowlist (README §Network access rules).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant