Compare commits

..

50 Commits

Author SHA1 Message Date
Simon 2ad2d06d01 chore(version): bump version to 1.8.0 2026-04-15 03:11:14 +08:00
Simon 8bf7abfe76 chore: wxt version 2026-04-15 03:09:15 +08:00
Simon 099a1251cd Merge branch 'main' of https://github.com/alibaba/page-agent 2026-04-14 15:54:25 +08:00
Simon 354397a1b4 Merge pull request #449 from alibaba/dependabot/npm_and_yarn/development-dependencies-d34cd256e0
chore(deps-dev): bump the development-dependencies group with 11 updates
2026-04-14 15:53:22 +08:00
Simon a1d9e11c05 Merge pull request #448 from alibaba/dependabot/github_actions/github-actions-903567a242
chore(deps): bump actions/upload-pages-artifact from 4 to 5 in the github-actions group
2026-04-14 15:52:48 +08:00
Simon 33538cca05 chore(dependabot): set labels 2026-04-14 15:51:55 +08:00
Simon 50f4866142 Merge pull request #447 from alibaba/fix/iife-keepnames-redeclaration
fix(vite): remove global helper functions in built assets
2026-04-14 15:45:47 +08:00
dependabot[bot] 28a2ebb817 chore(deps-dev): bump the development-dependencies group with 11 updates
Bumps the development-dependencies group with 11 updates:

