anything-analyzer-cdp

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Anything Analyzer CDP Skill

Anything Analyzer CDP Skill

Skill by ara.so — Daily 2026 Skills collection.
Anything Analyzer is an Electron desktop application that embeds a browser, captures all network traffic via Chrome DevTools Protocol (CDP), injects JS hooks, snapshots storage, and feeds the data to an AI (OpenAI/Anthropic/custom) to generate protocol analysis reports — useful for documenting registration flows, 2API reverse engineering, and general browser protocol analysis.
ara.so开发的Skill — 属于Daily 2026 Skills系列。
Anything Analyzer是一款嵌入浏览器的Electron桌面应用,它通过Chrome DevTools Protocol(CDP)捕获所有网络流量,注入JS钩子,存储快照,并将数据输入AI(OpenAI/Anthropic/自定义)生成协议分析报告——可用于记录注册流程、API逆向工程以及通用浏览器协议分析。

Installation & Setup

安装与设置

bash
git clone https://github.com/MouseWW/anything-analyzer.git
cd anything-analyzer
pnpm install
pnpm dev        # development mode
pnpm build      # production build
Windows native module build requirement:
bash
undefined
bash
git clone https://github.com/MouseWW/anything-analyzer.git
cd anything-analyzer
pnpm install
pnpm dev        # 开发模式
pnpm build      # 生产构建
Windows原生模块构建要求:
bash
undefined

Install Visual Studio Build Tools first, then:

先安装Visual Studio Build Tools,然后执行:

pnpm install
pnpm install

If better-sqlite3 fails:

如果better-sqlite3构建失败:

pnpm rebuild

**Package as installer:**
```bash
pnpm run build && npx electron-builder --win
pnpm rebuild

**打包为安装程序:**
```bash
pnpm run build && npx electron-builder --win

Core Architecture

核心架构

src/
├── main/                    # Electron main process
│   ├── ai/                  # AI analysis pipeline
│   │   ├── ai-analyzer.ts   # orchestrator
│   │   ├── data-assembler.ts# data preparation
│   │   ├── prompt-builder.ts# prompt generation
│   │   └── scene-detector.ts# rule-based scene classification
│   ├── capture/             # Capture engine
│   │   ├── capture-engine.ts# data sink → SQLite + renderer
│   │   ├── js-injector.ts   # hook script injection
│   │   └── storage-collector.ts # periodic storage snapshots
│   ├── cdp/
│   │   └── cdp-manager.ts   # CDP manager
│   ├── db/                  # SQLite via better-sqlite3
│   ├── session/
│   │   └── session-manager.ts # session lifecycle
│   ├── tab-manager.ts       # Multi-tab WebContentsView
│   ├── window.ts            # Main window layout
│   └── ipc.ts               # IPC handlers
├── preload/                 # Context bridge + hook script
├── renderer/                # React 19 + Ant Design 5 UI
└── shared/types.ts          # Shared TypeScript types
src/
├── main/                    # Electron主进程
│   ├── ai/                  # AI分析流水线
│   │   ├── ai-analyzer.ts   # 编排器
│   │   ├── data-assembler.ts# 数据准备
│   │   ├── prompt-builder.ts# 提示词生成
│   │   └── scene-detector.ts# 基于规则的场景分类
│   ├── capture/             # 捕获引擎
│   │   ├── capture-engine.ts# 数据接收器 → SQLite + 渲染进程
│   │   ├── js-injector.ts   # 钩子脚本注入
│   │   └── storage-collector.ts # 定期存储快照
│   ├── cdp/
│   │   └── cdp-manager.ts   # CDP管理器
│   ├── db/                  # 通过better-sqlite3操作SQLite
│   ├── session/
│   │   └── session-manager.ts # 会话生命周期管理
│   ├── tab-manager.ts       # 多标签页WebContentsView
│   ├── window.ts            # 主窗口布局
│   └── ipc.ts               # IPC处理器
├── preload/                 # 上下文桥接 + 钩子脚本
├── renderer/                # React 19 + Ant Design 5界面
└── shared/types.ts          # 共享TypeScript类型

Key Concepts

核心概念

Sessions

会话(Sessions)

A Session scopes all captured data. Each session has a name, target URL, and contains all requests, JS hook events, and storage snapshots captured during that session.
会话用于划分所有捕获的数据范围。每个会话包含名称、目标URL,以及会话期间捕获的所有请求、JS钩子事件和存储快照。

Capture Engine

捕获引擎(Capture Engine)

The capture engine:
  1. Attaches CDP to
    WebContentsView
    tabs
  2. Enables
    Fetch.enable
    for request interception
  3. Injects JS hooks via
    Page.addScriptToEvaluateOnNewDocument
  4. Collects storage snapshots periodically
