@insitue/claude-plugin 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "insitue",
3
- "version": "0.5.2",
3
+ "version": "0.6.0",
4
4
  "description": "Drive a Claude Code session from the InSitue browser overlay. Pick an element in your app, claude reads the file and proposes the edit.",
5
5
  "mcpServers": {
6
6
  "insitue": {
@@ -11,5 +11,10 @@
11
11
  ],
12
12
  "cwd": "${CLAUDE_PROJECT_DIR}"
13
13
  }
14
- }
14
+ },
15
+ "channels": [
16
+ {
17
+ "server": "insitue"
18
+ }
19
+ ]
15
20
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @insitue/claude-plugin
2
2
 
3
+ ## 0.7.0
4
+
5
+ - **Live picks without blocking the chat (channels, opt-in preview).** The MCP server now also PUSHES each pick as a Claude Code channel event (`notifications/claude/channel`). Start your session with `claude --dangerously-load-development-channels --channels plugin:insitue` and picks wake the idle agent instead of you waiting on a poll — the chat stays free for conversation the rest of the time. Plain `claude` + `/insitue:connect` is unchanged (8s poll fallback). The agent de-dupes by pick id, so the push + poll paths never double-handle a pick. Channels are a Claude Code research-preview feature (CLI-only); the flag is required during the preview.
6
+
7
+ ## 0.6.3
8
+
9
+ - **Responsive watch — interject without cancelling.** The `next_pick` long-poll is now 8s (was 25s). While the watch is running you can just type a message: Claude Code queues it and delivers it the moment the poll returns (≤~8s), so you no longer have to cancel the watch to ask a question. The connect instructions now make clear the watch never needs to be cancelled to talk — Claude answers and resumes watching.
10
+
3
11
  ## 0.6.2
4
12
 
5
13
  - **Echo the request before fixing.** The cloud-issue instructions (connect.md + the `claim_cloud_issue` tool) now require Claude to print the exact request verbatim ("Fixing locally: …") before any analysis or edits, so you always see what it's about to act on.
package/README.md CHANGED
@@ -177,6 +177,35 @@ before writing. After it writes, your dev server's HMR picks up
177
177
  the change and you see it live in the browser. Pick the next
178
178
  thing.
179
179
 
180
+ ### Live picks without blocking the chat (channels, preview)
181
+
182
+ By default the agent polls `next_pick` every ~8 s — the chat is
183
+ technically available between polls, but the polling loop runs
184
+ continuously in the background.
185
+
186
+ As an opt-in upgrade (Claude Code CLI only, research preview),
187
+ you can have picks **pushed** directly into the session so the
188
+ chat stays completely free between picks:
189
+
190
+ ```bash
191
+ claude --dangerously-load-development-channels --channels plugin:insitue
192
+ ```
193
+
194
+ With this flag, every pick the user sends from the browser wakes
195
+ Claude immediately via a channel notification — no polling needed,
196
+ and the chat is genuinely idle between picks. Claude still buffers
197
+ picks for `next_pick` in parallel, so a stale session or a missing
198
+ channel listener falls back to the normal poll automatically.
199
+
200
+ **Notes:**
201
+ - This is a **Claude Code research-preview** feature. The flag
202
+ `--dangerously-load-development-channels` is required during the
203
+ preview period and may change or be renamed in a future release.
204
+ - It works only with the CLI (`claude`), not Claude Desktop.
205
+ - The standard `/insitue:connect` workflow (plain `claude`, no
206
+ extra flags) continues to work exactly as before via polling —
207
+ channels are purely an opt-in upgrade, not a requirement.
208
+
180
209
  ---
181
210
 
182
211
  ## What gets shipped to claude
@@ -25,19 +25,57 @@ that means:
25
25
  `read_file` tools exposed by this same MCP server
26
26
  Either path is fine; pick whichever your runtime has.
27
27
 
28
+ ## Pick delivery modes and idempotency
29
+
30
+ Picks can reach you in one of two ways depending on how `claude`
31
+ was started. **Act on each pick `id` exactly once** regardless of
32
+ which path delivered it — the server always does both, so
33
+ double-delivery is possible and you must de-dupe by `id`.
34
+
35
+ ### Push mode (channels — opt-in, Claude Code only)
36
+
37
+ If the user started Claude Code with channel support
38
+ (`claude --dangerously-load-development-channels --channels plugin:insitue`),
39
+ picks are PUSHED into this session as
40
+ `<channel source="insitue">…</channel>` events. Each event
41
+ contains the pick's `id`, `userNote`, `source file:line`,
42
+ `confidence`, and URL — everything you need to act.
43
+
44
+ **In push mode you do NOT need to loop `next_pick`.** Stay idle
45
+ between picks so the user can chat freely. Each pushed pick wakes
46
+ you; handle it exactly like a `next_pick` pick (echo the request,
47
+ read the file, propose the edit, etc.), then go idle again.
48
+
49
+ ### Poll mode (plain `claude` — default)
50
+
51
+ If no `<channel>` pick events arrive, you are in poll mode. Loop
52
+ `next_pick` as described in §2 below (default 8 s timeout). This
53
+ is the same behaviour as before channels existed and requires no
54
+ extra flags.
55
+
56
+ ### Don't double-handle
57
+
58
+ If the same pick `id` arrives both via a channel event AND via
59
+ `next_pick`, act on it exactly once. Keep a set of handled ids in
60
+ your context and skip any id you've already processed.
61
+
28
62
  ## Your behaviour
