MCPcopy
hub / github.com/garrytan/gstack / handlePairAgent

Function handlePairAgent

browse/src/cli.ts:838–977  ·  view source on GitHub ↗
(state: ServerState, args: string[])

Source from the content-addressed store, hash-verified

836}
837
838async function handlePairAgent(state: ServerState, args: string[]): Promise<void> {
839 const clientName = parseFlag(args, '--client') || `remote-${Date.now()}`;
840 const domains = parseFlag(args, '--domain')?.split(',').map(d => d.trim());
841 const control = hasFlag(args, '--control') || hasFlag(args, '--admin');
842 const restrict = parseFlag(args, '--restrict');
843 const localHost = parseFlag(args, '--local');
844
845 // Call POST /pair to create a setup key
846 // Default: full access (read+write+admin+meta). --control adds browser-wide ops.
847 // --restrict limits: --restrict read (read-only), --restrict "read,write" (no admin)
848 const pairResp = await fetch(`http://127.0.0.1:${state.port}/pair`, {
849 method: 'POST',
850 headers: {
851 'Content-Type': 'application/json',
852 'Authorization': `Bearer ${state.token}`,
853 },
854 body: JSON.stringify({
855 domains,
856 clientId: clientName,
857 control,
858 ...(restrict ? { scopes: restrict.split(',').map(s => s.trim()) } : {}),
859 }),
860 signal: AbortSignal.timeout(5000),
861 });
862
863 if (!pairResp.ok) {
864 const err = await pairResp.text();
865 console.error(`[browse] Failed to create setup key: ${err}`);
866 process.exit(1);
867 }
868
869 const pairData = await pairResp.json() as {
870 setup_key: string;
871 expires_at: string;
872 scopes: string[];
873 tunnel_url: string | null;
874 server_url: string;
875 };
876
877 // Determine the URL to use
878 let serverUrl: string;
879 if (pairData.tunnel_url) {
880 // Server already verified the tunnel is alive, but double-check from CLI side
881 // in case of race condition between server probe and our request
882 try {
883 const cliProbe = await fetch(`${pairData.tunnel_url}/health`, {
884 headers: { 'ngrok-skip-browser-warning': 'true' },
885 signal: AbortSignal.timeout(5000),
886 });
887 if (cliProbe.ok) {
888 serverUrl = pairData.tunnel_url;
889 } else {
890 console.warn(`[browse] Tunnel returned HTTP ${cliProbe.status}, attempting restart...`);
891 pairData.tunnel_url = null; // fall through to restart logic
892 }
893 } catch {
894 console.warn('[browse] Tunnel unreachable from CLI, attempting restart...');
895 pairData.tunnel_url = null; // fall through to restart logic

Callers 1

mainFunction · 0.85

Calls 8

writeSecureFileFunction · 0.90
parseFlagFunction · 0.85
hasFlagFunction · 0.85
isNgrokAvailableFunction · 0.85
getHostConfigFunction · 0.85
generateInstructionBlockFunction · 0.85
fetchFunction · 0.70
textMethod · 0.45

Tested by

no test coverage detected