@insitue/claude-plugin 0.6.0 → 0.6.1
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.
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +4 -0
- package/dist/mcp-server.js +62 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# @insitue/claude-plugin
|
|
2
2
|
|
|
3
|
+
## 0.6.1
|
|
4
|
+
|
|
5
|
+
- **Fix: refuse to reuse a stale companion.** `ensureCompanion` now checks a reachable companion's version via the handshake and, if it is older than the cloud-feature floor (0.7.0), tears it down and spawns the current one — instead of silently attaching to a stale companion left on the port.
|
|
6
|
+
|
|
3
7
|
## 0.6.0
|
|
4
8
|
|
|
5
9
|
- **Sign in from Claude.** New `/insitue:login` command + `authenticate` / `complete_authentication` MCP tools open a browser, you approve, and a token is stored automatically — no manual paste.
|
package/dist/mcp-server.js
CHANGED
|
@@ -291,30 +291,64 @@ var PickBuffer = class {
|
|
|
291
291
|
this.waiters.length = 0;
|
|
292
292
|
}
|
|
293
293
|
};
|
|
294
|
+
var MIN_COMPANION = "0.7.0";
|
|
295
|
+
function semverGte(version, floor) {
|
|
296
|
+
function parse(v) {
|
|
297
|
+
const m = /^(\d+)\.(\d+)\.(\d+)/.exec(v);
|
|
298
|
+
if (!m) return [0, 0, 0];
|
|
299
|
+
return [parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10)];
|
|
300
|
+
}
|
|
301
|
+
const [vMaj, vMin, vPat] = parse(version);
|
|
302
|
+
const [fMaj, fMin, fPat] = parse(floor);
|
|
303
|
+
if (vMaj !== fMaj) return vMaj > fMaj;
|
|
304
|
+
if (vMin !== fMin) return vMin > fMin;
|
|
305
|
+
return vPat >= fPat;
|
|
306
|
+
}
|
|
294
307
|
async function probeCompanion(session2) {
|
|
295
308
|
try {
|
|
296
309
|
process.kill(session2.pid, 0);
|
|
297
310
|
} catch {
|
|
298
|
-
return
|
|
311
|
+
return null;
|
|
299
312
|
}
|
|
300
313
|
return new Promise((resolve) => {
|
|
314
|
+
let rawBody = "";
|
|
301
315
|
const req = httpRequest(
|
|
302
316
|
{
|
|
303
317
|
host: "127.0.0.1",
|
|
304
318
|
port: session2.port,
|
|
305
319
|
path: "/insitue/handshake",
|
|
306
320
|
method: "GET",
|
|
321
|
+
// Include an Origin so the handshake endpoint returns 200 + JSON
|
|
322
|
+
// instead of 403 (which it returns when Origin is absent). We
|
|
323
|
+
// use the loopback Origin — the companion's allowLocalhost flag
|
|
324
|
+
// accepts any localhost:* Origin, or else this falls back to 403
|
|
325
|
+
// which we still treat as "reachable" (non-null return).
|
|
326
|
+
headers: { origin: "http://localhost:5747" },
|
|
307
327
|
timeout: 1500
|
|
308
328
|
},
|
|
309
329
|
(res) => {
|
|
310
|
-
res.
|
|
311
|
-
|
|
330
|
+
res.setEncoding("utf8");
|
|
331
|
+
res.on("data", (chunk) => {
|
|
332
|
+
rawBody += chunk;
|
|
333
|
+
});
|
|
334
|
+
res.on("end", () => {
|
|
335
|
+
if (res.statusCode === 200) {
|
|
336
|
+
try {
|
|
337
|
+
const body = JSON.parse(rawBody);
|
|
338
|
+
resolve(body.companionVersion ?? "0.0.0");
|
|
339
|
+
} catch {
|
|
340
|
+
resolve("0.0.0");
|
|
341
|
+
}
|
|
342
|
+
} else {
|
|
343
|
+
resolve("0.0.0");
|
|
344
|
+
}
|
|
345
|
+
});
|
|
312
346
|
}
|
|
313
347
|
);
|
|
314
|
-
req.on("error", () => resolve(
|
|
348
|
+
req.on("error", () => resolve(null));
|
|
315
349
|
req.on("timeout", () => {
|
|
316
350
|
req.destroy();
|
|
317
|
-
resolve(
|
|
351
|
+
resolve(null);
|
|
318
352
|
});
|
|
319
353
|
req.end();
|
|
320
354
|
});
|
|
@@ -322,12 +356,30 @@ async function probeCompanion(session2) {
|
|
|
322
356
|
var ownedChild = null;
|
|
323
357
|
async function ensureCompanion(projectDir2) {
|
|
324
358
|
const existing = findSession(projectDir2);
|
|
325
|
-
if (existing
|
|
326
|
-
|
|
327
|
-
|
|
359
|
+
if (existing) {
|
|
360
|
+
const companionVersion = await probeCompanion(existing.session);
|
|
361
|
+
if (companionVersion !== null) {
|
|
362
|
+
if (semverGte(companionVersion, MIN_COMPANION)) {
|
|
363
|
+
process.stderr.write(
|
|
364
|
+
`[insitue-mcp] reusing companion at :${existing.session.port} (pid ${existing.session.pid}, v${companionVersion})
|
|
328
365
|
`
|
|
329
|
-
|
|
330
|
-
|
|
366
|
+
);
|
|
367
|
+
return existing.session;
|
|
368
|
+
}
|
|
369
|
+
process.stderr.write(
|
|
370
|
+
`[insitue-mcp] replacing stale companion (v${companionVersion} < ${MIN_COMPANION})
|
|
371
|
+
`
|
|
372
|
+
);
|
|
373
|
+
try {
|
|
374
|
+
process.kill(existing.session.pid);
|
|
375
|
+
} catch {
|
|
376
|
+
}
|
|
377
|
+
const sessionPath = join3(projectDir2, ".insitue", "session.json");
|
|
378
|
+
try {
|
|
379
|
+
rmSync(sessionPath);
|
|
380
|
+
} catch {
|
|
381
|
+
}
|
|
382
|
+
}
|
|
331
383
|
}
|
|
332
384
|
process.stderr.write(
|
|
333
385
|
`[insitue-mcp] starting companion via \`npx -y @insitue/companion@latest dev\` in ${projectDir2}\u2026
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@insitue/claude-plugin",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
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",
|