Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
155 commits
Select commit Hold shift + click to select a range
e76924e
feat(rpc): add the chat contract between the frontend and the backend
serialexperimentslainnnn Sep 23, 2026
4f11ce0
test: add the benchmark harness for 6.5.0
serialexperimentslainnnn Sep 23, 2026
810328f
build(deps): update DOMPurify to 3.4.16
serialexperimentslainnnn Sep 23, 2026
38ac800
build(deps): update highlight.js to 11.12.0
serialexperimentslainnnn Sep 23, 2026
265b255
refactor(git): remove the unused primary remote lookup
serialexperimentslainnnn Sep 23, 2026
97e8d48
fix(process): end a CLI blocked on stdin and scan stdout only once
serialexperimentslainnnn Sep 23, 2026
9b67e88
perf(session): write prompts to the CLI off the EDT
serialexperimentslainnnn Sep 23, 2026
fb3ff74
build(deps): update marked to 18.0.14
serialexperimentslainnnn Sep 23, 2026
3115862
docs: record kotlinx-serialization 1.9.0 and its NOTICE in the third-…
serialexperimentslainnnn Sep 23, 2026
0cb4e71
fix(credentials): keep a renewed credential when the keyring refuses …
serialexperimentslainnnn Sep 23, 2026
cf34f86
fix(mcp): grant an admission credit only after the spawn succeeds
serialexperimentslainnnn Sep 23, 2026
54fe292
fix(mcp): rotate the token file with an atomic move
serialexperimentslainnnn Sep 23, 2026
bd855b3
fix(mcp): bound frame headers and keep the bridge's reply thread alive
serialexperimentslainnnn Sep 23, 2026
58d05dc
fix(onboarding): verify an API key before approving it and refuse it …
serialexperimentslainnnn Sep 23, 2026
435d428
fix(guard): decide permissions off the protocol reader and bound the …
serialexperimentslainnnn Sep 23, 2026
90c6c7f
fix(diff): count context in unified-diff hunks and merge overlapping …
serialexperimentslainnnn Sep 23, 2026
272e245
perf(diff): cap edit snapshots at 1 MB and bound the store by bytes
serialexperimentslainnnn Sep 23, 2026
a4df2b3
perf(session): refresh the VFS only after tools that write
serialexperimentslainnnn Sep 23, 2026
fe029b2
perf(session): coalesce live tool output and diff edits off the EDT
serialexperimentslainnnn Sep 23, 2026
c1fecd9
fix(session): dispose closed chats through the Disposer and persist o…
serialexperimentslainnnn Sep 23, 2026
fcc8b29
fix(mcp): keep a server alive when one frame is malformed
serialexperimentslainnnn Sep 23, 2026
fca677a
fix(mcp): answer every call and every batch item whatever the tool th…
serialexperimentslainnnn Sep 23, 2026
64c458d
perf(mcp): number the lines of replace_all incrementally
serialexperimentslainnnn Sep 23, 2026
0cea2b6
fix(mcp): report the exit code of the run that was started
serialexperimentslainnnn Sep 23, 2026
ac7f7c5
fix(mcp): release shell processes and finished jobs
serialexperimentslainnnn Sep 23, 2026
416263e
fix(mcp): cap each line of a run's output tail
serialexperimentslainnnn Sep 23, 2026
66e2877
perf(mcp): split the read budget between the files of a batch
serialexperimentslainnnn Sep 23, 2026
bbc1ad0
perf(session): stream assistant deltas on a coalescing drain and expo…
serialexperimentslainnnn Sep 23, 2026
4618e75
build: move to Gradle 9.7.1 with a pinned distribution checksum
serialexperimentslainnnn Sep 23, 2026
072da3f
perf(mcp): group search matches by file without opening documents
serialexperimentslainnnn Sep 23, 2026
b944430
perf(mcp): collect project problems off the EDT and group them by file
serialexperimentslainnnn Sep 23, 2026
2462b06
build: split the plugin into shared, frontend and backend modules on …
serialexperimentslainnnn Sep 23, 2026
c0a63e3
build: declare the content modules in the plugin descriptor instead o…
serialexperimentslainnnn Sep 23, 2026
5fc8a1a
perf(mcp): trim the services listing and reuse a fresh tree walk
serialexperimentslainnnn Sep 23, 2026
37db36e
build(deps): update the npm toolchain and point it at the frontend mo…
serialexperimentslainnnn Sep 23, 2026
54c3415
ci: move to Java 25 and Node 24
serialexperimentslainnnn Sep 23, 2026
d664eff
perf(mcp): abbreviate commit rows and build working tree diffs file b…
serialexperimentslainnnn Sep 23, 2026
2c3d74d
fix(session): run the launch gates off the EDT and stop the boot watc…
serialexperimentslainnnn Sep 23, 2026
e30e333
perf(process): remember the located claude binary while it stays exec…
serialexperimentslainnnn Sep 23, 2026
67b90c1
docs: drop kotlinx-serialization from the redistributed third-party n…
serialexperimentslainnnn Sep 23, 2026
a2ea6be
perf(mcp): share one Reveal and one IdeActions per project
serialexperimentslainnnn Sep 23, 2026
a101a6e
build(deps): keep the npm toolchain on its locked versions
serialexperimentslainnnn Sep 23, 2026
fd09833
perf(page): stream running rows and tool output without re-rendering …
serialexperimentslainnnn Sep 23, 2026
6830ca3
fix(page): give tool cards a keyboard toggle and stop their endless a…
serialexperimentslainnnn Sep 23, 2026
a5b5ff3
refactor(frontend): move the chat browser host into the frontend module
serialexperimentslainnnn Sep 23, 2026
ab9a5da
refactor(frontend): move the chat theme into the frontend module
serialexperimentslainnnn Sep 23, 2026
85c5755
feat(frontend): drive the chat tabs through the chat contract
serialexperimentslainnnn Sep 23, 2026
a113ca8
fix(page): rebuild a permission card whose content changed and mark c…
serialexperimentslainnnn Sep 23, 2026
c162e4f
fix(page): announce each guard alert once and close a replaced filter…
serialexperimentslainnnn Sep 23, 2026
5f9dea8
fix(page): expose the composer toggles' state with aria-pressed
serialexperimentslainnnn Sep 23, 2026
4433bd6
fix(page): forward only links the host opens and intercept middle clicks
serialexperimentslainnnn Sep 23, 2026
9319739
perf(session): restore a chat from the end of its transcript and read…
serialexperimentslainnnn Sep 23, 2026
7a8adb9
test(bench): follow the page assembly into the frontend module
serialexperimentslainnnn Sep 23, 2026
f8c3d96
fix(page): rebuild a guard notice whose rule arrives in a later update
serialexperimentslainnnn Sep 23, 2026
7de5754
fix(session): withdraw a cancelled permission in order behind the dec…
serialexperimentslainnnn Sep 23, 2026
f3298c4
refactor(chat): build transcript rows, appends and trims from one pay…
serialexperimentslainnnn Sep 23, 2026
251ca81
refactor(chat): extract the chat presenter and registry from the Swin…
serialexperimentslainnnn Sep 23, 2026
96bc864
feat(rpc): serve the chat contract from the backend
serialexperimentslainnnn Sep 23, 2026
f38ae35
perf(mcp): put a ceiling on every max a tool takes
serialexperimentslainnnn Sep 23, 2026
a452239
perf(mcp): buffer the frames a connection reads
serialexperimentslainnnn Sep 23, 2026
70d1726
perf(session): tail agent transcripts from their last offset and cap …
serialexperimentslainnnn Sep 23, 2026
c533842
test(contract): scan every module's sources
serialexperimentslainnnn Sep 23, 2026
c26e260
test(contract): keep the frontend and the backend apart
serialexperimentslainnnn Sep 23, 2026
9043678
refactor(commands): reach the chats through the chat registry
serialexperimentslainnnn Sep 23, 2026
7590627
refactor(context): remove the host clipboard helpers and external-lin…
serialexperimentslainnnn Sep 23, 2026
c37d811
feat(session): expose MCP reconnect admission and prewarm to the brid…
serialexperimentslainnnn Sep 23, 2026
26e7562
perf(session): poll the quota every 3 s and at each message boundary
serialexperimentslainnnn Sep 23, 2026
00bbdae
feat(session): keep streaming entries running until their message set…
serialexperimentslainnnn Sep 23, 2026
6702df8
fix(session): read folded batch results so clean items settle as succ…
serialexperimentslainnnn Sep 23, 2026
222dc7b
perf(session): keep background-task output in a ring instead of copyi…
serialexperimentslainnnn Sep 23, 2026
58c083b
perf(session): store the agent index compact, debounce its writes and…
serialexperimentslainnnn Sep 23, 2026
1422fd5
fix(git): release a prompted Git action when no turn starts and guard…
serialexperimentslainnnn Sep 23, 2026
ef729d9
fix(session): always complete control requests, even on a bad reply o…
serialexperimentslainnnn Sep 23, 2026
27196f6
perf(page): patch the composer strip only when it changes and cycle v…
serialexperimentslainnnn Sep 23, 2026
1bf03df
fix(page): make menus, controls and the composer usable from the keyb…
serialexperimentslainnnn Sep 23, 2026
760f58a
fix(page): keep focus and current data across dashboard and tab re-re…
serialexperimentslainnnn Sep 23, 2026
cc1d3d4
fix(page): mark a settings row pending until the host confirms it
serialexperimentslainnnn Sep 23, 2026
3a04451
fix(page): open tool-card results at the first line of the new search…
serialexperimentslainnnn Sep 23, 2026
66f273e
test(page): follow the host calls into the frontend module and the na…
serialexperimentslainnnn Sep 23, 2026
d3789d3
fix(settings): source the environment script with the POSIX shell
serialexperimentslainnnn Sep 23, 2026
ef0be79
fix(process): decode the sign-in output as a stream and scan only its…
serialexperimentslainnnn Sep 23, 2026
1a46a63
fix(vuln): bound the vulnerability database body in time and size
serialexperimentslainnnn Sep 23, 2026
e188ab5
fix(context): let cancellation through the link index lookups
serialexperimentslainnnn Sep 23, 2026
60b3304
perf(session): start the MCP helper JVMs small and from the one jar t…
serialexperimentslainnnn Sep 23, 2026
7b28595
fix(page): rebuild changed permission cards, resolve each once and ex…
serialexperimentslainnnn Sep 23, 2026
558eec9
fix(page): forward only openable links to the host, middle clicks inc…
serialexperimentslainnnn Sep 23, 2026
3669c05
refactor(chat): reach MCP through the session layer and repaint chats…
serialexperimentslainnnn Sep 23, 2026
cfd3b6b
perf(chat): restore open chats after the settings load off the EDT
serialexperimentslainnnn Sep 23, 2026
00f691a
test(git): find the gear menu's wiring in the chat gear group
serialexperimentslainnnn Sep 23, 2026
41a6186
build(rpc): let the chat contract return flows from suspend calls
serialexperimentslainnnn Sep 23, 2026
0161709
fix(page): type permission markdown as the fragment it now returns
serialexperimentslainnnn Sep 23, 2026
de94a32
refactor(frontend): move the page sources and assets into the fronten…
serialexperimentslainnnn Sep 23, 2026
2a6cf68
test(guard): read the page sources from the frontend module
serialexperimentslainnnn Sep 23, 2026
1e797ef
fix(git): run the Git view's IDE actions in the frontend with the too…
serialexperimentslainnnn Sep 23, 2026
08fb7aa
build: bump the version to 6.5.0
serialexperimentslainnnn Sep 23, 2026
74a5fdf
docs: document Remote Development and the 2026.2 floor
serialexperimentslainnnn Sep 23, 2026
f6ea731
docs: add the 6.5.0 changelog and release notes
serialexperimentslainnnn Sep 23, 2026
69b8083
docs: state the 2026.2 floor and the module layout in the agent runbo…
serialexperimentslainnnn Sep 23, 2026
8628c36
refactor(session): remove the page-failure fallback nothing calls sin…
serialexperimentslainnnn Sep 23, 2026
747cd7c
build: compile the backend from the root sources and declare the opti…
serialexperimentslainnnn Sep 23, 2026
268c9a8
refactor(git): reach Git4Idea through the optional Git content module
serialexperimentslainnnn Sep 23, 2026
3fff4e4
refactor(github): reach the GitHub plugin through the optional GitHub…
serialexperimentslainnnn Sep 23, 2026
7c5dd0d
refactor(mcp): serve UAST and IntelliLang injection from optional con…
serialexperimentslainnnn Sep 23, 2026
8699e46
fix(terminal): open the sign-in and install terminal on the client th…
serialexperimentslainnnn Sep 23, 2026
992d038
perf(mcp): put a ceiling on the max of the remaining tools
serialexperimentslainnnn Sep 23, 2026
51b97be
build: bump the Gradle version to 6.5.0 and say the Code With Me chat…
serialexperimentslainnnn Sep 23, 2026
41804e3
build: register tasks without the delegates Gradle 9.6 deprecated
serialexperimentslainnnn Sep 23, 2026
07caefd
fix(build): compile against 2026.2 where the first build broke
serialexperimentslainnnn Sep 23, 2026
07f55c6
test(permission): drop the null checks Kotlin 2.4 proves redundant
serialexperimentslainnnn Sep 23, 2026
70d72c8
fix(build): declare the 2026.2 platform modules the backend and the G…
serialexperimentslainnnn Sep 23, 2026
650974e
fix(session): drop orphan outputs from a restore window read from the…
serialexperimentslainnnn Sep 23, 2026
af97b81
fix(process): close the dead CLI's stdin through the one teardown hel…
serialexperimentslainnnn Sep 23, 2026
501cbd5
refactor(context): remove the unreachable image-from-file reader
serialexperimentslainnnn Sep 23, 2026
cbda70a
test(guard): follow the guard view's wiring into the chat presenter a…
serialexperimentslainnnn Sep 23, 2026
67e72ef
test: read the content module descriptors and the frontend's page sou…
serialexperimentslainnnn Sep 23, 2026
c004895
build: compile the root tests with the serialization plugin
serialexperimentslainnnn Sep 23, 2026
0e57e41
refactor(process): declare the terminal host as a plain interface
serialexperimentslainnnn Sep 23, 2026
4a1e8f0
fix(page): link a read at the start of its range and align the page c…
serialexperimentslainnnn Sep 23, 2026
f4f3749
fix(build): name the module jars after their content modules and load…
serialexperimentslainnnn Sep 23, 2026
b2ac36c
style: apply the project formatter
serialexperimentslainnnn Sep 23, 2026
8580240
build(detekt): migrate the configuration to detekt 2.0
serialexperimentslainnnn Sep 23, 2026
91057e8
refactor(mcp): catch frame and batch-item failures without a generic …
serialexperimentslainnnn Sep 23, 2026
429cd4c
refactor(rpc): catch chat host failures without a generic catch
serialexperimentslainnnn Sep 23, 2026
dfd75b3
refactor(language): resolve the injection target in its own step
serialexperimentslainnnn Sep 23, 2026
39d4cdb
refactor(vcs): split the git write gateway into working-copy and repo…
serialexperimentslainnnn Sep 23, 2026
72c0995
refactor(window): move the frontend channel pushes out of the chat pr…
serialexperimentslainnnn Sep 23, 2026
b23159a
refactor: clear the line length, loop jump and magic number findings
serialexperimentslainnnn Sep 23, 2026
4fe0bf9
style(window): wrap the dropped page call warning within the line limit
serialexperimentslainnnn Sep 23, 2026
222f7e3
build(coverage): measure with JaCoCo 0.8.15, which reads the Java 25 …
serialexperimentslainnnn Sep 23, 2026
0450d68
build(coverage): record platform-loaded plugin classes with JaCoCo an…
serialexperimentslainnnn Sep 23, 2026
bc91091
test(rpc): cover the chat contract and the backend chat service
serialexperimentslainnnn Sep 23, 2026
c5292bd
style: apply the project formatter
serialexperimentslainnnn Sep 23, 2026
d9d8cd0
fix(frontend): depend on the intellij.platform.ui.jcef content module…
serialexperimentslainnnn Sep 23, 2026
92f87d5
fix(window): serve the chat options menu from the host over ChatApi s…
serialexperimentslainnnn Sep 24, 2026
86fb2d8
fix(session): select the open tab instead of duplicating a saved sess…
serialexperimentslainnnn Sep 24, 2026
fa8b6dc
fix(window): keep the client's tabs, focus and pushes in step with th…
serialexperimentslainnnn Sep 24, 2026
6f5e6b7
fix(clipboard): read the clipboard on the client with the wl-paste an…
serialexperimentslainnnn Sep 24, 2026
6229772
fix(modules): load the IntelliLang module through intellij.platform.l…
serialexperimentslainnnn Sep 24, 2026
64c9f8a
fix(session): read the dashboard's account off the EDT
serialexperimentslainnnn Sep 24, 2026
8fd1aa8
fix(database): depend on the intellij.database content modules that h…
serialexperimentslainnnn Sep 24, 2026
e773e95
fix(mcp): offer the Problems view tools only where this IDE lets the …
serialexperimentslainnnn Sep 24, 2026
01768c8
fix(guard): let the IDE's scratch folder pass the outside-project rul…
serialexperimentslainnnn Sep 24, 2026
ee72d85
fix(mcp): read the Problems view through the problemView plugin's mod…
serialexperimentslainnnn Sep 24, 2026
c30b433
refactor(mcp): drop ProblemsViewApi, which ProblemsViewAccess replaces
serialexperimentslainnnn Sep 24, 2026
b942ce4
fix(mcp): reach the Problems tool window through ProblemsViewAccess s…
serialexperimentslainnnn Sep 24, 2026
4fc35d5
fix(mcp): tell plugins callers that IDE modules such as IntelliLang a…
serialexperimentslainnnn Sep 24, 2026
0329a37
fix(mcp): create a scratch under its exact name unless that exact nam…
serialexperimentslainnnn Sep 24, 2026
8497382
fix(mcp): report the language the IDE resolved for a new scratch, or …
serialexperimentslainnnn Sep 24, 2026
030fc40
docs: complete the 6.5.0 changelog and release notes and stamp them f…
serialexperimentslainnnn Sep 24, 2026
bc3102c
build(prettier): ignore the vendored page bundles where the split mov…
serialexperimentslainnnn Sep 24, 2026
c700666
style(page): apply Prettier to the page sources and tests
serialexperimentslainnnn Sep 24, 2026
c64e2dd
feat(chat): show a shell call's command as its own copyable block, ap…
serialexperimentslainnnn Sep 24, 2026
68af35d
docs: recommend the skills and settings repository, describe the IDE …
serialexperimentslainnnn Oct 2, 2026
17937cb
fix: name the claude-code-native repository in the plugin's user agent
serialexperimentslainnnn Oct 2, 2026
7026d19
docs: stamp the 6.5.0 changelog and release notes for today
serialexperimentslainnnn Oct 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 5 additions & 5 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ What actually happened. Include error messages verbatim.

