Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
284241c
feat: add WSS support for HTTPS environments
aidenybai Feb 5, 2026
a96448b
fix: use current hostname instead of hardcoded localhost
aidenybai Feb 5, 2026
0589400
fix: resolve SSL, mkcert, and code duplication issues
cursoragent Feb 5, 2026
8510d3c
fix
aidenybai Feb 5, 2026
5f1aa7b
fix: add certHostnames option to support custom local domains
cursoragent Feb 5, 2026
b3ebab8
fix: use native https module instead of undici for health checks
aidenybai Feb 5, 2026
e384018
Fix WSS relay bugs: cert hostnames, race condition, health check prot…
cursoragent Feb 5, 2026
f8197ae
fix: add @types/node to utils package and use proper import
aidenybai Feb 5, 2026
f6029b0
fix: resolve security and logic bugs in WSS relay implementation
cursoragent Feb 5, 2026
fa6ee95
Fix certificate hostname tracking and onSecureUpgradeRequested type
cursoragent Feb 5, 2026
54b867c
Fix unnecessary dynamic import for unlink in mkcert.ts
cursoragent Feb 5, 2026
b772d01
fix: handle corrupted cert-hosts.json with try-catch around JSON.parse
cursoragent Feb 6, 2026
df38df2
fix: prevent hostname flag injection in mkcert execution
cursoragent Feb 6, 2026
94006d7
fix: properly await httpServer.close() and webSocketServer.close() in…
cursoragent Feb 6, 2026
9b8b371
fix: add retry delay when response.ok is false in ensureServerReady
cursoragent Feb 6, 2026
ab76689
fix: retry on network errors during server upgrade
cursoragent Feb 7, 2026
65cff04
fix: implement retry delay for connection upgrades and enhance error …
aidenybai Feb 7, 2026
d4e9540
Fix relay server auto-upgrade bugs and reconnection issues
cursoragent Feb 7, 2026
8b48e7c
Fix WebSocket connection and reconnection reliability issues
cursoragent Feb 7, 2026
abc9913
fix: resolve protocol fallback, network error handling, and reconnect…
cursoragent Feb 8, 2026
3213357
Fix startup message showing wrong protocol when connecting to existin…
cursoragent Feb 8, 2026
4b5ea74
Refactor relay package for clarity and consistency
aidenybai Feb 9, 2026
f2f42ab
fix
aidenybai Feb 9, 2026
e2e98d8
Fix protocol upgrade and reconnection bugs
cursoragent Feb 9, 2026
e9a091b
fix(relay): prioritize user secure preference and cleanup reconnect t…
cursoragent Feb 9, 2026
c2472f4
Fix protocol mismatch when connecting to existing relay
cursoragent Feb 9, 2026
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
2 changes: 2 additions & 0 deletions packages/gym/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
.next

certificates
16 changes: 2 additions & 14 deletions packages/provider-amp/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
#!/usr/bin/env node
import { spawn } from "node:child_process";
import { realpathSync } from "node:fs";
import { dirname, join } from "node:path";
import { spawnDetachedServer } from "@react-grab/utils/server";

const realScriptPath = realpathSync(process.argv[1]);
const scriptDir = dirname(realScriptPath);
const serverPath = join(scriptDir, "server.cjs");

const child = spawn(process.execPath, [serverPath], {
detached: true,
stdio: "inherit",
});

child.unref();
process.exit(0);
spawnDetachedServer();
4 changes: 3 additions & 1 deletion packages/provider-amp/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
import { connectRelay } from "@react-grab/relay";
import { ampAgentHandler } from "./handler.js";

const isSecureConnection = process.argv.includes("--secure");

fetch(
`https://www.react-grab.com/api/version?source=amp&t=${Date.now()}`,
).catch(() => {});

connectRelay({ handler: ampAgentHandler });
connectRelay({ handler: ampAgentHandler, secure: isSecureConnection });
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated server initialization across 7 provider packages

Medium Severity

All 7 provider server files contain identical boilerplate: --secure flag parsing, version check fetch, and connectRelay call. The PR extracted CLI logic into spawnDetachedServer but didn't apply the same pattern here. A utility like startProviderServer(handler, source) in @react-grab/utils/server would consolidate this duplication.

Fix in Cursor Fix in Web

16 changes: 2 additions & 14 deletions packages/provider-claude-code/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
#!/usr/bin/env node
import { spawn } from "node:child_process";
import { realpathSync } from "node:fs";
import { dirname, join } from "node:path";
import { spawnDetachedServer } from "@react-grab/utils/server";

const realScriptPath = realpathSync(process.argv[1]);
const scriptDir = dirname(realScriptPath);
const serverPath = join(scriptDir, "server.cjs");

const child = spawn(process.execPath, [serverPath], {
detached: true,
stdio: "inherit",
});

child.unref();
process.exit(0);
spawnDetachedServer();
4 changes: 3 additions & 1 deletion packages/provider-claude-code/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
import { connectRelay } from "@react-grab/relay";
import { claudeAgentHandler } from "./handler.js";

const isSecureConnection = process.argv.includes("--secure");

fetch(
`https://www.react-grab.com/api/version?source=claude-code&t=${Date.now()}`,
).catch(() => {});

connectRelay({ handler: claudeAgentHandler });
connectRelay({ handler: claudeAgentHandler, secure: isSecureConnection });
16 changes: 2 additions & 14 deletions packages/provider-codex/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
#!/usr/bin/env node
import { spawn } from "node:child_process";
import { realpathSync } from "node:fs";
import { dirname, join } from "node:path";
import { spawnDetachedServer } from "@react-grab/utils/server";

const realScriptPath = realpathSync(process.argv[1]);
const scriptDir = dirname(realScriptPath);
const serverPath = join(scriptDir, "server.cjs");

const child = spawn(process.execPath, [serverPath], {
detached: true,
stdio: "inherit",
});

child.unref();
process.exit(0);
spawnDetachedServer();
4 changes: 3 additions & 1 deletion packages/provider-codex/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
import { connectRelay } from "@react-grab/relay";
import { codexAgentHandler } from "./handler.js";

const isSecureConnection = process.argv.includes("--secure");

fetch(
`https://www.react-grab.com/api/version?source=codex&t=${Date.now()}`,
).catch(() => {});

connectRelay({ handler: codexAgentHandler });
connectRelay({ handler: codexAgentHandler, secure: isSecureConnection });
16 changes: 2 additions & 14 deletions packages/provider-cursor/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
#!/usr/bin/env node
import { spawn } from "node:child_process";
import { realpathSync } from "node:fs";
import { dirname, join } from "node:path";
import { spawnDetachedServer } from "@react-grab/utils/server";

const realScriptPath = realpathSync(process.argv[1]);
const scriptDir = dirname(realScriptPath);
const serverPath = join(scriptDir, "server.cjs");

const child = spawn(process.execPath, [serverPath], {
detached: true,
stdio: "inherit",
});

child.unref();
process.exit(0);
spawnDetachedServer();
4 changes: 3 additions & 1 deletion packages/provider-cursor/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
import { connectRelay } from "@react-grab/relay";
import { cursorAgentHandler } from "./handler.js";

const isSecureConnection = process.argv.includes("--secure");

fetch(
`https://www.react-grab.com/api/version?source=cursor&t=${Date.now()}`,
).catch(() => {});

connectRelay({ handler: cursorAgentHandler });
connectRelay({ handler: cursorAgentHandler, secure: isSecureConnection });
16 changes: 2 additions & 14 deletions packages/provider-droid/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
#!/usr/bin/env node
import { spawn } from "node:child_process";
import { realpathSync } from "node:fs";
import { dirname, join } from "node:path";
import { spawnDetachedServer } from "@react-grab/utils/server";

const realScriptPath = realpathSync(process.argv[1]);
const scriptDir = dirname(realScriptPath);
const serverPath = join(scriptDir, "server.cjs");

const child = spawn(process.execPath, [serverPath], {
detached: true,
stdio: "inherit",
});

child.unref();
process.exit(0);
spawnDetachedServer();
4 changes: 3 additions & 1 deletion packages/provider-droid/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
import { connectRelay } from "@react-grab/relay";
import { droidAgentHandler } from "./handler.js";

const isSecureConnection = process.argv.includes("--secure");

fetch(
`https://www.react-grab.com/api/version?source=droid&t=${Date.now()}`,
).catch(() => {});

connectRelay({ handler: droidAgentHandler });
connectRelay({ handler: droidAgentHandler, secure: isSecureConnection });
16 changes: 2 additions & 14 deletions packages/provider-gemini/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
#!/usr/bin/env node
import { spawn } from "node:child_process";
import { realpathSync } from "node:fs";
import { dirname, join } from "node:path";
import { spawnDetachedServer } from "@react-grab/utils/server";

const realScriptPath = realpathSync(process.argv[1]);
const scriptDir = dirname(realScriptPath);
const serverPath = join(scriptDir, "server.cjs");

const child = spawn(process.execPath, [serverPath], {
detached: true,
stdio: "inherit",
});

child.unref();
process.exit(0);
spawnDetachedServer();
4 changes: 3 additions & 1 deletion packages/provider-gemini/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
import { connectRelay } from "@react-grab/relay";
import { geminiAgentHandler } from "./handler.js";

const isSecureConnection = process.argv.includes("--secure");

fetch(
`https://www.react-grab.com/api/version?source=gemini&t=${Date.now()}`,
).catch(() => {});

connectRelay({ handler: geminiAgentHandler });
connectRelay({ handler: geminiAgentHandler, secure: isSecureConnection });
16 changes: 2 additions & 14 deletions packages/provider-opencode/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
#!/usr/bin/env node
import { spawn } from "node:child_process";
import { realpathSync } from "node:fs";
import { dirname, join } from "node:path";
import { spawnDetachedServer } from "@react-grab/utils/server";

const realScriptPath = realpathSync(process.argv[1]);
const scriptDir = dirname(realScriptPath);
const serverPath = join(scriptDir, "server.cjs");

const child = spawn(process.execPath, [serverPath], {
detached: true,
stdio: "inherit",
});

child.unref();
process.exit(0);
spawnDetachedServer();
4 changes: 3 additions & 1 deletion packages/provider-opencode/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
import { connectRelay } from "@react-grab/relay";
import { openCodeAgentHandler } from "./handler.js";

const isSecureConnection = process.argv.includes("--secure");

fetch(
`https://www.react-grab.com/api/version?source=opencode&t=${Date.now()}`,
).catch(() => {});

connectRelay({ handler: openCodeAgentHandler });
connectRelay({ handler: openCodeAgentHandler, secure: isSecureConnection });
9 changes: 4 additions & 5 deletions packages/react-grab/e2e/freeze-animations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ test.describe("Freeze Animations", () => {
}) => {
const getPageAnimationStates = async () => {
return reactGrab.page.evaluate((attrName) => {
return document.getAnimations().reduce<string[]>(
(states, animation) => {
return document
.getAnimations()
.reduce<string[]>((states, animation) => {
if (animation.effect instanceof KeyframeEffect) {
const target = animation.effect.target;
if (target instanceof Element) {
Expand All @@ -25,9 +26,7 @@ test.describe("Freeze Animations", () => {
}
states.push(animation.playState);
return states;
},
[],
);
}, []);
}, ATTRIBUTE_NAME);
};

Expand Down
14 changes: 11 additions & 3 deletions packages/react-grab/src/components/toolbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,9 @@ export const Toolbar: Component<ToolbarProps> = (props) => {
props.onToggleEnabled?.();

if (expandableWidth > 0) {
const widthChange = isCurrentlyEnabled ? -expandableWidth : expandableWidth;
const widthChange = isCurrentlyEnabled
? -expandableWidth
: expandableWidth;
expandedDimensions = {
width: expandedDimensions.width + widthChange,
height: expandedDimensions.height,
Expand All @@ -465,9 +467,15 @@ export const Toolbar: Component<ToolbarProps> = (props) => {

if (shouldCompensatePosition) {
const viewport = getVisualViewport();
const positionOffset = isCurrentlyEnabled ? expandableWidth : -expandableWidth;
const positionOffset = isCurrentlyEnabled
? expandableWidth
: -expandableWidth;
const clampMin = viewport.offsetLeft + TOOLBAR_SNAP_MARGIN_PX;
const clampMax = viewport.offsetLeft + viewport.width - expandedDimensions.width - TOOLBAR_SNAP_MARGIN_PX;
const clampMax =
viewport.offsetLeft +
viewport.width -
expandedDimensions.width -
TOOLBAR_SNAP_MARGIN_PX;
const compensatedX = clampToViewport(
preTogglePosition.x + positionOffset,
clampMin,
Expand Down
Loading
Loading