@insitue/sdk 0.1.1 → 0.1.2
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/dist/capture-only.js +2 -2
- package/dist/{chunk-LGN4LKXD.js → chunk-VMBBJKFF.js} +125 -7
- package/dist/{chunk-6SMY7D6U.js → chunk-X7V2UEBO.js} +100 -27
- package/dist/{chunk-BYR4ZXVS.js → chunk-YUNYW2IC.js} +1 -1
- package/dist/index.js +3 -3
- package/dist/overlay.js +2 -2
- package/package.json +1 -1
package/dist/capture-only.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
k,
|
|
10
10
|
runtimeErrorCount,
|
|
11
11
|
y
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-X7V2UEBO.js";
|
|
13
13
|
|
|
14
14
|
// src/client.ts
|
|
15
15
|
var CompanionClient = class {
|
|
@@ -173,6 +173,42 @@ function diffLines(diff) {
|
|
|
173
173
|
return k("div", { style: `color:${color};white-space:pre` }, ln || " ");
|
|
174
174
|
});
|
|
175
175
|
}
|
|
176
|
+
function renderMessageBody(text) {
|
|
177
|
+
const parts = [];
|
|
178
|
+
const lines = text.split("\n");
|
|
179
|
+
let buf = [];
|
|
180
|
+
let inCode = false;
|
|
181
|
+
let lang = "";
|
|
182
|
+
const flush = () => {
|
|
183
|
+
if (buf.length === 0) return;
|
|
184
|
+
parts.push({ code: inCode, lang, text: buf.join("\n") });
|
|
185
|
+
buf = [];
|
|
186
|
+
};
|
|
187
|
+
for (const line of lines) {
|
|
188
|
+
const fence = /^```(\w*)\s*$/.exec(line);
|
|
189
|
+
if (fence) {
|
|
190
|
+
flush();
|
|
191
|
+
inCode = !inCode;
|
|
192
|
+
lang = inCode ? fence[1] ?? "" : "";
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
buf.push(line);
|
|
196
|
+
}
|
|
197
|
+
flush();
|
|
198
|
+
return parts.map(
|
|
199
|
+
(p) => p.code ? k(
|
|
200
|
+
"div",
|
|
201
|
+
{
|
|
202
|
+
style: `${card};padding:8px;margin:4px 0;font:${mono};color:#ececef;overflow-x:auto;white-space:pre`
|
|
203
|
+
},
|
|
204
|
+
p.text
|
|
205
|
+
) : k(
|
|
206
|
+
"div",
|
|
207
|
+
{ style: "white-space:pre-wrap;word-break:break-word" },
|
|
208
|
+
p.text
|
|
209
|
+
)
|
|
210
|
+
);
|
|
211
|
+
}
|
|
176
212
|
function diffBlock(changes) {
|
|
177
213
|
return changes.map(
|
|
178
214
|
(c) => k("div", { style: "margin:6px 0" }, [
|
|
@@ -225,6 +261,7 @@ function App(props) {
|
|
|
225
261
|
const changesRef = A([]);
|
|
226
262
|
const activeTurnRef = A(null);
|
|
227
263
|
const threadRef = A(null);
|
|
264
|
+
const panelRef = A(null);
|
|
228
265
|
autoApplyRef.current = autoApply;
|
|
229
266
|
changesRef.current = changes;
|
|
230
267
|
activeTurnRef.current = activeTurn;
|
|
@@ -235,6 +272,32 @@ function App(props) {
|
|
|
235
272
|
}
|
|
236
273
|
return [...ms, { role: "agent", text: delta }];
|
|
237
274
|
});
|
|
275
|
+
const storageKey = `insitue:session:${typeof window !== "undefined" ? window.location.origin : "default"}`;
|
|
276
|
+
const hydratedRef = A(false);
|
|
277
|
+
y(() => {
|
|
278
|
+
if (hydratedRef.current) return;
|
|
279
|
+
hydratedRef.current = true;
|
|
280
|
+
try {
|
|
281
|
+
const raw = window.localStorage.getItem(storageKey);
|
|
282
|
+
if (!raw) return;
|
|
283
|
+
const saved = JSON.parse(raw);
|
|
284
|
+
if (Array.isArray(saved.messages)) setMessages(saved.messages);
|
|
285
|
+
if (Array.isArray(saved.history)) setHistory(saved.history);
|
|
286
|
+
if (typeof saved.autoApply === "boolean") setAutoApply(saved.autoApply);
|
|
287
|
+
if (typeof saved.open === "boolean") setOpen(saved.open);
|
|
288
|
+
} catch {
|
|
289
|
+
}
|
|
290
|
+
}, [storageKey]);
|
|
291
|
+
y(() => {
|
|
292
|
+
if (!hydratedRef.current) return;
|
|
293
|
+
try {
|
|
294
|
+
window.localStorage.setItem(
|
|
295
|
+
storageKey,
|
|
296
|
+
JSON.stringify({ messages, history, autoApply, open })
|
|
297
|
+
);
|
|
298
|
+
} catch {
|
|
299
|
+
}
|
|
300
|
+
}, [messages, history, autoApply, open, storageKey]);
|
|
238
301
|
y(() => {
|
|
239
302
|
installRuntimeCollectors();
|
|
240
303
|
const c = new CompanionClient(props.port, {
|
|
@@ -370,6 +433,25 @@ function App(props) {
|
|
|
370
433
|
const el = threadRef.current;
|
|
371
434
|
if (el) el.scrollTop = el.scrollHeight;
|
|
372
435
|
}, [messages, changes, turnBusy, activity]);
|
|
436
|
+
y(() => {
|
|
437
|
+
const onKey = (ev) => {
|
|
438
|
+
const meta = ev.metaKey || ev.ctrlKey;
|
|
439
|
+
if (meta && ev.key === "k") {
|
|
440
|
+
ev.preventDefault();
|
|
441
|
+
setOpen(true);
|
|
442
|
+
setTimeout(() => {
|
|
443
|
+
const ta = panelRef.current?.querySelector(
|
|
444
|
+
"textarea"
|
|
445
|
+
);
|
|
446
|
+
ta?.focus();
|
|
447
|
+
}, 0);
|
|
448
|
+
} else if (ev.key === "Escape" && open && !chatInput.trim()) {
|
|
449
|
+
setOpen(false);
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
window.addEventListener("keydown", onKey);
|
|
453
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
454
|
+
}, [open, chatInput]);
|
|
373
455
|
const captureSel = async (sel) => {
|
|
374
456
|
setLastSel(sel);
|
|
375
457
|
const b = await buildBundle(sel);
|
|
@@ -394,9 +476,30 @@ function App(props) {
|
|
|
394
476
|
}
|
|
395
477
|
};
|
|
396
478
|
const sendChat = () => {
|
|
397
|
-
if (!client || !
|
|
398
|
-
const turnId = bundle.id;
|
|
479
|
+
if (!client || !chatInput.trim() || turnBusy) return;
|
|
399
480
|
const text = chatInput.trim();
|
|
481
|
+
if (text.startsWith("/")) {
|
|
482
|
+
const [cmd, ...rest] = text.split(/\s+/);
|
|
483
|
+
if (cmd === "/clear") {
|
|
484
|
+
setMessages([]);
|
|
485
|
+
setChatInput("");
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
if (cmd === "/undo") {
|
|
489
|
+
const top = history.find((h) => h.status === "applied");
|
|
490
|
+
if (top) client.sendUndo(top.turnId);
|
|
491
|
+
setChatInput("");
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (cmd === "/commit") {
|
|
495
|
+
const msg = rest.join(" ") || "Apply InSitue session changes";
|
|
496
|
+
client.sendCommitSession(msg);
|
|
497
|
+
setChatInput("");
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
if (!bundle) return;
|
|
502
|
+
const turnId = bundle.id;
|
|
400
503
|
setActiveTurn({ turnId, prompt: text, sel: lastSel });
|
|
401
504
|
setMessages((ms) => [...ms, { role: "user", text }]);
|
|
402
505
|
setChatInput("");
|
|
@@ -550,12 +653,26 @@ ${resolved.snippet}`
|
|
|
550
653
|
},
|
|
551
654
|
[
|
|
552
655
|
...messages.map(
|
|
553
|
-
(m) => k(
|
|
656
|
+
(m, i) => k(
|
|
554
657
|
"div",
|
|
555
658
|
{
|
|
556
|
-
style: m.role === "user" ? `align-self:flex-end;max-width:88%;${card};border-color:#2e2e3c;padding:6px 8px;color:#ececef;white-space:pre-wrap;word-break:break-word` : `align-self:flex-start;max-width:96%;padding:6px 8px;color:#ececef
|
|
659
|
+
style: m.role === "user" ? `align-self:flex-end;max-width:88%;${card};border-color:#2e2e3c;padding:6px 8px;color:#ececef;white-space:pre-wrap;word-break:break-word;cursor:pointer` : `align-self:flex-start;max-width:96%;padding:6px 8px;color:#ececef`,
|
|
660
|
+
// Click any prior user message to re-populate the
|
|
661
|
+
// input — matches Claude.ai / Cursor edit-and-retry.
|
|
662
|
+
// The original turn stays in the thread; sending
|
|
663
|
+
// creates a new turn.
|
|
664
|
+
onClick: m.role === "user" ? () => {
|
|
665
|
+
setChatInput(m.text);
|
|
666
|
+
setTimeout(() => {
|
|
667
|
+
const ta = panelRef.current?.querySelector(
|
|
668
|
+
"textarea"
|
|
669
|
+
);
|
|
670
|
+
ta?.focus();
|
|
671
|
+
}, 0);
|
|
672
|
+
} : void 0,
|
|
673
|
+
title: m.role === "user" ? "click to edit + retry" : void 0
|
|
557
674
|
},
|
|
558
|
-
m.text
|
|
675
|
+
m.role === "agent" ? renderMessageBody(m.text) : m.text
|
|
559
676
|
)
|
|
560
677
|
),
|
|
561
678
|
thinking && turnBusy ? k(
|
|
@@ -687,7 +804,7 @@ ${resolved.snippet}`
|
|
|
687
804
|
proposed,
|
|
688
805
|
k("textarea", {
|
|
689
806
|
value: chatInput,
|
|
690
|
-
placeholder: messages.length ? "reply\u2026 (the agent remembers this thread)" : "what does this do? \xB7 make the padding bigger \xB7 fix this bug",
|
|
807
|
+
placeholder: messages.length ? "reply\u2026 (the agent remembers this thread) \xB7 /undo /clear /commit" : "what does this do? \xB7 make the padding bigger \xB7 fix this bug \xB7 \u2318K to focus",
|
|
691
808
|
rows: 2,
|
|
692
809
|
onInput: (ev) => setChatInput(ev.target.value),
|
|
693
810
|
onKeyDown: (ev) => {
|
|
@@ -852,6 +969,7 @@ ${resolved.snippet}`
|
|
|
852
969
|
const panel = open ? k(
|
|
853
970
|
"div",
|
|
854
971
|
{
|
|
972
|
+
ref: panelRef,
|
|
855
973
|
style: {
|
|
856
974
|
position: "fixed",
|
|
857
975
|
bottom: "64px",
|
|
@@ -1592,10 +1592,6 @@ async function toCanvas(node, options = {}) {
|
|
|
1592
1592
|
context.drawImage(img, 0, 0, canvas.width, canvas.height);
|
|
1593
1593
|
return canvas;
|
|
1594
1594
|
}
|
|
1595
|
-
async function toPng(node, options = {}) {
|
|
1596
|
-
const canvas = await toCanvas(node, options);
|
|
1597
|
-
return canvas.toDataURL();
|
|
1598
|
-
}
|
|
1599
1595
|
|
|
1600
1596
|
// src/capture.ts
|
|
1601
1597
|
function crossOrigin(url) {
|
|
@@ -1632,6 +1628,63 @@ function crossOriginMediaReason(root) {
|
|
|
1632
1628
|
}
|
|
1633
1629
|
return null;
|
|
1634
1630
|
}
|
|
1631
|
+
function findContextAncestor(el) {
|
|
1632
|
+
const minW = 420;
|
|
1633
|
+
const minH = 140;
|
|
1634
|
+
const maxW = window.innerWidth * 1.2;
|
|
1635
|
+
const maxH = window.innerHeight * 1.2;
|
|
1636
|
+
let cur = el;
|
|
1637
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
1638
|
+
const r3 = cur.getBoundingClientRect();
|
|
1639
|
+
if (r3.width >= minW && r3.height >= minH) return cur;
|
|
1640
|
+
const parent = cur.parentElement;
|
|
1641
|
+
if (!parent) return cur;
|
|
1642
|
+
const pr = parent.getBoundingClientRect();
|
|
1643
|
+
if (pr.width > maxW || pr.height > maxH) return cur;
|
|
1644
|
+
cur = parent;
|
|
1645
|
+
}
|
|
1646
|
+
return cur;
|
|
1647
|
+
}
|
|
1648
|
+
async function renderViewportCrop(cropRect, pixelRatio) {
|
|
1649
|
+
const bodyBg = getComputedStyle(document.body).backgroundColor;
|
|
1650
|
+
const htmlBg = getComputedStyle(document.documentElement).backgroundColor;
|
|
1651
|
+
const backgroundColor = bodyBg && bodyBg !== "rgba(0, 0, 0, 0)" && bodyBg !== "transparent" ? bodyBg : htmlBg && htmlBg !== "rgba(0, 0, 0, 0)" && htmlBg !== "transparent" ? htmlBg : "#ffffff";
|
|
1652
|
+
const fullCanvas = await toCanvas(document.documentElement, {
|
|
1653
|
+
pixelRatio,
|
|
1654
|
+
cacheBust: true,
|
|
1655
|
+
backgroundColor,
|
|
1656
|
+
filter: (n2) => {
|
|
1657
|
+
if (n2 instanceof Element && n2.closest?.("#insitu-root, [data-insitu-layer]")) {
|
|
1658
|
+
return false;
|
|
1659
|
+
}
|
|
1660
|
+
if (n2 instanceof HTMLImageElement) {
|
|
1661
|
+
if (crossOrigin(n2.currentSrc || n2.src) && n2.crossOrigin == null) {
|
|
1662
|
+
return false;
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
return true;
|
|
1666
|
+
}
|
|
1667
|
+
});
|
|
1668
|
+
const sx = window.scrollX;
|
|
1669
|
+
const sy = window.scrollY;
|
|
1670
|
+
const out = document.createElement("canvas");
|
|
1671
|
+
out.width = Math.max(1, Math.round(cropRect.width * pixelRatio));
|
|
1672
|
+
out.height = Math.max(1, Math.round(cropRect.height * pixelRatio));
|
|
1673
|
+
const ctx = out.getContext("2d");
|
|
1674
|
+
if (!ctx) return null;
|
|
1675
|
+
ctx.drawImage(
|
|
1676
|
+
fullCanvas,
|
|
1677
|
+
Math.round((cropRect.x + sx) * pixelRatio),
|
|
1678
|
+
Math.round((cropRect.y + sy) * pixelRatio),
|
|
1679
|
+
Math.round(cropRect.width * pixelRatio),
|
|
1680
|
+
Math.round(cropRect.height * pixelRatio),
|
|
1681
|
+
0,
|
|
1682
|
+
0,
|
|
1683
|
+
out.width,
|
|
1684
|
+
out.height
|
|
1685
|
+
);
|
|
1686
|
+
return out.toDataURL("image/png");
|
|
1687
|
+
}
|
|
1635
1688
|
function elementFor(sel) {
|
|
1636
1689
|
if (sel.mode === "element") return sel.pointerPath?.[0] ?? null;
|
|
1637
1690
|
if (sel.rect) {
|
|
@@ -1648,30 +1701,50 @@ async function buildBundle(sel) {
|
|
|
1648
1701
|
let screenshot;
|
|
1649
1702
|
let screenshotUnavailable;
|
|
1650
1703
|
if (el instanceof HTMLElement) {
|
|
1651
|
-
const
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1704
|
+
const context = findContextAncestor(el);
|
|
1705
|
+
const cr = context.getBoundingClientRect();
|
|
1706
|
+
const cropRect = new DOMRect(
|
|
1707
|
+
Math.max(0, cr.x),
|
|
1708
|
+
Math.max(0, cr.y),
|
|
1709
|
+
Math.min(window.innerWidth, cr.right) - Math.max(0, cr.x),
|
|
1710
|
+
Math.min(window.innerHeight, cr.bottom) - Math.max(0, cr.y)
|
|
1711
|
+
);
|
|
1712
|
+
const orig = {
|
|
1713
|
+
outline: el.style.outline,
|
|
1714
|
+
outlineOffset: el.style.outlineOffset
|
|
1715
|
+
};
|
|
1716
|
+
el.style.outline = "3px solid #ff6b00";
|
|
1717
|
+
el.style.outlineOffset = "2px";
|
|
1718
|
+
try {
|
|
1719
|
+
const dataUrl = await renderViewportCrop(
|
|
1720
|
+
cropRect,
|
|
1721
|
+
// Cap pixel ratio for full-document rasterise — 2× of a
|
|
1722
|
+
// long page is enough to blow per-tab canvas memory caps
|
|
1723
|
+
// on some browsers (and 1.5× still looks crisp).
|
|
1724
|
+
Math.min(dpr, 1.5)
|
|
1725
|
+
);
|
|
1726
|
+
if (!dataUrl || dataUrl.length < 1024) {
|
|
1727
|
+
const taint = crossOriginMediaReason(el);
|
|
1728
|
+
screenshotUnavailable = taint ? `${taint} \u2014 can't rasterise in-browser` : "rasterise produced an empty image";
|
|
1729
|
+
} else {
|
|
1730
|
+
screenshot = {
|
|
1731
|
+
mime: "image/png",
|
|
1732
|
+
dataUrl,
|
|
1733
|
+
// Bounds describe the SCREENSHOT (the crop region) so
|
|
1734
|
+
// the dashboard knows what slice of viewport this is.
|
|
1735
|
+
bounds: {
|
|
1736
|
+
x: cropRect.x,
|
|
1737
|
+
y: cropRect.y,
|
|
1738
|
+
width: cropRect.width,
|
|
1739
|
+
height: cropRect.height
|
|
1740
|
+
}
|
|
1741
|
+
};
|
|
1674
1742
|
}
|
|
1743
|
+
} catch {
|
|
1744
|
+
screenshotUnavailable = "rasterise failed";
|
|
1745
|
+
} finally {
|
|
1746
|
+
el.style.outline = orig.outline;
|
|
1747
|
+
el.style.outlineOffset = orig.outlineOffset;
|
|
1675
1748
|
}
|
|
1676
1749
|
}
|
|
1677
1750
|
return {
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
mountCaptureOnly
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-YUNYW2IC.js";
|
|
4
4
|
import {
|
|
5
5
|
mountInSitue
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-VMBBJKFF.js";
|
|
7
|
+
import "./chunk-X7V2UEBO.js";
|
|
8
8
|
|
|
9
9
|
// src/InSitue.tsx
|
|
10
10
|
import { useEffect } from "react";
|
package/dist/overlay.js
CHANGED
package/package.json
CHANGED