## Environment

> From **5.5.0** the minimum supported IDE is **2025.3 (build 253)**. The whole chat UI is the IDE's
> embedded browser, and the module that provides it does not exist before 253. On 2025.1 or 2025.2 the
> last supported version is **5.1.1** — a bug report against 5.5.0 on those builds is expected behaviour,
> not a defect.
> From **6.5.0** the minimum supported IDE is **2026.2 (build 262.8665.258)**. On 2025.3 or 2026.1 the
> last supported version is **6.0.1**; on 2025.1 or 2025.2 it is **5.1.1**. A bug report against 6.5.0 on
> an older build is expected behaviour, not a defect. In Remote Development, say whether the plugin is
> installed on the host, the client, or both.

- **OS:** (e.g. Ubuntu 24.04, macOS 14.5, Windows 11 23H2)
- **IDE:** (Help → About → product + build, e.g. `IntelliJ IDEA 2025.3 IC-253.28294.334`)
- **IDE:** (Help → About → product + build, e.g. `IntelliJ IDEA 2026.2.3 IU-262.10968.63`)
- **Plugin version:** (Settings → Plugins → Claude Code Native)
- **`claude` binary version:** output of `claude --version`
- **Binary location:** `which claude` (Linux/macOS) or `where claude` (Windows)
Expand Down
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ contact_links:

