]*>\s*<\/div>$/.test(content);
- if (!hasContent) {
- outputArea.style.cssText = 'display: none !important; visibility: hidden !important; height: 0 !important; min-height: 0 !important; max-height: 0 !important; padding: 0 !important; margin: 0 !important; border: none !important; opacity: 0 !important;';
- outputArea.classList.add('hidden-output');
- outputArea.classList.remove('has-content');
- }
- }
- }
-
- // 多次尝试隐藏,确保在各种时机都能生效
- hideOutputAreaEarly();
- document.addEventListener('DOMContentLoaded', hideOutputAreaEarly);
- setTimeout(hideOutputAreaEarly, 0);
- setTimeout(hideOutputAreaEarly, 100);
- setTimeout(hideOutputAreaEarly, 300);
- setTimeout(hideOutputAreaEarly, 500);
- setTimeout(function() { initCarousel(); initLayout(); }, 1000);
- setTimeout(function() { initCarousel(); initLayout(); }, 2000);
-
- // 深色模式适配 - 动态更新 output-area 背景色(防闪烁优化版)
- let lastUpdateTime = 0;
- const UPDATE_THROTTLE = 50; // 最小更新间隔 50ms
-
- function updateOutputAreaDarkMode() {
- const now = Date.now();
- if (now - lastUpdateTime < UPDATE_THROTTLE) {
- return; // 跳过过于频繁的更新
- }
- lastUpdateTime = now;
-
- const outputArea = document.getElementById('output-area');
- if (!outputArea) return;
-
- // 检查是否是深色模式
- const isDark = document.documentElement.classList.contains('dark') ||
- document.body.classList.contains('dark') ||
- window.matchMedia('(prefers-color-scheme: dark)').matches;
-
- if (isDark) {
- // 深色模式:深色背景
- outputArea.style.setProperty('background', '#111827', 'important');
- outputArea.style.setProperty('border-color', '#374151', 'important');
- } else {
- // 浅色模式:浅色背景
- outputArea.style.setProperty('background', '#fafafa', 'important');
- outputArea.style.setProperty('border-color', '#e5e7eb', 'important');
- }
- }
-
- // 延迟初始化,避免页面加载时闪烁
- setTimeout(function() {
- updateOutputAreaDarkMode();
-
- // 监听深色模式变化
- const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
- darkModeMediaQuery.addEventListener('change', updateOutputAreaDarkMode);
-
- // 监听 DOM class 变化
- const darkModeObserver = new MutationObserver(updateOutputAreaDarkMode);
- darkModeObserver.observe(document.documentElement, {
- attributes: true,
- attributeFilter: ['class']
- });
- darkModeObserver.observe(document.body, {
- attributes: true,
- attributeFilter: ['class']
- });
-
- // 监听 output-area 的内容变化
- const outputArea = document.getElementById('output-area');
- if (outputArea) {
- const outputContentObserver = new MutationObserver(function() {
- // 内容变化时立即应用深色模式样式
- requestAnimationFrame(updateOutputAreaDarkMode);
- });
-
- outputContentObserver.observe(outputArea, {
- childList: true,
- subtree: true
- });
- }
- }, 500); // 延迟 500ms 后再启动监听
-})();
-"""
-
-def create_interface():
- # Get the directory where this script is located for static files
- script_dir = os.path.dirname(os.path.abspath(__file__))
-
- # Helper function to convert image to base64 for embedding in HTML
- def image_to_base64(image_path):
- """Convert image file to base64 string for HTML embedding."""
- try:
- with open(image_path, 'rb') as img_file:
- img_data = img_file.read()
- b64_string = base64.b64encode(img_data).decode('utf-8')
- # Determine MIME type based on file extension
- ext = image_path.lower().split('.')[-1]
- mime_types = {
- 'png': 'image/png',
- 'jpg': 'image/jpeg',
- 'jpeg': 'image/jpeg',
- 'svg': 'image/svg+xml',
- 'gif': 'image/gif'
- }
- mime_type = mime_types.get(ext, 'image/png')
- return f"data:{mime_type};base64,{b64_string}"
- except Exception as e:
- print(f"Error loading image {image_path}: {e}")
- return ""
-
- # Inline CSS - all styles embedded directly
- INLINE_CSS = """
- /* Global Styles */
- .gradio-container {
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
- }
-
- /* Thinking Styles */
- .thinking-collapsed {
- background: #f9fafb;
- border: 1px solid #e5e7eb;
- border-radius: 8px;
- padding: 0.75rem;
- margin: 0.5rem 0;
- }
-
- .thinking-collapsed summary {
- cursor: pointer;
- font-weight: 500;
- color: #6b7280;
- font-size: 0.875rem;
- }
-
- .thinking-collapsed summary:hover {
- color: #374151;
- }
-
- .thinking-content {
- margin-top: 0.5rem;
- color: #374151;
- white-space: pre-wrap;
- font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
- font-size: 0.875rem;
- line-height: 1.5;
- }
-
- .thinking-streaming {
- background: #f0f9ff;
- border: 1px solid #bae6fd;
- border-radius: 8px;
- padding: 0.875rem;
- margin: 0.5rem 0;
- color: #0c4a6e;
- white-space: pre-wrap;
- font-family: 'SF Mono', Monaco, monospace;
- font-size: 0.875rem;
- line-height: 1.5;
- }
-
- /* Tool Call Card */
- .tool-call-card {
- background: #f9fafb;
- border-radius: 8px;
- padding: 1rem;
- margin: 0.75rem 0;
- }
-
- .tool-info {
- display: flex;
- flex-direction: column;
- gap: 0.25rem;
- }
-
- .tool-name {
- font-weight: 600;
- color: #374151;
- font-size: 0.875rem;
- }
-
- .tool-detail {
- color: #6b7280;
- font-size: 0.8rem;
- }
-
- /* Result Card */
- .result-card-expanded {
- background: white;
- border-radius: 8px;
- padding: 1.25rem;
- margin: 1rem 0;
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
- }
-
- .result-header-expanded {
- font-weight: 600;
- color: #374151;
- margin-bottom: 1.25rem;
- padding-bottom: 0.5rem;
- border-bottom: 1px solid #e5e7eb;
- font-size: 1rem;
- }
-
- .result-content-expanded {
- color: #4b5563;
- line-height: 1.6;
- }
-
- .result-content-expanded p {
- margin: 0.5rem 0;
- }
-
- .result-content-expanded code {
- background: #f3f4f6;
- padding: 0.125rem 0.375rem;
- border-radius: 3px;
- font-family: monospace;
- font-size: 0.875em;
- }
-
- /* Search Result Card Hover */
- .search-result-card {
- transition: all 0.2s ease;
- }
-
- .search-result-card:hover {
- box-shadow: 0 2px 8px rgba(102, 126, 234, 0.15) !important;
- border-color: #667eea !important;
- }
-
- /* Answer Section */
- .answer-section {
- background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
- border-left: 4px solid #10a37f;
- border-radius: 8px;
- padding: 1.5rem;
- margin: 1rem 0;
- }
-
- .answer-section p {
- color: #374151;
- line-height: 1.7;
- margin: 0.5rem 0;
- }
-
- .answer-section strong {
- color: #1e293b;
- font-weight: 600;
- }
-
- .answer-section a {
- color: #10a37f;
- text-decoration: none;
- font-weight: 500;
- }
-
- .answer-section a:hover {
- text-decoration: underline;
- }
-
- /* User Message Bubble - 淡蓝色背景,右对齐 */
- .user-message-bubble {
- background: linear-gradient(135deg, #e0f2fe 0%, #bae6fd 100%);
- color: #0c4a6e;
- border-radius: 1rem 1rem 0.25rem 1rem;
- padding: 1rem 1.25rem;
- margin: 1rem 0 1rem auto;
- max-width: 80%;
- box-shadow: 0 2px 8px rgba(14, 165, 233, 0.2);
- border: 1px solid #7dd3fc;
- text-align: left;
- }
-
- /* Reference Section Collapsible */
- .reference-section {
- margin-top: 40px;
- border-top: 1px solid #e5e7eb;
- padding-top: 20px;
- }
-
- .reference-title {
- font-size: 1.2rem;
- font-weight: 600;
- margin-bottom: 16px;
- color: #111827;
- cursor: pointer;
- outline: none;
- }
-
- .ref-url {
- text-align: left !important;
- }
-
- .user-message-content {
- line-height: 1.6;
- font-size: 0.95rem;
- }
-
- /* Output area - 固定高度可滚动 */
- /* 强制固定高度,内容在里面滚动 */
- #output-area,
- #output-area.output-box,
- div#output-area {
- height: 50vh !important;
- min-height: 250px !important;
- max-height: 50vh !important;
- overflow-y: scroll !important;
- overflow-x: hidden !important;
- padding: 1rem !important;
- border: 1px solid #e5e7eb !important;
- border-radius: 8px !important;
- background: #fafafa !important;
- scroll-behavior: smooth;
- flex-shrink: 0 !important;
- flex-grow: 0 !important;
- }
-
- /* 内部所有元素不能撑破容器 */
- #output-area * {
- max-height: none !important;
- overflow: visible !important;
- }
-
- #output-area > div {
- height: auto !important;
- max-height: none !important;
- overflow: visible !important;
- border: none !important;
- background: transparent !important;
- padding: 0 !important;
- margin: 0 !important;
- box-shadow: none !important;
- }
-
- /* 初始状态和空内容时隐藏 output-area */
- #output-area:empty,
- #output-area.hidden-output,
- #output-area:not(.has-content),
- .hidden-output#output-area,
- div.hidden-output#output-area,
- #main-content #output-area.hidden-output,
- #main-content .output-box.hidden-output {
- display: none !important;
- visibility: hidden !important;
- height: 0 !important;
- min-height: 0 !important;
- max-height: 0 !important;
- padding: 0 !important;
- margin: 0 !important;
- border: none !important;
- opacity: 0 !important;
- overflow: hidden !important;
- }
-
- /* 防止内部内容撑破容器 */
- #output-area > * {
- max-width: 100%;
- word-wrap: break-word;
- overflow-wrap: break-word;
- }
-
- /* 主内容区域布局 - 限制整体高度 */
- #main-content {
- display: flex !important;
- flex-direction: column !important;
- height: auto !important;
- max-height: none !important;
- overflow: visible !important;
- }
-
- /* Gradio 包装容器限制 */
- #main-content > div {
- flex-shrink: 0;
- }
-
- #output-area::-webkit-scrollbar {
- width: 8px;
- }
-
- #output-area::-webkit-scrollbar-track {
- background: #f1f1f1;
- border-radius: 4px;
- }
-
- #output-area::-webkit-scrollbar-thumb {
- background: #c1c1c1;
- border-radius: 4px;
- }
-
- #output-area::-webkit-scrollbar-thumb:hover {
- background: #a1a1a1;
- }
-
- /* 自动滚动控制按钮样式 */
- #auto-scroll-checkbox {
- margin-top: 0.5rem;
- }
-
- #auto-scroll-checkbox label {
- font-size: 0.85rem;
- color: #4b5563;
- }
-
- /* Completion Message */
- .completion-msg {
- text-align: center;
- color: #10a37f;
- font-weight: 600;
- padding: 1rem;
- margin: 1rem 0;
- background: #f0fdf4;
- border-radius: 8px;
- border: 1px solid #86efac;
- }
-
- /* Error Message */
- .error-message {
- background: #fee2e2;
- border-left: 4px solid #dc2626;
- border-radius: 8px;
- padding: 1rem;
- margin: 1rem 0;
- color: #991b1b;
- }
-
- .error-message strong {
- color: #7f1d1d;
- }
-
- .error-message a {
- color: #dc2626;
- font-weight: 500;
- }
-
- /* Round Badge - 淡蓝色背景 */
- .round-badge {
- display: inline-block;
- background: linear-gradient(135deg, #e0f2fe 0%, #bae6fd 100%);
- color: #0369a1;
- padding: 0.25rem 0.75rem;
- border-radius: 999px;
- font-size: 0.75rem;
- font-weight: 600;
- margin: 0.5rem 0;
- box-shadow: 0 2px 4px rgba(14, 165, 233, 0.15);
- border: 1px solid #7dd3fc;
- }
-
- /* Settings Section */
- #settings-group {
- background: transparent !important;
- border: none !important;
- padding: 0 !important;
- box-shadow: none !important;
- gap: 0 !important;
- }
-
- #max-rounds-slider, #auto-scroll-checkbox {
- background: #f9fafb;
- border: 1px solid #e5e7eb;
- border-radius: 6px;
- padding: 0.75rem;
- margin-bottom: 0.5rem;
- }
-
- .settings-header {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- margin-bottom: 0.875rem;
- }
-
- .settings-title {
- font-size: 0.875rem;
- font-weight: 600;
- color: #374151;
- }
-
- .settings-api-row {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-bottom: 0.375rem;
- }
-
- .settings-label {
- font-size: 0.8rem;
- font-weight: 500;
- color: #4b5563;
- }
-
- .settings-help-link {
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- font-size: 0.7rem;
- color: #667eea;
- text-decoration: none;
- transition: opacity 0.2s;
- }
-
- .settings-help-icon {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 14px;
- height: 14px;
- border-radius: 50%;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- font-size: 0.6rem;
- font-weight: bold;
- }
-
- /* Tools Section */
- .tools-section {
- margin-top: 0;
- }
-
- .tools-title {
- font-size: 0.875rem;
- font-weight: 600;
- color: #374151;
- margin-bottom: 0.5rem;
- margin-top: 0;
- }
-
- /* Tool Item */
- .tool-item {
- background: #f9fafb;
- padding: 0.75rem;
- border-radius: 6px;
- margin-bottom: 0.5rem;
- border: 1px solid #e5e7eb;
- }
-
- .tool-item strong {
- color: #374151;
- font-size: 0.85rem;
- }
-
- .tool-item span {
- color: #6b7280;
- font-size: 0.8rem;
- }
-
- /* Examples Section */
- .examples-section {
- margin-top: -0.5rem;
- }
-
- .examples-title {
- font-size: 0.875rem;
- font-weight: 600;
- color: #374151;
- margin-bottom: 0.5rem;
- }
-
- /* Example Carousel */
- .example-carousel {
- background: white;
- border-radius: 8px;
- padding: 1rem;
- border: 1px solid #e5e7eb;
- }
-
- .carousel-container {
- position: relative;
- min-height: 60px;
- margin-bottom: 0.75rem;
- }
-
- .carousel-item {
- display: none;
- opacity: 0;
- transition: opacity 0.3s ease;
- }
-
- .carousel-item.active {
- display: block;
- opacity: 1;
- }
-
- .carousel-item-text {
- background: linear-gradient(135deg, #f0f4ff 0%, #e8eeff 100%);
- padding: 1rem;
- border-radius: 6px;
- color: #374151;
- font-size: 0.875rem;
- line-height: 1.5;
- border: 1px solid #e0e7ff;
- }
-
- .carousel-controls {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 1rem;
- }
-
- .carousel-btn {
- cursor: pointer;
- width: 32px;
- height: 32px;
- border-radius: 50%;
- background: #f3f4f6;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 1.25rem;
- color: #6b7280;
- transition: all 0.2s ease;
- user-select: none;
- }
-
- .carousel-btn:hover {
- background: #667eea;
- color: white;
- }
-
- .carousel-indicators {
- display: flex;
- gap: 0.5rem;
- }
-
- .carousel-dot {
- width: 8px;
- height: 8px;
- border-radius: 50%;
- background: #d1d5db;
- cursor: pointer;
- transition: all 0.2s ease;
- }
-
- .carousel-dot.active {
- background: #667eea;
- width: 24px;
- border-radius: 4px;
- }
-
- /* Welcome Message */
- .welcome-container {
- text-align: center;
- padding: 3rem 2rem;
- }
-
- .welcome-title {
- font-size: 2rem;
- font-weight: 700;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
- margin-bottom: 1rem;
- }
-
- .welcome-subtitle {
- color: #6b7280;
- font-size: 1.1rem;
- margin-bottom: 2rem;
- }
-
- /* Footer */
- .footer-container {
- text-align: center;
- padding: 1.5rem;
- color: #9ca3af;
- font-size: 0.875rem;
- border-top: 1px solid #e5e7eb;
- margin-top: 2rem;
- }
-
- .footer-container a {
- color: #667eea;
- text-decoration: none;
- }
-
- .footer-container a:hover {
- text-decoration: underline;
- }
-
- /* Disclaimer */
- .disclaimer {
- text-align: center;
- padding: 1rem;
- color: #6b7280;
- font-size: 0.875rem;
- border-top: 1px solid #e5e7eb;
- margin-top: 1rem;
- }
-
- /* ========== 深色模式适配 ========== */
- @media (prefers-color-scheme: dark) {
- /* Settings 区域 */
- #settings-group {
- background: transparent !important;
- border: none !important;
- padding: 0 !important;
- gap: 0 !important;
- }
-
- #max-rounds-slider, #auto-scroll-checkbox {
- background: #1f2937 !important;
- border: 1px solid #374151 !important;
- border-radius: 6px !important;
- padding: 0.75rem !important;
- }
-
- .settings-title,
- .tools-title,
- .examples-title {
- color: #e5e7eb !important;
- }
-
- .settings-label {
- color: #9ca3af !important;
- }
-
- .settings-help-link {
- color: #818cf8 !important;
- }
-
- /* Available Tools 区域 */
- .tool-item {
- background: #1f2937 !important;
- border-color: #374151 !important;
- }
-
- .tool-item strong {
- color: #e5e7eb !important;
- }
-
- .tool-item span {
- color: #9ca3af !important;
- }
-
- /* Example Carousel 区域 */
- .example-carousel {
- background: #1f2937 !important;
- border-color: #374151 !important;
- }
-
- .carousel-item-text {
- background: linear-gradient(135deg, #1e3a5f 0%, #1e40af 100%) !important;
- border-color: #3b82f6 !important;
- color: #e0f2fe !important;
- }
-
- .carousel-btn {
- background: #374151 !important;
- color: #9ca3af !important;
- }
-
- .carousel-btn:hover {
- background: #667eea !important;
- color: white !important;
- }
-
- .carousel-dot {
- background: #4b5563 !important;
- }
-
- .carousel-dot.active {
- background: #667eea !important;
- }
-
- /* Output area 深色模式 */
- #output-area,
- #output-area.output-box,
- div#output-area {
- background: #111827 !important;
- border: 1px solid #374151 !important;
- }
-
- #output-area::-webkit-scrollbar-track {
- background: #1f2937 !important;
- }
-
- #output-area::-webkit-scrollbar-thumb {
- background: #4b5563 !important;
- }
-
- #output-area::-webkit-scrollbar-thumb:hover {
- background: #6b7280 !important;
- }
-
- /* Tool call card 深色模式 */
- .tool-call-card {
- background: #1f2937 !important;
- }
-
- .tool-name {
- color: #e5e7eb !important;
- }
-
- .tool-detail {
- color: #9ca3af !important;
- }
-
- /* Result card 深色模式 */
- .result-card-expanded {
- background: #1f2937 !important;
- }
-
- .result-header-expanded {
- color: #e5e7eb !important;
- border-bottom-color: #374151 !important;
- }
-
- .result-content-expanded {
- color: #d1d5db !important;
- }
-
- /* Thinking 深色模式 */
- .thinking-collapsed {
- background: #1f2937 !important;
- border-color: #374151 !important;
- }
-
- .thinking-collapsed summary {
- color: #9ca3af !important;
- }
-
- .thinking-content {
- color: #d1d5db !important;
- }
-
- .thinking-streaming {
- background: #0c4a6e !important;
- border-color: #0369a1 !important;
- color: #bae6fd !important;
- }
-
- /* Answer section 深色模式 */
- .answer-section {
- background: linear-gradient(135deg, #0c4a6e 0%, #164e63 100%) !important;
- }
-
- .answer-section p {
- color: #e0f2fe !important;
- }
-
- .answer-section strong {
- color: #f0f9ff !important;
- }
-
- /* 用户问题气泡深色模式 */
- .user-message-bubble {
- background: linear-gradient(135deg, #1e3a5f 0%, #1e40af 100%) !important;
- color: #e0f2fe !important;
- border-color: #3b82f6 !important;
- box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3) !important;
- }
-
- .user-message-content {
- color: #e0f2fe !important;
- }
-
- /* Round Badge 深色模式 */
- .round-badge {
- background: linear-gradient(135deg, #1e3a5f 0%, #1e40af 100%) !important;
- color: #93c5fd !important;
- border-color: #3b82f6 !important;
- box-shadow: 0 2px 4px rgba(59, 130, 246, 0.2) !important;
- }
-
- /* 搜索结果卡片深色模式 */
- .search-result-card {
- background: #1f2937 !important;
- border-color: #374151 !important;
- }
-
- .search-result-card:hover {
- border-color: #667eea !important;
- }
-
- /* 工具结果标题区域深色模式 */
- .result-card-expanded div[style*="background: linear-gradient"] {
- background: linear-gradient(135deg, #1e3a5f 0%, #1e40af 100%) !important;
- border-color: #3b82f6 !important;
- }
-
- .result-card-expanded div[style*="background: linear-gradient"] span[style*="color: #1e40af"],
- .result-card-expanded div[style*="background: linear-gradient"] a[style*="color: #1e40af"] {
- color: #93c5fd !important;
- }
-
- .result-card-expanded div[style*="color: #64748b"] {
- color: #9ca3af !important;
- }
-
- /* 完成消息深色模式 */
- .completion-msg {
- background: #064e3b !important;
- border-color: #059669 !important;
- color: #6ee7b7 !important;
- }
-
- /* 错误消息深色模式 */
- .error-message {
- background: #450a0a !important;
- border-color: #b91c1c !important;
- color: #fca5a5 !important;
- }
-
- /* 侧边栏标题深色模式 */
- div[style*="font-weight: 600"][style*="color: #374151"] {
- color: #e5e7eb !important;
- }
-
- /* Disclaimer 深色模式 */
- .disclaimer {
- color: #9ca3af !important;
- border-color: #374151 !important;
- }
- }
-
- /* Gradio 深色主题类名适配 */
- .dark #settings-group,
- .dark .tool-item,
- .dark .example-carousel {
- background: #1f2937 !important;
- border-color: #374151 !important;
- }
-
- .dark .settings-title,
- .dark .tools-title,
- .dark .examples-title,
- .dark .tool-item strong,
- .dark .result-header-expanded,
- .dark .tool-name {
- color: #e5e7eb !important;
- }
-
- .dark .settings-label,
- .dark .tool-item span,
- .dark .tool-detail,
- .dark .thinking-collapsed summary {
- color: #9ca3af !important;
- }
-
- .dark .settings-help-link {
- color: #818cf8 !important;
- }
-
- .dark .carousel-item-text {
- background: linear-gradient(135deg, #1e3a5f 0%, #1e40af 100%) !important;
- border-color: #3b82f6 !important;
- color: #e0f2fe !important;
- }
-
- .dark #output-area,
- .dark #output-area.output-box,
- .dark div#output-area {
- background: #111827 !important;
- border: 1px solid #374151 !important;
- }
-
- .dark .tool-call-card,
- .dark .result-card-expanded,
- .dark .thinking-collapsed {
- background: #1f2937 !important;
- border-color: #374151 !important;
- }
-
- .dark .result-content-expanded,
- .dark .thinking-content {
- color: #d1d5db !important;
- }
-
- .dark .answer-section {
- background: linear-gradient(135deg, #0c4a6e 0%, #164e63 100%) !important;
- }
-
- .dark .answer-section p {
- color: #e0f2fe !important;
- }
-
- .dark .search-result-card {
- background: #1f2937 !important;
- border-color: #374151 !important;
- }
-
- .dark .completion-msg {
- background: #064e3b !important;
- border-color: #059669 !important;
- color: #6ee7b7 !important;
- }
-
- /* 用户问题气泡 Gradio dark 模式 */
- .dark .user-message-bubble {
- background: linear-gradient(135deg, #1e3a5f 0%, #1e40af 100%) !important;
- color: #e0f2fe !important;
- border-color: #3b82f6 !important;
- box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3) !important;
- }
-
- .dark .user-message-content {
- color: #e0f2fe !important;
- }
-
- /* Round Badge Gradio dark 模式 */
- .dark .round-badge {
- background: linear-gradient(135deg, #1e3a5f 0%, #1e40af 100%) !important;
- color: #93c5fd !important;
- border-color: #3b82f6 !important;
- box-shadow: 0 2px 4px rgba(59, 130, 246, 0.2) !important;
- }
-
- /* 工具结果标题 Gradio dark 模式 */
- .dark .result-card-expanded div[style*="background: linear-gradient"] {
- background: linear-gradient(135deg, #1e3a5f 0%, #1e40af 100%) !important;
- border-color: #3b82f6 !important;
- }
-
- /* Disclaimer Gradio dark 模式 */
- .dark .disclaimer {
- color: #9ca3af !important;
- border-color: #374151 !important;
- }
- /* Reference Section */
- .reference-section {
- margin-top: 40px;
- border-top: 1px solid #e5e7eb;
- padding-top: 20px;
- }
- .reference-title {
- font-size: 1.2rem;
- font-weight: 600;
- margin-bottom: 16px;
- color: #111827;
- }
- .reference-item {
- display: block;
- background-color: #fff;
- border: 1px solid #e5e7eb;
- border-radius: 12px;
- padding: 12px 16px;
- margin-bottom: 12px;
- text-decoration: none;
- color: #374151;
- transition: all 0.2s;
- box-shadow: 0 1px 2px rgba(0,0,0,0.05);
- }
- .reference-item:hover {
- border-color: #3b82f6;
- box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1);
- transform: translateY(-1px);
- text-decoration: none;
- }
- .ref-number {
- display: inline-block;
- background-color: #eff6ff;
- color: #2563eb;
- font-weight: 600;
- padding: 2px 6px;
- border-radius: 6px;
- margin-right: 8px;
- font-size: 0.85em;
- }
- .ref-text {
- font-weight: 500;
- color: #1f2937;
- }
- .ref-url {
- display: block;
- margin-top: 4px;
- font-size: 0.8em;
- color: #6b7280;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- /* 深色模式适配 Reference Section */
- @media (prefers-color-scheme: dark) {
- .reference-title {
- color: #e5e7eb !important;
- }
- .reference-item {
- background-color: #1f2937 !important;
- border-color: #374151 !important;
- color: #d1d5db !important;
- }
- .reference-item:hover {
- border-color: #667eea !important;
- }
- .ref-number {
- background-color: #1e3a5f !important;
- color: #93c5fd !important;
- }
- .ref-text {
- color: #e5e7eb !important;
- }
- .ref-url {
- color: #9ca3af !important;
- }
- }
-
- /* Gradio dark 模式适配 Reference Section */
- .dark .reference-title {
- color: #e5e7eb !important;
- }
- .dark .reference-item {
- background-color: #1f2937 !important;
- border-color: #374151 !important;
- color: #d1d5db !important;
- }
- .dark .reference-item:hover {
- border-color: #667eea !important;
- }
- .dark .ref-number {
- background-color: #1e3a5f !important;
- color: #93c5fd !important;
- }
- .dark .ref-text {
- color: #e5e7eb !important;
- }
- .dark .ref-url {
- color: #9ca3af !important;
- }
- """
-
- with gr.Blocks(css=INLINE_CSS, theme=gr.themes.Soft(), js=CAROUSEL_JS) as demo:
- # Header with logo and title images - convert to base64 for proper rendering
- # Files are in the same directory as app.py (test1/)
- logo_path = os.path.join(script_dir, "or-logo1.png")
- title_path = os.path.join(script_dir, "openresearcher-title.svg")
-
- logo_base64 = image_to_base64(logo_path)
- title_base64 = image_to_base64(title_path)
- lambda_path = os.path.join(script_dir, "lambda.png")
- lambda_base64 = image_to_base64(lambda_path)
-
- # Build header HTML with base64 images
- header_html = f"""
-
-""")
-
- # Main layout: Left sidebar + Right content
- with gr.Row():
- # Left Sidebar (settings & tools)
- with gr.Column(scale=1, min_width=280):
- # API Settings in a unified box
- with gr.Group(elem_id="settings-group"):
- gr.HTML('''
-
- ''')
- serper_input = gr.Textbox(
- label="",
- value=SERPER_API_KEY,
- type="password",
- placeholder="Enter your Serper API key...",
- show_label=False,
- elem_id="serper-api-input",
- container=False,
- visible=False
- )
- inference_mode_input = gr.Radio(
- choices=["Auto (local + cloud backup)", "Local only", "Cloud only"],
- value="Auto (local + cloud backup)",
- label="Inference Mode",
- elem_id="inference-mode-radio"
- )
- max_rounds_input = gr.Slider(
- minimum=1,
- maximum=200,
- value=50,
- step=1,
- label="Max Rounds",
- elem_id="max-rounds-slider"
- )
- auto_scroll_checkbox = gr.Checkbox(
- label="Auto Scroll",
- value=True,
- elem_id="auto-scroll-checkbox",
- interactive=True
- )
-
- # Tools info
- gr.HTML("""
-
- """)
-
- # Example carousel with navigation
- gr.HTML("""
-
- """)
-
- # Main content area (30-70)
- with gr.Column(scale=3, elem_id="main-content"):
- # Output area (on top, hidden initially)
- output_area = gr.HTML(
- value="",
- elem_classes=["output-box"],
- elem_id="output-area",
- visible=True
- )
-
- # Welcome message (will be hidden after first search)
- welcome_html = gr.HTML(
- value="""
-
-
What Would You Like to Research?
-
I am OpenResearcher, a leading open-source Deep Research Agent, welcome to try!
-
Due to high traffic, if your submission has no response, please refresh the page and resubmit. Thank you!
-
- """,
- elem_id="welcome-container"
- )
-
- # Input area at bottom
- question_input = gr.Textbox(
- label="",
- placeholder="Ask me anything and I'll handle the rest...",
- lines=2,
- show_label=False,
- elem_id="question-input",
- autofocus=True
- )
-
- with gr.Row(elem_id="button-row"):
- submit_btn = gr.Button(
- "🔍 Start DeepResearch",
- variant="primary",
- elem_classes=["primary-btn"],
- scale=3
- )
- stop_btn = gr.Button("⏹ Stop", variant="stop", scale=1)
- clear_btn = gr.Button("🗑 Clear", scale=1)
-
- # Lambda sponsor banner
- _lambda_img_tag = f'
- """)
-
- # Function to hide welcome and show output
- async def start_research(question, serper_key, max_rounds, inference_mode, agent_type):
- # Generator that first hides welcome, then streams results
- # Also clears the input box for the next question
-
- # Initial yield to immediately clear welcome, show loading in output, and clear input
- # IMPORTANT: Don't use empty string for output, or JS will hide the output area!
- yield "", '
Delving into it...
', ""
-
- if agent_type == "Deep Research":
- async for result in run_agent_streaming(question, serper_key, max_rounds, inference_mode):
- yield "", result, ""
- else:
- web_runner = get_web_agent_runner()
- if web_runner:
- async for result in web_runner(question, max_rounds, inference_mode):
- yield "", result, ""
- else:
- yield "", '
Web Action Mode not available.
', ""
-
- agent_type_input = gr.Dropdown(
- choices=["Deep Research", "Web Action"],
- value="Deep Research",
- label="Agent Mode",
- elem_id="agent-type-dropdown"
- )
-
- # Event handlers
- submit_event = submit_btn.click(
- fn=start_research,
- inputs=[question_input, serper_input, max_rounds_input, inference_mode_input, agent_type_input],
- outputs=[welcome_html, output_area, question_input],
- show_progress="hidden",
- concurrency_limit=20
- )
-
- question_input.submit(
- fn=start_research,
- inputs=[question_input, serper_input, max_rounds_input, inference_mode_input, agent_type_input],
- outputs=[welcome_html, output_area, question_input],
- show_progress="hidden",
- concurrency_limit=20
- )
-
- stop_btn.click(fn=None, inputs=None, outputs=None, cancels=[submit_event])
- clear_btn.click(
- fn=lambda: ("""
-
- """, "", ""),
- outputs=[welcome_html, output_area, question_input]
- )
-
- # Disclaimer
- gr.HTML('''
-
- ⚠️ AI may generate incorrect information or citations. Please double-check important facts.
-
- ''')
-
- return demo
-
-app = FastAPI()
-
-@app.get("/health")
-@app.head("/health")
-def health():
- return {"status": "ok"}
-
-@app.get("/api-docs", response_class=HTMLResponse)
-def api_docs():
- return """
-
-
-
-
- """
-
-demo = create_interface()
-app = gr.mount_gradio_app(app, demo, path="/")
-
-if __name__ == "__main__":
- print("="*60)
- print("OpenResearcher DeepSearch Agent - ZeroGPU Space")
- print("="*60)
- uvicorn.run(app, host="0.0.0.0", port=7860)
\ No newline at end of file
diff --git a/config/config.json b/config/config.json
deleted file mode 100644
index d0af4449aecc3f763b6c0b9e39384cda5f2afb85..0000000000000000000000000000000000000000
--- a/config/config.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "server": {
- "bind": "0.0.0.0",
- "port": "9867"
- },
- "instanceDefaults": {
- "mode": "headless"
- },
- "multiInstance": {
- "strategy": "simple"
- },
- "browser": {
- "binary": "/usr/bin/google-chrome"
- }
-}
diff --git a/entrypoint.sh b/entrypoint.sh
deleted file mode 100644
index 199b0bf50b09dea9ba34aa8b4c23caf2ef8adea6..0000000000000000000000000000000000000000
--- a/entrypoint.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-
-# Start Pinchtab in the background
-# Using 'server' command and custom config
-export PINCHTAB_CONFIG=/app/config/config.json
-pinchtab server &
-
-# Wait for Pinchtab to start (optional but helpful)
-# sleep 5
-
-# Start the Python application
-python app.py
diff --git a/lambda.png b/lambda.png
deleted file mode 100644
index 2b6b4a035282f06a1c422fcf53c23ec0d6521935..0000000000000000000000000000000000000000
--- a/lambda.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:fab6f3889e9ffd3609fc20fe7f8be8c971110fe044ab6ad17f8b6b2665d212aa
-size 222125
diff --git a/openresearcher-title.svg b/openresearcher-title.svg
deleted file mode 100644
index 4c711edeb0a27c0499c5d4c5f87ca288e676bd09..0000000000000000000000000000000000000000
--- a/openresearcher-title.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/or-logo1.png b/or-logo1.png
deleted file mode 100644
index 1c2c53946048c2651ffa75ca223845bf1496fe47..0000000000000000000000000000000000000000
--- a/or-logo1.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:4d6288904dea6e09ad8ec22bb342309c3bb774a96fc94698798f496649558418
-size 617714
diff --git a/pinchtab/.devcontainer/devcontainer.json b/pinchtab/.devcontainer/devcontainer.json
deleted file mode 100644
index a9382e4dd77517feba302639b63b2c143b9c3a57..0000000000000000000000000000000000000000
--- a/pinchtab/.devcontainer/devcontainer.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "PinchTab",
- "image": "mcr.microsoft.com/devcontainers/go:1.23",
- "features": {
- "ghcr.io/devcontainers/features/docker-in-docker:2": {}
- },
- "postCreateCommand": "docker compose up -d && go build -o pinchtab ./cmd/pinchtab && echo 'Done! Run: ./pinchtab health'",
- "forwardPorts": [9867],
- "portsAttributes": {
- "9867": {
- "label": "PinchTab",
- "onAutoForward": "notify"
- }
- }
-}
diff --git a/pinchtab/.dockerignore b/pinchtab/.dockerignore
deleted file mode 100644
index 7fb19cdfddd569047db4c82742ccdb8202d293f7..0000000000000000000000000000000000000000
--- a/pinchtab/.dockerignore
+++ /dev/null
@@ -1,42 +0,0 @@
-# Binaries
-pinchtab
-browser-bridge
-
-# Test coverage
-coverage.out
-*.test
-
-# Git
-.git/
-.github/
-
-# Tests (E2E fixtures, scenarios, results)
-tests/
-
-# Local state
-.pinchtab/
-.openclaw/
-
-# macOS
-.DS_Store
-
-# Editor
-.vscode/
-*.swp
-
-# Docs (not needed in image)
-docs/
-
-# Development
-node_modules/
-dashboard/node_modules/
-*.log
-
-# Build caches
-.gocache/
-.gomodcache/
-tmp/
-
-# Markdown (README, RELEASE, etc.)
-*.md
-!dashboard/**/*.md
diff --git a/pinchtab/.github/DEFINITION_OF_DONE.md b/pinchtab/.github/DEFINITION_OF_DONE.md
deleted file mode 100644
index cf3aacb274ba840f7207f65ac815f42b9330d7c2..0000000000000000000000000000000000000000
--- a/pinchtab/.github/DEFINITION_OF_DONE.md
+++ /dev/null
@@ -1,53 +0,0 @@
-# Definition of Done (PR Checklist)
-
-## Automated ✅ (CI/GitHub enforces these)
-These run automatically via `ci.yml`. If your PR fails them, fix and re-push.
-- [ ] Go formatting & linting passes (gofmt, vet, golangci-lint)
-- [ ] Unit + E2E tests pass (`go test ./...` and `./dev e2e`)
-- [ ] Build succeeds (`go build`)
-- [ ] CodeQL security scan passes
-- [ ] Branch naming follows convention
-
-## Manual — Code Quality (Required)
-- [ ] **Error handling explicit** — All errors wrapped with `%w`, no silent failures
-- [ ] **No regressions** — Verify stealth, token efficiency, session persistence work (test locally if unsure)
-- [ ] **SOLID principles** — Functions do one thing, testable, no unnecessary deps
-- [ ] **No redundant comments** — Comments explain *why* or *context*, not *what* the code does
- - ❌ Bad: `// Loop through items` above `for _, item := range items`
- - ❌ Bad: `// Return error` above `return err`
- - ✅ Good: `// Prioritize chromium-browser on ARM64 (Raspberry Pi default)`
- - ✅ Good: `// Chrome may not be installed in CI, so empty result is valid`
-
-## Manual — Testing (Required)
-- [ ] **New/changed functionality has tests** — Same-package unit tests preferred
-- [ ] **Docker E2E tests run locally** — If you modified handlers/bridge/tabs, run: `./dev e2e` (Docker curl E2E) and/or `./dev e2e cli` (Docker CLI E2E)
-- [ ] **npm commands work** (if npm wrapper touched):
- - `npm pack` in `/npm/` produces valid tarball
- - `npm install -g pinchtab` (or from local tarball) succeeds
- - `pinchtab --version` + basic commands work after install
-
-## Manual — Documentation (Required)
-- [ ] **README.md updated** — If user-facing changes (CLI, API, env vars, install)
-- [ ] **/docs/ updated** — If API/architecture/perf changed (optional for small fixes)
-
-## Manual — Review (Required)
-- [ ] **PR description explains what + why** — Especially stealth/perf/compatibility impact
-- [ ] **Commits are atomic** — Logical grouping, good messages
-- [ ] **No breaking changes to npm** — Unless explicitly major version bump
-
-## Conditional (Only if applicable)
-- [ ] Headed-mode tested (if dashboard/UI changes)
-- [ ] Breaking changes documented in PR description (if any)
-
----
-
-## Quick Checklist (Copy/Paste for PRs)
-```markdown
-## Definition of Done
-- [ ] Unit + Docker E2E tests added & passing
-- [ ] Error handling explicit (wrapped with %w)
-- [ ] No regressions in stealth/perf/persistence
-- [ ] No redundant comments (explain why, not what)
-- [ ] README/docs updated (if user-facing)
-- [ ] npm install works (if npm changes)
-```
diff --git a/pinchtab/.github/DOCUMENTATION_REVIEW.md b/pinchtab/.github/DOCUMENTATION_REVIEW.md
deleted file mode 100644
index 8f7b74346a8a2330149874dbc8821643876b0531..0000000000000000000000000000000000000000
--- a/pinchtab/.github/DOCUMENTATION_REVIEW.md
+++ /dev/null
@@ -1,398 +0,0 @@
-# Documentation Review Guide
-
-## Purpose
-
-Code is the source of truth. This guide helps agents audit, validate, and maintain documentation to ensure it stays in sync with the codebase.
-
-Use this document when asking agents to review documentation for accuracy, completeness, and consistency.
-
----
-
-## Quick Summary
-
-When asked to review documentation, an agent should:
-
-1. **Verify all examples match current code behavior**
-2. **Check doc structure against actual codebase**
-3. **Update or remove outdated content**
-4. **Report findings and improvements**
-
----
-
-## Detailed Review Process
-
-### Phase 1: Code-to-Docs Validation
-
-#### 1.1 Check All Examples
-
-For **every code example** in `/docs`:
-
-- [ ] **Run the example** (if it's executable)
- - Does it produce the expected output?
- - Does it work with current API/CLI?
- - Are environment variables correct?
-
-- [ ] **Verify API endpoints**
- - Do endpoints still exist? (`GET /snapshot`, `POST /action`, etc.)
- - Do request/response formats match?
- - Are all parameters documented?
- - Are deprecated endpoints removed?
-
-- [ ] **Verify CLI commands**
- - Do commands still exist? (`pinchtab config set`, `pinchtab health`, etc.)
- - Do they work as documented?
- - Are flags/options correct?
- - Are deprecated commands removed?
-
-- [ ] **Verify configuration values**
- - Do env vars still exist? (`CHROME_EXTENSION_PATHS`, `BRIDGE_PORT`, etc.)
- - Are default values correct?
- - Are deprecated config options removed?
-
-#### 1.2 Check Content Accuracy
-
-For **every paragraph, section, and claim** in `/docs`:
-
-- [ ] **API behavior** — Does it accurately describe current behavior?
-- [ ] **Performance notes** — Are benchmarks/timings still valid?
-- [ ] **Stealth/security claims** — Do they match current implementation?
-- [ ] **Feature availability** — Is feature still implemented?
-- [ ] **Limitations** — Are noted limitations still present?
-- [ ] **Requirements** — Are tool versions, Chrome versions, etc. correct?
-
-#### 1.3 Cross-Check Against Code
-
-Use the code as reference:
-
-```
-For each doc section:
-1. Find the corresponding code file(s)
-2. Compare doc description with actual implementation
-3. If different → docs are WRONG
-4. If missing → docs are INCOMPLETE
-5. If outdated → docs are STALE
-```
-
-**Example:**
-- Doc says: "fill action with refs sets the input value"
-- Code says: `FillByNodeID()` exists → docs are CORRECT ✅
-- Code says: no `FillByNodeID()` → docs are WRONG ❌
-
----
-
-### Phase 2: Structure Review
-
-#### 2.1 Check Documentation Structure
-
-**File structure should match codebase organization:**
-
-```
-docs/
-├── api/
-│ ├── endpoints/
-│ │ ├── navigation.md
-│ │ ├── snapshot.md
-│ │ ├── actions.md
-│ │ ├── find.md
-│ │ ├── evaluate.md
-│ │ └── ...
-│ └── ...
-├── cli/
-│ ├── management.md
-│ ├── config.md
-│ └── ...
-├── architecture/
-│ └── ...
-└── index.json
-```
-
-**Verify:**
-- [ ] All major API endpoints documented?
-- [ ] All CLI commands documented?
-- [ ] Organization makes sense?
-- [ ] Groups reflect actual functionality?
-- [ ] No duplicate content?
-- [ ] No orphaned docs (not linked from index)?
-
-#### 2.2 Check index.json
-
-**Verify index.json structure:**
-
-```json
-{
- "sections": [
- {
- "title": "API",
- "path": "api/",
- "items": [
- {
- "title": "Endpoints",
- "path": "api/endpoints/",
- "items": [
- { "title": "Navigation", "path": "api/endpoints/navigation.md" },
- { "title": "Snapshot", "path": "api/endpoints/snapshot.md" },
- ...
- ]
- }
- ]
- }
- ]
-}
-```
-
-**Checks:**
-- [ ] All sections map to actual directories?
-- [ ] All items map to actual files?
-- [ ] No broken paths?
-- [ ] Nesting depth reasonable (not too deep)?
-- [ ] Titles are accurate and clear?
-- [ ] Order makes sense (API before examples)?
-
----
-
-### Phase 3: Report Findings
-
-#### If Changes Were Made
-
-**Create a PR with:**
-
-1. **Summary of fixes**
- ```markdown
- ## Documentation Fixes
-
- - Updated /docs/api/endpoints/fill.md to document FillByNodeID support (fixes #114)
- - Removed deprecated /docs/api/endpoints/old-nav.md (no longer exists in code)
- - Fixed /docs/cli/config.md examples to use new config set syntax
- - Updated Chrome requirement from 144 to 145+ for extension support
- ```
-
-2. **List of possible improvements** (as comments in PR)
- ```markdown
- ## Suggested Improvements
-
- - [ ] /docs/architecture/ could use a "bridge lifecycle" diagram
- - [ ] /docs/api/endpoints/actions.md could add more examples
- - [ ] /docs/cli/config.md could show YAML format examples
- ```
-
-3. **PR description**
- ```markdown
- ## Documentation Review — Code Alignment
-
- Verified all examples, API endpoints, CLI commands, and config values against current code.
-
- ### Changes Made
- - X examples updated to match current API
- - X endpoints documented/updated
- - X CLI commands verified
- - X deprecated content removed
-
- ### No Changes Needed
- - API behavior accurate
- - Structure organized
- - Examples working
-
- ### Improvements Suggested
- See comments in PR for enhancement requests.
- ```
-
-#### If No Changes Needed but Improvements Found
-
-**Create a GitHub issue:**
-
-```markdown
-Title: docs: enhancement - add examples for [feature]
-
-Body:
-## Suggestion
-
-The documentation could be improved by:
-
-1. Adding example for feature X (current docs only show basic usage)
-2. Adding "Common Patterns" section to endpoint Y
-3. Adding troubleshooting section to CLI guide
-
-## Reasoning
-
-Users asking "how do I..." suggests these are common use cases.
-
-## References
-
-- See /docs/api/endpoints/[endpoint].md
-- See /docs/cli/[command].md
-```
-
----
-
-## Checklist for Agents
-
-When given the task "Review documentation", verify:
-
-### Code Accuracy
-- [ ] All examples are tested and working
-- [ ] All API endpoints documented correctly
-- [ ] All CLI commands documented correctly
-- [ ] All config options documented correctly
-- [ ] No deprecated content remains
-- [ ] All current features documented
-
-### Structure
-- [ ] index.json paths are correct
-- [ ] Directory structure makes sense
-- [ ] No orphaned docs
-- [ ] Grouping still makes sense
-- [ ] Navigation depth reasonable
-
-### Output
-- [ ] If changes: Create PR with summary + improvements list
-- [ ] If no changes but improvements: Create GitHub issue with enhancement request
-- [ ] Always: Note which docs were spot-checked and results
-
----
-
-## Common Documentation Mistakes to Fix
-
-❌ **Outdated examples:**
-```bash
-# OLD (deprecated)
-pinchtab nav https://pinchtab.com # ← This command was removed
-
-# NEW (correct)
-curl -X POST http://localhost:9867/navigate \
- -d '{"url":"https://pinchtab.com"}'
-```
-
-❌ **Wrong API format:**
-```javascript
-// OLD (incorrect)
-response = await fetch('/action', {
- body: JSON.stringify({action: 'click', ref: 'e5'})
-})
-
-// NEW (correct)
-response = await fetch('/action', {
- body: JSON.stringify({kind: 'click', ref: 'e5'})
-})
-```
-
-❌ **Missing new features:**
-```markdown
-
-
-
-```
-
-❌ **Incorrect config examples:**
-```bash
-# OLD (deprecated env var name)
-export BRIDGE_NAV_TIMEOUT=30
-
-# NEW (correct)
-export PINCHTAB_NAVIGATE_TIMEOUT=30
-```
-
----
-
-## Documentation File Locations
-
-**Root docs location:** `/docs`
-
-**Key files to check:**
-
-- `/docs/index.json` — Navigation/structure
-- `/docs/README.md` — Overview
-- `/docs/api/endpoints/*.md` — API documentation
-- `/docs/cli/*.md` — CLI documentation
-- `/docs/configuration.md` — Configuration reference
-- `/docs/architecture/*.md` — Architecture/design docs
-- `/docs/examples/*.md` — Usage examples
-
----
-
-## When to Ask for Documentation Review
-
-**Ask for review:**
-- After major feature additions (new endpoints, CLI commands)
-- After refactoring (config structure changes, API changes)
-- After bug fixes affecting documented behavior
-- Periodically (every quarter) for general sync-up
-- Before major releases (ensure nothing is stale)
-
-**Example requests:**
-
-> "Review documentation against current code. Check all API examples, CLI commands, and config values. Update docs to match code or remove outdated content. Create a PR with a summary of changes."
-
-> "Audit /docs for accuracy. Update any incorrect examples, remove deprecated features, fix broken index.json paths. Create an issue with improvement suggestions if no changes needed."
-
----
-
-## Quality Gates
-
-A documentation review is **complete** when:
-
-✅ All examples are tested and working
-✅ All API endpoints match code implementation
-✅ All CLI commands match code implementation
-✅ All config options match code implementation
-✅ No deprecated content remains
-✅ index.json structure is accurate
-✅ Documentation structure reflects codebase
-✅ Either: PR with fixes submitted, OR Issue with improvements created
-
----
-
-## Example Review Output (PR)
-
-```markdown
-## Documentation Review — Code Alignment
-
-All examples, endpoints, and CLI commands verified against current codebase.
-
-### ✅ Changes Made (3 files)
-
-1. **docs/api/endpoints/actions.md**
- - Updated fill example to show ref support (new in PR #119)
- - Added FillByNodeID code path documentation
-
-2. **docs/cli/config.md**
- - Fixed config set examples (new syntax with PR #120)
- - Added YAML output format example
-
-3. **docs/api/endpoints/find.md**
- - Added Find endpoint documentation (new in feat/allocation-strategies)
-
-### ✅ Verified (No Changes Needed)
-
-- All navigate endpoint examples working
-- All snapshot filters documented correctly
-- All action kinds (click, type, press, etc.) verified
-- Config sections (server, chrome, orchestrator) accurate
-- Environment variable names current
-
-### 💡 Suggested Improvements
-
-See comments below for enhancement requests (low priority):
-- [ ] Add "common patterns" section to actions.md
-- [ ] Add troubleshooting FAQ to cli/config.md
-- [ ] Create /docs/examples/multi-step-workflow.md
-
-### Review Stats
-
-- Examples tested: 12/12 ✅
-- Endpoints checked: 8/8 ✅
-- CLI commands checked: 5/5 ✅
-- Config sections checked: 4/4 ✅
-- Deprecated content found: 0 ✅
-- Structure issues found: 0 ✅
-```
-
----
-
-## Related Documents
-
-- [DEFINITION_OF_DONE.md](./DEFINITION_OF_DONE.md) — PR checklist
-- [LABELING_GUIDE.md](./LABELING_GUIDE.md) — Issue labeling guide
-
----
-
-Last updated: 2026-03-04
diff --git a/pinchtab/.github/GOVERNANCE.md b/pinchtab/.github/GOVERNANCE.md
deleted file mode 100644
index 0634ea3c6a6c1d62fffda0dc282983288a37ba9a..0000000000000000000000000000000000000000
--- a/pinchtab/.github/GOVERNANCE.md
+++ /dev/null
@@ -1,85 +0,0 @@
-# GitHub Governance Documents
-
-This directory contains pinchtab's governance and workflow documents referenced by developers and automated agents.
-
-## Documents
-
-### [DEFINITION_OF_DONE.md](./DEFINITION_OF_DONE.md)
-**Purpose:** PR checklist for code quality, testing, and documentation before merging.
-
-**For:** All contributors submitting PRs
-**How to use:** Check this list before submitting a PR, or ask agents to verify PRs against it.
-
-**Key sections:**
-- Automated checks (CI enforces)
-- Manual code quality requirements
-- Testing requirements
-- Documentation requirements
-- Quick checklist for copy/paste
-
----
-
-### [LABELING_GUIDE.md](./LABELING_GUIDE.md)
-**Purpose:** Reference guide for issue and PR labeling to maintain consistent triage.
-
-**For:** Maintainers triaging issues, agents reviewing tickets
-**How to use:** Point agents to this guide when asking them to review and label open issues.
-
-**Key sections:**
-- 3-tier labeling system (Type → Status → Priority)
-- Decision tree for triage
-- Guidelines for agents
-- Examples of well-labeled issues
-- Common mistakes to avoid
-
----
-
-### [DOCUMENTATION_REVIEW.md](./DOCUMENTATION_REVIEW.md)
-**Purpose:** Guide for auditing documentation to ensure it stays in sync with code (code is source of truth).
-
-**For:** Agents maintaining documentation, quality assurance
-**How to use:** Point agents to this guide when asking them to audit docs for accuracy and consistency.
-
-**Key sections:**
-- Code-to-docs validation (examples, endpoints, commands, config)
-- Structure review (organization, index.json, grouping)
-- Output requirements (PR with fixes or GitHub issue with improvements)
-- Common documentation mistakes to fix
-- Quality gates for completion
-
----
-
-## Quick Reference
-
-| Document | Audit For | Used By |
-|----------|-----------|---------|
-| DEFINITION_OF_DONE.md | PR quality before merge | Developers, agents, reviewers |
-| LABELING_GUIDE.md | Consistent issue triage | Maintainers, agents |
-| DOCUMENTATION_REVIEW.md | Documentation accuracy vs code | Agents, QA |
-
----
-
-## How Agents Use These
-
-When asking an agent to help with PRs, issues, or documentation:
-
-**For PR review:**
-> "Review this PR against `.github/DEFINITION_OF_DONE.md` and ensure it meets all requirements."
-
-**For issue triage:**
-> "Review open issues and apply labels according to `.github/LABELING_GUIDE.md`. Ensure Type + Status + Priority are consistent."
-
-**For documentation audit:**
-> "Review documentation against current code using `.github/DOCUMENTATION_REVIEW.md`. Verify all examples match code, update or remove outdated content, report changes in a PR or improvements in a GitHub issue."
-
----
-
-## Maintenance
-
-- **DEFINITION_OF_DONE.md** — Update when code quality standards change
-- **LABELING_GUIDE.md** — Update when new labels are added or workflow changes
-- This **README.md** — Update when new governance documents are added
-
----
-
-Last updated: 2026-03-04
diff --git a/pinchtab/.github/ISSUE_TEMPLATE/bug_report.md b/pinchtab/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 37a7d3683ad1bf6d541c19a53589350c67bcd6f3..0000000000000000000000000000000000000000
--- a/pinchtab/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-title: ''
-labels: bug
-assignees: ''
-
----
-
-**Describe the bug**
-A clear and concise description of what the bug is.
-
-**To Reproduce**
-Steps to reproduce the behavior:
-1. Start Pinchtab with `...`
-2. Send request to `/...` with body `...`
-3. See error
-
-**Expected behavior**
-A clear and concise description of what you expected to happen.
-
-**Screenshots/Logs**
-If applicable, add screenshots or console output to help explain your problem.
-
-**Environment (please complete the following information):**
- - OS: [e.g. macOS, Ubuntu]
- - Browser Version: [e.g. Chrome 120]
- - Go Version: [e.g. 1.25.0]
-
-**Additional context**
-Add any other context about the problem here.
diff --git a/pinchtab/.github/ISSUE_TEMPLATE/feature_request.md b/pinchtab/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 11fc491ef1dae316f2b06bbb40eaba9c757fdfd1..0000000000000000000000000000000000000000
--- a/pinchtab/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: ''
-labels: enhancement
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Additional context**
-Add any other context or screenshots about the feature request here.
diff --git a/pinchtab/.github/LABELING_GUIDE.md b/pinchtab/.github/LABELING_GUIDE.md
deleted file mode 100644
index c2a882ad374475ae2e2c52124b8ccfbb2838c948..0000000000000000000000000000000000000000
--- a/pinchtab/.github/LABELING_GUIDE.md
+++ /dev/null
@@ -1,246 +0,0 @@
-# Labeling Guide
-
-This document describes the labeling system used for issues and PRs in pinchtab. Use this guide when triaging tickets or asking agents to review open issues.
-
----
-
-## Quick Reference
-
-Every issue should have:
-1. **Exactly one Type label** (bug, enhancement, documentation, question, etc.)
-2. **One Status label** (ready, in-progress, blocked, fixed-unreleased, needs-investigation)
-3. **One Priority label** (high, medium, low) — optional for documentation or questions
-
----
-
-## Tier 1: Issue Type (Mandatory)
-
-Choose **exactly one**:
-
-| Label | Color | Usage |
-|-------|-------|-------|
-| `bug` | 🔴 Red | Something isn't working correctly |
-| `enhancement` | 🔵 Cyan | New feature or capability request |
-| `documentation` | 🔵 Blue | Improvements/additions to README, docs, or code comments |
-| `question` | 🟣 Purple | Request for clarification or information |
-| `good first issue` | 🟣 Purple | Good for newcomers (in addition to type label) |
-| `help wanted` | 🟢 Green | Needs extra attention or expertise |
-| `dependencies` | 🔵 Blue | Dependency updates (PR label) |
-| `invalid` | 🟡 Yellow | Doesn't seem right; requires clarification |
-| `duplicate` | ⚪ Gray | Already exists (close and reference original) |
-| `wontfix` | ⚪ White | Deliberate decision not to fix |
-
-### Examples
-
-- **Bug:** "fill action silently no-ops when using refs" → `bug`
-- **Enhancement:** "Add CHROME_EXTENSION_PATHS support" → `enhancement`
-- **Documentation:** "Update README with new CLI commands" → `documentation`
-- **Question:** "How do I configure stealth mode?" → `question`
-
----
-
-## Tier 2: Status (Recommended)
-
-Choose **one** to show current state:
-
-| Label | Color | Meaning | When to Use |
-|-------|-------|---------|------------|
-| `status: ready` | 🔵 Blue | Ready to start work | Issue is fully understood, no blockers, waiting for someone to pick it up |
-| `status: in-progress` | 🟡 Yellow | Actively being worked on | Someone has claimed the issue and is working on a fix/feature |
-| `status: blocked` | 🔴 Red | Blocked by something | Waiting on external dependency, another issue, or decision |
-| `status: fixed-unreleased` | 🟢 Green | Fix merged, not in release | PR is merged but feature/fix isn't in a released version yet |
-| `status: needs-investigation` | 🔴 Red | Needs debugging/research | Not enough info; requires investigation before work can start |
-
-### Workflow
-
-```
-New Issue
- ↓
-[Triage] Add Type + Status
- ↓
-status: needs-investigation (if unclear) or status: ready (if clear)
- ↓
-Developer picks it up
- ↓
-status: in-progress
- ↓
-PR submitted
- ↓
-PR merged
- ↓
-status: fixed-unreleased (for bugs) or remove status (for features)
- ↓
-Release cut
- ↓
-Remove status label (feature is released)
-```
-
----
-
-## Tier 3: Priority (Optional, for bugs/enhancements)
-
-Choose **one** to indicate urgency:
-
-| Label | Color | Level | When to Use |
-|-------|-------|-------|------------|
-| `priority: high` | 🔴 Red | Critical; blocks users | Security vulnerability, critical bug, high-demand feature |
-| `priority: medium` | 🟡 Yellow | Normal; important for roadmap | Important bug or feature; should be done soon |
-| `priority: low` | 🟢 Green | Nice to have; can defer | Minor improvement, polish, or edge case |
-
-### Examples
-
-- **High:** "SafePath() fails to block path traversal" (security) → `bug` + `priority: high`
-- **Medium:** "Snapshot doesn't work inside iframes" (affects users) → `bug` + `priority: medium`
-- **Low:** "Consider migrating to PINCHTAB_* env vars" (nice refactor) → `enhancement` + `priority: low`
-
----
-
-## Special Labels
-
-### `good first issue`
-Add this **in addition to the type label** for issues that are good entry points for new contributors.
-
-**Criteria:**
-- Clear problem statement
-- Solution is straightforward
-- Doesn't require deep knowledge of codebase
-- Estimated effort: <4 hours
-
-**Example:** "documentation: Add /find endpoint example to README" → `documentation` + `good first issue`
-
-### `help wanted`
-Indicates the issue needs expertise or has been stalled.
-
-**When to use:**
-- Needs specific expertise (e.g., "needs Windows testing")
-- Issue has been open >2 weeks without progress
-- Complex problem that benefits from external input
-
----
-
-## Decision Tree for Triage
-
-```
-New issue arrives
- ↓
-1. Is it a valid issue?
- NO → `invalid` + close
- YES ↓
-2. What is it?
- → Bug? `bug` + assess severity → `priority: high|medium|low`
- → New feature? `enhancement` + assess importance → `priority: high|medium|low`
- → Docs missing? `documentation` + no priority needed
- → Unclear? `question` + no priority needed
- ↓
-3. Can we start work immediately?
- YES → `status: ready`
- NO ↓
-4. Why not?
- → Need info → `status: needs-investigation`
- → Waiting on something → `status: blocked`
- → Already fixed → `status: fixed-unreleased`
-```
-
----
-
-## Guidelines for Agents
-
-When reviewing open issues, follow this checklist:
-
-- [ ] **Each issue has exactly one Type label** (bug, enhancement, documentation, question)
-- [ ] **Bugs have Priority labels** (high, medium, low)
-- [ ] **Enhancements have Priority labels** (high, medium, low)
-- [ ] **Each issue has a Status label** (ready, in-progress, blocked, fixed-unreleased, needs-investigation)
-- [ ] **No duplicate labels** (e.g., two type labels on one issue)
-- [ ] **Status matches reality** (e.g., `status: in-progress` has an active PR)
-- [ ] **Stale issues reviewed** (e.g., `status: blocked` for >2 weeks should note why)
-
----
-
-## Current Label Inventory
-
-**Type labels (10):**
-- bug, enhancement, documentation, question, good first issue, help wanted, dependencies, invalid, duplicate, wontfix
-
-**Status labels (5):**
-- status: ready, status: in-progress, status: blocked, status: fixed-unreleased, status: needs-investigation
-
-**Priority labels (3):**
-- priority: high, priority: medium, priority: low
-
-**Code labels (1):**
-- javascript
-
----
-
-## Examples of Well-Labeled Issues
-
-### Example 1: Security Bug
-```
-Title: SafePath() fails to block path traversal on Windows
-Labels: bug, priority: high, status: ready
-```
-**Why:** Critical security issue, ready to work on, high priority.
-
-### Example 2: Feature Request (Ready)
-```
-Title: feat: Resource Pool with pluggable allocation strategies
-Labels: enhancement, priority: medium, status: ready
-```
-**Why:** Enhancement, medium priority (important for roadmap), ready to start.
-
-### Example 3: Feature (Blocked)
-```
-Title: feat: Semantic Element Selection via NLP (/find endpoint)
-Labels: enhancement, priority: medium, status: blocked
-```
-**Why:** Enhancement, medium priority, but blocked (perhaps waiting on design decision).
-
-### Example 4: Bug (Not Ready)
-```
-Title: click and humanClick fail to trigger Bootstrap dropdown
-Labels: bug, priority: medium, status: needs-investigation
-```
-**Why:** Bug, medium priority, but needs investigation (reproduction steps unclear).
-
-### Example 5: Already Fixed
-```
-Title: Installation issue
-Labels: bug, priority: high, status: fixed-unreleased
-```
-**Why:** Critical bug, but fix is already merged and waiting for release.
-
----
-
-## Common Mistakes
-
-❌ **Don't do this:**
-
-| Mistake | Why | Fix |
-|---------|-----|-----|
-| Two Type labels on one issue | Ambiguous; what is it really? | Choose one type only |
-| Status label on closed issue | Status should reflect open work | Remove status label when closing |
-| No Priority on bugs | Can't triage effectively | Add priority: high/medium/low to all bugs |
-| `status: in-progress` with no PR | Misleading; is someone actually working on it? | Only use when work is actively underway |
-| Forgetting Status labels | No visibility into progress | Always add a status label during triage |
-
----
-
-## Related Documents
-
-- [DEFINITION_OF_DONE.md](./DEFINITION_OF_DONE.md) — Checklist for PRs before merge
-- [CONTRIBUTING.md](../CONTRIBUTING.md) — Contribution guidelines (if present)
-
----
-
-## Last Updated
-
-2026-03-04
-
----
-
-## Summary
-
-**For agents:** Use this guide to understand and apply labels when triaging issues. Ensure every issue has Type + Status + Priority (if applicable).
-
-**For maintainers:** Review labels during triage and ensure consistency. Use the Decision Tree above as a quick reference.
diff --git a/pinchtab/.github/PULL_REQUEST_TEMPLATE.md b/pinchtab/.github/PULL_REQUEST_TEMPLATE.md
deleted file mode 100644
index 9ccbc2a5051da7743bb858f5f923d7a950468292..0000000000000000000000000000000000000000
--- a/pinchtab/.github/PULL_REQUEST_TEMPLATE.md
+++ /dev/null
@@ -1,30 +0,0 @@
-## What Changed?
-
-
-## Why?
-
-
-## Testing
-
-
-- [ ] Unit and/or Docker E2E tests added or updated
-- [ ] Manual testing completed (describe below)
-
-## Checklist
-See [DEFINITION_OF_DONE.md](./DEFINITION_OF_DONE.md) for the full checklist.
-
-**Automated (CI enforces):**
-- [ ] gofmt + golangci-lint passes
-- [ ] All tests pass
-- [ ] Build succeeds
-
-**Manual:**
-- [ ] Error handling explicit (wrapped with `%w`)
-- [ ] No regressions in stealth/performance/persistence
-- [ ] README/CHANGELOG updated (if user-facing)
-- [ ] npm install works (if npm changes)
-
-## Impact
-
-
----
diff --git a/pinchtab/.github/RELEASING.md b/pinchtab/.github/RELEASING.md
deleted file mode 100644
index 3e7329ebf6cea8e54f8cc16ad10b7d39db618928..0000000000000000000000000000000000000000
--- a/pinchtab/.github/RELEASING.md
+++ /dev/null
@@ -1,44 +0,0 @@
-# Releasing PinchTab
-
-This is the release checklist for the GitHub tag-driven release pipeline.
-
-## One-time setup
-
-- Create the public tap repository `pinchtab/homebrew-tap`.
-- Add the `HOMEBREW_TAP_GITHUB_TOKEN` Actions secret to `pinchtab/pinchtab`.
-- The token must have write access to `pinchtab/homebrew-tap`.
-
-## What the release workflow does
-
-Pushing a tag like `v0.7.0` triggers [release.yml](/Users/luigi/dev/prj/giago/pt-bosch/.github/workflows/release.yml), which:
-
-1. Builds release binaries and creates the GitHub release via GoReleaser.
-2. Publishes the npm package.
-3. Builds and publishes container images.
-4. Generates a Homebrew formula PR against `pinchtab/homebrew-tap`.
-
-## Release steps
-
-1. Verify the branch you want to release is merged to `main`.
-2. Push the release tag:
-
-```bash
-git tag v0.7.0
-git push origin v0.7.0
-```
-
-3. Watch the `Release` workflow in GitHub Actions.
-4. Confirm GoReleaser opens a PR in `pinchtab/homebrew-tap`.
-5. Merge that PR.
-
-After the tap PR is merged, users can install with:
-
-```bash
-brew install pinchtab/tap/pinchtab
-```
-
-## Notes
-
-- The Homebrew formula is not published until the tap PR is merged.
-- No extra automation is required in `homebrew-tap` unless you want auto-merge.
-- The release workflow can also be run manually with `workflow_dispatch` and a tag input.
diff --git a/pinchtab/.github/workflows/branch-naming.yml b/pinchtab/.github/workflows/branch-naming.yml
deleted file mode 100644
index 70776c121c8389716509164dcb17cf2592c5a5f7..0000000000000000000000000000000000000000
--- a/pinchtab/.github/workflows/branch-naming.yml
+++ /dev/null
@@ -1,50 +0,0 @@
-name: Branch Naming
-
-on:
- pull_request:
- types: [opened, synchronize, reopened]
-
-permissions:
- contents: read
-
-jobs:
- check-branch-name:
- name: Branch Name Convention
- runs-on: ubuntu-latest
- if: github.event.pull_request.draft == false
- steps:
- - name: Check branch name
- run: |
- BRANCH="${GITHUB_HEAD_REF}"
- echo "Branch: $BRANCH"
-
- # Allow long-running branches
- if [[ "$BRANCH" =~ ^(main|develop|staging)$ ]]; then
- echo "✅ Long-running branch: $BRANCH"
- exit 0
- fi
-
- # Allow dependabot branches
- if [[ "$BRANCH" =~ ^dependabot/ ]]; then
- echo "✅ Dependabot branch: $BRANCH"
- exit 0
- fi
-
- # Enforce prefix/description pattern
- PATTERN="^(feature|feat|fix|hotfix|docs|chore|refactor|test)/[a-z0-9][a-z0-9-]*$"
- if [[ ! "$BRANCH" =~ $PATTERN ]]; then
- echo "❌ Branch name '$BRANCH' doesn't match convention."
- echo ""
- echo "Expected format: