Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [5.8.1] — 2026-08-30

### Fixed
- **Closing the last chat no longer reports an internal error.** Closing a chat that was the only one
open, and that had been used, left the IDE logging `Already disposed` from the browser component the
chat had just torn down. The chat's card is now hidden before it leaves the tool window, so the layout
never lays out a browser that is already gone. Nothing about closing a chat changes for you: the
replacement chat still opens as before.

## [5.8.0] — 2026-08-28

**A chat in the IDE can now be driven from claude.ai or the Claude app**, and keeps running on your own
Expand Down
9 changes: 8 additions & 1 deletion CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# CODEOWNERS — Claude Code Native
#
# GitHub uses this file to auto-request reviews on pull requests.
# Maintainer: @serialexperimentslainnnn (the local author "Lain" / lain.agent604@passmail.com).
# Maintainer: @serialexperimentslainnnn (the local author "Lain" / lain@digitalexperiments.dev).

# Default owner for everything in the repo.
* @serialexperimentslainnnn
Expand All @@ -15,6 +15,13 @@
/src/main/kotlin/dev/lain/claudejb/permission/ @serialexperimentslainnnn
/src/main/kotlin/dev/lain/claudejb/protocol/ @serialexperimentslainnnn

# Two files nothing may edit in passing. CLAUDE.md carries the standing directive over the
# guard and its tests, and .gitignore is what keeps credentials and local state out of the
# history in the first place — a quiet line added to either is a change to the rules, not a
# chore, so both are owned outright.
/CLAUDE.md @serialexperimentslainnnn
/.gitignore @serialexperimentslainnnn