# TODO: replace with the GitHub Discussions URL once enabled for the repo.
- name: GitHub Discussions
url: https://github.com/serialexperimentslainnnn/claude-code-for-jetbrains/discussions
url: https://github.com/serialexperimentslainnnn/claude-code-native/discussions
about: Ask a question, share a workflow, or discuss ideas before filing an issue.

- name: Security vulnerability
url: https://github.com/serialexperimentslainnnn/claude-code-for-jetbrains/security/advisories/new
url: https://github.com/serialexperimentslainnnn/claude-code-native/security/advisories/new
about: Do NOT open a public issue. Report it privately here; see SECURITY.md.
4 changes: 2 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ or the permission surface, say what happens to a user who already ran it.
- [ ] Commits follow Conventional Commits (the `commit-msg` hook enforces it —
install once with `git config core.hooksPath .githooks`).
- [ ] `./gradlew test verifyPlugin buildPlugin` passes locally.
- [ ] `verifyPlugin` is **Compatible** across the declared range (253 → 263.\*)
- [ ] `verifyPlugin` is **Compatible** across the declared range (262.8665.258 → 263.\*)
and reports no new internal-API usage (`@ApiStatus.Internal`).
The CDN download is unreliable here; use
`-PlocalIdePath=<dir>[,<dir>…]` with locally-extracted IDEs.
Expand All @@ -45,7 +45,7 @@ or the permission surface, say what happens to a user who already ran it.
- [ ] No new deprecated or scheduled-for-removal IntelliJ Platform APIs.
- [ ] Tests added or updated for the new behaviour — `src/test/kotlin/…` for
Kotlin, `src/test/frontend/…` (`npm test`) for anything under
`src/main/resources/jcef/`.
`frontend/src/main/resources/jcef/` or `frontend/src/main/ts/`.
- [ ] Protocol changes: `./gradlew checkDrift` is green and the baseline in
`scripts/drift-baseline.properties` matches what was verified.
- [ ] New dependency? Its licence is compatible with GPL-3.0-only and it is
Expand Down
16 changes: 4 additions & 12 deletions .github/ci-image/jvm-test.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,14 @@

