如何防止Claude自动隐藏侧栏不让切换对话?

我用Simple Chat Hub这个扩展
https://chromewebstore.google.com/detail/simple-chat-hub/dpfkgaedamhcmkkgeiajeggihmfjhhlj
在这个里面用Claude网页版,Claude发现是被嵌套在iframe里,就自动隐藏掉侧栏,不让切换对话

很可惜扩展开发者的账号被Anthropic给ban了,没法处理…… :melting_face:

站里有没有手搓大神搓一个脚本出来,防止Claude隐藏侧栏?
我用AI搓了两个,都不管用…… :melting_face:

失败案例1:

// ==UserScript==
// @name         Claude反iframe嵌套检测-Gemini
// @namespace    http://tampermonkey.net/
// @version      20260611
// @description  伪装 window.top 和 parent,防止网站检测到被嵌套在 iframe 中(仅限 JS 检测)
// @author       Gemini
// @include      https://claude.ai/*
// @run-at       document-start
// @grant        none
// ==/UserScript==


(function() {
    'use strict';

    // 这段函数将被转化为字符串,直接注入到网页的真实执行环境中
    function bypassInMainWorld() {
        // 如果当前页面本身就是顶层窗口,则不需要伪装
        if (window.self === window.top) return;

        const defineProp = (obj, prop, value) => {
            try {
                Object.defineProperty(obj, prop, {
                    get: () => value,
                    configurable: true,
                    enumerable: true
                });
            } catch (e) {
                console.warn(`[Iframe Bypass] 无法伪装属性: ${prop}`, e);
            }
        };

        // 1. 基础关系伪装
        defineProp(window, 'top', window);
        defineProp(window, 'parent', window);
        defineProp(window, 'frameElement', null);

        // 2. 绕过现代浏览器的 ancestorOrigins 检测 (极其重要)
        // 很多现代网站会检查 window.location.ancestorOrigins.length 是否大于 0
        if (window.location && 'ancestorOrigins' in window.location) {
            try {
                const emptyOrigins = Object.create(DOMStringList.prototype);
                Object.defineProperties(emptyOrigins, {
                    length: { value: 0, configurable: true },
                    item: { value: () => null, configurable: true },
                    contains: { value: () => false, configurable: true }
                });
                defineProp(window.location, 'ancestorOrigins', emptyOrigins);
            } catch (e) {}
        }

        // 3. 伪装 document.referrer (防止网站通过来源域名判断)
        defineProp(document, 'referrer', '');

        console.log('[Iframe Bypass V2] 核心环境伪装已注入主线程。');
    }

    // 将上面编写的函数转为字符串,作为 script 标签直接插进 DOM 树
    // 这样可以彻底摆脱油猴沙箱的限制,让网页自身的 JS 只能读到我们修改后的值
    const script = document.createElement('script');
    script.textContent = `(${bypassInMainWorld.toString()})();`;

    if (document.documentElement) {
        document.documentElement.appendChild(script);
        script.remove();
    } else {
        // 保险兜底:如果 documentElement 还没准备好,用观察器第一时间注入
        const observer = new MutationObserver(() => {
            if (document.documentElement) {
                document.documentElement.appendChild(script);
                script.remove();
                observer.disconnect();
            }
        });
        observer.observe(document, { childList: true, subtree: true });
    }
})();

失败案例2

// ==UserScript==
// @name         Claude反iframe嵌套检测-Copilot
// @namespace    http://tampermonkey.net/
// @version      20260611
// @description  伪装 window.top 和 parent,防止网站检测到被嵌套在 iframe 中(仅限 JS 检测)
// @author       Copilot
// @include      https://claude.ai/*
// @run-at       document-start
// @grant        none
// ==/UserScript==



(function(){
  'use strict';
  const inject = (fn) => {
    const s = document.createElement('script');
    s.textContent = '('+fn.toString()+')();';
    document.documentElement.appendChild(s);
    s.remove();
  };

  inject(function(){
    try{
      // 1) 覆盖 document.referrer
      try {
        Object.defineProperty(document, 'referrer', { configurable:true, get:()=>'' });
      } catch(e){}

      // 2) 覆盖 frameElement
      try {
        Object.defineProperty(window, 'frameElement', { configurable:true, get:()=>null });
      } catch(e){}

      // 3) 拦截 self!==top 检测:用 Proxy 包装 window 对象的 top 属性访问(尽力而为)
      try {
        const handler = {
          get(target, prop, receiver){
            if(prop === 'top') return receiver;
            return Reflect.get(target, prop, receiver);
          }
        };
        // 仅在可行时替换 window 的原型链代理
        const winProxy = new Proxy(window, handler);
        // 将常用全局名绑定到代理(尽力覆盖页面脚本读取)
        window.__winProxy = winProxy;
        // 覆盖常见全局引用
        try { window.top = window; } catch(e){}
      } catch(e){}

      // 4) 劫持 Function.prototype.toString 以隐藏检测代码片段
      try {
        const origToString = Function.prototype.toString;
        Function.prototype.toString = function(){
          const s = origToString.call(this);
          if(/self\s*!==\s*top|window\.frameElement|document\.referrer/.test(s)){
            return 'function() { /* hidden */ }';
          }
          return s;
        };
      } catch(e){}

      // 5) 拦截 postMessage 检测(页面可能向父窗口发送探测消息)
      try {
        const origPost = window.postMessage;
        window.postMessage = function(msg, targetOrigin, transfer){
          if(typeof msg === 'string' && /areYouTop|amIFramed/i.test(msg)) return;
          return origPost.call(this, msg, targetOrigin, transfer);
        };
      } catch(e){}

      // 6) 覆盖 addEventListener 以捕获“message”监听器中对 top 的检测
      try {
        const origAdd = EventTarget.prototype.addEventListener;
        EventTarget.prototype.addEventListener = function(type, listener, opts){
          if(type === 'message'){
            const wrapped = function(ev){
              try{
                // 屏蔽来自父窗口的探测
                if(ev && ev.data && /areYouTop|amIFramed/i.test(ev.data)) return;
              }catch(e){}
              return listener.call(this, ev);
            };
            return origAdd.call(this, type, wrapped, opts);
          }
          return origAdd.call(this, type, listener, opts);
        };
      } catch(e){}

      // 7) 记录当前策略是否可能失败(用于调试)
      try {
        const ok = (function(){ try { return window.self === window.top; } catch(e){ return false; } })();
        if(!ok){
          console.warn('iframe-bypass: partial — some detections may still work');
        }
      } catch(e){}
    }catch(e){
      console.error('iframe-bypass: injection failed', e);
    }
  });

})();

换了种思路,不盯着侧栏了,反正目的都是获取历史对话,那就通过claude的API获取出来
改换思路后让AI写了个userscript,很简单