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
182 changes: 182 additions & 0 deletions .claude/commands/icr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
---
description: Run an Interactive Code Review (ICR) session inside the running Eclipse (BlueMind Dev Tools)
argument-hint: "[--source <branch>] [--repo <path>]"
---

Run an Interactive Code Review (ICR) session **inside the running Eclipse** (BlueMind Developer
Tools plugin). The user selects code in an Eclipse editor, right-clicks **Ask Claude (ICR)…**, and
types a question or change request. You listen for these via the plugin's MCP server, act on each one
(answer and/or edit the file), and post a reply that appears inline in Eclipse as a comment thread.

## Usage

```
/icr [--source <branch>] [--repo <path>]
```

- `--source`: branch the review is framed against (e.g. `master`). Optional context only — the user
can comment on any selection in any file, not just the diff.
- `--repo`: repository path (default: current working directory).

This reuses the always-on Eclipse MCP server (the same one documented in
`net.bluemind.devtools/docs/CLAUDE_CODE_MCP.md`). There is no separate server to start — `icr_start`
simply opens a review session and enables the editor menu.

## Architecture — a thin dispatcher, one agent per thread

The main Claude session must stay free. It does **not** run the poll loop and it does **not** handle
threads itself. Instead:

1. It launches a **background poller** that long-polls `icr_next` until a thread arrives, prints it,
and exits (Step 3). While it polls, your main session is idle and usable.
2. When a thread arrives, the main session **spawns a fresh subagent to handle just that one thread**
(Step 4), waits for it, then **re-arms the poller** and goes back to idle.

Threads are dispatched **serially** — one subagent at a time — which keeps concurrent edits to the
same file from colliding. Threads posted while a subagent is working are queued server-side (not
lost) and delivered on the next poll. Each subagent gets a clean, focused context (just its thread),
so long review sessions never accumulate context or hit turn/token limits.

## What to do

### Step 1 — Locate the Eclipse MCP endpoint

Parse `$ARGUMENTS` for `--source` and `--repo` (default `--repo` to the current working directory).

Find the config of the Eclipse open on this workspace and extract `url` + `token`:

```bash
# There may be several if multiple Eclipse instances run (one per branch). Prefer the one whose
# "workspace"/"projects" match the repo under review; otherwise take the first.
ls ~/.config/bluemind/mcp/eclipse-*.json
CFG=$(ls ~/.config/bluemind/mcp/eclipse-*.json | head -1)
URL=$(jq -r .url "$CFG")
TOKEN=$(jq -r .token "$CFG")
```

If no config exists, tell the user to enable **Window → Preferences → BlueMind → "Enable MCP server
for Claude Code"** and that the plugin must be installed/running, then stop.

Note the resolved `URL` and `TOKEN` — you'll pass them to each per-thread subagent (Step 4). Define a
helper for the calls you make directly from the main session (`icr_start`, `icr_stop`):

```bash
icr() { # $1=tool name, $2=arguments JSON object
curl -s -X POST "$URL" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
--max-time 60 \
-d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",\"params\":{\"name\":\"$1\",\"arguments\":$2}}" \
| jq -r '.result.content[0].text'
}
```

### Step 2 — Start the session

```bash
icr icr_start '{"source":"<source-or-empty>","repo":"<repo>"}'
```

This enables the **Ask Claude (ICR)…** context menu in Eclipse and re-queues any thread still
awaiting an answer. Tell the user:

> ICR session active. In Eclipse, select code → right-click **Ask Claude (ICR)…** (or `Ctrl+Alt+C`)
> to leave a question or change request. I'll handle each one in a dedicated agent and reply inline.

### Step 3 — Listen with a background poller

Run the poll loop **in the background** so the main session isn't blocked. The poller long-polls
`icr_next`, keeps looping while the status is `idle`, and prints the payload + exits as soon as the
status is anything else (`thread` or `inactive`). Its exit re-invokes the main session to dispatch.

Launch this with `run_in_background: true`:

```bash
CFG=$(ls ~/.config/bluemind/mcp/eclipse-*.json | head -1)
URL=$(jq -r .url "$CFG"); TOKEN=$(jq -r .token "$CFG")
while :; do
RESP=$(curl -s -X POST "$URL" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" --max-time 60 \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"icr_next","arguments":{}}}' \
| jq -c '.result.content[0].text | fromjson')
[ "$(echo "$RESP" | jq -r '.status // "idle"')" != "idle" ] && { echo "$RESP"; break; }
done
```

When it exits:

- Payload `{"status":"inactive"}` → the session was stopped in Eclipse. Go to Step 5.
- Payload `{"status":"thread","thread":{…}}` → dispatch it (Step 4), then **relaunch this poller**.

### Step 4 — Dispatch one subagent per thread