捕获引擎的工作流程:
  1. 将CDP附加到
    WebContentsView
    标签页
  2. 启用
    Fetch.enable
    进行请求拦截
  3. 通过
    Page.addScriptToEvaluateOnNewDocument
    注入JS钩子
  4. 定期收集存储快照

AI Analysis Pipeline

AI分析流水线

  1. Scene detection — rule-based classification (registration, OAuth, API auth, etc.)
  2. Data assembly — selects relevant requests, deduplicates, truncates large bodies
  3. Prompt building — constructs structured prompt with scene context
  4. LLM call — streams response back to renderer
  1. 场景检测 — 基于规则的分类(注册、OAuth、API认证等)
  2. 数据组装 — 筛选相关请求、去重、截断大请求体
  3. 提示词构建 — 结合场景上下文构建结构化提示词
  4. LLM调用 — 将响应流式传输回渲染进程

Configuration

配置

LLM Provider Setup (Settings UI)

LLM提供商设置(设置界面)

Configure via the Settings panel (bottom-left gear icon):
typescript
// Config shape (stored in SQLite settings table)
interface LLMConfig {
  provider: 'openai' | 'anthropic' | 'custom';
  apiKey: string;      // from env or user input
  model: string;       // e.g. 'gpt-4o', 'claude-sonnet-4-20250514'
  baseUrl?: string;    // for custom OpenAI-compatible endpoints
}
OpenAI:
  • API Key:
    $OPENAI_API_KEY
  • Model:
    gpt-4o
    or
    gpt-4o-mini
Anthropic:
  • API Key:
    $ANTHROPIC_API_KEY
  • Model:
    claude-sonnet-4-20250514
Custom (OpenAI-compatible):
  • Base URL: e.g.
    https://api.deepseek.com/v1
  • API Key: your provider key
  • Model: provider-specific model name
通过设置面板(左下角齿轮图标)配置:
typescript
// 配置结构(存储在SQLite设置表中)
interface LLMConfig {
  provider: 'openai' | 'anthropic' | 'custom';
  apiKey: string;      // 来自环境变量或用户输入
  model: string;       // 例如 'gpt-4o', 'claude-sonnet-4-20250514'
  baseUrl?: string;    // 用于自定义OpenAI兼容端点
}
OpenAI:
  • API密钥:
    $OPENAI_API_KEY
  • 模型:
    gpt-4o
    gpt-4o-mini
Anthropic:
  • API密钥:
    $ANTHROPIC_API_KEY
  • 模型:
    claude-sonnet-4-20250514
自定义(兼容OpenAI):
  • 基础URL:例如
    https://api.deepseek.com/v1
  • API密钥:你的提供商密钥
  • 模型:提供商指定的模型名称

IPC API (Main ↔ Renderer)

IPC API(主进程 ↔ 渲染进程)

Session Management

会话管理

typescript
// Create a session
const session = await window.electron.ipcRenderer.invoke('session:create', {
  name: 'My Analysis Session',
  url: 'https://example.com'
})

// List sessions
const sessions = await window.electron.ipcRenderer.invoke('session:list')

// Delete session
await window.electron.ipcRenderer.invoke('session:delete', sessionId)
typescript
// 创建会话
const session = await window.electron.ipcRenderer.invoke('session:create', {
  name: 'My Analysis Session',
  url: 'https://example.com'
})

// 列出会话
const sessions = await window.electron.ipcRenderer.invoke('session:list')

// 删除会话
await window.electron.ipcRenderer.invoke('session:delete', sessionId)

Capture Control

捕获控制

typescript
// Start capturing for current tab
await window.electron.ipcRenderer.invoke('capture:start', { sessionId, tabId })

// Stop capturing
await window.electron.ipcRenderer.invoke('capture:stop', { sessionId, tabId })

// Get captured requests
const requests = await window.electron.ipcRenderer.invoke('capture:getRequests', sessionId)
typescript
// 开始捕获当前标签页
await window.electron.ipcRenderer.invoke('capture:start', { sessionId, tabId })

// 停止捕获
await window.electron.ipcRenderer.invoke('capture:stop', { sessionId, tabId })

// 获取已捕获的请求
const requests = await window.electron.ipcRenderer.invoke('capture:getRequests', sessionId)

AI Analysis

AI分析

typescript
// Trigger AI analysis (streams back via IPC events)
await window.electron.ipcRenderer.invoke('analyze:start', { sessionId })

// Listen for streaming chunks
window.electron.ipcRenderer.on('analyze:chunk', (_, chunk: string) => {
  setReport(prev => prev + chunk)
})