# Declared before FROM so it can be used there. The default names this repository's own package; a fork
# overrides it with --build-arg rather than editing the file.
ARG NODE_IMAGE=ghcr.io/serialexperimentslainnnn/node-test:v1.0.0
ARG NODE_IMAGE=ghcr.io/serialexperimentslainnnn/node-test:v1.1.0
FROM ${NODE_IMAGE}

# NB there is no dnf tuning here and that is not an omission: `max_parallel_downloads=20` and
# `fastestmirror=True` were written into /etc/dnf/dnf.conf by node-test, and this image starts from its
# filesystem — so the JDK transaction below already runs with them. Adding the lines again would append a
# SECOND copy of each key to dnf.conf rather than overriding anything.
#
# Temurin, not Fedora's OpenJDK.
#
# Fedora 44 no longer packages java-21-openjdk — it has moved on to a newer LTS — and the JDK version is not
# ours to float: build.gradle.kts pins the toolchain to 21 because the IDE runs on JBR 21, which is the
# ceiling. Building on 25 would produce class files no target IDE can load. Adoptium's repository is the
# same source the `setup-java` action uses on the hosted runners, so the image and the pipeline compile
# against the same JDK rather than two different builds of "21".
#
# There is deliberately no `dnf-plugins-core`: nothing here calls `dnf config-manager` — the repo file is
# written with `printf` — and `curl` is already in the base image, so installing it dragged in a ~150 MB
# Python stack to run a command nobody ran.
Expand All @@ -81,7 +73,7 @@ RUN curl -fsSL https://packages.adoptium.net/artifactory/api/gpg/key/public \
'gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Adoptium' \
> /etc/yum.repos.d/adoptium.repo \
&& dnf -y --setopt=install_weak_deps=False --setopt=tsflags=nodocs install \
temurin-21-jdk \
temurin-25-jdk \
python3 \
zip \
&& dnf clean all \
Expand Down Expand Up @@ -125,9 +117,9 @@ RUN dnf -y --setopt=install_weak_deps=False --setopt=tsflags=nodocs install \
# silently break on the next base-image bump. The symlink keeps the ENV below stable across rebuilds.
RUN JH="$(dirname "$(dirname "$(readlink -f "$(command -v javac)")")")" \
&& echo "JAVA_HOME=$JH" >> /etc/environment \
&& ln -sfn "$JH" /opt/java-21 \
&& ln -sfn "$JH" /opt/java-25 \
&& "$JH/bin/java" -version
ENV JAVA_HOME=/opt/java-21
ENV JAVA_HOME=/opt/java-25
ENV PATH="${JAVA_HOME}/bin:${PATH}"

