mirror of
https://github.com/AIPexStudio/AIPex.git
synced 2026-05-13 18:51:35 +00:00
refactor: reorganize imports and improve code formatting across multiple files
This commit is contained in:
@@ -3,12 +3,6 @@
|
||||
* Safe to import from any context (background, content, React components)
|
||||
*/
|
||||
|
||||
// Re-export storage adapter (no React dependency)
|
||||
export {
|
||||
ChromeStorageAdapter,
|
||||
chromeStorageAdapter,
|
||||
} from "@aipexstudio/browser-runtime";
|
||||
|
||||
// Re-export types only (no runtime React dependency)
|
||||
export type {
|
||||
ChatbotEventHandlers,
|
||||
@@ -20,6 +14,11 @@ export type {
|
||||
UseChatOptions,
|
||||
UseChatReturn,
|
||||
} from "@aipexstudio/aipex-react";
|
||||
// Re-export storage adapter (no React dependency)
|
||||
export {
|
||||
ChromeStorageAdapter,
|
||||
chromeStorageAdapter,
|
||||
} from "@aipexstudio/browser-runtime";
|
||||
|
||||
/**
|
||||
* React hooks should be imported directly from their sources:
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
import type { AppSettings } from "@aipexstudio/aipex-core";
|
||||
import {
|
||||
type AutomationMode,
|
||||
STORAGE_KEYS,
|
||||
aisdk,
|
||||
SessionStorage,
|
||||
STORAGE_KEYS,
|
||||
validateAutomationMode,
|
||||
} from "@aipexstudio/aipex-core";
|
||||
import { SYSTEM_PROMPT } from "@aipexstudio/aipex-react/components/chatbot/constants";
|
||||
@@ -62,16 +62,21 @@ export function useBrowserContextProviders() {
|
||||
* Filter tools based on automation mode
|
||||
* In background mode, filter out computer and screenshot-related tools
|
||||
*/
|
||||
function filterToolsByMode(tools: typeof allBrowserTools, mode: AutomationMode) {
|
||||
function filterToolsByMode(
|
||||
tools: typeof allBrowserTools,
|
||||
mode: AutomationMode,
|
||||
) {
|
||||
// In background mode, filter out computer and screenshot-related tools
|
||||
if (mode === 'background') {
|
||||
return tools.filter(tool => {
|
||||
if (mode === "background") {
|
||||
return tools.filter((tool) => {
|
||||
const toolName = tool.name.toLowerCase();
|
||||
// Filter out computer tool and all screenshot-related tools
|
||||
return toolName !== 'computer' &&
|
||||
!toolName.includes('screenshot') &&
|
||||
!toolName.includes('take_screenshot') &&
|
||||
!toolName.includes('capture_screenshot');
|
||||
return (
|
||||
toolName !== "computer" &&
|
||||
!toolName.includes("screenshot") &&
|
||||
!toolName.includes("take_screenshot") &&
|
||||
!toolName.includes("capture_screenshot")
|
||||
);
|
||||
});
|
||||
}
|
||||
// In focus mode, include all tools
|
||||
@@ -83,8 +88,11 @@ function filterToolsByMode(tools: typeof allBrowserTools, mode: AutomationMode)
|
||||
* In background mode, visual tools (computer, screenshot) are excluded
|
||||
*/
|
||||
export function useBrowserTools() {
|
||||
const [automationModeRaw] = useStorage<string>(STORAGE_KEYS.AUTOMATION_MODE, "focus");
|
||||
|
||||
const [automationModeRaw] = useStorage<string>(
|
||||
STORAGE_KEYS.AUTOMATION_MODE,
|
||||
"focus",
|
||||
);
|
||||
|
||||
const automationMode: AutomationMode = useMemo(
|
||||
() => validateAutomationMode(automationModeRaw),
|
||||
[automationModeRaw],
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* DOM Element Handle
|
||||
*
|
||||
*
|
||||
* Provides ElementHandle/Locator interface using DOM-based operations
|
||||
* No CDP/debugger required - suitable for background mode
|
||||
*/
|
||||
|
||||
import type { ElementHandle, Locator, TextSnapshotNode } from "./types";
|
||||
import { DomLocator } from "./dom-locator";
|
||||
import type { ElementHandle, Locator, TextSnapshotNode } from "./types";
|
||||
|
||||
/**
|
||||
* DOM-based Locator implementation
|
||||
@@ -84,10 +84,7 @@ class DomLocatorImpl implements Locator {
|
||||
export class DomElementHandle implements ElementHandle {
|
||||
private locator: DomLocatorImpl;
|
||||
|
||||
constructor(
|
||||
private tabId: number,
|
||||
private node: TextSnapshotNode,
|
||||
) {
|
||||
constructor(tabId: number, node: TextSnapshotNode) {
|
||||
this.locator = new DomLocatorImpl(tabId, node.id);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* DOM Locator - Pure DOM-based element operations
|
||||
*
|
||||
*
|
||||
* Uses chrome.scripting.executeScript to interact with elements by UID
|
||||
* No CDP/debugger required - suitable for background mode
|
||||
*/
|
||||
@@ -265,7 +265,7 @@ function runDomAction(payload: DomActionPayload): DomActionResponse<any> {
|
||||
if (monacoEditor && typeof monacoEditor.getValue === "function") {
|
||||
return { success: true, data: monacoEditor.getValue() };
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (_e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
@@ -275,7 +275,7 @@ function runDomAction(payload: DomActionPayload): DomActionResponse<any> {
|
||||
if (codeMirror && typeof codeMirror.getValue === "function") {
|
||||
return { success: true, data: codeMirror.getValue() };
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (_e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ function runDomAction(payload: DomActionPayload): DomActionResponse<any> {
|
||||
if (aceEditor && typeof aceEditor.getValue === "function") {
|
||||
return { success: true, data: aceEditor.getValue() };
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (_e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
|
||||
@@ -8,16 +8,10 @@
|
||||
* The implementation is chosen based on the automation mode setting.
|
||||
*/
|
||||
|
||||
import type { TextSnapshotNode } from "./types";
|
||||
import { snapshotManager } from "./snapshot-manager";
|
||||
import { getAutomationMode } from "../runtime/automation-mode";
|
||||
import {
|
||||
hasGlobPatterns,
|
||||
parseSearchQuery,
|
||||
searchSnapshotText,
|
||||
type SearchOptions,
|
||||
SKIP_ROLES,
|
||||
} from "./query";
|
||||
import { type SearchOptions, SKIP_ROLES, searchSnapshotText } from "./query";
|
||||
import { snapshotManager } from "./snapshot-manager";
|
||||
import type { TextSnapshotNode } from "./types";
|
||||
|
||||
/**
|
||||
* DOM snapshot node structure from @aipexstudio/dom-snapshot
|
||||
@@ -441,11 +435,7 @@ function formatNode(
|
||||
const shouldInclude = shouldIncludeInOutput(node);
|
||||
const attributes = shouldInclude ? getNodeAttributes(node) : [node.role];
|
||||
// marker: '*' = exact focused node; '→' = ancestor in focus path
|
||||
const marker = node.focused
|
||||
? "*"
|
||||
: focusAncestorSet.has(node.id)
|
||||
? "→"
|
||||
: " ";
|
||||
const marker = node.focused ? "*" : focusAncestorSet.has(node.id) ? "→" : " ";
|
||||
let result = `${" ".repeat(depth * 1) + marker + attributes.join(" ")}\n`;
|
||||
|
||||
// recursively format child nodes
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useEffect, useMemo, useState } from "react";
|
||||
import { ChromeStorageAdapter } from "../storage/storage-adapter.js";
|
||||
/**
|
||||
* React hook for Chrome storage (similar to @plasmohq/storage/hook)
|
||||
*
|
||||
*
|
||||
* @throws {Error} If React is not properly loaded (useState is null/undefined)
|
||||
*/
|
||||
export function useStorage(key, defaultValue) {
|
||||
@@ -10,13 +10,13 @@ export function useStorage(key, defaultValue) {
|
||||
if (!useState || !useEffect || !useMemo) {
|
||||
throw new Error(
|
||||
"[useStorage] React hooks are not available. This usually means:\n" +
|
||||
"1. React is being loaded multiple times (check for duplicate React instances)\n" +
|
||||
"2. This hook is being imported in a non-React context (e.g., background script)\n" +
|
||||
"3. Vite/bundler config is externalizing React incorrectly\n" +
|
||||
"Fix: Ensure 'react' and 'react-dom' are deduped in vite.config.ts"
|
||||
"1. React is being loaded multiple times (check for duplicate React instances)\n" +
|
||||
"2. This hook is being imported in a non-React context (e.g., background script)\n" +
|
||||
"3. Vite/bundler config is externalizing React incorrectly\n" +
|
||||
"Fix: Ensure 'react' and 'react-dom' are deduped in vite.config.ts",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const [value, setValue] = useState(defaultValue);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const storage = useMemo(() => new ChromeStorageAdapter(), []);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ChromeStorageAdapter } from "../storage/storage-adapter.js";
|
||||
|
||||
/**
|
||||
* React hook for Chrome storage (similar to @plasmohq/storage/hook)
|
||||
*
|
||||
*
|
||||
* @throws {Error} If React is not properly loaded (useState is null/undefined)
|
||||
*/
|
||||
export function useStorage<T = unknown>(
|
||||
@@ -14,13 +14,13 @@ export function useStorage<T = unknown>(
|
||||
if (!useState || !useEffect || !useMemo) {
|
||||
throw new Error(
|
||||
"[useStorage] React hooks are not available. This usually means:\n" +
|
||||
"1. React is being loaded multiple times (check for duplicate React instances)\n" +
|
||||
"2. This hook is being imported in a non-React context (e.g., background script)\n" +
|
||||
"3. Vite/bundler config is externalizing React incorrectly\n" +
|
||||
"Fix: Ensure 'react' and 'react-dom' are deduped in vite.config.ts"
|
||||
"1. React is being loaded multiple times (check for duplicate React instances)\n" +
|
||||
"2. This hook is being imported in a non-React context (e.g., background script)\n" +
|
||||
"3. Vite/bundler config is externalizing React incorrectly\n" +
|
||||
"Fix: Ensure 'react' and 'react-dom' are deduped in vite.config.ts",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const [value, setValue] = useState<T | undefined>(defaultValue);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { tool } from "@aipexstudio/aipex-core";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
type ElementHandle,
|
||||
SmartElementHandle,
|
||||
} from "../automation";
|
||||
import { type ElementHandle, SmartElementHandle } from "../automation";
|
||||
import { DomElementHandle } from "../automation/dom-element-handle";
|
||||
import * as snapshotProvider from "../automation/snapshot-provider";
|
||||
import {
|
||||
|
||||
9
packages/dom-snapshot/src/collector.d.ts
vendored
9
packages/dom-snapshot/src/collector.d.ts
vendored
@@ -1,3 +1,8 @@
|
||||
import type { CollectorOptions, SerializedDomSnapshot } from "./types.js";
|
||||
export declare function collectDomSnapshot(rootDocument?: Document, options?: Partial<CollectorOptions>): SerializedDomSnapshot;
|
||||
export declare function collectDomSnapshotInPage(options?: Partial<CollectorOptions>): SerializedDomSnapshot;
|
||||
export declare function collectDomSnapshot(
|
||||
rootDocument?: Document,
|
||||
options?: Partial<CollectorOptions>,
|
||||
): SerializedDomSnapshot;
|
||||
export declare function collectDomSnapshotInPage(
|
||||
options?: Partial<CollectorOptions>,
|
||||
): SerializedDomSnapshot;
|
||||
|
||||
4
packages/dom-snapshot/src/manager.d.ts
vendored
4
packages/dom-snapshot/src/manager.d.ts
vendored
@@ -1,3 +1,5 @@
|
||||
import type { SerializedDomSnapshot, TextSnapshot } from "./types.js";
|
||||
export declare function buildTextSnapshot(source: SerializedDomSnapshot): TextSnapshot;
|
||||
export declare function buildTextSnapshot(
|
||||
source: SerializedDomSnapshot,
|
||||
): TextSnapshot;
|
||||
export declare function formatSnapshot(snapshot: TextSnapshot): string;
|
||||
|
||||
25
packages/dom-snapshot/src/query.d.ts
vendored
25
packages/dom-snapshot/src/query.d.ts
vendored
@@ -9,27 +9,36 @@ export declare const SKIP_ROLES: string[];
|
||||
* Search options for snapshot text queries
|
||||
*/
|
||||
export interface SearchOptions {
|
||||
contextLevels?: number;
|
||||
caseSensitive?: boolean;
|
||||
useGlob?: boolean;
|
||||
contextLevels?: number;
|
||||
caseSensitive?: boolean;
|
||||
useGlob?: boolean;
|
||||
}
|
||||
/**
|
||||
* Search result containing matched lines and context
|
||||
*/
|
||||
export interface SearchResult {
|
||||
matchedLines: number[];
|
||||
contextLines: number[];
|
||||
totalMatches: number;
|
||||
matchedLines: number[];
|
||||
contextLines: number[];
|
||||
totalMatches: number;
|
||||
}
|
||||
/**
|
||||
* Main search entry point
|
||||
* Searches snapshot text and returns matched lines with surrounding context
|
||||
*/
|
||||
export declare function searchSnapshotText(snapshotText: string, query: string, options?: SearchOptions): SearchResult;
|
||||
export declare function searchSnapshotText(
|
||||
snapshotText: string,
|
||||
query: string,
|
||||
options?: SearchOptions,
|
||||
): SearchResult;
|
||||
/**
|
||||
* Search snapshot and format results with context
|
||||
*/
|
||||
export declare function searchAndFormat(snapshot: SerializedDomSnapshot, query: string, contextLevels?: number, options?: Partial<SearchOptions>): string | null;
|
||||
export declare function searchAndFormat(
|
||||
snapshot: SerializedDomSnapshot,
|
||||
query: string,
|
||||
contextLevels?: number,
|
||||
options?: Partial<SearchOptions>,
|
||||
): string | null;
|
||||
/**
|
||||
* Parse search query string with "|" separator
|
||||
* Example: "登录 | Login | Sign In" -> ["登录", "Login", "Sign In"]
|
||||
|
||||
@@ -7,7 +7,10 @@ import type { TextSnapshotNode } from "./types.js";
|
||||
/**
|
||||
* Check if a node should be included in output with full attributes
|
||||
*/
|
||||
export declare function shouldIncludeInOutput(node: TextSnapshotNode, skipRoles?: string[]): boolean;
|
||||
export declare function shouldIncludeInOutput(
|
||||
node: TextSnapshotNode,
|
||||
skipRoles?: string[],
|
||||
): boolean;
|
||||
/**
|
||||
* Get node attributes for formatting
|
||||
*/
|
||||
@@ -15,8 +18,16 @@ export declare function getNodeAttributes(node: TextSnapshotNode): string[];
|
||||
/**
|
||||
* Format a node recursively into text representation
|
||||
*/
|
||||
export declare function formatNode(node: TextSnapshotNode, depth: number, focusAncestorSet: Set<string>, skipRoles?: string[]): string;
|
||||
export declare function formatNode(
|
||||
node: TextSnapshotNode,
|
||||
depth: number,
|
||||
focusAncestorSet: Set<string>,
|
||||
skipRoles?: string[],
|
||||
): string;
|
||||
/**
|
||||
* Build focus ancestor set for highlighting focus path
|
||||
*/
|
||||
export declare function buildFocusAncestorSet(root: TextSnapshotNode, idToNode: Map<string, TextSnapshotNode>): Set<string>;
|
||||
export declare function buildFocusAncestorSet(
|
||||
root: TextSnapshotNode,
|
||||
idToNode: Map<string, TextSnapshotNode>,
|
||||
): Set<string>;
|
||||
|
||||
148
packages/dom-snapshot/src/types.d.ts
vendored
148
packages/dom-snapshot/src/types.d.ts
vendored
@@ -1,88 +1,88 @@
|
||||
export interface DomSnapshotNode {
|
||||
id: string;
|
||||
role: string;
|
||||
name?: string;
|
||||
value?: string;
|
||||
description?: string;
|
||||
children: DomSnapshotNode[];
|
||||
tagName?: string;
|
||||
checked?: boolean | "mixed";
|
||||
pressed?: boolean | "mixed";
|
||||
disabled?: boolean;
|
||||
focused?: boolean;
|
||||
selected?: boolean;
|
||||
expanded?: boolean;
|
||||
placeholder?: string;
|
||||
href?: string;
|
||||
title?: string;
|
||||
textContent?: string;
|
||||
inputType?: string;
|
||||
id: string;
|
||||
role: string;
|
||||
name?: string;
|
||||
value?: string;
|
||||
description?: string;
|
||||
children: DomSnapshotNode[];
|
||||
tagName?: string;
|
||||
checked?: boolean | "mixed";
|
||||
pressed?: boolean | "mixed";
|
||||
disabled?: boolean;
|
||||
focused?: boolean;
|
||||
selected?: boolean;
|
||||
expanded?: boolean;
|
||||
placeholder?: string;
|
||||
href?: string;
|
||||
title?: string;
|
||||
textContent?: string;
|
||||
inputType?: string;
|
||||
}
|
||||
export interface DomSnapshotFlatMap {
|
||||
[uid: string]: DomSnapshotNode;
|
||||
[uid: string]: DomSnapshotNode;
|
||||
}
|
||||
export interface DomSnapshotResult {
|
||||
root: DomSnapshotNode;
|
||||
idToNode: DomSnapshotFlatMap;
|
||||
totalNodes: number;
|
||||
timestamp: number;
|
||||
root: DomSnapshotNode;
|
||||
idToNode: DomSnapshotFlatMap;
|
||||
totalNodes: number;
|
||||
timestamp: number;
|
||||
}
|
||||
export interface CollectorOptions {
|
||||
/**
|
||||
* Maximum text length stored for StaticText nodes. Defaults to 160.
|
||||
*/
|
||||
maxTextLength: number;
|
||||
/**
|
||||
* Should we include invisible elements (display:none / hidden). Defaults to false.
|
||||
*/
|
||||
includeHidden: boolean;
|
||||
/**
|
||||
* Whether to capture raw text nodes as StaticText entries. Defaults to true.
|
||||
*/
|
||||
captureTextNodes: boolean;
|
||||
/**
|
||||
* Maximum text length stored for StaticText nodes. Defaults to 160.
|
||||
*/
|
||||
maxTextLength: number;
|
||||
/**
|
||||
* Should we include invisible elements (display:none / hidden). Defaults to false.
|
||||
*/
|
||||
includeHidden: boolean;
|
||||
/**
|
||||
* Whether to capture raw text nodes as StaticText entries. Defaults to true.
|
||||
*/
|
||||
captureTextNodes: boolean;
|
||||
}
|
||||
export interface SerializedDomSnapshot extends DomSnapshotResult {
|
||||
/**
|
||||
* Additional metadata to help debug or visualize the snapshot.
|
||||
*/
|
||||
metadata: {
|
||||
title: string;
|
||||
url: string;
|
||||
collectedAt: string;
|
||||
options: Partial<CollectorOptions>;
|
||||
};
|
||||
/**
|
||||
* Additional metadata to help debug or visualize the snapshot.
|
||||
*/
|
||||
metadata: {
|
||||
title: string;
|
||||
url: string;
|
||||
collectedAt: string;
|
||||
options: Partial<CollectorOptions>;
|
||||
};
|
||||
}
|
||||
export interface TextSnapshotNode {
|
||||
id: string;
|
||||
role: string;
|
||||
name?: string;
|
||||
value?: string;
|
||||
description?: string;
|
||||
children: TextSnapshotNode[];
|
||||
backendDOMNodeId?: number;
|
||||
tagName?: string;
|
||||
focused?: boolean;
|
||||
modal?: boolean;
|
||||
keyshortcuts?: string;
|
||||
roledescription?: string;
|
||||
valuetext?: string;
|
||||
disabled?: boolean;
|
||||
expanded?: boolean;
|
||||
selected?: boolean;
|
||||
checked?: boolean | "mixed";
|
||||
pressed?: boolean | "mixed";
|
||||
level?: number;
|
||||
valuemin?: number;
|
||||
valuemax?: number;
|
||||
autocomplete?: string;
|
||||
haspopup?: string;
|
||||
invalid?: string;
|
||||
orientation?: string;
|
||||
readonly?: boolean;
|
||||
required?: boolean;
|
||||
elementHandle?: () => Promise<Element>;
|
||||
id: string;
|
||||
role: string;
|
||||
name?: string;
|
||||
value?: string;
|
||||
description?: string;
|
||||
children: TextSnapshotNode[];
|
||||
backendDOMNodeId?: number;
|
||||
tagName?: string;
|
||||
focused?: boolean;
|
||||
modal?: boolean;
|
||||
keyshortcuts?: string;
|
||||
roledescription?: string;
|
||||
valuetext?: string;
|
||||
disabled?: boolean;
|
||||
expanded?: boolean;
|
||||
selected?: boolean;
|
||||
checked?: boolean | "mixed";
|
||||
pressed?: boolean | "mixed";
|
||||
level?: number;
|
||||
valuemin?: number;
|
||||
valuemax?: number;
|
||||
autocomplete?: string;
|
||||
haspopup?: string;
|
||||
invalid?: string;
|
||||
orientation?: string;
|
||||
readonly?: boolean;
|
||||
required?: boolean;
|
||||
elementHandle?: () => Promise<Element>;
|
||||
}
|
||||
export interface TextSnapshot {
|
||||
root: TextSnapshotNode;
|
||||
idToNode: Map<string, TextSnapshotNode>;
|
||||
root: TextSnapshotNode;
|
||||
idToNode: Map<string, TextSnapshotNode>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user