@mseep/anything-analyzer 3.6.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codeartsdoer/.codebaseignore +0 -0
- package/.codeartsdoer/AGENTS.md +12 -0
- package/.github/workflows/build.yml +146 -0
- package/README.en.md +264 -0
- package/README.md +276 -0
- package/RELEASE_NOTES.md +16 -0
- package/USAGE.md +490 -0
- package/color-preview-r3.html +414 -0
- package/color-preview.html +414 -0
- package/dev-app-update.yml +3 -0
- package/electron-builder.yml +36 -0
- package/electron.vite.config.ts +40 -0
- package/package.json +53 -0
- package/report-2026-04-13-copilot-claude-sonnet-4.6.md +955 -0
- package/resources/doloffer-logo.png +0 -0
- package/resources/entitlements.mac.plist +12 -0
- package/resources/icon.ico +0 -0
- package/resources/icon.png +0 -0
- package/src/main/ai/ai-analyzer.ts +517 -0
- package/src/main/ai/crypto-script-extractor.ts +206 -0
- package/src/main/ai/data-assembler.ts +205 -0
- package/src/main/ai/llm-router.ts +1120 -0
- package/src/main/ai/prompt-builder.ts +349 -0
- package/src/main/ai/scene-detector.ts +302 -0
- package/src/main/capture/capture-engine.ts +130 -0
- package/src/main/capture/interaction-recorder.ts +171 -0
- package/src/main/capture/js-injector.ts +57 -0
- package/src/main/capture/replay-engine.ts +256 -0
- package/src/main/capture/storage-collector.ts +76 -0
- package/src/main/cdp/cdp-manager.ts +233 -0
- package/src/main/db/database.ts +41 -0
- package/src/main/db/migrations.ts +235 -0
- package/src/main/db/repositories.ts +574 -0
- package/src/main/fingerprint/http-spoofing.ts +48 -0
- package/src/main/fingerprint/presets.ts +173 -0
- package/src/main/fingerprint/profile-generator.ts +115 -0
- package/src/main/fingerprint/profile-store.ts +52 -0
- package/src/main/index.ts +260 -0
- package/src/main/ipc.ts +856 -0
- package/src/main/logger.ts +42 -0
- package/src/main/mcp/mcp-config.ts +66 -0
- package/src/main/mcp/mcp-manager.ts +155 -0
- package/src/main/mcp/mcp-server.ts +1038 -0
- package/src/main/prompt-templates.ts +170 -0
- package/src/main/proxy/ca-manager.ts +204 -0
- package/src/main/proxy/cert-download-page.ts +171 -0
- package/src/main/proxy/cert-installer.ts +242 -0
- package/src/main/proxy/mitm-proxy-config.ts +37 -0
- package/src/main/proxy/mitm-proxy-server.ts +1085 -0
- package/src/main/proxy/system-proxy.ts +248 -0
- package/src/main/session/session-manager.ts +724 -0
- package/src/main/tab-manager.ts +582 -0
- package/src/main/updater.ts +111 -0
- package/src/main/window.ts +235 -0
- package/src/preload/hook-script.ts +270 -0
- package/src/preload/index.ts +211 -0
- package/src/preload/interaction-hook.ts +286 -0
- package/src/preload/stealth-script.ts +302 -0
- package/src/preload/target-preload.ts +15 -0
- package/src/renderer/App.tsx +656 -0
- package/src/renderer/components/AiLogDetail.tsx +173 -0
- package/src/renderer/components/AiLogList.tsx +101 -0
- package/src/renderer/components/AiLogView.module.css +364 -0
- package/src/renderer/components/AiLogView.tsx +86 -0
- package/src/renderer/components/AnalyzeBar.module.css +79 -0
- package/src/renderer/components/AnalyzeBar.tsx +104 -0
- package/src/renderer/components/BrowserPanel.module.css +67 -0
- package/src/renderer/components/BrowserPanel.tsx +90 -0
- package/src/renderer/components/ControlBar.module.css +47 -0
- package/src/renderer/components/ControlBar.tsx +205 -0
- package/src/renderer/components/HookLog.tsx +132 -0
- package/src/renderer/components/InteractionLog.tsx +183 -0
- package/src/renderer/components/MCPServerModal.tsx +427 -0
- package/src/renderer/components/PromptTemplateModal.tsx +254 -0
- package/src/renderer/components/ReportView.module.css +413 -0
- package/src/renderer/components/ReportView.tsx +429 -0
- package/src/renderer/components/RequestDetail.module.css +191 -0
- package/src/renderer/components/RequestDetail.tsx +202 -0
- package/src/renderer/components/RequestLog.module.css +69 -0
- package/src/renderer/components/RequestLog.tsx +208 -0
- package/src/renderer/components/SessionList.module.css +245 -0
- package/src/renderer/components/SessionList.tsx +247 -0
- package/src/renderer/components/SettingsModal.tsx +100 -0
- package/src/renderer/components/StatusBar.module.css +44 -0
- package/src/renderer/components/StatusBar.tsx +102 -0
- package/src/renderer/components/StorageView.module.css +41 -0
- package/src/renderer/components/StorageView.tsx +178 -0
- package/src/renderer/components/TabBar.module.css +88 -0
- package/src/renderer/components/TabBar.tsx +70 -0
- package/src/renderer/components/Titlebar.module.css +254 -0
- package/src/renderer/components/Titlebar.tsx +169 -0
- package/src/renderer/components/settings/FingerprintSection.tsx +198 -0
- package/src/renderer/components/settings/GeneralSection.tsx +164 -0
- package/src/renderer/components/settings/LLMSection.tsx +148 -0
- package/src/renderer/components/settings/MCPServerSection.tsx +136 -0
- package/src/renderer/components/settings/MitmProxySection.tsx +320 -0
- package/src/renderer/components/settings/ProxySection.tsx +110 -0
- package/src/renderer/css-modules.d.ts +4 -0
- package/src/renderer/hooks/useCapture.ts +383 -0
- package/src/renderer/hooks/useConfirm.tsx +91 -0
- package/src/renderer/hooks/useSession.ts +136 -0
- package/src/renderer/hooks/useTabs.ts +103 -0
- package/src/renderer/i18n/en.ts +167 -0
- package/src/renderer/i18n/index.ts +47 -0
- package/src/renderer/i18n/zh.ts +170 -0
- package/src/renderer/index.html +12 -0
- package/src/renderer/main.tsx +15 -0
- package/src/renderer/styles/global.css +144 -0
- package/src/renderer/styles/themes/ayu-dark.css +59 -0
- package/src/renderer/styles/themes/catppuccin.css +59 -0
- package/src/renderer/styles/themes/discord.css +59 -0
- package/src/renderer/styles/themes/dracula.css +59 -0
- package/src/renderer/styles/themes/github-dark.css +59 -0
- package/src/renderer/styles/themes/gruvbox.css +59 -0
- package/src/renderer/styles/themes/index.css +11 -0
- package/src/renderer/styles/themes/light.css +59 -0
- package/src/renderer/styles/themes/nord.css +59 -0
- package/src/renderer/styles/themes/one-dark.css +59 -0
- package/src/renderer/styles/themes/tokyo-night.css +59 -0
- package/src/renderer/styles/tokens.css +137 -0
- package/src/renderer/theme.ts +31 -0
- package/src/renderer/ui/Badge.module.css +38 -0
- package/src/renderer/ui/Badge.tsx +36 -0
- package/src/renderer/ui/Button.module.css +142 -0
- package/src/renderer/ui/Button.tsx +46 -0
- package/src/renderer/ui/Collapse.module.css +49 -0
- package/src/renderer/ui/Collapse.tsx +57 -0
- package/src/renderer/ui/CopyableBlock.module.css +56 -0
- package/src/renderer/ui/CopyableBlock.tsx +42 -0
- package/src/renderer/ui/Empty.module.css +19 -0
- package/src/renderer/ui/Empty.tsx +34 -0
- package/src/renderer/ui/Icons.tsx +346 -0
- package/src/renderer/ui/Input.module.css +103 -0
- package/src/renderer/ui/Input.tsx +94 -0
- package/src/renderer/ui/InputNumber.module.css +68 -0
- package/src/renderer/ui/InputNumber.tsx +104 -0
- package/src/renderer/ui/Modal.module.css +83 -0
- package/src/renderer/ui/Modal.tsx +67 -0
- package/src/renderer/ui/Popconfirm.module.css +73 -0
- package/src/renderer/ui/Popconfirm.tsx +74 -0
- package/src/renderer/ui/Progress.module.css +35 -0
- package/src/renderer/ui/Progress.tsx +30 -0
- package/src/renderer/ui/Select.module.css +91 -0
- package/src/renderer/ui/Select.tsx +100 -0
- package/src/renderer/ui/Spinner.module.css +44 -0
- package/src/renderer/ui/Spinner.tsx +27 -0
- package/src/renderer/ui/Switch.module.css +39 -0
- package/src/renderer/ui/Switch.tsx +43 -0
- package/src/renderer/ui/Tabs.module.css +76 -0
- package/src/renderer/ui/Tabs.tsx +53 -0
- package/src/renderer/ui/Tag.module.css +66 -0
- package/src/renderer/ui/Tag.tsx +47 -0
- package/src/renderer/ui/Timeline.module.css +42 -0
- package/src/renderer/ui/Timeline.tsx +29 -0
- package/src/renderer/ui/Toast.module.css +99 -0
- package/src/renderer/ui/Toast.tsx +90 -0
- package/src/renderer/ui/Tooltip.module.css +26 -0
- package/src/renderer/ui/Tooltip.tsx +23 -0
- package/src/renderer/ui/VirtualTable.module.css +230 -0
- package/src/renderer/ui/VirtualTable.tsx +416 -0
- package/src/renderer/ui/index.ts +55 -0
- package/src/shared/types.ts +695 -0
- package/tests/main/ai/crypto-script-extractor.test.ts +281 -0
- package/tests/main/ai/llm-router.test.ts +1537 -0
- package/tests/main/ai/prompt-builder.test.ts +178 -0
- package/tests/main/ai/scene-detector.test.ts +212 -0
- package/tests/main/db/migrations.test.ts +134 -0
- package/tests/main/release-workflow.test.ts +59 -0
- package/tsconfig.json +7 -0
- package/tsconfig.node.json +23 -0
- package/tsconfig.web.json +24 -0
- package/vitest.config.ts +13 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import log from "electron-log/main";
|
|
2
|
+
import { app } from "electron";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Initialize electron-log for persistent file logging.
|
|
7
|
+
* Log files are stored in the app's userData/logs directory.
|
|
8
|
+
*
|
|
9
|
+
* Must be called after app.whenReady() since it uses app.getPath().
|
|
10
|
+
*/
|
|
11
|
+
export function initLogger(): void {
|
|
12
|
+
// Store logs in userData/logs/
|
|
13
|
+
const logDir = join(app.getPath("userData"), "logs");
|
|
14
|
+
log.transports.file.resolvePathFn = () => join(logDir, "main.log");
|
|
15
|
+
|
|
16
|
+
// Keep max 5MB per file, rotate up to 3 old files
|
|
17
|
+
log.transports.file.maxSize = 5 * 1024 * 1024;
|
|
18
|
+
|
|
19
|
+
// Log level: info and above go to file, all go to console in dev
|
|
20
|
+
log.transports.file.level = "info";
|
|
21
|
+
log.transports.console.level = process.env.NODE_ENV === "development" ? "debug" : "warn";
|
|
22
|
+
|
|
23
|
+
// Format: [timestamp] [level] message
|
|
24
|
+
log.transports.file.format = "[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}] {text}";
|
|
25
|
+
|
|
26
|
+
// Override console methods so existing console.log/warn/error
|
|
27
|
+
// statements throughout the codebase are automatically captured.
|
|
28
|
+
log.initialize();
|
|
29
|
+
|
|
30
|
+
log.info("=== Application started ===");
|
|
31
|
+
log.info(`Version: ${app.getVersion()}, Platform: ${process.platform} ${process.arch}`);
|
|
32
|
+
log.info(`Electron: ${process.versions.electron}, Node: ${process.versions.node}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get the directory containing log files.
|
|
37
|
+
*/
|
|
38
|
+
export function getLogPath(): string {
|
|
39
|
+
return join(app.getPath("userData"), "logs", "main.log");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default log;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { app } from "electron";
|
|
4
|
+
import type { MCPServerConfig } from "@shared/types";
|
|
5
|
+
|
|
6
|
+
function getConfigPath(): string {
|
|
7
|
+
return join(app.getPath("userData"), "mcp-servers.json");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 将缺少 transport 字段的旧配置迁移为 stdio 类型
|
|
12
|
+
*/
|
|
13
|
+
function migrateConfig(raw: Record<string, unknown>): MCPServerConfig {
|
|
14
|
+
if (!raw.transport) {
|
|
15
|
+
return {
|
|
16
|
+
id: raw.id as string,
|
|
17
|
+
name: raw.name as string,
|
|
18
|
+
enabled: raw.enabled as boolean,
|
|
19
|
+
transport: "stdio",
|
|
20
|
+
command: (raw.command as string) || "",
|
|
21
|
+
args: (raw.args as string[]) || [],
|
|
22
|
+
env: (raw.env as Record<string, string>) || {},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return raw as unknown as MCPServerConfig;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Load MCP server configs from disk. Returns empty array if file does not exist.
|
|
30
|
+
*/
|
|
31
|
+
export function loadMCPServers(): MCPServerConfig[] {
|
|
32
|
+
const path = getConfigPath();
|
|
33
|
+
if (!existsSync(path)) return [];
|
|
34
|
+
try {
|
|
35
|
+
const parsed = JSON.parse(readFileSync(path, "utf-8")) as Record<string, unknown>[];
|
|
36
|
+
return parsed.map(migrateConfig);
|
|
37
|
+
} catch {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function persist(servers: MCPServerConfig[]): void {
|
|
43
|
+
writeFileSync(getConfigPath(), JSON.stringify(servers, null, 2), "utf-8");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Save (create or update) a server config.
|
|
48
|
+
*/
|
|
49
|
+
export function saveMCPServer(server: MCPServerConfig): void {
|
|
50
|
+
const servers = loadMCPServers();
|
|
51
|
+
const idx = servers.findIndex((s) => s.id === server.id);
|
|
52
|
+
if (idx >= 0) {
|
|
53
|
+
servers[idx] = server;
|
|
54
|
+
} else {
|
|
55
|
+
servers.push(server);
|
|
56
|
+
}
|
|
57
|
+
persist(servers);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Delete a server config by ID.
|
|
62
|
+
*/
|
|
63
|
+
export function deleteMCPServer(id: string): void {
|
|
64
|
+
const servers = loadMCPServers();
|
|
65
|
+
persist(servers.filter((s) => s.id !== id));
|
|
66
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client";
|
|
2
|
+
// Must use explicit .js extension for CJS require resolution in Electron main process
|
|
3
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
4
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
5
|
+
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
6
|
+
import type { MCPServerConfig } from "@shared/types";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* MCP 工具描述,包含来源信息
|
|
10
|
+
*/
|
|
11
|
+
export interface MCPToolInfo {
|
|
12
|
+
serverName: string;
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
inputSchema: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface ConnectedServer {
|
|
19
|
+
config: MCPServerConfig;
|
|
20
|
+
client: Client;
|
|
21
|
+
transport: Transport;
|
|
22
|
+
tools: MCPToolInfo[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 管理 MCP 服务器连接,提供统一的工具列表和调用接口。
|
|
27
|
+
*/
|
|
28
|
+
export class MCPClientManager {
|
|
29
|
+
private servers = new Map<string, ConnectedServer>();
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 连接单个 MCP 服务器
|
|
33
|
+
*/
|
|
34
|
+
async connect(config: MCPServerConfig): Promise<void> {
|
|
35
|
+
if (this.servers.has(config.id)) {
|
|
36
|
+
await this.disconnect(config.id);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let transport: Transport;
|
|
40
|
+
|
|
41
|
+
if (config.transport === "streamableHttp") {
|
|
42
|
+
const url = new URL(config.url);
|
|
43
|
+
transport = new StreamableHTTPClientTransport(url, {
|
|
44
|
+
requestInit: config.headers && Object.keys(config.headers).length > 0
|
|
45
|
+
? { headers: config.headers }
|
|
46
|
+
: undefined,
|
|
47
|
+
});
|
|
48
|
+
} else {
|
|
49
|
+
transport = new StdioClientTransport({
|
|
50
|
+
command: config.command,
|
|
51
|
+
args: config.args,
|
|
52
|
+
env: { ...process.env, ...config.env } as Record<string, string>,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const client = new Client(
|
|
57
|
+
{ name: "anything-analyzer", version: "1.0.0" },
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
await client.connect(transport);
|
|
61
|
+
|
|
62
|
+
// 获取工具列表
|
|
63
|
+
const { tools } = await client.listTools();
|
|
64
|
+
const toolInfos: MCPToolInfo[] = tools.map((t) => ({
|
|
65
|
+
serverName: config.name,
|
|
66
|
+
name: t.name,
|
|
67
|
+
description: t.description ?? "",
|
|
68
|
+
inputSchema: t.inputSchema as Record<string, unknown>,
|
|
69
|
+
}));
|
|
70
|
+
|
|
71
|
+
this.servers.set(config.id, { config, client, transport, tools: toolInfos });
|
|
72
|
+
console.log(`[MCP] Connected to ${config.name}, tools: ${toolInfos.map((t) => t.name).join(", ")}`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 断开单个服务器连接
|
|
77
|
+
*/
|
|
78
|
+
async disconnect(id: string): Promise<void> {
|
|
79
|
+
const server = this.servers.get(id);
|
|
80
|
+
if (!server) return;
|
|
81
|
+
try {
|
|
82
|
+
await server.client.close();
|
|
83
|
+
} catch {
|
|
84
|
+
// ignore close errors
|
|
85
|
+
}
|
|
86
|
+
this.servers.delete(id);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 断开所有连接
|
|
91
|
+
*/
|
|
92
|
+
async disconnectAll(): Promise<void> {
|
|
93
|
+
const ids = [...this.servers.keys()];
|
|
94
|
+
await Promise.allSettled(ids.map((id) => this.disconnect(id)));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 连接所有启用的服务器
|
|
99
|
+
*/
|
|
100
|
+
async connectAll(configs: MCPServerConfig[]): Promise<void> {
|
|
101
|
+
const enabled = configs.filter((c) => c.enabled);
|
|
102
|
+
await Promise.allSettled(
|
|
103
|
+
enabled.map((c) => this.connect(c).catch((err) => {
|
|
104
|
+
console.error(`[MCP] Failed to connect ${c.name}:`, err);
|
|
105
|
+
})),
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 列出所有已连接服务器的工具
|
|
111
|
+
*/
|
|
112
|
+
listAllTools(): MCPToolInfo[] {
|
|
113
|
+
const all: MCPToolInfo[] = [];
|
|
114
|
+
for (const server of this.servers.values()) {
|
|
115
|
+
all.push(...server.tools);
|
|
116
|
+
}
|
|
117
|
+
return all;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 调用工具(路由到正确的 MCP 客户端)
|
|
122
|
+
*/
|
|
123
|
+
async callTool(toolName: string, args: Record<string, unknown>): Promise<string> {
|
|
124
|
+
for (const server of this.servers.values()) {
|
|
125
|
+
const tool = server.tools.find((t) => t.name === toolName);
|
|
126
|
+
if (tool) {
|
|
127
|
+
const result = await server.client.callTool({ name: toolName, arguments: args });
|
|
128
|
+
// 将结果内容拼接为文本
|
|
129
|
+
if (result.isError) {
|
|
130
|
+
const errorText = Array.isArray(result.content)
|
|
131
|
+
? result.content.map((c: { type: string; text?: string }) => c.type === "text" ? c.text ?? "" : "").join("\n")
|
|
132
|
+
: String(result.content);
|
|
133
|
+
throw new Error(`Tool ${toolName} error: ${errorText}`);
|
|
134
|
+
}
|
|
135
|
+
const textParts: string[] = [];
|
|
136
|
+
if (Array.isArray(result.content)) {
|
|
137
|
+
for (const item of result.content as Array<{ type: string; text?: string }>) {
|
|
138
|
+
if (item.type === "text" && item.text) {
|
|
139
|
+
textParts.push(item.text);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return textParts.join("\n") || JSON.stringify(result.content);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
throw new Error(`Tool not found: ${toolName}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 是否有已连接的服务器
|
|
151
|
+
*/
|
|
152
|
+
hasConnections(): boolean {
|
|
153
|
+
return this.servers.size > 0;
|
|
154
|
+
}
|
|
155
|
+
}
|