| Package | From | To |
| --- | --- | --- |
| [@microsoft/api-extractor](https://github.com/microsoft/rushstack/tree/HEAD/apps/api-extractor) | `7.58.1` | `7.58.2` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `25.5.2` | `25.6.0` |
| [dotenv](https://github.com/motdotla/dotenv) | `17.4.1` | `17.4.2` |
| [globals](https://github.com/sindresorhus/globals) | `17.4.0` | `17.5.0` |
| [prettier](https://github.com/prettier/prettier) | `3.8.1` | `3.8.2` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.58.1` | `8.58.2` |
| [@types/chrome](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/chrome) | `0.1.39` | `0.1.40` |
| [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `1.7.0` | `1.8.0` |
| [react](https://github.com/facebook/react/tree/HEAD/packages/react) | `19.2.4` | `19.2.5` |
| [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom) | `19.2.4` | `19.2.5` |
| [simple-icons](https://github.com/simple-icons/simple-icons) | `16.15.0` | `16.16.0` |


Updates `@microsoft/api-extractor` from 7.58.1 to 7.58.2
- [Changelog](https://github.com/microsoft/rushstack/blob/main/apps/api-extractor/CHANGELOG.md)
- [Commits](https://github.com/microsoft/rushstack/commits/@microsoft/api-extractor_v7.58.2/apps/api-extractor)

Updates `@types/node` from 25.5.2 to 25.6.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `dotenv` from 17.4.1 to 17.4.2
- [Changelog](https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md)
- [Commits](https://github.com/motdotla/dotenv/compare/v17.4.1...v17.4.2)

Updates `globals` from 17.4.0 to 17.5.0
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v17.4.0...v17.5.0)

Updates `prettier` from 3.8.1 to 3.8.2
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.8.1...3.8.2)

Updates `typescript-eslint` from 8.58.1 to 8.58.2
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.2/packages/typescript-eslint)

Updates `@types/chrome` from 0.1.39 to 0.1.40
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/chrome)

Updates `lucide-react` from 1.7.0 to 1.8.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.8.0/packages/lucide-react)

Updates `react` from 19.2.4 to 19.2.5
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.5/packages/react)

Updates `react-dom` from 19.2.4 to 19.2.5
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.5/packages/react-dom)

Updates `simple-icons` from 16.15.0 to 16.16.0
- [Release notes](https://github.com/simple-icons/simple-icons/releases)
- [Commits](https://github.com/simple-icons/simple-icons/compare/16.15.0...16.16.0)

---
updated-dependencies:
- dependency-name: "@microsoft/api-extractor"
  dependency-version: 7.58.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: "@types/node"
  dependency-version: 25.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: dotenv
  dependency-version: 17.4.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: globals
  dependency-version: 17.5.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: prettier
  dependency-version: 3.8.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: typescript-eslint
  dependency-version: 8.58.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: "@types/chrome"
  dependency-version: 0.1.40
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: lucide-react
  dependency-version: 1.8.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: react
  dependency-version: 19.2.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: react-dom
  dependency-version: 19.2.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
- dependency-name: simple-icons
  dependency-version: 16.16.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-13 20:13:25 +00:00
dependabot[bot] 7a08022c72 chore(deps): bump actions/upload-pages-artifact
Bumps the github-actions group with 1 update: [actions/upload-pages-artifact](https://github.com/actions/upload-pages-artifact).


Updates `actions/upload-pages-artifact` from 4 to 5
- [Release notes](https://github.com/actions/upload-pages-artifact/releases)
- [Commits](https://github.com/actions/upload-pages-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-pages-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-13 20:10:33 +00:00
Simon 78c829d955 fix: global helper functions redeclaration 2026-04-14 02:57:13 +08:00
Simon 5008345ce8 Merge pull request #425 from XePope/fix/autofixer-wait-fallback-format
fix(core): correct autoFixer wait fallback action format
2026-04-13 20:33:08 +08:00
Simon a1b7684bf2 Merge pull request #418 from lgy2020/fix/simulator-mask-raf-leak
fix(mask): dispose 后 requestAnimationFrame 循环未停止导致内存泄漏
2026-04-13 20:14:32 +08:00
Simon da67f3b07e chore(controller): .disposed guard 2026-04-13 20:13:41 +08:00
Simon c72ff95670 docs: update links in troubleshooting page 2026-04-13 17:21:26 +08:00
Simon d7a38abdbd chore: update tsconfig 2026-04-13 16:07:24 +08:00
Simon 6fed95b365 chore: enable workspace TypeScript SDK prompt 2026-04-13 15:23:35 +08:00
Simon 0099c1ca8b chore: upgrade wxt 2026-04-13 15:19:05 +08:00
Simon c5c7e8af55 chore: set ts SDK path 2026-04-12 04:29:26 +08:00
Simon 83476da97f docs: update agents.md 2026-04-12 03:39:15 +08:00
Simon 4b6b591849 Merge pull request #423 from alibaba/chore/update-dev-guide-and-pr-skill
chore: update dev guide and PR skill
2026-04-12 03:29:38 +08:00
Simon b5ec9c4406 Merge pull request #422 from alibaba/refactor/typescript-6
refactor: upgrade to TypeScript 6 with source-first monorepo resolution
2026-04-12 03:28:46 +08:00
Simon ca197d14e9 fix: dom typing 2026-04-12 03:16:39 +08:00
Simon acfb336a9a fix: pre-publish and post-publish hooks 2026-04-12 03:16:13 +08:00
Simon 4d27d49752 refactor(setup): upgrade to TypeScript 6 with source-first monorepo resolution 2026-04-12 02:04:21 +08:00
XePope b46693f525 fix(core): correct autoFixer wait fallback action format 2026-04-09 16:49:16 +08:00
Simon c3720ce6b3 chore(repo): update dev guide and PR skill 2026-04-09 03:51:13 +08:00
Simon f68c73c5e9 feat: add maintainer's skills; rm npmrc 2026-04-08 22:37:03 +08:00
Simon 58d992d875 Merge pull request #420 from alibaba/refactor/node-and-eslint-upgrade
refactor: upgrade Node and ESLint
2026-04-08 22:05:06 +08:00
Simon e9784a16d0 chore: upgrade deps 2026-04-08 22:00:29 +08:00
Simon ebe3a3f7c3 chore: rm eslint-config-prettier and eslint-plugin-react-refresh 2026-04-08 21:58:03 +08:00
Simon 9ebb629aca fix: wxt vite-plugin error 2026-04-08 21:16:29 +08:00
Simon 4f80ec1459 refactor: upgrade ESLint 9→10 and simplify React lint toolchain
- Upgrade eslint and @eslint/js to v10
- Replace eslint-plugin-react-x + eslint-plugin-react-dom + eslint-plugin-react-hooks
  with unified @eslint-react/eslint-plugin
- Raise dev Node.js requirement to ^22.13.0 || >=24 (runtime packages unaffected)
- Add .npmrc with engine-strict=true
- Move all @eslint-react rule overrides to eslint.config.js,
  eliminating plugin-specific inline eslint-disable comments
- Fix real issues caught by new rules: useless assignments,
  leaked setTimeout, ref naming, useState setter naming
2026-04-08 20:31:31 +08:00
liuguiyuan 9104064e8c fix(mask): stop requestAnimationFrame loop on dispose to prevent memory leak
The #moveCursorToTarget() method recursively schedules itself via
requestAnimationFrame, creating a continuous animation loop for the
AI cursor. However, dispose() only removes the DOM wrapper element
without stopping this loop, causing:

- CPU waste: rAF callback continues executing every frame (~60fps)
  after the mask is disposed, performing unnecessary calculations
  on a detached cursor element.
- Resource leak: Each SimulatorMask instance creates an unrecoverable
  animation loop that persists for the lifetime of the page.
- Console noise: style assignments to removed DOM nodes may produce
  browser warnings.

Fix: Add a #disposed boolean flag, checked at the top of
#moveCursorToTarget() to short-circuit the recursion. Set the flag
to true in dispose() before removing DOM elements.

Changes:
- Add #disposed field (default false)
- Guard #moveCursorToTarget() with early return when #disposed
- Set #disposed = true in dispose() before cleanup
2026-04-08 18:53:42 +08:00
Simon a43e653a74 chore: simplify issue config 2026-04-08 18:52:53 +08:00
Simon 3bffd76626 chore: update github templates 2026-04-08 18:49:16 +08:00
Simon 015101d6ae Merge pull request #416 from alibaba/dependabot/npm_and_yarn/development-dependencies-ffd7d36be5
chore(deps-dev): bump typescript-eslint from 8.58.0 to 8.58.1 in the development-dependencies group
2026-04-08 18:45:14 +08:00
dependabot[bot] 8904e602dd chore(deps-dev): bump typescript-eslint
Bumps the development-dependencies group with 1 update: [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).


Updates `typescript-eslint` from 8.58.0 to 8.58.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.1/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.58.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-08 09:36:39 +00:00
Simon d384967e41 chore: dependabot config 2026-04-08 17:34:17 +08:00
Simon 531b59f538 chore: add git-cleanup skill 2026-04-08 17:28:11 +08:00
Simon bef26c3feb Merge pull request #415 from alibaba/fix/security-deps-hono-vite-path-to-regexp
fix(deps): update hono, path-to-regexp and vite for security patches
2026-04-08 17:21:17 +08:00
Simon c48dd538a0 fix(deps): update hono, @hono/node-server, path-to-regexp and vite for security patches
- hono 4.12.8 → 4.12.12 (cookie bypass, middleware bypass, path traversal, IP matching)
- @hono/node-server 1.19.11 → 1.19.13 (middleware bypass)
- path-to-regexp 8.3.0 → 8.4.2 (ReDoS)
- vite ^7.3.1 → ^7.3.2 (arbitrary file read, fs.deny bypass, path traversal)
2026-04-08 17:20:14 +08:00
Simon 950767c1bf Merge pull request #414 from alibaba/fix/panel-history-max-height-responsive
fix(ui): make panel history max-height responsive to viewport
2026-04-08 17:07:09 +08:00
Simon 12b6001d53 fix(ui): make panel history max-height responsive to viewport 2026-04-08 17:05:10 +08:00
Simon 2c1972ed89 Merge pull request #413 from alibaba/fix/ext-result-card-font-size
fix(ext): increase result card font size and use foreground color
2026-04-08 16:52:39 +08:00
Simon 362bf822f7 fix(ext): increase result card font size and use foreground color
Fixes conflicting text-xs/text-[11px] classes and muted color on the
ResultCard component, making the result text more readable.

Closes #360
2026-04-08 16:50:09 +08:00
dependabot[bot] 4734e2df26 chore(deps-dev): bump the development-dependencies group with 6 updates (#405) 2026-04-07 15:39:11 +08:00
Simon c2648c1749 chore(setup): update TypeScript SDK path in settings 2026-04-04 03:44:31 +08:00
Simon 7071a6c26a fix(mcp): bind HTTP+WS server to localhost only (#399) 2026-04-04 03:15:20 +08:00
Simon 303ece84fd feat: add update-changelog skill documentation 2026-04-04 03:14:37 +08:00
Simon 8a0266ce8d docs: update changelog for version 1.7.1 2026-04-04 03:14:23 +08:00
74 changed files with 3220 additions and 1955 deletions
+64
View File
@@ -0,0 +1,64 @@
---
name: git-cleanup
description: Clean up local git branches and remotes accumulated from PR reviews. Use when the user asks to clean branches, remove stale remotes, or tidy up the local git state.
---
# Git Cleanup
Clean local branches (except `main` and current branch) and non-origin remotes.
Useful after reviewing multiple PRs that leave behind tracking branches and contributor remotes.
## Workflow
### 1. Survey
Run these in parallel:
```bash
git branch
git remote
git status --short
git stash list
```
Present a summary of how many branches and remotes will be removed.
### 2. Safety Checks — Ask Before Proceeding
**Stop and ask for confirmation if any of these are true:**
- Current branch is NOT `main`
- Working tree has uncommitted changes or stashes
- Any branch is ahead of its upstream
List unmerged branches separately and let the user decide.
### 3. Delete Branches
```bash
# Safe delete first (fails on unmerged branches)
git branch | grep -v '^\*' | grep -v '^\s*main$' | xargs git branch -d 2>&1
# Force-delete only with explicit user approval
git branch -D <branch>
```
### 4. Remove Remotes
```bash
git remote | grep -v '^origin$' | xargs -I{} git remote remove {}
```
### 5. Confirm
```bash
git branch && echo "---" && git remote
```
Report what was cleaned up.
## Key Rules
- **NEVER** delete `main` or the current checked-out branch
- **NEVER** force-delete unmerged branches without user confirmation
- If in doubt, ask
+100
View File
@@ -0,0 +1,100 @@
---
name: pre-impl-discussion
description: "Conduct a thorough pre-implementation discussion before making significant changes. Use when the user wants to discuss, plan, or evaluate a change before implementing it — especially when they say words like 'discuss', 'evaluate', 'plan', or 'let's talk about'."
argument-hint: "Describe the change to evaluate"
---
# Pre-Implementation Discussion
Facilitate a structured, collaborative discussion to evaluate a proposed change **before any implementation begins**.
## Golden Rule
**Do NOT implement anything until the user explicitly confirms the final plan and says to proceed.** Not even "let me try on a branch" — that's implementation. The user will tell you when discussion is over.
## Interaction Style
- **Concise during discussion.** Each intermediate response should be short and focused on the current question. Do NOT repeat the full plan in every response.
- **Complete when finalizing.** Once the plan is mature and the user asks for it, present a single comprehensive (but terse) summary for final review.
- **Ask, don't assume.** When uncertain about project context, constraints, or preferences — ask. The user prefers collaborative discussion over receiving a pre-baked answer.
- **Challenge the premise.** Question whether the proposed change is the right one. Suggest simpler alternatives if they exist.
- **Match the user's language.** Reply in the same language the user writes in.
## Procedure
### 1. Understand the Current State
Before forming any opinion:
- **Read the relevant source files** — configs, code, docs that relate to the change
- **Understand the project structure** — what's published vs private, what environments things target, existing constraints
- **Map the impact surface** — which files, packages, or systems would be affected
- **Estimate implementation cost** — how many files to touch, how much config to rewrite, what could break
Do NOT skip this step. Do NOT rely on assumptions about what "most projects" do.
### 2. Research Thoroughly
- **Consult official sources** — docs, changelogs, migration guides, GitHub issues
- **Verify every claim with evidence.** Don't say "X supports Y" without a source. If unsure, say so.
- **Search in parallel** to save time — batch independent queries
Common pitfalls:
- Assuming compatibility without checking actual version constraints
- Confusing roadmap/aspirations with actual released state
- Missing transitive constraints (a dependency of a dependency)
### 3. Present Findings (Concise)
Share a **brief** assessment. Tables work well for comparisons. Highlight **blockers** and **unknowns** prominently — don't bury them in paragraphs.
### 4. Identify Key Decisions
Surface the decisions the user needs to make. Present them as clear choices with trade-offs, not as a recommendation monologue.
For each decision point:
- What are the options? (2-3 max)
- What does each option cost or give up?
- What's your lean and why? (one sentence)
### 5. Iterate
The user will ask follow-up questions, raise concerns, or challenge assumptions. For each round:
- **Research if needed** — don't answer from instinct when facts are available
- **Answer only what was asked** — don't re-present the entire plan
- **Update your mental model** based on user feedback
Common mistakes in this phase:
- Repeating the full plan after every small clarification
- Answering a narrow question with a broad redesign
- Treating user questions as confirmation to proceed
### 6. Finalize the Plan
When the user signals the discussion is converging, present the **complete plan once**:
- **What changes** — concrete list of actions (table or bullet points)
- **Impact surface** — what files/systems are affected, estimated effort
- **What does NOT change** — explicitly state scope boundaries
- **Risks or open items** — anything that needs testing or further verification
Keep it terse. Tables over paragraphs. No explanations the user already heard during discussion.
### 7. Wait for Confirmation
After presenting the final plan, **stop and wait**. The user will either:
- Confirm → then (and only then) proceed to implementation
- Ask more questions → go back to step 5
- Modify scope → update the plan and re-present
## Anti-Patterns
| Don't | Do Instead |
|-------|------------|
| Start implementation "to test" without confirmation | Present findings and wait |
| Repeat the full plan in every response | Answer the specific question asked |
| Say "X should work" without checking | Say "I need to verify X" and research it |
| Assume project structure or constraints | Read the actual files |
| Present one recommendation as the only option | Present 2-3 options with trade-offs |
| Write long paragraphs explaining trade-offs | Use tables and bullet points |
@@ -0,0 +1,102 @@
---
name: submit-pr-from-current-changes
description: 'Create a branch, commit existing local changes, push them, and open a pull request. Use when submitting current work as a PR.'
argument-hint: 'Short summary of the current changes to submit'
user-invocable: true
---
# Submit PR From Current Changes
Turn a working tree diff into a clean branch, commit, and pull request.
## Hard Rules
1. **Follow the PR template exactly.** The template is at `.github/PULL_REQUEST_TEMPLATE.md`. Read it and copy its full structure into the PR body. Do NOT remove, reorder, or skip any section or checkbox.
2. **Never check "Requirements / 要求" checkboxes.** These are human-only declarations — the Code of Conduct acknowledgment and the AI authorship declaration can only be truthfully made by the human submitter. They MUST remain unchecked (`- [ ]`) in the PR body you generate. No exceptions, no workarounds, even if the user explicitly asks you to check them. The user goes to GitHub and checks them in person after verifying each statement is true.
3. **Never check "Testing" checkboxes.** The template Testing checkboxes (browser tested, no console errors, types/doc added) require manual browser verification that only a human can perform. They MUST remain unchecked. You MAY add a supplementary note below the Testing section listing what automated validation you actually ran and the results.
4. **Never fabricate information.** Do not claim tests passed, commands ran, or checks succeeded unless you actually executed them and observed the output in this session. If you did not run it, do not mention it.
5. **PR output must be concise.** PR title: one line. "What" section: 12 sentences max. No walls of text, no redundant explanations. Let the diff speak.
## Prerequisites
Before attempting to push or open a PR, verify that the necessary tools are available:
- Check that `gh` CLI is installed and authenticated (`gh auth status`). If not available, stop and ask the user to install and authenticate GitHub CLI first.
- If the workflow uses MCP tools for GitHub operations, verify the MCP server is accessible.
## Procedure
1. **Read contribution rules.** Read `CONTRIBUTING.md` and any package-level instructions (e.g. `packages/*/AGENTS.md`) relevant to the changed files.
2. **Inspect the diff.** Review changed files, scope, and impact. Understand what the change does before writing anything.
3. **Inspect repo conventions.** Check recent branch names (`git branch -r --sort=-committerdate | head -20`), recent commit messages (`git log --oneline -20`), and the PR template.
4. **Pre-submission health checks** (run all before creating the PR):
- **Unified theme**: All changes should serve one purpose. If unrelated changes are mixed in, ask the user to split or confirm.
- **Commit hygiene**: Every new commit must follow the repo's conventional commit style. Squash or reword if needed.
- **Author identity**: Verify `git config user.name` and `git config user.email` are set and the email looks real (not empty, not `noreply` unless intentional). Warn the user if not.
- **No leftover artifacts**: Check for debug logs, `.only` in tests, conflict markers, or temp files in the diff.
- **Lint and build**: Run lint/build for the affected area. Record results honestly.
5. **Warn if the PR looks too hasty.** If any of these are true, pause and warn the user before proceeding:
- Large diff with no description of intent provided
- Changes touch core lib or extension (where vibe coding is prohibited per `CONTRIBUTING.md`)
- Multiple unrelated concerns in one diff
- No validation has been run at all
- Remind the user: _"This project does not accept low-quality or AI-generated PRs without meaningful human review. Please review your changes carefully."_
6. **Branch.** Check the current branch first:
- If already on a non-main feature branch with a valid name (matching `type/topic` convention), reuse it.
- If the branch name does not follow repo conventions (e.g. missing prefix, unclear topic), ask the user whether to rename or create a new one.
- If on `main` or a default branch, create a new branch from it with a short kebab-case name: prefix (`fix/`, `feat/`, `docs/`, `refactor/`, `chore/`) + concrete topic words.
7. **Stage and commit.** Stage only the intended files. Use `type(scope): subject` format. Keep the subject specific and compact.
8. **Push.** Push with `-u origin HEAD`.
9. **Open PR.** Use `gh pr create` with the full PR template structure. Fill in "What" and "Type" sections based on the actual diff. Leave all "Testing" and "Requirements" checkboxes unchecked.
10. **Report results.** Tell the user: branch name, commit hash, PR link, and what validation actually ran (with pass/fail).
## Post-Submission Reminder
After successfully opening the PR, ALWAYS give a brief reminder in the user's language. Keep it concise and natural, but make sure it clearly tells the user:
1. They need to test the changes themselves in the browser.
2. They need to go to the PR page and check the Testing and Requirements checkboxes only after verifying each item.
3. The PR will not enter review until those checkboxes are checked.
4. The project does not accept autonomously AI-generated PRs, so they should only check the AI declaration if it is truthful.
## Branch Naming
- Prefer short kebab-case names with a repo-consistent prefix such as `fix/`, `feat/`, `docs/`, `refactor/`, or `chore/`.
- Match the change type first, then the smallest useful topic.
- Prefer concrete topic words over issue text dumps.
## Commit Style
- Use the repository's prevailing commit style (conventional commits).
- Use `type(scope): subject` when scope is clear from the changed area.
- Keep the subject specific and compact.
- If multiple commits exist on the branch, each one must independently follow conventions.
## Validation Strategy
- Default to enough validation to defend the PR, not the absolute minimum.
- Prefer area-specific build, lint, or test commands when they exist.
- Escalate to broader validation when the diff crosses packages, changes shared code, or affects release behavior.
- Never claim checks that did not actually run.
- You MAY note what you ran and the results below the Testing section in the PR body, but do NOT check the template checkboxes.
## Decision Points
- No local changes → stop, say so.
- `gh` CLI not available → stop, ask user to install it.
- Unrelated files mixed → stage only the intended subset or ask whether the work should be split.
- If the repo has area-specific instructions, read them before naming the branch or writing the PR.
- Change is small but high-risk → prefer broader validation.
- Change is narrowly scoped and low-risk → run the most relevant checks, not arbitrary unrelated ones.
- Template has declarations you cannot truthfully check → leave unchecked, tell the user why.
## Completion Checks
- The branch exists remotely and tracks upstream.
- The commit message(s) match repo style.
- All commit authors have proper name and email configured.
- The PR title matches the commit intent.
- The PR body follows the template structure completely.
- All "Requirements" and "Testing" checkboxes are unchecked (`- [ ]`) in the PR body. Double-check: if any `- [x]` appears in these sections, it is a violation — fix it before submitting.
- The reported validation is accurate — nothing fabricated.
- The post-submission reminder was delivered in the user's language, concisely and accurately.
+109
View File
@@ -0,0 +1,109 @@
---
name: update-changelog
description: 'Update docs/CHANGELOG.md from git history, GitHub releases, and code diffs. Use when: writing release notes, syncing the latest changelog entry, summarizing a new tag, or keeping changelog wording concise and consistent.'
argument-hint: 'Describe the target, for example: latest version only'
---
# Update Changelog
Update `docs/CHANGELOG.md` from repository evidence instead of guesswork.
## When to Use
- Add the newest release entry to `docs/CHANGELOG.md`
- Sync changelog text with GitHub Releases
- Summarize the latest tag from git history or code diffs
## Defaults
- Keep the wording brief
- Only add the latest missing version unless the user explicitly asks to backfill older releases
- Prefer GitHub sources first, especially Releases and tag metadata
- Skip `Features` / `Improvements` / `Bug Fixes` headings when the release only has a few clear items
## Procedure
### 1. Read the local style
- Open `docs/CHANGELOG.md`
- Match the existing tone, bullet style, section ordering, and date format
### 2. Determine the target release
- Read the root `package.json` version and compare it with the top changelog entry
- Find the previous tag for the target version
- If the latest version is already documented, stop and report that no changelog update is needed
### 3. Gather evidence
Prefer these sources in order:
1. GitHub release notes
```bash
GH_PAGER=cat gh release view v<version> --repo <owner>/<repo> --json tagName,name,publishedAt,body
```
2. Tag date
```bash
git log -1 --format=%cs v<version>
```
3. Commit history between tags
```bash
git --no-pager log --format='%h %s' --no-merges v<previous>..v<version>
```
4. Diff scope when commit subjects are vague
```bash
git --no-pager diff --name-only v<previous>..v<version>
git --no-pager diff --stat v<previous>..v<version>
```
5. Read touched files directly only when the user-visible change is still unclear
### 4. Distill what belongs in the changelog
Include:
- User-visible features
- Important behavior changes
- Bug fixes that improve reliability, compatibility, or developer experience
- Small docs updates only when they materially change supported setups or onboarding
Exclude unless explicitly requested:
- Pure version bumps
- Routine dependency updates
- Internal refactors with no visible impact
- Mechanical formatting noise
### 5. Choose the structure
- If the release has 1 to 3 clear points, write flat bullets directly under the version heading
- If the release has several distinct items, use short headings such as `### Features`, `### Improvements`, and `### Bug Fixes`
- Do not force categories when they make the entry longer or noisier
### 6. Write the entry
- Add or update only the requested release entry
- Keep bullets short and concrete
- Reuse project terminology from nearby entries
- Avoid marketing language
- Do not copy noisy GitHub release text verbatim
### 7. Verify
- Check dates, version numbers, and tag boundaries
- Ensure Markdown structure matches nearby entries
- Confirm no intermediate versions were added unless requested
## Completion Checks
- The newest requested version is documented
- The wording is concise and consistent with the surrounding changelog
- The entry is backed by GitHub releases, git history, or code diff evidence
- Low-signal internal changes were left out
+24 -26
View File
@@ -1,61 +1,59 @@
name: Bug Report
description: Report a bug
title: '[Bug] '
labels: ['bug']
type: Bug
body:
- type: markdown
attributes:
value: |
Thanks for your interest in improving the project! Before submitting, please read our guidelines.
感谢您对改进项目的兴趣!提交前请阅读我们的指南
Thanks for your interest in improving the project! Before submitting, please search for existing issues.
感谢参与我们的社区!请先搜索现有 Issue,避免重复提交
- [Code of Conduct](https://github.com/alibaba/page-agent/blob/main/docs/CODE_OF_CONDUCT.md)
- [Contributing Guide](https://github.com/alibaba/page-agent/blob/main/CONTRIBUTING.md)
> 为了让更多人参与讨论,请尽量使用英文提交 Issue,感谢理解 🙏
- type: textarea
id: description
attributes:
label: What happened?
placeholder: Describe the bug and expected behavior
label: What happened? / 问题描述
description: Describe what you expected vs what actually happened.
placeholder: 'A clear description of the bug.'
validations:
required: true
- type: textarea
id: code
id: reproduction
attributes:
label: Code
render: typescript
placeholder: Minimal reproduction code
label: How to reproduce / 如何复现
description: Provide steps, URL, config or code snippet to reproduce the bug.
placeholder: '1. Open URL: https://...'
validations:
required: false
required: true
- type: input
id: version
attributes:
label: Version
placeholder: '0.0.0'
- type: input
id: browser
attributes:
label: Browser
placeholder: 'Chrome 120, Firefox 119, etc.'
validations:
required: false
- type: input
id: version
attributes:
label: version
placeholder: '0.0.0'
validations:
required: false
placeholder: 'e.g. Chrome 130'
- type: checkboxes
id: community
id: checklist
attributes:
label: Community Communication / 社区沟通
description: Confirm you will communicate respectfully and constructively / 确认将以礼貌、建设性的方式沟通
label: Before submitting
options:
- label: I will be polite and respectful. / 我会保持礼貌与尊重。
required: true
- label: I will share constructive, actionable suggestions. / 我会提供建设性、可行动的建议。
required: true
- label: I have read the Code of Conduct. / 我已阅读行为准则。
required: true
- label: I have searched existing issues and this is not a duplicate.
required: true
validations:
required: true
-6
View File
@@ -1,11 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Questions & Ideas / 问题与想法(Discussions
url: https://github.com/alibaba/page-agent/discussions
about: Use Discussions for Q&A and ideation. 使用 Discussions 进行问答与想法交流。
- name: Security Report / 安全问题报告
url: https://github.com/alibaba/page-agent/security/policy
about: Report security vulnerabilities responsibly. 通过安全页面报告漏洞。
- name: Contributing Guide / 贡献指南
url: https://github.com/alibaba/page-agent/blob/main/CONTRIBUTING.md
about: How to contribute code and ideas. 如何进行贡献与提交代码。
+9 -14
View File
@@ -1,32 +1,28 @@
name: Feature Request
description: Suggest a feature
title: '[Feature] '
labels: ['enhancement']
type: Feature
body:
- type: markdown
attributes:
value: |
Thanks for your interest in improving the project! Before submitting, please read our guidelines.
感谢您对改进项目的兴趣!提交前请阅读我们的指南
Thanks for your interest in improving the project! Before submitting, please search for existing issues.
感谢参与我们的社区!请先搜索现有 Issue,避免重复提交
- [Code of Conduct](https://github.com/alibaba/page-agent/blob/main/docs/CODE_OF_CONDUCT.md)
- [Contributing Guide](https://github.com/alibaba/page-agent/blob/main/CONTRIBUTING.md)
> 为了让更多人参与讨论,请尽量使用英文提交 Issue,感谢理解 🙏
- type: textarea
id: description
attributes:
label: Feature Description / 功能描述
description: Describe the problem, solution, and any API changes. / 描述问题、解决方案以及 API 变更。
description: Describe the problem, solution, and any API changes.
placeholder: |
**Problem**:
What problem does this solve?
**Solution**:
How should this work?
**Proposed API**:
```typescript
// code here
```
validations:
required: true
@@ -34,14 +30,13 @@ body:
- type: checkboxes
id: community
attributes:
label: Community Communication / 社区沟通
description: Confirm you will communicate respectfully and constructively / 确认将以礼貌、建设性的方式沟通
label: Before submitting
options:
- label: I will be polite and respectful. / 我会保持礼貌与尊重。
required: true
- label: I will share constructive, actionable suggestions. / 我会提供建设性、可行动的建议。
required: true
- label: I have read the CODE_OF_CONDUCT.md and CONTRIBUTING.md. / 我已阅读行为准则。
required: true
- label: I have searched existing issues and this is not a duplicate.
required: true
validations:
required: true
+5 -7
View File
@@ -2,15 +2,15 @@
Brief description of changes.
Closes #(issue)
## Type
- [ ] Breaking change
- [ ] Bug fix
- [ ] Feature / Improvement
- [ ] Refactor
- [ ] Documentation
- [ ] Website
- [ ] Demo / Testing
- [ ] Breaking change
- [ ] Refactor / Chores
- [ ] Documentation / Website / Demo / Testing
## Testing
@@ -18,8 +18,6 @@ Brief description of changes.
- [ ] No console errors
- [ ] Types/doc added
Closes #(issue)
## Requirements / 要求
- [ ] I have read and follow the [Code of Conduct](../docs/CODE_OF_CONDUCT.md) and [Contributing Guide](../CONTRIBUTING.md) . / 我已阅读并遵守行为准则。
+11 -4
View File
@@ -4,28 +4,35 @@ updates:
directory: '/'
schedule:
interval: 'weekly'
labels:
- 'dependencies'
groups:
# 生产依赖 - 小版本更新
production-dependencies:
dependency-type: 'production'
update-types:
- 'minor'
- 'patch'
# 开发依赖 - 小版本更新
development-dependencies:
dependency-type: 'development'
update-types:
- 'minor'
- 'patch'
# Major 更新单独处理(不分组,需要人工审查)
# 安全更新也不分组,Dependabot 会自动优先创建独立 PR
development-major:
dependency-type: 'development'
update-types:
- 'major'
# Production major updates are intentionally ungrouped for individual review.
# Security updates are also ungrouped — Dependabot prioritizes them automatically.
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'weekly'
labels:
- 'dependencies'
groups:
github-actions:
patterns:
+1 -1
View File
@@ -31,7 +31,7 @@ jobs:
uses: actions/configure-pages@v6
- name: Upload artifact
uses: actions/upload-pages-artifact@v4
uses: actions/upload-pages-artifact@v5
with:
path: './packages/website/dist'
+3
View File
@@ -25,6 +25,9 @@ dist-ssr
*.sw?
.qoder
# publish backup
package.json.bak
# env files
.env
.env.*
+4 -1
View File
@@ -35,5 +35,8 @@
"blanks-around-lists": false,
"ol-prefix": false,
"no-duplicate-heading": false
}
},
"js/ts.tsdk.path": "node_modules/typescript/lib",
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
+7 -6
View File
@@ -5,7 +5,7 @@
This is a **monorepo** with npm workspaces:
- **Page Agent** (`packages/page-agent/`) - Main entry with built-in UI Panel, published as `page-agent` on npm
- **Extension** (`packages/extension/`) - Browser extension (WXT + React) 🚧 WIP
- **Extension** (`packages/extension/`) - Browser extension (WXT + React)
- **Website** (`packages/website/`) - React docs and landing page. **When working on website, follow `packages/website/AGENTS.md`**
Internal packages:
@@ -18,10 +18,11 @@ Internal packages:
## Development Commands
```bash
npm start # Start website dev server
npm run build # Build all packages
npm run build:libs # Build all libraries
npm run lint # ESLint with TypeScript strict rules
npm start # Start website dev server
npm run build # Build all packages
npm run build:libs # Build all libraries
npm run typecheck # Typecheck all packages (libs + website + extension)
npm run lint # ESLint
npm run zip -w @page-agent/ext # Zip the extension package
```
@@ -29,7 +30,7 @@ npm run zip -w @page-agent/ext # Zip the extension package
### Monorepo Structure
Simple monorepo solution: TypeScript references + Vite aliases. Update tsconfig and vite config when adding/removing packages.
Source-first monorepo: library `package.json` exports point to `src/*.ts` during development. At publish time, `scripts/pre-publish.js` promotes `publishConfig` fields to top-level (swapping to `dist/`), and `scripts/post-publish.js` restores the originals.
```
packages/
+2 -2
View File
@@ -50,8 +50,8 @@ Fastest way to try PageAgent with our free Demo LLM:
| Mirrors | URL |
| ------- | ---------------------------------------------------------------------------------- |
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.7.1/dist/iife/page-agent.demo.js |
| China | https://registry.npmmirror.com/page-agent/1.7.1/files/dist/iife/page-agent.demo.js |
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.8.0/dist/iife/page-agent.demo.js |
| China | https://registry.npmmirror.com/page-agent/1.8.0/files/dist/iife/page-agent.demo.js |
### NPM Installation
+50
View File
@@ -5,6 +5,56 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.7.1] - 2026-04-04
### Features
- **Optional `keepSemanticTags`** - Added an experimental `keepSemanticTags` config to preserve semantic structure in PageController output
- **Per-task extension system instructions** - Extension `ExecuteConfig` now supports `systemInstruction`
### Improvements
- **Smarter scroll handling** - Scroll container detection and scroll direction handling are more reliable
- **Better accessibility-aware element detection** - Interactive candidates with supported ARIA attributes and `role="listitem"` are recognized more accurately
### Bug Fixes
- Fixed iframe-origin filtering for extension `postMessage` listeners
- Avoided a `currentScript` null pointer during deferred initialization
## [1.7.0] - 2026-03-31
- **More reliable click actions** - Click handling now reuses pointer coordinates, verifies targets with `elementFromPoint`, and behaves better on layered layouts
- **Better mask event handling** - `SimulatorMask` now supports passthrough events when automation should not fully swallow input
- Fixed a `SimulatorMask` memory leak
## [1.6.3] - 2026-03-30
### Features
- **Experimental all-tabs control** - Extension can include and control all browser tabs via `experimentalIncludeAllTabs`
### Improvements
- **Calmer empty state motion** - Disabled the EmptyState auto-start animation in the extension UI
- **Cleaner extension docs** - Simplified setup and tab-control documentation across the README and developer guide
### Bug Fixes
- Fixed new-tab detection from content scripts
- Fixed tab deduplication and multi-window handling in the extension
## [1.6.2] - 2026-03-25
- **Longer task input** - The UI task input now accepts up to 1000 characters
- **Contributor docs refresh** - Added a maintainer note and refreshed contributor-facing documentation
- Fixed lint issues in the release pipeline
## [1.6.1] - 2026-03-22
- **Internal PageController action exports** - PageController actions are now exposed as internal methods for easier reuse across packages
- **Expanded docs** - Added MCP docs and clarified project limitations and homepage details
## [1.6.0] - 2026-03-21
### Features
+2 -2
View File
@@ -49,8 +49,8 @@
| Mirrors | URL |
| ------- | ---------------------------------------------------------------------------------- |
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.7.1/dist/iife/page-agent.demo.js |
| China | https://registry.npmmirror.com/page-agent/1.7.1/files/dist/iife/page-agent.demo.js |
| Global | https://cdn.jsdelivr.net/npm/page-agent@1.8.0/dist/iife/page-agent.demo.js |
| China | https://registry.npmmirror.com/page-agent/1.8.0/files/dist/iife/page-agent.demo.js |
### NPM 安装
+1 -1
View File
@@ -10,7 +10,7 @@ For contribution rules and expectations, see [../CONTRIBUTING.md](../CONTRIBUTIN
1. **Prerequisites**
- `macOS` / `Linux` / `WSL`
- `node.js >= 20` with `npm >= 10`
- `node.js >= 24` with `npm >= 11`
- An editor that supports `ts/eslint/prettier`
- Make sure `eslint`, `prettier` and `commitlint` work well. Un-linted code won't pass the CI.
+6 -29
View File
@@ -1,8 +1,5 @@
import eslintReact from '@eslint-react/eslint-plugin'
import js from '@eslint/js'
import reactDom from 'eslint-plugin-react-dom'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import reactX from 'eslint-plugin-react-x'
import { defineConfig, globalIgnores } from 'eslint/config'
import globals from 'globals'
import tseslint from 'typescript-eslint'
@@ -15,44 +12,24 @@ export default defineConfig([
'**/.wxt',
'**/.output',
]),
{
plugins: {
'react-hooks': reactHooks,
},
rules: reactHooks.configs.recommended.rules,
},
{
files: ['**/*.{ts,tsx}'],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
// reactHooks.configs['recommended-latest'],
reactRefresh.configs.vite,
// Remove tseslint.configs.recommended and replace with this
...tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
...tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
...tseslint.configs.stylisticTypeChecked,
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
eslintReact.configs['recommended-typescript'],
],
languageOptions: {
parserOptions: {
// project: ['./tsconfig.json'],
// project: ['./packages/*/tsconfig.json'],
// tsconfigRootDir: import.meta.dirname,
projectService: true,
},
ecmaVersion: 2020,
globals: globals.browser,
},
rules: {
// Add any additional rules here
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
@@ -72,14 +49,14 @@ export default defineConfig([
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/restrict-plus-operands': 'off',
'react-dom/no-missing-button-type': 'off',
'react-x/no-nested-component-definitions': 'off',
'@typescript-eslint/prefer-optional-chain': 'off',
'@typescript-eslint/use-unknown-in-catch-callback-variable': 'off',
'@typescript-eslint/no-unnecessary-type-parameters': 'off',
// 'require-await': 'off',
'@typescript-eslint/require-await': 'off',
'@eslint-react/dom-no-missing-button-type': 'off',
'@eslint-react/no-nested-component-definitions': 'off',
'@eslint-react/no-array-index-key': 'off',
'@eslint-react/dom-no-dangerously-set-innerhtml': 'off',
},
},
])
+2334 -1508
View File
File diff suppressed because it is too large Load Diff
+21 -22
View File
@@ -1,7 +1,7 @@
{
"name": "root",
"private": true,
"version": "1.7.1",
"version": "1.8.0",
"type": "module",
"workspaces": [
"packages/page-controller",
@@ -22,7 +22,7 @@
},
"homepage": "https://alibaba.github.io/page-agent/",
"engines": {
"node": "^20.19.0 || ^22.13.0 || >=24"
"node": "^22.13.0 || >=24"
},
"scripts": {
"start": "npm run dev --workspace=@page-agent/website",
@@ -33,41 +33,40 @@
"build:website": "npm run build:website --workspace=@page-agent/website",
"build:ext": "npm run build:libs && npm run zip -w @page-agent/ext",
"version": "node scripts/sync-version.js",
"postpublish": "npm run postpublish --workspaces --if-present",
"typecheck": "tsc --noEmit -p tsconfig.typecheck.json && tsc --noEmit -p packages/extension/tsconfig.json",
"lint": "eslint .",
"cleanup": "rm -rf packages/*/dist",
"prepare": "husky"
"cleanup": "rm -rf packages/*/dist && rm -rf packages/*/.output",
"prepare": "husky || true"
},
"devDependencies": {
"@commitlint/cli": "^20.5.0",
"@commitlint/config-conventional": "^20.5.0",
"@eslint/js": "^9.39.2",
"@microsoft/api-extractor": "^7.57.7",
"@eslint-react/eslint-plugin": "^4.2.3",
"@eslint/js": "^10.0.1",
"@microsoft/api-extractor": "^7.58.2",
"@tailwindcss/vite": "^4.2.2",
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
"@types/node": "^25.5.0",
"@types/node": "^25.6.0",
"@vitejs/plugin-react-swc": "^4.3.0",
"chalk": "^5.6.2",
"concurrently": "^9.2.1",
"dotenv": "^17.3.1",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-react-dom": "^2.13.0",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.5.2",
"eslint-plugin-react-x": "^2.13.0",
"globals": "^17.4.0",
"dotenv": "^17.4.2",
"eslint": "^10.2.0",
"globals": "^17.5.0",
"husky": "^9.1.7",
"lint-staged": "^16.4.0",
"prettier": "^3.8.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.58.0",
"prettier": "^3.8.2",
"typescript": "^6.0.2",
"typescript-eslint": "^8.58.2",
"unplugin-dts": "^1.0.0-beta.6",
"vite": "^7.3.1",
"vite-plugin-css-injected-by-js": "^4.0.1",
"vite-bundle-analyzer": "^1.3.6"
"vite": "^7.3.2",
"vite-bundle-analyzer": "^1.3.7",
"vite-plugin-css-injected-by-js": "^4.0.1"
},
"overrides": {
"typescript": "^5.9.3"
"typescript": "^6.0.2",
"@vitejs/plugin-react": "^5.2.0"
},
"lint-staged": {
"*.{js,ts,cjs,cts,mjs,mts}": [
+22 -12
View File
@@ -1,16 +1,26 @@
{
"name": "@page-agent/core",
"private": false,
"version": "1.7.1",
"version": "1.8.0",
"type": "module",
"main": "./dist/esm/page-agent-core.js",
"module": "./dist/esm/page-agent-core.js",
"types": "./dist/esm/PageAgentCore.d.ts",
"main": "./src/PageAgentCore.ts",
"types": "./src/PageAgentCore.ts",
"exports": {
".": {
"types": "./dist/esm/PageAgentCore.d.ts",
"import": "./dist/esm/page-agent-core.js",
"default": "./dist/esm/page-agent-core.js"
"types": "./src/PageAgentCore.ts",
"default": "./src/PageAgentCore.ts"
}
},
"publishConfig": {
"main": "./dist/esm/page-agent-core.js",
"module": "./dist/esm/page-agent-core.js",
"types": "./dist/esm/PageAgentCore.d.ts",
"exports": {
".": {
"types": "./dist/esm/PageAgentCore.d.ts",
"import": "./dist/esm/page-agent-core.js",
"default": "./dist/esm/page-agent-core.js"
}
}
},
"files": [
@@ -39,18 +49,18 @@
"scripts": {
"build": "vite build",
"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))\"",
"postpublish": "node -e \"['README.md','LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\""
"prepublishOnly": "node ../../scripts/pre-publish.js",
"postpublish": "node ../../scripts/post-publish.js"
},
"dependencies": {
"chalk": "^5.6.2",
"@page-agent/llms": "1.7.1",
"@page-agent/page-controller": "1.7.1"
"@page-agent/llms": "1.8.0",
"@page-agent/page-controller": "1.8.0"
},
"peerDependencies": {
"zod": "^3.25.0 || ^4.0.0"
},
"devDependencies": {
"zod": "^4.3.5"
"zod": "^4.3.6"
}
}
+2 -2
View File
@@ -19,7 +19,7 @@ const log = console.log.bind(console, chalk.yellow('[autoFixer]'))
* - etc.
*/
export function normalizeResponse(response: any, tools?: Map<string, PageAgentTool>): any {
let resolvedArguments = null as any
let resolvedArguments: any
const choice = (response as { choices?: Choice[] }).choices?.[0]
if (!choice) throw new Error('No choices in response')
@@ -93,7 +93,7 @@ export function normalizeResponse(response: any, tools?: Map<string, PageAgentTo
// fix incomplete formats
if (!resolvedArguments.action) {
log(`#5: fixing tool_call`)
resolvedArguments.action = { name: 'wait', input: { seconds: 1 } }
resolvedArguments.action = { wait: { seconds: 1 } }
}
// pack back to standard format
-9
View File
@@ -1,9 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
// @workaround DTS bug
// dts do not work with monorepo path mapping
// disable path mapping for it
"paths": {}
}
}
+3 -17
View File
@@ -1,22 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
"noEmit": false,
"allowImportingTsExtensions": false,
"baseUrl": ".",
"outDir": "dist",
"paths": {
//
"@page-agent/llms": ["../llms/src/index.ts"],
"@page-agent/page-controller": ["../page-controller/src/PageController.ts"]
}
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo"
},
"include": ["**/*.ts"],
"exclude": ["dist", "node_modules"],
"references": [
//
{ "path": "../llms" },
{ "path": "../page-controller" }
]
"include": ["src/**/*.ts"],
"exclude": ["dist", "node_modules"]
}
+9 -4
View File
@@ -11,13 +11,18 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
export default defineConfig({
clearScreen: false,
plugins: [
dts({ tsconfigPath: './tsconfig.dts.json', bundleTypes: true }),
dts({
bundleTypes: true,
compilerOptions: {
composite: true,
noEmit: false,
emitDeclarationOnly: true,
declaration: true,
},
}),
cssInjectedByJsPlugin({ relativeCSSInjection: true }),
],
publicDir: false,
esbuild: {
keepNames: true,
},
build: {
lib: {
entry: resolve(__dirname, 'src/PageAgentCore.ts'),
+13 -12
View File
@@ -1,7 +1,7 @@
{
"name": "@page-agent/ext",
"private": true,
"version": "1.7.1",
"version": "1.8.0",
"type": "module",
"scripts": {
"dev": "wxt",
@@ -16,31 +16,32 @@
"@radix-ui/react-separator": "^1.1.8",
"@radix-ui/react-slot": "^1.2.4",
"@radix-ui/react-switch": "^1.2.6",
"@types/chrome": "^0.1.38",
"@tailwindcss/vite": "^4.2.2",
"@types/chrome": "^0.1.40",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.1",
"@types/react-dom": "^19.2.3",
"@wxt-dev/module-react": "^1.2.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"idb": "^8.0.3",
"lucide-react": "^1.7.0",
"lucide-react": "^1.8.0",
"motion": "^12.38.0",
"next-themes": "^0.4.6",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react": "^19.2.5",
"react-dom": "^19.2.5",
"rough-notation": "^0.5.1",
"simple-icons": "^16.14.0",
"simple-icons": "^16.16.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.5.0",
"tailwindcss": "^4.1.14",
"tailwindcss": "^4.2.2",
"tw-animate-css": "^1.4.0",
"wxt": "^0.20.20"
},
"dependencies": {
"@page-agent/core": "1.7.1",
"@page-agent/llms": "1.7.1",
"@page-agent/page-controller": "1.7.1",
"@page-agent/ui": "1.7.1",
"@page-agent/core": "1.8.0",
"@page-agent/llms": "1.8.0",
"@page-agent/page-controller": "1.8.0",
"@page-agent/ui": "1.8.0",
"ai-motion": "^0.4.8",
"chalk": "^5.6.2"
},
@@ -56,7 +56,7 @@ export class RemotePageController {
}
async getBrowserState(): Promise<BrowserState> {
let browserState = {} as BrowserState
let browserState: BrowserState
debug('getBrowserState', this.currentTabId)
const currentUrl = await this.getCurrentUrl()
@@ -24,7 +24,7 @@ export class TabsController {
currentTabId: number | null = null
private disposed = false
private port: chrome.runtime.Port | null = null
private port?: chrome.runtime.Port
private portRetries = 0
private windowId: number | null = null
@@ -44,7 +44,7 @@ export class TabsController {
this.currentTabId = null
this.disposed = false
this.port = null
this.port = undefined
this.portRetries = 0
this.windowId = null
@@ -338,7 +338,7 @@ export class TabsController {
})
this.port.onDisconnect.addListener(() => {
this.port = null
this.port = undefined
if (this.disposed) return
if (this.portRetries >= 7) {
console.error(PREFIX, 'tab events port failed after 7 retries, giving up')
@@ -354,7 +354,7 @@ export class TabsController {
debug('dispose')
this.disposed = true
this.port?.disconnect()
this.port = null
this.port = undefined
}
}
@@ -49,7 +49,9 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
const [showToken, setShowToken] = useState(false)
const [showApiKey, setShowApiKey] = useState(false)
useEffect(() => {
const [prevConfig, setPrevConfig] = useState(config)
if (prevConfig !== config) {
setPrevConfig(config)
setBaseURL(config?.baseURL || DEMO_BASE_URL)
setModel(config?.model || DEMO_MODEL)
setApiKey(config?.apiKey)
@@ -59,7 +61,7 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
setExperimentalLlmsTxt(config?.experimentalLlmsTxt ?? false)
setExperimentalIncludeAllTabs(config?.experimentalIncludeAllTabs ?? false)
setDisableNamedToolChoice(config?.disableNamedToolChoice ?? false)
}, [config])
}
// Poll for user auth token every second until found
useEffect(() => {
@@ -71,7 +71,6 @@ export function HistoryDetail({
{/* Events (read-only) */}
<div className="flex-1 overflow-y-auto p-3 space-y-2">
{session.history.map((event, index) => (
// eslint-disable-next-line react-x/no-array-index-key
<EventCard key={index} event={event} />
))}
</div>
@@ -34,7 +34,6 @@ export function HistoryList({
}, [])
useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
load()
}, [load])
+1 -1
View File
@@ -54,7 +54,7 @@ function ResultCard({
Result: {success ? 'Success' : 'Failed'}
</span>
</div>
<p className="text-xs text-[11px] text-muted-foreground pl-5 whitespace-pre-wrap">{text}</p>
<p className="text-[12px] text-foreground pl-5 whitespace-pre-wrap">{text}</p>
{children}
</div>
)
@@ -133,7 +133,6 @@ export default function App() {
)}
{history.map((event, index) => (
// eslint-disable-next-line react-x/no-array-index-key
<EventCard key={index} event={event} />
))}
@@ -206,9 +206,9 @@ export function useHubWs(
const [wsState, setWsState] = useState<HubWsState>(() => (wsPort ? 'connecting' : 'disconnected'))
const hubWsRef = useRef<HubWs | null>(null)
const latest = useRef({ execute, stop, configure, config })
const latestRef = useRef({ execute, stop, configure, config })
useEffect(() => {
latest.current = { execute, stop, configure, config }
latestRef.current = { execute, stop, configure, config }
})
useEffect(() => {
@@ -218,14 +218,14 @@ export function useHubWs(
Number(wsPort),
{
onExecute: async (task, incomingConfig) => {
const { execute, configure, config } = latest.current
const { execute, configure, config } = latestRef.current
if (incomingConfig) {
await configure({ ...config, ...incomingConfig } as ExtConfig)
}
const result = await execute(task)
return { success: result.success, data: result.data }
},
onStop: () => latest.current.stop(),
onStop: () => latestRef.current.stop(),
},
setWsState
)
@@ -178,7 +178,6 @@ export default function App() {
{showEmptyState && <EmptyState />}
{history.map((event, index) => (
// eslint-disable-next-line react-x/no-array-index-key
<EventCard key={index} event={event} />
))}
+3 -18
View File
@@ -3,26 +3,11 @@
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
"useDefineForClassFields": true,
"noEmit": false,
"allowImportingTsExtensions": false,
"strictNullChecks": true,
"jsx": "react-jsx",
"baseUrl": ".",
"types": ["node", "chrome"],
"paths": {
// Self root
"@/*": ["src/*"],
"@page-agent/llms": ["../llms/src/index.ts"],
"@page-agent/page-controller": ["../page-controller/src/PageController.ts"],
"@page-agent/core": ["../core/src/PageAgentCore.ts"],
"@page-agent/ui": ["../ui/src/index.ts"]
"@/*": ["./src/*"]
}
},
"references": [
//
{ "path": "../llms" },
{ "path": "../page-controller" },
{ "path": "../core" },
{ "path": "../ui" }
]
}
}
+20 -10
View File
@@ -1,15 +1,25 @@
{
"name": "@page-agent/llms",
"version": "1.7.1",
"version": "1.8.0",
"type": "module",
"main": "./dist/lib/page-agent-llms.js",
"module": "./dist/lib/page-agent-llms.js",
"types": "./dist/lib/index.d.ts",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": {
"types": "./dist/lib/index.d.ts",
"import": "./dist/lib/page-agent-llms.js",
"default": "./dist/lib/page-agent-llms.js"
"types": "./src/index.ts",
"default": "./src/index.ts"
}
},
"publishConfig": {
"main": "./dist/lib/page-agent-llms.js",
"module": "./dist/lib/page-agent-llms.js",
"types": "./dist/lib/index.d.ts",
"exports": {
".": {
"types": "./dist/lib/index.d.ts",
"import": "./dist/lib/page-agent-llms.js",
"default": "./dist/lib/page-agent-llms.js"
}
}
},
"files": [
@@ -33,8 +43,8 @@
"homepage": "https://alibaba.github.io/page-agent/",
"scripts": {
"build": "vite build",
"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{}})\""
"prepublishOnly": "node ../../scripts/pre-publish.js",
"postpublish": "node ../../scripts/post-publish.js"
},
"dependencies": {
"chalk": "^5.6.2"
@@ -43,6 +53,6 @@
"zod": "^3.25.0 || ^4.0.0"
},
"devDependencies": {
"zod": "^4.3.5"
"zod": "^4.3.6"
}
}
-9
View File
@@ -1,9 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
// @workaround DTS bug
// dts do not work with monorepo path mapping
// disable path mapping for it
"paths": {}
}
}
+1 -5
View File
@@ -1,11 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
"noEmit": false,
"allowImportingTsExtensions": false,
"baseUrl": ".",
"outDir": "dist"
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo"
},
"include": ["**/*.ts"],
"exclude": ["dist", "node_modules"]
+11 -4
View File
@@ -11,11 +11,18 @@ console.log(chalk.cyan(`📦 Building @page-agent/llms`))
export default defineConfig({
clearScreen: false,
plugins: [dts({ tsconfigPath: './tsconfig.dts.json', bundleTypes: true })],
plugins: [
dts({
bundleTypes: true,
compilerOptions: {
composite: true,
noEmit: false,
emitDeclarationOnly: true,
declaration: true,
},
}),
],
publicDir: false,
esbuild: {
keepNames: true,
},
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@page-agent/mcp",
"private": false,
"version": "1.7.1",
"version": "1.8.0",
"type": "module",
"bin": {
"page-agent-mcp": "src/index.js"
@@ -30,6 +30,6 @@
"dependencies": {
"@modelcontextprotocol/sdk": "^1.29.0",
"ws": "^8.20.0",
"zod": "^4.3.5"
"zod": "^4.3.6"
}
}
+3 -2
View File
@@ -6,6 +6,7 @@ import { WebSocketServer } from 'ws'
const EXT_ID = 'akldabonmimlicnjlflnapfeklbfemhj'
const STORE_URL = `https://chromewebstore.google.com/detail/page-agent-ext/${EXT_ID}`
const LOOPBACK_HOST = 'localhost'
const launcherTemplate = readFileSync(
fileURLToPath(new URL('./launcher.html', import.meta.url)),
@@ -60,8 +61,8 @@ export class HubBridge {
reject(err)
}
})
this.#httpServer.listen(this.port, () => {
console.error(`[page-agent-mcp] HTTP + WS on http://localhost:${this.port}`)
this.#httpServer.listen(this.port, LOOPBACK_HOST, () => {
console.error(`[page-agent-mcp] HTTP + WS on http://${LOOPBACK_HOST}:${this.port}`)
resolve()
})
})
+24 -14
View File
@@ -1,16 +1,26 @@
{
"name": "page-agent",
"private": false,
"version": "1.7.1",
"version": "1.8.0",
"type": "module",
"main": "./dist/esm/page-agent.js",
"module": "./dist/esm/page-agent.js",
"types": "./dist/esm/PageAgent.d.ts",
"main": "./src/PageAgent.ts",
"types": "./src/PageAgent.ts",
"exports": {
".": {
"types": "./dist/esm/PageAgent.d.ts",
"import": "./dist/esm/page-agent.js",
"default": "./dist/esm/page-agent.js"
"types": "./src/PageAgent.ts",
"default": "./src/PageAgent.ts"
}
},
"publishConfig": {
"main": "./dist/esm/page-agent.js",
"module": "./dist/esm/page-agent.js",
"types": "./dist/esm/PageAgent.d.ts",
"exports": {
".": {
"types": "./dist/esm/PageAgent.d.ts",
"import": "./dist/esm/page-agent.js",
"default": "./dist/esm/page-agent.js"
}
}
},
"files": [
@@ -40,20 +50,20 @@
"build": "vite build && npm run build:demo",
"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\"",
"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{}})\""
"prepublishOnly": "node ../../scripts/pre-publish.js",
"postpublish": "node ../../scripts/post-publish.js"
},
"dependencies": {
"@page-agent/core": "1.7.1",
"@page-agent/llms": "1.7.1",
"@page-agent/page-controller": "1.7.1",
"@page-agent/ui": "1.7.1",
"@page-agent/core": "1.8.0",
"@page-agent/llms": "1.8.0",
"@page-agent/page-controller": "1.8.0",
"@page-agent/ui": "1.8.0",
"chalk": "^5.6.2"
},
"peerDependencies": {
"zod": "^3.25.0 || ^4.0.0"
},
"devDependencies": {
"zod": "^4.3.5"
"zod": "^4.3.6"
}
}
-9
View File
@@ -1,9 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
// @workaround DTS bug
// dts do not work with monorepo path mapping
// disable path mapping for it
"paths": {}
}
}
+3 -21
View File
@@ -1,26 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
"noEmit": false,
"allowImportingTsExtensions": false,
"baseUrl": ".",
"outDir": "dist",
"paths": {
//
"@page-agent/llms": ["../llms/src/index.ts"],
"@page-agent/page-controller": ["../page-controller/src/PageController.ts"],
"@page-agent/core": ["../core/src/PageAgentCore.ts"],
"@page-agent/ui": ["../ui/src/index.ts"]
}
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo"
},
"include": ["**/*.ts"],
"exclude": ["dist", "node_modules"],
"references": [
//
{ "path": "../llms" },
{ "path": "../page-controller" },
{ "path": "../core" },
{ "path": "../ui" }
]
"include": ["src/**/*.ts"],
"exclude": ["dist", "node_modules"]
}
+9 -4
View File
@@ -11,13 +11,18 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
export default defineConfig({
clearScreen: false,
plugins: [
dts({ tsconfigPath: './tsconfig.dts.json', bundleTypes: true }),
dts({
bundleTypes: true,
compilerOptions: {
composite: true,
noEmit: false,
emitDeclarationOnly: true,
declaration: true,
},
}),
cssInjectedByJsPlugin({ relativeCSSInjection: true }),
],
publicDir: false,
esbuild: {
keepNames: true,
},
build: {
lib: {
entry: resolve(__dirname, 'src/PageAgent.ts'),
-11
View File
@@ -21,17 +21,6 @@ export default defineConfig(() => ({
// analyzer()
],
publicDir: false,
esbuild: {
keepNames: true,
},
resolve: {
alias: {
'@page-agent/page-controller': resolve(__dirname, '../page-controller/src/PageController.ts'),
'@page-agent/llms': resolve(__dirname, '../llms/src/index.ts'),
'@page-agent/core': resolve(__dirname, '../core/src/PageAgentCore.ts'),
'@page-agent/ui': resolve(__dirname, '../ui/src/index.ts'),
},
},
build: {
lib: {
entry: resolve(__dirname, 'src/demo.ts'),
+19 -9
View File
@@ -1,15 +1,25 @@
{
"name": "@page-agent/page-controller",
"version": "1.7.1",
"version": "1.8.0",
"type": "module",
"main": "./dist/lib/page-controller.js",
"module": "./dist/lib/page-controller.js",
"types": "./dist/lib/PageController.d.ts",
"main": "./src/PageController.ts",
"types": "./src/PageController.ts",
"exports": {
".": {
"types": "./dist/lib/PageController.d.ts",
"import": "./dist/lib/page-controller.js",
"default": "./dist/lib/page-controller.js"
"types": "./src/PageController.ts",
"default": "./src/PageController.ts"
}
},
"publishConfig": {
"main": "./dist/lib/page-controller.js",
"module": "./dist/lib/page-controller.js",
"types": "./dist/lib/PageController.d.ts",
"exports": {
".": {
"types": "./dist/lib/PageController.d.ts",
"import": "./dist/lib/page-controller.js",
"default": "./dist/lib/page-controller.js"
}
}
},
"files": [
@@ -32,8 +42,8 @@
"homepage": "https://alibaba.github.io/page-agent/",
"scripts": {
"build": "vite build",
"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{}})\""
"prepublishOnly": "node ../../scripts/pre-publish.js",
"postpublish": "node ../../scripts/post-publish.js"
},
"dependencies": {
"ai-motion": "^0.4.8"
@@ -185,7 +185,7 @@ export class PageController extends EventTarget {
const blacklist = [
...(this.config.interactiveBlacklist || []),
...document.querySelectorAll('[data-page-agent-not-interactive]').values(),
...Array.from(document.querySelectorAll('[data-page-agent-not-interactive]')),
]
this.flatTree = dom.getFlatTree({
+16
View File
@@ -0,0 +1,16 @@
import type { FlatDomTree } from './type'
interface DomTreeArgs {
doHighlightElements?: boolean
focusHighlightIndex?: number
viewportExpansion?: number
debugMode?: boolean
interactiveBlacklist?: Element[]
interactiveWhitelist?: Element[]
highlightOpacity?: number
highlightLabelOpacity?: number
}
declare const domTree: (args?: DomTreeArgs) => FlatDomTree
export default domTree
@@ -10,6 +10,8 @@ export class SimulatorMask extends EventTarget {
wrapper = document.createElement('div')
motion: Motion | null = null
#disposed = false
#cursor = document.createElement('div')
#currentCursorX = 0
@@ -129,6 +131,8 @@ export class SimulatorMask extends EventTarget {
}
#moveCursorToTarget() {
if (this.#disposed) return
const newX = this.#currentCursorX + (this.#targetCursorX - this.#currentCursorX) * 0.2
const newY = this.#currentCursorY + (this.#targetCursorY - this.#currentCursorY) * 0.2
@@ -156,11 +160,15 @@ export class SimulatorMask extends EventTarget {
}
setCursorPosition(x: number, y: number) {
if (this.#disposed) return
this.#targetCursorX = x
this.#targetCursorY = y
}
triggerClickAnimation() {
if (this.#disposed) return
this.#cursor.classList.remove(cursorStyles.clicking)
// Force reflow to restart animation
void this.#cursor.offsetHeight
@@ -168,7 +176,7 @@ export class SimulatorMask extends EventTarget {
}
show() {
if (this.shown) return
if (this.shown || this.#disposed) return
this.shown = true
this.motion?.start()
@@ -186,7 +194,7 @@ export class SimulatorMask extends EventTarget {
}
hide() {
if (!this.shown) return
if (!this.shown || this.#disposed) return
this.shown = false
this.motion?.fadeOut()
@@ -200,6 +208,7 @@ export class SimulatorMask extends EventTarget {
}
dispose() {
this.#disposed = true
console.log('dispose SimulatorMask')
this.motion?.dispose()
this.wrapper.remove()
@@ -1,9 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
// @workaround DTS bug
// dts do not work with monorepo path mapping
// disable path mapping for it
"paths": {}
}
}
+1 -5
View File
@@ -1,11 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
"noEmit": false,
"allowImportingTsExtensions": false,
"baseUrl": ".",
"outDir": "dist"
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo"
},
"include": ["**/*.ts", "**/*.js"],
"exclude": ["dist", "node_modules"]
+9 -4
View File
@@ -13,13 +13,18 @@ console.log(chalk.cyan(`📦 Building @page-agent/page-controller`))
export default defineConfig({
clearScreen: false,
plugins: [
dts({ tsconfigPath: './tsconfig.dts.json', bundleTypes: true }),
dts({
bundleTypes: true,
compilerOptions: {
composite: true,
noEmit: false,
emitDeclarationOnly: true,
declaration: true,
},
}),
cssInjectedByJsPlugin({ relativeCSSInjection: true }),
],
publicDir: false,
esbuild: {
keepNames: true,
},
build: {
lib: {
entry: resolve(__dirname, 'src/PageController.ts'),
+19 -9
View File
@@ -1,15 +1,25 @@
{
"name": "@page-agent/ui",
"version": "1.7.1",
"version": "1.8.0",
"type": "module",
"main": "./dist/lib/page-agent-ui.js",
"module": "./dist/lib/page-agent-ui.js",
"types": "./dist/lib/index.d.ts",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": {
"types": "./dist/lib/index.d.ts",
"import": "./dist/lib/page-agent-ui.js",
"default": "./dist/lib/page-agent-ui.js"
"types": "./src/index.ts",
"default": "./src/index.ts"
}
},
"publishConfig": {
"main": "./dist/lib/page-agent-ui.js",
"module": "./dist/lib/page-agent-ui.js",
"types": "./dist/lib/index.d.ts",
"exports": {
".": {
"types": "./dist/lib/index.d.ts",
"import": "./dist/lib/page-agent-ui.js",
"default": "./dist/lib/page-agent-ui.js"
}
}
},
"files": [
@@ -32,7 +42,7 @@
"homepage": "https://alibaba.github.io/page-agent/",
"scripts": {
"build": "vite build",
"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{}})\""
"prepublishOnly": "node ../../scripts/pre-publish.js",
"postpublish": "node ../../scripts/post-publish.js"
}
}
+1 -1
View File
@@ -291,7 +291,7 @@
transition: max-height 0.2s;
.expanded & {
max-height: 400px;
max-height: min(500px, calc(100vh - 200px - var(--height)));
}
.historyItem {
-9
View File
@@ -1,9 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
// @workaround DTS bug
// dts do not work with monorepo path mapping
// disable path mapping for it
"paths": {}
}
}
+1 -5
View File
@@ -1,11 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
"noEmit": false,
"allowImportingTsExtensions": false,
"baseUrl": ".",
"outDir": "dist"
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo"
},
"include": ["**/*.ts", "**/*.js"],
"exclude": ["dist", "node_modules"]
+9 -4
View File
@@ -13,13 +13,18 @@ console.log(chalk.cyan(`📦 Building @page-agent/ui`))
export default defineConfig({
clearScreen: false,
plugins: [
dts({ tsconfigPath: './tsconfig.dts.json', bundleTypes: true }),
dts({
bundleTypes: true,
compilerOptions: {
composite: true,
noEmit: false,
emitDeclarationOnly: true,
declaration: true,
},
}),
cssInjectedByJsPlugin({ relativeCSSInjection: true }),
],
publicDir: false,
esbuild: {
keepNames: true,
},
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
+8 -9
View File
@@ -1,13 +1,12 @@
{
"name": "@page-agent/website",
"private": true,
"version": "1.7.1",
"version": "1.8.0",
"type": "module",
"scripts": {
"dev": "vite --host 0.0.0.0",
"build:website": "vite build",
"preview": "vite preview",
"typecheck": "tsc --noEmit"
"preview": "vite preview"
},
"devDependencies": {
"@radix-ui/react-icons": "^1.3.2",
@@ -16,19 +15,19 @@
"@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tooltip": "^1.2.8",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.1",
"@types/react-dom": "^19.2.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^1.7.0",
"lucide-react": "^1.8.0",
"motion": "^12.38.0",
"next-themes": "^0.4.6",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react": "^19.2.5",
"react-dom": "^19.2.5",
"rough-notation": "^0.5.1",
"simple-icons": "^16.14.0",
"simple-icons": "^16.16.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.5.0",
"tailwindcss": "^4.1.14",
"tailwindcss": "^4.2.2",
"tw-animate-css": "^1.4.0",
"wouter": "^3.9.0"
}
@@ -169,7 +169,6 @@ function highlightSyntax(code: string): string {
const HighlightSyntaxClient: React.FC<HighlightSyntaxProps> = ({ code }) => {
const htmlContent = highlightSyntax(code)
// eslint-disable-next-line react-dom/no-dangerously-set-innerhtml
return <code className={styles.syntax} dangerouslySetInnerHTML={{ __html: htmlContent }} />
}
@@ -140,6 +140,7 @@ function JSConsole({
// 全局console拦截处理
useEffect(() => {
const interceptor = ConsoleInterceptor.getInstance()
let scrollTimer: ReturnType<typeof setTimeout>
const handleGlobalConsole = (type: string, args: unknown[]) => {
const content = args.map((arg) => formatResult(arg)).join(' ')
@@ -152,8 +153,8 @@ function JSConsole({
setOutputs((prev) => [...prev, outputItem])
// 自动滚动到底部
setTimeout(() => {
clearTimeout(scrollTimer)
scrollTimer = setTimeout(() => {
if (outputRef.current) {
outputRef.current.scrollTop = outputRef.current.scrollHeight
}
@@ -164,6 +165,7 @@ function JSConsole({
return () => {
interceptor.unsubscribe(handleGlobalConsole)
clearTimeout(scrollTimer)
}
}, [])
+2 -2
View File
@@ -1,8 +1,8 @@
// Demo build (auto-init with demo LLM, for quick testing)
export const CDN_DEMO_URL =
'https://cdn.jsdelivr.net/npm/page-agent@1.7.1/dist/iife/page-agent.demo.js'
'https://cdn.jsdelivr.net/npm/page-agent@1.8.0/dist/iife/page-agent.demo.js'
export const CDN_DEMO_CN_URL =
'https://registry.npmmirror.com/page-agent/1.7.1/files/dist/iife/page-agent.demo.js'
'https://registry.npmmirror.com/page-agent/1.8.0/files/dist/iife/page-agent.demo.js'
// Demo LLM for website testing (homepage quick trial uses flash)
export const DEMO_MODEL = 'qwen3.5-flash'
+4 -5
View File
@@ -9,25 +9,24 @@ const LanguageContext = createContext<{
} | null>(null)
export function LanguageProvider({ children }: { children: ReactNode }) {
const [language, setLang] = useState<Lang>(() => {
const [language, setLanguage] = useState<Lang>(() => {
const stored = localStorage.getItem('language') as Lang
if (stored === 'zh-CN' || stored === 'en-US') return stored
return navigator.language.startsWith('zh') ? 'zh-CN' : 'en-US'
})
const setLanguage = (lang: Lang) => {
setLang(lang)
const switchLanguage = (lang: Lang) => {
setLanguage(lang)
localStorage.setItem('language', lang)
}
return (
<LanguageContext value={{ language, isZh: language === 'zh-CN', setLanguage }}>
<LanguageContext value={{ language, isZh: language === 'zh-CN', setLanguage: switchLanguage }}>
{children}
</LanguageContext>
)
}
// eslint-disable-next-line react-refresh/only-export-components
export function useLanguage() {
const ctx = use(LanguageContext)
if (!ctx) throw new Error('useLanguage must be used within LanguageProvider')
@@ -103,25 +103,25 @@ function FormatErrorsContent(isZh: boolean) {
<>
{' '}
<a
href="https://github.com/alibaba/page-agent/discussions"
href="https://github.com/alibaba/page-agent/issues"
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 dark:text-blue-400 underline underline-offset-2"
>
GitHub Discussions
GitHub Issues
</a>{' '}
</>
) : (
<>
If the above steps don't help, join the{' '}
If the above steps don't help, open a{' '}
<a
href="https://github.com/alibaba/page-agent/discussions"
href="https://github.com/alibaba/page-agent/issues"
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 dark:text-blue-400 underline underline-offset-2"
>
GitHub Discussions
GitHub Issue
</a>{' '}
with your model name and error details.
</>
@@ -1,4 +1,3 @@
/* eslint-disable react-dom/no-dangerously-set-innerhtml */
import type { PageAgent as PageAgentType } from 'page-agent'
import { useEffect, useState } from 'react'
import { Link, useSearchParams } from 'wouter'
@@ -46,10 +45,11 @@ export default function HeroSection() {
: 'Goto docs in navigation bar, find Quick-Start section, and summarize in markdown'
const [task, setTask] = useState(() => defaultTask)
useEffect(() => {
const [prevDefaultTask, setPrevDefaultTask] = useState(defaultTask)
if (prevDefaultTask !== defaultTask) {
setPrevDefaultTask(defaultTask)
setTask(defaultTask)
}, [defaultTask])
}
const [params] = useSearchParams()
const isOther = params.has('try_other')
+6 -4
View File
@@ -18,10 +18,12 @@ function ScrollToTop() {
export default function Router() {
useEffect(() => {
const schedule = globalThis.requestIdleCallback ?? ((cb: () => void) => setTimeout(cb, 1))
const cancel = globalThis.cancelIdleCallback ?? clearTimeout
const id = schedule(() => docsImport())
return () => cancel(id)
if ('requestIdleCallback' in globalThis) {
const id = requestIdleCallback(() => docsImport())
return () => cancelIdleCallback(id)
}
const id = setTimeout(() => docsImport(), 1)
return () => clearTimeout(id)
}, [])
return (
+3 -24
View File
@@ -2,31 +2,10 @@
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
"noEmit": false,
"allowImportingTsExtensions": false,
"baseUrl": ".",
"outDir": "dist",
"paths": {
// Self root
"@/*": ["src/*"],
"@page-agent/llms": ["../llms/src/index.ts"],
"@page-agent/page-controller": ["../page-controller/src/PageController.ts"],
"@page-agent/core": ["../core/src/PageAgentCore.ts"],
"@page-agent/ui": ["../ui/src/index.ts"],
"page-agent": ["../page-agent/src/PageAgent.ts"]
"@/*": ["./src/*"]
}
},
"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["dist", "node_modules"],
"references": [
//
{ "path": "../llms" },
{ "path": "../page-controller" },
{ "path": "../core" },
{ "path": "../ui" },
{ "path": "../page-agent" }
]
"include": ["src/**/*.ts", "src/**/*.tsx"],
"exclude": ["dist", "node_modules"]
}
-9
View File
@@ -90,16 +90,7 @@ export default defineConfig(({ mode }) => ({
},
resolve: {
alias: {
// Self root
'@': resolve(__dirname, 'src'),
// Monorepo packages (always bundle local code instead of npm versions)
'@page-agent/page-controller': resolve(__dirname, '../page-controller/src/PageController.ts'),
'@page-agent/llms': resolve(__dirname, '../llms/src/index.ts'),
'@page-agent/core': resolve(__dirname, '../core/src/PageAgentCore.ts'),
'@page-agent/ui': resolve(__dirname, '../ui/src/index.ts'),
'page-agent': resolve(__dirname, '../page-agent/src/PageAgent.ts'),
},
},
define: {
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env node
/**
* Restore package.json from the backup created by pre-publish.js,
* then clean up temporary files (backup, LICENSE, README.md).
*
* Usage: node ../../scripts/post-publish.js (from a package dir)
*/
import { existsSync, readFileSync, renameSync, rmSync } from 'fs'
import { join } from 'path'
const pkgPath = join(process.cwd(), 'package.json')
const bakPath = pkgPath + '.bak'
if (!existsSync(bakPath)) {
console.log(' No backup found, nothing to restore.')
process.exit(0)
}
const name = JSON.parse(readFileSync(pkgPath, 'utf-8')).name
renameSync(bakPath, pkgPath)
console.log(' ✓ package.json restored from backup')
rmSync(join(process.cwd(), 'LICENSE'), { force: true })
console.log(' ✓ LICENSE removed')
if (name === 'page-agent') {
rmSync(join(process.cwd(), 'README.md'), { force: true })
console.log(' ✓ README.md removed')
}
+42
View File
@@ -0,0 +1,42 @@
#!/usr/bin/env node
/**
* Backup package.json, then rewrite it for publish:
* - Promote `publishConfig` fields to top level
* - Remove `publishConfig` (npm doesn't need the wrapper)
* - Copy LICENSE (and README.md for the main package)
*
* Usage: node ../../scripts/pre-publish.js (from a package dir)
*/
import { copyFileSync, readFileSync, writeFileSync } from 'fs'
import { join } from 'path'
const pkgPath = join(process.cwd(), 'package.json')
const raw = readFileSync(pkgPath, 'utf-8')
const pkg = JSON.parse(raw)
const publishConfig = pkg.publishConfig
if (!publishConfig) {
console.log(' No publishConfig found, skipping manifest rewrite.')
process.exit(0)
}
// Backup the original file byte-for-byte
copyFileSync(pkgPath, pkgPath + '.bak')
console.log(' ✓ package.json backed up')
for (const [field, value] of Object.entries(publishConfig)) {
pkg[field] = value
}
delete pkg.publishConfig
writeFileSync(pkgPath, JSON.stringify(pkg, null, ' ') + '\n')
console.log(` ✓ Manifest rewritten for publish (${Object.keys(publishConfig).join(', ')})`)
const root = join(process.cwd(), '../..')
copyFileSync(join(root, 'LICENSE'), join(process.cwd(), 'LICENSE'))
console.log(' ✓ LICENSE copied')
if (pkg.name === 'page-agent') {
copyFileSync(join(root, 'README.md'), join(process.cwd(), 'README.md'))
console.log(' ✓ README.md copied')
}
+6 -8
View File
@@ -1,18 +1,14 @@
{
"compilerOptions": {
"composite": true,
"target": "ES2024",
"target": "es2025",
"useDefineForClassFields": true,
"lib": ["ES2024", "DOM", "DOM.Iterable"],
"module": "ESNext",
"lib": ["ESNext", "DOM"],
"module": "esnext",
"skipLibCheck": true,
"allowJs": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
// "baseUrl": "src",
"baseUrl": ".",
"outDir": "dist",
// "incremental": true,
/* Bundler mode */
"moduleResolution": "bundler",
@@ -27,6 +23,8 @@
"noUnusedParameters": false,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
"noUncheckedSideEffectImports": true,
"types": ["node"]
}
}
-14
View File
@@ -1,14 +0,0 @@
// this is only for IDE ts language server to work.
// do not use this for building or linting.
{
"extends": "./tsconfig.base.json",
"references": [
{ "path": "./packages/page-controller" },
{ "path": "./packages/ui" },
{ "path": "./packages/llms" },
{ "path": "./packages/page-agent" },
{ "path": "./packages/website" }
],
"include": ["packages/*/src/**/*.ts", "packages/*/src/**/*.tsx"],
"exclude": ["node_modules", "dist", "packages/*/dist"]
}
+25
View File
@@ -0,0 +1,25 @@
// Unified typecheck config for all lib/website packages.
// Run: tsc --noEmit -p tsconfig.typecheck.json
// Extension is checked separately (WXT has its own tsconfig base).
//
// With source-first package.json exports, TS resolves @page-agent/*
// to sibling src/ via workspace symlinks — no paths mapping needed.
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"composite": false,
"noEmit": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.typecheck.tsbuildinfo",
"paths": {
"@/*": ["./packages/website/src/*"]
}
},
"include": [
"packages/llms/src/**/*",
"packages/page-controller/src/**/*",
"packages/ui/src/**/*",
"packages/core/src/**/*",
"packages/page-agent/src/**/*",
"packages/website/src/**/*"
]
}