// Listen for completion
window.electron.ipcRenderer.on('analyze:done', () => {
  setAnalyzing(false)
})
typescript
// 触发AI分析(通过IPC事件流式返回)
await window.electron.ipcRenderer.invoke('analyze:start', { sessionId })

// 监听流式返回的片段
window.electron.ipcRenderer.on('analyze:chunk', (_, chunk: string) => {
  setReport(prev => prev + chunk)
})

// 监听分析完成事件
window.electron.ipcRenderer.on('analyze:done', () => {
  setAnalyzing(false)
})

Real Code Examples

真实代码示例

Extend the Scene Detector

扩展场景检测器

typescript
// src/main/ai/scene-detector.ts
import { CapturedRequest } from '../../shared/types'

export type Scene =
  | 'registration'
  | 'oauth'
  | 'api-auth'
  | 'websocket'
  | 'general'

export function detectScene(requests: CapturedRequest[]): Scene {
  const urls = requests.map(r => r.url.toLowerCase())
  const bodies = requests.map(r => r.requestBody?.toLowerCase() ?? '')

  // OAuth detection
  if (urls.some(u => u.includes('oauth') || u.includes('authorize') || u.includes('callback'))) {
    return 'oauth'
  }

  // Registration detection
  if (
    bodies.some(b => b.includes('password') && (b.includes('email') || b.includes('username'))) &&
    urls.some(u => u.includes('register') || u.includes('signup') || u.includes('sign-up'))
  ) {
    return 'registration'
  }

  // WebSocket upgrade detection
  if (requests.some(r => r.isWebSocket)) {
    return 'websocket'
  }

  // Auth token patterns
  if (urls.some(u => u.includes('/auth') || u.includes('/token') || u.includes('/login'))) {
    return 'api-auth'
  }

  return 'general'
}
typescript
// src/main/ai/scene-detector.ts
import { CapturedRequest } from '../../shared/types'

export type Scene =
  | 'registration'
  | 'oauth'
  | 'api-auth'
  | 'websocket'
  | 'general'

export function detectScene(requests: CapturedRequest[]): Scene {
  const urls = requests.map(r => r.url.toLowerCase())
  const bodies = requests.map(r => r.requestBody?.toLowerCase() ?? '')

  // OAuth检测
  if (urls.some(u => u.includes('oauth') || u.includes('authorize') || u.includes('callback'))) {
    return 'oauth'
  }

  // 注册流程检测
  if (
    bodies.some(b => b.includes('password') && (b.includes('email') || b.includes('username'))) &&
    urls.some(u => u.includes('register') || u.includes('signup') || u.includes('sign-up'))
  ) {
    return 'registration'
  }

  // WebSocket升级检测
  if (requests.some(r => r.isWebSocket)) {
    return 'websocket'
  }

  // 认证令牌模式检测
  if (urls.some(u => u.includes('/auth') || u.includes('/token') || u.includes('/login'))) {
    return 'api-auth'
  }

  return 'general'
}

Custom Prompt Builder

自定义提示词构建器

typescript
// src/main/ai/prompt-builder.ts
import { Scene } from './scene-detector'
import { AssembledData } from './data-assembler'