29
63
 
30
64
  1. Call `mcp__insitue__list_recent_picks` once. If there are
31
65
  any picks the user made before you attached, summarise them
32
66
  ("you picked X but haven't sent a description yet — make sure
33
67
  to click Send in the InSitue panel"). Otherwise just say
34
- "Connected. Pick something in the browser when you're ready."
68
+ "Connected pick something in the browser when you're ready.
69
+ You can also just type to ask me anything anytime; I'll answer
70
+ and keep watching, no need to cancel."
35
71
  2. Enter the loop: call `mcp__insitue__next_pick`. It long-polls
36
- (~25s default — short on purpose so the chat stays responsive
37
- to other questions the user might type while you wait). When
38
- it returns with `status: "timeout"`, **call it again immediately
39
- without announcing it** the timeout is just a heartbeat, not
40
- news. When it returns with `status: "ok"`:
72
+ (~8sdeliberately short. The user can type at ANY time without
73
+ cancelling: Claude Code queues their message and delivers it the
74
+ moment this call returns, so a short poll means they wait at most
75
+ ~8s to reach you and never need to hit Esc). When it returns with
76
+ `status: "timeout"` **and the user hasn't said anything**, call it
77
+ again immediately without announcing it — the timeout is just a
78
+ heartbeat, not news. When it returns with `status: "ok"`:
41
79
  - **Always echo the prompt back first.** Before any action,
42
80
  diff, or follow-up question, lead with:
43
81
 
@@ -73,10 +111,14 @@ Either path is fine; pick whichever your runtime has.
73
111
  again. **Do not narrate the loop** — no "still waiting…", no
74
112
  "polling again…". The user sees `[insitue] 📥 pick received`
75
113
  on stderr the moment their pick lands; that's the
76
- confirmation, not your narration. If the user types another
77
- question while you're between calls, answer it first (since
78
- the chat is responsive), then resume the loop with
79
- `next_pick`.
114
+ confirmation, not your narration. **The user never has to cancel
115
+ the watch to talk to you.** When a message from the user arrives
116
+ while you're watching (it queues during the poll and lands the
117
+ moment `next_pick` returns), STOP looping, answer it fully, and do
118
+ whatever they ask — then resume the watch by calling `next_pick`
119
+ again. Their message is the priority; the watch waits for them, not
120
+ the other way around. Never tell the user to cancel or re-run
121
+ `/insitue:connect` just to ask a question.
80
122
  4. **End the session properly.** When the user says "stop",
81
123
  "done", "quit", "thanks", "exit", "disconnect", "stop
82
124
  insitue", or anything else that clearly ends the InSitue
@@ -204,7 +204,7 @@ function readPackageVersion() {
204
204
  return "unknown";
205
205
  }
206
206
  var MAX_BUFFERED_PICKS = 32;
207
- var NEXT_PICK_DEFAULT_TIMEOUT_MS = 25 * 1e3;
207
+ var NEXT_PICK_DEFAULT_TIMEOUT_MS = 8 * 1e3;
208
208
  var NEXT_PICK_MAX_TIMEOUT_MS = 30 * 60 * 1e3;
209
209
  function findSession(projectDir2) {
210
210
  const candidate = join3(projectDir2, ".insitue", "session.json");
@@ -501,6 +501,25 @@ function connectToCompanion(s) {
501
501
  `[insitue] \u{1F4E5} pick received \u2014 "${note}" @ ${where}
502
502
  `
503
503
  );
504
+ try {
505
+ const channelContent = `InSitue pick ready (id: ${summary.id})
506
+ Note: ${summary.userNote ?? "(no description)"}
507
+ Source: ${summary.source ? `${summary.source.file}:${summary.source.line ?? "?"}` : "(unknown)"}
508
+ Confidence: ${summary.confidence}
509
+ ` + (summary.url ? `URL: ${summary.url}
510
+ ` : "");
511
+ void server.server.notification(
512
+ {
513
+ method: "notifications/claude/channel",
514
+ params: {
515
+ content: channelContent,
516
+ meta: { pick_id: summary.id }
517
+ }
518
+ }
519
+ ).catch(() => {
520
+ });
521
+ } catch {
522
+ }
504
523
  } catch (err) {
505
524
  process.stderr.write(
506
525
  `[insitue-mcp] dropped malformed pick: ${err.message}
@@ -590,10 +609,21 @@ function endSession() {
590
609
  session = null;
591
610
  return { closedWs, killedCompanion, removedSessionFile };
592
611
  }
593
- var server = new McpServer({
594
- name: "insitue",
595
- version: readPackageVersion()
596
- });
612
+ var server = new McpServer(
613
+ {
614
+ name: "insitue",
615
+ version: readPackageVersion()
616
+ },
617
+ {
618
+ capabilities: {
619
+ // Declare the Claude Code "channel" experimental capability so the
620
+ // MCP server is permitted to emit notifications/claude/channel events.
621
+ // Claude Code checks for this key during its research-preview channel
622
+ // handshake; without it the push notification is silently dropped.
623
+ experimental: { "claude/channel": {} }
624
+ }
625
+ }
626
+ );
597
627
  server.registerTool(
598
628
  "next_pick",
599
629
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@insitue/claude-plugin",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "Drive Claude (Code AND Desktop) from the InSitue browser overlay — pick an element in your app, claude reads the file and proposes the edit.",
5
5
  "keywords": [
6
6
  "insitue",