# Gradle writes here, and the path MUST match GRADLE_USER_HOME in the workflow. If they diverge, the warm
Expand Down
6 changes: 3 additions & 3 deletions .github/ci-image/node-test.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
# BUILDING — from the repository ROOT, so /.dockerignore applies:
#
# docker build -f .github/ci-image/node-test.Dockerfile \
# -t ghcr.io/OWNER/node-test:v1.0.0 .
# docker push ghcr.io/OWNER/node-test:v1.0.0
# -t ghcr.io/OWNER/node-test:v1.1.0 .
# docker push ghcr.io/OWNER/node-test:v1.1.0
#
# The tag is `vMAJOR.MINOR.PATCH`, never `latest`: a floating tag makes "which image was that job green on?"
# unanswerable, and this repository's standard is to pin. Bumping it is a commit — change the tag here and
Expand Down Expand Up @@ -49,7 +49,7 @@ RUN echo "max_parallel_downloads=20" >> /etc/dnf/dnf.conf \
# not, and bumping the tag is the deliberate act that moves it.
RUN dnf -y upgrade --refresh \
&& dnf -y --setopt=install_weak_deps=False --setopt=tsflags=nodocs install \
nodejs npm \
nodejs24 nodejs24-bin nodejs24-npm nodejs24-npm-bin \
git-core unzip tar which findutils procps-ng ca-certificates \
&& dnf clean all \
&& rm -rf /var/cache/dnf \
Expand Down
67 changes: 25 additions & 42 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,14 @@ jobs:
# EVERY job in this file runs in this image, and the image is the ONLY caching mechanism.
#
# `gradle/actions/setup-gradle` used to sit in the heavy jobs and was quietly useless here: the warm
# GRADLE_USER_HOME measures 31 GB (23 GB of extracted IDE transforms under caches/9.5.1, 7.7 GB of the
# GRADLE_USER_HOME measures 31 GB (23 GB of extracted IDE transforms under caches/9.7.1, 7.7 GB of the
# downloaded IDE artifacts under modules-2), and a GitHub Actions cache entry is capped at 10 GB per
# repository. It could never have stored what it appeared to be storing — it was saving a partial
# cache, evicting it, and re-downloading the rest on the next run. The image has no such ceiling, and
# the trade is explicit: refreshing what CI has cached now means rebuilding and pushing the image,
# which is a deliberate act rather than something that drifts between runs.
container:
image: ghcr.io/serialexperimentslainnnn/jvm-test:v1.0.0
image: ghcr.io/serialexperimentslainnnn/jvm-test:v1.1.0
# The package stays PRIVATE and is pulled with the run's own GITHUB_TOKEN — no new secret, nothing to
# rotate, and access dies with the job. This requires the package to have been granted Read access to
# THIS repository (package settings -> Manage Actions access): `packages: read` widens what the token
Expand Down Expand Up @@ -158,7 +158,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 20
container:
image: ghcr.io/serialexperimentslainnnn/jvm-test:v1.0.0
image: ghcr.io/serialexperimentslainnnn/jvm-test:v1.1.0
# The package stays PRIVATE and is pulled with the run's own GITHUB_TOKEN — no new secret, nothing to
# rotate, and access dies with the job. `packages: read` is granted per job below; without it the pull
# fails with a 401 that reads like a wrong image name rather than a permission problem.
Expand Down Expand Up @@ -229,7 +229,7 @@ jobs:
build/reports/kover/
retention-days: 14