export function buildPrompt(scene: Scene, data: AssembledData): string {
  const sceneInstructions: Record<Scene, string> = {
    registration: `Analyze this registration flow. Extract:
1. Required fields and validation rules
2. Password requirements  
3. Captcha/bot protection mechanisms
4. Email verification flow
5. Reproducible curl commands for each step`,

    oauth: `Analyze this OAuth flow. Extract:
1. OAuth provider and grant type
2. Authorization URL with all parameters
3. Token exchange endpoint and parameters
4. Token refresh mechanism
5. Scopes requested`,

    'api-auth': `Analyze this authentication protocol. Extract:
1. Auth endpoint and method
2. Request payload schema
3. Response token format (JWT/session/etc)
4. Token usage in subsequent requests (header name, format)
5. Expiry and refresh strategy`,

    websocket: `Analyze this WebSocket protocol. Extract:
1. Upgrade request headers
2. Initial handshake messages
3. Message format (JSON/binary/custom)
4. Heartbeat/ping-pong mechanism
5. Event types and schemas`,

    general: `Analyze this web protocol. Extract:
1. Core API endpoints and their purposes
2. Authentication mechanism
3. Request/response schemas
4. Error handling patterns
5. Rate limiting signals`,
  }

  return `You are a protocol reverse engineer. ${sceneInstructions[scene]}
typescript
// src/main/ai/prompt-builder.ts
import { Scene } from './scene-detector'
import { AssembledData } from './data-assembler'

export function buildPrompt(scene: Scene, data: AssembledData): string {
  const sceneInstructions: Record<Scene, string> = {
    registration: `分析此注册流程。提取以下内容:
1. 必填字段和验证规则
2. 密码要求  
3. 验证码/机器人防护机制
4. 邮箱验证流程
5. 可复现的各步骤curl命令`,

    oauth: `分析此OAuth流程。提取以下内容:
1. OAuth提供商和授权类型
2. 包含所有参数的授权URL
3. 令牌交换端点和参数
4. 令牌刷新机制
5. 请求的权限范围`,

    'api-auth': `分析此认证协议。提取以下内容:
1. 认证端点和请求方法
2. 请求负载结构
3. 响应令牌格式(JWT/会话等)
4. 后续请求中令牌的使用方式(头名称、格式)
5. 过期和刷新策略`,

    websocket: `分析此WebSocket协议。提取以下内容:
1. 升级请求头
2. 初始握手消息
3. 消息格式(JSON/二进制/自定义)
4. 心跳/ ping-pong机制
5. 事件类型和结构`,

    general: `分析此Web协议。提取以下内容:
1. 核心API端点及其用途
2. 认证机制
3. 请求/响应结构
4. 错误处理模式
5. 限流信号`,
  }

  return `你是一名协议逆向工程师。${sceneInstructions[scene]}

Captured Data

捕获的数据

Network Requests (${data.requests.length} total)

网络请求(共${data.requests.length}条)

${data.requests.map(r =>
**${r.method} ${r.url}** Status: ${r.statusCode} Request Headers: ${JSON.stringify(r.requestHeaders, null, 2)} Request Body: ${r.requestBody ?? '(empty)'} Response Headers: ${JSON.stringify(r.responseHeaders, null, 2)} Response Body: ${r.responseBody ?? '(empty)'}
).join('\n---\n')}
${data.requests.map(r =>
**${r.method} ${r.url}** 状态码: ${r.statusCode} 请求头: ${JSON.stringify(r.requestHeaders, null, 2)} 请求体: ${r.requestBody ?? '(空)'} 响应头: ${JSON.stringify(r.responseHeaders, null, 2)} 响应体: ${r.responseBody ?? '(空)'}
).join('\n---\n')}

JS Hook Events

JS钩子事件

${JSON.stringify(data.hookEvents, null, 2)}
${JSON.stringify(data.hookEvents, null, 2)}

Storage Snapshots

存储快照

${JSON.stringify(data.storageSnapshots, null, 2)}
Generate a comprehensive protocol analysis report in Markdown.` }
undefined
${JSON.stringify(data.storageSnapshots, null, 2)}
生成一份全面的Markdown格式协议分析报告。` }
undefined

Adding a Custom JS Hook

添加自定义JS钩子

