Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 785a2d194e | |||
| 391e70dca4 | |||
| 3ffcd6482d | |||
| 0cd04db40f | |||
| 23f1818503 | |||
| 5fdb49fecb | |||
| fe1893a382 | |||
| 8c1c1ed9fe | |||
| 6cbb4e99c4 | |||
| 34ce56b446 | |||
| 23ec4602c2 | |||
| 536e5076da | |||
| 81807e17ca | |||
| 6944bedf85 | |||
| 897b919044 | |||
| 3a3bb0e58c | |||
| bc7ccf47ff | |||
| c781eba986 | |||
| efe131660a | |||
| 22516dec74 | |||
| 1f8953c450 | |||
| d6a57f3e20 | |||
| e0027f99c4 | |||
| b234868bc1 | |||
| 10ae34a677 | |||
| 2fb01b7315 | |||
| 5c80f2b002 |
+7
-3
@@ -25,11 +25,15 @@ dist-ssr
|
|||||||
*.sw?
|
*.sw?
|
||||||
.qoder
|
.qoder
|
||||||
|
|
||||||
|
# env files
|
||||||
#
|
|
||||||
.env
|
.env
|
||||||
|
.env.*
|
||||||
|
|
||||||
# Copied files for npm publish (generated by prepublishOnly)
|
# Copied files for npm publish (generated by prepublishOnly)
|
||||||
packages/page-agent/README.md
|
packages/page-agent/README.md
|
||||||
packages/page-agent/README-zh.md
|
packages/page-agent/README-zh.md
|
||||||
packages/page-agent/LICENSE
|
packages/page-agent/LICENSE
|
||||||
|
|
||||||
|
# extension
|
||||||
|
.output
|
||||||
|
.wxt
|
||||||
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"recommendations": ["dbaeumer.vscode-eslint", "prettier.prettier-vscode"]
|
"recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
@@ -6,6 +6,7 @@
|
|||||||
"HITL",
|
"HITL",
|
||||||
"innerhtml",
|
"innerhtml",
|
||||||
"llms",
|
"llms",
|
||||||
|
"npmmirror",
|
||||||
"onwarn",
|
"onwarn",
|
||||||
"opensource",
|
"opensource",
|
||||||
"qwen",
|
"qwen",
|
||||||
|
|||||||
@@ -72,28 +72,14 @@ const pageInfo = await this.pageController.getPageInfo()
|
|||||||
3. **LLM Processing**: AI returns action plans (page-agent)
|
3. **LLM Processing**: AI returns action plans (page-agent)
|
||||||
4. **Indexed Operations**: PageAgent calls PageController by element index
|
4. **Indexed Operations**: PageAgent calls PageController by element index
|
||||||
|
|
||||||
### IIFE Builds (`packages/page-agent/dist/iife/`)
|
|
||||||
|
|
||||||
Two IIFE builds for script tag usage:
|
|
||||||
|
|
||||||
| Build | File | Description |
|
|
||||||
| ----- | -------------------- | -------------------------------- |
|
|
||||||
| Demo | `page-agent.demo.js` | Auto-init with built-in test API |
|
|
||||||
| Full | `page-agent.js` | Exposes `PageAgent` class only |
|
|
||||||
|
|
||||||
Demo build supports query params (e.g., `?model=gpt-4&lang=en-US`).
|
|
||||||
|
|
||||||
Build with `npm run build:iife --workspace=page-agent`.
|
|
||||||
|
|
||||||
## Key Files Reference
|
## Key Files Reference
|
||||||
|
|
||||||
### Page Agent (`packages/page-agent/`)
|
### Page Agent (`packages/page-agent/`)
|
||||||
|
|
||||||
| File | Description |
|
| File | Description |
|
||||||
| ------------------------ | -------------------------------------------- |
|
| ------------------ | -------------------------------------------- |
|
||||||
| `src/PageAgent.ts` | ⭐ Main class with UI, extends PageAgentCore |
|
| `src/PageAgent.ts` | ⭐ Main class with UI, extends PageAgentCore |
|
||||||
| `src/entry-iife.ts` | IIFE entry (exposes PageAgent class) |
|
| `src/demo.ts` | IIFE demo entry (auto-init with demo API) |
|
||||||
| `src/entry-iife-demo.ts` | IIFE demo entry (auto-init with demo API) |
|
|
||||||
|
|
||||||
### Core (`packages/core/`)
|
### Core (`packages/core/`)
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -69,10 +69,10 @@ members of the project's leadership.
|
|||||||
|
|
||||||
## Attribution
|
## Attribution
|
||||||
|
|
||||||
This Code of Conduct is adapted from the [Contributor Covenant][https://www.contributor-covenant.org], version 1.4,
|
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 1.4,
|
||||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||||
|
|
||||||
----
|
---
|
||||||
|
|
||||||
> Chinese Version
|
> Chinese Version
|
||||||
> 《阿里巴巴开源行为准则》
|
> 《阿里巴巴开源行为准则》
|
||||||
|
|||||||
+2
-2
@@ -122,13 +122,13 @@ npm start
|
|||||||
- Start and serve a local `iife` script
|
- Start and serve a local `iife` script
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev:iife # Serving IIFE with auto rebuild at http://localhost:5174/page-agent.js
|
npm run dev:demo # Serving IIFE with auto rebuild at http://localhost:5174/page-agent.demo.js
|
||||||
```
|
```
|
||||||
|
|
||||||
- Add a new bookmark
|
- Add a new bookmark
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
javascript:(function(){var s=document.createElement('script');s.src=`http://localhost:5174/page-agent.js?t=${Math.random()}`;s.onload=()=>console.log(%27PageAgent ready!%27);document.head.appendChild(s);})();
|
javascript:(function(){var s=document.createElement('script');s.src=`http://localhost:5174/page-agent.demo.js?t=${Math.random()}`;s.onload=()=>console.log(%27PageAgent ready!%27);document.head.appendChild(s);})();
|
||||||
```
|
```
|
||||||
|
|
||||||
- Click the bookmark on any page to load Page-Agent
|
- Click the bookmark on any page to load Page-Agent
|
||||||
|
|||||||
+16
-18
@@ -20,34 +20,38 @@
|
|||||||
## ✨ Features
|
## ✨ Features
|
||||||
|
|
||||||
- **🎯 轻松集成**
|
- **🎯 轻松集成**
|
||||||
|
- 无需 Python,无需无头浏览器,无需浏览器插件。纯页面内脚本。
|
||||||
- **🔐 端侧运行**
|
- **🔐 端侧运行**
|
||||||
- **🧠 HTML 脱水**
|
- **🧠 HTML 脱水**
|
||||||
- **💬 自然语言接口**
|
- **💬 自然语言接口**
|
||||||
- **🎨 HITL 交互界面**
|
- **🎨 HITL 交互界面**
|
||||||
|
|
||||||
## 🗺️ Roadmap
|
以及 😉
|
||||||
|
|
||||||
👉 [**Roadmap**](https://github.com/alibaba/page-agent/issues/96)
|
- **🧪 实验性的 Chrome 扩展,支持跨页面控制** - `-b feat/ext`
|
||||||
|
|
||||||
|
👉 [**🗺️ Roadmap**](https://github.com/alibaba/page-agent/issues/96)
|
||||||
|
|
||||||
## 🚀 快速开始
|
## 🚀 快速开始
|
||||||
|
|
||||||
### 快速体验 (With Testing LLM)
|
### 一行代码集成
|
||||||
|
|
||||||
最快的体验方式:
|
通过我们免费的 Demo LLM 快速体验 PageAgent:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script
|
<script
|
||||||
src="https://registry.npmmirror.com/@page-agent/cdn/latest/files/dist/page-agent.demo.js"
|
src="https://registry.npmmirror.com/page-agent/1.0.0-beta.5/files/dist/iife/page-agent.demo.js"
|
||||||
crossorigin="true"
|
crossorigin="true"
|
||||||
></script>
|
></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
> ⚠️ **仅用于技术评估。** Demo 模型有速率限制和使用限制,生产环境请使用 NPM 方式。
|
> - **⚠️ 仅用于技术评估。** Demo LLM 有速率和使用限制,可能随时变更。
|
||||||
|
> - **🌷 建议使用自己的 LLM API。**
|
||||||
|
|
||||||
| 镜像 | URL |
|
| 镜像 | URL |
|
||||||
| ------ | ----------------------------------------------------------------------------------- |
|
| ------ | ----------------------------------------------------------------------------------------- |
|
||||||
| Global | https://cdn.jsdelivr.net/npm/page-agent/dist/iife/page-agent.demo.js |
|
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.0.0-beta.5/dist/iife/page-agent.demo.js |
|
||||||
| China | https://registry.npmmirror.com/page-agent/latest/files/dist/iife/page-agent.demo.js |
|
| China | https://registry.npmmirror.com/page-agent/1.0.0-beta.5/files/dist/iife/page-agent.demo.js |
|
||||||
|
|
||||||
### NPM 安装
|
### NPM 安装
|
||||||
|
|
||||||
@@ -86,15 +90,9 @@ packages/
|
|||||||
|
|
||||||
## 🤝 贡献
|
## 🤝 贡献
|
||||||
|
|
||||||
欢迎社区贡献!以下是参与方式:
|
欢迎社区贡献!请参阅 [CONTRIBUTING.md](CONTRIBUTING.md) 了解环境配置和本地开发说明。
|
||||||
|
|
||||||
1. Fork 并 clone。`git clone https://github.com/alibaba/page-agent.git && cd page-agent`
|
请在贡献前阅读[行为准则](CODE_OF_CONDUCT.md)。
|
||||||
2. 安装依赖: `npm install`
|
|
||||||
3. 启动开发: `npm start`
|
|
||||||
|
|
||||||
更多详情请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。
|
|
||||||
|
|
||||||
请在贡献前阅读我们的[行为准则](CODE_OF_CONDUCT.md)。
|
|
||||||
|
|
||||||
## 👏 致谢
|
## 👏 致谢
|
||||||
|
|
||||||
|
|||||||
@@ -19,35 +19,39 @@ The GUI Agent Living in Your Webpage. Control web interfaces with natural langua
|
|||||||
|
|
||||||
## ✨ Features
|
## ✨ Features
|
||||||
|
|
||||||
- **🎯 Easy Integration** - Transform your webpage into an agent with a single script tag.
|
- **🎯 Easy Integration**
|
||||||
|
- No python. No headless browser. No browser extension. Just in-page scripts.
|
||||||
- **🔐 Client-Side Processing**
|
- **🔐 Client-Side Processing**
|
||||||
- **🧠 DOM Extraction**
|
- **🧠 DOM Extraction**
|
||||||
- **💬 Natural Language Interface**
|
- **💬 Natural Language Interface**
|
||||||
- **🎨 UI with Human in the loop**
|
- **🎨 UI with Human in the loop**
|
||||||
|
|
||||||
## 🗺️ Roadmap
|
And 😉
|
||||||
|
|
||||||
👉 [**Roadmap**](https://github.com/alibaba/page-agent/issues/96)
|
- **🧪 `cross-page` control with an experimental chrome extension** - `-b feat/ext`
|
||||||
|
|
||||||
|
👉 [**🗺️ Roadmap**](https://github.com/alibaba/page-agent/issues/96)
|
||||||
|
|
||||||
## 🚀 Quick Start
|
## 🚀 Quick Start
|
||||||
|
|
||||||
### Quick Try (With Testing LLM)
|
### One-line integration
|
||||||
|
|
||||||
Fastest way to try PageAgent:
|
Fastest way to try PageAgent with our free Demo LLM:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script
|
<script
|
||||||
src="https://cdn.jsdelivr.net/npm/page-agent/dist/iife/page-agent.demo.js"
|
src="https://cdn.jsdelivr.net/npm/page-agent@1.0.0-beta.5/dist/iife/page-agent.demo.js"
|
||||||
crossorigin="true"
|
crossorigin="true"
|
||||||
></script>
|
></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
> ⚠️ **For technical evaluation only.** Demo model has rate limits and usage restrictions. Use NPM for production.
|
> - **⚠️ For technical evaluation only.** Demo LLM has rate limits and usage restrictions. May change without notice.
|
||||||
|
> - **🌷 Bring your own LLM API.**
|
||||||
|
|
||||||
| Mirrors | URL |
|
| Mirrors | URL |
|
||||||
| ------- | ----------------------------------------------------------------------------------- |
|
| ------- | ----------------------------------------------------------------------------------------- |
|
||||||
| Global | https://cdn.jsdelivr.net/npm/page-agent/dist/iife/page-agent.demo.js |
|
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.0.0-beta.5/dist/iife/page-agent.demo.js |
|
||||||
| China | https://registry.npmmirror.com/page-agent/latest/files/dist/iife/page-agent.demo.js |
|
| China | https://registry.npmmirror.com/page-agent/1.0.0-beta.5/files/dist/iife/page-agent.demo.js |
|
||||||
|
|
||||||
### NPM Installation
|
### NPM Installation
|
||||||
|
|
||||||
@@ -84,15 +88,9 @@ packages/
|
|||||||
|
|
||||||
## 🤝 Contributing
|
## 🤝 Contributing
|
||||||
|
|
||||||
We welcome contributions from the community! Here's how to get started:
|
We welcome contributions from the community! Follow our instructions in [CONTRIBUTING.md](CONTRIBUTING.md) for environment setup and local development.
|
||||||
|
|
||||||
1. Fork and clone. `git clone https://github.com/alibaba/page-agent.git && cd page-agent`
|
Please read [Code of Conduct](CODE_OF_CONDUCT.md) before contributing.
|
||||||
2. Install dependencies: `npm install`
|
|
||||||
3. Start development: `npm start`
|
|
||||||
|
|
||||||
More details in [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
||||||
|
|
||||||
Please read our [Code of Conduct](CODE_OF_CONDUCT.md) before contributing.
|
|
||||||
|
|
||||||
## 👏 Acknowledgments
|
## 👏 Acknowledgments
|
||||||
|
|
||||||
|
|||||||
Generated
+8207
-8221
File diff suppressed because it is too large
Load Diff
+121
-121
@@ -1,123 +1,123 @@
|
|||||||
{
|
{
|
||||||
"name": "root",
|
"name": "root",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.0-beta.1",
|
"version": "1.0.0-beta.5",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/page-controller",
|
"packages/page-controller",
|
||||||
"packages/ui",
|
"packages/ui",
|
||||||
"packages/llms",
|
"packages/llms",
|
||||||
"packages/core",
|
"packages/core",
|
||||||
"packages/page-agent",
|
"packages/page-agent",
|
||||||
"packages/website"
|
"packages/website"
|
||||||
],
|
],
|
||||||
"description": "AI-powered UI agent for web applications",
|
"description": "AI-powered UI agent for web applications",
|
||||||
"author": "Simon<gaomeng1900>",
|
"author": "Simon<gaomeng1900>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/alibaba/page-agent.git"
|
"url": "https://github.com/alibaba/page-agent.git"
|
||||||
},
|
},
|
||||||
"homepage": "https://alibaba.github.io/page-agent/",
|
"homepage": "https://alibaba.github.io/page-agent/",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.0.0",
|
"node": ">=20.0.0",
|
||||||
"npm": ">=10.0.0"
|
"npm": ">=10.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"cleanup": "rm -rf packages/*/dist",
|
"cleanup": "rm -rf packages/*/dist",
|
||||||
"start": "npm run dev --workspace=@page-agent/website",
|
"start": "npm run dev --workspace=@page-agent/website",
|
||||||
"build:website": "npm run build:website --workspace=@page-agent/website",
|
"build:website": "npm run build:website --workspace=@page-agent/website",
|
||||||
"build:libs": "npm run build --workspaces --if-present",
|
"build:libs": "npm run build --workspaces --if-present",
|
||||||
"build": "npm run build:libs && npm run build:website",
|
"build": "npm run build:libs && npm run build:website",
|
||||||
"dev:iife": "npm run dev:iife --workspace=page-agent",
|
"dev:demo": "npm run dev:demo --workspace=page-agent",
|
||||||
"version": "node scripts/sync-version.js",
|
"version": "node scripts/sync-version.js",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"prepare": "husky"
|
"prepare": "husky"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^20.3.1",
|
"@commitlint/cli": "^20.3.1",
|
||||||
"@commitlint/config-conventional": "^20.3.1",
|
"@commitlint/config-conventional": "^20.3.1",
|
||||||
"@eslint/js": "^9.39.2",
|
"@eslint/js": "^9.39.2",
|
||||||
"@microsoft/api-extractor": "^7.55.2",
|
"@microsoft/api-extractor": "^7.55.2",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
||||||
"@types/node": "^25.0.7",
|
"@types/node": "^25.0.9",
|
||||||
"concurrently": "^9.2.1",
|
"concurrently": "^9.2.1",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"eslint": "^9.39.2",
|
"eslint": "^9.39.2",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-react-dom": "^2.5.7",
|
"eslint-plugin-react-dom": "^2.7.2",
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
"eslint-plugin-react-refresh": "^0.4.26",
|
"eslint-plugin-react-refresh": "^0.4.26",
|
||||||
"eslint-plugin-react-x": "^2.5.7",
|
"eslint-plugin-react-x": "^2.7.2",
|
||||||
"globals": "^17.0.0",
|
"globals": "^17.0.0",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"lint-staged": "^16.2.4",
|
"lint-staged": "^16.2.4",
|
||||||
"prettier": "^3.7.4",
|
"prettier": "^3.8.0",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"typescript-eslint": "^8.53.0",
|
"typescript-eslint": "^8.53.1",
|
||||||
"unplugin-dts": "^1.0.0-beta.6",
|
"unplugin-dts": "^1.0.0-beta.6",
|
||||||
"vite": "^7.3.1",
|
"vite": "^7.3.1",
|
||||||
"vite-plugin-css-injected-by-js": "^3.5.2"
|
"vite-plugin-css-injected-by-js": "^3.5.2"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{js,ts,cjs,cts,mjs,mts}": [
|
"*.{js,ts,cjs,cts,mjs,mts}": [
|
||||||
"npx prettier --write --ignore-unknown",
|
"npx prettier --write --ignore-unknown",
|
||||||
"npx eslint --quiet"
|
"npx eslint --quiet"
|
||||||
],
|
],
|
||||||
"*.{jsx,tsx}": [
|
"*.{jsx,tsx}": [
|
||||||
"npx prettier --write --ignore-unknown",
|
"npx prettier --write --ignore-unknown",
|
||||||
"npx eslint --quiet"
|
"npx eslint --quiet"
|
||||||
],
|
],
|
||||||
"*.css": [
|
"*.css": [
|
||||||
"npx prettier --write --ignore-unknown"
|
"npx prettier --write --ignore-unknown"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"commitlint": {
|
"commitlint": {
|
||||||
"extends": [
|
"extends": [
|
||||||
"@commitlint/config-conventional"
|
"@commitlint/config-conventional"
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"subject-case": [
|
"subject-case": [
|
||||||
0,
|
0,
|
||||||
"never"
|
"never"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"semi": false,
|
"semi": false,
|
||||||
"useTabs": true,
|
"useTabs": true,
|
||||||
"printWidth": 100,
|
"printWidth": 100,
|
||||||
"trailingComma": "es5",
|
"trailingComma": "es5",
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"@trivago/prettier-plugin-sort-imports"
|
"@trivago/prettier-plugin-sort-imports"
|
||||||
],
|
],
|
||||||
"importOrder": [
|
"importOrder": [
|
||||||
"<THIRD_PARTY_MODULES>",
|
"<THIRD_PARTY_MODULES>",
|
||||||
"^(@/).*(?<!css)$",
|
"^(@/).*(?<!css)$",
|
||||||
"^[./].*(?<!css)$",
|
"^[./].*(?<!css)$",
|
||||||
".css$"
|
".css$"
|
||||||
],
|
],
|
||||||
"importOrderSeparation": true,
|
"importOrderSeparation": true,
|
||||||
"importOrderSortSpecifiers": true,
|
"importOrderSortSpecifiers": true,
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": "*.md",
|
"files": "*.md",
|
||||||
"options": {
|
"options": {
|
||||||
"useTabs": false,
|
"useTabs": false,
|
||||||
"tabWidth": 4
|
"tabWidth": 4
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"files": "*.json",
|
"files": "*.json",
|
||||||
"options": {
|
"options": {
|
||||||
"useTabs": false,
|
"useTabs": false,
|
||||||
"tabWidth": 4
|
"tabWidth": 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+49
-49
@@ -1,51 +1,51 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/core",
|
"name": "@page-agent/core",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.0.0-beta.1",
|
"version": "1.0.0-beta.5",
|
||||||
"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",
|
||||||
"types": "./dist/esm/PageAgentCore.d.ts",
|
"types": "./dist/esm/PageAgentCore.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"types": "./dist/esm/PageAgentCore.d.ts",
|
"types": "./dist/esm/PageAgentCore.d.ts",
|
||||||
"import": "./dist/esm/page-agent-core.js",
|
"import": "./dist/esm/page-agent-core.js",
|
||||||
"default": "./dist/esm/page-agent-core.js"
|
"default": "./dist/esm/page-agent-core.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist/"
|
"dist/"
|
||||||
],
|
],
|
||||||
"description": "GUI agent for web applications - add intelligent automation to any webpage with a single script",
|
"description": "GUI agent for web applications - add intelligent automation to any webpage with a single script",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"ai",
|
"ai",
|
||||||
"automation",
|
"automation",
|
||||||
"ui-agent",
|
"ui-agent",
|
||||||
"GUI-agent",
|
"GUI-agent",
|
||||||
"browser-automation",
|
"browser-automation",
|
||||||
"web-agent",
|
"web-agent",
|
||||||
"llm",
|
"llm",
|
||||||
"dom-interaction",
|
"dom-interaction",
|
||||||
"web-automation",
|
"web-automation",
|
||||||
"GUI-simulation"
|
"GUI-simulation"
|
||||||
],
|
],
|
||||||
"author": "Simon<gaomeng1900>",
|
"author": "Simon<gaomeng1900>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/alibaba/page-agent.git"
|
"url": "https://github.com/alibaba/page-agent.git"
|
||||||
},
|
},
|
||||||
"homepage": "https://alibaba.github.io/page-agent/",
|
"homepage": "https://alibaba.github.io/page-agent/",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"dev:iife": "concurrently \"vite build --config vite.iife.config.js --watch\" \"npx serve dist/iife -p 5174\"",
|
"dev:iife": "concurrently \"vite build --config vite.iife.config.js --watch\" \"npx serve dist/iife -p 5174\"",
|
||||||
"prepublishOnly": "node -e \"const fs=require('fs');['README.md','LICENSE'].forEach(f=>fs.copyFileSync('../../'+f,f))\"",
|
"prepublishOnly": "node -e \"const fs=require('fs');['README.md','LICENSE'].forEach(f=>fs.copyFileSync('../../'+f,f))\"",
|
||||||
"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": {
|
||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
"zod": "^4.3.5",
|
"zod": "^4.3.5",
|
||||||
"@page-agent/llms": "1.0.0-beta.1",
|
"@page-agent/llms": "1.0.0-beta.5",
|
||||||
"@page-agent/page-controller": "1.0.0-beta.1"
|
"@page-agent/page-controller": "1.0.0-beta.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (C) 2025 Alibaba Group Holding Limited
|
* Copyright (C) 2025 Alibaba Group Holding Limited
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*/
|
*/
|
||||||
import { LLM, type Tool } from '@page-agent/llms'
|
import { InvokeError, LLM, type Tool } from '@page-agent/llms'
|
||||||
import type { PageController } from '@page-agent/page-controller'
|
import type { PageController } from '@page-agent/page-controller'
|
||||||
import chalk from 'chalk'
|
import chalk from 'chalk'
|
||||||
import zod from 'zod'
|
import zod from 'zod'
|
||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
AgentActivity,
|
AgentActivity,
|
||||||
AgentReflection,
|
AgentReflection,
|
||||||
AgentStatus,
|
AgentStatus,
|
||||||
AgentStep,
|
AgentStepEvent,
|
||||||
ExecutionResult,
|
ExecutionResult,
|
||||||
HistoricalEvent,
|
HistoricalEvent,
|
||||||
MacroToolInput,
|
MacroToolInput,
|
||||||
@@ -26,6 +26,7 @@ import { assert } from './utils/assert'
|
|||||||
|
|
||||||
export { type PageAgentConfig }
|
export { type PageAgentConfig }
|
||||||
export { tool, type PageAgentTool } from './tools'
|
export { tool, type PageAgentTool } from './tools'
|
||||||
|
export type * from './types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AI agent for browser DOM automation.
|
* AI agent for browser DOM automation.
|
||||||
@@ -98,8 +99,7 @@ export class PageAgentCore extends EventTarget {
|
|||||||
this.emitActivity({ type: 'retrying', attempt, maxAttempts })
|
this.emitActivity({ type: 'retrying', attempt, maxAttempts })
|
||||||
// Also push to history for panel rendering
|
// Also push to history for panel rendering
|
||||||
this.history.push({
|
this.history.push({
|
||||||
type: 'error',
|
type: 'retry',
|
||||||
errorType: 'retry',
|
|
||||||
message: `LLM retry attempt ${attempt} of ${maxAttempts}`,
|
message: `LLM retry attempt ${attempt} of ${maxAttempts}`,
|
||||||
attempt,
|
attempt,
|
||||||
maxAttempts,
|
maxAttempts,
|
||||||
@@ -107,14 +107,14 @@ export class PageAgentCore extends EventTarget {
|
|||||||
this.#emitHistoryChange()
|
this.#emitHistoryChange()
|
||||||
})
|
})
|
||||||
this.#llm.addEventListener('error', (e) => {
|
this.#llm.addEventListener('error', (e) => {
|
||||||
const { error } = (e as CustomEvent).detail
|
const error = (e as CustomEvent).detail.error as Error | InvokeError
|
||||||
const message = String(error)
|
const message = String(error)
|
||||||
this.emitActivity({ type: 'error', message })
|
this.emitActivity({ type: 'error', message })
|
||||||
// Also push to history for panel rendering
|
// Also push to history for panel rendering
|
||||||
this.history.push({
|
this.history.push({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
errorType: 'error',
|
|
||||||
message,
|
message,
|
||||||
|
rawResponse: (error as InvokeError).rawResponse,
|
||||||
})
|
})
|
||||||
this.#emitHistoryChange()
|
this.#emitHistoryChange()
|
||||||
})
|
})
|
||||||
@@ -254,7 +254,7 @@ export class PageAgentCore extends EventTarget {
|
|||||||
next_goal: input.next_goal,
|
next_goal: input.next_goal,
|
||||||
}
|
}
|
||||||
const actionName = Object.keys(input.action)[0]
|
const actionName = Object.keys(input.action)[0]
|
||||||
const action: AgentStep['action'] = {
|
const action: AgentStepEvent['action'] = {
|
||||||
name: actionName,
|
name: actionName,
|
||||||
input: input.action[actionName],
|
input: input.action[actionName],
|
||||||
output: output,
|
output: output,
|
||||||
@@ -262,10 +262,12 @@ export class PageAgentCore extends EventTarget {
|
|||||||
|
|
||||||
this.history.push({
|
this.history.push({
|
||||||
type: 'step',
|
type: 'step',
|
||||||
|
stepIndex: step,
|
||||||
reflection,
|
reflection,
|
||||||
action,
|
action,
|
||||||
usage: result.usage,
|
usage: result.usage,
|
||||||
} as AgentStep)
|
rawResponse: result.rawResponse,
|
||||||
|
} as AgentStepEvent)
|
||||||
this.#emitHistoryChange()
|
this.#emitHistoryChange()
|
||||||
|
|
||||||
console.log(chalk.green('Step finished:'), actionName)
|
console.log(chalk.green('Step finished:'), actionName)
|
||||||
|
|||||||
@@ -33,8 +33,9 @@ export interface MacroToolResult {
|
|||||||
/**
|
/**
|
||||||
* A single agent step with reflection and action
|
* A single agent step with reflection and action
|
||||||
*/
|
*/
|
||||||
export interface AgentStep {
|
export interface AgentStepEvent {
|
||||||
type: 'step'
|
type: 'step'
|
||||||
|
stepIndex: number
|
||||||
reflection: Partial<AgentReflection>
|
reflection: Partial<AgentReflection>
|
||||||
action: {
|
action: {
|
||||||
name: string
|
name: string
|
||||||
@@ -48,6 +49,8 @@ export interface AgentStep {
|
|||||||
cachedTokens?: number
|
cachedTokens?: number
|
||||||
reasoningTokens?: number
|
reasoningTokens?: number
|
||||||
}
|
}
|
||||||
|
/** Raw LLM response for debugging */
|
||||||
|
rawResponse?: unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,20 +69,33 @@ export interface UserTakeoverEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error event (retry or error from LLM)
|
* Retry event - LLM call is being retried
|
||||||
*/
|
*/
|
||||||
export interface ErrorEvent {
|
export interface RetryEvent {
|
||||||
type: 'error'
|
type: 'retry'
|
||||||
errorType: 'retry' | 'error'
|
|
||||||
message: string
|
message: string
|
||||||
attempt?: number
|
attempt: number
|
||||||
maxAttempts?: number
|
maxAttempts: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error event - fatal error from LLM or execution
|
||||||
|
*/
|
||||||
|
export interface AgentErrorEvent {
|
||||||
|
type: 'error'
|
||||||
|
message: string
|
||||||
|
rawResponse?: unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Union type for all history events
|
* Union type for all history events
|
||||||
*/
|
*/
|
||||||
export type HistoricalEvent = AgentStep | ObservationEvent | UserTakeoverEvent | ErrorEvent
|
export type HistoricalEvent =
|
||||||
|
| AgentStepEvent
|
||||||
|
| ObservationEvent
|
||||||
|
| UserTakeoverEvent
|
||||||
|
| RetryEvent
|
||||||
|
| AgentErrorEvent
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Agent execution status
|
* Agent execution status
|
||||||
|
|||||||
+41
-41
@@ -1,43 +1,43 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/llms",
|
"name": "@page-agent/llms",
|
||||||
"version": "1.0.0-beta.1",
|
"version": "1.0.0-beta.5",
|
||||||
"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",
|
||||||
"types": "./dist/lib/index.d.ts",
|
"types": "./dist/lib/index.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"types": "./dist/lib/index.d.ts",
|
"types": "./dist/lib/index.d.ts",
|
||||||
"import": "./dist/lib/page-agent-llms.js",
|
"import": "./dist/lib/page-agent-llms.js",
|
||||||
"default": "./dist/lib/page-agent-llms.js"
|
"default": "./dist/lib/page-agent-llms.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist/"
|
"dist/"
|
||||||
],
|
],
|
||||||
"description": "LLM client with reflection-before-action mental model for page-agent",
|
"description": "LLM client with reflection-before-action mental model for page-agent",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"page-agent",
|
"page-agent",
|
||||||
"llm",
|
"llm",
|
||||||
"openai",
|
"openai",
|
||||||
"tool-calling",
|
"tool-calling",
|
||||||
"agent"
|
"agent"
|
||||||
],
|
],
|
||||||
"author": "Simon<gaomeng1900>",
|
"author": "Simon<gaomeng1900>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/alibaba/page-agent.git",
|
"url": "https://github.com/alibaba/page-agent.git",
|
||||||
"directory": "packages/llms"
|
"directory": "packages/llms"
|
||||||
},
|
},
|
||||||
"homepage": "https://alibaba.github.io/page-agent/",
|
"homepage": "https://alibaba.github.io/page-agent/",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"prepublishOnly": "node -e \"const fs=require('fs');['LICENSE'].forEach(f=>fs.copyFileSync('../../'+f,f))\"",
|
"prepublishOnly": "node -e \"const fs=require('fs');['LICENSE'].forEach(f=>fs.copyFileSync('../../'+f,f))\"",
|
||||||
"postpublish": "node -e \"['LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\""
|
"postpublish": "node -e \"['LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\""
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
"zod": "^4.3.5"
|
"zod": "^4.3.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,14 +107,23 @@ export class OpenAIClient implements LLMClient {
|
|||||||
case 'length':
|
case 'length':
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.CONTEXT_LENGTH,
|
InvokeErrorType.CONTEXT_LENGTH,
|
||||||
'Response truncated: max tokens reached'
|
'Response truncated: max tokens reached',
|
||||||
|
undefined,
|
||||||
|
data
|
||||||
)
|
)
|
||||||
case 'content_filter':
|
case 'content_filter':
|
||||||
throw new InvokeError(InvokeErrorType.CONTENT_FILTER, 'Content filtered by safety system')
|
throw new InvokeError(
|
||||||
|
InvokeErrorType.CONTENT_FILTER,
|
||||||
|
'Content filtered by safety system',
|
||||||
|
undefined,
|
||||||
|
data
|
||||||
|
)
|
||||||
default:
|
default:
|
||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.UNKNOWN,
|
InvokeErrorType.UNKNOWN,
|
||||||
`Unexpected finish_reason: ${choice.finish_reason}`
|
`Unexpected finish_reason: ${choice.finish_reason}`,
|
||||||
|
undefined,
|
||||||
|
data
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +137,8 @@ export class OpenAIClient implements LLMClient {
|
|||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.NO_TOOL_CALL,
|
InvokeErrorType.NO_TOOL_CALL,
|
||||||
'No tool call found in response',
|
'No tool call found in response',
|
||||||
normalizedData
|
undefined,
|
||||||
|
data
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +147,8 @@ export class OpenAIClient implements LLMClient {
|
|||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.UNKNOWN,
|
InvokeErrorType.UNKNOWN,
|
||||||
`Tool "${toolCallName}" not found in tools`,
|
`Tool "${toolCallName}" not found in tools`,
|
||||||
normalizedData
|
undefined,
|
||||||
|
data
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +158,8 @@ export class OpenAIClient implements LLMClient {
|
|||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.INVALID_TOOL_ARGS,
|
InvokeErrorType.INVALID_TOOL_ARGS,
|
||||||
'No tool call arguments found',
|
'No tool call arguments found',
|
||||||
normalizedData
|
undefined,
|
||||||
|
data
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +170,8 @@ export class OpenAIClient implements LLMClient {
|
|||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.INVALID_TOOL_ARGS,
|
InvokeErrorType.INVALID_TOOL_ARGS,
|
||||||
'Failed to parse tool arguments as JSON',
|
'Failed to parse tool arguments as JSON',
|
||||||
error
|
error,
|
||||||
|
data
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +182,8 @@ export class OpenAIClient implements LLMClient {
|
|||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.INVALID_TOOL_ARGS,
|
InvokeErrorType.INVALID_TOOL_ARGS,
|
||||||
'Tool arguments validation failed',
|
'Tool arguments validation failed',
|
||||||
validation.error
|
validation.error,
|
||||||
|
data
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const toolInput = validation.data
|
const toolInput = validation.data
|
||||||
@@ -182,7 +196,8 @@ export class OpenAIClient implements LLMClient {
|
|||||||
throw new InvokeError(
|
throw new InvokeError(
|
||||||
InvokeErrorType.TOOL_EXECUTION_ERROR,
|
InvokeErrorType.TOOL_EXECUTION_ERROR,
|
||||||
`Tool execution failed: ${(e as Error).message}`,
|
`Tool execution failed: ${(e as Error).message}`,
|
||||||
e
|
e,
|
||||||
|
data
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,14 +25,18 @@ export class InvokeError extends Error {
|
|||||||
type: InvokeErrorType
|
type: InvokeErrorType
|
||||||
retryable: boolean
|
retryable: boolean
|
||||||
statusCode?: number
|
statusCode?: number
|
||||||
|
/* raw error (provided if this error is caused by another error) */
|
||||||
rawError?: unknown
|
rawError?: unknown
|
||||||
|
/* raw response from the API (provided if this error is caused by an API calling) */
|
||||||
|
rawResponse?: unknown
|
||||||
|
|
||||||
constructor(type: InvokeErrorType, message: string, rawError?: unknown) {
|
constructor(type: InvokeErrorType, message: string, rawError?: unknown, rawResponse?: unknown) {
|
||||||
super(message)
|
super(message)
|
||||||
this.name = 'InvokeError'
|
this.name = 'InvokeError'
|
||||||
this.type = type
|
this.type = type
|
||||||
this.retryable = this.isRetryable(type)
|
this.retryable = this.isRetryable(type)
|
||||||
this.rawError = rawError
|
this.rawError = rawError
|
||||||
|
this.rawResponse = rawResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
private isRetryable(type: InvokeErrorType): boolean {
|
private isRetryable(type: InvokeErrorType): boolean {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { DEFAULT_TEMPERATURE, LLM_MAX_RETRIES } from './constants'
|
|||||||
import { InvokeError } from './errors'
|
import { InvokeError } from './errors'
|
||||||
import type { InvokeOptions, InvokeResult, LLMClient, LLMConfig, Message, Tool } from './types'
|
import type { InvokeOptions, InvokeResult, LLMClient, LLMConfig, Message, Tool } from './types'
|
||||||
|
|
||||||
export type { InvokeOptions, InvokeResult, LLMClient, LLMConfig, Message, Tool }
|
export type { InvokeError, InvokeOptions, InvokeResult, LLMClient, LLMConfig, Message, Tool }
|
||||||
|
|
||||||
export function parseLLMConfig(config: LLMConfig): Required<LLMConfig> {
|
export function parseLLMConfig(config: LLMConfig): Required<LLMConfig> {
|
||||||
// Runtime validation as defensive programming (types already guarantee these)
|
// Runtime validation as defensive programming (types already guarantee these)
|
||||||
|
|||||||
@@ -1,54 +1,54 @@
|
|||||||
{
|
{
|
||||||
"name": "page-agent",
|
"name": "page-agent",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.0.0-beta.1",
|
"version": "1.0.0-beta.5",
|
||||||
"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",
|
||||||
"types": "./dist/esm/PageAgent.d.ts",
|
"types": "./dist/esm/PageAgent.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"types": "./dist/esm/PageAgent.d.ts",
|
"types": "./dist/esm/PageAgent.d.ts",
|
||||||
"import": "./dist/esm/page-agent.js",
|
"import": "./dist/esm/page-agent.js",
|
||||||
"default": "./dist/esm/page-agent.js"
|
"default": "./dist/esm/page-agent.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist/"
|
"dist/"
|
||||||
],
|
],
|
||||||
"description": "GUI agent for web applications - add intelligent automation to any webpage with a single script",
|
"description": "GUI agent for web applications - add intelligent automation to any webpage with a single script",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"ai",
|
"ai",
|
||||||
"automation",
|
"automation",
|
||||||
"ui-agent",
|
"ui-agent",
|
||||||
"GUI-agent",
|
"GUI-agent",
|
||||||
"browser-automation",
|
"browser-automation",
|
||||||
"web-agent",
|
"web-agent",
|
||||||
"llm",
|
"llm",
|
||||||
"dom-interaction",
|
"dom-interaction",
|
||||||
"web-automation",
|
"web-automation",
|
||||||
"GUI-simulation"
|
"GUI-simulation"
|
||||||
],
|
],
|
||||||
"author": "Simon<gaomeng1900>",
|
"author": "Simon<gaomeng1900>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/alibaba/page-agent.git"
|
"url": "https://github.com/alibaba/page-agent.git"
|
||||||
},
|
},
|
||||||
"homepage": "https://alibaba.github.io/page-agent/",
|
"homepage": "https://alibaba.github.io/page-agent/",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build && npm run build:demo",
|
"build": "vite build && npm run build:demo",
|
||||||
"build:demo": "vite build --config vite.iife.config.js",
|
"build:demo": "vite build --config vite.iife.config.js",
|
||||||
"dev:demo": "concurrently \"vite build --config vite.iife.config.js --watch\" \"npx serve dist/iife -p 5174\"",
|
"dev:demo": "concurrently \"vite build --config vite.iife.config.js --watch\" \"npx serve dist/iife -p 5174\"",
|
||||||
"prepublishOnly": "node -e \"const fs=require('fs');['README.md','LICENSE'].forEach(f=>fs.copyFileSync('../../'+f,f))\"",
|
"prepublishOnly": "node -e \"const fs=require('fs');['README.md','LICENSE'].forEach(f=>fs.copyFileSync('../../'+f,f))\"",
|
||||||
"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": {
|
||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
"zod": "^4.3.5",
|
"zod": "^4.3.5",
|
||||||
"@page-agent/llms": "1.0.0-beta.1",
|
"@page-agent/llms": "1.0.0-beta.5",
|
||||||
"@page-agent/page-controller": "1.0.0-beta.1",
|
"@page-agent/page-controller": "1.0.0-beta.5",
|
||||||
"@page-agent/core": "1.0.0-beta.1",
|
"@page-agent/core": "1.0.0-beta.5",
|
||||||
"@page-agent/ui": "1.0.0-beta.1"
|
"@page-agent/ui": "1.0.0-beta.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ setTimeout(() => {
|
|||||||
|
|
||||||
// Create agent
|
// Create agent
|
||||||
window.pageAgent = new PageAgent(config)
|
window.pageAgent = new PageAgent(config)
|
||||||
|
window.pageAgent.panel.show()
|
||||||
|
|
||||||
console.log('🚀 page-agent.js initialized with config:', window.pageAgent.config)
|
console.log('🚀 page-agent.js initialized with config:', window.pageAgent.config)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/page-controller",
|
"name": "@page-agent/page-controller",
|
||||||
"version": "1.0.0-beta.1",
|
"version": "1.0.0-beta.5",
|
||||||
"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",
|
||||||
"types": "./dist/lib/PageController.d.ts",
|
"types": "./dist/lib/PageController.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"types": "./dist/lib/PageController.d.ts",
|
"types": "./dist/lib/PageController.d.ts",
|
||||||
"import": "./dist/lib/page-controller.js",
|
"import": "./dist/lib/page-controller.js",
|
||||||
"default": "./dist/lib/page-controller.js"
|
"default": "./dist/lib/page-controller.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist/"
|
"dist/"
|
||||||
],
|
],
|
||||||
"description": "Page controller for page-agent - DOM operations and element interactions",
|
"description": "Page controller for page-agent - DOM operations and element interactions",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"page-agent",
|
"page-agent",
|
||||||
"dom",
|
"dom",
|
||||||
"browser-automation",
|
"browser-automation",
|
||||||
"web-automation"
|
"web-automation"
|
||||||
],
|
],
|
||||||
"author": "Simon<gaomeng1900>",
|
"author": "Simon<gaomeng1900>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/alibaba/page-agent.git",
|
"url": "https://github.com/alibaba/page-agent.git",
|
||||||
"directory": "packages/page-controller"
|
"directory": "packages/page-controller"
|
||||||
},
|
},
|
||||||
"homepage": "https://alibaba.github.io/page-agent/",
|
"homepage": "https://alibaba.github.io/page-agent/",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"prepublishOnly": "node -e \"const fs=require('fs');['LICENSE'].forEach(f=>fs.copyFileSync('../../'+f,f))\"",
|
"prepublishOnly": "node -e \"const fs=require('fs');['LICENSE'].forEach(f=>fs.copyFileSync('../../'+f,f))\"",
|
||||||
"postpublish": "node -e \"['LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\""
|
"postpublish": "node -e \"['LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\""
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ai-motion": "^0.4.8"
|
"ai-motion": "^0.4.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ export class PageController extends EventTarget {
|
|||||||
/** last time the tree was updated */
|
/** last time the tree was updated */
|
||||||
private lastTimeUpdate = 0
|
private lastTimeUpdate = 0
|
||||||
|
|
||||||
|
/** Whether the tree has been indexed at least once */
|
||||||
|
private isIndexed = false
|
||||||
|
|
||||||
/** Visual mask overlay for blocking user interaction during automation */
|
/** Visual mask overlay for blocking user interaction during automation */
|
||||||
private mask: InstanceType<typeof import('./mask/SimulatorMask').SimulatorMask> | null = null
|
private mask: InstanceType<typeof import('./mask/SimulatorMask').SimulatorMask> | null = null
|
||||||
private maskReady: Promise<void> | null = null
|
private maskReady: Promise<void> | null = null
|
||||||
@@ -196,6 +199,9 @@ export class PageController extends EventTarget {
|
|||||||
this.elementTextMap.clear()
|
this.elementTextMap.clear()
|
||||||
this.elementTextMap = dom.getElementTextMap(this.simplifiedHTML)
|
this.elementTextMap = dom.getElementTextMap(this.simplifiedHTML)
|
||||||
|
|
||||||
|
// Mark as indexed - now element actions are allowed
|
||||||
|
this.isIndexed = true
|
||||||
|
|
||||||
// Restore mask blocking
|
// Restore mask blocking
|
||||||
if (this.mask) {
|
if (this.mask) {
|
||||||
this.mask.wrapper.style.pointerEvents = 'auto'
|
this.mask.wrapper.style.pointerEvents = 'auto'
|
||||||
@@ -215,11 +221,22 @@ export class PageController extends EventTarget {
|
|||||||
|
|
||||||
// ======= Element Actions =======
|
// ======= Element Actions =======
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure the tree has been indexed before any index-based operation.
|
||||||
|
* Throws if updateTree() hasn't been called yet.
|
||||||
|
*/
|
||||||
|
private assertIndexed(): void {
|
||||||
|
if (!this.isIndexed) {
|
||||||
|
throw new Error('DOM tree not indexed. Can not perform actions on elements.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Click element by index
|
* Click element by index
|
||||||
*/
|
*/
|
||||||
async clickElement(index: number): Promise<ActionResult> {
|
async clickElement(index: number): Promise<ActionResult> {
|
||||||
try {
|
try {
|
||||||
|
this.assertIndexed()
|
||||||
const element = getElementByIndex(this.selectorMap, index)
|
const element = getElementByIndex(this.selectorMap, index)
|
||||||
const elemText = this.elementTextMap.get(index)
|
const elemText = this.elementTextMap.get(index)
|
||||||
await clickElement(element)
|
await clickElement(element)
|
||||||
@@ -249,6 +266,7 @@ export class PageController extends EventTarget {
|
|||||||
*/
|
*/
|
||||||
async inputText(index: number, text: string): Promise<ActionResult> {
|
async inputText(index: number, text: string): Promise<ActionResult> {
|
||||||
try {
|
try {
|
||||||
|
this.assertIndexed()
|
||||||
const element = getElementByIndex(this.selectorMap, index)
|
const element = getElementByIndex(this.selectorMap, index)
|
||||||
const elemText = this.elementTextMap.get(index)
|
const elemText = this.elementTextMap.get(index)
|
||||||
await inputTextElement(element, text)
|
await inputTextElement(element, text)
|
||||||
@@ -270,6 +288,7 @@ export class PageController extends EventTarget {
|
|||||||
*/
|
*/
|
||||||
async selectOption(index: number, optionText: string): Promise<ActionResult> {
|
async selectOption(index: number, optionText: string): Promise<ActionResult> {
|
||||||
try {
|
try {
|
||||||
|
this.assertIndexed()
|
||||||
const element = getElementByIndex(this.selectorMap, index)
|
const element = getElementByIndex(this.selectorMap, index)
|
||||||
const elemText = this.elementTextMap.get(index)
|
const elemText = this.elementTextMap.get(index)
|
||||||
await selectOptionElement(element as HTMLSelectElement, optionText)
|
await selectOptionElement(element as HTMLSelectElement, optionText)
|
||||||
@@ -298,6 +317,8 @@ export class PageController extends EventTarget {
|
|||||||
try {
|
try {
|
||||||
const { down, numPages, pixels, index } = options
|
const { down, numPages, pixels, index } = options
|
||||||
|
|
||||||
|
this.assertIndexed()
|
||||||
|
|
||||||
const scrollAmount = pixels ?? numPages * (down ? 1 : -1) * window.innerHeight
|
const scrollAmount = pixels ?? numPages * (down ? 1 : -1) * window.innerHeight
|
||||||
|
|
||||||
const element = index !== undefined ? getElementByIndex(this.selectorMap, index) : null
|
const element = index !== undefined ? getElementByIndex(this.selectorMap, index) : null
|
||||||
@@ -327,6 +348,8 @@ export class PageController extends EventTarget {
|
|||||||
try {
|
try {
|
||||||
const { right, pixels, index } = options
|
const { right, pixels, index } = options
|
||||||
|
|
||||||
|
this.assertIndexed()
|
||||||
|
|
||||||
const scrollAmount = pixels * (right ? 1 : -1)
|
const scrollAmount = pixels * (right ? 1 : -1)
|
||||||
|
|
||||||
const element = index !== undefined ? getElementByIndex(this.selectorMap, index) : null
|
const element = index !== undefined ? getElementByIndex(this.selectorMap, index) : null
|
||||||
@@ -394,6 +417,7 @@ export class PageController extends EventTarget {
|
|||||||
this.selectorMap.clear()
|
this.selectorMap.clear()
|
||||||
this.elementTextMap.clear()
|
this.elementTextMap.clear()
|
||||||
this.simplifiedHTML = '<EMPTY>'
|
this.simplifiedHTML = '<EMPTY>'
|
||||||
|
this.isIndexed = false
|
||||||
this.mask?.dispose()
|
this.mask?.dispose()
|
||||||
this.mask = null
|
this.mask = null
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-36
@@ -1,38 +1,38 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/ui",
|
"name": "@page-agent/ui",
|
||||||
"version": "1.0.0-beta.1",
|
"version": "1.0.0-beta.5",
|
||||||
"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",
|
||||||
"types": "./dist/lib/index.d.ts",
|
"types": "./dist/lib/index.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"types": "./dist/lib/index.d.ts",
|
"types": "./dist/lib/index.d.ts",
|
||||||
"import": "./dist/lib/page-agent-ui.js",
|
"import": "./dist/lib/page-agent-ui.js",
|
||||||
"default": "./dist/lib/page-agent-ui.js"
|
"default": "./dist/lib/page-agent-ui.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist/"
|
"dist/"
|
||||||
],
|
],
|
||||||
"description": "UI components for page-agent - Panel and i18n",
|
"description": "UI components for page-agent - Panel and i18n",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"page-agent",
|
"page-agent",
|
||||||
"ui",
|
"ui",
|
||||||
"panel",
|
"panel",
|
||||||
"i18n"
|
"i18n"
|
||||||
],
|
],
|
||||||
"author": "Simon<gaomeng1900>",
|
"author": "Simon<gaomeng1900>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/alibaba/page-agent.git",
|
"url": "https://github.com/alibaba/page-agent.git",
|
||||||
"directory": "packages/ui"
|
"directory": "packages/ui"
|
||||||
},
|
},
|
||||||
"homepage": "https://alibaba.github.io/page-agent/",
|
"homepage": "https://alibaba.github.io/page-agent/",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"prepublishOnly": "node -e \"const fs=require('fs');['LICENSE'].forEach(f=>fs.copyFileSync('../../'+f,f))\"",
|
"prepublishOnly": "node -e \"const fs=require('fs');['LICENSE'].forEach(f=>fs.copyFileSync('../../'+f,f))\"",
|
||||||
"postpublish": "node -e \"['LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\""
|
"postpublish": "node -e \"['LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -563,9 +563,8 @@ export class Panel {
|
|||||||
|
|
||||||
// 2. Render each history event
|
// 2. Render each history event
|
||||||
const history = this.#agent.history
|
const history = this.#agent.history
|
||||||
for (let i = 0; i < history.length; i++) {
|
for (const event of history) {
|
||||||
const event = history[i]
|
items.push(...this.#createHistoryCards(event))
|
||||||
items.push(...this.#createHistoryCards(event, i + 1))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#historySection.innerHTML = items.join('')
|
this.#historySection.innerHTML = items.join('')
|
||||||
@@ -577,14 +576,17 @@ export class Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Create cards for a history event */
|
/** Create cards for a history event */
|
||||||
#createHistoryCards(event: PanelAgentAdapter['history'][number], stepNumber: number): string[] {
|
#createHistoryCards(event: PanelAgentAdapter['history'][number]): string[] {
|
||||||
const cards: string[] = []
|
const cards: string[] = []
|
||||||
const time = formatTime(this.#config.language ?? 'en-US')
|
const time = formatTime(this.#config.language ?? 'en-US')
|
||||||
const meta = this.#i18n.t('ui.panel.step', {
|
const meta =
|
||||||
number: stepNumber.toString(),
|
event.type === 'step' && event.stepIndex !== undefined
|
||||||
time,
|
? this.#i18n.t('ui.panel.step', {
|
||||||
duration: '',
|
number: (event.stepIndex + 1).toString(),
|
||||||
})
|
time,
|
||||||
|
duration: '',
|
||||||
|
})
|
||||||
|
: time
|
||||||
|
|
||||||
if (event.type === 'step') {
|
if (event.type === 'step') {
|
||||||
// Reflection card
|
// Reflection card
|
||||||
@@ -606,6 +608,13 @@ export class Panel {
|
|||||||
)
|
)
|
||||||
} else if (event.type === 'user_takeover') {
|
} else if (event.type === 'user_takeover') {
|
||||||
cards.push(createCard({ icon: '👤', content: 'User takeover', meta, type: 'input' }))
|
cards.push(createCard({ icon: '👤', content: 'User takeover', meta, type: 'input' }))
|
||||||
|
} else if (event.type === 'retry') {
|
||||||
|
const retryInfo = `${event.message || 'Retrying'} (${event.attempt}/${event.maxAttempts})`
|
||||||
|
cards.push(createCard({ icon: '🔄', content: retryInfo, meta, type: 'observation' }))
|
||||||
|
} else if (event.type === 'error') {
|
||||||
|
cards.push(
|
||||||
|
createCard({ icon: '❌', content: event.message || 'Error', meta, type: 'observation' })
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cards
|
return cards
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ export interface PanelAgentAdapter extends EventTarget {
|
|||||||
|
|
||||||
/** History of agent events */
|
/** History of agent events */
|
||||||
readonly history: readonly {
|
readonly history: readonly {
|
||||||
type: 'step' | 'observation' | 'user_takeover' | 'error'
|
type: 'step' | 'observation' | 'user_takeover' | 'retry' | 'error'
|
||||||
|
stepIndex?: number
|
||||||
/** For 'step' type */
|
/** For 'step' type */
|
||||||
reflection?: {
|
reflection?: {
|
||||||
evaluation_previous_goal?: string
|
evaluation_previous_goal?: string
|
||||||
@@ -48,6 +49,11 @@ export interface PanelAgentAdapter extends EventTarget {
|
|||||||
}
|
}
|
||||||
/** For 'observation' type */
|
/** For 'observation' type */
|
||||||
content?: string
|
content?: string
|
||||||
|
/** For 'retry' type */
|
||||||
|
attempt?: number
|
||||||
|
maxAttempts?: number
|
||||||
|
/** For 'retry' and 'error' types */
|
||||||
|
message?: string
|
||||||
}[]
|
}[]
|
||||||
|
|
||||||
/** Current task being executed */
|
/** Current task being executed */
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
{
|
{
|
||||||
"name": "@page-agent/website",
|
"name": "@page-agent/website",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.0-beta.1",
|
"version": "1.0.0-beta.5",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host 0.0.0.0",
|
"dev": "vite --host 0.0.0.0",
|
||||||
"build:website": "vite build",
|
"build:website": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"typecheck": "tsc --noEmit"
|
"typecheck": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.1.18",
|
||||||
"@types/react": "^19.2.8",
|
"@types/react": "^19.2.8",
|
||||||
"@types/react-dom": "^19.2.1",
|
"@types/react-dom": "^19.2.1",
|
||||||
"@vitejs/plugin-react-swc": "^4.1.0",
|
"@vitejs/plugin-react-swc": "^4.1.0",
|
||||||
"i18next": "^25.7.4",
|
"i18next": "^25.7.4",
|
||||||
"i18next-browser-languagedetector": "^8.2.0",
|
"i18next-browser-languagedetector": "^8.2.0",
|
||||||
"react": "^19.2.3",
|
"react": "^19.2.3",
|
||||||
"react-dom": "^19.2.3",
|
"react-dom": "^19.2.3",
|
||||||
"react-i18next": "^16.5.2",
|
"react-i18next": "^16.5.3",
|
||||||
"tailwindcss": "^4.1.14",
|
"tailwindcss": "^4.1.14",
|
||||||
"tw-animate-css": "^1.4.0",
|
"tw-animate-css": "^1.4.0",
|
||||||
"wouter": "^3.9.0"
|
"wouter": "^3.9.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@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",
|
||||||
"@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",
|
"@radix-ui/react-tooltip": "^1.2.8",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"lucide-react": "^0.562.0",
|
"lucide-react": "^0.562.0",
|
||||||
"motion": "^12.26.1",
|
"motion": "^12.27.1",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"rough-notation": "^0.5.1",
|
"rough-notation": "^0.5.1",
|
||||||
"simple-icons": "^16.5.0",
|
"simple-icons": "^16.6.0",
|
||||||
"sonner": "^2.0.7",
|
"sonner": "^2.0.7",
|
||||||
"tailwind-merge": "^3.4.0"
|
"tailwind-merge": "^3.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +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 = 'https://cdn.jsdelivr.net/npm/page-agent/dist/iife/page-agent.demo.js'
|
export const CDN_DEMO_URL =
|
||||||
|
'https://cdn.jsdelivr.net/npm/page-agent@1.0.0-beta.5/dist/iife/page-agent.demo.js'
|
||||||
export const CDN_DEMO_CN_URL =
|
export const CDN_DEMO_CN_URL =
|
||||||
'https://registry.npmmirror.com/page-agent/latest/files/dist/iife/page-agent.demo.js'
|
'https://registry.npmmirror.com/page-agent/1.0.0-beta.5/files/dist/iife/page-agent.demo.js'
|
||||||
|
|
||||||
// Demo LLM for website testing
|
// Demo LLM for website testing
|
||||||
export const DEMO_MODEL = 'PAGE-AGENT-FREE-TESTING-RANDOM'
|
export const DEMO_MODEL = 'PAGE-AGENT-FREE-TESTING-RANDOM'
|
||||||
|
|||||||
+36
-5
@@ -9,6 +9,7 @@
|
|||||||
import chalk from 'chalk'
|
import chalk from 'chalk'
|
||||||
import { existsSync, readFileSync, readdirSync, writeFileSync } from 'fs'
|
import { existsSync, readFileSync, readdirSync, writeFileSync } from 'fs'
|
||||||
import { dirname, join } from 'path'
|
import { dirname, join } from 'path'
|
||||||
|
import { exit } from 'process'
|
||||||
import { fileURLToPath } from 'url'
|
import { fileURLToPath } from 'url'
|
||||||
|
|
||||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||||
@@ -17,17 +18,23 @@ const rootDir = join(__dirname, '..')
|
|||||||
// Parse arguments
|
// Parse arguments
|
||||||
const versionArg = process.argv[2]
|
const versionArg = process.argv[2]
|
||||||
|
|
||||||
|
if (!versionArg) {
|
||||||
|
console.log(chalk.yellow('⚠️ No version specified.\n'))
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
// Read root package.json
|
// Read root package.json
|
||||||
const rootPkgPath = join(rootDir, 'package.json')
|
const rootPkgPath = join(rootDir, 'package.json')
|
||||||
const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf-8'))
|
const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf-8'))
|
||||||
const newVersion = versionArg || rootPkg.version
|
const oldVersion = rootPkg.version
|
||||||
|
const newVersion = versionArg
|
||||||
|
|
||||||
console.log(chalk.cyan.bold('\n📦 Syncing version\n'))
|
console.log(chalk.cyan.bold('\n📦 Syncing version\n'))
|
||||||
|
|
||||||
// Update root package.json if new version specified
|
// Update root package.json if new version specified
|
||||||
if (versionArg) {
|
if (versionArg) {
|
||||||
rootPkg.version = newVersion
|
rootPkg.version = newVersion
|
||||||
writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, '\t') + '\n')
|
writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, ' ') + '\n')
|
||||||
console.log(chalk.green('✓') + ` ${chalk.bold('root')} → ${chalk.yellow(newVersion)}`)
|
console.log(chalk.green('✓') + ` ${chalk.bold('root')} → ${chalk.yellow(newVersion)}`)
|
||||||
} else {
|
} else {
|
||||||
console.log(chalk.dim(' root:') + ` ${chalk.yellow(newVersion)} ${chalk.dim('(source)')}`)
|
console.log(chalk.dim(' root:') + ` ${chalk.yellow(newVersion)} ${chalk.dim('(source)')}`)
|
||||||
@@ -69,11 +76,10 @@ for (const pkg of packages) {
|
|||||||
if (!existsSync(pkgPath)) continue
|
if (!existsSync(pkgPath)) continue
|
||||||
|
|
||||||
const pkgJson = JSON.parse(readFileSync(pkgPath, 'utf-8'))
|
const pkgJson = JSON.parse(readFileSync(pkgPath, 'utf-8'))
|
||||||
const oldVersion = pkgJson.version
|
|
||||||
let pkgChanged = false
|
let pkgChanged = false
|
||||||
|
|
||||||
// Update package version
|
// Update package version
|
||||||
if (oldVersion !== newVersion) {
|
if (pkgJson.version !== newVersion) {
|
||||||
pkgJson.version = newVersion
|
pkgJson.version = newVersion
|
||||||
pkgChanged = true
|
pkgChanged = true
|
||||||
}
|
}
|
||||||
@@ -88,7 +94,7 @@ for (const pkg of packages) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFileSync(pkgPath, JSON.stringify(pkgJson, null, '\t') + '\n')
|
writeFileSync(pkgPath, JSON.stringify(pkgJson, null, ' ') + '\n')
|
||||||
console.log(
|
console.log(
|
||||||
chalk.green('✓') +
|
chalk.green('✓') +
|
||||||
` ${chalk.bold(pkgJson.name)}: ${chalk.dim(oldVersion)} → ${chalk.yellow(newVersion)}`
|
` ${chalk.bold(pkgJson.name)}: ${chalk.dim(oldVersion)} → ${chalk.yellow(newVersion)}`
|
||||||
@@ -96,6 +102,31 @@ for (const pkg of packages) {
|
|||||||
hasChanges = true
|
hasChanges = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update CDN URLs in documentation and source files
|
||||||
|
const CDN_DEMO_URL_OLD = `https://cdn.jsdelivr.net/npm/page-agent@${oldVersion}/dist/iife/page-agent.demo.js`
|
||||||
|
const CDN_DEMO_URL_NEW = `https://cdn.jsdelivr.net/npm/page-agent@${newVersion}/dist/iife/page-agent.demo.js`
|
||||||
|
const CDN_DEMO_CN_URL_OLD = `https://registry.npmmirror.com/page-agent/${oldVersion}/files/dist/iife/page-agent.demo.js`
|
||||||
|
const CDN_DEMO_CN_URL_NEW = `https://registry.npmmirror.com/page-agent/${newVersion}/files/dist/iife/page-agent.demo.js`
|
||||||
|
|
||||||
|
const filesToUpdateCdn = ['README.md', 'README-zh.md', 'packages/website/src/constants.ts']
|
||||||
|
|
||||||
|
for (const relPath of filesToUpdateCdn) {
|
||||||
|
const filePath = join(rootDir, relPath)
|
||||||
|
if (!existsSync(filePath)) continue
|
||||||
|
|
||||||
|
let content = readFileSync(filePath, 'utf-8')
|
||||||
|
const original = content
|
||||||
|
|
||||||
|
content = content.replaceAll(CDN_DEMO_URL_OLD, CDN_DEMO_URL_NEW)
|
||||||
|
content = content.replaceAll(CDN_DEMO_CN_URL_OLD, CDN_DEMO_CN_URL_NEW)
|
||||||
|
|
||||||
|
if (content !== original) {
|
||||||
|
writeFileSync(filePath, content)
|
||||||
|
console.log(chalk.green('✓') + ` ${chalk.bold(relPath)}: CDN URLs updated`)
|
||||||
|
hasChanges = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log(chalk.green.bold(`\n✓ Version synced: ${newVersion}\n`))
|
console.log(chalk.green.bold(`\n✓ Version synced: ${newVersion}\n`))
|
||||||
|
|
||||||
// Show git commands hint
|
// Show git commands hint
|
||||||
|
|||||||
Reference in New Issue
Block a user