Do **not** handle the thread in the main session. Spawn a subagent (Agent tool) whose entire job is
that one thread, and wait for it. Then relaunch the poller (Step 3). Give the subagent this brief,
with `URL`, `TOKEN`, `<repo>`, and the verbatim `thread` JSON substituted in:

> You are handling one Interactive Code Review thread inside a running Eclipse. Endpoint: `URL` /
> bearer token `TOKEN`. Repo: `<repo>`.
>
> Thread JSON: `<thread>`
>
> The thread has: `id`, `filePath` (workspace-relative, e.g. `/net.bluemind.foo/src/Foo.java`),
> `absolutePath`, `startLine`, `endLine`, `selectedText`, `body` (the user's request), `status`, and
> `replies` (the full conversation on this thread; the last entry is the user's latest message).
>
> 1. Read the file (use `absolutePath`) around `startLine`–`endLine`, using `selectedText` as the
> precise anchor.
> 2. Decide from `body` and `replies`:
> - **A question / clarification** → answer it.
> - **A change request** → edit the file, then recompile in Eclipse when warranted (see fast-mode
> rules below). Derive the Eclipse project from the first segment of `filePath` (e.g.
> `net.bluemind.foo`) and call `refresh_projects`; inspect `get_problems` and fix compile errors
> before replying.
> - **Both** → make the edit first, then answer.
> 3. Post your reply (markdown, rendered in the Eclipse popup). Reference the earlier exchange; if you
> changed code, summarize what you did.
>
> Call MCP tools with curl, e.g.:
> ```bash
> icr() { curl -s -X POST "$URL" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
> --max-time 60 \
> -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",\"params\":{\"name\":\"$1\",\"arguments\":$2}}" \
> | jq -r '.result.content[0].text'; }
> icr refresh_projects '{"projects":["net.bluemind.foo"]}'
> icr icr_reply '{"threadId":"<id>","body":"<your markdown reply>"}'
> ```
> Follow the **Keeping replies fast** rules below. Your final message is not shown to the user — the
> reply the user sees is the one you post with `icr_reply`.

When the subagent returns, relaunch the poller (Step 3).

### Step 5 — Stop

When the user says they are done, or the poller returned `{"status":"inactive"}`:

```bash
icr icr_stop '{}'
```

This ends the session and disables the menu. Existing `💬` threads stay visible in open editors.

## Keeping replies fast (default: fast mode)

These rules are part of the brief handed to each per-thread subagent (Step 4). Replies feel slow in
Eclipse not because of long polling (that delivers a thread the instant it's posted) but because of
the work done *after* the thread arrives: source verification, Eclipse recompiles, and
multi-paragraph reply generation. Threads are also handled **serially** — the next poll only resumes
after the current reply is posted — so long turnarounds compound.

Default to a lean loop optimized for responsiveness:

- **Keep replies short.** A few sentences, not essays. This is the single biggest lever on latency.
Expand only when the user asks for detail.
- **For questions, answer directly** from the code you can already see. Skip `ack`/cross-file
verification unless the answer is non-obvious or you'd otherwise be guessing.
- **For change requests, still edit correctly**, but only recompile (`refresh_projects` +
`get_problems`) when the edit is non-trivial or could plausibly break compilation. Skip the
recompile for trivial edits (comments, renames within a scope, string/message tweaks) and say so.
- Don't over-explain the tooling or narrate steps — just do the work and reply.

If the user asks for thoroughness (verify before answering, always recompile, detailed rationale),
switch back to the careful mode for the rest of the session.
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# BlueMind Developer Tools — Plugin Eclipse

Plugin Eclipse pour le développement BlueMind. Il fournit quatre fonctionnalités :
Plugin Eclipse pour le développement BlueMind. Il fournit cinq fonctionnalités :

- **Lancement rapide des tests** : clic droit sur un projet `*.tests` pour lancer les JUnit Plugin Tests avec une configuration préconfigurée.
- **Synchronisation POM → workspace** : détecte automatiquement les changements dans `open/global/pom.xml` (via inotify) et propose de mettre à jour la configuration Eclipse en conséquence.
- **Serveur MCP pour Claude Code** : expose un endpoint HTTP JSON-RPC local (loopback + token) permettant à Claude Code de déclencher des tests dans l'Eclipse qui tourne et de récupérer stdout/stderr + outcome. Voir [docs/CLAUDE_CODE_MCP.md](net.bluemind.devtools/docs/CLAUDE_CODE_MCP.md).
- **Vue « Branch Changed Files »** : liste les fichiers modifiés sur la branche courante par rapport au merge-base avec l'upstream (committed / staged / unstaged), avec ouverture du fichier ou de l'éditeur de comparaison. Menu *Window → Show View → BlueMind → Branch Changed Files*.
- **Interactive Code Review (ICR)** : revue de code interactive native. On sélectionne du code dans un éditeur, *clic droit → Ask Claude (ICR)…* (ou `Ctrl+Alt+C`) pour poser une question ou demander une modification ; Claude (skill `/icr`) écoute via le serveur MCP, agit, et répond inline sous forme de fil de commentaires (glyphe `💬`). Voir [docs/CLAUDE_CODE_MCP.md](net.bluemind.devtools/docs/CLAUDE_CODE_MCP.md) §5.

## Installation

Expand Down Expand Up @@ -56,6 +57,35 @@ Format : une option par ligne, `#` pour les commentaires.
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
```

## Code Review interactif (ICR) — skill `/icr`

La revue de code interactive est pilotée depuis Claude Code par la commande `/icr`. Cette commande
est fournie dans ce dépôt : [`.claude/commands/icr.md`](.claude/commands/icr.md).

### Mise en place

1. **Activer le serveur MCP** : dans Eclipse, **Window → Preferences → BlueMind** → cocher
*« Enable MCP server for Claude Code »*. Le plugin écrit alors `~/.config/bluemind/mcp/eclipse-*.json`
(url + token loopback). `jq` doit être installé.
2. **Installer la commande `/icr`** — copier le fichier à l'un de ces emplacements :
- **Globale** (toutes vos sessions Claude Code) : `~/.claude/commands/icr.md`
```bash
mkdir -p ~/.claude/commands && cp .claude/commands/icr.md ~/.claude/commands/
```
- **Par projet** : `<dépôt>/.claude/commands/icr.md` (p. ex. dans votre checkout
`bluemind-all`), pour la partager avec l'équipe via git.

### Utilisation

1. Lancer `/icr` dans Claude Code depuis le dépôt à relire (`/icr [--source <branche>] [--repo <chemin>]`).
2. Dans Eclipse, sélectionner du code → *clic droit → Ask Claude (ICR)…* (ou `Ctrl+Alt+C`) pour poser
une question ou demander une modification. Claude répond inline (glyphe `💬`).
3. La vue **Window → Show View → BlueMind → Code Review Conversations** liste tous les fils ouverts ;
un double-clic ouvre le fichier sur la ligne concernée.

> La commande `/icr` est documentée pas à pas dans le fichier lui-même ; le détail du protocole MCP
> est dans [docs/CLAUDE_CODE_MCP.md](net.bluemind.devtools/docs/CLAUDE_CODE_MCP.md) §5.

## Build local

Prérequis : Java 21+, Maven 3.9+
Expand Down
2 changes: 1 addition & 1 deletion deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ CP="$(find "$ECLIPSE_PLUGINS" -name '*.jar' ! -name '*.source_*' | tr '\n' ':')"
echo "Eclipse: $ECLIPSE"
echo "Compiling (JavaSE-21)..."
find "$SRC" -name '*.java' > "$BUILD_DIR/srcs.txt"
javac --release 21 -cp "$CP" -d "$OUT" "@$BUILD_DIR/srcs.txt"
javac --release 21 -encoding UTF-8 -cp "$CP" -d "$OUT" "@$BUILD_DIR/srcs.txt"

cp -r "$PLUGIN_DIR/icons" "$OUT/"
cp "$PLUGIN_DIR/plugin.xml" "$OUT/"
Expand Down
6 changes: 5 additions & 1 deletion net.bluemind.devtools/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Bundle-Vendor: BlueMind
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.core.resources,
org.eclipse.core.expressions,
org.eclipse.core.filebuffers,
org.eclipse.core.filesystem,
org.eclipse.debug.core,
org.eclipse.debug.ui,
Expand Down Expand Up @@ -35,6 +36,9 @@ Require-Bundle: org.eclipse.core.runtime,
Import-Package: com.sun.net.httpserver,
org.eclipse.egit.core.internal.indexdiff;x-internal:=true,
org.eclipse.egit.core.internal.storage;x-internal:=true,
org.eclipse.egit.ui.internal.revision;x-internal:=true
org.eclipse.egit.core.project;x-internal:=true,
org.eclipse.egit.ui.internal.decorators;x-internal:=true,
org.eclipse.egit.ui.internal.revision;x-internal:=true,
org.eclipse.ui.internal.texteditor.quickdiff;x-internal:=true
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
26 changes: 26 additions & 0 deletions net.bluemind.devtools/docs/CLAUDE_CODE_MCP.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,29 @@ tourner avec un `.class` obsolète.
- Fichier de config `chmod 600`.
- Pas de chemin d'exécution arbitraire : seuls les 3 outils ci-dessus sont exposés, et chacun
n'accepte que des noms de projet / classe / méthode — résolus via l'API workspace Eclipse.

## 5. Interactive Code Review (ICR)

Le même serveur MCP expose des outils pour la revue de code interactive **native dans Eclipse**.
L'utilisateur sélectionne du code dans un éditeur, fait **clic droit → Ask Claude (ICR)…**
(ou `Ctrl+Alt+C`) et saisit une question ou une demande de modification. Claude (le skill `/icr`)
écoute via `icr_next`, agit (réponse et/ou édition de fichier) puis répond via `icr_reply` ;
la réponse s'affiche inline dans Eclipse sous forme de fil de commentaires (glyphe `💬`).

Contrairement aux runs de test, ici **c'est Eclipse qui produit les événements** et Claude qui les
draine en long-poll : `icr_next` bloque ~25 s puis renvoie `{"status":"idle"}` si rien n'est arrivé,
sinon `{"status":"thread","thread":{…}}`. Chaque outil renvoie son payload en **JSON** dans le
contenu texte (parser avec `jq -r '.result.content[0].text' | jq …`).

| Tool | Arguments | Description |
|-------------|--------------------------|----------------------------------------------------------------|
| `icr_start` | `source?`, `repo?` | Démarre/reprend une session, active le menu, re-queue le pending|
| `icr_list` | — | Liste tous les fils (JSON) — catch-up après reconnexion |
| `icr_next` | — | Long-poll du prochain fil à traiter (`idle` / `thread`) |
| `icr_reply` | `threadId`, `body` | Poste la réponse de Claude (markdown rendu dans le popup) |
| `icr_stop` | — | Termine la session (désactive le menu) |

Le champ `thread` contient : `id`, `filePath` (relatif au workspace), `absolutePath`, `startLine`,
`endLine`, `selectedText`, `body`, `status`, `replies[]` (conversation complète). Le skill `/icr`
orchestre la boucle ; après une édition il appelle `refresh_projects` pour recompiler avant de
répondre.
73 changes: 73 additions & 0 deletions net.bluemind.devtools/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@
category="net.bluemind.devtools.gitchanges.category"
class="net.bluemind.devtools.gitchanges.views.ChangedFilesView"
restorable="true"/>
<view
id="net.bluemind.devtools.icr.views.threads"
name="Code Review Conversations"
category="net.bluemind.devtools.gitchanges.category"
class="net.bluemind.devtools.icr.ui.IcrThreadsView"
restorable="true"/>
</extension>

<extension point="org.eclipse.ui.commands">
Expand All @@ -118,4 +124,71 @@
</menuContribution>
</extension>

<!-- Interactive Code Review (ICR) -->

<extension point="org.eclipse.ui.services">
<sourceProvider
provider="net.bluemind.devtools.icr.ui.IcrSourceProvider">
<variable
name="net.bluemind.devtools.icr.active"
priorityLevel="workbench"/>
</sourceProvider>
</extension>

<extension point="org.eclipse.ui.commands">
<command
id="net.bluemind.devtools.icr.askClaude"
name="Ask Claude (ICR)"
description="Open a code review thread on the selected code for Claude to answer"/>
</extension>

<extension point="org.eclipse.ui.handlers">
<handler
commandId="net.bluemind.devtools.icr.askClaude"
class="net.bluemind.devtools.icr.ui.AskClaudeIcrHandler"/>
</extension>

<extension point="org.eclipse.ui.menus">
<!-- Plain text editors. -->
<menuContribution locationURI="popup:#TextEditorContext?after=additions">
<command
commandId="net.bluemind.devtools.icr.askClaude"
label="Ask Claude (ICR)..."
style="push">
<visibleWhen checkEnabled="false">
<with variable="net.bluemind.devtools.icr.active">
<equals value="true"/>
</with>
</visibleWhen>
</command>
</menuContribution>
<!-- JDT Java editor uses its own context menu id, not #TextEditorContext. -->
<menuContribution locationURI="popup:#CompilationUnitEditorContext?after=additions">
<command
commandId="net.bluemind.devtools.icr.askClaude"
label="Ask Claude (ICR)..."
style="push">
<visibleWhen checkEnabled="false">
<with variable="net.bluemind.devtools.icr.active">
<equals value="true"/>
</with>
</visibleWhen>
</command>
</menuContribution>
</extension>

<extension point="org.eclipse.ui.bindings">
<key
commandId="net.bluemind.devtools.icr.askClaude"
contextId="org.eclipse.ui.textEditorScope"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
sequence="M1+M3+C"/>
</extension>

<extension point="org.eclipse.ui.workbench.texteditor.codeMiningProviders">
<codeMiningProvider
id="net.bluemind.devtools.icr.codeMining"
class="net.bluemind.devtools.icr.ui.IcrCodeMiningProvider"/>
</extension>

</plugin>
Loading