typescript
// src/main/capture/js-injector.ts
export function buildHookScript(): string {
  return `
(function() {
  // Hook fetch
  const _fetch = window.fetch.bind(window)
  window.fetch = async function(...args) {
    const [input, init] = args
    const url = input instanceof Request ? input.url : String(input)
    
    // Pre-request hook
    window.__cdpHook?.({ type: 'fetch:request', url, init: JSON.stringify(init) })
    
    const response = await _fetch(...args)
    const clone = response.clone()
    
    // Post-response hook (non-blocking)
    clone.text().then(body => {
      window.__cdpHook?.({ type: 'fetch:response', url, status: response.status, body })
    }).catch(() => {})
    
    return response
  }

  // Hook XHR
  const _open = XMLHttpRequest.prototype.open
  const _send = XMLHttpRequest.prototype.send
  
  XMLHttpRequest.prototype.open = function(method, url, ...rest) {
    this.__hookData = { method, url }
    return _open.apply(this, [method, url, ...rest])
  }
  
  XMLHttpRequest.prototype.send = function(body) {
    this.addEventListener('load', function() {
      window.__cdpHook?.({
        type: 'xhr:complete',
        method: this.__hookData?.method,
        url: this.__hookData?.url,
        requestBody: body,
        status: this.status,
        responseBody: this.responseText
      })
    })
    return _send.apply(this, [body])
  }

  // Hook crypto.subtle for key detection
  if (window.crypto?.subtle) {
    const _sign = crypto.subtle.sign.bind(crypto.subtle)
    crypto.subtle.sign = async function(algorithm, key, data) {
      window.__cdpHook?.({ type: 'crypto:sign', algorithm: JSON.stringify(algorithm) })
      return _sign(algorithm, key, data)
    }
  }

  // Hook document.cookie
  const cookieDesc = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie')
  Object.defineProperty(document, 'cookie', {
    get: function() { return cookieDesc.get.call(this) },
    set: function(val) {
      window.__cdpHook?.({ type: 'cookie:set', value: val })
      return cookieDesc.set.call(this, val)
    }
  })
})()
`
}
typescript
// src/main/capture/js-injector.ts
export function buildHookScript(): string {
  return `
(function() {
  // Hook fetch
  const _fetch = window.fetch.bind(window)
  window.fetch = async function(...args) {
    const [input, init] = args
    const url = input instanceof Request ? input.url : String(input)
    
    // 请求前钩子
    window.__cdpHook?.({ type: 'fetch:request', url, init: JSON.stringify(init) })
    
    const response = await _fetch(...args)
    const clone = response.clone()
    
    // 请求后钩子(非阻塞)
    clone.text().then(body => {
      window.__cdpHook?.({ type: 'fetch:response', url, status: response.status, body })
    }).catch(() => {})
    
    return response
  }

  // Hook XHR
  const _open = XMLHttpRequest.prototype.open
  const _send = XMLHttpRequest.prototype.send
  
  XMLHttpRequest.prototype.open = function(method, url, ...rest) {
    this.__hookData = { method, url }
    return _open.apply(this, [method, url, ...rest])
  }
  
  XMLHttpRequest.prototype.send = function(body) {
    this.addEventListener('load', function() {
      window.__cdpHook?.({
        type: 'xhr:complete',
        method: this.__hookData?.method,
        url: this.__hookData?.url,
        requestBody: body,
        status: this.status,
        responseBody: this.responseText
      })
    })
    return _send.apply(this, [body])
  }

  // Hook crypto.subtle用于密钥检测
  if (window.crypto?.subtle) {
    const _sign = crypto.subtle.sign.bind(crypto.subtle)
    crypto.subtle.sign = async function(algorithm, key, data) {
      window.__cdpHook?.({ type: 'crypto:sign', algorithm: JSON.stringify(algorithm) })
      return _sign(algorithm, key, data)
    }
  }

  // Hook document.cookie
  const cookieDesc = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie')
  Object.defineProperty(document, 'cookie', {
    get: function() { return cookieDesc.get.call(this) },
    set: function(val) {
      window.__cdpHook?.({ type: 'cookie:set', value: val })
      return cookieDesc.set.call(this, val)
    }
  })
})()
`
}

Database Schema Access

数据库结构访问

typescript
// src/main/db/ — SQLite via better-sqlite3
import Database from 'better-sqlite3'
import path from 'path'
import { app } from 'electron'

const DB_PATH = path.join(app.getPath('userData'), 'analyzer.db')

export function getDb(): Database.Database {
  const db = new Database(DB_PATH)
  db.pragma('journal_mode = WAL')
  return db
}

// Typical schema
export function initSchema(db: Database.Database) {
  db.exec(`
    CREATE TABLE IF NOT EXISTS sessions (
      id TEXT PRIMARY KEY,
      name TEXT NOT NULL,
      url TEXT NOT NULL,
      created_at INTEGER NOT NULL
    );

    CREATE TABLE IF NOT EXISTS requests (
      id TEXT PRIMARY KEY,
      session_id TEXT NOT NULL,
      url TEXT NOT NULL,
      method TEXT NOT NULL,
      status_code INTEGER,
      request_headers TEXT,
      request_body TEXT,
      response_headers TEXT,
      response_body TEXT,
      is_sse INTEGER DEFAULT 0,
      is_websocket INTEGER DEFAULT 0,
      timestamp INTEGER NOT NULL,
      FOREIGN KEY (session_id) REFERENCES sessions(id)
    );

    CREATE TABLE IF NOT EXISTS hook_events (
      id TEXT PRIMARY KEY,
      session_id TEXT NOT NULL,
      type TEXT NOT NULL,
      data TEXT NOT NULL,
      timestamp INTEGER NOT NULL
    );

    CREATE TABLE IF NOT EXISTS storage_snapshots (
      id TEXT PRIMARY KEY,
      session_id TEXT NOT NULL,
      cookies TEXT,
      local_storage TEXT,
      session_storage TEXT,
      timestamp INTEGER NOT NULL
    );

    CREATE TABLE IF NOT EXISTS settings (
      key TEXT PRIMARY KEY,
      value TEXT NOT NULL
    );
  `)
}
typescript
// src/main/db/ — 通过better-sqlite3操作SQLite
import Database from 'better-sqlite3'
import path from 'path'
import { app } from 'electron'

const DB_PATH = path.join(app.getPath('userData'), 'analyzer.db')

export function getDb(): Database.Database {
  const db = new Database(DB_PATH)
  db.pragma('journal_mode = WAL')
  return db
}

