Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 24eefdef23 | |||
| 252f550c04 | |||
| 628c249d45 | |||
| 61d598142d | |||
| c0510b2235 | |||
| ca0005c825 |
@@ -49,8 +49,8 @@ Fastest way to try PageAgent with our free Demo LLM:
|
|||||||
|
|
||||||
| Mirrors | URL |
|
| Mirrors | URL |
|
||||||
| ------- | ---------------------------------------------------------------------------------- |
|
| ------- | ---------------------------------------------------------------------------------- |
|
||||||
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.5.9/dist/iife/page-agent.demo.js |
|
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.5.10/dist/iife/page-agent.demo.js |
|
||||||
| China | https://registry.npmmirror.com/page-agent/1.5.9/files/dist/iife/page-agent.demo.js |
|
| China | https://registry.npmmirror.com/page-agent/1.5.10/files/dist/iife/page-agent.demo.js |
|
||||||
|
|
||||||
### NPM Installation
|
### NPM Installation
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -49,8 +49,8 @@
|
|||||||
|
|
||||||
| Mirrors | URL |
|
| Mirrors | URL |
|
||||||
| ------- | ---------------------------------------------------------------------------------- |
|
| ------- | ---------------------------------------------------------------------------------- |
|
||||||
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.5.9/dist/iife/page-agent.demo.js |
|
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.5.10/dist/iife/page-agent.demo.js |
|
||||||
| China | https://registry.npmmirror.com/page-agent/1.5.9/files/dist/iife/page-agent.demo.js |
|
| China | https://registry.npmmirror.com/page-agent/1.5.10/files/dist/iife/page-agent.demo.js |
|
||||||
|
|
||||||
### NPM 安装
|
### NPM 安装
|
||||||
|
|
||||||
|
|||||||
Generated
+20
-21
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "root",
|
"name": "root",
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "root",
|
"name": "root",
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/page-controller",
|
"packages/page-controller",
|
||||||
@@ -11799,11 +11799,11 @@
|
|||||||
},
|
},
|
||||||
"packages/core": {
|
"packages/core": {
|
||||||
"name": "@page-agent/core",
|
"name": "@page-agent/core",
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@page-agent/llms": "1.5.9",
|
"@page-agent/llms": "1.5.10",
|
||||||
"@page-agent/page-controller": "1.5.9",
|
"@page-agent/page-controller": "1.5.10",
|
||||||
"chalk": "^5.6.2"
|
"chalk": "^5.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -11815,13 +11815,13 @@
|
|||||||
},
|
},
|
||||||
"packages/extension": {
|
"packages/extension": {
|
||||||
"name": "@page-agent/ext",
|
"name": "@page-agent/ext",
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@page-agent/core": "1.5.9",
|
"@page-agent/core": "1.5.10",
|
||||||
"@page-agent/llms": "1.5.9",
|
"@page-agent/llms": "1.5.10",
|
||||||
"@page-agent/page-controller": "1.5.9",
|
"@page-agent/page-controller": "1.5.10",
|
||||||
"@page-agent/ui": "1.5.9",
|
"@page-agent/ui": "1.5.10",
|
||||||
"ai-motion": "^0.4.8",
|
"ai-motion": "^0.4.8",
|
||||||
"chalk": "^5.6.2"
|
"chalk": "^5.6.2"
|
||||||
},
|
},
|
||||||
@@ -11832,7 +11832,6 @@
|
|||||||
"@radix-ui/react-separator": "^1.1.8",
|
"@radix-ui/react-separator": "^1.1.8",
|
||||||
"@radix-ui/react-slot": "^1.2.4",
|
"@radix-ui/react-slot": "^1.2.4",
|
||||||
"@radix-ui/react-switch": "^1.2.6",
|
"@radix-ui/react-switch": "^1.2.6",
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
|
||||||
"@types/chrome": "^0.1.37",
|
"@types/chrome": "^0.1.37",
|
||||||
"@types/react": "^19.2.14",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.1",
|
"@types/react-dom": "^19.2.1",
|
||||||
@@ -11859,7 +11858,7 @@
|
|||||||
},
|
},
|
||||||
"packages/llms": {
|
"packages/llms": {
|
||||||
"name": "@page-agent/llms",
|
"name": "@page-agent/llms",
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^5.6.2"
|
"chalk": "^5.6.2"
|
||||||
@@ -11873,7 +11872,7 @@
|
|||||||
},
|
},
|
||||||
"packages/mcp": {
|
"packages/mcp": {
|
||||||
"name": "@page-agent/mcp",
|
"name": "@page-agent/mcp",
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.27.1",
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
||||||
@@ -11888,13 +11887,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/page-agent": {
|
"packages/page-agent": {
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@page-agent/core": "1.5.9",
|
"@page-agent/core": "1.5.10",
|
||||||
"@page-agent/llms": "1.5.9",
|
"@page-agent/llms": "1.5.10",
|
||||||
"@page-agent/page-controller": "1.5.9",
|
"@page-agent/page-controller": "1.5.10",
|
||||||
"@page-agent/ui": "1.5.9",
|
"@page-agent/ui": "1.5.10",
|
||||||
"chalk": "^5.6.2"
|
"chalk": "^5.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -11906,7 +11905,7 @@
|
|||||||
},
|
},
|
||||||
"packages/page-controller": {
|
"packages/page-controller": {
|
||||||
"name": "@page-agent/page-controller",
|
"name": "@page-agent/page-controller",
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ai-motion": "^0.4.8"
|
"ai-motion": "^0.4.8"
|
||||||
@@ -11914,12 +11913,12 @@
|
|||||||
},
|
},
|
||||||
"packages/ui": {
|
"packages/ui": {
|
||||||
"name": "@page-agent/ui",
|
"name": "@page-agent/ui",
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"packages/website": {
|
"packages/website": {
|
||||||
"name": "@page-agent/website",
|
"name": "@page-agent/website",
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@radix-ui/react-icons": "^1.3.2",
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
"@radix-ui/react-separator": "^1.1.8",
|
"@radix-ui/react-separator": "^1.1.8",
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "root",
|
"name": "root",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/page-controller",
|
"packages/page-controller",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/core",
|
"name": "@page-agent/core",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/esm/page-agent-core.js",
|
"main": "./dist/esm/page-agent-core.js",
|
||||||
"module": "./dist/esm/page-agent-core.js",
|
"module": "./dist/esm/page-agent-core.js",
|
||||||
@@ -44,8 +44,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
"@page-agent/llms": "1.5.9",
|
"@page-agent/llms": "1.5.10",
|
||||||
"@page-agent/page-controller": "1.5.9"
|
"@page-agent/page-controller": "1.5.10"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"zod": "^3.25.0 || ^4.0.0"
|
"zod": "^3.25.0 || ^4.0.0"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/ext",
|
"name": "@page-agent/ext",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "wxt",
|
"dev": "wxt",
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
"@radix-ui/react-separator": "^1.1.8",
|
"@radix-ui/react-separator": "^1.1.8",
|
||||||
"@radix-ui/react-slot": "^1.2.4",
|
"@radix-ui/react-slot": "^1.2.4",
|
||||||
"@radix-ui/react-switch": "^1.2.6",
|
"@radix-ui/react-switch": "^1.2.6",
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
|
||||||
"@types/chrome": "^0.1.37",
|
"@types/chrome": "^0.1.37",
|
||||||
"@types/react": "^19.2.14",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.1",
|
"@types/react-dom": "^19.2.1",
|
||||||
@@ -38,10 +37,10 @@
|
|||||||
"wxt": "^0.20.19"
|
"wxt": "^0.20.19"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@page-agent/core": "1.5.9",
|
"@page-agent/core": "1.5.10",
|
||||||
"@page-agent/llms": "1.5.9",
|
"@page-agent/llms": "1.5.10",
|
||||||
"@page-agent/page-controller": "1.5.9",
|
"@page-agent/page-controller": "1.5.10",
|
||||||
"@page-agent/ui": "1.5.9",
|
"@page-agent/ui": "1.5.10",
|
||||||
"ai-motion": "^0.4.8",
|
"ai-motion": "^0.4.8",
|
||||||
"chalk": "^5.6.2"
|
"chalk": "^5.6.2"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ export class MultiPageAgent extends PageAgentCore {
|
|||||||
},
|
},
|
||||||
|
|
||||||
onBeforeStep: async (agent) => {
|
onBeforeStep: async (agent) => {
|
||||||
|
if (!tabsController.currentTabId) return
|
||||||
// make sure the current tab is loaded before the step starts
|
// make sure the current tab is loaded before the step starts
|
||||||
await tabsController.waitUntilTabLoaded(tabsController.currentTabId!)
|
await tabsController.waitUntilTabLoaded(tabsController.currentTabId!)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -58,8 +58,6 @@ export class RemotePageController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getBrowserState(): Promise<BrowserState> {
|
async getBrowserState(): Promise<BrowserState> {
|
||||||
if (!this.currentTabId) throw new Error('tabsController not initialized.')
|
|
||||||
|
|
||||||
let browserState = {} as BrowserState
|
let browserState = {} as BrowserState
|
||||||
debug('getBrowserState', this.currentTabId)
|
debug('getBrowserState', this.currentTabId)
|
||||||
|
|
||||||
@@ -178,7 +176,7 @@ interface DomActionReturn {
|
|||||||
/**
|
/**
|
||||||
* Check if a URL can run content scripts.
|
* Check if a URL can run content scripts.
|
||||||
*/
|
*/
|
||||||
function isContentScriptAllowed(url: string | undefined): boolean {
|
export function isContentScriptAllowed(url: string | undefined): boolean {
|
||||||
if (!url) return false
|
if (!url) return false
|
||||||
|
|
||||||
const restrictedPatterns = [
|
const restrictedPatterns = [
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { isContentScriptAllowed } from './RemotePageController'
|
||||||
|
|
||||||
const PREFIX = '[TabsController]'
|
const PREFIX = '[TabsController]'
|
||||||
|
|
||||||
function debug(...messages: any[]) {
|
function debug(...messages: any[]) {
|
||||||
@@ -49,23 +51,25 @@ export class TabsController extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (includeInitialTab) {
|
if (includeInitialTab) {
|
||||||
this.currentTabId = this.initialTabId
|
|
||||||
|
|
||||||
const info = await sendMessage({
|
const info = await sendMessage({
|
||||||
type: 'TAB_CONTROL',
|
type: 'TAB_CONTROL',
|
||||||
action: 'get_tab_info',
|
action: 'get_tab_info',
|
||||||
payload: { tabId: this.initialTabId },
|
payload: { tabId: this.initialTabId },
|
||||||
})
|
})
|
||||||
|
|
||||||
this.tabs.push({
|
if (isContentScriptAllowed(info.url)) {
|
||||||
id: result.tabId,
|
this.currentTabId = this.initialTabId
|
||||||
isInitial: true,
|
|
||||||
url: info.url,
|
|
||||||
title: info.title,
|
|
||||||
status: info.status,
|
|
||||||
})
|
|
||||||
|
|
||||||
await this.createTabGroup([this.initialTabId])
|
this.tabs.push({
|
||||||
|
id: result.tabId,
|
||||||
|
isInitial: true,
|
||||||
|
url: info.url,
|
||||||
|
title: info.title,
|
||||||
|
status: info.status,
|
||||||
|
})
|
||||||
|
|
||||||
|
await this.createTabGroup([this.initialTabId])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.updateCurrentTabId(this.currentTabId)
|
await this.updateCurrentTabId(this.currentTabId)
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import {
|
import {
|
||||||
ChevronDown,
|
|
||||||
Copy,
|
Copy,
|
||||||
CornerUpLeft,
|
CornerUpLeft,
|
||||||
|
ExternalLink,
|
||||||
Eye,
|
Eye,
|
||||||
EyeOff,
|
EyeOff,
|
||||||
|
FoldVertical,
|
||||||
HatGlasses,
|
HatGlasses,
|
||||||
Home,
|
Home,
|
||||||
Loader2,
|
Loader2,
|
||||||
Scale,
|
Scale,
|
||||||
|
UnfoldVertical,
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { siGithub } from 'simple-icons'
|
import { siGithub } from 'simple-icons'
|
||||||
@@ -153,6 +155,16 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Hub link */}
|
||||||
|
<a
|
||||||
|
href="/hub.html"
|
||||||
|
target="_blank"
|
||||||
|
className="flex items-center justify-between p-3 rounded-md border bg-muted/50 text-xs font-medium text-muted-foreground hover:text-foreground hover:border-foreground/20 transition-colors"
|
||||||
|
>
|
||||||
|
Manage Page Agent Hub
|
||||||
|
<ExternalLink className="size-3" />
|
||||||
|
</a>
|
||||||
|
|
||||||
<div className="flex flex-col gap-1.5">
|
<div className="flex flex-col gap-1.5">
|
||||||
<label className="text-xs text-muted-foreground">Base URL</label>
|
<label className="text-xs text-muted-foreground">Base URL</label>
|
||||||
<Input
|
<Input
|
||||||
@@ -167,7 +179,7 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
|
|||||||
{isTestingEndpoint(baseURL) && (
|
{isTestingEndpoint(baseURL) && (
|
||||||
<div className="p-2.5 rounded-md border border-amber-500/30 bg-amber-500/5 text-[11px] text-muted-foreground leading-relaxed">
|
<div className="p-2.5 rounded-md border border-amber-500/30 bg-amber-500/5 text-[11px] text-muted-foreground leading-relaxed">
|
||||||
<Scale className="size-3 inline-block mr-1 -mt-0.5 text-amber-600" />
|
<Scale className="size-3 inline-block mr-1 -mt-0.5 text-amber-600" />
|
||||||
You are using the free testing API. By using this service you agree to the{' '}
|
You are using our testing API. By using this you agree to the{' '}
|
||||||
<a
|
<a
|
||||||
href="https://github.com/alibaba/page-agent/blob/main/docs/terms-and-privacy.md"
|
href="https://github.com/alibaba/page-agent/blob/main/docs/terms-and-privacy.md"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -176,7 +188,6 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
|
|||||||
>
|
>
|
||||||
Terms of Use & Privacy Policy
|
Terms of Use & Privacy Policy
|
||||||
</a>
|
</a>
|
||||||
. No sensitive data. No guaranteed availability.
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -212,7 +223,7 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col gap-1.5">
|
<div className="flex flex-col gap-1.5">
|
||||||
<label className="text-xs text-muted-foreground">Language</label>
|
<label className="text-xs text-muted-foreground">Response Language</label>
|
||||||
<select
|
<select
|
||||||
value={language ?? ''}
|
value={language ?? ''}
|
||||||
onChange={(e) => setLanguage((e.target.value || undefined) as LanguagePreference)}
|
onChange={(e) => setLanguage((e.target.value || undefined) as LanguagePreference)}
|
||||||
@@ -231,10 +242,7 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
|
|||||||
className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground cursor-pointer mt-1 font-bold"
|
className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground cursor-pointer mt-1 font-bold"
|
||||||
>
|
>
|
||||||
Advanced
|
Advanced
|
||||||
<ChevronDown
|
{advancedOpen ? <FoldVertical className="size-3" /> : <UnfoldVertical className="size-3" />}
|
||||||
className="size-3 transition-transform"
|
|
||||||
style={{ transform: advancedOpen ? 'rotate(0deg)' : 'rotate(90deg)' }}
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{advancedOpen && (
|
{advancedOpen && (
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export function MotionOverlay({ active }: { active: boolean }) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
className="pointer-events-none absolute inset-0 z-10 opacity-60"
|
className="pointer-events-none absolute inset-0 z-10 opacity-60 overflow-hidden"
|
||||||
style={{ display: active ? undefined : 'none' }}
|
style={{ display: active ? undefined : 'none' }}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ function Switch({ className, ...props }: React.ComponentProps<typeof SwitchPrimi
|
|||||||
<SwitchPrimitive.Root
|
<SwitchPrimitive.Root
|
||||||
data-slot="switch"
|
data-slot="switch"
|
||||||
className={cn(
|
className={cn(
|
||||||
'peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
|
'peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 cursor-pointer items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { Plug, PlugZap, Square, Unplug } from 'lucide-react'
|
import { FoldVertical, Plug, PlugZap, Square, UnfoldVertical, Unplug } from 'lucide-react'
|
||||||
import { useEffect, useRef } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
|
|
||||||
import { useAgent } from '@/agent/useAgent'
|
import { useAgent } from '@/agent/useAgent'
|
||||||
import { ActivityCard, EventCard } from '@/components/cards'
|
import { ActivityCard, EventCard } from '@/components/cards'
|
||||||
import { Logo, MotionOverlay, StatusDot } from '@/components/misc'
|
import { Logo, MotionOverlay, StatusDot } from '@/components/misc'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
|
import { Switch } from '@/components/ui/switch'
|
||||||
|
|
||||||
import { useHubWs } from './hub-ws'
|
import { useHubWs } from './hub-ws'
|
||||||
|
|
||||||
@@ -25,33 +26,72 @@ export default function App() {
|
|||||||
const wsLabel = {
|
const wsLabel = {
|
||||||
connected: 'Connected',
|
connected: 'Connected',
|
||||||
connecting: 'Connecting…',
|
connecting: 'Connecting…',
|
||||||
disconnected: new URLSearchParams(location.search).get('ws') ? 'Disconnected' : 'Standalone',
|
disconnected: new URLSearchParams(location.search).get('ws') ? 'Disconnected' : 'No connection',
|
||||||
}[wsState]
|
}[wsState]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen bg-background">
|
<div className="flex h-screen bg-background">
|
||||||
<MotionOverlay active={isRunning} />
|
|
||||||
|
|
||||||
{/* Left — Protocol docs */}
|
{/* Left — Protocol docs */}
|
||||||
<aside className="w-80 shrink-0 border-r flex flex-col bg-muted/20">
|
<aside className="w-80 shrink-0 border-r flex flex-col bg-muted/20">
|
||||||
<div className="flex items-center gap-2 px-5 py-4 border-b">
|
<a
|
||||||
|
href="https://alibaba.github.io/page-agent/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="flex items-center gap-2 px-5 h-12 border-b hover:bg-muted/30 transition-colors"
|
||||||
|
>
|
||||||
<Logo className="size-5" />
|
<Logo className="size-5" />
|
||||||
<span className="text-sm font-semibold tracking-tight">Page Agent Hub</span>
|
<span className="text-sm font-semibold tracking-tight">Page Agent Hub</span>
|
||||||
|
<span className="text-[9px] font-medium uppercase tracking-wider text-amber-600 bg-amber-500/10 border border-amber-500/30 rounded px-1.5 py-0.5">
|
||||||
|
Beta
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div className="flex-1 overflow-y-auto px-5 py-4 space-y-6">
|
||||||
|
<div className="text-xs text-muted-foreground leading-relaxed space-y-2">
|
||||||
|
<p>
|
||||||
|
Page Agent Hub lets local apps (e.g. MCP servers) control the Page Agent extension via
|
||||||
|
WebSocket.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Check out the official{' '}
|
||||||
|
<a
|
||||||
|
href="https://github.com/alibaba/page-agent/tree/main/packages/mcp"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="underline hover:text-foreground"
|
||||||
|
>
|
||||||
|
MCP server package
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<HubConfig />
|
||||||
|
|
||||||
|
<ProtocolDocsCollapsible />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 overflow-y-auto px-5 py-4">
|
<div className="border-t px-5 py-3 text-[10px] text-muted-foreground/60 flex items-center justify-between">
|
||||||
<ProtocolDocs />
|
<span className="font-mono">v{__VERSION__}</span>
|
||||||
</div>
|
<span>
|
||||||
|
Built with ♥️ by{' '}
|
||||||
<div className="border-t px-5 py-3 text-[11px] text-muted-foreground/60">
|
<a
|
||||||
Connect via <code className="text-[10px]">hub.html?ws=PORT</code>
|
href="https://github.com/gaomeng1900"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="underline hover:text-foreground"
|
||||||
|
>
|
||||||
|
@Simon
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
{/* Right — Live session */}
|
{/* Right — Live session */}
|
||||||
<main className="flex-1 flex flex-col min-w-0">
|
<main className="flex-1 flex flex-col min-w-0 relative">
|
||||||
{/* Header bar */}
|
<MotionOverlay active={isRunning} />
|
||||||
<header className="flex items-center justify-between border-b px-5 py-3">
|
|
||||||
|
<header className="flex items-center justify-between border-b px-5 h-12">
|
||||||
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
||||||
<WsIcon className="size-3.5" />
|
<WsIcon className="size-3.5" />
|
||||||
<span>{wsLabel}</span>
|
<span>{wsLabel}</span>
|
||||||
@@ -104,49 +144,108 @@ export default function App() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function ProtocolDocs() {
|
function HubConfig() {
|
||||||
|
const [allowAll, setAllowAll] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
chrome.storage.local.get('allowAllHubConnection').then((r) => {
|
||||||
|
setAllowAll(r.allowAllHubConnection === true)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const toggle = (checked: boolean) => {
|
||||||
|
setAllowAll(checked)
|
||||||
|
chrome.storage.local.set({ allowAllHubConnection: checked })
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-5 text-xs text-muted-foreground">
|
<div>
|
||||||
<section>
|
<h3 className="text-[11px] font-semibold text-foreground/80 uppercase tracking-wider mb-2">
|
||||||
<h3 className="text-[11px] font-semibold text-foreground/80 uppercase tracking-wider mb-2">
|
Config
|
||||||
Caller → Hub
|
</h3>
|
||||||
</h3>
|
<div className="group/hub relative">
|
||||||
<pre className="bg-muted/50 rounded-md p-3 font-mono text-[10px] leading-relaxed whitespace-pre-wrap">
|
<label
|
||||||
{`{ type: "execute", task: string, config?: object }
|
className={`flex items-center justify-between p-3 rounded-md border cursor-pointer text-xs ${allowAll ? 'bg-amber-500/10 border-amber-500/30 text-amber-600' : 'bg-muted/50 text-muted-foreground'}`}
|
||||||
{ type: "stop" }`}
|
>
|
||||||
</pre>
|
Auto-approve connections
|
||||||
</section>
|
<Switch
|
||||||
|
checked={allowAll}
|
||||||
|
onCheckedChange={toggle}
|
||||||
|
className={allowAll ? 'data-[state=checked]:bg-amber-500' : ''}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
<section>
|
{/* hide with invisible absolute opacity-0*/}
|
||||||
<h3 className="text-[11px] font-semibold text-foreground/80 uppercase tracking-wider mb-2">
|
<div className="group-hover/hub:visible group-hover/hub:opacity-100 transition-opacity duration-150 left-0 right-0 top-full z-10 pt-2">
|
||||||
Hub → Caller
|
<div className="relative p-2.5 rounded-md border border-border bg-background/60 backdrop-blur-md shadow-2xl text-muted-foreground text-xs leading-relaxed">
|
||||||
</h3>
|
<div className="absolute -top-1.5 left-5 size-3 rotate-45 rounded-[1px] border-l border-t border-border bg-background/60 backdrop-blur-md" />
|
||||||
<pre className="bg-muted/50 rounded-md p-3 font-mono text-[10px] leading-relaxed whitespace-pre-wrap">
|
By default, each connection requires your approval before running tasks. <br />
|
||||||
{`{ type: "ready" }
|
Enable this to skip per-session approval.
|
||||||
{ type: "result", success: boolean, data: string }
|
<br />
|
||||||
{ type: "error", message: string }`}
|
<span className="font-semibold">* Use with caution!</span>
|
||||||
</pre>
|
</div>
|
||||||
</section>
|
</div>
|
||||||
|
</div>
|
||||||
<section>
|
</div>
|
||||||
<h3 className="text-[11px] font-semibold text-foreground/80 uppercase tracking-wider mb-2">
|
)
|
||||||
Flow
|
}
|
||||||
</h3>
|
|
||||||
<ol className="list-decimal list-inside space-y-1 text-[11px] leading-relaxed">
|
function ProtocolDocsCollapsible() {
|
||||||
<li>Hub opens WS to caller's server</li>
|
const [open, setOpen] = useState(false)
|
||||||
<li>
|
|
||||||
Sends <code className="text-[10px]">ready</code>
|
return (
|
||||||
</li>
|
<div>
|
||||||
<li>
|
<button
|
||||||
Caller sends <code className="text-[10px]">execute</code> with task
|
type="button"
|
||||||
</li>
|
onClick={() => setOpen(!open)}
|
||||||
<li>Hub runs agent, streams events</li>
|
className="flex items-center gap-1 text-[11px] font-semibold text-foreground/80 uppercase tracking-wider cursor-pointer"
|
||||||
<li>
|
>
|
||||||
Hub sends <code className="text-[10px]">result</code> or{' '}
|
Docs
|
||||||
<code className="text-[10px]">error</code>
|
{open ? <FoldVertical className="size-3" /> : <UnfoldVertical className="size-3" />}
|
||||||
</li>
|
</button>
|
||||||
</ol>
|
|
||||||
</section>
|
{open && (
|
||||||
|
<div className="mt-3 space-y-4 text-xs text-muted-foreground">
|
||||||
|
<p className="text-[10px]">
|
||||||
|
Connect via <code className="text-[10px]">hub.html?ws=PORT</code>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h4 className="text-[11px] font-medium text-foreground/60 mb-1.5">Flow</h4>
|
||||||
|
<ol className="list-decimal list-inside space-y-1 text-[11px] leading-relaxed">
|
||||||
|
<li>Hub opens WS to caller's server</li>
|
||||||
|
<li>
|
||||||
|
Sends <code className="text-[10px]">ready</code>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Caller sends <code className="text-[10px]">execute</code> with task
|
||||||
|
</li>
|
||||||
|
<li>Hub runs agent, streams events</li>
|
||||||
|
<li>
|
||||||
|
Hub sends <code className="text-[10px]">result</code> or{' '}
|
||||||
|
<code className="text-[10px]">error</code>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h4 className="text-[11px] font-medium text-foreground/60 mb-1.5">Caller → Hub</h4>
|
||||||
|
<pre className="bg-muted/50 rounded-md p-3 font-mono text-[10px] leading-relaxed whitespace-pre-wrap">
|
||||||
|
{`{ type: "execute", task: string, config?: object }
|
||||||
|
{ type: "stop" }`}
|
||||||
|
</pre>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h4 className="text-[11px] font-medium text-foreground/60 mb-1.5">Hub → Caller</h4>
|
||||||
|
<pre className="bg-muted/50 rounded-md p-3 font-mono text-[10px] leading-relaxed whitespace-pre-wrap">
|
||||||
|
{`{ type: "ready" }
|
||||||
|
{ type: "result", success: boolean, data: string }
|
||||||
|
{ type: "error", message: string }`}
|
||||||
|
</pre>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ export class HubWs {
|
|||||||
#ws: WebSocket | null = null
|
#ws: WebSocket | null = null
|
||||||
#state: HubWsState = 'disconnected'
|
#state: HubWsState = 'disconnected'
|
||||||
#busy = false
|
#busy = false
|
||||||
|
#approved = false
|
||||||
#handlers: HubWsHandlers
|
#handlers: HubWsHandlers
|
||||||
#port: number
|
#port: number
|
||||||
#onStateChange: (state: HubWsState) => void
|
#onStateChange: (state: HubWsState) => void
|
||||||
@@ -103,6 +104,7 @@ export class HubWs {
|
|||||||
ws.addEventListener('close', () => {
|
ws.addEventListener('close', () => {
|
||||||
this.#ws = null
|
this.#ws = null
|
||||||
this.#busy = false
|
this.#busy = false
|
||||||
|
this.#approved = false
|
||||||
this.#setState('disconnected')
|
this.#setState('disconnected')
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -115,6 +117,7 @@ export class HubWs {
|
|||||||
this.#ws?.close()
|
this.#ws?.close()
|
||||||
this.#ws = null
|
this.#ws = null
|
||||||
this.#busy = false
|
this.#busy = false
|
||||||
|
this.#approved = false
|
||||||
this.#setState('disconnected')
|
this.#setState('disconnected')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +133,7 @@ export class HubWs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#handleMessage(raw: string) {
|
async #handleMessage(raw: string) {
|
||||||
let msg: InboundMessage
|
let msg: InboundMessage
|
||||||
try {
|
try {
|
||||||
msg = JSON.parse(raw)
|
msg = JSON.parse(raw)
|
||||||
@@ -138,6 +141,11 @@ export class HubWs {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(await this.#checkApproval())) {
|
||||||
|
this.#send({ type: 'error', message: 'User denied the connection request.' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
case 'execute':
|
case 'execute':
|
||||||
this.#handleExecute(msg)
|
this.#handleExecute(msg)
|
||||||
@@ -148,6 +156,22 @@ export class HubWs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async #checkApproval(): Promise<boolean> {
|
||||||
|
if (this.#approved) return true
|
||||||
|
|
||||||
|
const { allowAllHubConnection } = await chrome.storage.local.get('allowAllHubConnection')
|
||||||
|
if (allowAllHubConnection === true) {
|
||||||
|
this.#approved = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const ok = window.confirm(
|
||||||
|
'An external application is requesting to control your browser via Page Agent Ext.\nAllow this session?'
|
||||||
|
)
|
||||||
|
if (ok) this.#approved = true
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
async #handleExecute(msg: ExecuteMessage) {
|
async #handleExecute(msg: ExecuteMessage) {
|
||||||
if (this.#busy) {
|
if (this.#busy) {
|
||||||
this.#send({ type: 'error', message: 'Hub is busy with another task' })
|
this.#send({ type: 'error', message: 'Hub is busy with another task' })
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/llms",
|
"name": "@page-agent/llms",
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/lib/page-agent-llms.js",
|
"main": "./dist/lib/page-agent-llms.js",
|
||||||
"module": "./dist/lib/page-agent-llms.js",
|
"module": "./dist/lib/page-agent-llms.js",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/mcp",
|
"name": "@page-agent/mcp",
|
||||||
"private": true,
|
"private": false,
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
"page-agent-mcp": "src/index.js"
|
"page-agent-mcp": "src/index.js"
|
||||||
|
|||||||
+148
-40
@@ -1,9 +1,10 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Page Agent – Connecting</title>
|
<link rel="icon" href="https://img.alicdn.com/imgextra/i1/O1CN01mRGret1QrKiu7CFJI_!!6000000002029-2-tps-64-64.png" />
|
||||||
|
<title>Page Agent MCP Launcher</title>
|
||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -15,7 +16,7 @@
|
|||||||
system-ui,
|
system-ui,
|
||||||
-apple-system,
|
-apple-system,
|
||||||
sans-serif;
|
sans-serif;
|
||||||
background: #0a0a0a;
|
background: #09090b;
|
||||||
color: #e5e5e5;
|
color: #e5e5e5;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -24,23 +25,37 @@
|
|||||||
}
|
}
|
||||||
.card {
|
.card {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
max-width: 420px;
|
max-width: 480px;
|
||||||
padding: 3rem 2rem;
|
padding: 3rem 2rem;
|
||||||
}
|
}
|
||||||
|
.logo {
|
||||||
|
width: 72px;
|
||||||
|
height: 72px;
|
||||||
|
border-radius: 18px;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
.badge {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #52525b;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 1.25rem;
|
font-size: 1.35rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
p {
|
.sub {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
color: #a3a3a3;
|
color: #a1a1aa;
|
||||||
line-height: 1.6;
|
line-height: 1.7;
|
||||||
}
|
}
|
||||||
.spinner {
|
.spinner {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
border: 3px solid #333;
|
border: 3px solid #27272a;
|
||||||
border-top-color: #fff;
|
border-top-color: #fff;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
animation: spin 0.8s linear infinite;
|
animation: spin 0.8s linear infinite;
|
||||||
@@ -58,72 +73,165 @@
|
|||||||
a:hover {
|
a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.install {
|
.install {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.install.show {
|
.install.show {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.btn {
|
|
||||||
display: inline-block;
|
.tips {
|
||||||
margin-top: 1rem;
|
margin-top: 1.75rem;
|
||||||
padding: 0.5rem 1.25rem;
|
text-align: left;
|
||||||
|
background: #18181b;
|
||||||
|
border: 1px solid #27272a;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 1.25rem 1.5rem;
|
||||||
|
}
|
||||||
|
.tips li {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
color: #a1a1aa;
|
||||||
|
line-height: 1.7;
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
|
.tips li + li {
|
||||||
|
margin-top: 0.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.store-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.625rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
padding: 0.625rem 1.5rem;
|
||||||
background: #2563eb;
|
background: #2563eb;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border-radius: 0.5rem;
|
border-radius: 10px;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
transition: background 0.15s;
|
||||||
}
|
}
|
||||||
.btn:hover {
|
.store-btn:hover {
|
||||||
background: #1d4ed8;
|
background: #1d4ed8;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
.store-btn img {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.links {
|
||||||
|
margin-top: 1.75rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1.5rem;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
}
|
||||||
|
.links a {
|
||||||
|
color: #71717a;
|
||||||
|
transition: color 0.15s;
|
||||||
|
}
|
||||||
|
.links a:hover {
|
||||||
|
color: #a1a1aa;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
<img
|
||||||
|
class="logo"
|
||||||
|
src="https://img.alicdn.com/imgextra/i3/O1CN01JPT4Fj1FJTfmHfNxO_!!6000000000466-49-tps-512-512.webp"
|
||||||
|
alt="Page Agent"
|
||||||
|
/>
|
||||||
|
<div class="badge">Page Agent MCP Launcher</div>
|
||||||
|
|
||||||
<div id="connecting">
|
<div id="connecting">
|
||||||
<div class="spinner"></div>
|
<div class="spinner"></div>
|
||||||
<h1>Connecting to Page Agent</h1>
|
<h1 data-i18n="connecting_title">Connecting to Page Agent</h1>
|
||||||
<p>Opening the hub in your browser...</p>
|
<p class="sub" data-i18n="connecting_sub">Opening the hub in your browser…</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="install" class="install">
|
<div id="install" class="install">
|
||||||
<h1>Extension Not Found</h1>
|
<h1 data-i18n="install_title">Extension Required</h1>
|
||||||
<p>The Page Agent browser extension is required.<br />Install it and try again.</p>
|
<p class="sub" data-i18n="install_sub">
|
||||||
<a class="btn" href="__STORE_URL__" target="_blank">Install Extension</a>
|
Page Agent requires the latest browser extension to work.
|
||||||
<p style="margin-top: 1.5rem; font-size: 0.75rem">
|
|
||||||
After installing, restart the MCP server or refresh this page.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<a class="store-btn" href="__STORE_URL__" target="_blank">
|
||||||
|
<img
|
||||||
|
src="https://img.alicdn.com/imgextra/i3/O1CN01JpW0Vo1sR3FpiZKFM_!!6000000005762-55-tps-192-192.svg"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
<span data-i18n="install_btn">Install from Chrome Web Store</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<ul class="tips">
|
||||||
|
<li data-i18n="tip_outdated">
|
||||||
|
If the extension is outdated, please update it to the latest version.
|
||||||
|
</li>
|
||||||
|
<li data-i18n="tip_other_browser">
|
||||||
|
If the extension is not installed in this browser, open this page from the
|
||||||
|
browser that has it installed.
|
||||||
|
</li>
|
||||||
|
<li data-i18n="tip_refresh">Refresh this page after installing or updating.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="links">
|
||||||
|
<a href="https://alibaba.github.io/page-agent/docs/introduction/overview" target="_blank" data-i18n="link_docs">Docs</a>
|
||||||
|
<a href="https://github.com/alibaba/page-agent/issues" target="_blank" data-i18n="link_issues">Report an Issue</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
|
||||||
;(function () {
|
|
||||||
var EXT_ID = '__EXT_ID__'
|
|
||||||
var wsPort = __WS_PORT__
|
|
||||||
|
|
||||||
function showInstall() {
|
<script>
|
||||||
|
{
|
||||||
|
const EXT_ID = '__EXT_ID__'
|
||||||
|
const wsPort = __WS_PORT__
|
||||||
|
|
||||||
|
const zh = {
|
||||||
|
connecting_title: '正在连接 Page Agent',
|
||||||
|
connecting_sub: '正在浏览器中打开 Hub…',
|
||||||
|
install_title: '需要安装浏览器插件',
|
||||||
|
install_sub: 'Page Agent 需要安装最新版浏览器插件才能运行。',
|
||||||
|
install_btn: '从 Chrome 应用商店安装',
|
||||||
|
tip_outdated: '如果插件版本过旧,请更新到最新版本。',
|
||||||
|
tip_other_browser:
|
||||||
|
'如果该浏览器中未安装插件,请从装有插件的浏览器打开此页面。',
|
||||||
|
tip_refresh: '安装或更新后,请刷新此页面。',
|
||||||
|
link_docs: '文档',
|
||||||
|
link_issues: '问题反馈',
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^zh\b/i.test(navigator.language)) {
|
||||||
|
document.querySelectorAll('[data-i18n]').forEach((el) => {
|
||||||
|
const key = el.getAttribute('data-i18n')
|
||||||
|
if (zh[key]) el.textContent = zh[key]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const showInstall = () => {
|
||||||
document.getElementById('connecting').style.display = 'none'
|
document.getElementById('connecting').style.display = 'none'
|
||||||
document.getElementById('install').classList.add('show')
|
document.getElementById('install').classList.add('show')
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (typeof chrome === 'undefined' || !chrome.runtime || !chrome.runtime.sendMessage) {
|
if (!globalThis.chrome?.runtime?.sendMessage) {
|
||||||
showInstall()
|
showInstall()
|
||||||
return
|
} else {
|
||||||
}
|
chrome.runtime.sendMessage(
|
||||||
chrome.runtime.sendMessage(
|
EXT_ID,
|
||||||
EXT_ID,
|
{ type: 'OPEN_HUB', wsPort },
|
||||||
{ type: 'OPEN_HUB', wsPort: wsPort },
|
(response) => {
|
||||||
function (response) {
|
if (chrome.runtime.lastError || !response?.ok) showInstall()
|
||||||
if (chrome.runtime.lastError || !response || !response.ok) {
|
|
||||||
showInstall()
|
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
)
|
}
|
||||||
} catch (e) {
|
} catch {
|
||||||
showInstall()
|
showInstall()
|
||||||
}
|
}
|
||||||
})()
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "page-agent",
|
"name": "page-agent",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/esm/page-agent.js",
|
"main": "./dist/esm/page-agent.js",
|
||||||
"module": "./dist/esm/page-agent.js",
|
"module": "./dist/esm/page-agent.js",
|
||||||
@@ -44,10 +44,10 @@
|
|||||||
"postpublish": "node -e \"['README.md','LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\""
|
"postpublish": "node -e \"['README.md','LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\""
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@page-agent/core": "1.5.9",
|
"@page-agent/core": "1.5.10",
|
||||||
"@page-agent/llms": "1.5.9",
|
"@page-agent/llms": "1.5.10",
|
||||||
"@page-agent/page-controller": "1.5.9",
|
"@page-agent/page-controller": "1.5.10",
|
||||||
"@page-agent/ui": "1.5.9",
|
"@page-agent/ui": "1.5.10",
|
||||||
"chalk": "^5.6.2"
|
"chalk": "^5.6.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/page-controller",
|
"name": "@page-agent/page-controller",
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/lib/page-controller.js",
|
"main": "./dist/lib/page-controller.js",
|
||||||
"module": "./dist/lib/page-controller.js",
|
"module": "./dist/lib/page-controller.js",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/ui",
|
"name": "@page-agent/ui",
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/lib/page-agent-ui.js",
|
"main": "./dist/lib/page-agent-ui.js",
|
||||||
"module": "./dist/lib/page-agent-ui.js",
|
"module": "./dist/lib/page-agent-ui.js",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/website",
|
"name": "@page-agent/website",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.5.9",
|
"version": "1.5.10",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host 0.0.0.0",
|
"dev": "vite --host 0.0.0.0",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// Demo build (auto-init with demo LLM, for quick testing)
|
// Demo build (auto-init with demo LLM, for quick testing)
|
||||||
export const CDN_DEMO_URL =
|
export const CDN_DEMO_URL =
|
||||||
'https://cdn.jsdelivr.net/npm/page-agent@1.5.9/dist/iife/page-agent.demo.js'
|
'https://cdn.jsdelivr.net/npm/page-agent@1.5.10/dist/iife/page-agent.demo.js'
|
||||||
export const CDN_DEMO_CN_URL =
|
export const CDN_DEMO_CN_URL =
|
||||||
'https://registry.npmmirror.com/page-agent/1.5.9/files/dist/iife/page-agent.demo.js'
|
'https://registry.npmmirror.com/page-agent/1.5.10/files/dist/iife/page-agent.demo.js'
|
||||||
|
|
||||||
// Demo LLM for website testing (homepage quick trial uses flash)
|
// Demo LLM for website testing (homepage quick trial uses flash)
|
||||||
export const DEMO_MODEL = 'qwen3.5-flash'
|
export const DEMO_MODEL = 'qwen3.5-flash'
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ const MODEL_GROUPS: Record<string, string[]> = {
|
|||||||
'claude-sonnet-3.5',
|
'claude-sonnet-3.5',
|
||||||
],
|
],
|
||||||
xAI: ['grok-4.1-fast', 'grok-4', 'grok-code-fast'],
|
xAI: ['grok-4.1-fast', 'grok-4', 'grok-code-fast'],
|
||||||
MiniMax: ['MiniMax-M2.5', 'MiniMax-M2.5-highspeed'],
|
MiniMax: ['MiniMax-M2.7', 'MiniMax-M2.7-highspeed', 'MiniMax-M2.5', 'MiniMax-M2.5-highspeed'],
|
||||||
MoonshotAI: ['kimi-k2.5'],
|
MoonshotAI: ['kimi-k2.5'],
|
||||||
'Z.AI': ['glm-5', 'glm-4.7'],
|
'Z.AI': ['glm-5', 'glm-4.7'],
|
||||||
}
|
}
|
||||||
@@ -126,7 +126,7 @@ const pageAgent = new PageAgent({
|
|||||||
const pageAgent = new PageAgent({
|
const pageAgent = new PageAgent({
|
||||||
baseURL: 'https://api.minimax.io/v1',
|
baseURL: 'https://api.minimax.io/v1',
|
||||||
apiKey: 'your-minimax-api-key',
|
apiKey: 'your-minimax-api-key',
|
||||||
model: 'MiniMax-M2.5'
|
model: 'MiniMax-M2.7'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Self-hosted models (e.g., Ollama)
|
// Self-hosted models (e.g., Ollama)
|
||||||
|
|||||||
Reference in New Issue
Block a user