surf-cli 2.7.2 → 2.8.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.
- package/README.md +110 -9
- package/native/browser-lock.cjs +169 -0
- package/native/chatgpt-client.cjs +18 -1
- package/native/cli.cjs +670 -279
- package/native/config.cjs +2 -2
- package/native/do-executor.cjs +2 -9
- package/native/do-parser.cjs +12 -0
- package/native/doctor.cjs +583 -0
- package/native/gemini-client.cjs +91 -20
- package/native/grok-client.cjs +270 -170
- package/native/host-helpers.cjs +51 -4
- package/native/host.cjs +22 -7
- package/native/mcp-server.cjs +10 -7
- package/native/socket-path.cjs +46 -0
- package/package.json +5 -5
- package/scripts/install-native-host.cjs +155 -53
- package/scripts/uninstall-native-host.cjs +93 -15
- package/skills/surf/SKILL.md +46 -18
package/native/gemini-client.cjs
CHANGED
|
@@ -652,9 +652,21 @@ async function runGeminiWebViaPage(input) {
|
|
|
652
652
|
if (typed.error) throw new Error(typed.error);
|
|
653
653
|
|
|
654
654
|
const beforeResult = await jsEval(tabId, `
|
|
655
|
-
|
|
655
|
+
const imageKey = (img) => {
|
|
656
|
+
const url = img.currentSrc || img.src || "";
|
|
657
|
+
return url + "|" + img.naturalWidth + "x" + img.naturalHeight;
|
|
658
|
+
};
|
|
659
|
+
const baselineKeys = Array.from(document.images)
|
|
660
|
+
.filter((img) => {
|
|
661
|
+
const url = img.currentSrc || img.src || "";
|
|
662
|
+
return img.naturalWidth >= 512
|
|
663
|
+
&& img.naturalHeight >= 512
|
|
664
|
+
&& (url.includes("gg-dl") || url.startsWith("blob:"));
|
|
665
|
+
})
|
|
666
|
+
.map(imageKey);
|
|
667
|
+
return JSON.stringify(baselineKeys);
|
|
656
668
|
`);
|
|
657
|
-
const
|
|
669
|
+
const baselineImageKeys = JSON.parse(JSON.parse(checkJsResult(beforeResult, "Count images")) || "[]");
|
|
658
670
|
|
|
659
671
|
if (log) log("Submitting...");
|
|
660
672
|
const sendResult = await jsEval(tabId, `
|
|
@@ -669,26 +681,60 @@ async function runGeminiWebViaPage(input) {
|
|
|
669
681
|
// Poll for response
|
|
670
682
|
if (log) log("Waiting for response...");
|
|
671
683
|
const deadline = Date.now() + timeoutMs;
|
|
672
|
-
let
|
|
684
|
+
let imageEntries = [];
|
|
673
685
|
let responseText = "";
|
|
674
686
|
|
|
675
687
|
while (Date.now() < deadline) {
|
|
676
688
|
await new Promise(r => setTimeout(r, 2000));
|
|
677
689
|
const pollResult = await jsEval(tabId, `
|
|
678
|
-
const
|
|
679
|
-
|
|
680
|
-
.
|
|
690
|
+
const baselineKeys = new Set(${JSON.stringify(baselineImageKeys)});
|
|
691
|
+
const imageKey = (img) => {
|
|
692
|
+
const url = img.currentSrc || img.src || "";
|
|
693
|
+
return url + "|" + img.naturalWidth + "x" + img.naturalHeight;
|
|
694
|
+
};
|
|
695
|
+
const generatedImgs = Array.from(document.images)
|
|
696
|
+
.filter((img) => {
|
|
697
|
+
const url = img.currentSrc || img.src || "";
|
|
698
|
+
return img.naturalWidth >= 512
|
|
699
|
+
&& img.naturalHeight >= 512
|
|
700
|
+
&& (url.includes("gg-dl") || url.startsWith("blob:"));
|
|
701
|
+
})
|
|
702
|
+
.filter((img) => !baselineKeys.has(imageKey(img)));
|
|
703
|
+
window.__surfGeminiBlobImages = window.__surfGeminiBlobImages || [];
|
|
704
|
+
window.__surfGeminiBlobImageIndexes = window.__surfGeminiBlobImageIndexes || Object.create(null);
|
|
705
|
+
const images = await Promise.all(generatedImgs.map(async (img) => {
|
|
706
|
+
const url = img.currentSrc || img.src || "";
|
|
707
|
+
if (!url.startsWith("blob:")) return { url };
|
|
708
|
+
const key = imageKey(img);
|
|
709
|
+
if (Number.isInteger(window.__surfGeminiBlobImageIndexes[key])) {
|
|
710
|
+
return { url, blobIndex: window.__surfGeminiBlobImageIndexes[key], type: "image/png" };
|
|
711
|
+
}
|
|
712
|
+
const canvas = document.createElement("canvas");
|
|
713
|
+
canvas.width = img.naturalWidth;
|
|
714
|
+
canvas.height = img.naturalHeight;
|
|
715
|
+
const ctx = canvas.getContext("2d");
|
|
716
|
+
if (!ctx) throw new Error("Canvas context unavailable");
|
|
717
|
+
ctx.drawImage(img, 0, 0);
|
|
718
|
+
const dataUrl = canvas.toDataURL("image/png");
|
|
719
|
+
const blobIndex = window.__surfGeminiBlobImages.push({
|
|
720
|
+
url,
|
|
721
|
+
b64: dataUrl.split(",")[1],
|
|
722
|
+
type: "image/png",
|
|
723
|
+
}) - 1;
|
|
724
|
+
window.__surfGeminiBlobImageIndexes[key] = blobIndex;
|
|
725
|
+
return { url, blobIndex, type: "image/png" };
|
|
726
|
+
}));
|
|
681
727
|
const loading = !!document.querySelector('mat-progress-bar, .loading-indicator, message-loading');
|
|
682
728
|
const turns = document.querySelectorAll('message-content');
|
|
683
729
|
const lastTurn = turns.length ? turns[turns.length - 1] : null;
|
|
684
730
|
const text = lastTurn ? lastTurn.textContent?.trim() : "";
|
|
685
|
-
return JSON.stringify({
|
|
731
|
+
return JSON.stringify({ images, loading, text, turns: turns.length });
|
|
686
732
|
`);
|
|
687
733
|
const poll = JSON.parse(JSON.parse(checkJsResult(pollResult, "Poll response")));
|
|
688
|
-
const newImgs = poll.
|
|
734
|
+
const newImgs = poll.images || [];
|
|
689
735
|
|
|
690
736
|
if (newImgs.length > 0) {
|
|
691
|
-
|
|
737
|
+
imageEntries = newImgs;
|
|
692
738
|
responseText = poll.text || "";
|
|
693
739
|
if (log) log(`Found ${newImgs.length} generated image(s)`);
|
|
694
740
|
break;
|
|
@@ -699,23 +745,47 @@ async function runGeminiWebViaPage(input) {
|
|
|
699
745
|
}
|
|
700
746
|
}
|
|
701
747
|
|
|
702
|
-
if (!
|
|
748
|
+
if (!imageEntries.length && !responseText) {
|
|
703
749
|
throw new Error("Gemini response timed out");
|
|
704
750
|
}
|
|
705
751
|
|
|
706
|
-
// Download images via extension
|
|
752
|
+
// Download URL-backed images via extension; read blob images from the page in chunks.
|
|
707
753
|
const images = [];
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
754
|
+
for (const img of imageEntries) {
|
|
755
|
+
if (Number.isInteger(img?.blobIndex)) {
|
|
756
|
+
let b64 = "";
|
|
757
|
+
let offset = 0;
|
|
758
|
+
const chunkSize = 40000;
|
|
759
|
+
let type = img.type || "image/png";
|
|
760
|
+
while (true) {
|
|
761
|
+
const chunkResult = await jsEval(tabId, `
|
|
762
|
+
const item = window.__surfGeminiBlobImages?.[${img.blobIndex}];
|
|
763
|
+
if (!item) return JSON.stringify({ error: "Blob image not found" });
|
|
764
|
+
return JSON.stringify({
|
|
765
|
+
chunk: item.b64.slice(${offset}, ${offset + chunkSize}),
|
|
766
|
+
done: ${offset + chunkSize} >= item.b64.length,
|
|
767
|
+
type: item.type || "image/png",
|
|
768
|
+
url: item.url,
|
|
769
|
+
});
|
|
770
|
+
`);
|
|
771
|
+
const chunk = JSON.parse(JSON.parse(checkJsResult(chunkResult, "Read blob image chunk")));
|
|
772
|
+
if (chunk.error) throw new Error(chunk.error);
|
|
773
|
+
b64 += chunk.chunk || "";
|
|
774
|
+
type = chunk.type || type;
|
|
775
|
+
if (chunk.done) break;
|
|
776
|
+
offset += chunkSize;
|
|
714
777
|
}
|
|
778
|
+
images.push({ url: img.url, b64, type });
|
|
779
|
+
continue;
|
|
715
780
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
781
|
+
if (img?.url && fetchUrl) {
|
|
782
|
+
if (log) log(`Downloading image (${img.url.slice(0, 60)}...)...`);
|
|
783
|
+
const dlResult = await fetchUrl(img.url);
|
|
784
|
+
if (dlResult?.b64) {
|
|
785
|
+
images.push({ url: img.url, b64: dlResult.b64, type: dlResult.type || "image/png" });
|
|
786
|
+
}
|
|
787
|
+
} else if (img?.url) {
|
|
788
|
+
images.push({ url: img.url });
|
|
719
789
|
}
|
|
720
790
|
}
|
|
721
791
|
|
|
@@ -917,6 +987,7 @@ module.exports = {
|
|
|
917
987
|
hasRequiredCookies,
|
|
918
988
|
buildCookieMap,
|
|
919
989
|
parseGeminiStreamGenerateResponse,
|
|
990
|
+
runGeminiWebViaPage,
|
|
920
991
|
REQUIRED_COOKIES,
|
|
921
992
|
ALL_COOKIE_NAMES,
|
|
922
993
|
GEMINI_APP_URL,
|