// 典型结构
export function initSchema(db: Database.Database) {
  db.exec(`
    CREATE TABLE IF NOT EXISTS sessions (
      id TEXT PRIMARY KEY,
      name TEXT NOT NULL,
      url TEXT NOT NULL,
      created_at INTEGER NOT NULL
    );

    CREATE TABLE IF NOT EXISTS requests (
      id TEXT PRIMARY KEY,
      session_id TEXT NOT NULL,
      url TEXT NOT NULL,
      method TEXT NOT NULL,
      status_code INTEGER,
      request_headers TEXT,
      request_body TEXT,
      response_headers TEXT,
      response_body TEXT,
      is_sse INTEGER DEFAULT 0,
      is_websocket INTEGER DEFAULT 0,
      timestamp INTEGER NOT NULL,
      FOREIGN KEY (session_id) REFERENCES sessions(id)
    );

    CREATE TABLE IF NOT EXISTS hook_events (
      id TEXT PRIMARY KEY,
      session_id TEXT NOT NULL,
      type TEXT NOT NULL,
      data TEXT NOT NULL,
      timestamp INTEGER NOT NULL
    );

    CREATE TABLE IF NOT EXISTS storage_snapshots (
      id TEXT PRIMARY KEY,
      session_id TEXT NOT NULL,
      cookies TEXT,
      local_storage TEXT,
      session_storage TEXT,
      timestamp INTEGER NOT NULL
    );

    CREATE TABLE IF NOT EXISTS settings (
      key TEXT PRIMARY KEY,
      value TEXT NOT NULL
    );
  `)
}

Shared Types Reference

共享类型参考

typescript
// src/shared/types.ts
export interface Session {
  id: string
  name: string
  url: string
  createdAt: number
}

export interface CapturedRequest {
  id: string
  sessionId: string
  url: string
  method: string
  statusCode?: number
  requestHeaders?: Record<string, string>
  requestBody?: string
  responseHeaders?: Record<string, string>
  responseBody?: string
  isSSE: boolean
  isWebSocket: boolean
  timestamp: number
}

export interface HookEvent {
  id: string
  sessionId: string
  type: 'fetch:request' | 'fetch:response' | 'xhr:complete' | 'crypto:sign' | 'cookie:set'
  data: Record<string, unknown>
  timestamp: number
}

export interface StorageSnapshot {
  id: string
  sessionId: string
  cookies: string
  localStorage: Record<string, string>
  sessionStorage: Record<string, string>
  timestamp: number
}

export interface LLMConfig {
  provider: 'openai' | 'anthropic' | 'custom'
  apiKey: string
  model: string
  baseUrl?: string
}
typescript
// src/shared/types.ts
export interface Session {
  id: string
  name: string
  url: string
  createdAt: number
}

export interface CapturedRequest {
  id: string
  sessionId: string
  url: string
  method: string
  statusCode?: number
  requestHeaders?: Record<string, string>
  requestBody?: string
  responseHeaders?: Record<string, string>
  responseBody?: string
  isSSE: boolean
  isWebSocket: boolean
  timestamp: number
}

export interface HookEvent {
  id: string
  sessionId: string
  type: 'fetch:request' | 'fetch:response' | 'xhr:complete' | 'crypto:sign' | 'cookie:set'
  data: Record<string, unknown>
  timestamp: number
}

export interface StorageSnapshot {
  id: string
  sessionId: string
  cookies: string
  localStorage: Record<string, string>
  sessionStorage: Record<string, string>
  timestamp: number
}

export interface LLMConfig {
  provider: 'openai' | 'anthropic' | 'custom'
  apiKey: string
  model: string
  baseUrl?: string
}

Common Patterns

常见使用场景

Pattern: Capture a Full Registration Flow

