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