# A workflow is privileged code: it runs with a token, and it can publish to the Marketplace. A ruleset is
# the gate that decides what reaches main at all. Both are listed LAST so they win over every earlier glob.
#
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Three different things are often confused. All of them are legitimate; they solv
| Permissions | An inline card per call, plus a deterministic lock that runs before any auto-approval | Handled by the CLI in the terminal | JetBrains' own approvals |
| Account | Your `claude` subscription or API key | Your `claude` subscription or API key | JetBrains AI credits, your own Anthropic API key, or a Claude Console account |
| Agents / background tasks | A tab and a transcript per agent; background tasks keep their output | Visible as terminal output | Not applicable |
| [Remote Control](#remote-control--pick-a-chat-up-from-your-phone) | A button in the chat and a row in the ⚙ menu; the chat you are looking at is the one that goes to your phone | The CLI's own `/remote-control`, typed in the terminal | Not applicable — it does not run your local CLI |
| Needs the `claude` CLI | Yes — and installs it for you if you do not have it | Yes | No |

Anthropic's [Claude Code [Beta]](https://plugins.jetbrains.com/plugin/27310-claude-code-beta-) is not
Expand Down Expand Up @@ -640,6 +641,13 @@ phone button in the chat's button row and a row in the ⚙ menu, neither of whic
has accepted; a refusal names its reason on the button and in the chat. Permission cards answered from
the phone close themselves here.

**5.7.0** — the [Sensitive Guard](#security) stops being invisible: it keeps a log of every alert it
raises, per project, and a **Guard** view in the chat's view row to read it — what matched, what the rule
saw, the verdict, and what let the call through if anything did. Every rule gets a mode (Enforcing,
Permissive, Allow All), as does the guard as a whole; **Settings ▸ Claude Code Security** becomes its own
page, with the three whitelist reaches and the extra credential globs and blocked domains. A shield in
the chat's button row suspends the guard for a duration you pick. Most settings became per project.

**5.5.0** — a tab and a transcript per agent, with the whole tree one hover away; a single **Workloads**
diagram of everything running across every chat; background tasks that keep their output after they
end and survive a restart; a [Git integration](#git) whose write actions are asked of Claude rather than
Expand Down
8 changes: 8 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## v5.8.1 — 2026-08-30

**Closing your last chat no longer raises an internal error.** If the chat you closed was the
only one open and you had actually used it, the IDE logged an `Already disposed` error while
tearing the chat's browser down. The chat is now hidden before it is removed, so nothing tries
to lay out a browser that has already gone. Closing a chat behaves exactly as before otherwise,
replacement chat included.

## v5.8.0 — 2026-08-28

**Pick a chat up from your phone.** Remote Control connects a chat running in your IDE to
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ plugins {
}

group = "dev.lain"
version = "5.8.0"
version = "5.8.1"

repositories {
mavenCentral()
Expand Down
7 changes: 5 additions & 2 deletions docs/FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,11 @@ Because that is where its settings and credentials live. Since 5.5.0 the whole
settings document is in the IDE's PasswordSafe rather than in
`.idea/claude-code.xml` — they were per-project plaintext in a file people
commit, and they include an env block, which is where an API key or a
credentialed proxy URL ends up. One consequence worth knowing: **the settings are
now global, not per project.**
credentialed proxy URL ends up. The scope worth knowing: **since 5.7.0 the
settings are one document per IDE installation, per project** — two IDEs on the
same machine keep separate settings, and so do two projects in the same IDE.
(Between 5.5.0 and 5.7.0 there was a single global document; it is kept as the
seed a project without settings of its own starts from.)

If the safe cannot be read (a locked KWallet, say), the plugin treats that as a
failure and refuses to save over it — a failed read is not an empty
Expand Down
8 changes: 6 additions & 2 deletions docs/TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,12 @@ Since **5.5.0** the settings live in the IDE's **PasswordSafe**, not in a file.
The old `.idea/claude-code.xml` is read once, copied into the safe, and deleted
only after the safe has accepted the copy. Two things follow:

- **Settings are now global**, not per project. The safe is application-wide,
which is also the scope these settings actually had.
- **Settings are kept per IDE installation, per project** since 5.7.0. The safe
is application-wide, but each entry is keyed by the IDE's configuration
directory and the project, so two IDEs — or two checkouts — do not share a
document. The single global document that 5.5.0–5.7.0 wrote is still read as
the seed for a project that has none of its own, which is why it is never
deleted.
- **If the safe cannot be read**, the plugin refuses to save over it rather than
treating a failed read as an empty configuration. On Linux that usually means a
locked KWallet/keyring — unlock it and restart the IDE. A read that failed
Expand Down
1 change: 1 addition & 0 deletions src/main/kotlin/dev/lain/claudejb/ui/ChatTabsPanel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ internal class ChatTabsPanel : JBPanel<ChatTabsPanel>(BorderLayout()), Disposabl
} else {
pushChats()
}
tab.component.isVisible = false
onClosed(tab)
content.remove(tab.component)
tab.disposer?.let { Disposer.dispose(it) }
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/dev/lain/claudejb/util/PluginIdentity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package dev.lain.claudejb.util

object PluginIdentity {

const val PLUGIN_VERSION = "5.8.0"
const val PLUGIN_VERSION = "5.8.1"

private const val PROJECT_URL = "https://github.com/serialexperimentslainnnn/claude-code-for-jetbrains"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,30 @@ class ChatTabsCloseHeadlessTest : BasePlatformTestCase() {
assertEquals(listOf("A"), closed)
}

fun `test the last tab is hidden before it leaves the deck, never shown again`() {
val a = open("A")
tabs.select(a)

tabs.close(a)

assertFalse(
"closing the only card must not leave the card layout re-showing the torn down chat",
a.component.isVisible,
)
assertNull("and the card must be out of the deck", a.component.parent)
}

fun `test closing the selected tab hides it and shows the survivor`() {
val a = open("A")
val b = open("B")
tabs.select(a)

tabs.close(a)

assertFalse(a.component.isVisible)
assertTrue(b.component.isVisible)
}

fun `test the closed tab is out of the model when close returns`() {
val a = open("A")
open("B")
Expand Down
Loading