场景:捕获完整注册流程

  1. Click New Session → enter name + target URL (e.g.
    https://example.com/register
    )
  2. Click Start Capture
  3. In the embedded browser, complete the full registration flow
  4. Click Stop Capture
  5. Click Analyze → AI generates a report with extracted fields, validation rules, and curl commands
  1. 点击新建会话 → 输入名称 + 目标URL(例如
    https://example.com/register
  2. 点击开始捕获
  3. 在嵌入浏览器中完成完整注册流程
  4. 点击停止捕获
  5. 点击分析 → AI生成包含提取字段、验证规则和curl命令的报告

Pattern: OAuth Flow Analysis

场景:OAuth流程分析

  1. Create session with the OAuth entry URL
  2. Start capture
  3. Authorize the OAuth flow including the redirect callback
  4. Stop capture — the analyzer auto-detects OAuth and focuses prompt on token exchange
  1. 创建包含OAuth入口URL的会话
  2. 开始捕获
  3. 完成OAuth授权流程(包括重定向回调)
  4. 停止捕获 — 分析器会自动检测OAuth场景,并将提示词聚焦于令牌交换

Pattern: Adding a New LLM Provider

场景:添加新的LLM提供商

typescript
// src/main/ai/ai-analyzer.ts
import Anthropic from '@anthropic-ai/sdk'
import OpenAI from 'openai'

export async function* callLLM(
  config: LLMConfig,
  prompt: string
): AsyncGenerator<string> {
  if (config.provider === 'anthropic') {
    const client = new Anthropic({ apiKey: config.apiKey })
    const stream = await client.messages.stream({
      model: config.model,
      max_tokens: 8192,
      messages: [{ role: 'user', content: prompt }]
    })
    for await (const chunk of stream) {
      if (chunk.type === 'content_block_delta' && chunk.delta.type === 'text_delta') {
        yield chunk.delta.text
      }
    }
  } else {
    // OpenAI or custom compatible
    const client = new OpenAI({
      apiKey: config.apiKey,
      baseURL: config.baseUrl  // undefined = default OpenAI
    })
    const stream = await client.chat.completions.create({
      model: config.model,
      messages: [{ role: 'user', content: prompt }],
      stream: true
    })
    for await (const chunk of stream) {
      yield chunk.choices[0]?.delta?.content ?? ''
    }
  }
}
typescript
// src/main/ai/ai-analyzer.ts
import Anthropic from '@anthropic-ai/sdk'
import OpenAI from 'openai'

export async function* callLLM(
  config: LLMConfig,
  prompt: string
): AsyncGenerator<string> {
  if (config.provider === 'anthropic') {
    const client = new Anthropic({ apiKey: config.apiKey })
    const stream = await client.messages.stream({
      model: config.model,
      max_tokens: 8192,
      messages: [{ role: 'user', content: prompt }]
    })
    for await (const chunk of stream) {
      if (chunk.type === 'content_block_delta' && chunk.delta.type === 'text_delta') {
        yield chunk.delta.text
      }
    }
  } else {
    // OpenAI或兼容自定义提供商
    const client = new OpenAI({
      apiKey: config.apiKey,
      baseURL: config.baseUrl  // undefined = 使用默认OpenAI地址
    })
    const stream = await client.chat.completions.create({
      model: config.model,
      messages: [{ role: 'user', content: prompt }],
      stream: true
    })
    for await (const chunk of stream) {
      yield chunk.choices[0]?.delta?.content ?? ''
    }
  }
}

Pattern: Filter Requests Before Analysis

场景:分析前过滤请求

typescript
// Useful for large sessions — filter to only auth-related requests
function filterRelevantRequests(requests: CapturedRequest[]): CapturedRequest[] {
  const AUTH_PATTERNS = [
    /\/auth/, /\/login/, /\/register/, /\/signup/, /\/token/,
    /\/oauth/, /\/session/, /\/verify/, /\/captcha/
  ]
  
  return requests.filter(r => {
    // Always include if has auth header
    if (r.requestHeaders?.['authorization'] || r.requestHeaders?.['x-auth-token']) {
      return true
    }
    // Include if URL matches auth patterns
    if (AUTH_PATTERNS.some(p => p.test(r.url))) return true
    // Include if response sets cookies
    if (r.responseHeaders?.['set-cookie']) return true
    // Exclude static assets
    if (/\.(js|css|png|jpg|gif|svg|woff|ico)(\?|$)/.test(r.url)) return false
    return false
  })
}
typescript
// 适用于大型会话 — 仅过滤与认证相关的请求
function filterRelevantRequests(requests: CapturedRequest[]): CapturedRequest[] {
  const AUTH_PATTERNS = [
    /\/auth/, /\/login/, /\/register/, /\/signup/, /\/token/,
    /\/oauth/, /\/session/, /\/verify/, /\/captcha/
  ]
  
  return requests.filter(r => {
    // 包含认证头的请求始终保留
    if (r.requestHeaders?.['authorization'] || r.requestHeaders?.['x-auth-token']) {
      return true
    }
    // URL匹配认证模式的请求保留
    if (AUTH_PATTERNS.some(p => p.test(r.url))) return true
    // 响应设置Cookie的请求保留
    if (r.responseHeaders?.['set-cookie']) return true
    // 排除静态资源
    if (/\.(js|css|png|jpg|gif|svg|woff|ico)(\?|$)/.test(r.url)) return false
    return false
  })
}

Troubleshooting

故障排除

better-sqlite3
build fails on Windows

Windows下
better-sqlite3
构建失败

bash
npm install --global windows-build-tools
bash
npm install --global windows-build-tools

or install Visual Studio Build Tools 2022 manually

或手动安装Visual Studio Build Tools 2022

pnpm rebuild
undefined
pnpm rebuild
undefined

better-sqlite3
wrong Electron version

better-sqlite3
与Electron版本不匹配

bash
undefined
bash
undefined

Rebuild for current Electron version

针对当前Electron版本重新构建

./node_modules/.bin/electron-rebuild -f -w better-sqlite3
./node_modules/.bin/electron-rebuild -f -w better-sqlite3

or

npx @electron/rebuild -f -w better-sqlite3
undefined
npx @electron/rebuild -f -w better-sqlite3
undefined

CDP not attaching to tab

CDP无法附加到标签页

  • Ensure
    WebContentsView
    is fully loaded before calling
    cdpManager.attach()
  • Check
    webContents.getURL()
    isn't
    about:blank
    before enabling Fetch
  • For popups/OAuth windows, listen for
    new-window
    or
    setWindowOpenHandler
    and capture the new
    WebContents
  • 确保调用
    cdpManager.attach()
    WebContentsView
    已完全加载
  • 检查调用Fetch启用前
    webContents.getURL()
    不是
    about:blank
  • 对于弹窗/OAuth窗口,监听
    new-window
    setWindowOpenHandler
    事件并捕获新的
    WebContents

AI response truncated

AI响应被截断

  • Increase
    max_tokens
    in the LLM call (default 8192, increase to 16384)
  • Reduce request body size in
    data-assembler.ts
    — truncate large response bodies to first 2000 chars
  • 在LLM调用中增加
    max_tokens
    值(默认8192,可增加到16384)
  • data-assembler.ts
    中减小请求体大小 — 将大响应体截断为前2000个字符

Requests missing response bodies

请求缺少响应体

  • CDP
    Fetch.getResponseBody
    must be called before
    Fetch.continueRequest
  • Binary/gzip responses need base64 decoding: check
    base64Encoded
    field in CDP response
  • Some streaming responses (SSE) can't have body captured synchronously — mark as SSE and capture chunks via
    Network.eventSourceMessageReceived
  • 必须在调用
    Fetch.continueRequest
    前调用CDP的
    Fetch.getResponseBody
  • 二进制/gzip响应需要base64解码:检查CDP响应中的
    base64Encoded
    字段
  • 部分流式响应(SSE)无法同步捕获响应体 — 标记为SSE并通过
    Network.eventSourceMessageReceived
    捕获片段

HTTPS interception not working

HTTPS拦截不生效

  • CDP Fetch interception works on all HTTPS by default in Electron's WebContentsView
  • If a site uses certificate pinning, it may reject interception — look for
    ERR_CERT_*
    in request errors
  • Electron的WebContentsView默认支持CDP Fetch拦截所有HTTPS请求
  • 如果网站使用证书固定,可能会拒绝拦截 — 查看请求错误中的
    ERR_CERT_*
    信息

App window blank on startup

应用启动后窗口空白

bash
undefined
bash
undefined

Check renderer build

检查渲染进程构建情况

pnpm dev
pnpm dev

Look for Vite errors in terminal — usually missing env vars or import errors

在终端中查看Vite错误 — 通常是缺少环境变量或导入错误

undefined
undefined

Development Tips

开发技巧

  • Hot reload:
    pnpm dev
    uses electron-vite with HMR for renderer and restart for main
  • Devtools: In dev mode, DevTools auto-opens for renderer; use
    Ctrl+Shift+I
    for embedded browser webview devtools
  • SQLite inspection: Use DB Browser for SQLite on
    %APPDATA%/anything-analyzer/analyzer.db
    (Windows) or
    ~/Library/Application Support/anything-analyzer/analyzer.db
    (macOS)
  • IPC debugging: Add
    console.log
    in
    ipc.ts
    handlers — logs appear in Electron main process terminal
  • CDP raw events: Enable
    cdp.on('*', console.log)
    in
    cdp-manager.ts
    during development to see all CDP events
  • 热重载
    pnpm dev
    使用electron-vite,渲染进程支持HMR,主进程会自动重启
  • 开发者工具:开发模式下,渲染进程会自动打开DevTools;使用
    Ctrl+Shift+I
    打开嵌入浏览器webview的开发者工具
  • SQLite检查:使用DB Browser for SQLite打开Windows下的
    %APPDATA%/anything-analyzer/analyzer.db
    或macOS下的
    ~/Library/Application Support/anything-analyzer/analyzer.db
  • IPC调试:在
    ipc.ts
    处理器中添加
    console.log
    — 日志会显示在Electron主进程终端
  • CDP原始事件:开发期间在
    cdp-manager.ts
    中启用
    cdp.on('*', console.log)
    查看所有CDP事件