# The JCEF web app (src/main/resources/jcef/*.js) under vitest + jsdom. Nothing here ships in the
# The JCEF web app (frontend/src/main/resources/jcef/*.js) under vitest + jsdom. Nothing here ships in the
# plugin — vitest and jsdom are devDependencies — but the code under test absolutely does.
frontend-test:
name: Frontend tests
Expand All @@ -239,7 +239,7 @@ jobs:
# `node-test`, not `jvm-test`: this job is `npm ci` and then vitest. On the single combined image it
# pulled a JDK, a Gradle distribution and 3.4 GB of extracted IntelliJ Platform it never opened —
# 1m05s of container init for 8 seconds of work.
image: ghcr.io/serialexperimentslainnnn/node-test:v1.0.0
image: ghcr.io/serialexperimentslainnnn/node-test:v1.1.0
# The package stays PRIVATE and is pulled with the run's own GITHUB_TOKEN — no new secret, nothing to
# rotate, and access dies with the job. `packages: read` is granted per job below; without it the pull
# fails with a 401 that reads like a wrong image name rather than a permission problem.
Expand Down Expand Up @@ -283,7 +283,7 @@ jobs:
timeout-minutes: 10
container:
# `node-test`: this job is `npm ci` and two `npm audit` invocations. Nothing here touches the JVM.
image: ghcr.io/serialexperimentslainnnn/node-test:v1.0.0
image: ghcr.io/serialexperimentslainnnn/node-test:v1.1.0
# The package stays PRIVATE and is pulled with the run's own GITHUB_TOKEN — no new secret, nothing to
# rotate, and access dies with the job. `packages: read` is granted per job below; without it the pull
# fails with a 401 that reads like a wrong image name rather than a permission problem.
Expand Down Expand Up @@ -389,7 +389,7 @@ jobs:
# Same image as every other job, and it does NOT carry the IDEs this job downloads — see the note at
# the top of .github/ci-image/jvm-test.Dockerfile. Baking them made the image 38.1 GB, which every job paid for
# on its own runner, to save ten minutes on the one job that runs least often.
image: ghcr.io/serialexperimentslainnnn/jvm-test:v1.0.0
image: ghcr.io/serialexperimentslainnnn/jvm-test:v1.1.0
# The package stays PRIVATE and is pulled with the run's own GITHUB_TOKEN — no new secret, nothing to
# rotate, and access dies with the job. `packages: read` is granted per job below; without it the pull
# fails with a 401 that reads like a wrong image name rather than a permission problem.
Expand Down Expand Up @@ -522,13 +522,22 @@ jobs:
run: |
zip=$(ls build/distributions/*.zip)
unzip -o -q "$zip" -d /tmp/artifact
jar=$(ls /tmp/artifact/*/lib/claude-code-native-*.jar | grep -v searchableOptions)
# -1 lists entry names alone; directory entries end in `/` and carry nothing.
unzip -Z -1 "$jar" | grep -v '/$' \
| grep -vE '^dev/lain/claudejb/.*\.class$' \
| grep -vE '^META-INF/' \
| grep -vE '^icons/[^/]+\.svg$' \
| grep -vE '^jcef/(.+\.(js|html)|css/.+\.css)$' > /tmp/unexpected.txt || true
ls /tmp/artifact/*/lib/dev.lain.claudejb-*.jar /tmp/artifact/*/lib/modules/dev.lain.claudejb.*.jar 2>/dev/null \
| grep -v searchableOptions > /tmp/jars.txt || true
if [ "$(wc -l < /tmp/jars.txt)" -lt 4 ]; then
echo "::error::expected the plugin jar and the shared, frontend and backend module jars"
find /tmp/artifact -name '*.jar'
exit 1
fi
: > /tmp/unexpected.txt
while IFS= read -r jar; do
unzip -Z -1 "$jar" | grep -v '/$' \
| grep -vE '^dev/lain/claudejb/.*\.class$' \
| grep -vE '^META-INF/' \
| grep -vE '^dev\.lain\.claudejb\.(shared|frontend|backend|git|github|java|intellilang|terminal|bookmarks|database|problems)\.xml$' \
| grep -vE '^icons/[^/]+\.svg$' \
| grep -vE '^jcef/(.+\.(js|html)|css/.+\.css)$' >> /tmp/unexpected.txt || true
done < /tmp/jars.txt
if [ -s /tmp/unexpected.txt ]; then
echo "::error::unexpected entries in the plugin jar — either they must not ship, or add their family to this allowlist"
cat /tmp/unexpected.txt
Expand Down Expand Up @@ -556,7 +565,7 @@ jobs:

zip=$(ls build/distributions/*.zip)
unzip -o -q "$zip" -d /tmp/dist
jar=$(ls /tmp/dist/*/lib/claude-code-native-*.jar | grep -v searchableOptions | head -1)
jar=$(ls /tmp/dist/*/lib/dev.lain.claudejb-*.jar | grep -v searchableOptions | head -1)

# ONE listing, read by every assertion below. `-Z1` prints one entry name per line, so names are
# matched WHOLE (`grep -qxF`) instead of as substrings of `unzip -l`'s formatted table — where
Expand Down Expand Up @@ -627,7 +636,7 @@ jobs:
# dead IDE into a fast, explained failure instead of letting it eat the whole budget.
timeout-minutes: 45
container:
image: ghcr.io/serialexperimentslainnnn/jvm-test:v1.0.0
image: ghcr.io/serialexperimentslainnnn/jvm-test:v1.1.0
# The package stays PRIVATE and is pulled with the run's own GITHUB_TOKEN — no new secret, nothing to
# rotate, and access dies with the job. `packages: read` is granted per job below; without it the pull
# fails with a 401 that reads like a wrong image name rather than a permission problem.
Expand All @@ -652,32 +661,6 @@ jobs:
with:
persist-credentials: false

# The image running this job carries no X11 whatsoever: it was built for headless Gradle and npm, and
# nothing in it has ever had to draw. This is the one job that does — a real IDE, with a real Chromium
# inside it.
#
# .github/ci-image/jvm-test.Dockerfile ALREADY bakes this exact package set, which is where it belongs:
# the image is this pipeline's only caching mechanism, so a `dnf install` per run is a network
# transaction whose failure mode is this job's worst one. This step survives because every workflow
# pins `jvm-test:v1.0.0`, and that tag names an image built BEFORE the Dockerfile gained the stack. A
# Dockerfile edit changes nothing on its own; the image has to be rebuilt and a new tag cut.
#
# DELETE THIS STEP in the same change that bumps the tag — in every workflow that names it, not just
# this one (ci.yml ×4, release.yml, codeql.yml, drift.yml). Leaving it behind costs one redundant
# install per nightly run; deleting it BEFORE the tag moves costs an IDE that never opens its port.
#
# A missing library here does not announce itself — the IDE simply never opens :8082 — which is exactly
# the silence the bounded wait below turns back into a message.
- name: Install the virtual display and the libraries the IDE draws through
run: |
set -euo pipefail
dnf -y --setopt=install_weak_deps=False --setopt=tsflags=nodocs install \
xorg-x11-server-Xvfb \
gtk3 nss alsa-lib mesa-libgbm libxkbcommon-x11 \
libXtst libXi libXrender libXext libXrandr libXcursor \
liberation-fonts
dnf clean all

# Step one of the two-process dance that build.gradle.kts and docs/UI_TESTING.md both document: the IDE
# comes up under Xvfb and STAYS UP, and the suite is a second Gradle invocation that talks to it over
# :8082. Backgrounded here rather than split into a second job, because the two halves must share a host.
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
timeout-minutes: 45
container:
# `jvm-test`: the manual build is `./gradlew classes`, which resolves the whole IntelliJ Platform.
image: ghcr.io/serialexperimentslainnnn/jvm-test:v1.0.0
image: ghcr.io/serialexperimentslainnnn/jvm-test:v1.1.0
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -58,11 +58,11 @@ jobs:
with:
persist-credentials: false

# No `setup-java` step: the image already carries the Temurin 21 the rest of the pipeline builds
# No `setup-java` step: the image already carries the Temurin 25 the rest of the pipeline builds
# with. Provisioning a second JDK here meant CodeQL analysed a build that used a different one.

- name: Initialize CodeQL
uses: github/codeql-action/init@18420e3271f74589575af831a523c833acda327f # codeql-bundle-v2.26.2
uses: github/codeql-action/init@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
with:
languages: java-kotlin
build-mode: manual
Expand Down Expand Up @@ -160,7 +160,7 @@ jobs:
run: ./gradlew --no-daemon --stacktrace classes

- name: Analyze
uses: github/codeql-action/analyze@18420e3271f74589575af831a523c833acda327f # codeql-bundle-v2.26.2
uses: github/codeql-action/analyze@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
with:
category: /language:java-kotlin

Expand All @@ -177,13 +177,13 @@ jobs:
persist-credentials: false

- name: Initialize CodeQL
uses: github/codeql-action/init@18420e3271f74589575af831a523c833acda327f # codeql-bundle-v2.26.2
uses: github/codeql-action/init@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
with:
languages: javascript-typescript
build-mode: none
queries: security-extended

- name: Analyze
uses: github/codeql-action/analyze@18420e3271f74589575af831a523c833acda327f # codeql-bundle-v2.26.2
uses: github/codeql-action/analyze@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
with:
category: /language:javascript-typescript
2 changes: 1 addition & 1 deletion .github/workflows/drift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
timeout-minutes: 30
container:
# `jvm-test`: this job runs `npm install` and the global claude CLI install AND `./gradlew checkDrift`.
image: ghcr.io/serialexperimentslainnnn/jvm-test:v1.0.0
image: ghcr.io/serialexperimentslainnnn/jvm-test:v1.1.0
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ jobs:
# gate could pass or fail on a toolchain the pull request never saw.
container:
# `jvm-test`: this gate runs `npm ci`, `npm test` AND `./gradlew test verifyPlugin` in one job.
image: ghcr.io/serialexperimentslainnnn/jvm-test:v1.0.0
image: ghcr.io/serialexperimentslainnnn/jvm-test:v1.1.0
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
Expand Down Expand Up @@ -396,10 +396,10 @@ jobs:
with:
node-version-file: .nvmrc

- uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0
- uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1
with:
distribution: temurin
java-version: '21'
java-version: '25'

# NB no `setup-gradle`, deliberately, and this was the last one left in any workflow.
#
Expand Down Expand Up @@ -450,7 +450,7 @@ jobs:
echo "published $name sha256=$(sha256sum "dist/$name" | cut -d' ' -f1)"

- name: Attest build provenance
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-path: dist/${{ steps.artifact.outputs.name }}

Expand Down
Loading
Loading