diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml new file mode 100644 index 00000000..a26d2c27 --- /dev/null +++ b/.gitea/workflows/ci.yaml @@ -0,0 +1,36 @@ +name: CI + +on: + pull_request: + push: + branches-ignore: + - main + - release/* + +env: + RUNNER_TOOL_CACHE: /toolcache + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: pnpm/action-setup@v4 + + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: "20.x" + cache: 'pnpm' + + - name: Install + run: pnpm install --frozen-lockfile + + - name: Typecheck + run: pnpm run typecheck + + - name: Build + run: pnpm run build + + - name: Check URL inventory, i18n parity, and frontmatter conventions + run: pnpm run check diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml index f0ffc171..3f96a947 100644 --- a/.gitea/workflows/deploy.yaml +++ b/.gitea/workflows/deploy.yaml @@ -35,6 +35,7 @@ jobs: run: | pnpm install --frozen-lockfile pnpm run build + pnpm run check - name: Set up QEMU # uses: docker/setup-qemu-action@v3 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..519a3e4d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,64 @@ +# 贡献指南 / Contributing Guide + +> EN summary: file path = doc ID = published URL, no `id:`/`sidebar_position:` frontmatter, no number-prefixed filenames, `title:` is the only page-title source (no body `# H1`), images live in a sibling `.assets/` folder, and every `docs/**/*.md` needs an `i18n/en/docusaurus-plugin-content-docs/current/**/*.md` mirror. Run `pnpm run check` before opening a PR — it enforces all of this. See [REFACTOR_PROPOSAL.md](./REFACTOR_PROPOSAL.md) for the full rationale. + +本文档记录本仓库的文档结构约定,帮助人类贡献者和 AI Agent 在不读遍全部历史讨论的情况下,正确地新增/修改文档。 + +## 核心约定 + +| 关注点 | 唯一来源 | +|---|---| +| URL / doc ID | 文件路径本身(不使用 `id:`、不使用数字前缀) | +| 页面标题 / 侧边栏文字 / `` | frontmatter `title:`(可选 `sidebar_label:` 用于侧边栏简称) | +| 侧边栏排序 | `sidebars.js`,三个 sidebar(`use`/`dev`/`change`)均为显式列表 | +| 图片 | `<文档名>.assets/` 同级目录 | +| 内部链接 | 指向 `.md` 文件的相对路径(构建时会校验) | +| URL 不变契约 | 提交的 `scripts/url-inventory.txt`,每次 PR 由 CI 校验 | + +**为什么这样做**:过去 `id:`/`sidebar_position:`/数字前缀/`README.md` 四种机制同时存在,导致侧边栏文字和页面标题可能不一致(例如"VSCode 扩展开发脚本" vs 页面实际标题"使用 VSCode 开发脚本"),且文件名与 URL 无法直接对应。现在文件路径就是 URL,看文件名就知道页面在哪。 + +## 新增一篇文档 + +1. 在 `docs/<section>/` 下创建 `xxx.md`(不要加数字前缀,不要用 `README.md`——除非确实是该目录的落地页,此时用 `index.md`)。 +2. frontmatter 只写 `title:`(必需)和可选的 `sidebar_label:`;不要写 `id:` 或 `sidebar_position:`。 +3. 正文**不要**再写一个 `# 标题` 作为 H1——`title:` 会自动渲染为页面标题。 +4. 在 `sidebars.js` 对应的数组里加一行 `"section/xxx"`(除非这是一个故意不出现在侧边栏的隐藏页面,如 `use/install_comple`)。 +5. 在 `i18n/en/docusaurus-plugin-content-docs/current/<section>/xxx.md` 创建英文镜像,路径和文件名必须完全一致。 +6. 图片放在 `docs/<section>/xxx.assets/` 下,用 `./xxx.assets/foo.png` 引用;纯 UI 截图等语言无关的图片,英文版可以用 `@site/docs/<section>/xxx.assets/foo.png` 直接复用中文版的图片,不必重复存一份二进制文件。 +7. 跑一次 `pnpm run build && pnpm run check`,确认三项检查全部通过。 + +## 新增一条更新日志 + +`change/` 下的版本文件(`v1.x.md`)不使用数字前缀排序;在 `sidebars.js` 的 `change` 数组里手动插入新版本号(数组顺序即侧边栏顺序,新版本插在最前面)。`change/beta-changelog.md` 是 Beta 版本的单独更新日志。 + +## 加载不变的 URL(改动前必须确认不受影响) + +以下 URL 被扩展程序硬编码调用,**任何重构都不能改变它们**: + +- `/docs/script_installation/` +- `/docs/use/install_comple/`(`install_comple` 是历史拼写,故意保留,不是笔误) +- `/uninstall/` + +`scripts/check-url-inventory.mjs` 会在每次 `pnpm run build` 后对比 `scripts/url-inventory.txt`;如果你的改动导致路由变化,CI 会失败并列出具体差异。**新增**路由是允许的(比如加一个 redirect),但需要在同一个 PR 里用 `node scripts/check-url-inventory.mjs --write` 更新这个文件,让 review 能看到你有意添加了什么。 + +## 翻译对照表 + +| 中文 | English | +|---|---| +| 脚本猫 | ScriptCat | +| 用户脚本 | user script | +| 后台脚本 | background script | +| 定时脚本 | scheduled script | +| 油猴 | Tampermonkey | + +英文标题结构应尽量与中文一一对应(标题层级、顺序一致),这样跨语言的锚点链接更容易对齐;注意 Docusaurus 生成的锚点是基于**渲染后的英文标题文本**,不是中文锚点的直接翻译(例如 `## Scheduled Script (\`@crontab\`)` 生成的锚点是 `#scheduled-script-crontab`,需要用构建产物核实,不要凭感觉猜。 + +## 本地检查命令 + +```bash +pnpm run build # 构建两个语言版本,onBrokenLinks/onBrokenAnchors 设置为 throw +pnpm run check # 依次跑 url 一致性 / i18n 覆盖率 / frontmatter 规范三项检查 +pnpm run check:urls # 单独跑 URL 不变契约检查 +pnpm run check:i18n # 单独跑中英文档配对检查 +pnpm run check:frontmatter # 单独跑 title/id/sidebar_position/H1 规范检查 +``` diff --git a/docs/about/README.md b/docs/about/index.md similarity index 100% rename from docs/about/README.md rename to docs/about/index.md diff --git a/docs/change/beta.md b/docs/change/beta-changelog.md similarity index 99% rename from docs/change/beta.md rename to docs/change/beta-changelog.md index 6c80e5a8..8b5b450f 100644 --- a/docs/change/beta.md +++ b/docs/change/beta-changelog.md @@ -1,18 +1,16 @@ --- -id: beta-changelog -sidebar_position: 1 +title: Beta 更新日志 --- import GithubStar from '@site/src/components/GithubStar'; import SponsorBlock from '@site/src/components/SponsorBlock/zh.mdx'; -# Beta 更新日志 <GithubStar variant="bar" scene="changelog" /> <SponsorBlock /> -脚本猫的版本发布主要分为两条分支: 正式版本与预发布版本,正式版本更新日志请看:[更新日志](./README.md) +脚本猫的版本发布主要分为两条分支: 正式版本与预发布版本,正式版本更新日志请看:[更新日志](./index.md) 预发布版本是在正式发布之前的版本.它们通常用于测试新功能,预发布版本的版本号包含一个预发布标识符,例如: `1.0.0-beta.1`. diff --git a/docs/change/README.md b/docs/change/index.md similarity index 99% rename from docs/change/README.md rename to docs/change/index.md index cb393d5c..bd7cf7e8 100644 --- a/docs/change/README.md +++ b/docs/change/index.md @@ -1,18 +1,16 @@ --- -id: change -sidebar_position: 1 +title: 更新日志 --- import GithubStar from '@site/src/components/GithubStar'; import SponsorBlock from '@site/src/components/SponsorBlock/zh.mdx'; -# 更新日志 <GithubStar variant="bar" scene="changelog" /> <SponsorBlock /> -Beta 版本更新日志请查看 [Beta 更新日志](./beta.md) +Beta 版本更新日志请查看 [Beta 更新日志](./beta-changelog.md) ⚠️ 请注意,如果你使用的 Windows 8/7/XP 系统,或者浏览器内核版本低于\<120,需要自行手动安装[旧版脚本猫](https://bbs.tampermonkey.net.cn/thread-3068-1-1.html),v0.16.x 是最后一个支持 Manifest V2 的版本,安装步骤可以参考:[加载解压缩方式安装扩展](/docs/use/use/#%E5%8A%A0%E8%BD%BD%E8%A7%A3%E5%8E%8B%E7%BC%A9%E6%96%B9%E5%BC%8F%E5%AE%89%E8%A3%85%E6%89%A9%E5%B1%95)。 @@ -2124,7 +2122,7 @@ Firefox 的 Manifest V3 版本还在筹备中。 - 界面 UI 调整 - 增加`GM_xmlhttpRequest`所支持的`unsafe header`和支持`arraybuffer`,`nocache`,`user`,`password`,`overrideMimeType`,功能 -- 增加运行日志查看功能,点击面板`运行状态`栏即可查看最后一次运行日志.具体请看:[console](/dev/meta.md#console)功能 +- 增加运行日志查看功能,点击面板`运行状态`栏即可查看最后一次运行日志.具体请看:[console](/dev/background.md#日志)功能 - 修复`GM_notification`的`done`回调 - 优化调整代码列表排序逻辑 - 优化最后更新栏点击可进行脚本的手动检查更新 diff --git a/docs/change/img/README.assets/iShot_2024-04-23_11.14.37.gif b/docs/change/v0.16.assets/iShot_2024-04-23_11.14.37.gif similarity index 100% rename from docs/change/img/README.assets/iShot_2024-04-23_11.14.37.gif rename to docs/change/v0.16.assets/iShot_2024-04-23_11.14.37.gif diff --git a/docs/change/img/README.assets/image-20240423111623608.png b/docs/change/v0.16.assets/image-20240423111623608.png similarity index 100% rename from docs/change/img/README.assets/image-20240423111623608.png rename to docs/change/v0.16.assets/image-20240423111623608.png diff --git a/docs/change/img/v0.16.assets/image-20240423113515332.png b/docs/change/v0.16.assets/image-20240423113515332.png similarity index 100% rename from docs/change/img/v0.16.assets/image-20240423113515332.png rename to docs/change/v0.16.assets/image-20240423113515332.png diff --git a/docs/change/img/README.assets/setting.png b/docs/change/v0.16.assets/setting.png similarity index 100% rename from docs/change/img/README.assets/setting.png rename to docs/change/v0.16.assets/setting.png diff --git a/docs/change/v0.16.md b/docs/change/v0.16.md index 9ba3ecf8..58160113 100644 --- a/docs/change/v0.16.md +++ b/docs/change/v0.16.md @@ -1,14 +1,12 @@ --- -sidebar_position: 10000 +title: v0.16 --- -# v0.16 - ## v0.16.1 ## 最后更新添加排序功能 -![image-20240423113515332](img/v0.16.assets/image-20240423113515332.png) +![image-20240423113515332](v0.16.assets/image-20240423113515332.png) ## v0.16.2 @@ -16,13 +14,13 @@ sidebar_position: 10000 默认配置为 5 个菜单项,超过 5 个菜单项时,菜单会自动隐藏,点击更多按钮展示隐藏的菜单项。 -![alt text](img/README.assets/setting.png) +![alt text](v0.16.assets/setting.png) -![iShot_2024-04-23_11.14.37](img/README.assets/iShot_2024-04-23_11.14.37.gif) +![iShot_2024-04-23_11.14.37](v0.16.assets/iShot_2024-04-23_11.14.37.gif) ## 脚本列表添加列调整隐藏操作 -![image-20240423111623608](img/README.assets/image-20240423111623608.png) +![image-20240423111623608](v0.16.assets/image-20240423111623608.png) ## v0.16.3 diff --git a/docs/change/img/v0.17.assets/image-20250620165421754.png b/docs/change/v0.17.assets/image-20250620165421754.png similarity index 100% rename from docs/change/img/v0.17.assets/image-20250620165421754.png rename to docs/change/v0.17.assets/image-20250620165421754.png diff --git a/docs/change/img/v0.17.assets/image-20250620165529101.png b/docs/change/v0.17.assets/image-20250620165529101.png similarity index 100% rename from docs/change/img/v0.17.assets/image-20250620165529101.png rename to docs/change/v0.17.assets/image-20250620165529101.png diff --git a/docs/change/img/v0.17.assets/image-20250620165640030.png b/docs/change/v0.17.assets/image-20250620165640030.png similarity index 100% rename from docs/change/img/v0.17.assets/image-20250620165640030.png rename to docs/change/v0.17.assets/image-20250620165640030.png diff --git a/docs/change/v0.17.md b/docs/change/v0.17.md index 2577c2c7..b03e2b6e 100644 --- a/docs/change/v0.17.md +++ b/docs/change/v0.17.md @@ -1,9 +1,7 @@ --- -sidebar_position: 9999 +title: v0.17 --- -# v0.17 - 从 v0.17.0 开始,脚本猫升级为 manifest v3,并且切换储存引擎`indexedDB`为`chrome.storage.local`,储存引擎切换会自动打开本页面并重启扩展,如果发现数据出现问题,请前往[Github](https://github.com/scriptscat/scriptcat/issues)给我们反馈。 ## v0.17.0-alpha @@ -18,16 +16,16 @@ sidebar_position: 9999 ### 弹出页面增加快速检查脚本更新 -![image-20250620165421754](img/v0.17.assets/image-20250620165421754.png) +![image-20250620165421754](v0.17.assets/image-20250620165421754.png) ### 实现网站黑名单功能 -![image-20250620165529101](img/v0.17.assets/image-20250620165529101.png) +![image-20250620165529101](v0.17.assets/image-20250620165529101.png) ### UserConfig添加switch类型 -![image-20250620165640030](img/v0.17.assets/image-20250620165640030.png) +![image-20250620165640030](v0.17.assets/image-20250620165640030.png) diff --git a/docs/change/v1.1.md b/docs/change/v1.1.md index 15995c94..4d9fb845 100644 --- a/docs/change/v1.1.md +++ b/docs/change/v1.1.md @@ -1,9 +1,7 @@ --- -sidebar_position: 9998 +title: v1.1 --- -# v1.1 - ## 网盘平台 新增了Dropbox支持 diff --git a/docs/change/img/v1.2.assets/08c2889f-3029-4d3c-b180-c52d77c8077c.png b/docs/change/v1.2.assets/08c2889f-3029-4d3c-b180-c52d77c8077c.png similarity index 100% rename from docs/change/img/v1.2.assets/08c2889f-3029-4d3c-b180-c52d77c8077c.png rename to docs/change/v1.2.assets/08c2889f-3029-4d3c-b180-c52d77c8077c.png diff --git a/docs/change/img/v1.2.assets/image-20251016225931823.png b/docs/change/v1.2.assets/image-20251016225931823.png similarity index 100% rename from docs/change/img/v1.2.assets/image-20251016225931823.png rename to docs/change/v1.2.assets/image-20251016225931823.png diff --git a/docs/change/img/v1.2.assets/image-20251016230129315.png b/docs/change/v1.2.assets/image-20251016230129315.png similarity index 100% rename from docs/change/img/v1.2.assets/image-20251016230129315.png rename to docs/change/v1.2.assets/image-20251016230129315.png diff --git a/docs/change/img/v1.2.assets/image-20251023103730266.png b/docs/change/v1.2.assets/image-20251023103730266.png similarity index 100% rename from docs/change/img/v1.2.assets/image-20251023103730266.png rename to docs/change/v1.2.assets/image-20251023103730266.png diff --git a/docs/change/img/v1.2.assets/image-20251204174034940.png b/docs/change/v1.2.assets/image-20251204174034940.png similarity index 100% rename from docs/change/img/v1.2.assets/image-20251204174034940.png rename to docs/change/v1.2.assets/image-20251204174034940.png diff --git a/docs/change/v1.2.md b/docs/change/v1.2.md index 97356c09..9ced4b43 100644 --- a/docs/change/v1.2.md +++ b/docs/change/v1.2.md @@ -1,40 +1,38 @@ --- -sidebar_position: 9997 +title: v1.2 --- -# v1.2 - 修复版本更新不会再主动打开更新日志页面 ## 脚本列表侧边栏 [#794](https://github.com/scriptscat/scriptcat/issues/794) 增加了侧边栏可以进行高级筛选,增加了标签功能,在脚本->设置中可以对标签进行修改调整 -![image-20251016230129315](img/v1.2.assets/image-20251016230129315.png) +![image-20251016230129315](v1.2.assets/image-20251016230129315.png) ## 卡片视图 [#860](https://github.com/scriptscat/scriptcat/issues/860) 现在增加卡片视图,在首次启动时会自动切换卡片视图和表格视图,让窄屏能够更好的查看脚本信息 -![image-20251023103730266](img/v1.2.assets/image-20251023103730266.png) +![image-20251023103730266](v1.2.assets/image-20251023103730266.png) ## 更友好的检查更新逻辑 [#755](https://github.com/scriptscat/scriptcat/issues/755) 现在优化了检查更新的逻辑,不会再一股脑的弹出所有脚本的更新提示,而是会合并成一个更新窗口,你可以在这个窗口中选择要更新的脚本,也可以一键更新全部,并且会显示脚本的变动程度 -![image-20251016225931823](img/v1.2.assets/image-20251016225931823.png) +![image-20251016225931823](v1.2.assets/image-20251016225931823.png) ## 增加编辑器配置和编辑器类型定义 [#708](https://github.com/scriptscat/scriptcat/pull/708) 现在可以自定义编辑器配置和编辑器类型定义,编辑器配置可以参考 `tsconfig.json` 中的 [compilerOptions](https://www.typescriptlang.org/tsconfig/#compilerOptions) 进行编写 -![08c2889f-3029-4d3c-b180-c52d77c8077c](img/v1.2.assets/08c2889f-3029-4d3c-b180-c52d77c8077c.png) +![08c2889f-3029-4d3c-b180-c52d77c8077c](v1.2.assets/08c2889f-3029-4d3c-b180-c52d77c8077c.png) ## 后台运行选项 [#1048](https://github.com/scriptscat/scriptcat/pull/1048) 在`设置-运行时`中增加了后台运行选项,启用后,即使关闭所有窗口,浏览器仍会在后台运行,并最小化到系统托盘,直到您手动退出浏览器。这使后台脚本能够继续运行。 -![image-20251204174034940](img/v1.2.assets/image-20251204174034940.png) +![image-20251204174034940](v1.2.assets/image-20251204174034940.png) ## API 更新 diff --git a/docs/change/v1.3.md b/docs/change/v1.3.md index 7cbd0a7e..637adfee 100644 --- a/docs/change/v1.3.md +++ b/docs/change/v1.3.md @@ -1,9 +1,7 @@ --- -sidebar_position: 9996 +title: v1.3 --- -# v1.3 - ## 新的脚本安装逻辑 [#842](https://github.com/scriptscat/scriptcat/issues/842) 重新设计了脚本安装流程,不再依赖外部网站跳转打开新窗口进行安装,而是直接在当前页面内完成安装。同时优化了安装页面的布局,支持响应式显示,代码预览区域可滚动查看,下载失败等错误也会直接在页面中展示。 diff --git a/docs/change/v1.4.md b/docs/change/v1.4.md index c5ab5983..4cd87d9c 100644 --- a/docs/change/v1.4.md +++ b/docs/change/v1.4.md @@ -1,9 +1,7 @@ --- -sidebar_position: 9995 +title: v1.4 — Agent 智能助手 --- -# v1.4 — Agent 智能助手 - :::caution 测试阶段 v1.4 目前仍处于测试阶段,以下功能和 API 可能会在正式发布前进行调整。欢迎试用并反馈问题。 ::: diff --git a/docs/dev/agent/builtin-tools.md b/docs/dev/agent/agent-builtin-tools.md similarity index 99% rename from docs/dev/agent/builtin-tools.md rename to docs/dev/agent/agent-builtin-tools.md index 9971ac2f..528e9833 100644 --- a/docs/dev/agent/builtin-tools.md +++ b/docs/dev/agent/agent-builtin-tools.md @@ -1,10 +1,7 @@ --- -id: agent-builtin-tools -sidebar_position: 10 +title: 内置工具参考 --- -# 内置工具参考 - Agent 内置了一系列工具供 AI 在对话中自动调用。这些工具在持久化对话中默认可用,脚本开发者通常不需要直接调用它们——AI 会根据用户意图自动选择合适的工具。 了解这些工具的能力有助于编写更好的系统提示词和自定义工具。 diff --git a/docs/dev/agent/conversation.md b/docs/dev/agent/agent-conversation.md similarity index 99% rename from docs/dev/agent/conversation.md rename to docs/dev/agent/agent-conversation.md index 7888fcb8..d26de51d 100644 --- a/docs/dev/agent/conversation.md +++ b/docs/dev/agent/agent-conversation.md @@ -1,10 +1,7 @@ --- -id: agent-conversation -sidebar_position: 2 +title: 对话 API --- -# 对话 API - `@grant CAT.agent.conversation` 对话 API 是 Agent 系统的核心,允许脚本创建 AI 对话、发送消息并接收回复。 diff --git a/docs/dev/agent/dom.md b/docs/dev/agent/agent-dom.md similarity index 99% rename from docs/dev/agent/dom.md rename to docs/dev/agent/agent-dom.md index 963aeed4..049b5353 100644 --- a/docs/dev/agent/dom.md +++ b/docs/dev/agent/agent-dom.md @@ -1,10 +1,7 @@ --- -id: agent-dom -sidebar_position: 3 +title: DOM 操作 API --- -# DOM 操作 API - `@grant CAT.agent.dom` DOM 操作 API 提供完整的浏览器页面自动化能力,包括导航、内容读取、截图、表单交互和 DOM 监控。 diff --git a/docs/dev/agent/mcp.md b/docs/dev/agent/agent-mcp.md similarity index 98% rename from docs/dev/agent/mcp.md rename to docs/dev/agent/agent-mcp.md index 06f27de9..5f95d336 100644 --- a/docs/dev/agent/mcp.md +++ b/docs/dev/agent/agent-mcp.md @@ -1,10 +1,7 @@ --- -id: agent-mcp -sidebar_position: 8 +title: MCP 管理 API --- -# MCP 管理 API - `@grant CAT.agent.mcp` MCP([Model Context Protocol](https://modelcontextprotocol.io/))管理 API 允许脚本管理 MCP 服务器连接,MCP 服务器提供的工具会自动注册到 Agent,供 AI 对话调用。 diff --git a/docs/dev/agent/model.md b/docs/dev/agent/agent-model.md similarity index 97% rename from docs/dev/agent/model.md rename to docs/dev/agent/agent-model.md index 9d5dd691..fcfb8bcb 100644 --- a/docs/dev/agent/model.md +++ b/docs/dev/agent/agent-model.md @@ -1,10 +1,7 @@ --- -id: agent-model -sidebar_position: 6 +title: 模型查询 API --- -# 模型查询 API - `@grant CAT.agent.model` 模型查询 API 提供只读访问,查询用户在管理页面中已配置的模型信息。出于安全考虑,API Key 不会暴露给脚本。 diff --git a/docs/dev/agent/opfs.md b/docs/dev/agent/agent-opfs.md similarity index 99% rename from docs/dev/agent/opfs.md rename to docs/dev/agent/agent-opfs.md index 87205117..cd396c81 100644 --- a/docs/dev/agent/opfs.md +++ b/docs/dev/agent/agent-opfs.md @@ -1,10 +1,7 @@ --- -id: agent-opfs -sidebar_position: 7 +title: OPFS 文件 API --- -# OPFS 文件 API - `@grant CAT.agent.opfs` OPFS(Origin Private File System)文件 API 允许脚本在 Agent 工作区中读写文件。所有路径相对于 `agents/workspace/` 目录。 diff --git a/docs/dev/agent/skill-dev.md b/docs/dev/agent/agent-skill-dev.md similarity index 99% rename from docs/dev/agent/skill-dev.md rename to docs/dev/agent/agent-skill-dev.md index 5ee0d89d..1351f0bb 100644 --- a/docs/dev/agent/skill-dev.md +++ b/docs/dev/agent/agent-skill-dev.md @@ -1,10 +1,7 @@ --- -id: agent-skill-dev -sidebar_position: 9 +title: Skill 开发指南 --- -# Skill 开发指南 - Skill 是 Agent 系统的扩展包,由**提示词 + 工具脚本 + 参考资料**组合而成。通过 Skill,可以为 AI 注入专业领域知识和自定义工具能力。 ## Skill 目录结构 diff --git a/docs/dev/agent/skill-install.md b/docs/dev/agent/agent-skill-install.md similarity index 95% rename from docs/dev/agent/skill-install.md rename to docs/dev/agent/agent-skill-install.md index 7f6129fc..39cdc568 100644 --- a/docs/dev/agent/skill-install.md +++ b/docs/dev/agent/agent-skill-install.md @@ -1,10 +1,7 @@ --- -id: agent-skill-install -sidebar_position: 3.5 +title: Skill 安装与使用 --- -# Skill 安装与使用 - Skill 是 Agent 的扩展能力包,为 AI 注入专业领域知识和自定义工具。本页介绍如何安装、配置和管理 Skill。 :::tip 官方 Skill 仓库 @@ -95,5 +92,5 @@ const conv = await CAT.agent.conversation.create({ ## 了解更多 -- [Skill 管理 API](./agent-skill) — 通过脚本编程式管理 Skill -- [Skill 开发指南](./agent-skill-dev) — 创建自己的 Skill +- [Skill 管理 API](./agent-skill.md) — 通过脚本编程式管理 Skill +- [Skill 开发指南](./agent-skill-dev.md) — 创建自己的 Skill diff --git a/docs/dev/agent/skill.md b/docs/dev/agent/agent-skill.md similarity index 98% rename from docs/dev/agent/skill.md rename to docs/dev/agent/agent-skill.md index 52629b3b..02fd6d1d 100644 --- a/docs/dev/agent/skill.md +++ b/docs/dev/agent/agent-skill.md @@ -1,10 +1,7 @@ --- -id: agent-skill -sidebar_position: 4 +title: Skill 管理 API --- -# Skill 管理 API - `@grant CAT.agent.skills` Skill 管理 API 允许脚本查询、安装、卸载和调用 Skill 扩展包。 diff --git a/docs/dev/agent/task.md b/docs/dev/agent/agent-task.md similarity index 98% rename from docs/dev/agent/task.md rename to docs/dev/agent/agent-task.md index 6659038d..a81fda97 100644 --- a/docs/dev/agent/task.md +++ b/docs/dev/agent/agent-task.md @@ -1,10 +1,7 @@ --- -id: agent-task -sidebar_position: 5 +title: 定时任务 API --- -# 定时任务 API - `@grant CAT.agent.task` 定时任务 API 允许脚本创建基于 Cron 表达式的定时任务,支持两种执行模式。 diff --git a/docs/dev/agent/index.md b/docs/dev/agent/index.md index 02b3029e..e4cc18bc 100644 --- a/docs/dev/agent/index.md +++ b/docs/dev/agent/index.md @@ -1,10 +1,7 @@ --- -id: agent -sidebar_position: 1 +title: Agent 智能助手 --- -# Agent 智能助手 - :::caution 测试阶段 Agent 功能目前仍处于测试阶段,以下 API 和行为可能会在正式发布前进行调整。 ::: diff --git a/docs/dev/api.md b/docs/dev/api.md index d065cefd..fa33e1c1 100644 --- a/docs/dev/api.md +++ b/docs/dev/api.md @@ -1,9 +1,7 @@ --- -id: api +title: API 文档 --- -# API 文档 - ## 说明 本扩展 API 定义参考 [Tampermonkey 文档](https://www.tampermonkey.net/documentation.php),由于时间和精力问题,只实现了部分 API,后续将继续迭代。本扩展进行扩充或者与原 GM 不同的 API 将在文档中特殊标注(使用 * 号)。对于某些 API 还提供了同步函数,同步函数规则:`GM.*`,具体请看文档内容。 @@ -44,7 +42,7 @@ GM_log("调试信息", "debug"); ### GM_get/set/deleteValue -从储存中获取或者设置值,数据在同一 [**storageName**](meta.md#storagename-%F0%9F%A7%AA) 中可以共享,且可以实时的同步。 +从储存中获取或者设置值,数据在同一 [**storageName**](meta.md#storagename-) 中可以共享,且可以实时的同步。 ```typescript // 添加数据,请注意数据只能为 bool;string;number;object 四种类型,不能存储对象实例 @@ -103,9 +101,9 @@ GM_deleteValues(["a", "b"]); ### GM_add/removeValueChangeListener -> tabid 于 0.17.0-alpha 后删除,详情见 [GM_cookie](#gm_cookie) +> tabid 于 0.17.0-alpha 后删除,详情见 [GM_cookie](#gm_cookie-) -对值的监听操作,add 会返回一个监听 id,使用 remove 可以取消监听。可以使用这个方法实现一个简单的通信,使用 [**storageName**](meta.md#storagename-%F0%9F%A7%AA) 可以实现跨脚本通信。 +对值的监听操作,add 会返回一个监听 id,使用 remove 可以取消监听。可以使用这个方法实现一个简单的通信,使用 [**storageName**](meta.md#storagename-) 可以实现跨脚本通信。 ```typescript // tabid 是只有后台脚本监听才有的参数 diff --git a/docs/dev/background.md b/docs/dev/background.md index 2d7296a9..0e8984bf 100644 --- a/docs/dev/background.md +++ b/docs/dev/background.md @@ -1,9 +1,7 @@ --- -id: background +title: 后台脚本 --- -# 后台脚本 - 后台脚本适用于持续运行类型的脚本。后台脚本是脚本猫特有的脚本,后台脚本运行在沙盒中,无法操作 DOM 对象。可使用与油猴一致的 GM API 进行开发,对于兼容性会在文档中标出。 diff --git a/docs/dev/cat-api.md b/docs/dev/cat-api.md index 2e2fbc9c..a5d62ec2 100644 --- a/docs/dev/cat-api.md +++ b/docs/dev/cat-api.md @@ -1,9 +1,7 @@ --- -id: cat-api +title: CatApi 文档 --- -# CatApi 文档 - ## 说明 本扩展特有的 API 将会以 CAT\_ 开头进行定义. diff --git a/docs/dev/cloudcat.md b/docs/dev/cloudcat.md index 0d489b9f..74f09650 100644 --- a/docs/dev/cloudcat.md +++ b/docs/dev/cloudcat.md @@ -1,10 +1,7 @@ --- -id: cloudcat +title: 云端执行 --- - -# 云端执行 - > 提供了多种云端的运行方式,详情请看[运行环境](#运行环境)。另外[CloudCat](https://github.com/scriptscat/cloudcat)是用于云端执行后台脚本的服务,是一个FAAS平台,还在开发中。 ⚠请注意⚠,上传到云端后,定时脚本表达式中的`once`语义会进行改变,将`once`之前的时间替换成最小值运行. diff --git a/docs/dev/config.md b/docs/dev/config.md index 57bb6604..3b5250c8 100644 --- a/docs/dev/config.md +++ b/docs/dev/config.md @@ -1,9 +1,7 @@ --- -id: config +title: 用户配置 --- -# 用户配置 - `==UserConfig==` 中的内容,应该在`==UserScript==` 后方,表示脚本的一些用户配置.配置信息的描述使用[yaml](https://yaml.org/)格式来进行编写: ```js diff --git a/docs/dev/README.md b/docs/dev/index.md similarity index 90% rename from docs/dev/README.md rename to docs/dev/index.md index 996fb8bf..183b3f6e 100644 --- a/docs/dev/README.md +++ b/docs/dev/index.md @@ -1,14 +1,12 @@ --- -id: dev +title: 简介 --- -# 简介 - 本扩展支持三种类型的脚本,分别为: - 前台脚本 - [后台脚本](./background.md) -- [定时脚本](./background.md#定时脚本) +- [定时脚本](./background.md#定时脚本crontab) 前台脚本为通常意义上的油猴脚本,后台脚本与定时脚本为本脚本猫扩展所特有支持的脚本,详情请看相对应的文档. diff --git a/docs/dev/meta.md b/docs/dev/meta.md index 7281cbbb..3b4ca389 100644 --- a/docs/dev/meta.md +++ b/docs/dev/meta.md @@ -1,9 +1,7 @@ --- -id: meta +title: 描述文档 --- -# 描述文档 - `==UserScript==` 中的内容,用于描述脚本所需要的权限和脚本的信息作用等,在脚本的最开始的位置. ```js @@ -84,11 +82,11 @@ ScriptCat 不支持自动检查 CSP 限制来决定注入方式采用`content` ### background -表示本脚本为后台脚本,需要运行在后台环境,具体请看[后台脚本](./background.md#后台脚本) +表示本脚本为后台脚本,需要运行在后台环境,具体请看[后台脚本](./background.md#后台脚本-background) ### crontab -表示脚本为定时脚本,需要有 cron 表达式值,只能存在一个 cron 表达式,会在后台环境中定时运行,具体请看[定时脚本](./background.md#定时脚本) +表示脚本为定时脚本,需要有 cron 表达式值,只能存在一个 cron 表达式,会在后台环境中定时运行,具体请看[定时脚本](./background.md#定时脚本crontab) ### match diff --git a/docs/dev/subscribe.md b/docs/dev/subscribe.md index 29120ed5..540ba233 100644 --- a/docs/dev/subscribe.md +++ b/docs/dev/subscribe.md @@ -1,10 +1,7 @@ --- -id: subscribe +title: 订阅模式 --- - -# 订阅模式 - 文件开头必须使用`UserSubscribe`而不是`UserScript`,安装时的链接推荐使用`user.sub.js`后缀,必须使用`https`链接。 订阅脚本仅会在安装时弹出安装界面由用户确认订阅,但后续的更新采用静默更新的方式,除非`connect`权限发生改变,否则不会弹出更新界面由用户确认。 diff --git a/docs/script_installation.md b/docs/script_installation.md index 7b47c755..e0d920b1 100644 --- a/docs/script_installation.md +++ b/docs/script_installation.md @@ -1,4 +1,6 @@ -# 脚本安装 +--- +title: 脚本安装 +--- 此页面用作在 `脚本猫` 中安装新用户脚本的中间步骤。 diff --git a/docs/use/4.from-other/_category_.json b/docs/use/4.from-other/_category_.json deleted file mode 100644 index 3fae8406..00000000 --- a/docs/use/4.from-other/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "从其它管理器迁移" -} \ No newline at end of file diff --git a/docs/use/99.policy/_category_.json b/docs/use/99.policy/_category_.json deleted file mode 100644 index a546350d..00000000 --- a/docs/use/99.policy/_category_.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "label": "服务协议" -} \ No newline at end of file diff --git a/docs/use/3.QA.md b/docs/use/QA.md similarity index 100% rename from docs/use/3.QA.md rename to docs/use/QA.md diff --git a/docs/use/4.from-other/img/migrate-from-tampermonkey/image-20250716221722742.webp b/docs/use/from-other/migrate-from-tampermonkey.assets/image-20250716221722742.webp similarity index 100% rename from docs/use/4.from-other/img/migrate-from-tampermonkey/image-20250716221722742.webp rename to docs/use/from-other/migrate-from-tampermonkey.assets/image-20250716221722742.webp diff --git a/docs/use/4.from-other/img/migrate-from-tampermonkey/image-20250716222132062.webp b/docs/use/from-other/migrate-from-tampermonkey.assets/image-20250716222132062.webp similarity index 100% rename from docs/use/4.from-other/img/migrate-from-tampermonkey/image-20250716222132062.webp rename to docs/use/from-other/migrate-from-tampermonkey.assets/image-20250716222132062.webp diff --git a/docs/use/4.from-other/img/migrate-from-tampermonkey/image-20250716222326368.webp b/docs/use/from-other/migrate-from-tampermonkey.assets/image-20250716222326368.webp similarity index 100% rename from docs/use/4.from-other/img/migrate-from-tampermonkey/image-20250716222326368.webp rename to docs/use/from-other/migrate-from-tampermonkey.assets/image-20250716222326368.webp diff --git a/docs/use/4.from-other/img/migrate-from-tampermonkey/image-20250716222403452.webp b/docs/use/from-other/migrate-from-tampermonkey.assets/image-20250716222403452.webp similarity index 100% rename from docs/use/4.from-other/img/migrate-from-tampermonkey/image-20250716222403452.webp rename to docs/use/from-other/migrate-from-tampermonkey.assets/image-20250716222403452.webp diff --git a/docs/use/4.from-other/migrate-from-tampermonkey.md b/docs/use/from-other/migrate-from-tampermonkey.md similarity index 60% rename from docs/use/4.from-other/migrate-from-tampermonkey.md rename to docs/use/from-other/migrate-from-tampermonkey.md index 10ec553a..e159f1aa 100644 --- a/docs/use/4.from-other/migrate-from-tampermonkey.md +++ b/docs/use/from-other/migrate-from-tampermonkey.md @@ -1,4 +1,6 @@ -# 从 Tampermonkey 迁移到 Scriptcat +--- +title: 从 Tampermonkey 迁移到 Scriptcat +--- 如果你正在使用 Tampermonkey 并希望迁移到 Scriptcat,以下是一些步骤和提示,帮助你顺利完成迁移。 @@ -6,20 +8,20 @@ 首先点击 Tampermonkey 图标,进入管理面板 -![image-20250716221722742](./img/migrate-from-tampermonkey/image-20250716221722742.webp) +![image-20250716221722742](./migrate-from-tampermonkey.assets/image-20250716221722742.webp) 点击`实用工具`,点击压缩包`导出`,即可导出压缩包文件 -![image-20250716222132062](./img/migrate-from-tampermonkey/image-20250716222132062.webp) +![image-20250716222132062](./migrate-from-tampermonkey.assets/image-20250716222132062.webp) ## 导入到 Scriptcat 在 Scriptcat 扩展中,点击控制面板图标,进入管理面板 -![image-20250716222326368](./img/migrate-from-tampermonkey/image-20250716222326368.webp) +![image-20250716222326368](./migrate-from-tampermonkey.assets/image-20250716222326368.webp) 选择`工具`,然后点击`导入文件`,选择之前导出的 Tampermonkey 压缩包文件,点击`打开`即可导入。 -![image-20250716222403452](./img/migrate-from-tampermonkey/image-20250716222403452.webp) +![image-20250716222403452](./migrate-from-tampermonkey.assets/image-20250716222403452.webp) 然后在新弹出的页面中选择或者全选你要导入的脚本,点击`导入`按钮即可。 diff --git a/docs/use/4.from-other/img/migrate-from-violentmonkey/image-20250716223536305.webp b/docs/use/from-other/migrate-from-violentmonkey.assets/image-20250716223536305.webp similarity index 100% rename from docs/use/4.from-other/img/migrate-from-violentmonkey/image-20250716223536305.webp rename to docs/use/from-other/migrate-from-violentmonkey.assets/image-20250716223536305.webp diff --git a/docs/use/4.from-other/img/migrate-from-violentmonkey/image-20250716223849488.webp b/docs/use/from-other/migrate-from-violentmonkey.assets/image-20250716223849488.webp similarity index 100% rename from docs/use/4.from-other/img/migrate-from-violentmonkey/image-20250716223849488.webp rename to docs/use/from-other/migrate-from-violentmonkey.assets/image-20250716223849488.webp diff --git a/docs/use/4.from-other/migrate-from-violentmonkey.md b/docs/use/from-other/migrate-from-violentmonkey.md similarity index 59% rename from docs/use/4.from-other/migrate-from-violentmonkey.md rename to docs/use/from-other/migrate-from-violentmonkey.md index 6dbafad9..e71da73d 100644 --- a/docs/use/4.from-other/migrate-from-violentmonkey.md +++ b/docs/use/from-other/migrate-from-violentmonkey.md @@ -1,4 +1,6 @@ -# 从 Violentmonkey 迁移到 Scriptcat +--- +title: 从 Violentmonkey 迁移到 Scriptcat +--- 如果你正在使用 Violentmonkey 并希望迁移到 Scriptcat,以下是一些步骤和提示,帮助你顺利完成迁移。 @@ -6,20 +8,20 @@ 首先点击 Violentmonkey 图标,进入管理面板 -![image-20250716223536305](./img/migrate-from-violentmonkey/image-20250716223536305.webp) +![image-20250716223536305](./migrate-from-violentmonkey.assets/image-20250716223536305.webp) 点击`设置`,点击`导出为zip文件`,即可导出压缩包文件 -![image-20250716223849488](./img/migrate-from-violentmonkey/image-20250716223849488.webp) +![image-20250716223849488](./migrate-from-violentmonkey.assets/image-20250716223849488.webp) ## 导入到 Scriptcat 在 Scriptcat 扩展中,点击控制面板图标,进入管理面板 -![image-20250716222326368](./img/migrate-from-tampermonkey/image-20250716222326368.webp) +![image-20250716222326368](./migrate-from-tampermonkey.assets/image-20250716222326368.webp) 选择`工具`,然后点击`导入文件`,选择之前导出的 Violentmonkey 压缩包文件,点击`打开`即可导入。 -![image-20250716222403452](./img/migrate-from-tampermonkey/image-20250716222403452.webp) +![image-20250716222403452](./migrate-from-tampermonkey.assets/image-20250716222403452.webp) 然后在新弹出的页面中选择或者全选你要导入的脚本,点击`导入`按钮即可。 diff --git a/docs/use/img/README.assets/chrome-open-dev.webp b/docs/use/open-dev.assets/chrome-open-dev.webp similarity index 100% rename from docs/use/img/README.assets/chrome-open-dev.webp rename to docs/use/open-dev.assets/chrome-open-dev.webp diff --git a/docs/use/img/README.assets/chrome-open-settings.webp b/docs/use/open-dev.assets/chrome-open-settings.webp similarity index 100% rename from docs/use/img/README.assets/chrome-open-settings.webp rename to docs/use/open-dev.assets/chrome-open-settings.webp diff --git a/docs/use/img/5.open-dev.assets/edge mobile 138.png b/docs/use/open-dev.assets/edge mobile 138.png similarity index 100% rename from docs/use/img/5.open-dev.assets/edge mobile 138.png rename to docs/use/open-dev.assets/edge mobile 138.png diff --git a/docs/use/img/5.open-dev.assets/edge mobile.png b/docs/use/open-dev.assets/edge mobile.png similarity index 100% rename from docs/use/img/5.open-dev.assets/edge mobile.png rename to docs/use/open-dev.assets/edge mobile.png diff --git a/docs/use/img/README.assets/edge-open-dev.webp b/docs/use/open-dev.assets/edge-open-dev.webp similarity index 100% rename from docs/use/img/README.assets/edge-open-dev.webp rename to docs/use/open-dev.assets/edge-open-dev.webp diff --git a/docs/use/img/README.assets/edge-open-settings.webp b/docs/use/open-dev.assets/edge-open-settings.webp similarity index 100% rename from docs/use/img/README.assets/edge-open-settings.webp rename to docs/use/open-dev.assets/edge-open-settings.webp diff --git a/docs/use/img/5.open-dev.assets/image-20250623140940401.webp b/docs/use/open-dev.assets/image-20250623140940401.webp similarity index 100% rename from docs/use/img/5.open-dev.assets/image-20250623140940401.webp rename to docs/use/open-dev.assets/image-20250623140940401.webp diff --git a/docs/use/img/5.open-dev.assets/image-20250623141002831.webp b/docs/use/open-dev.assets/image-20250623141002831.webp similarity index 100% rename from docs/use/img/5.open-dev.assets/image-20250623141002831.webp rename to docs/use/open-dev.assets/image-20250623141002831.webp diff --git a/docs/use/img/5.open-dev.assets/image-20260130233429385.png b/docs/use/open-dev.assets/image-20260130233429385.png similarity index 100% rename from docs/use/img/5.open-dev.assets/image-20260130233429385.png rename to docs/use/open-dev.assets/image-20260130233429385.png diff --git a/docs/use/img/5.open-dev.assets/image-20260130233818464.png b/docs/use/open-dev.assets/image-20260130233818464.png similarity index 100% rename from docs/use/img/5.open-dev.assets/image-20260130233818464.png rename to docs/use/open-dev.assets/image-20260130233818464.png diff --git a/docs/use/5.open-dev.md b/docs/use/open-dev.md similarity index 87% rename from docs/use/5.open-dev.md rename to docs/use/open-dev.md index 08c9e3d2..574134e1 100644 --- a/docs/use/5.open-dev.md +++ b/docs/use/open-dev.md @@ -9,7 +9,6 @@ import BrowserGuide from '@site/src/components/BrowserGuide'; import GithubStar from '@site/src/components/GithubStar'; import SponsorBlock from '@site/src/components/SponsorBlock/zh.mdx'; -# 开启浏览器 User Scripts 支持 <GithubStar variant="bar" scene="install" /> @@ -47,32 +46,32 @@ import SponsorBlock from '@site/src/components/SponsorBlock/zh.mdx'; ① 打开浏览器的扩展管理界面,或者访问 [edge://extensions/](edge://extensions/) -![edge-open-settings](./img/README.assets/edge-open-settings.webp) +![edge-open-settings](./open-dev.assets/edge-open-settings.webp) ② 在扩展管理界面中,找到脚本猫扩展,点击`详情` -![image-20260130233429385](img/5.open-dev.assets/image-20260130233429385.png) +![image-20260130233429385](open-dev.assets/image-20260130233429385.png) ③ 在脚本猫扩展的详情页中,找到`允许用户脚本`选项,开启它,然后关闭扩展再开启扩展,或者重启浏览器,使脚本功能生效。 > ⚠️⚠️⚠️ 低版本 Edge 浏览器(\<=143 版本)或者没有该选项的用户,请参考[开启开发者模式](#开启开发者模式) -![image-20260130233818464](img/5.open-dev.assets/image-20260130233818464.png) +![image-20260130233818464](open-dev.assets/image-20260130233818464.png) </TabItem> <TabItem value="chrome" label={<div className="flex items-center gap-1"><Icon height={16} width={16} icon="logos:chrome" />Chrome</div>}> ① 打开浏览器的扩展管理界面,或者访问 [chrome://extensions/](chrome://extensions/) -![chrome-open-settings](./img/README.assets/chrome-open-settings.webp) +![chrome-open-settings](./open-dev.assets/chrome-open-settings.webp) ② 在扩展管理界面中,找到脚本猫扩展,点击`详情` -![image-20250623140940401](img/5.open-dev.assets/image-20250623140940401.webp) +![image-20250623140940401](open-dev.assets/image-20250623140940401.webp) ③ 在脚本猫扩展的详情页中,找到`允许用户脚本`选项,开启它,然后关闭扩展再开启扩展,或者重启浏览器,使脚本功能生效。 -![image-20250623141002831](img/5.open-dev.assets/image-20250623141002831.webp) +![image-20250623141002831](open-dev.assets/image-20250623141002831.webp) </TabItem> <TabItem value="edge-mobile" label={<div className="flex items-center gap-1"><Icon height={16} width={16} icon="logos:microsoft-edge" />Edge Mobile</div>}> @@ -86,7 +85,7 @@ Edge Mobile 内核版本 ≥ 138 时,不需要开启开发者模式,只需 > ⚠️⚠️⚠️ 内核版本低于 138 或没有该选项的用户,请参考[开启开发者模式](#开启开发者模式) -![edge-mobile-allow-user-scripts](./img/5.open-dev.assets/edge%20mobile%20138.png) +![edge-mobile-allow-user-scripts](./open-dev.assets/edge%20mobile%20138.png) </TabItem> </Tabs> @@ -98,11 +97,11 @@ Edge Mobile 内核版本 ≥ 138 时,不需要开启开发者模式,只需 ① 打开浏览器的扩展管理界面,或者访问 [edge://extensions/](edge://extensions/) -![edge-open-settings](./img/README.assets/edge-open-settings.webp) +![edge-open-settings](./open-dev.assets/edge-open-settings.webp) ② 打开`开发人员模式`(某些浏览器该模式可能会存在其他选项中 如 360 浏览器: 高级管理>开发者模式) -![edge-open-dev](./img/README.assets/edge-open-dev.webp) +![edge-open-dev](./open-dev.assets/edge-open-dev.webp) ③ 开启开发者模式后,关闭扩展再开启扩展,或者重启浏览器,使脚本功能生效。 @@ -111,11 +110,11 @@ Edge Mobile 内核版本 ≥ 138 时,不需要开启开发者模式,只需 ① 打开浏览器的扩展管理界面,或者访问 [chrome://extensions/](chrome://extensions/) -![chrome-open-settings](./img/README.assets/chrome-open-settings.webp) +![chrome-open-settings](./open-dev.assets/chrome-open-settings.webp) ② 打开`开发人员模式`(某些浏览器该模式可能会存在其他选项中 如 360 浏览器: 高级管理>开发者模式) -![chrome-open-dev](./img/README.assets/chrome-open-dev.webp) +![chrome-open-dev](./open-dev.assets/chrome-open-dev.webp) ③ 开启开发者模式后,关闭扩展再开启扩展,或者重启浏览器,使脚本功能生效。 @@ -125,7 +124,7 @@ Edge Mobile 内核版本 ≥ 138 时,不需要开启开发者模式,只需 Edge Mobile 内核版本低于 138 或没有「允许用户脚本」选项时,点击扩展页上方的设置按钮开启开发者模式。 -![edge-mobile-open-dev](./img/5.open-dev.assets/edge%20mobile.png) +![edge-mobile-open-dev](./open-dev.assets/edge%20mobile.png) </TabItem> </Tabs> diff --git a/docs/use/99.policy/disclaimer.md b/docs/use/policy/disclaimer.md similarity index 97% rename from docs/use/99.policy/disclaimer.md rename to docs/use/policy/disclaimer.md index f6e86035..bb31fc6a 100644 --- a/docs/use/99.policy/disclaimer.md +++ b/docs/use/policy/disclaimer.md @@ -1,10 +1,8 @@ --- -id: disclaimer -title: 免责声明 +title: ScriptCat 免责协议 +sidebar_label: 免责声明 --- -# ScriptCat 免责协议 - ScriptCat 相关产品和服务(包括但不限于浏览器扩展、脚本站点、API服务等,以下统称"服务")由 ScriptCat 团队(以下简称"我们"或"开发者")开发和提供。在您开始使用我们的服务之前,请仔细阅读以下免责协议。用户访问、下载、安装、使用我们的任何产品或服务的⾏为,都将被视作是对本声明全部内容的⽆异议的认可。 一、我们的服务及其所有内容和功能均按"现状"和"可用"基础提供,无任何明示或暗示的保证。我们不保证服务的性能、功能或可用性,也不保证服务将无错误运行或任何错误将被纠正。 diff --git a/docs/use/99.policy/privacy.md b/docs/use/policy/privacy.md similarity index 97% rename from docs/use/99.policy/privacy.md rename to docs/use/policy/privacy.md index 7475d024..a6cb66c4 100644 --- a/docs/use/99.policy/privacy.md +++ b/docs/use/policy/privacy.md @@ -1,10 +1,8 @@ --- -id: privacy -title: 隐私政策 +title: ScriptCat 隐私政策 +sidebar_label: 隐私政策 --- -# ScriptCat 隐私政策 - 欢迎您使用 ScriptCat 浏览器扩展!ScriptCat(以下简称"我们的产品")是由 scriptcat.org(以下简称"我们")开发并运营的浏览器扩展。 **我们深知隐私保护的重要性,因此在设计之初就坚持隐私优先的原则。** diff --git a/docs/use/99.policy/privacy_website.md b/docs/use/policy/privacy_website.md similarity index 97% rename from docs/use/99.policy/privacy_website.md rename to docs/use/policy/privacy_website.md index cb0ddfb0..a0109109 100644 --- a/docs/use/99.policy/privacy_website.md +++ b/docs/use/policy/privacy_website.md @@ -1,10 +1,8 @@ --- -id: privacy_website -title: 脚本站点 隐私政策 +title: ScriptCat 脚本站点 隐私政策 +sidebar_label: 脚本站点 隐私政策 --- -# ScriptCat 脚本站点 隐私政策 - 欢迎您访问我们的产品。 ScriptCat (包括 App 及网站等产品提供的服务,以下简称“产品和服务”)是由 scriptcat.org (以下简称“我们”)开发并运营的。 确保用户的数据安全和隐私保护是我们的首要任务, 本隐私政策载明了您访问和使用我们的产品和服务时所收集的数据及其处理方式。 请您在继续使用我们的产品前务必认真仔细阅读并确认充分理解本隐私政策全部规则和要点, 一旦您选择使用,即视为您同意本隐私政策的全部内容,同意我们按其收集和使用您的相关信息。 如您在在阅读过程中,对本政策有任何疑问,可联系我们的客服咨询, 请通过 yz@ggnb.top 或产品中的反馈方式与我们取得联系。 如您不同意相关协议或其中的任何条款的,您应停止使用我们的产品和服务。 diff --git a/docs/use/2.script_installation.md b/docs/use/script_installation.md similarity index 100% rename from docs/use/2.script_installation.md rename to docs/use/script_installation.md diff --git a/docs/use/2.sync.md b/docs/use/sync.md similarity index 93% rename from docs/use/2.sync.md rename to docs/use/sync.md index 42566d57..cbc04b11 100644 --- a/docs/use/2.sync.md +++ b/docs/use/sync.md @@ -1,9 +1,7 @@ --- -id: sync +title: 同步与备份 --- -# 同步与备份 - 支持以下云储存: - [x] WebDAV diff --git a/docs/use/img/README.assets/chrome-load-unpacked-img.webp b/docs/use/use.assets/chrome-load-unpacked-img.webp similarity index 100% rename from docs/use/img/README.assets/chrome-load-unpacked-img.webp rename to docs/use/use.assets/chrome-load-unpacked-img.webp diff --git a/docs/use/img/README.assets/chrome-load-unpacked.webp b/docs/use/use.assets/chrome-load-unpacked.webp similarity index 100% rename from docs/use/img/README.assets/chrome-load-unpacked.webp rename to docs/use/use.assets/chrome-load-unpacked.webp diff --git a/docs/use/img/README.assets/download-zip.webp b/docs/use/use.assets/download-zip.webp similarity index 100% rename from docs/use/img/README.assets/download-zip.webp rename to docs/use/use.assets/download-zip.webp diff --git a/docs/use/img/README.assets/edge-load-unpacked-img.webp b/docs/use/use.assets/edge-load-unpacked-img.webp similarity index 100% rename from docs/use/img/README.assets/edge-load-unpacked-img.webp rename to docs/use/use.assets/edge-load-unpacked-img.webp diff --git a/docs/use/img/README.assets/edge-load-unpacked.webp b/docs/use/use.assets/edge-load-unpacked.webp similarity index 100% rename from docs/use/img/README.assets/edge-load-unpacked.webp rename to docs/use/use.assets/edge-load-unpacked.webp diff --git a/docs/use/1.README.md b/docs/use/use.md similarity index 92% rename from docs/use/1.README.md rename to docs/use/use.md index adb5d128..93f00212 100644 --- a/docs/use/1.README.md +++ b/docs/use/use.md @@ -1,9 +1,8 @@ --- -id: use +slug: /use/use +title: 快速开始 --- -# 快速开始 - 脚本猫是一个可以执行用户脚本的浏览器扩展,兼容油猴脚本,并提供更多功能。如果您发现 BUG 或者建议可以前往[GitHub Repo](https://github.com/scriptscat/scriptcat)进行反馈。 ## 安装扩展 @@ -24,17 +23,17 @@ id: use ① 先从[Github Release](https://github.com/scriptscat/scriptcat/releases)或者[社区下载](https://bbs.tampermonkey.net.cn/thread-3068-1-1.html)页面中,下载`zip`文件,如果是`crx`文件将其后缀改为`zip` -② 准备一个文件夹用于存放插件,将上面的 zip 解压到该文件夹。解压后如下(**注意:此文件夹不可删除或移动,否则扩展将无法正常运行**) ![download-zip](./img/README.assets/download-zip.webp) +② 准备一个文件夹用于存放插件,将上面的 zip 解压到该文件夹。解压后如下(**注意:此文件夹不可删除或移动,否则扩展将无法正常运行**) ![download-zip](./use.assets/download-zip.webp) ③ 打开浏览器的扩展管理界面加载解压缩的扩展 (参考 [开启开发者模式支持 manifest v3 版脚本猫](/docs/use/open-dev/) 先打开开发者模式) -- 1. **Edge** ![edge-load-unpacked](./img/README.assets/edge-load-unpacked.webp) -- 2. **Chrome** ![chrome-load-unpacked](./img/README.assets/chrome-load-unpacked.webp) +- 1. **Edge** ![edge-load-unpacked](./use.assets/edge-load-unpacked.webp) +- 2. **Chrome** ![chrome-load-unpacked](./use.assets/chrome-load-unpacked.webp) ④ 选择加载步骤 ② 中新建的文件夹(加载完成后扩展管理界面的扩展列表中会显示脚本猫图标,浏览器的地址栏的右上角点击扩展按钮也可看见) -- 1. **Edge** ![edge-load-unpacked-img](./img/README.assets/edge-load-unpacked-img.webp) -- 2. **Chrome** ![chrome-load-unpacked-img](./img/README.assets/chrome-load-unpacked-img.webp) +- 1. **Edge** ![edge-load-unpacked-img](./use.assets/edge-load-unpacked-img.webp) +- 2. **Chrome** ![chrome-load-unpacked-img](./use.assets/chrome-load-unpacked-img.webp) ⑤ 点击右上角脚本猫图标,在出现的界面右上角点击`┆`>获取脚本,即可前往脚本站搜索安装脚本 diff --git a/docs/use/6.vscode.md b/docs/use/vscode.md similarity index 95% rename from docs/use/6.vscode.md rename to docs/use/vscode.md index 4304b6f6..af159ff5 100644 --- a/docs/use/6.vscode.md +++ b/docs/use/vscode.md @@ -1,16 +1,14 @@ --- -title: VSCode 扩展开发脚本 +title: 使用 VSCode 开发脚本 --- -# 使用 VSCode 开发脚本 - ScriptCat 提供了 VSCode 扩展,让你可以在 VSCode 中编写用户脚本,保存后自动同步到浏览器中的 ScriptCat,无需手动复制粘贴,大幅提升开发效率。 ## 安装准备 你需要安装以下两个工具: -1. **浏览器安装 ScriptCat 扩展** — 如果还没有安装,请参考 [快速开始](/docs/use/) 进行安装 +1. **浏览器安装 ScriptCat 扩展** — 如果还没有安装,请参考 [快速开始](/docs/use/use/) 进行安装 2. **VSCode 安装 ScriptCat 扩展** — 在 VSCode 扩展商店搜索「[scriptcat-vscode](https://marketplace.visualstudio.com/items?itemName=CodFrm.scriptcat-vscode)」,或前往 [GitHub 仓库](https://github.com/scriptscat/scriptcat-vscode) 下载安装 ## 建立连接 diff --git a/docusaurus.config.js b/docusaurus.config.js index bfb7a416..5b92de76 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -9,8 +9,13 @@ const config = { tagline: "可以执行自定义脚本的浏览器扩展", url: "https://docs.scriptcat.org", baseUrl: "/", - onBrokenLinks: "warn", - onBrokenMarkdownLinks: "warn", + onBrokenLinks: "throw", + onBrokenAnchors: "throw", + markdown: { + hooks: { + onBrokenMarkdownLinks: "throw", + }, + }, favicon: "img/logo.png", trailingSlash: true, @@ -19,7 +24,24 @@ const config = { organizationName: "scriptscat", // Usually your GitHub org/user name. projectName: "scriptcat.org", // Usually your repo name. - plugins: [["@gracefullight/docusaurus-plugin-tailwind", {}]], + plugins: [ + ["@gracefullight/docusaurus-plugin-tailwind", {}], + [ + "@docusaurus/plugin-client-redirects", + /** @type {import('@docusaurus/plugin-client-redirects').Options} */ + ({ + // /docs/use/use/ is the quick-start doc; /docs/use/ itself has never + // resolved (broken footer link + broken in-content links) — redirect + // it instead of renaming the existing doc, so no published URL moves. + redirects: [ + { + to: "/docs/use/use/", + from: "/docs/use/", + }, + ], + }), + ], + ], // Even if you don't use internalization, you can use this field to set useful // metadata like html lang. For example, if your site is Chinese, you may want @@ -51,7 +73,12 @@ const config = { // Please change this to your repo. // Remove this to remove the "edit this page" links. editUrl: "https://github.com/scriptscat/scriptcat.org/edit/main", + // So "Edit this page" on /en/ docs opens the en source file, not zh. + editLocalizedFiles: true, }, + // No blog/ directory exists; without this, newer Docusaurus versions + // emit an empty /blog/ index route that was never part of the site. + blog: false, theme: { customCss: require.resolve("./src/css/custom.css"), }, @@ -97,13 +124,13 @@ const config = { }, { type: "doc", - docId: "dev/dev", + docId: "dev/index", position: "left", label: "开发文档", }, { type: "doc", - docId: "change/change", + docId: "change/index", position: "right", label: "更新日志", }, @@ -131,7 +158,7 @@ const config = { items: [ { label: "使用指南", - to: "/docs/use", + to: "/docs/use/use", }, { label: "开发指南", diff --git a/i18n/en/docusaurus-plugin-content-docs/current.json b/i18n/en/docusaurus-plugin-content-docs/current.json index b06e894d..fae992e5 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current.json +++ b/i18n/en/docusaurus-plugin-content-docs/current.json @@ -10,5 +10,9 @@ "sidebar.use.category.从其它管理器迁移": { "message": "Migrate from other managers", "description": "The label for category 从其它管理器迁移 in sidebar use" + }, + "sidebar.dev.category.Agent 智能助手": { + "message": "Agent", + "description": "The label for category Agent 智能助手 in sidebar dev" } } diff --git a/i18n/en/docusaurus-plugin-content-docs/current/about/index.md b/i18n/en/docusaurus-plugin-content-docs/current/about/index.md new file mode 100644 index 00000000..fe8a917b --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/about/index.md @@ -0,0 +1,20 @@ +--- +sidebar: false +title: About +description: About ScriptCat +icon: info +--- + + +## About ScriptCat + +Inspired by Tampermonkey's design and compatible with Tampermonkey scripts, ScriptCat implements a background-script execution framework and provides a number of special APIs that let scripts do more, along with a great editor that makes writing and developing script code more comfortable and fluid. + +For our development roadmap, see [Project #1](https://github.com/scriptscat/scriptcat/projects/1), where we publish our development plans. If you have any suggestions, feel free to open an [issue](https://github.com/scriptscat/scriptcat/issues) to let us know. + +**If you find it useful, please consider giving us a Star ❤❤❤** + +## Tampermonkey Chinese Forum +> [Click here to visit](https://bbs.tampermonkey.net.cn/) + +The Tampermonkey Chinese Forum is a community we created for developing and discussing Tampermonkey-style scripts. The forum has a wealth of script-learning resources and many experienced members, so you can discuss and ask questions there. We also support publishing and installing scripts, so everyone is free to share their own work. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/change/beta.md b/i18n/en/docusaurus-plugin-content-docs/current/change/beta-changelog.md similarity index 99% rename from i18n/en/docusaurus-plugin-content-docs/current/change/beta.md rename to i18n/en/docusaurus-plugin-content-docs/current/change/beta-changelog.md index 043c1142..3d18361f 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/change/beta.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/change/beta-changelog.md @@ -1,18 +1,16 @@ --- -id: beta-changelog -sidebar_position: 1 +title: Beta Changelog --- import GithubStar from '@site/src/components/GithubStar'; import SponsorBlock from '@site/src/components/SponsorBlock/en.mdx'; -# Beta Changelog <GithubStar variant="bar" scene="changelog" /> <SponsorBlock /> -ScriptCat's version releases are divided into two main branches: stable releases and pre-release versions. For the stable release changelog, please see: [Changelog](./README.md) +ScriptCat's version releases are divided into two main branches: stable releases and pre-release versions. For the stable release changelog, please see: [Changelog](./index.md) Pre-release versions are released before the official stable version. They are typically used to test new features. Pre-release version numbers contain a pre-release identifier, for example: `1.0.0-beta.1`. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/change/README.md b/i18n/en/docusaurus-plugin-content-docs/current/change/index.md similarity index 99% rename from i18n/en/docusaurus-plugin-content-docs/current/change/README.md rename to i18n/en/docusaurus-plugin-content-docs/current/change/index.md index e25dd3b5..ce3ef839 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/change/README.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/change/index.md @@ -1,18 +1,16 @@ --- -id: change -sidebar_position: 1 +title: Changelog --- import GithubStar from '@site/src/components/GithubStar'; import SponsorBlock from '@site/src/components/SponsorBlock/en.mdx'; -# Changelog <GithubStar variant="bar" scene="changelog" /> <SponsorBlock /> -For Beta version changelog, please see [Beta Changelog](./beta.md) +For Beta version changelog, please see [Beta Changelog](./beta-changelog.md) ⚠️ Please note that if you are using Windows 8/7/XP, or your browser kernel version is lower than 120, you need to manually install the [legacy version of ScriptCat](https://github.com/scriptscat/scriptcat/releases). v0.16.x is the last version that supports Manifest V2. Installation steps can be found at: [Install Extension by Loading Unpacked](/docs/use/use/#load-unpacked-extension-installation). diff --git a/i18n/en/docusaurus-plugin-content-docs/current/change/v0.16.md b/i18n/en/docusaurus-plugin-content-docs/current/change/v0.16.md new file mode 100644 index 00000000..6d5b2ec3 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/change/v0.16.md @@ -0,0 +1,36 @@ +--- +title: v0.16 +--- + +## v0.16.1 + +## Added sorting by last updated + +![image-20240423113515332](@site/docs/change/v0.16.assets/image-20240423113515332.png) + +## v0.16.2 + +## Menu auto-hide configuration + +The default configuration shows 5 menu items; once there are more than 5, the menu automatically hides the rest, and clicking "more" reveals the hidden items. + +![alt text](@site/docs/change/v0.16.assets/setting.png) + +![iShot_2024-04-23_11.14.37](@site/docs/change/v0.16.assets/iShot_2024-04-23_11.14.37.gif) + +## Added a column show/hide control to the script list + +![image-20240423111623608](@site/docs/change/v0.16.assets/image-20240423111623608.png) + +## v0.16.3 + +> Mainly bug fixes + +## v0.16.4 + +> Mainly bug fixes + +## v0.16.5 + +> Mainly bug fixes + diff --git a/i18n/en/docusaurus-plugin-content-docs/current/change/v0.17.md b/i18n/en/docusaurus-plugin-content-docs/current/change/v0.17.md new file mode 100644 index 00000000..268cc6b6 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/change/v0.17.md @@ -0,0 +1,31 @@ +--- +title: v0.17 +--- + +Starting with v0.17.0, ScriptCat upgraded to Manifest V3 and switched its storage engine from `indexedDB` to `chrome.storage.local`. Switching storage engines automatically opens this page and restarts the extension. If you notice any data issues, please let us know on [GitHub](https://github.com/scriptscat/scriptcat/issues). + +## v0.17.0-alpha + +Refactored for Manifest V3, switched the storage engine, and modified some features + +- To stay consistent with Tampermonkey, removed `maxRedirects` from `GM_xmlhttpRequest` in favor of `redirect` +- Removed `GM_cookie`'s `store` method along with `storeId` and `tabId`; getting cookies now uses the current page's `store` directly (for example, incognito and normal windows have different stores) +- Removed `@require-css` + +## v0.17.0-beta.4 + +### Added a quick script-update check to the popup page + +![image-20250620165421754](@site/docs/change/v0.17.assets/image-20250620165421754.png) + + + +### Implemented a site blacklist feature + +![image-20250620165529101](@site/docs/change/v0.17.assets/image-20250620165529101.png) + + + +### Added a switch type to UserConfig + +![image-20250620165640030](@site/docs/change/v0.17.assets/image-20250620165640030.png) diff --git a/i18n/en/docusaurus-plugin-content-docs/current/change/v1.1.md b/i18n/en/docusaurus-plugin-content-docs/current/change/v1.1.md new file mode 100644 index 00000000..93847d50 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/change/v1.1.md @@ -0,0 +1,11 @@ +--- +title: v1.1 +--- + +## Cloud Storage Platforms + +Added Dropbox support + +## API Updates + +- Added `@early-start`, letting your script run earlier than the page [#649](https://github.com/scriptscat/scriptcat/pull/649) diff --git a/i18n/en/docusaurus-plugin-content-docs/current/change/v1.2.md b/i18n/en/docusaurus-plugin-content-docs/current/change/v1.2.md new file mode 100644 index 00000000..a3967005 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/change/v1.2.md @@ -0,0 +1,41 @@ +--- +title: v1.2 +--- + +Fixed version updates no longer automatically opening the changelog page + +## Script List Sidebar [#794](https://github.com/scriptscat/scriptcat/issues/794) + +Added advanced filtering to the sidebar, along with a tagging feature; tags can be edited from Script → Settings. + +![image-20251016230129315](@site/docs/change/v1.2.assets/image-20251016230129315.png) + +## Card View [#860](https://github.com/scriptscat/scriptcat/issues/860) + +Added a card view, which switches automatically between card view and table view on first launch, so narrow screens can display script information better. + +![image-20251023103730266](@site/docs/change/v1.2.assets/image-20251023103730266.png) + +## Friendlier Update-Check Logic [#755](https://github.com/scriptscat/scriptcat/issues/755) + +Optimized the update-check logic — instead of popping up an update prompt for every script at once, they're now merged into a single update window, where you can choose which scripts to update or update all of them with one click. It also shows how much each script has changed. + +![image-20251016225931823](@site/docs/change/v1.2.assets/image-20251016225931823.png) + +## Added Editor Configuration and Editor Type Definitions [#708](https://github.com/scriptscat/scriptcat/pull/708) + +You can now customize the editor configuration and editor type definitions; the editor configuration can be written referencing [compilerOptions](https://www.typescriptlang.org/tsconfig/#compilerOptions) from `tsconfig.json`. + +![08c2889f-3029-4d3c-b180-c52d77c8077c](@site/docs/change/v1.2.assets/08c2889f-3029-4d3c-b180-c52d77c8077c.png) + +## Background Running Option [#1048](https://github.com/scriptscat/scriptcat/pull/1048) + +Added a background-running option under Settings → Runtime. When enabled, the browser keeps running in the background and minimizes to the system tray even after all windows are closed, until you manually quit the browser. This lets background scripts keep running. + +![image-20251204174034940](@site/docs/change/v1.2.assets/image-20251204174034940.png) + +## API Updates + +- Supports `inject-into`, so scripts can now be injected into the content environment [#711](https://github.com/scriptscat/scriptcat/issues/711) +- `GM_openInTab` supports parameters for pinning the tab, opening in an incognito window, and more [#788](https://github.com/scriptscat/scriptcat/pull/788) +- `GM_registerMenuCommand` supports second-level menus and separator lines [#831](https://github.com/scriptscat/scriptcat/pull/831) diff --git a/i18n/en/docusaurus-plugin-content-docs/current/change/v1.3.md b/i18n/en/docusaurus-plugin-content-docs/current/change/v1.3.md index 344a1e42..50d53ac0 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/change/v1.3.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/change/v1.3.md @@ -1,9 +1,7 @@ --- -sidebar_position: 9996 +title: v1.3 --- -# v1.3 - ## New Script Installation Flow [#842](https://github.com/scriptscat/scriptcat/issues/842) Redesigned the script installation flow — no longer relies on external website redirects or opening new windows. Scripts are now installed directly within the current page. The install page layout has also been optimized with responsive design, scrollable code preview, and inline error display for download failures. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/change/v1.4.md b/i18n/en/docusaurus-plugin-content-docs/current/change/v1.4.md new file mode 100644 index 00000000..a9f44bf8 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/change/v1.4.md @@ -0,0 +1,50 @@ +--- +title: v1.4 — Agent +--- + +:::caution Testing Phase +v1.4 is currently still in a testing phase; the following features and APIs may change before the official release. Feedback from trying it out is welcome. +::: + +v1.4 is a major update for ScriptCat, introducing an all-new **Agent** system that lets users automate browser actions, extract web data, manage files, and run scheduled tasks through natural-language conversation. + +## Agent + +A new Agent chat entry point has been added to the dashboard, where you can hold a multi-turn conversation with an AI model; the AI automatically calls built-in tools to complete tasks. + +**Core capabilities:** + +- **Multi-model support** — OpenAI-compatible and native Anthropic formats, with Prompt Caching support +- **11 built-in tools** — web fetch/search, tab management, the OPFS file system, code execution, user interaction, and more +- **Skill system** — packages of prompts + tool scripts + reference material that extend the Agent's domain knowledge +- **MCP integration** — supports the [Model Context Protocol](https://modelcontextprotocol.io/) to connect to external tool servers +- **DOM automation** — page navigation, screenshots, clicking, filling, scrolling, script execution, and more +- **Scheduled tasks** — Cron-expression-based task scheduling (Internal / Event modes) +- **Sub-agents** — can spawn independent sub-agents to handle complex sub-tasks +- **Context management** — Auto-compact and Prompt Caching to reduce token usage + +**Script API (`CAT.agent.*`):** + +User scripts can call Agent capabilities through the `CAT.agent.*` namespace, including the conversation, dom, skills, task, model, opfs, and mcp APIs. Each API requires the corresponding permission to be declared with `@grant`. + +**6 dashboard pages:** Chat, Model Configuration, Skill Management, Scheduled Tasks, MCP Servers, and the OPFS Browser. + +## Support for the `@unwrap` Tag + +Lets a script be injected directly into the page, bypassing the sandbox wrapper. + +## The `window.onurlchange` Event + +Implements Tampermonkey-compatible URL-change event listening using the Navigation API. + +## Editor Improvements + +Added an edit menu (find, replace, undo, etc.), and fixed several keyboard shortcut and hint issues. + +## Multi-platform Search Engines + +Script discovery now supports choosing between different search engine platforms. + +## More Icon Providers + +Added more script icon service providers. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-builtin-tools.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-builtin-tools.md new file mode 100644 index 00000000..2a2abd2a --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-builtin-tools.md @@ -0,0 +1,275 @@ +--- +title: Built-in Tools Reference +--- + +The Agent has a set of built-in tools that the AI can call automatically during a conversation. These tools are available by default in persistent conversations, and script developers usually don't need to call them directly — the AI automatically picks the right tool based on the user's intent. + +Understanding what these tools can do helps you write better system prompts and custom tools. + +## Web Data Fetching + +### web_fetch + +Fetches the content of a URL, supporting HTML-to-text extraction and LLM summarization. + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `url` | `string` | Yes | Target URL (http/https only) | +| `prompt` | `string` | No | Summarization prompt (when provided, the LLM is used to distill the content) | +| `max_length` | `number` | No | Maximum character count for the content | + +**Behavior details:** +- 30-second request timeout +- HTML content automatically extracts the main body (removing navigation, sidebars, etc.) +- JSON responses are automatically parsed +- Plain text is returned as-is +- When `prompt` is provided, the fetched content is sent to the LLM for summarization + +**Return value:** +```json +{ + "url": "https://example.com", + "content_type": "text/html", + "content": "The extracted body content...", + "truncated": false, + "final_url": "https://example.com/redirected" +} +``` + +### web_search + +Queries a search engine and returns structured search results. + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `query` | `string` | Yes | The search keywords | +| `max_results` | `number` | No | Maximum number of results (defaults to 5, capped at 10) | + +**Supported search engines:** + +| Engine | Description | Configuration required | +|------|------|---------| +| DuckDuckGo | The default engine | No configuration needed | +| Bing | Microsoft Bing Search | Requires an API Key | +| Baidu | Baidu Search | No API Key needed | +| Google Custom Search | Google Custom Search | Requires an API Key + CSE ID | + +Search engines are configured in the dashboard under Agent → Settings. + +**Return value:** +```json +[ + { + "title": "Search result title", + "url": "https://example.com/result", + "snippet": "Result snippet text..." + } +] +``` + +### get_tab_content + +Reads the rendered page content of a given tab, converting it into structured Markdown with CSS-selector annotations. + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `tab_id` | `number` | Yes | Tab ID | +| `selector` | `string` | No | A CSS selector; only extracts the matching part | +| `prompt` | `string` | No | Summarization prompt | +| `max_length` | `number` | No | Maximum character count for the content | + +Difference from `web_fetch`: `get_tab_content` reads the page **as already rendered by the browser** (including dynamic JS content), while `web_fetch` makes a new HTTP request. + +**Return value:** +```json +{ + "tab_id": 123, + "url": "https://example.com", + "title": "Page title", + "content": "Structured content...", + "truncated": false, + "used_selector": "main" +} +``` + +## Tab Management + +### list_tabs + +Queries open tabs, supporting several filter conditions. + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `url_pattern` | `string` | No | A regex to match the URL | +| `title_pattern` | `string` | No | A regex to match the title | +| `active` | `boolean` | No | Only return the active tab | +| `window_id` | `number` | No | A specific window | +| `audible` | `boolean` | No | Only return tabs currently playing audio | + +### open_tab + +Opens a new tab or navigates an existing one. + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `url` | `string` | Yes | Target URL | +| `tab_id` | `number` | No | An existing tab ID (when provided, navigates that tab; otherwise a new tab is opened) | +| `active` | `boolean` | No | Whether to activate it (defaults to `true`) | +| `window_id` | `number` | No | A specific window | +| `wait_until_loaded` | `boolean` | No | Whether to wait for the page to finish loading (defaults to `true`) | + +### close_tab + +Closes a tab. + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `tab_id` | `number` | Yes | Tab ID | + +### activate_tab + +Activates a tab and focuses its window. + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `tab_id` | `number` | Yes | Tab ID | + +## File System (OPFS) + +### opfs_write + +Writes a file to the workspace. + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `path` | `string` | Yes | File path | +| `content` | `string` | Yes | File content (supports binary via a data URL) | + +### opfs_read + +Reads a file from the workspace. By default it auto-detects the file type: text files return their content, binary files return a blob URL. + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `path` | `string` | Yes | File path | +| `mode` | `string` | No | `"text"` / `"blob"` / `"auto"` (default), forces the return mode | +| `offset` | `number` | No | Starting line number (1-based), text mode only | +| `limit` | `number` | No | Number of lines to read, text mode only (pagination is required once text exceeds 200 lines) | + +### opfs_list + +Lists the contents of a directory. + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `path` | `string` | No | Directory path (defaults to the root directory) | + +### opfs_delete + +Deletes a file or directory. + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `path` | `string` | Yes | File/directory path | + +## User Interaction + +### ask_user + +Asks the user a question, supporting either free-form input or a structured choice. + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `question` | `string` | Yes | The question content | +| `options` | `string[]` | No | A list of choices (when provided, this becomes a multiple-choice question) | +| `multiple` | `boolean` | No | Whether multiple selection is allowed (defaults to `false`) | + +**Timeout:** returns `{ answer: null, reason: "timeout" }` after 5 minutes without a response. + +**Return value:** +```json +{ "answer": "The user's answer text" } +``` + +### execute_script + +Executes JavaScript code on the page or in the sandbox. + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `code` | `string` | Yes | The JavaScript code | +| `target` | `string` | Yes | `"page"` or `"sandbox"` | +| `tab_id` | `number` | No | The target tab when `target` is page (defaults to the current active tab) | +| `world` | `string` | No | `"MAIN"` or `"ISOLATED"` (default), page mode only | + +**Execution environment comparison:** + +| Environment | DOM | Page JS | Extension blob URLs | Use case | +|------|-----|---------|---------------|---------| +| page + ISOLATED | Yes | No | Yes | Reading the DOM, extracting content | +| page + MAIN | Yes | Yes | No | Calling page functions | +| sandbox | No | No | No | Pure computation | + +## Sub-agents + +### agent + +Spawns an independent sub-agent to handle a complex sub-task. + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `prompt` | `string` | Yes | The sub-task description | +| `description` | `string` | No | A short label (3-5 words, used in the UI) | +| `type` | `string` | No | The sub-agent type (see below); defaults to `"general"` | +| `tab_id` | `number` | No | A tab ID passed to the sub-agent, which will operate on that tab | + +**Sub-agent types:** + +| type | Description | Available tools | +|------|------|---------| +| `researcher` | Information retrieval (read-only) | web_search, web_fetch, reading page content | +| `page_operator` | Browser automation | Tab management, DOM operations, page interaction | +| `general` | General-purpose (default) | All tools | + +**Characteristics:** +- A sub-agent has its own independent conversation context +- It **cannot** use `ask_user` or `agent` (to prevent recursion) +- The sub-agent's events are passed to the parent conversation via `sub_agent_event` + +## Task Management + +This group of tools manages a temporary task list within a conversation (in-memory, not persisted). + +### create_task + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `subject` | `string` | Yes | Task title | +| `description` | `string` | No | Detailed description | + +### get_task + +| Parameter | Type | Required | +|------|------|------| +| `task_id` | `string` | Yes | + +### update_task + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `task_id` | `string` | Yes | Task ID | +| `status` | `string` | No | `"pending"` / `"in_progress"` / `"completed"` | +| `subject` | `string` | No | New title | +| `description` | `string` | No | New description | + +### list_tasks + +Takes no parameters; returns a brief list of all tasks. + +### delete_task + +| Parameter | Type | Required | +|------|------|------| +| `task_id` | `string` | Yes | + +> The task management tools mainly let the AI track its own progress while working through complex, multi-step tasks; task data is not persisted. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-conversation.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-conversation.md new file mode 100644 index 00000000..3630098f --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-conversation.md @@ -0,0 +1,285 @@ +--- +title: Conversation API +--- + +`@grant CAT.agent.conversation` + +The Conversation API is the core of the Agent system, letting a script create AI conversations, send messages, and receive replies. + +## Creating a Conversation + +```javascript +const conv = await CAT.agent.conversation.create(options?); +``` + +### ConversationCreateOptions + +| Parameter | Type | Default | Description | +|------|------|--------|------| +| `id` | `string` | auto-generated | Conversation ID, used to resume an existing conversation | +| `system` | `string` | — | Custom system prompt, appended after the built-in prompt | +| `model` | `string` | default model | Model ID (obtained after configuring it in the dashboard) | +| `maxIterations` | `number` | `20` | Maximum number of tool-call loop iterations within a single conversation turn | +| `skills` | `"auto" \| string[]` | — | `"auto"` loads all Skills automatically, or specify an array of Skill names | +| `tools` | `ToolDefinition[]` | — | Custom tool list (see below) | +| `commands` | `Record<string, CommandHandler>` | — | Custom conversation commands | +| `ephemeral` | `boolean` | `false` | Ephemeral conversation, not persisted to storage | +| `cache` | `boolean` | `true` | Enable Prompt Caching (reduces token usage) | +| `background` | `boolean` | `false` | Background conversation that keeps running after the UI disconnects; can be reconnected via `attach()` | + +### Custom Tools + +A script can register its own tools for the AI to call: + +```javascript +const conv = await CAT.agent.conversation.create({ + tools: [{ + name: "get_weather", + description: "Get weather information for a given city", + parameters: { + type: "object", + properties: { + city: { + type: "string", + description: "City name" + }, + unit: { + type: "string", + enum: ["celsius", "fahrenheit"], + description: "Temperature unit" + } + }, + required: ["city"] + }, + handler: async (args) => { + // args = { city: "Beijing", unit: "celsius" } + const data = await fetchWeather(args.city, args.unit); + return { temperature: data.temp, condition: data.condition }; + } + }] +}); +``` + +A tool's `parameters` follows the [JSON Schema](https://json-schema.org/) spec; the AI uses `description` to understand when and how to call the tool. + +### Custom Commands + +You can register custom commands starting with `/`: + +```javascript +const conv = await CAT.agent.conversation.create({ + commands: { + "/export": async (args) => { + // triggered when the user types "/export pdf" + await exportToPdf(args); + return "Export complete"; + } + } +}); +``` + +Built-in commands: `/new` (start a new conversation), `/reset` (reset context), `/compact` (compact message history). + +## Getting an Existing Conversation + +```javascript +const conv = await CAT.agent.conversation.get(conversationId); +// returns null if the conversation doesn't exist +``` + +## ConversationInstance Methods + +### chat — Synchronous Chat + +```javascript +const reply = await conv.chat(content, options?); +``` + +Sends a message and waits for the full reply to come back. The AI may call tools while replying; `chat` waits for all tool calls to finish before returning the final result. + +**Parameters:** + +| Parameter | Type | Description | +|------|------|------| +| `content` | `string \| ContentBlock[]` | Message content: text or multi-modal content blocks | +| `options.tools` | `ToolDefinition[]` | Extra tools appended just for this call (merged with the tools set at creation time) | + +**Return value, ChatReply:** + +| Field | Type | Description | +|------|------|------| +| `content` | `string \| ContentBlock[]` | The AI's reply content | +| `thinking` | `string` | The model's thinking process (only some models support this) | +| `toolCalls` | `ToolCall[]` | The tool calls recorded during this reply | +| `usage` | `{ inputTokens, outputTokens }` | Token usage | +| `command` | `boolean` | Whether this reply was triggered by a command | + +### chatStream — Streaming Chat + +```javascript +const stream = await conv.chatStream(content, options?); +for await (const chunk of stream) { + // handle streaming events +} +``` + +Receives the AI's reply in real time — useful when you need to progressively display the output. + +**StreamChunk event types:** + +| type | Field | Description | +|------|------|------| +| `content_delta` | `content: string` | Incremental text content | +| `thinking_delta` | `thinking: string` | Incremental thinking content | +| `tool_call` | `toolCall: ToolCall` | Tool call info (fires on state changes) | +| `content_block` | `block: ContentBlock` | A content block (image, file, etc.) | +| `done` | `usage: { inputTokens, outputTokens }` | The conversation turn is complete | +| `error` | `error: string, errorCode?: string` | An error occurred | + +**Error codes (errorCode):** + +| Error code | Description | +|--------|------| +| `rate_limit` | API rate limit; usually retried automatically | +| `auth` | Authentication failed; check the API Key | +| `tool_timeout` | Tool execution timed out | +| `max_iterations` | Reached the maximum tool-call loop count | +| `api_error` | Other API error | + +### getMessages — Get Message History + +```javascript +const messages = await conv.getMessages(); +``` + +Returns `ChatMessage[]`, containing every message in the conversation. + +**ChatMessage structure:** + +| Field | Type | Description | +|------|------|------| +| `id` | `string` | Message ID | +| `role` | `"user" \| "assistant" \| "system" \| "tool"` | Message role | +| `content` | `string \| ContentBlock[]` | Message content | +| `thinking` | `string` | Thinking process (assistant messages) | +| `toolCalls` | `ToolCall[]` | Tool call records (assistant messages) | +| `toolCallId` | `string` | The corresponding tool call ID (tool messages) | +| `usage` | `{ inputTokens, outputTokens }` | Token usage | +| `createtime` | `number` | Creation timestamp | + +### clear — Clear the Conversation + +```javascript +await conv.clear(); +``` + +Clears all message history in the conversation. + +### save — Persist the Conversation + +```javascript +await conv.save(); +``` + +Saves the conversation's metadata to storage. Ephemeral conversations (`ephemeral: true`) are not saved by default; calling this method converts them to persistent. + +### attach — Reconnect to a Background Conversation + +```javascript +const stream = await conv.attach(); +for await (const chunk of stream) { + // receive real-time events from the background conversation +} +``` + +When a conversation was created with `background: true` and is still running in the background, you can reconnect to it with `attach()` to receive its subsequent streaming events. + +### Instance Properties + +| Property | Type | Description | +|------|------|------| +| `id` | `string` | Conversation ID | +| `title` | `string` | Conversation title | +| `modelId` | `string` | The model ID in use | + +## Multi-modal Content + +Message content can be a plain text string, or a `ContentBlock[]` array to support multiple modalities: + +```javascript +// Send text + an image +await conv.chat([ + { type: "text", text: "Please analyze the content of this image" }, + { type: "image", attachmentId: "img-id", mimeType: "image/png" } +]); +``` + +### ContentBlock Types + +| type | Required fields | Description | +|------|---------|------| +| `text` | `text: string` | Text content | +| `image` | `attachmentId: string, mimeType: string` | An image; the model must support vision | +| `file` | `attachmentId: string, mimeType: string, name: string` | A file | +| `audio` | `attachmentId: string, mimeType: string` | Audio | + +## Ephemeral vs. Persistent Conversations + +| Feature | Persistent conversation (default) | Ephemeral conversation | +|------|-------------------|---------------------| +| Message storage | Persisted to OPFS | Memory only | +| Built-in tools | All available | Not included; must be supplied via `tools` | +| Conversation list | Visible | Not visible | +| Prompt Caching | Supported | Can be disabled | +| Use case | General conversation | Lightweight one-off tasks, quick Q&A | + +## Context Management + +### Auto-compact + +When the conversation's context usage exceeds **80%** of the model's context window, the system automatically calls the LLM to generate a summary of the history, replacing older messages to free up space. + +### Prompt Caching + +Enabled by default. For Anthropic models, the system prompt and message history are cached, which can significantly reduce token usage and latency on repeated conversation turns. + +Can be disabled with `cache: false`: + +```javascript +const conv = await CAT.agent.conversation.create({ cache: false }); +``` + +## Full Example + +```javascript +// ==UserScript== +// @name Smart Translation Assistant +// @match *://*/* +// @grant CAT.agent.conversation +// @grant CAT.agent.dom +// ==/UserScript== + +// Create a conversation with a custom tool +const conv = await CAT.agent.conversation.create({ + system: "You are a translation assistant. The user will give you web page content — please translate it into Chinese.", + tools: [{ + name: "get_selection", + description: "Get the text the user has selected on the page", + parameters: { type: "object", properties: {} }, + handler: async () => { + return { text: window.getSelection()?.toString() || "No text selected" }; + } + }] +}); + +// Stream the translation result +const stream = await conv.chatStream("Please get the selected text and translate it into Chinese"); +let result = ""; +for await (const chunk of stream) { + if (chunk.type === "content_delta") { + result += chunk.content; + // update the UI in real time + updateTranslationUI(result); + } +} +``` diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-dom.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-dom.md new file mode 100644 index 00000000..311a762a --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-dom.md @@ -0,0 +1,336 @@ +--- +title: DOM API +--- + +`@grant CAT.agent.dom` + +The DOM API provides complete browser page automation capabilities, including navigation, content reading, screenshots, form interaction, and DOM monitoring. + +## Tab Management + +### listTabs — List Tabs + +```javascript +const tabs = await CAT.agent.dom.listTabs(); +``` + +Returns information about every open tab. + +**Return value, TabInfo[]:** + +| Field | Type | Description | +|------|------|------| +| `tabId` | `number` | Tab ID | +| `url` | `string` | Current URL | +| `title` | `string` | Page title | +| `active` | `boolean` | Whether it's the currently active tab | +| `windowId` | `number` | The window ID it belongs to | +| `discarded` | `boolean` | Whether it has been discarded (suspended) | + +## Navigation + +### navigate — Navigate the Page + +```javascript +const result = await CAT.agent.dom.navigate(url, options?); +``` + +**Parameters:** + +| Parameter | Type | Default | Description | +|------|------|--------|------| +| `url` | `string` | — | Target URL (required) | +| `options.tabId` | `number` | currently active tab | Specify a tab | +| `options.waitUntil` | `boolean` | `true` | Whether to wait for the page to finish loading | +| `options.timeout` | `number` | `30000` | Timeout in milliseconds | + +**Return value, NavigateResult:** + +```typescript +{ tabId: number; url: string; title: string } +``` + +## Content Reading + +### readPage — Read Page Content + +```javascript +const page = await CAT.agent.dom.readPage(options?); +``` + +Converts the page DOM into structured text, automatically removing irrelevant elements like `<script>`, `<style>`, `<noscript>`, `<svg>`, and `<link[rel=stylesheet]>`. + +**Parameters:** + +| Parameter | Type | Default | Description | +|------|------|--------|------| +| `options.tabId` | `number` | currently active tab | Specify a tab | +| `options.selector` | `string` | — | CSS selector; only returns content from matching elements | +| `options.maxLength` | `number` | — | Maximum character count; truncated beyond this | +| `options.removeTags` | `string[]` | — | Additional tag names to remove | + +**Return value, PageContent:** + +| Field | Type | Description | +|------|------|------| +| `title` | `string` | Page title | +| `url` | `string` | Page URL | +| `html` | `string` | The processed page text content | +| `truncated` | `boolean` | Whether the content was truncated | +| `totalLength` | `number` | The original total content length | + +### screenshot — Take a Screenshot + +```javascript +const shot = await CAT.agent.dom.screenshot(options?); +``` + +**Parameters:** + +| Parameter | Type | Default | Description | +|------|------|--------|------| +| `options.tabId` | `number` | currently active tab | Specify a tab | +| `options.quality` | `number` | `80` | JPEG quality (0-100) | +| `options.fullPage` | `boolean` | `false` | Capture the full page | +| `options.selector` | `string` | — | CSS selector; only captures the matching element's area | +| `options.saveTo` | `string` | — | Path to save to in the OPFS workspace | + +**Return value, ScreenshotResult:** + +| Field | Type | Description | +|------|------|------| +| `dataUrl` | `string` | A base64 data URL | +| `path` | `string` | The OPFS save path (when `saveTo` is used) | +| `size` | `number` | The file size (when `saveTo` is used) | + +**Screenshot mode selection:** + +| Scenario | Behavior | +|------|------| +| `selector` is used | Locates the element's bounds via CDP and crops the screenshot | +| Background tab | Tries a CDP screenshot; if it fails, activates the tab and uses `captureVisibleTab` | +| Foreground tab | Uses `captureVisibleTab` directly | + +```javascript +// Save a screenshot to OPFS +const shot = await CAT.agent.dom.screenshot({ + saveTo: "screenshots/page.png", + quality: 90 +}); +console.log(`Saved to ${shot.path}, size ${shot.size} bytes`); +``` + +## Page Interaction + +### click — Click an Element + +```javascript +const result = await CAT.agent.dom.click(selector, options?); +``` + +**Parameters:** + +| Parameter | Type | Default | Description | +|------|------|--------|------| +| `selector` | `string` | — | CSS selector (required) | +| `options.tabId` | `number` | currently active tab | Specify a tab | +| `options.trusted` | `boolean` | `false` | Use CDP to fire a real mouse event | + +**Return value, ActionResult:** + +| Field | Type | Description | +|------|------|------| +| `success` | `boolean` | Whether it succeeded | +| `navigated` | `boolean` | Whether the click caused page navigation | +| `url` | `string` | The new URL after navigation | +| `newTab` | `boolean` | Whether a new tab was opened | + +**trusted vs. regular click:** + +- `trusted: false` (default) — simulates `element.click()` via injected JS; fast, but some sites may detect it as a non-genuine event +- `trusted: true` — sends a real mouse event via the Chrome DevTools Protocol, behaving identically to a real user action, but requires the debugger permission + +### fill — Fill a Form + +```javascript +const result = await CAT.agent.dom.fill(selector, value, options?); +``` + +**Parameters:** + +| Parameter | Type | Description | +|------|------|------| +| `selector` | `string` | CSS selector (required) | +| `value` | `string` | The value to fill in (required) | +| `options.tabId` | `number` | Specify a tab | +| `options.trusted` | `boolean` | Use CDP to simulate keyboard input | + +**Behavior:** +- Normal mode: sets `element.value` and dispatches an `input` event +- trusted mode: CDP focuses the element → types character by character + +### scroll — Scroll the Page + +```javascript +const result = await CAT.agent.dom.scroll(direction, options?); +``` + +**Parameters:** + +| Parameter | Type | Description | +|------|------|------| +| `direction` | `"up" \| "down" \| "top" \| "bottom"` | Scroll direction (required) | +| `options.tabId` | `number` | Specify a tab | +| `options.selector` | `string` | Scroll a specific container instead of the whole page | + +**Return value, ScrollResult:** + +| Field | Type | Description | +|------|------|------| +| `scrollTop` | `number` | The scroll position after scrolling | +| `scrollHeight` | `number` | The total content height | +| `clientHeight` | `number` | The visible area height | +| `atBottom` | `boolean` | Whether it has scrolled to the bottom | + +### waitFor — Wait for an Element + +```javascript +const result = await CAT.agent.dom.waitFor(selector, options?); +``` + +Polls for the specified element to appear on the page (checking every 500ms). + +**Parameters:** + +| Parameter | Type | Default | Description | +|------|------|--------|------| +| `selector` | `string` | — | CSS selector (required) | +| `options.tabId` | `number` | currently active tab | Specify a tab | +| `options.timeout` | `number` | `10000` | Timeout in milliseconds | + +**Return value, WaitForResult:** + +| Field | Type | Description | +|------|------|------| +| `found` | `boolean` | Whether the element was found | +| `element` | `object` | Element info (only present when found=true) | +| `element.selector` | `string` | The matching selector | +| `element.tag` | `string` | Tag name | +| `element.text` | `string` | Text content | +| `element.role` | `string` | ARIA role | +| `element.type` | `string` | input type | +| `element.visible` | `boolean` | Whether it's visible | + +## Script Execution + +### executeScript — Execute JavaScript + +```javascript +const result = await CAT.agent.dom.executeScript(code, options?); +``` + +**Parameters:** + +| Parameter | Type | Default | Description | +|------|------|--------|------| +| `code` | `string` | — | JavaScript code (required) | +| `options.tabId` | `number` | currently active tab | Specify a tab | +| `options.world` | `"MAIN" \| "ISOLATED"` | `"ISOLATED"` | Execution environment | + +**Two execution environments:** + +| Environment | Description | Use case | +|------|------|---------| +| **ISOLATED** | The extension's isolated environment, separate from the page's JS | DOM manipulation, reading content, using the extension's blob URLs | +| **MAIN** | The page's own environment, sharing the `window` object | Calling the page's JS functions, reading page variables | + +```javascript +// ISOLATED — safely read the DOM +const title = await CAT.agent.dom.executeScript( + "return document.querySelector('h1')?.textContent", + { world: "ISOLATED" } +); + +// MAIN — call a JS function on the page +const data = await CAT.agent.dom.executeScript( + "return window.__APP_STATE__", + { world: "MAIN" } +); +``` + +> The code is wrapped in `new Function()` for execution, supporting a `return` value. The timeout is 30 seconds. + +## DOM Monitoring + +Monitors DOM changes and dialog events on the page via the Chrome DevTools Protocol. + +### startMonitor — Start Monitoring + +```javascript +await CAT.agent.dom.startMonitor(tabId); +``` + +Starts monitoring DOM changes and dialogs (alert/confirm/prompt) on the given tab. + +### stopMonitor — Stop Monitoring + +```javascript +const result = await CAT.agent.dom.stopMonitor(tabId); +``` + +Stops monitoring and returns the changes collected. + +**Return value, MonitorResult:** + +| Field | Type | Description | +|------|------|------| +| `dialogs` | `Array<{ type, message }>` | The list of dialogs | +| `addedNodes` | `Array<{ tag, id?, class?, role?, text }>` | A summary of newly added DOM nodes | + +### peekMonitor — Check Monitoring Status + +```javascript +const status = await CAT.agent.dom.peekMonitor(tabId); +``` + +Non-destructively checks the current monitoring status. + +**Return value, MonitorStatus:** + +| Field | Type | Description | +|------|------|------| +| `hasChanges` | `boolean` | Whether there are changes | +| `dialogCount` | `number` | The number of dialogs | +| `nodeCount` | `number` | The number of newly added nodes | + +## Full Example + +```javascript +// ==UserScript== +// @name Automatic Form Filling +// @match https://example.com/form +// @grant CAT.agent.dom +// ==/UserScript== + +// Wait for the form to load +await CAT.agent.dom.waitFor("form#signup", { timeout: 5000 }); + +// Fill in the form +await CAT.agent.dom.fill("input[name=username]", "test_user"); +await CAT.agent.dom.fill("input[name=email]", "test@example.com"); + +// Check the agreement checkbox +await CAT.agent.dom.click("input[type=checkbox]#agree"); + +// Screenshot the filled-in result +await CAT.agent.dom.screenshot({ + selector: "form#signup", + saveTo: "screenshots/form-filled.png" +}); + +// Click submit +const result = await CAT.agent.dom.click("button[type=submit]", { trusted: true }); +if (result.navigated) { + console.log("Form submitted successfully, navigated to:", result.url); +} +``` diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-mcp.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-mcp.md new file mode 100644 index 00000000..5da784ad --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-mcp.md @@ -0,0 +1,169 @@ +--- +title: MCP Management API +--- + +`@grant CAT.agent.mcp` + +The MCP ([Model Context Protocol](https://modelcontextprotocol.io/)) Management API lets a script manage MCP server connections. The tools an MCP server provides are automatically registered with the Agent for AI conversations to call. + +## MCP Servers + +ScriptCat's MCP Client uses the **Streamable HTTP** transport protocol (JSON-RPC 2.0 over POST), supporting MCP protocol version `2025-03-26`. + +An MCP server can provide three kinds of capabilities: + +| Capability | Description | +|------|------| +| **Tools** | Tool functions, automatically registered as tools the Agent can call | +| **Resources** | Readable resources (text/binary) | +| **Prompts** | Prompt templates, supporting parameters | + +## listServers — List Servers + +```javascript +const servers = await CAT.agent.mcp.listServers(); +``` + +**Return value, MCPServerConfig[]:** + +| Field | Type | Description | +|------|------|------| +| `id` | `string` | Server ID | +| `name` | `string` | Display name | +| `url` | `string` | The HTTP endpoint address | +| `apiKey` | `string` | API Key (optional) | +| `headers` | `Record<string, string>` | Custom request headers (optional) | +| `enabled` | `boolean` | Whether it's enabled | +| `createtime` | `number` | Creation timestamp | +| `updatetime` | `number` | Update timestamp | + +## getServer — Get Server Details + +```javascript +const server = await CAT.agent.mcp.getServer(serverId); +``` + +## addServer — Add a Server + +```javascript +const server = await CAT.agent.mcp.addServer({ + name: "My MCP Server", + url: "https://mcp.example.com/api", + apiKey: "sk-xxx", // optional + headers: { // optional custom headers + "X-Custom": "value" + }, + enabled: true +}); +``` + +## updateServer — Update a Server + +```javascript +await CAT.agent.mcp.updateServer(serverId, { + name: "New name", + enabled: false +}); +``` + +## removeServer — Remove a Server + +```javascript +await CAT.agent.mcp.removeServer(serverId); +``` + +## testConnection — Test the Connection + +```javascript +await CAT.agent.mcp.testConnection(serverId); +``` + +Attempts to connect to the server and exchange protocol versions; returns nothing on success, throws on failure. + +## listTools — List Tools + +```javascript +const tools = await CAT.agent.mcp.listTools(serverId); +``` + +Returns the list of tools the server provides; each tool includes `name`, `description`, and `inputSchema` (a JSON Schema parameter definition). + +Tools from enabled MCP servers are automatically registered with the Agent, named using the format `mcp_{serverId}_{toolName}`. + +## listResources — List Resources + +```javascript +const resources = await CAT.agent.mcp.listResources(serverId); +``` + +Returns the list of resources the server can provide. + +## readResource — Read a Resource + +```javascript +const result = await CAT.agent.mcp.readResource(serverId, uri); +``` + +**Parameters:** + +| Parameter | Type | Description | +|------|------|------| +| `serverId` | `string` | Server ID | +| `uri` | `string` | Resource URI | + +Returns the resource's content. + +## listPrompts — List Prompt Templates + +```javascript +const prompts = await CAT.agent.mcp.listPrompts(serverId); +``` + +## getPrompt — Get a Prompt + +```javascript +const messages = await CAT.agent.mcp.getPrompt(serverId, promptName, args?); +``` + +**Parameters:** + +| Parameter | Type | Description | +|------|------|------| +| `serverId` | `string` | Server ID | +| `promptName` | `string` | Prompt name | +| `args` | `Record<string, string>` | Prompt parameters | + +## Full Example + +```javascript +// ==UserScript== +// @name MCP Tool Management +// @match *://*/* +// @grant CAT.agent.mcp +// @grant CAT.agent.conversation +// ==/UserScript== + +// Add an MCP server +const server = await CAT.agent.mcp.addServer({ + name: "Knowledge Base", + url: "https://my-kb.example.com/mcp", + apiKey: "my-api-key", + enabled: true +}); + +// Test the connection +try { + await CAT.agent.mcp.testConnection(server.id); + console.log("Connected successfully!"); +} catch (e) { + console.error("Connection failed:", e); +} + +// See the available tools +const tools = await CAT.agent.mcp.listTools(server.id); +console.log("Available tools:", tools.map(t => t.name)); + +// Use it in a conversation — MCP tools are registered automatically, so the AI can call them directly +const conv = await CAT.agent.conversation.create(); +const reply = await conv.chat("Please use the knowledge base to search for information about ScriptCat"); +``` diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-model.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-model.md new file mode 100644 index 00000000..087261c5 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-model.md @@ -0,0 +1,91 @@ +--- +title: Model Query API +--- + +`@grant CAT.agent.model` + +The Model Query API provides read-only access to query the model information the user has configured in the dashboard. For security reasons, the API Key is never exposed to scripts. + +## list — List All Models + +```javascript +const models = await CAT.agent.model.list(); +``` + +**Return value, ModelSummary[]:** + +| Field | Type | Description | +|------|------|------| +| `id` | `string` | Model ID | +| `name` | `string` | Display name | +| `provider` | `"openai" \| "anthropic" \| "zhipu"` | Provider type | +| `apiBaseUrl` | `string` | The API base address | +| `model` | `string` | The model identifier (e.g. `gpt-4o`, `claude-sonnet-4-20250514`) | +| `maxTokens` | `number` | Maximum output token count | +| `contextWindow` | `number` | Context window size | +| `supportsVision` | `boolean` | Whether it supports visual input (images) | +| `supportsImageOutput` | `boolean` | Whether it supports image generation | + +> Note: the return value **does not include** the `apiKey` field. + +## get — Get a Specific Model + +```javascript +const model = await CAT.agent.model.get(modelId); +``` + +Returns `null` if the model doesn't exist. + +## getDefault — Get the Default Model ID + +```javascript +const defaultId = await CAT.agent.model.getDefault(); +``` + +Returns the default model ID string set by the user. + +## getSummary — Get a Model List Summary + +```javascript +const summary = await CAT.agent.model.getSummary(); +``` + +Returns a text summary string of all configured models, suitable for injecting directly into a prompt for the AI to reference. + +## Use Cases + +### Letting the User Choose a Model + +```javascript +// ==UserScript== +// @name Model Selection Example +// @grant CAT.agent.model +// @grant CAT.agent.conversation +// ==/UserScript== + +const models = await CAT.agent.model.list(); +const defaultId = await CAT.agent.model.getDefault(); + +// Present these to the user to choose from +const selectedModel = models.find(m => m.supportsVision) || models[0]; + +const conv = await CAT.agent.conversation.create({ + model: selectedModel.id +}); +``` + +### Checking Model Capabilities + +```javascript +const model = await CAT.agent.model.get("my-model-id"); +if (model?.supportsVision) { + // can send images + await conv.chat([ + { type: "text", text: "Please describe this image" }, + { type: "image", attachmentId: imgId, mimeType: "image/png" } + ]); +} else { + // text only + await conv.chat("Please describe the content of the current page"); +} +``` diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-opfs.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-opfs.md new file mode 100644 index 00000000..7fcbc586 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-opfs.md @@ -0,0 +1,204 @@ +--- +title: OPFS File API +--- + +`@grant CAT.agent.opfs` + +The OPFS (Origin Private File System) File API lets a script read and write files in the Agent workspace. All paths are relative to the `agents/workspace/` directory. + +## write — Write a File + +```javascript +const result = await CAT.agent.opfs.write(path, content); +``` + +**Parameters:** + +| Parameter | Type | Description | +|------|------|------| +| `path` | `string` | File path (required); supports nested directories | +| `content` | `string \| Blob` | The file content | + +**Supported `content` formats:** + +| Format | Description | +|------|------| +| A plain string | Saved as a UTF-8 text file | +| A data URL string | Automatically decoded and saved as binary (e.g. `data:image/png;base64,...`) | +| A `Blob` object | Saved directly as binary data | + +**Return value, WriteResult:** + +| Field | Type | Description | +|------|------|------| +| `path` | `string` | The path the file was saved to | +| `size` | `number` | File size in bytes | + +```javascript +// Write a text file +await CAT.agent.opfs.write("data/config.json", JSON.stringify({ key: "value" })); + +// Write a binary file (data URL) +const canvas = document.createElement("canvas"); +const dataUrl = canvas.toDataURL("image/png"); +await CAT.agent.opfs.write("images/chart.png", dataUrl); +``` + +> If the parent directories in the path don't exist, they're created automatically. If the file already exists, its content is overwritten. + +## read — Read a File + +```javascript +const result = await CAT.agent.opfs.read(path, format?); +``` + +**Parameters:** + +| Parameter | Type | Default | Description | +|------|------|--------|------| +| `path` | `string` | — | File path (required) | +| `format` | `"text" \| "bloburl"` | `"text"` | The read format | + +**Return value, ReadResult:** + +| Field | Type | Condition | Description | +|------|------|------|------| +| `path` | `string` | Always | File path | +| `size` | `number` | Always | File size | +| `content` | `string` | format="text" | The file's text content | +| `blobUrl` | `string` | format="bloburl" | A blob URL | +| `mimeType` | `string` | format="bloburl" | MIME type | + +**Two read modes:** + +```javascript +// Text mode — good for JSON and text files +const config = await CAT.agent.opfs.read("data/config.json"); +const data = JSON.parse(config.content); + +// Blob URL mode — good for images and binary files +const image = await CAT.agent.opfs.read("images/chart.png", "bloburl"); +// image.blobUrl = "blob:chrome-extension://xxx/yyy" +// This URL can be used inside an executeScript call in the ISOLATED world +``` + +**Automatically recognized MIME types:** + +| Extension | MIME type | +|--------|----------| +| `.jpg` / `.jpeg` | `image/jpeg` | +| `.png` | `image/png` | +| `.gif` | `image/gif` | +| `.webp` | `image/webp` | +| `.svg` | `image/svg+xml` | +| `.mp3` | `audio/mpeg` | +| `.wav` | `audio/wav` | +| `.mp4` | `video/mp4` | +| `.pdf` | `application/pdf` | +| `.json` | `application/json` | +| `.txt` | `text/plain` | +| `.html` | `text/html` | +| `.css` | `text/css` | +| `.js` | `application/javascript` | +| Other | `application/octet-stream` | + +## list — List a Directory + +```javascript +const entries = await CAT.agent.opfs.list(path?); +``` + +**Parameters:** + +| Parameter | Type | Default | Description | +|------|------|--------|------| +| `path` | `string` | `""` | Directory path; an empty string means the root directory | + +**Return value, FileEntry[]:** + +| Field | Type | Description | +|------|------|------| +| `name` | `string` | File/directory name | +| `type` | `"file" \| "directory"` | Type | +| `size` | `number` | File size (only for the `file` type) | + +```javascript +const entries = await CAT.agent.opfs.list("data/"); +for (const entry of entries) { + if (entry.type === "file") { + console.log(`${entry.name} (${entry.size} bytes)`); + } else { + console.log(`${entry.name}/`); + } +} +``` + +## delete — Delete a File or Directory + +```javascript +const result = await CAT.agent.opfs.delete(path); +``` + +Supports recursively deleting a directory and all of its contents. + +**Return value:** + +```typescript +{ success: true } +``` + +## readAttachment — Read an Attachment + +```javascript +const result = await CAT.agent.opfs.readAttachment(attachmentId); +``` + +Reads attachment data (images, files, etc.) from a conversation. The attachment ID comes from `ContentBlock.attachmentId` in a message. + +**Parameters:** + +| Parameter | Type | Description | +|------|------|------| +| `attachmentId` | `string` | Attachment ID (required) | + +**Return value:** + +| Field | Type | Description | +|------|------|------| +| `id` | `string` | Attachment ID | +| `data` | `Blob` | The attachment's binary data | +| `size` | `number` | File size in bytes | +| `mimeType` | `string` | MIME type | + +```javascript +// Read an image attachment generated by the AI in a conversation +const messages = await conv.getMessages(); +const lastMsg = messages[messages.length - 1]; +const imageBlock = lastMsg.content.find(b => b.type === "image"); +if (imageBlock) { + const attachment = await CAT.agent.opfs.readAttachment(imageBlock.attachmentId); + console.log(`Attachment size: ${attachment.size}, type: ${attachment.mimeType}`); +} +``` + +## Blob URL Usage Notes + +- Blob URLs are in the form `blob:chrome-extension://xxx/yyy` +- **Can only be used in the ISOLATED world** (the default environment for `executeScript`) +- The extension's blob URLs cannot be accessed from the MAIN world (the page environment) +- A blob URL's lifetime is tied to the extension session + +```javascript +// Correct: use the blob URL in the ISOLATED world +const img = await CAT.agent.opfs.read("images/photo.png", "bloburl"); +await CAT.agent.dom.executeScript(` + const img = document.createElement("img"); + img.src = "${img.blobUrl}"; + document.body.appendChild(img); +`, { world: "ISOLATED" }); + +// Wrong: not accessible from the MAIN world +await CAT.agent.dom.executeScript(` + fetch("${img.blobUrl}") // this will fail! +`, { world: "MAIN" }); +``` diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-skill-dev.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-skill-dev.md new file mode 100644 index 00000000..8a9d482f --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-skill-dev.md @@ -0,0 +1,420 @@ +--- +title: Skill Development Guide +--- + +A Skill is an extension package for the Agent system, made up of **prompts + tool scripts + reference material**. Skills let you inject domain-specific knowledge and custom tool capabilities into the AI. + +## Skill Directory Structure + +``` +my-skill/ +├── SKILL.cat.md # Required: metadata + prompt (entry file) +├── scripts/ # Optional: SkillScript tool scripts +│ ├── search.js +│ └── export.js +└── references/ # Optional: reference material files + ├── api-docs.md + └── examples.json +``` + +> `SKILL.cat.md` is the Skill's entry file. When installing via URL, ScriptCat first fetches this file, then fetches the other files by relative path based on the `scripts` and `references` declared in its frontmatter. + +## SKILL.cat.md Format + +SKILL.cat.md uses YAML frontmatter to declare metadata, with the Markdown body serving as the prompt given to the AI. + +```markdown +--- +name: "weather-assistant" +description: "Weather lookup assistant, supports global city weather queries and forecasts" +config: + apiKey: + title: "OpenWeather API Key" + type: "text" + secret: true + required: true + unit: + title: "Temperature unit" + type: "select" + values: ["celsius", "fahrenheit"] + default: "celsius" + detailed: + title: "Detailed mode" + type: "switch" + default: false + maxDays: + title: "Forecast days" + type: "number" + default: 7 +--- + +# Weather Lookup Assistant + +You can use the following tools to look up weather information: + +## Tool Description + +- **get_weather**: looks up the current weather and forecast for a given city + - the `city` parameter is the city name (Chinese and English both supported) + - the `days` parameter is the number of forecast days + +## Usage Rules + +1. When the user asks about the weather, first confirm the city name +2. By default, return the current weather plus a 3-day forecast +3. Display temperature according to the configured unit +``` + +### Metadata Fields + +| Field | Type | Required | Description | +|------|------|------|------| +| `name` | `string` | Yes | The Skill's unique identifier (English kebab-case recommended) | +| `description` | `string` | Yes | A short description (shown in the list) | +| `version` | `string` | No | Version number (semver format, e.g. `1.0.0`), used for update checks | +| `scripts` | `string[]` | No | A list of script file names (e.g. `["search.js"]`); fetched automatically from the `scripts/` directory when installing via URL | +| `references` | `string[]` | No | A list of reference-material file names (e.g. `["api-docs.md"]`); fetched automatically from the `references/` directory when installing via URL | +| `config` | `object` | No | The config field definitions | + +### Config Field Types + +| type | Description | Special properties | +|------|------|---------| +| `text` | A text input | `secret`: whether it's masked in the UI | +| `number` | A number input | — | +| `select` | A dropdown select | `values`: the option list (`string[]`) | +| `switch` | A toggle | — | + +**Common properties:** + +| Property | Type | Description | +|------|------|------| +| `title` | `string` | Display title | +| `required` | `boolean` | Whether it's required | +| `default` | `unknown` | Default value | +| `secret` | `boolean` | Whether it's sensitive information | + +The user fills in config values in the Skill settings on the dashboard. + +### The Prompt Body + +The Markdown body is injected as the AI's system prompt. Suggestions for writing it: + +- Describe the tools the Skill provides and what they're for +- Explain the meaning of each tool's parameters and how they should be used +- Give typical use cases and things to watch out for +- If there's reference material, explain how to consult it + +## SkillScript Tool Scripts + +A SkillScript is a tool script the AI can call. Each SkillScript file is registered as one LLM tool. + +### Metadata Format + +```javascript +// ==SkillScript== +// @name get_weather +// @description Look up the weather for a given city +// @param city string [required] City name, Chinese and English both supported +// @param days number Number of forecast days, defaults to 3 +// @param format string [json,text] Output format +// @grant CAT.agent.opfs +// @require https://cdn.example.com/utils.js +// @timeout 60 +// ==SkillScript== +``` + +### Metadata Fields + +| Tag | Description | Example | +|------|------|------| +| `@name` | The tool's name (used when the AI calls it) | `get_weather` | +| `@description` | The tool's description (the AI uses this to decide when to call it) | `Look up city weather` | +| `@param` | Parameter definition (can repeat) | see below | +| `@grant` | The GM API permission needed | `CAT.agent.opfs` | +| `@require` | An external library URL (cached after loading) | `https://cdn.example.com/lib.js` | +| `@timeout` | Execution timeout in seconds | `60` (default 300) | + +### `@param` Syntax + +``` +@param paramName type[enumValues] [required] description +``` + +**Type:** `string`, `number`, `boolean` + +**Enum values (optional):** wrapped in square brackets, comma-separated + +**Required marker:** add `[required]` before the description + +```javascript +// A required string parameter +// @param city string [required] City name + +// A string parameter with an enum +// @param unit string [celsius,fahrenheit] Temperature unit + +// An optional number parameter +// @param days number Number of forecast days + +// A boolean parameter +// @param detailed boolean Whether to return detailed information +``` + +Parameter definitions are automatically converted into a JSON Schema for the LLM to use when calling the tool. + +### Writing the Script + +```javascript +// ==SkillScript== +// @name get_weather +// @description Look up the weather for a given city +// @param city string [required] City name +// @param days number Number of forecast days +// @timeout 30 +// ==SkillScript== + +// 1. Receive the parameters passed in by the AI via arguments[0] +const { city, days = 3 } = arguments[0]; + +// 2. CAT_CONFIG provides the Skill config the user filled in on the dashboard +const apiKey = CAT_CONFIG.apiKey; +const unit = CAT_CONFIG.unit || "celsius"; + +// 3. Run the business logic +const url = `https://api.openweathermap.org/data/2.5/forecast?q=${city}&cnt=${days}&units=${unit === "celsius" ? "metric" : "imperial"}&appid=${apiKey}`; +const response = await fetch(url); + +if (!response.ok) { + throw new Error(`API request failed: ${response.status}`); +} + +const data = await response.json(); + +// 4. Use return to send the result back to the AI +return { + city: data.city.name, + country: data.city.country, + forecasts: data.list.map(item => ({ + date: item.dt_txt, + temp: item.main.temp, + description: item.weather[0].description + })) +}; +``` + +### Execution Environment + +| Feature | Description | +|------|------| +| **Where it runs** | The sandbox's isolated environment (no DOM access) | +| **Getting parameters** | `arguments[0]` — the parameter object passed in by the AI | +| **Getting config** | `CAT_CONFIG` — a global read-only object containing the user's config | +| **Return value** | The `return` statement returns a JSON-serializable value | +| **Async support** | Supports `async/await`, `fetch`, `Promise` | +| **External libraries** | Loaded via `@require`, cached locally | +| **Timeout** | 300 seconds by default, customizable via `@timeout` | +| **GM API** | Available once declared via `@grant` (e.g. `CAT.agent.opfs`) | + +### `@require` External Libraries + +```javascript +// ==SkillScript== +// @name analyze +// @description Data analysis +// @require https://cdn.jsdelivr.net/npm/lodash@4/lodash.min.js +// ==SkillScript== + +// Libraries loaded via @require can be used directly +const result = _.groupBy(data, "category"); +return result; +``` + +External libraries are cached the first time they're loaded, and the cached version is used directly on subsequent executions. + +## Reference Material + +Files in the `references/` directory serve as reference material the AI can consult. When needed, the AI reads these files via the built-in `read_reference` tool. + +Good candidates for reference material: +- API documentation +- Data format descriptions +- Collections of usage examples +- Domain knowledge documents + +## Example Repository + +We maintain an official Skill example repository with several ready-to-use Skills and script API examples: + +**[scriptscat/skills](https://github.com/scriptscat/skills)** + +**Skill list:** + +| Directory | Description | Install | +|------|------|------| +| `browser-automation/` | Page analysis, DOM operations, form filling, screenshots, navigation | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/browser-automation/SKILL.cat.md) | +| `scheduled-tasks/` | Cron scheduled tasks (internal + event mode) | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/scheduled-tasks/SKILL.cat.md) | +| `skill-creator/` | Helps create, test, and package new Skills | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/skill-creator/SKILL.cat.md) | +| `file-parser/` | Parses common file formats (Excel, PDF, Word, CSV, PPT) | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/file-parser/SKILL.cat.md) | +| `scriptcat-dev/` | ScriptCat/Tampermonkey script development assistant | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/scriptcat-dev/SKILL.cat.md) | +| `synology-office-sheet/` | Reads/writes Synology Office spreadsheets | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/synology-office-sheet/SKILL.cat.md) | +| `wechat-publisher/` | WeChat Official Account operations assistant — content collection, article writing, and publishing | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/wechat-publisher/SKILL.cat.md) | +| `xiaohongshu-publisher/` | Xiaohongshu (RED) operations assistant — post writing, image generation, and publishing | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/xiaohongshu-publisher/SKILL.cat.md) | + +**Example code:** + +| Directory | Description | +|------|------| +| `examples/conversation/` | Conversation API examples — chat, streaming, tool calls | +| `examples/dom/` | DOM API examples — reading pages, filling forms, tab management | +| `examples/config/` | Skill Config examples — config field declarations and using `CAT_CONFIG` | +| `examples/page_copilot.user.js` | A complete user script example — a right-click AI assistant with a streaming UI | + +It's recommended to start learning Skill development from the code in the example repository. + +## Installation Methods + +### Install via URL + +Open the `SKILL.cat.md` URL directly in the browser; ScriptCat automatically intercepts it and shows the install page. + +You can also do this from the dashboard → Agent → Skill Management: + +1. Click the URL install button +2. Paste the `SKILL.cat.md` URL +3. Confirm the install + +ScriptCat first fetches `SKILL.cat.md`, then fetches the other files by relative path based on the `scripts` and `references` declared in its frontmatter. After installing, it records the `installUrl`, which is later used to check for updates by version number. + +### Installing from a Script + +```javascript +// ==UserScript== +// @grant CAT.agent.skills +// ==/UserScript== + +await CAT.agent.skills.install( + skillMdContent, + [{ name: "search.js", code: scriptCode }], + [{ name: "docs.md", content: docsContent }] +); +``` + +## The Skill Loading Mechanism + +Skills use a three-tier progressive loading mechanism to optimize context usage: + +| Tier | When | Content | +|------|------|------| +| **Summary** | At the start of a conversation | Skill name + description + tool list (injected into the system prompt) | +| **Prompt** | When the AI actively calls `load_skill` | The full body of SKILL.cat.md | +| **Tools** | After load_skill | SkillScripts are registered as callable LLM tools | + +The AI automatically calls `load_skill` when it needs to load the full Skill content and tools. + +## Full Example + +### Directory Structure + +``` +translator-skill/ +├── SKILL.cat.md +├── scripts/ +│ └── translate.js +└── references/ + └── language-codes.md +``` + +### SKILL.cat.md + +```markdown +--- +name: "translator" +description: "Multi-language translation tool, supports 100+ languages" +version: "1.0.0" +scripts: + - translate.js +references: + - language-codes.md +config: + apiKey: + title: "Translation API Key" + type: "text" + secret: true + required: true + defaultTarget: + title: "Default target language" + type: "select" + values: ["zh", "en", "ja", "ko", "fr", "de", "es"] + default: "zh" +--- + +# Translation Assistant + +Use the `translate` tool to translate text. Consult language-codes.md for the full list of language codes. + +## Usage Rules + +- If the user hasn't specified a target language, use the default language from the config +- Automatically split long text into chunks for translation +- Preserve the original formatting (Markdown, code blocks, etc.) +``` + +### scripts/translate.js + +```javascript +// ==SkillScript== +// @name translate +// @description Translate text into a given language +// @param text string [required] The text to translate +// @param target string Target language code (defaults to the config value) +// @param source string Source language code (defaults to auto-detect) +// @timeout 60 +// ==SkillScript== + +const { text, target, source } = arguments[0]; +const apiKey = CAT_CONFIG.apiKey; +const targetLang = target || CAT_CONFIG.defaultTarget || "zh"; + +const response = await fetch("https://api.example.com/translate", { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${apiKey}` + }, + body: JSON.stringify({ + text, + target_language: targetLang, + source_language: source || "auto" + }) +}); + +if (!response.ok) { + throw new Error(`Translation failed: ${response.statusText}`); +} + +const result = await response.json(); +return { + original: text, + translated: result.translated_text, + source_language: result.detected_language, + target_language: targetLang +}; +``` + +### references/language-codes.md + +```markdown +# Language Code Reference + +| Code | Language | +|------|------| +| zh | Chinese | +| en | English | +| ja | Japanese | +| ko | Korean | +| fr | French | +| de | German | +| es | Spanish | +| ... | ... | +``` diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-skill-install.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-skill-install.md new file mode 100644 index 00000000..abdc545c --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-skill-install.md @@ -0,0 +1,96 @@ +--- +title: Installing and Using Skills +--- + +A Skill is an extension package for the Agent that injects domain-specific knowledge and custom tools into the AI. This page covers how to install, configure, and manage Skills. + +:::tip Official Skill Repository +**[scriptscat/skills](https://github.com/scriptscat/skills)** — includes ready-to-use Skills for browser automation, scheduled tasks, file parsing, a script development assistant, and more. +::: + +## Installation Methods + +### Method 1: Install via URL + +Open the `SKILL.cat.md` URL directly in the browser's address bar; ScriptCat automatically intercepts it and shows an install confirmation page. + +For example, installing the official browser-automation Skill: + +``` +https://raw.githubusercontent.com/scriptscat/skills/main/browser-automation/SKILL.cat.md +``` + +You can also do this from the dashboard: + +1. Open the ScriptCat dashboard → **Agent → Skills** +2. Click the **URL** button in the upper right +3. Paste the `SKILL.cat.md` URL +4. Click Install + +ScriptCat automatically fetches `SKILL.cat.md` along with the scripts and reference files it declares. + +### Method 2: Install via ZIP + +1. Open the ScriptCat dashboard → **Agent → Skills** +2. Click the **+** button in the upper right +3. Choose a Skill package in `.zip` format + +The ZIP package's directory structure should follow the standard Skill format (containing `SKILL.cat.md`). + +## Official Skill List + +You can also right-click `Copy Link` and paste it into the Skill Management URL field to install. + +| Skill | Description | Install | +|-------|------|------| +| [browser-automation](https://github.com/scriptscat/skills/tree/main/browser-automation) | Page analysis, DOM operations, form filling, screenshots, navigation | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/browser-automation/SKILL.cat.md) | +| [scheduled-tasks](https://github.com/scriptscat/skills/tree/main/scheduled-tasks) | Cron scheduled tasks (LLM auto-execution / script callbacks) | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/scheduled-tasks/SKILL.cat.md) | +| [skill-creator](https://github.com/scriptscat/skills/tree/main/skill-creator) | Helps create, test, and package new Skills | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/skill-creator/SKILL.cat.md) | +| [file-parser](https://github.com/scriptscat/skills/tree/main/file-parser) | Parses Excel, PDF, Word, CSV, and PPT files | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/file-parser/SKILL.cat.md) | +| [scriptcat-dev](https://github.com/scriptscat/skills/tree/main/scriptcat-dev) | ScriptCat/Tampermonkey script development assistant | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/scriptcat-dev/SKILL.cat.md) | +| [synology-office-sheet](https://github.com/scriptscat/skills/tree/main/synology-office-sheet) | Reads/writes Synology Office spreadsheets | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/synology-office-sheet/SKILL.cat.md) | +| [wechat-publisher](https://github.com/scriptscat/skills/tree/main/wechat-publisher) | WeChat Official Account operations assistant | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/wechat-publisher/SKILL.cat.md) | +| [xiaohongshu-publisher](https://github.com/scriptscat/skills/tree/main/xiaohongshu-publisher) | Xiaohongshu (RED) operations assistant | [Install](https://raw.githubusercontent.com/scriptscat/skills/main/xiaohongshu-publisher/SKILL.cat.md) | + +## Configuring a Skill + +Some Skills require configuration (like an API Key): + +1. Find the installed Skill on the **Agent → Skills** page +2. Click the **settings** icon (gear) +3. Fill in the configuration and save + +Fields marked `secret` in the configuration are masked in the UI. + +## Enable / Disable + +On the Skills management page, use the toggle on a Skill's card to control whether it's enabled. Disabled Skills are not loaded into conversations. + +## Checking for Updates + +Skills installed via URL support version checking: + +1. Click the **Check for Updates** button in the upper right of the Skills page +2. A Skill card with a new version available shows an **Update** button +3. Click it to upgrade with one click + +Updates are compared using the `version` field (in semver format) declared in `SKILL.cat.md`. + +## Using Skills in a Conversation + +Installed Skills are automatically available in Agent conversations. The AI decides when to load and call a Skill's tools based on the conversation content. + +You can also specify which Skills to load when creating a conversation: + +```javascript +const conv = await CAT.agent.conversation.create({ + skills: "auto" // automatically load all Skills + // or specify particular Skills + // skills: ["browser-automation", "file-parser"] +}); +``` + +## Learn More + +- [Skill Management API](./agent-skill.md) — manage Skills programmatically from a script +- [Skill Development Guide](./agent-skill-dev.md) — create your own Skill diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-skill.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-skill.md new file mode 100644 index 00000000..b3fded1c --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-skill.md @@ -0,0 +1,122 @@ +--- +title: Skill Management API +--- + +`@grant CAT.agent.skills` + +The Skill Management API lets a script query, install, uninstall, and invoke Skill packages. + +For Skill development and packaging, see the [Skill Development Guide](../agent-skill-dev). Official Skill example repository: [scriptscat/skills](https://github.com/scriptscat/skills). + +## list — List Installed Skills + +```javascript +const skills = await CAT.agent.skills.list(); +``` + +**Return value, SkillSummary[]:** + +| Field | Type | Description | +|------|------|------| +| `name` | `string` | Skill name | +| `description` | `string` | Skill description | +| `version` | `string` | Version number (semver) | +| `toolNames` | `string[]` | List of included SkillScript tool names | +| `referenceNames` | `string[]` | List of included reference-material file names | +| `hasConfig` | `boolean` | Whether config fields are declared | +| `enabled` | `boolean` | Whether it's enabled (defaults to `true`) | +| `installUrl` | `string` | The install source URL (used for update checks) | +| `installtime` | `number` | Install timestamp | +| `updatetime` | `number` | Update timestamp | + +## get — Get Skill Details + +```javascript +const skill = await CAT.agent.skills.get(name); +``` + +Returns the full `SkillRecord`, or `null` if it doesn't exist. + +**SkillRecord structure:** + +Inherits all fields from `SkillSummary`, plus: + +| Field | Type | Description | +|------|------|------| +| `prompt` | `string` | The Markdown body of SKILL.cat.md (the prompt given to the AI) | +| `config` | `Record<string, SkillConfigField>` | The config field definitions (schema) | + +**SkillConfigField structure:** + +| Field | Type | Description | +|------|------|------| +| `title` | `string` | Display title | +| `type` | `"text" \| "number" \| "select" \| "switch"` | Field type | +| `secret` | `boolean` | Whether it's sensitive information (masked in the UI) | +| `required` | `boolean` | Whether it's required | +| `default` | `unknown` | Default value | +| `values` | `string[]` | The option list (only for the `select` type) | + +## install — Install a Skill + +```javascript +const record = await CAT.agent.skills.install(skillMd, scripts?, references?); +``` + +**Parameters:** + +| Parameter | Type | Description | +|------|------|------| +| `skillMd` | `string` | The content of the SKILL.cat.md file (required) | +| `scripts` | `Array<{ name, code }>` | The list of SkillScript files | +| `references` | `Array<{ name, content }>` | The list of reference-material files | + +If a Skill with the same name already exists, this performs an update instead. + +```javascript +const record = await CAT.agent.skills.install( + `--- +name: my-search +description: Custom search tool +--- + +When the user needs to search, use the search tool.`, + [{ name: "search.js", code: skillScriptCode }], + [{ name: "api-docs.md", content: "# API Documentation\n..." }] +); +``` + +## remove — Uninstall a Skill + +```javascript +const success = await CAT.agent.skills.remove(name); +``` + +Returns `true` if the uninstall succeeded, `false` if the Skill doesn't exist. + +## call — Directly Invoke a SkillScript + +```javascript +const result = await CAT.agent.skills.call(skillName, scriptName, params?); +``` + +Directly executes a SkillScript from the given Skill, bypassing the AI conversation. + +**Parameters:** + +| Parameter | Type | Description | +|------|------|------| +| `skillName` | `string` | Skill name (required) | +| `scriptName` | `string` | SkillScript name (required) | +| `params` | `Record<string, unknown>` | The parameters to pass in (matching the `@param` declarations) | + +```javascript +// Directly call a search script from a Skill +const results = await CAT.agent.skills.call( + "my-search", + "search", + { query: "ScriptCat", limit: 5 } +); +``` + +> SkillScript execution has a timeout limit (300 seconds by default, customizable via `@timeout`). diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-task.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-task.md new file mode 100644 index 00000000..4a580dd8 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-task.md @@ -0,0 +1,197 @@ +--- +title: Scheduled Task API +--- + +`@grant CAT.agent.task` + +The Scheduled Task API lets a script create Cron-expression-based scheduled tasks, supporting two execution modes. + +## Execution Modes + +### Internal Mode + +Automatically executed by the Agent system: +- Automatically creates or resumes a conversation when the cron fires +- Sends the configured `prompt` to the LLM +- Lets you specify a model and Skills +- Execution history and token usage are recorded automatically + +### Event Mode + +Handled by the script itself: +- Sends an event notification to the script when the cron fires +- The script listens for the event via `addListener` +- Fully custom handling logic + +## create — Create a Task + +```javascript +const task = await CAT.agent.task.create(options); +``` + +**Parameters, AgentTaskCreateOptions:** + +| Parameter | Type | Required | Description | +|------|------|------|------| +| `name` | `string` | Yes | Task name | +| `crontab` | `string` | Yes | A standard cron expression (5 fields: minute hour day month weekday) | +| `mode` | `"internal" \| "event"` | Yes | Execution mode | +| `enabled` | `boolean` | No | Whether it's enabled; defaults to `true` | +| `notify` | `boolean` | No | Whether to send a browser notification when triggered | +| `prompt` | `string` | No | The prompt for internal mode | +| `modelId` | `string` | No | The model ID used for internal mode | +| `skills` | `string[]` | No | The list of Skills loaded for internal mode | +| `maxIterations` | `number` | No | The maximum tool-call rounds for internal mode; defaults to `10` | + +**Return value, AgentTask:** + +| Field | Type | Description | +|------|------|------| +| `id` | `string` | Task ID | +| `name` | `string` | Task name | +| `crontab` | `string` | Cron expression | +| `mode` | `string` | Execution mode | +| `enabled` | `boolean` | Whether it's enabled | +| `notify` | `boolean` | Whether notifications are sent | +| `nextruntime` | `number` | Next execution timestamp | +| `lastruntime` | `number` | Last execution timestamp | +| `lastRunStatus` | `"success" \| "error"` | Status of the last execution | +| `lastRunError` | `string` | Error message from the last execution | +| `createtime` | `number` | Creation timestamp | + +**Cron expression examples:** + +| Expression | Description | +|--------|------| +| `* * * * *` | Every minute | +| `0 9 * * *` | Every day at 09:00 | +| `0 */2 * * *` | Every 2 hours | +| `30 8 * * 1-5` | Weekdays at 08:30 | +| `0 0 1 * *` | The 1st of every month at 00:00 | + +## list — List All Tasks + +```javascript +const tasks = await CAT.agent.task.list(); +``` + +Returns every task created by the current script. + +## get — Get Task Details + +```javascript +const task = await CAT.agent.task.get(taskId); +``` + +Returns `undefined` if the task doesn't exist. + +## update — Update a Task + +```javascript +const task = await CAT.agent.task.update(taskId, partial); +``` + +**Updatable fields:** + +```javascript +await CAT.agent.task.update(task.id, { + name: "New name", + crontab: "0 10 * * *", + enabled: false, + prompt: "New prompt", + notify: true +}); +``` + +`nextruntime` is automatically recalculated after an update. + +## remove — Delete a Task + +```javascript +const success = await CAT.agent.task.remove(taskId); +``` + +## runNow — Run Immediately + +```javascript +await CAT.agent.task.runNow(taskId); +``` + +Triggers one execution of the task right away, without waiting for the cron schedule (non-blocking, runs in the background). + +## addListener — Listen for Task Triggers + +```javascript +const listenerId = await CAT.agent.task.addListener(taskId, callback); +``` + +Only used for tasks in **event mode**. Runs the callback when the cron fires. + +**Callback parameter, AgentTaskTrigger:** + +| Field | Type | Description | +|------|------|------| +| `taskId` | `string` | Task ID | +| `name` | `string` | Task name | +| `crontab` | `string` | Cron expression | +| `triggeredAt` | `number` | Trigger timestamp | + +## removeListener — Remove a Listener + +```javascript +await CAT.agent.task.removeListener(listenerId); +``` + +## Full Examples + +### Internal Mode — Automatic AI Execution + +```javascript +// ==UserScript== +// @name Daily News Summary +// @match *://*/* +// @grant CAT.agent.task +// ==/UserScript== + +const task = await CAT.agent.task.create({ + name: "Daily news summary", + crontab: "0 9 * * *", // every day at 9:00 + mode: "internal", + prompt: "Please search today's tech news and generate a short summary saved to OPFS", + skills: ["web-search"], + maxIterations: 10, + notify: true +}); + +console.log("Task created, next run:", new Date(task.nextruntime)); +``` + +### Event Mode — Script Handles It Itself + +```javascript +// ==UserScript== +// @name Scheduled Data Collection +// @match *://*/* +// @grant CAT.agent.task +// @grant CAT.agent.dom +// ==/UserScript== + +const task = await CAT.agent.task.create({ + name: "Stock data collection", + crontab: "*/30 9-15 * * 1-5", // every 30 minutes, 9:00-15:00 on weekdays + mode: "event", + enabled: true, + notify: false +}); + +await CAT.agent.task.addListener(task.id, async (trigger) => { + console.log(`Task triggered: ${trigger.name} at ${new Date(trigger.triggeredAt)}`); + + // custom collection logic + await CAT.agent.dom.navigate("https://finance.example.com/stock"); + const content = await CAT.agent.dom.readPage({ selector: ".stock-table" }); + + // process the data... + console.log("Collection complete"); +}); +``` diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/index.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/index.md new file mode 100644 index 00000000..33cf7806 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/agent/index.md @@ -0,0 +1,104 @@ +--- +title: Agent +--- + +:::caution Testing Phase +The Agent feature is currently still in a testing phase; the following APIs and behavior may change before the official release. +::: + +## Overview + +ScriptCat v1.4 introduces the Agent system, giving user scripts a set of capabilities including AI conversation, browser automation, file management, and scheduled tasks. + +Scripts call these capabilities through the `CAT.agent.*` namespace, and every API requires the corresponding permission to be declared with `@grant`. + +## Feature Modules + +| Module | Permission | Description | +|------|---------|------| +| [Conversation](./agent-conversation) | `@grant CAT.agent.conversation` | Create AI conversations, send messages, stream responses, define custom tools | +| [DOM Operations](./agent-dom) | `@grant CAT.agent.dom` | Page navigation, screenshots, clicking, filling, scrolling, DOM monitoring | +| [Skill](./agent-skill) | `@grant CAT.agent.skills` | Install/uninstall/invoke Skill packages | +| [Scheduled Tasks](./agent-task) | `@grant CAT.agent.task` | Cron scheduled tasks, event listening | +| [Model](./agent-model) | `@grant CAT.agent.model` | Query configured model information (read-only) | +| [OPFS Files](./agent-opfs) | `@grant CAT.agent.opfs` | Read/write Agent workspace files | +| [MCP](./agent-mcp) | `@grant CAT.agent.mcp` | Manage MCP server connections | +| [Skill Development](./agent-skill-dev) | — | SKILL.cat.md + SkillScript development guide | + +## Quick Start + +The simplest possible Agent script: + +```javascript +// ==UserScript== +// @name Hello Agent +// @match *://*/* +// @grant CAT.agent.conversation +// ==/UserScript== + +const conv = await CAT.agent.conversation.create(); +const reply = await conv.chat("Hi, please introduce yourself"); +console.log(reply.content); +``` + +## Architecture Overview + +The Agent system spans multiple isolated contexts within the browser extension: + +``` +User script → Sandbox (isolated execution) + ↓ WindowMessage + Offscreen (DOM access) + ↓ ExtensionMessage + Service Worker (core scheduling) + ├── LLM Provider (OpenAI / Anthropic) + ├── ToolRegistry (tool registration and execution) + ├── SkillScriptExecutor (Skill script execution) + ├── MCPClient (MCP protocol client) + └── TaskScheduler (scheduled task scheduling) +``` + +### Storage Structure + +The Agent stores data using the browser's OPFS (Origin Private File System): + +``` +agents/ +├── conversations/ # conversation history +├── attachments/ # attachments (images, files) +├── skills/{name}/ # Skill package files +│ ├── SKILL.cat.md +│ ├── scripts/ +│ └── references/ +├── tasks/ # scheduled task config and execution records +└── workspace/ # user workspace files (the directory opfs_* tools operate on) +``` + +### Supported Models + +| Provider | Format | Features | +|----------|------|------| +| OpenAI-compatible | OpenAI Chat Completions API | Supports GPT-4o, DeepSeek, and other compatible models | +| Anthropic | Anthropic Messages API | Supports the Claude family, Prompt Caching | +| Zhipu | Zhipu API | Supports the GLM model family | + +Add a Provider and API Key under "Model Configuration" in the dashboard to use it. + +### The Skill Ecosystem + +A Skill is a package combining prompts + tool scripts + reference material, letting you inject domain-specific knowledge and custom tools into the Agent. + +**Official Skill repository: [scriptscat/skills](https://github.com/scriptscat/skills)** + +Includes ready-to-use Skills for browser automation, scheduled tasks, a Skill-creation tool, conversation/DOM/config examples, and more. + +**Installation methods:** + +- **URL install** — open the `SKILL.cat.md` URL directly in the browser; ScriptCat automatically intercepts it and shows the install page. You can also paste the URL under the dashboard's Agent → Skill Management. +- **Script install** — install programmatically via the `CAT.agent.skills.install()` API + +**Checking for updates:** + +A Skill installed via URL records its install source; the dashboard lets you check for updates and upgrade with one click (based on semver comparison of the `version` field). + +See [Skill Management API](./agent-skill) and [Skill Development Guide](./agent-skill-dev) for details. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/api.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/api.md new file mode 100644 index 00000000..837881b1 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/api.md @@ -0,0 +1,634 @@ +--- +title: API Documentation +--- + +## Overview + +This extension's API definitions are based on the [Tampermonkey documentation](https://www.tampermonkey.net/documentation.php). Due to time and effort constraints, only part of the API has been implemented so far, and it will keep iterating. Any API that this extension extends or that differs from the original GM API is specially marked in the documentation (using a `*`). Some APIs also provide a synchronous-style counterpart following the rule `GM.*` — see the documentation content for details. + +For the detailed API definitions, see `scriptcat.d.ts` or the built-in editor hints, as the documentation may not always be up to date. For APIs specific to this extension, see the [CatApi Documentation](cat-api.md). + +You can also find related examples in the [example directory](https://github.com/scriptscat/scriptcat/tree/main/example). + +## Definitions + +### GM_info + +Gets information about the script, including metadata and runtime environment parameters. Commonly used fields include `scriptHandler`, `version`, `scriptMetaStr`, `scriptUpdateURL`, `downloadMode`, and more. See `scriptcat.d.ts` for the detailed (though not exhaustive) definition. + +```js +console.log(GM_info.scriptHandler); +console.log(GM_info.version); +console.log(GM_info.scriptMetaStr); +``` + +* `sandboxMode` currently only has the value `raw`. `runAt` is not supported. `userAgentData` is supported, but may not exactly match Tampermonkey. + +### GM_log \* + +Logging function. A background script's logs can be viewed in the dashboard's run log (click the run status column). Compared to Tampermonkey, a log `level` has been added. + +```typescript +declare function GM_log(message: string, level?: GMTypes.LoggerLevel): void; + +declare namespace GMTypes { + type LoggerLevel = "debug" | "info" | "warn" | "error"; +} +``` + +```js +GM_log("debug info", "debug"); +``` + +### GM_get/set/deleteValue + +Gets or sets a value in storage. Data under the same [**storageName**](meta.md#storagename-) can be shared and synced in real time. + +```typescript +// Add data — note that data can only be one of bool/string/number/object; you cannot store a class instance +declare function GM_setValue(name: string, value: any): void; +// Get data +declare function GM_getValue(name: string, defaultValue?: any): any | undefined; +// Delete data; getting it again returns undefined or defaultValue +declare function GM_deleteValue(name: string): void; +``` + +```js +GM_setValue("foo", 42); +const v = GM_getValue("foo", 0); +GM_deleteValue("foo"); +``` + +#### Note: When `GM_setValue` is called with `undefined`, ScriptCat deletes that key, unlike Tampermonkey/GreaseMonkey, which stores `undefined` as the value. + +#### Note: Because data operations are asynchronous, calling `window.close()` immediately after `GM_setValue` or `GM_deleteValue` may prevent the data from being correctly updated. It's recommended to use `await GM.setValue` or `await GM.deleteValue` to ensure the data operation completes. + +### GM_listValues + +Lists all keys. + +```typescript +declare function GM_listValues(): string[]; +``` + +```js +console.log(GM_listValues()); +``` + +### GM_setValues / GM_getValues / GM_deleteValues \* + +Batch get/set APIs (extension). + +```typescript +// Sets multiple values; values is an object whose keys are the value names and whose values are the value contents +declare function GM_setValues(values: { [key: string]: any }): void; +// Gets multiple values; if keysOrDefaults is an object, its values are used as the defaults +declare function GM_getValues(keysOrDefaults: { [key: string]: any } | string[] | null | undefined): { [key: string]: any }; +// Deletes multiple values; names is an array of strings +declare function GM_deleteValues(names: string[]): void; +``` + +```js +// Batch set +GM_setValues({ a: 1, b: 2 }); +// Batch get (returns the default if not present) +const { a, b, c = 3 } = GM_getValues({ a: 0, b: 0, c: 3 }); +// Batch delete +GM_deleteValues(["a", "b"]); +``` + +#### Note: Because data operations are asynchronous, calling `window.close()` immediately after `GM_setValues` or `GM_deleteValues` may prevent the data from being correctly updated. It's recommended to use `await GM.setValues` or `await GM.deleteValues` to ensure the data operation completes. + +### GM_add/removeValueChangeListener + +> `tabid` was removed after 0.17.0-alpha — see [GM_cookie](#gm_cookie-) for details. + +Listens for changes to a value. `add` returns a listener id, and `remove` can be used to cancel the listener. This method can be used to implement simple communication; using [**storageName**](meta.md#storagename-) enables cross-script communication. + +```typescript +// tabid is only present when listening from a background script +type ValueChangeListener = ( + name: string, + oldValue: any, + newValue: any, + remote: boolean, + tabid?: number +) => any; + +declare function GM_addValueChangeListener( + name: string, + listener: GMTypes.ValueChangeListener +): number; + +declare function GM_removeValueChangeListener(listenerId: number): void; +``` + +```js +const id = GM_addValueChangeListener("foo", (k, oldV, newV, remote) => { + console.log(k, oldV, newV, remote); +}); +GM_removeValueChangeListener(id); +``` + +### GM_getResourceText/GM_getResourceURL + +Gets resource information declared with `@resource`. + +```typescript +// GM_getResourceText gets the resource's text data; byte-type data such as images returns an empty string — use GM_getResourceURL for those instead +declare function GM_getResourceText(name: string): string | undefined; +// GM_getResourceURL gets base64-encoded data; a blob URL can also be obtained via the second parameter +declare function GM_getResourceURL(name: string, isBlobUrl?: boolean): string | undefined; +``` + +```js +const css = GM_getResourceText("mystyle"); +const imgUrl = GM_getResourceURL("logo"); +``` + +### GM_addElement + +Inserts an element into the page. Can bypass CSP restrictions. + +```typescript +declare function GM_addElement(tag: string, attributes: any): HTMLElement; +declare function GM_addElement(parentNode: Element, tag: string, attrs: any): HTMLElement; +``` + +```js +// Insert a script +GM_addElement("script", { src: "https://example.com/app.js" }); +// Insert a style +GM_addElement(document.head, "style", { textContent: ".foo{color:blue}" }); +``` + +### GM_addStyle + +Adds a style to the page and returns the style DOM node. Can bypass CSP restrictions. + +```typescript +declare function GM_addStyle(css: string): HTMLElement; +``` + +```js +GM_addStyle(` + body { background: #f0f0f0; } + .btn { color: red; } +`); +``` + +### GM_openInTab \* + +Opens a new window. + +```typescript +declare function GM_openInTab(url: string, options: GMTypes.OpenTabOptions): GMTypes.Tab; +declare function GM_openInTab(url: string, loadInBackground: boolean): GMTypes.Tab; +declare function GM_openInTab(url: string): GMTypes.Tab; + +declare namespace GMTypes { + interface OpenTabOptions { + /** + * Determines whether the new tab gets focus when opened. + * + * - `true` → the new tab is immediately switched to the foreground. + * - `false` → the new tab opens in the background, without stealing focus from the current page. + * + * Default: true + */ + active?: boolean; + + /** + * Determines where the new tab is inserted. + * + * - If a `boolean`: + * - `true` → inserted right after the current tab. + * - `false` → inserted at the end of the window. + * - If a `number`: + * - `0` → inserted one position before the current tab. + * - `1` → inserted one position after the current tab. + * + * Default: true + */ + insert?: boolean | number; + + /** + * Determines whether the parent tab (i.e. `openerTabId`) is set. + * + * - `true` → the browser can track which tab opened the child tab, + * which helps some extensions (like tab-tree managers) identify parent/child relationships. + * + * Default: true + */ + setParent?: boolean; + + /** + * Whether to open the tab in a private (incognito) window. + * + * Note: ScriptCat's manifest.json sets `"incognito": "split"`, + * so when running in a normal window, tabId/windowId will not be + * available, and only the "open a new tab" action can be performed. + * + * Default: false + */ + incognito?: boolean; + + /** + * Legacy compatibility field, supported only by Tampermonkey. + * Its meaning is the **opposite** of `active`: + * + * - `true` → equivalent to `active = false` (loads in the background). + * - `false` → equivalent to `active = true` (loads in the foreground). + * + * ⚠️ Not recommended: overlaps with `active` and is easy to confuse. + * + * Default: false + * @deprecated Use `active` instead + */ + loadInBackground?: boolean; + + /** + * Whether to pin the new tab to the left side of the browser's tab bar. + * + * - `true` → the new tab is pinned. + * - `false` → a regular tab. + * + * Default: false + */ + pinned?: boolean; + + /** + * Uses `window.open` to open the new tab instead of `chrome.tabs.create`. + * Useful when opening links with certain special protocols, e.g. `vscode://`, `m3u8dl://`. + * Other parameters have no effect when using this open method. + * + * Related: Issue #178 #1043 + * Default: false + */ + useOpen?: boolean; + } + + interface Tab { + close(): void; + onclose?: () => void; + closed?: boolean; + name?: string; + } +} +``` + +```js +const tab = GM_openInTab("https://example.com", { active: false }); +tab.onclose = () => console.log("closed"); +tab.close(); +``` + +### GM_get/saveTab/GM_getTabs + +A method for storing data similar to `GM_setValue`, but this method's lifetime is tied to a single browser tab's open→close cycle, and it cannot be used from a background script. + +```typescript +// Get tab data +declare function GM_getTab(callback: (obj: object) => void): void; +// Save tab data +declare function GM_saveTab(obj: object): void; +// Get all tabs' data +declare function GM_getTabs(callback: (objs: { [key: number]: object }) => void): void; +``` + +```js +GM_saveTab({ foo: 1 }, () => console.log("saved")); +GM_getTab(tab => console.log(tab)); +GM_getTabs(tabs => console.log(tabs)); +``` + +### GM_registerMenuCommand * + +* Registers a menu item that appears in the popup page and the right-click menu; clicking it calls the `listener` function. +* By default, matching Tampermonkey, menu items with the same displayed text only show once. +* Specifying an `id` lets you update the menu item. +* If `name` is an empty string and there is no `listener`, a separator line is added to the right-click menu. + +```typescript +function GM_registerMenuCommand( + name: string, + listener?: (inputValue?: any) => void, + options_or_accessKey?: + | { + id?: number | string; + accessKey?: string; + autoClose?: boolean; // ScriptCat-specific option; defaults to true, and false keeps the popup menu page open after clicking + nested?: boolean; // ScriptCat-specific option; defaults to true, and false raises the browser's right-click menu item from a third-level to a second-level menu + individual?: boolean; // ScriptCat-specific option; defaults to false, and true means identical menu items are not merged together + } + | string +): number; +``` + +```js +const cmdId = GM_registerMenuCommand("Test Command 01", () => alert("Called 01")); +GM_registerMenuCommand("Test Command 02", () => alert("Called 02"), {id: "custom-id"}); +``` + +### GM_unregisterMenuCommand + +Removes a registered menu item by its id. + +```typescript +declare function GM_unregisterMenuCommand(id: number): void; +``` + +```js +GM_unregisterMenuCommand(cmdId); +GM_unregisterMenuCommand("custom-id"); +``` + +### GM_notification \* + +Sends a notification message, providing `progress` and `buttons` capabilities (not supported in Firefox), so a notification can show a progress bar or buttons. Also provides two extra methods, `GM_closeNotification` and `GM_updateNotification` (not supported in Firefox). + +[example](https://github.com/scriptscat/scriptcat/blob/main/example/gm_notification.js) + +```typescript +declare function GM_notification( + details: GMTypes.NotificationDetails, + ondone?: GMTypes.NotificationOnDone +): void; +declare function GM_notification( + text: string, + title: string, + image: string, + onclick: GMTypes.NotificationOnClick +): void; +declare function GM_closeNotification(id: string): void; +declare function GM_updateNotification(id: string, details: GMTypes.NotificationDetails): void; + +declare namespace GMTypes { + interface NotificationDetails { + text?: string; + title?: string; + tag?: string; + image?: string; + highlight?: boolean; + silent?: boolean; + timeout?: number; + url?: string; + onclick?: NotificationOnClick; + ondone?: NotificationOnDone; + progress?: number; + oncreate?: NotificationOnClick; + // At most 2 can exist + buttons?: NotificationButton[]; + } + + interface NotificationThis extends NotificationDetails { + id: string; + } + + type NotificationOnClickEvent = { + event: "click" | "buttonClick"; + id: string; + isButtonClick: boolean; + buttonClickIndex: number | undefined; + byUser: boolean | undefined; + preventDefault: () => void; + highlight: NotificationDetails["highlight"]; + image: NotificationDetails["image"]; + silent: NotificationDetails["silent"]; + tag: NotificationDetails["tag"]; + text: NotificationDetails["tag"]; + timeout: NotificationDetails["timeout"]; + title: NotificationDetails["title"]; + url: NotificationDetails["url"]; + }; + type NotificationOnClick = (this: NotificationThis, event: NotificationOnClickEvent) => unknown; + type NotificationOnDone = (this: NotificationThis, user?: boolean) => unknown; + + interface NotificationButton { + title: string; + iconUrl?: string; + } + +} + +``` + +```js +GM_notification({ title: "Progress", text: "Loading", progress: 50 }); +``` + +#### Note: `GM_closeNotification` and `GM_updateNotification` are ScriptCat-specific. To update a notification, use `tag`. + + +```js +GM_notification({ title: "Progress", text: "Loading", progress: 50, tag: "notification01"}); +GM_notification({ title: "Progress", text: "Done", progress: 100, tag: "notification01"}); // updates the progress +GM_notification({ title: "Progress", text: "Done", progress: 100, tag: "notification01", timeout: 1}); // closes after 1ms +``` + +### GM_setClipboard \* + +Sets the clipboard. A callback is not yet supported, unlike Tampermonkey. + +```typescript +declare function GM_setClipboard( + data: string, + info?: string | { type?: string; mimetype?: string } +): void; +``` + +```js +GM_setClipboard("Hello World", "text"); +``` + +### GM_xmlhttpRequest \* + +* A cross-origin HTTP request that can bypass CSP, supporting domains declared with `@connect`. Some functionality is missing; the cookie feature is not currently supported in Firefox. User authorization is required for normal access; a host described by `@connect` can skip user authorization. + +* `anonymous` and `cookie` are handled differently from Tampermonkey: when `anonymous` is true and `cookie` is present, only the specified cookie is sent, without any other cookies attached. + +* Special headers are also supported: + + - user-agent + - origin + - referer + - cookie + - host + - ... + +```typescript +declare function GM_xmlhttpRequest(details: GMTypes.XHRDetails): GMTypes.AbortHandle<void>; + +declare namespace GMTypes { + interface XHRResponse { + finalUrl?: string; + readyState?: 0 | 1 | 2 | 3 | 4; + responseHeaders?: string; + status?: number; + statusText?: string; + response?: any; + responseText?: string; + responseXML?: Document | null; + } + + interface XHRProgress extends XHRResponse { + done: number; + lengthComputable: boolean; + loaded: number; + position: number; + total: number; + totalSize: number; + } + + type Listener<OBJ> = (event: OBJ) => any; + + interface XHRDetails { + method?: "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS"; + url: string; + headers?: { [key: string]: string }; + data?: string | FormData; + cookie?: string; + binary?: boolean; + timeout?: number; + responseType?: "text" | "arraybuffer" | "blob" | "json" | "document" | "stream"; // stream is a fairly basic implementation in the current version + overrideMimeType?: string; + anonymous?: boolean; + fetch?: boolean; + user?: string; + password?: string; + nocache?: boolean; + redirect?: "follow" | "error" | "manual"; // to stay consistent with Tampermonkey, maxRedirects was deprecated after v0.17.0 in favor of redirect, which forces fetch mode + + onload?: Listener<XHRResponse>; + onloadstart?: Listener<XHRResponse>; + onloadend?: Listener<XHRResponse>; + onprogress?: Listener<XHRProgress>; + onreadystatechange?: Listener<XHRResponse>; + ontimeout?: () => void; + onabort?: () => void; + onerror?: (err: string) => void; + } +} +``` + +```js +GM_xmlhttpRequest({ + method: "GET", + url: "https://api.example.com/data", + onload: res => console.log(res.responseText) +}); +``` + +### GM_download + +* Downloads a file, with headers and other options configurable; compared to Tampermonkey it also supports cookie and anonymous options. If given a blob URL, it opens the download directly and only fires the `onload` event — this differs from Tampermonkey and exists to support background scripts, which can't otherwise create a download (useful for scenarios like generating reports). +* Returns a Promise object and provides an `abort()` method. + +```typescript +declare function GM_download(details: GMTypes.DownloadDetails): GMTypes.AbortHandle<boolean>; +declare function GM_download(url: string, filename: string): GMTypes.AbortHandle<boolean>; + +declare namespace GMTypes { + interface DownloadError { + error: + | "not_enabled" + | "not_whitelisted" + | "not_permitted" + | "not_supported" + | "not_succeeded" + | "unknown"; + details?: string; + } + + interface DownloadDetails { + method?: "GET" | "POST"; + downloadMode?: "native" | "browser"; + url: string; + name: string; + headers?: { [key: string]: string }; + saveAs?: boolean; + timeout?: number; + cookie?: string; + anonymous?: boolean; + + onerror?: Listener<DownloadError>; + ontimeout?: () => void; + onload?: Listener<object>; + onprogress?: Listener<XHRProgress>; + } +} +``` + +```js +// Callback form +const dl = GM_download({ url: "https://example.com/file.zip", name: "file.zip", onload: () => alert("Done") }); +dl.abort(); +``` + +### GM_cookie \* + +Asynchronously operates on page cookies, supporting cross-origin, HttpOnly, and partitioned cookies. + +> After v0.17.0-alpha, the `store` and `tabid` related parameters were removed; ScriptCat now decides whether to get cookies from the incognito or normal window based on the window it's currently in. + +You must declare the operated host with `@connect`, and it requires user authorization to use. While compatible with Tampermonkey's `GM_cookie.list` operation, this isn't recommended, for the sake of consistency. + +* `sameSite` is not supported. + +```typescript +// name and domain cannot both be empty +declare function GM_cookie( + action: GMTypes.CookieAction, + details: GMTypes.CookieDetails, + ondone: (cookie: GMTypes.Cookie[], error: unknown | undefined) => void +): void; + +declare namespace GMTypes { + type CookieAction = "list" | "delete" | "set"; + interface CookieDetails { + url?: string; + name?: string; + value?: string; + domain?: string; + path?: string; + secure?: boolean; + session?: boolean; + httpOnly?: boolean; + expirationDate?: number; + partitionKey?: CookieDetailsPartitionKeyType; + } + interface Cookie { + domain: string; + name: string; + value: string; + session: boolean; + hostOnly: boolean; + expirationDate?: number; + path: string; + httpOnly: boolean; + secure: boolean; + } +} + +// Callback form +GM_cookie("list", { url: "https://example.com" }, (cookies) => { + console.log(cookies); + GM_cookie("set", { + name: "foo", + value: "bar", + domain: "example.com" + }, (result) => { + console.log(result); + GM_cookie("delete", { name: "foo", domain: "example.com" }, (result) => { + console.log(result); + }); + }); +}); + +// Promise form +const cookies = await GM.cookie.list({ url: "https://example.com" }); +await GM.cookie.set({ name: "foo", value: "bar", domain: "example.com" }); +await GM.cookie.delete("foo", { domain: "example.com" }); +``` + +**Note**: You must declare the allowed domain in the metadata using `@connect example.com`. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/background.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/background.md new file mode 100644 index 00000000..29f4570e --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/background.md @@ -0,0 +1,343 @@ +--- +title: Background Script +--- + +Background scripts are suited to scripts that need to keep running continuously. Background scripts are a ScriptCat-specific script type; they run in a sandbox and cannot access the DOM. They can be developed using the same GM APIs as Tampermonkey, and compatibility notes are called out in the documentation. + +## Background Script (`@background`) + +A background script is declared with the `@background` attribute. It lets the script keep running in the background after the script is enabled or the browser starts. + +## Scheduled Script (`@crontab`) + +> A scheduled script is a kind of background script suited to tasks that need to **run repeatedly on a time cycle**. + +A scheduled script is declared with the `@crontab` attribute. It supports minute-level and second-level scheduling, and provides ScriptCat's extended syntax `once` / `once(...)` to avoid running more than once within the same time cycle. + +⚠️ Notes: + +* In a single script, **only the first `@crontab` takes effect** +* It's recommended that the script's **single execution time + retry time** not exceed the cron interval, otherwise executions may overlap + +## Cron Expression Notes + +ScriptCat's cron implementation is based on [**node-cron**](https://github.com/kelektiv/node-cron/), with a small extension on top of standard cron syntax. + +### Expression Format + +#### Standard 5-Field Format (Recommended) + +```text +minute hour day month weekday +``` + +#### Extended 6-Field Format (Not Recommended) + +```text +second minute hour day month weekday +``` + +> ⚠️ The 6-field format is not recommended +> Browser environments can't guarantee second-level precision, and it increases performance overhead — the background page may have its scheduling delayed. + +### Syntax Available Per Field + +| Syntax | Meaning | Example | +| ------- | -------------------- | ------------------------ | +| `*` | Any value | `*` (every minute/hour) | +| number | Specific value | `5` (the 5th minute) | +| `a,b,c` | Multiple discrete values | `1,15,30` | +| `a-b` | Contiguous range | `10-23` | +| `*/n` | Every n units | `*/5` | +| `a-b/n` | Range with step | `10-50/10` | + +#### Weekday Rules + +* `1–6`: Monday through Saturday +* `0` or `7`: Sunday + +## The `once` Extension Syntax + +### What `once` Means + +Using `once` in a cron expression means: + +> **Within the current time cycle, only allow one successful execution** + +Even if later time points within the same cycle still match the cron rule, the script will not run again. + +### `once` vs. `once(...)` + +| Syntax | Underlying cron value for this field | Description | +| ------------- | ------------------------------------- | ------------------------------------------------------------------ | +| `once` | `*` (any value) | Runs on the first match within the cycle, without a specific time | +| `once(expr)` | `expr` | Runs only at times matching `expr` within the cycle, and only once | + +`once(expr)` lets you precisely specify candidate time points while still enforcing "run only once per cycle." All standard cron syntax (numbers, ranges, steps, lists) is supported inside the parentheses. + +Example comparison: + +```text +* once * * * // any minute of every hour; runs on the first match, no further runs that hour +* once(9-17) * * * // between 9:00 and 17:59 every day, runs once per hour +0,30 once * * * // whichever of minute 0 or 30 is matched first each hour runs; no further runs that hour +``` + +### The Position of `once` = the Time Cycle It Limits + +Wherever `once` / `once(...)` is placed, it means "run only once within that time granularity." + +| `once` position | Behavior | +| ---------------- | ------------------------------- | +| minute field | Runs only once per minute | +| hour field | Runs only once per hour | +| day field | Runs only once per day | +| month field | Runs only once per month | +| weekday field | Runs only once per week | + +Examples: + +```text +* once * * * // runs only once per hour +* * once * * // runs only once per day +* 9-18 once * * // runs only once between 9:00 and 18:59 each day +``` + +### `once` Combined with Ranges / Lists / Steps + +`once` / `once(...)` can be combined with any cron syntax, but there is only one rule: + +> **Within the same cycle, once a run has succeeded, all further matching time points are ignored** + +#### Example 1: Range + +```text +* 10 once * * +``` + +Meaning: + +* Every day, 10:00–10:59 are candidate times +* After the first match of the day +* 10:05–10:59 will no longer run + +#### Example 2: List + +```text +* 1,3,5 once * * +``` + +Meaning: + +* Every day, 1:00, 3:00, and 5:00 are candidate times +* If 1:00 has already run +* 3:00 and 5:00 will be skipped + +#### Example 3: Step + +```text +* */4 once * * +``` + +Meaning: + +* Every day, 0:00, 4:00, 8:00, 12:00, 16:00, and 20:00 are candidate times +* After the first run of the day +* No further time points will run + +#### Example 4: `once(...)` Specifying Candidate Time Points + +```text +* once(9-17) * * * +``` + +Meaning: + +* Every day, 9:00 through 17:00 are candidate hours +* The cycle resets every hour; within an hour, the first match stops further runs +* Effect: runs once per hour between 9:00 and 17:00 each day, 9 times in total + +```text +* 9-18 once * * +``` + +Meaning: + +* Every day, 9:00–18:59 are candidate times +* `once` in the day field locks the cycle to once per day +* After the first match of the day, nothing else runs before 18:59 + +## `@crontab` Examples + +### Common + +```js +//@crontab * * * * * // runs once per minute +//@crontab * * * * * * // runs once per second (not recommended) +//@crontab 0 */6 * * * // runs on the hour every 6 hours +//@crontab 15 */6 * * * // runs at minute 15 every 6 hours +//@crontab * once * * * // runs at most once per hour +//@crontab * * once * * // runs at most once per day +//@crontab * 10 once * * // runs only once within the 10:00 hour each day (e.g. if it ran at 10:04, it won't run again from 10:05-10:59) +//@crontab * */4 once * * // checks at most once every 4 hours each day (e.g. if it ran at 4:00, it won't run again at 8, 12, 16, 20, 24, etc.) +``` + +### Advanced + +```js +//@crontab * 1,3,5 once * * // runs once at 1:00, 3:00, or 5:00 each day (e.g. if it ran at 1:00, it won't run again at 3:00 or 5:00) +//@crontab * 10-23 once * * // runs once between 10:00 and 23:59 each day (e.g. if it ran at 10:04, it won't run again from 10:05-23:59) +//@crontab * once 13 * * // runs once per hour on the 13th of every month +//@crontab * once(9-17) * * * // runs once per hour between 9:00 and 17:00 each day +//@crontab 0,30 once * * * // whichever of minute 0 or 30 is matched first each hour runs; no repeat that hour +//@crontab * 9-18 once * * // runs only once between 9:00 and 18:00 each day +``` + +## Usage Recommendations + +### Good Fits for `once` + +* Tasks that **only need to run once** per day/hour +* Status checks, sync, and reporting scripts +* Avoiding the following problems: + + * The browser hasn't been opened for a long time + * Background-page scheduling delays + * Duplicate execution caused by a browser restart + +### Not Recommended for `once` + +* Tasks that must run at a precise moment +* Scripts whose execution time may significantly exceed the cron interval +* Tasks with strict consistency requirements on the number of executions + +## Testing Cron Expressions + +When testing a cron expression, please **temporarily replace `once` / `once(...)` with their underlying value**: + +* `once` → `*` +* `once(expr)` → `expr` + +Note that testing tools may not support the extended 6-field format. + +Recommended tools: + +* [crontab.guru](https://crontab.guru/) +* [tool.lu cron calculator](https://tool.lu/crontab/) + +On the script list page, hover over the **run status column** to see the script's **next scheduled execution time**. + +## Logs + +On the script list page, hovering over the `run status column` shows a tooltip with the script's run status; +clicking it pops up the log content printed via `GM_log`. + +![](@site/docs/dev/background.assets/image-20210621214143661.png) + +![](@site/docs/dev/background.assets/image-20210621214124685.png) + +## Script Debugging + +Background scripts can be debugged directly from the script editor page, but this has the following limitations: + +* `value` doesn't sync properly +* `registerMenu` menus don't trigger properly + +![](@site/docs/dev/background.assets/image-20210903141601057.png) + +To debug the real runtime environment, enable **Developer Mode** in the extension settings, then open the extension's `background.html` page to debug. + +Errors raised at runtime can also be viewed in the run log. + +![image-20210903144155450](@site/docs/dev/background.assets/image-20210903144155450.png) + +## Promise + +The following pattern is highly recommended, as it also allows the script manager to monitor script execution. +If the script performs any asynchronous operation, it **must return a `Promise`**. + +```ts +// ==UserScript== +// @name Background Script +// @namespace wyz +// @version 1.0.0 +// @author wyz +// @background +// ==/UserScript== +return new Promise((resolve, reject) => { + if (Math.round((Math.random() * 10) % 2)) { + resolve("ok"); // succeeded + } else { + reject("error"); // failed, with the error reason + } +}); +``` + +```js +// ==UserScript== +// @name Scheduled script that runs once a day +// @namespace wyz +// @version 1.0.0 +// @author wyz +// @crontab * * once * * +// ==/UserScript== +return new Promise((resolve, reject) => { + if (Math.round((Math.random() * 10) % 2)) { + resolve("ok"); // succeeded + } else { + reject("error"); // failed, with the error reason + } +}); +``` + +```js +// ==UserScript== +// @name Call an API +// @namespace wyz +// @version 1.0.0 +// @author wyz +// @crontab * * once * * +// ==/UserScript== +return new Promise((resolve, reject) => { + GM_xmlhttpRequest({ + url: "https://bbs.tampermonkey.net.cn/", + onload() { + resolve("ok"); // succeeded + }, + onerror() { + reject("error"); // failed, with the error reason + }, + }); +}); +``` + +Please make sure to call `resolve` / `reject` only after the script's logic has truly finished. +Once called, the manager considers the script's execution complete, and any subsequent GM operations will no longer take effect. + +## Error Retry + +ScriptCat background scripts support error retry. +When a script fails, it can `reject` with a `CATRetryError` to trigger a retry. + +* Minimum retry interval: 5 seconds +* Avoid conflicting with the script's own execution time, otherwise duplicate execution may occur + +```js +// ==UserScript== +// @name Retry example +// @namespace https://bbs.tampermonkey.net.cn/ +// @version 0.1.0 +// @description try to take over the world! +// @author You +// @crontab * * once * * +// @grant GM_notification +// ==/UserScript== + +return new Promise((resolve, reject) => { + GM_notification({ + title: "retry", + text: "Retrying in 10 seconds", + }); + reject(new CATRetryError("xxx error", 10)); +}); +``` diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/cat-api.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/cat-api.md new file mode 100644 index 00000000..6b6e7610 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/cat-api.md @@ -0,0 +1,135 @@ +--- +title: CatApi Documentation +--- + +## Overview + +APIs specific to this extension are all defined starting with `CAT_`. + +You can also find related examples in the [example directory](https://github.com/scriptscat/scriptcat/tree/main/example). + +## Definitions + +### CAT_setProxy + +> Deprecated as of the 0.9.1 stable release; may return in a beta version in the future. + +Sets a proxy. Note that this feature will conflict with extensions like Proxy SwitchyOmega. Multiple scripts can use a proxy without conflicting (for example, one script providing Google access and another providing Twitter access). + +Please first read up on [PAC](https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_PAC_file) and [Chromium's full URL restrictions in PAC](https://github.com/FelisCatus/SwitchyOmega/wiki/Chromium-Full-URL-Restriction). + +```typescript +declare function CAT_setProxy(rule: CAT_Types.ProxyRule[] | string): void; + +declare namespace CAT_Types { + interface ProxyRule { + proxyServer: ProxyServer; + matchUrl: string[]; + } + type ProxyScheme = "http" | "https" | "quic" | "socks4" | "socks5"; + interface ProxyServer { + scheme?: ProxyScheme; + host: string; + port?: number; + } +} +``` + +### CAT_clearProxy + +> Deprecated as of the 0.9.1 stable release; may return in a beta version in the future. + +Clears the proxy. + +```typescript +declare function CAT_clearProxy(): void; +``` + +### CAT_click + +> Deprecated as of the 0.9.1 stable release; may return in a beta version in the future. + +A real click. This API is experimental and may change or be removed. + +Implemented using [Input.dispatchMouseEvent](https://chromedevtools.github.io/devtools-protocol/tot/Input/#method-dispatchMouseEvent). Make sure the element is within the visible area, and that the coordinates are relative to the window's position. + +```ts +declare function CAT_click(x: number, y: number): void; +``` + +### CAT_userConfig + +You can call this API to open the script's [UserConfig](./config.md) page. + +```ts +declare function CAT_userConfig(): void; +``` + +### CAT_fileStorage + +Controls the storage system configured by the manager. An `app/uuid` directory will be created for this API to use; if the `baseDir` parameter is specified, it will be used as the base directory instead. + +```ts +/** + * Controls the storage system configured by the manager. An app/uuid directory will be created for this API to use; if the baseDir parameter is specified, it will be used as the base directory instead. + * Uploads overwrite files with the same name by default. + * @param action Operation type: list lists all files in the given directory, upload uploads a file, download downloads a file, delete deletes a file, config opens the config page. move/mkdir and similar operations are not yet provided. + * @param details + */ +declare function CAT_fileStorage( + action: "list", + details: { + // File path + path?: string; + // Base directory; if not set, the script's uuid is used as the directory + baseDir?: string; + onload?: (files: CATType.FileStorageFileInfo[]) => void; + onerror?: (error: CATType.FileStorageError) => void; + } +): void; +declare function CAT_fileStorage( + action: "download", + details: { + file: CATType.FileStorageFileInfo; // Some platforms require the file's hash, so the file info must be passed in + onload: (data: Blob) => void; + // onprogress?: (progress: number) => void; + onerror?: (error: CATType.FileStorageError) => void; + // public?: boolean; + } +): void; +declare function CAT_fileStorage( + action: "delete", + details: { + path: string; + onload?: () => void; + onerror?: (error: CATType.FileStorageError) => void; + // public?: boolean; + } +): void; +declare function CAT_fileStorage( + action: "upload", + details: { + path: string; + // Base directory; if not set, the script's uuid is used as the directory + baseDir?: string; + data: Blob; + onload?: () => void; + // onprogress?: (progress: number) => void; + onerror?: (error: CATType.FileStorageError) => void; + // public?: boolean; + } +): void; +declare function CAT_fileStorage(action: "config"): void; +``` + +### CAT_scriptLoaded + +When using `early-start`, you can use this function to determine whether the script has fully loaded. + +```js +function CAT_ScriptLoaded(): Promise<void>; + +CAT_scriptLoaded().then(() => { + console.log("Script has fully loaded"); +}); +``` diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/cloudcat.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/cloudcat.md new file mode 100644 index 00000000..932327b5 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/cloudcat.md @@ -0,0 +1,91 @@ +--- +title: Cloud Execution +--- + +> Several ways to run in the cloud are provided; see [Running Environments](#running-environments) for details. In addition, [CloudCat](https://github.com/scriptscat/cloudcat) is a service for running background scripts in the cloud — a FAAS platform that is still under development. + +⚠ Please note ⚠, once uploaded to the cloud, the meaning of `once` in a scheduled-script expression changes: the time before `once` is replaced with its minimum value when running. + +For example: + +* `* * once * *` => `0 0 * * *`: runs once per day, becomes running at 00:00 every day +* `* 1-23 once * *` => `0 1 * * *`: runs once between 1:00 and 23:00 every day, becomes running at 01:00 every day +* `* 1,3,5 once * *` => `0 1 * * *`: runs once at 1:00, 3:00, or 5:00 every day, becomes running at 01:00 every day +* `* */4 once * *` => `0 0 * * *`: runs once every 4 hours every day, becomes running at 00:00 every day +* `* 1-23/4 once * *` => `0 1 * * *`: runs once every 4 hours between 1:00 and 23:00 every day, becomes running at 01:00 every day +* `* 10 once * *` => `0 10 * * *`: runs once at 10:00 every day, becomes running at minute 00 of hour 10 every day +* `* * * once *` => `0 0 1 * *`: runs once per month, becomes running at 00:00 on the 1st of every month + +## Additional CloudCat Description Values + +A reference script: [Bilibili Auto Check-in](https://scriptcat.org/script-show-page/48) + +### cloudCat + +Declaring this attribute allows the script to run via `CloudCat`. Once a script has this option, a cloud-execution button appears in the script list; clicking it lets you choose an execution method — see [Running Environments](#running-environments). + +![image-20220203225847694](@site/docs/dev/cloudcat.assets/image-20220203225847694.png) + +### cloudServer + +> Related to cloudCat, not yet implemented + +The default cloudCat server address + + +### exportValue + +Describes the Values to export to the cloud; multiple declarations are allowed. + +```ts +// @exportValue key1,key2,key3 +// @exportValue key4,key5,key6 +``` + +### exportCookie + +Describes the cookies to export to the cloud; multiple declarations are allowed. Parameters are described using `GM_cookie`'s `CookieDetails`, for example: + +```ts +// The following exports the cookie named cookie1 from https://docs.scriptcat.org/docs/use/ +// @exportCookie url=https://docs.scriptcat.org/docs/use;name=cookie1 + +// This exports all cookies for the scriptcat.org domain +// @exportCookie domain=scriptcat.org + +// All available parameters: +// @exportCookie domain=scriptcat.org;url=https://docs.scriptcat.org/docs/use;name=cookie1;path=/docs/use;secure=true;session=true +``` + +## API Support Changes +> Currently only the following APIs are supported; unless otherwise noted, they behave the same as the original API. + +### GM_xmlhttpRequest + + +### GM_notification + + +### GM_log + +### GM_getValue + +Currently only supports getting Values exported via `@exportValue`; set/delete/list and other methods are not supported. + +## Running Environments + +### Local + +Exports a zip package; after extracting it into a folder, run the following commands to execute it locally (requires a local Node.js environment): + +```bash +npm i +node index.js +``` + + +### Tencent Cloud + +First create a Tencent Cloud key at [**Access Keys**](https://console.cloud.tencent.com/cam/capi) — if using a sub-account, make sure to grant it Cloud Function permissions. Then enable the service at [**Function Service**](https://console.cloud.tencent.com/scf/list), which comes with a certain amount of free usage each month. The region defaults to Shanghai; adjust it if needed. After clicking upload, a scheduled trigger is automatically created based on `@crontab` to run the function on schedule. + +![image-20220203224956248](@site/docs/dev/cloudcat.assets/image-20220203224956248.png) diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/config.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/config.md new file mode 100644 index 00000000..79affd96 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/config.md @@ -0,0 +1,69 @@ +--- +title: UserConfig +--- + +The content inside `==UserConfig==` goes after `==UserScript==`, and describes some user-configurable options for the script. The configuration is written in [YAML](https://yaml.org/) format: + +```js +/* ==UserConfig== +group1: + configA: # key is group.config, e.g. this key is group1.configA + title: Config A # the config's title + description: This is a text-type config # the config's description + type: text # option type; auto-detected from the data if omitted + default: default value # the config's default value + min: 2 # minimum 2 characters + max: 18 # maximum 18 characters + password: true # mark as a password field + configB: + title: Config B + description: This is a checkbox config + type: checkbox + default: true + configC: + title: Config C + description: This is a select-list config + type: select + default: 1 + values: [1,2,3,4,5] + configD: + title: Config D + description: This is a dynamic select-list config + type: select + bind: $cookies # dynamically bound values; the key starts with $, and the value must be an array + configE: + title: Config E + description: This is a multi-select-list config + type: mult-select + default: [1] + values: [1,2,3,4,5] + configF: + title: Config F + description: This is a dynamic multi-select-list config + type: mult-select + bind: $cookies + configG: + title: Config G + description: This is a numeric config + type: number + default: 1 + min: 10 # minimum value + max: 16 # maximum value + unit: min # unit label + configH: + title: Config H + description: This is a long-text config + type: textarea + default: default value +--- +group2: # second config group + configX: + title: Config X + description: This is a text-type config + default: default value + ==/UserConfig== */ +``` + +Once defined here, a config button appears in the dashboard for the user to configure. Developers use `GM_getValue` to read the config's value, with the key expressed as `group.config`. + +![](@site/docs/dev/config.assets/image-20210621213013631.png) diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/index.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/index.md new file mode 100644 index 00000000..84daac15 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/index.md @@ -0,0 +1,15 @@ +--- +title: Introduction +--- + +This extension supports three types of scripts: + +- Foreground scripts +- [Background scripts](./background.md) +- [Scheduled scripts](./background.md#scheduled-script-crontab) + +Foreground scripts are what people usually mean by Tampermonkey scripts. Background scripts and scheduled scripts are script types specific to the ScriptCat extension — see the corresponding documentation for details. + +You can use this documentation to learn about [Tampermonkey's API](./api.md) and [ScriptCat's background scripts](./background.md). We also maintain a [Tampermonkey Script Development Guide](https://learn.scriptcat.org/) site with a wealth of learning resources — you're welcome to join the discussion there. + +If you find gaps in the documentation, please let us know on [GitHub](https://github.com/scriptscat/scriptcat.org), or send us a PR to help improve it. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/meta.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/meta.md new file mode 100644 index 00000000..006cfe0d --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/meta.md @@ -0,0 +1,212 @@ +--- +title: Metadata Block +--- + +The content inside `==UserScript==` describes the permissions a script needs, information about the script, and so on. It sits at the very start of the script. + +```js +// ==UserScript== +// @name New Userscript +// @namespace https://bbs.tampermonkey.net.cn/ +// @version 0.1.0 +// @description try to take over the world! +// @author You +// @crontab * * once * * +// ==/UserScript== +``` + +## Main Values + +### name + +Script name + +### namespace + +Script namespace. `name + namespace` determines the script's uniqueness. + +### version + +The script's version. It's recommended to follow [semantic versioning](https://semver.org/), so that when a version change is detected, the user is prompted to update, and so on. + +### description + +A detailed description of the script + +### author + +Script author + +### run-at + +When the script runs + +| Value | Runs | Supported since | +| -------------- | ------------------------------------------------------------------ | ---------------------- | +| document-start | Injects the script into the page as soon as the URL matches on the frontend | v0.3.0 | +| document-end | Injects the script after the DOM has finished loading; page scripts and images may still be loading at this point | v0.3.0 | +| document-idle | Injects the script after all content has finished loading | v0.3.0 | +| document-body | The script is only injected once the page has a `body` element | v0.6.2 | +| document-menu | Shows a menu on right-click; running the script uses the script name as the menu name | v0.3.4-v0.9.4 (🔥 removed) | + +For menu icons, you can refer to [Unicode Symbols](https://unicode-table.com/en/) and [emoji](https://www.emojiall.com/en-US/). + +### run-in + +Specifies the environment the script is injected into: `@run-in normal-tabs` for regular tabs, `@run-in incognito-tabs` for incognito tabs. + +### early-start (v1.1.0+) + +When `run-at` is `document-start`, the script runs as early as possible, but it still can't guarantee loading faster than the page. + +Once you've defined `@run-at document-start`, you can add `@early-start` to make the script load faster than the page: [example](https://github.com/scriptscat/scriptcat/blob/main/example/early-start.js) + +### inject-into + +:::tip + +In the content-script environment (`content`), `unsafeWindow` only points to the environment's own current `window`, and cannot access the page's `window`. + +ScriptCat does not support automatically checking CSP restrictions to decide whether to inject as `content` or `page` (i.e. Tampermonkey's `@inject-into auto`). + +::: + +Specifies where the script is injected, supporting `page` and `content`, defaulting to `page`. + +- `page`: the script is injected into the page environment, and can use `unsafeWindow` to access the page's `window` and `DOM` +- `content`: the script is injected into the content-script environment, cannot directly access the page's `window` object, but can access the page `DOM`, and is not subject to `CSP` + +### storageName 🧪 + +The storage space for `Value`; data under the same `storageName` can be shared and communicated across scripts. This is ScriptCat-specific. + +### background + +Marks this script as a background script, which needs to run in the background environment. See [Background Script](./background.md#background-script-background) for details. + +### crontab + +Marks the script as a scheduled script, which requires a cron expression value. Only one cron expression can exist, and it runs on that schedule in the background environment. See [Scheduled Script](./background.md#scheduled-script-crontab) for details. + +### match + +Only URLs matched by `match` will run the script, following [Match patterns](https://developer.chrome.com/docs/extensions/mv3/match_patterns/). In `match`, `*` is a wildcard, `tld` matches the top-level domain, and a domain starting with `*.` will also match `xxx.com`: + +| Value | Correct examples | Incorrect examples | +| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | +| `http://scriptcat.org/doc/match` | `http://scriptcat.org/doc/match` | `http://scriptcat.org/doc/runAt` | +| `*://*/param?*` | `https://scriptcat.org/param` \| `http://scriptcat.org/param?search=tampermonkey` | `https://scriptcat.org/test/param` | +| `*://*/prefix*suffix` | `http://scriptcat.org/prefix/suffix` \| `http://scriptcat.org/prefix/mid/suffix` \| `http://scriptcat.org/prefixsuffix` | `http://scriptcat.org/prefix/suffix/end` | +| `http*://scriptcat.org/*` | `https://scriptcat.org/` \| `https://scriptcat.org/doc` \| `http://scriptcat.org/doc/match` \| `http://scriptcat.org/param?search=tampermonkey` | `https://doc.scriptcat.org/` | +| `http*://scriptcat.org/doc/*` | `https://scriptcat.org/doc` \| `http://scriptcat.org/doc/match` | `http://scriptcat.org/param?search=tampermonkey` | +| `http*://scriptcat.tld/doc/*` | `https://scriptcat.cn/doc` \| `http://scriptcat.net.cn/doc/match` | `http://google.com/param?search=tampermonkey` | +| `http*://*.scriptcat.org/doc/*` | `https://scriptcat.cn/doc` \| `http://www.scriptcat.net.cn/doc/match` | `http://google.com/param?search=tampermonkey` | + +### include + +Supports `\*` for fuzzy matching, allowing non-standard URLs + +### exclude + +URLs that should not match; uses the same expression syntax as `include` + +### grant + +Requests API permission — an API can only be called once it has been requested. See the permission list at: [API Documentation](./api.md) and [CAT API Documentation](./cat-api.md). + +Two special values: + +- **none**: the script does not run in the sandbox environment, but directly in the page environment. In this environment, no GM APIs are available, but the page's `window` object can be accessed directly. +- **unsafeWindow**: in the sandbox environment, if you need to access the page's `window` object, use `unsafeWindow` to do so. (Tampermonkey doesn't require declaring this — it's kept only for compatibility, which admittedly isn't very clean.) + +### connect + +Requests access permission for a site; see `GM_cookie` and `GM_xmlhttpRequest` + +### resource + +Includes a resource file. After declaring `@resource`, you can use `GM_getResourceText`/`GM_getResourceURL` to retrieve the information. + +```js +// @resource icon https://bbs.tampermonkey.net.cn/favicon.ico +// @resource html https://bbs.tampermonkey.net.cn/ +// @resource xml https://bbs.tampermonkey.net.cn/sitemap.xml +// Adding resource integrity verification +// @resource icon https://bbs.tampermonkey.net.cn/favicon.ico#md5-xxx,sha256-xxx +``` + +### require + +Includes an external JS file; supports [resource integrity verification](#resource-integrity-verification) + +### require-css + +Includes an external CSS file; supports [resource integrity verification](#resource-integrity-verification) + +### noframes + +Marks the script as not running inside a `<frame>` + +### definition + +The reference address of a `.d.ts` file, enabling editor auto-completion hints + +### antifeature + +This is related to the script marketplace; unwelcome features need to be flagged with this description value, for example: + +```js +// @antifeature ads This script has ads +// @antifeature referral-link This script modifies or redirects to the author's referral link +``` + +## Additional Description Values + +### license + +The current script's open-source license + +### updateURL + +Update checking requires the remote script to have a `@version` tag for this to take effect. + +The link the script uses to check for updates; if not set, it defaults to the link's `user.js => meta.js`, or the current link if there's no `user.js`. + +If `@updateURL` is configured, `@downloadURL` must also be configured for `@updateURL` to take effect. + +### downloadURL + +The download address for the script update + +### supportURL + +Support site, bug report page + +### homepage, homepageURL, website + +Script homepage + +### source + +Script source code page + +### icon, iconURL, defaulticon + +Script icon + +### icon64, icon64URL + +64x64-sized script icon + +### Notes + +### Resource Integrity Verification + +- Use md5, sha1, sha256, sha384, or sha512 to verify resources against tampering. Multiple verification methods can be separated with `;` or `,`. +- Per [W3C recommendations](https://w3c.github.io/webappsec-subresource-integrity/#hash-collision-attacks), md5 and sha1 are not recommended; use sha384 or a stronger hash algorithm instead. + +For example: + +```js +// @require https://cdn.jsdelivr.net/npm/darkmode-js@1.5.7/lib/darkmode-js.min.js#md5-d55836f30c097da753179f82fa6f108f,sha256-a476ab8560837a51938aa6e1720c8be87c2862b6221690e9de7ffac113811a90 +``` diff --git a/i18n/en/docusaurus-plugin-content-docs/current/dev/subscribe.md b/i18n/en/docusaurus-plugin-content-docs/current/dev/subscribe.md new file mode 100644 index 00000000..25300210 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/dev/subscribe.md @@ -0,0 +1,56 @@ +--- +title: Subscription Mode +--- + +The file must start with `UserSubscribe` instead of `UserScript`. The installation link should use the `user.sub.js` extension, and must be an `https` link. + +A subscription script only shows the installation dialog for the user to confirm the subscription at install time; subsequent updates are silent, and the update dialog is only shown again if the `connect` permission changes. + +A single subscription script can describe the installation links for multiple scripts. Scripts installed via subscription mode are installed silently, without a confirmation dialog, and the installed scripts still appear in the script list — but their `connect` permission uses the `connect` declared in the subscription rather than the script's own `connect` permission. + +```js +// ==UserSubscribe== +// @name xxx +// @description Subscribe to the xxx script series +// @version 0.1.0 +// @author You +// @connect www.baidu.com +// @scriptUrl https://script.tampermonkey.net.cn/48.user.js +// @scriptUrl https://script.tampermonkey.net.cn/49.user.js +// ==/UserSubscribe== +``` + +## Subscription Updates and Script Updates + +According to the user's configured `update interval`, ScriptCat periodically checks the subscription link for updates; `version` must be configured for this to take effect. + +Each subscription update or change compares the script links against the currently installed scripts: scripts no longer in the new subscription are removed, and newly added scripts are installed silently. Script updates follow the script's own `version`, using the same update logic as a normally installed script. + +## Silent Install and Update + +Subscribed scripts are installed and updated silently — adding, removing, or updating a script from a subscription only shows a notification, without requiring user confirmation again. Because of this silent-update mechanism, please only subscribe to sources you trust. + + +## metadata + +The meaning of certain metadata fields changes within a subscription script. + +### name + +The subscription name (can also be edited directly in the subscription list) + +### description + +The subscription description, describing what the subscription is for + +### version + +The subscription version. If omitted, updates are instead triggered by whether the subscription script's content has changed. + +### connect + +Requests access permission for a site; see `GM_cookie` and `GM_xmlhttpRequest`. For scripts installed via subscription mode, `connect` is overridden by the subscription's `connect`. + +### scriptUrl + +The script installation links required by the subscription diff --git a/i18n/en/docusaurus-plugin-content-docs/current/script_installation.md b/i18n/en/docusaurus-plugin-content-docs/current/script_installation.md index 00da6173..3c212093 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/script_installation.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/script_installation.md @@ -1,4 +1,6 @@ -# Script Installation +--- +title: Script Installation +--- This page is used as an intermediate step to install a new user script in `ScriptCat`. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/3.QA.md b/i18n/en/docusaurus-plugin-content-docs/current/use/QA.md similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/3.QA.md rename to i18n/en/docusaurus-plugin-content-docs/current/use/QA.md diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/img/migrate-from-tampermonkey/image-20250716225507707.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-tampermonkey.assets/image-20250716225507707.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/img/migrate-from-tampermonkey/image-20250716225507707.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-tampermonkey.assets/image-20250716225507707.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/img/migrate-from-tampermonkey/image-20250716225611932.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-tampermonkey.assets/image-20250716225611932.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/img/migrate-from-tampermonkey/image-20250716225611932.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-tampermonkey.assets/image-20250716225611932.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/img/migrate-from-tampermonkey/image-20250716225719787.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-tampermonkey.assets/image-20250716225719787.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/img/migrate-from-tampermonkey/image-20250716225719787.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-tampermonkey.assets/image-20250716225719787.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/img/migrate-from-tampermonkey/image-20250716225741428.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-tampermonkey.assets/image-20250716225741428.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/img/migrate-from-tampermonkey/image-20250716225741428.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-tampermonkey.assets/image-20250716225741428.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/migrate-from-tampermonkey.md b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-tampermonkey.md similarity index 61% rename from i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/migrate-from-tampermonkey.md rename to i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-tampermonkey.md index 06ba4848..54aaabcf 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/migrate-from-tampermonkey.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-tampermonkey.md @@ -1,4 +1,6 @@ -# Migrate from Tampermonkey to Scriptcat +--- +title: Migrate from Tampermonkey to Scriptcat +--- If you are currently using Tampermonkey and want to migrate to Scriptcat, here are some steps and tips to help you complete the migration smoothly. @@ -6,20 +8,20 @@ If you are currently using Tampermonkey and want to migrate to Scriptcat, here a First, click the Tampermonkey icon to enter the dashboard -![image-20250716225507707](./img/migrate-from-tampermonkey/image-20250716225507707.webp) +![image-20250716225507707](./migrate-from-tampermonkey.assets/image-20250716225507707.webp) Click `Utilities`, then click `Export` under the zip file section to export the zip file -![image-20250716225611932](./img/migrate-from-tampermonkey/image-20250716225611932.webp) +![image-20250716225611932](./migrate-from-tampermonkey.assets/image-20250716225611932.webp) ## Import to Scriptcat In the Scriptcat extension, click the dashboard icon to enter the management panel -![image-20250716225719787](./img/migrate-from-tampermonkey/image-20250716225719787.webp) +![image-20250716225719787](./migrate-from-tampermonkey.assets/image-20250716225719787.webp) Select `Tools`, then click `Import File`, choose the previously exported Tampermonkey zip file, and click `Open` to import. -![image-20250716225741428](./img/migrate-from-tampermonkey/image-20250716225741428.webp) +![image-20250716225741428](./migrate-from-tampermonkey.assets/image-20250716225741428.webp) Then in the newly opened page, select or select all the scripts you want to import, and click the `Import` button. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/img/migrate-from-violentmonkey.assets/image-20250716225900597.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-violentmonkey.assets/image-20250716225900597.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/img/migrate-from-violentmonkey.assets/image-20250716225900597.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-violentmonkey.assets/image-20250716225900597.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/img/migrate-from-violentmonkey.assets/image-20250716225935258.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-violentmonkey.assets/image-20250716225935258.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/img/migrate-from-violentmonkey.assets/image-20250716225935258.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-violentmonkey.assets/image-20250716225935258.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/migrate-from-violentmonkey.md b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-violentmonkey.md similarity index 61% rename from i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/migrate-from-violentmonkey.md rename to i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-violentmonkey.md index 800e4ece..41403462 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/4.from-other/migrate-from-violentmonkey.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-violentmonkey.md @@ -1,4 +1,6 @@ -# Migrating from Violentmonkey to Scriptcat +--- +title: Migrating from Violentmonkey to Scriptcat +--- If you are currently using Violentmonkey and want to migrate to Scriptcat, here are the steps and tips to help you complete the migration smoothly. @@ -6,20 +8,20 @@ If you are currently using Violentmonkey and want to migrate to Scriptcat, here First, click the Violentmonkey icon to enter the management panel -![image-20250716225900597](./img/migrate-from-violentmonkey.assets/image-20250716225900597.webp) +![image-20250716225900597](./migrate-from-violentmonkey.assets/image-20250716225900597.webp) Click `Settings`, then click `Export as zip file` to export the backup file -![image-20250716225935258](./img/migrate-from-violentmonkey.assets/image-20250716225935258.webp) +![image-20250716225935258](./migrate-from-violentmonkey.assets/image-20250716225935258.webp) ## Import to Scriptcat In the Scriptcat extension, click the dashboard icon to enter the management panel -![image-20250716225719787](./img/migrate-from-tampermonkey/image-20250716225719787.webp) +![image-20250716225719787](./migrate-from-tampermonkey.assets/image-20250716225719787.webp) Select `Tools`, then click `Import File`, choose the previously exported Violentmonkey zip file, and click `Open` to import. -![image-20250716225741428](./img/migrate-from-tampermonkey/image-20250716225741428.webp) +![image-20250716225741428](./migrate-from-tampermonkey.assets/image-20250716225741428.webp) Then in the newly opened page, select or select all the scripts you want to import, and click the `Import` button. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/allow-user-scripts-toggle.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/allow-user-scripts-toggle.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/allow-user-scripts-toggle.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/allow-user-scripts-toggle.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/chrome-developer-mode-toggle.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/chrome-developer-mode-toggle.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/chrome-developer-mode-toggle.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/chrome-developer-mode-toggle.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/chrome-extensions-page.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/chrome-extensions-page.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/chrome-extensions-page.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/chrome-extensions-page.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/edge mobile 138.png b/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/edge mobile 138.png similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/edge mobile 138.png rename to i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/edge mobile 138.png diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/edge mobile.png b/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/edge mobile.png similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/edge mobile.png rename to i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/edge mobile.png diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/edge-allow-user-scripts.png b/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/edge-allow-user-scripts.png similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/edge-allow-user-scripts.png rename to i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/edge-allow-user-scripts.png diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/edge-developer-mode-toggle.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/edge-developer-mode-toggle.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/edge-developer-mode-toggle.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/edge-developer-mode-toggle.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/edge-extensions-details.png b/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/edge-extensions-details.png similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/edge-extensions-details.png rename to i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/edge-extensions-details.png diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/edge-extensions-page.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/edge-extensions-page.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/edge-extensions-page.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/edge-extensions-page.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/scriptcat-extension-details.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/scriptcat-extension-details.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/img/5.open-dev.assets/scriptcat-extension-details.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.assets/scriptcat-extension-details.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/5.open-dev.md b/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.md similarity index 87% rename from i18n/en/docusaurus-plugin-content-docs/current/use/5.open-dev.md rename to i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.md index 032cfbbf..ad93b056 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/5.open-dev.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.md @@ -9,7 +9,6 @@ import BrowserGuide from '@site/src/components/BrowserGuide'; import GithubStar from '@site/src/components/GithubStar'; import SponsorBlock from '@site/src/components/SponsorBlock/en.mdx'; -# Enable Browser User Scripts Support <GithubStar variant="bar" scene="install" /> @@ -47,32 +46,32 @@ import SponsorBlock from '@site/src/components/SponsorBlock/en.mdx'; ① Open the browser's extension management interface, or visit [edge://extensions/](edge://extensions/) -![edge-open-settings](./img/5.open-dev.assets/edge-extensions-page.webp) +![edge-open-settings](./open-dev.assets/edge-extensions-page.webp) ② In the extension management interface, find the ScriptCat extension and click `Details` -![edge-extensions-details](img/5.open-dev.assets/edge-extensions-details.png) +![edge-extensions-details](open-dev.assets/edge-extensions-details.png) ③ In the ScriptCat extension details page, find the `Allow user scripts` option and enable it. Then disable and re-enable the extension, or restart the browser to make the script functionality effective. > ⚠️⚠️⚠️ For lower version Edge browsers (\<=143 version) or users without this option, please refer to [Enable Developer Mode](#enable-developer-mode) -![edge-allow-user-scripts](img/5.open-dev.assets/edge-allow-user-scripts.png) +![edge-allow-user-scripts](open-dev.assets/edge-allow-user-scripts.png) </TabItem> <TabItem value="chrome" label={<div className="flex items-center gap-1"><Icon height={16} width={16} icon="logos:chrome" />Chrome</div>}> ① Open the browser's extension management interface, or visit [chrome://extensions/](chrome://extensions/) -![chrome-open-settings](./img/5.open-dev.assets/chrome-extensions-page.webp) +![chrome-open-settings](./open-dev.assets/chrome-extensions-page.webp) ② In the extension management interface, find the ScriptCat extension and click `Details` -![scriptcat-extension-details](img/5.open-dev.assets/scriptcat-extension-details.webp) +![scriptcat-extension-details](open-dev.assets/scriptcat-extension-details.webp) ③ In the ScriptCat extension details page, find the `Allow user scripts` option and enable it. Then disable and re-enable the extension, or restart the browser to make the script functionality effective. -![allow-user-scripts-toggle](img/5.open-dev.assets/allow-user-scripts-toggle.webp) +![allow-user-scripts-toggle](open-dev.assets/allow-user-scripts-toggle.webp) </TabItem> <TabItem value="edge-mobile" label={<div className="flex items-center gap-1"><Icon height={16} width={16} icon="logos:microsoft-edge" />Edge Mobile</div>}> @@ -86,7 +85,7 @@ For Edge Mobile with browser engine version ≥ 138, Developer Mode is not requi > ⚠️⚠️⚠️ For browser engine versions lower than 138, or users without this option, please refer to [Enable Developer Mode](#enable-developer-mode) -![edge-mobile-allow-user-scripts](./img/5.open-dev.assets/edge%20mobile%20138.png) +![edge-mobile-allow-user-scripts](./open-dev.assets/edge%20mobile%20138.png) </TabItem> </Tabs> @@ -98,11 +97,11 @@ For Edge Mobile with browser engine version ≥ 138, Developer Mode is not requi ① Open the browser's extension management interface, or visit [edge://extensions/](edge://extensions/) -![edge-open-settings](./img/5.open-dev.assets/edge-extensions-page.webp) +![edge-open-settings](./open-dev.assets/edge-extensions-page.webp) ② Enable `Developer mode` (In some browsers, this mode may be located in other options, such as 360 Browser: Advanced Management > Developer Mode) -![edge-open-dev](./img/5.open-dev.assets/edge-developer-mode-toggle.webp) +![edge-open-dev](./open-dev.assets/edge-developer-mode-toggle.webp) ③ After enabling developer mode, disable and then re-enable the extension, or restart the browser to make the script functionality effective. @@ -111,11 +110,11 @@ For Edge Mobile with browser engine version ≥ 138, Developer Mode is not requi ① Open the browser's extension management interface, or visit [chrome://extensions/](chrome://extensions/) -![chrome-open-settings](./img/5.open-dev.assets/chrome-extensions-page.webp) +![chrome-open-settings](./open-dev.assets/chrome-extensions-page.webp) ② Enable `Developer mode` (In some browsers, this mode may be located in other options, such as 360 Browser: Advanced Management > Developer Mode) -![chrome-open-dev](./img/5.open-dev.assets/chrome-developer-mode-toggle.webp) +![chrome-open-dev](./open-dev.assets/chrome-developer-mode-toggle.webp) ③ After enabling developer mode, disable and then re-enable the extension, or restart the browser to make the script functionality effective. @@ -125,7 +124,7 @@ For Edge Mobile with browser engine version ≥ 138, Developer Mode is not requi For Edge Mobile with browser engine versions lower than 138, or without the `Allow user scripts` option, tap the settings button at the top of the extensions page to enable Developer Mode. -![edge-mobile-open-dev](./img/5.open-dev.assets/edge%20mobile.png) +![edge-mobile-open-dev](./open-dev.assets/edge%20mobile.png) </TabItem> </Tabs> diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/99.policy/disclaimer.md b/i18n/en/docusaurus-plugin-content-docs/current/use/policy/disclaimer.md similarity index 97% rename from i18n/en/docusaurus-plugin-content-docs/current/use/99.policy/disclaimer.md rename to i18n/en/docusaurus-plugin-content-docs/current/use/policy/disclaimer.md index 6bf6da70..617118a5 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/99.policy/disclaimer.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/policy/disclaimer.md @@ -1,10 +1,8 @@ --- -id: disclaimer -title: Disclaimer +title: ScriptCat Disclaimer +sidebar_label: Disclaimer --- -# ScriptCat Disclaimer - ScriptCat related products and services (including but not limited to browser extensions, script websites, API services, etc., collectively referred to as "Services") are developed and provided by the ScriptCat team (hereinafter referred to as "we" or "developers"). Before you start using our services, please carefully read the following disclaimer. User access, download, installation, and use of any of our products or services will be deemed as unconditional acceptance of all content of this statement. 1. Our services and all their content and functionality are provided on an "as is" and "as available" basis, without any express or implied warranties. We do not guarantee the performance, functionality, or availability of the services, nor do we guarantee that the services will run error-free or that any errors will be corrected. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/99.policy/privacy.md b/i18n/en/docusaurus-plugin-content-docs/current/use/policy/privacy.md similarity index 99% rename from i18n/en/docusaurus-plugin-content-docs/current/use/99.policy/privacy.md rename to i18n/en/docusaurus-plugin-content-docs/current/use/policy/privacy.md index 21a66c81..5d1998e1 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/99.policy/privacy.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/policy/privacy.md @@ -1,5 +1,4 @@ --- -id: privacy title: Privacy Policy --- diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/99.policy/privacy_website.md b/i18n/en/docusaurus-plugin-content-docs/current/use/policy/privacy_website.md similarity index 99% rename from i18n/en/docusaurus-plugin-content-docs/current/use/99.policy/privacy_website.md rename to i18n/en/docusaurus-plugin-content-docs/current/use/policy/privacy_website.md index 17c499db..d9b18f70 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/99.policy/privacy_website.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/policy/privacy_website.md @@ -1,5 +1,4 @@ --- -id: privacy_website title: Script Website Privacy Policy --- diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/2.script_installation.md b/i18n/en/docusaurus-plugin-content-docs/current/use/script_installation.md similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/2.script_installation.md rename to i18n/en/docusaurus-plugin-content-docs/current/use/script_installation.md diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/2.sync.md b/i18n/en/docusaurus-plugin-content-docs/current/use/sync.md similarity index 92% rename from i18n/en/docusaurus-plugin-content-docs/current/use/2.sync.md rename to i18n/en/docusaurus-plugin-content-docs/current/use/sync.md index d3d59565..35d8287d 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/2.sync.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/sync.md @@ -1,9 +1,7 @@ --- -id: sync +title: Synchronization and Backup --- -# Synchronization and Backup - Supports the following cloud storage: - [x] WebDAV diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/img/README.assets/chrome-load-unpacked-img.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/use.assets/chrome-load-unpacked-img.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/img/README.assets/chrome-load-unpacked-img.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/use.assets/chrome-load-unpacked-img.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/img/README.assets/chrome-load-unpacked.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/use.assets/chrome-load-unpacked.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/img/README.assets/chrome-load-unpacked.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/use.assets/chrome-load-unpacked.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/img/README.assets/download-zip.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/use.assets/download-zip.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/img/README.assets/download-zip.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/use.assets/download-zip.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/img/README.assets/edge-load-unpacked-img.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/use.assets/edge-load-unpacked-img.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/img/README.assets/edge-load-unpacked-img.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/use.assets/edge-load-unpacked-img.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/img/README.assets/edge-load-unpacked.webp b/i18n/en/docusaurus-plugin-content-docs/current/use/use.assets/edge-load-unpacked.webp similarity index 100% rename from i18n/en/docusaurus-plugin-content-docs/current/use/img/README.assets/edge-load-unpacked.webp rename to i18n/en/docusaurus-plugin-content-docs/current/use/use.assets/edge-load-unpacked.webp diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/1.README.md b/i18n/en/docusaurus-plugin-content-docs/current/use/use.md similarity index 92% rename from i18n/en/docusaurus-plugin-content-docs/current/use/1.README.md rename to i18n/en/docusaurus-plugin-content-docs/current/use/use.md index 1b448b33..403e1f2a 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/1.README.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/use.md @@ -1,9 +1,8 @@ --- -id: use +slug: /use/use +title: Quick Start --- -# Quick Start - ScriptCat is a browser extension that can execute user scripts, compatible with Tampermonkey scripts, and provides more features. If you find any bugs or have suggestions, you can visit [GitHub Repo](https://github.com/scriptscat/scriptcat) to provide feedback. ## Install Extension @@ -24,17 +23,17 @@ If your browser is not in the above list, you can download the `zip`/`crx` file ① First download the `zip` file from [Github Release](https://github.com/scriptscat/scriptcat/releases) or [Community Download](https://bbs.tampermonkey.net.cn/thread-3068-1-1.html) page. If it's a `crx` file, change its extension to `zip`. -② Prepare a folder for storing the plugin, and extract the above zip file to that folder. After extraction, it should look like this (**Note: This folder cannot be deleted or moved, otherwise the extension will not work properly**) ![download-zip](./img/README.assets/download-zip.webp) +② Prepare a folder for storing the plugin, and extract the above zip file to that folder. After extraction, it should look like this (**Note: This folder cannot be deleted or moved, otherwise the extension will not work properly**) ![download-zip](./use.assets/download-zip.webp) ③ Open the browser's extension management interface to load the unpacked extension (refer to [Enable developer mode to support manifest v3 ScriptCat](/docs/use/open-dev/) to enable developer mode first) -- 1. **Edge** ![edge-load-unpacked](./img/README.assets/edge-load-unpacked.webp) -- 2. **Chrome** ![chrome-load-unpacked](./img/README.assets/chrome-load-unpacked.webp) +- 1. **Edge** ![edge-load-unpacked](./use.assets/edge-load-unpacked.webp) +- 2. **Chrome** ![chrome-load-unpacked](./use.assets/chrome-load-unpacked.webp) ④ Select the folder created in step ② (after loading is complete, the ScriptCat icon will appear in the extension list in the extension management interface, and you can also see it by clicking the extension button in the upper right corner of the browser's address bar) -- 1. **Edge** ![edge-load-unpacked-img](./img/README.assets/edge-load-unpacked-img.webp) -- 2. **Chrome** ![chrome-load-unpacked-img](./img/README.assets/chrome-load-unpacked-img.webp) +- 1. **Edge** ![edge-load-unpacked-img](./use.assets/edge-load-unpacked-img.webp) +- 2. **Chrome** ![chrome-load-unpacked-img](./use.assets/chrome-load-unpacked-img.webp) ⑤ Click the ScriptCat icon in the upper right corner, click `┆` > Get Scripts in the upper right corner of the interface that appears, and you can go to the script site to search and install scripts. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/6.vscode.md b/i18n/en/docusaurus-plugin-content-docs/current/use/vscode.md similarity index 94% rename from i18n/en/docusaurus-plugin-content-docs/current/use/6.vscode.md rename to i18n/en/docusaurus-plugin-content-docs/current/use/vscode.md index 08885c6a..ffb3271d 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/6.vscode.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/vscode.md @@ -1,16 +1,14 @@ --- -title: Develop Scripts with the VSCode Extension +title: Develop Scripts with VSCode --- -# Develop Scripts with VSCode - ScriptCat provides a VSCode extension that lets you write user scripts in VSCode. After saving, changes are automatically synced to ScriptCat in the browser — no manual copy-pasting required, greatly improving development efficiency. ## Prerequisites You need to install the following two tools: -1. **Install the ScriptCat extension in your browser** — If you haven't installed it yet, follow the [Quick Start](/docs/use/) guide to install it +1. **Install the ScriptCat extension in your browser** — If you haven't installed it yet, follow the [Quick Start](/docs/use/use/) guide to install it 2. **Install the ScriptCat extension in VSCode** — Search for "[scriptcat-vscode](https://marketplace.visualstudio.com/items?itemName=CodFrm.scriptcat-vscode)" in the VSCode Extensions marketplace, or download it from the [GitHub repository](https://github.com/scriptscat/scriptcat-vscode) ## Establish a Connection diff --git a/package.json b/package.json index 1aab14ac..183f5ca4 100644 --- a/package.json +++ b/package.json @@ -14,11 +14,16 @@ "serve": "docusaurus serve", "write-translations": "docusaurus write-translations", "write-heading-ids": "docusaurus write-heading-ids", - "typecheck": "tsc" + "typecheck": "tsc", + "check:urls": "node scripts/check-url-inventory.mjs", + "check:i18n": "node scripts/check-i18n-parity.mjs", + "check:frontmatter": "node scripts/check-frontmatter.mjs", + "check": "npm run check:urls && npm run check:i18n && npm run check:frontmatter" }, "dependencies": { "@ant-design/icons": "^5.1.4", "@docusaurus/core": "^3.10.1", + "@docusaurus/plugin-client-redirects": "^3.10.1", "@docusaurus/plugin-google-gtag": "^3.10.1", "@docusaurus/preset-classic": "^3.10.1", "@gracefullight/docusaurus-plugin-tailwind": "^1.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e536bff4..3ea21468 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@docusaurus/core': specifier: ^3.10.1 version: 3.10.1(@mdx-js/react@3.1.0(@types/react@18.3.20)(react@18.3.1))(acorn@8.14.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.2.2) + '@docusaurus/plugin-client-redirects': + specifier: ^3.10.1 + version: 3.10.1(@mdx-js/react@3.1.0(@types/react@18.3.20)(react@18.3.1))(acorn@8.14.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.2.2) '@docusaurus/plugin-google-gtag': specifier: ^3.10.1 version: 3.10.1(@mdx-js/react@3.1.0(@types/react@18.3.20)(react@18.3.1))(acorn@8.14.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.2.2) @@ -754,6 +757,10 @@ packages: resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + '@babel/template@7.27.0': resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==} engines: {node: '>=6.9.0'} @@ -1103,6 +1110,13 @@ packages: react: '*' react-dom: '*' + '@docusaurus/plugin-client-redirects@3.10.1': + resolution: {integrity: sha512-LHgd+YDvkhfOHMAE6XtUng3DQNzVM765RqVRrMJgHtzAvfopQhY6ieprqjxDVBdv21cLma6I0jHr+YCZH8fL9A==} + engines: {node: '>=20.0'} + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + '@docusaurus/plugin-content-blog@3.10.1': resolution: {integrity: sha512-mmkgE6Q2+K74tnkou7tXlpDLvoCU/qkSa2GSQ3XUiHWvcebCoDQzS670RR3tO8PmaWlIyWWISYWzZLuMfxunRA==} engines: {node: '>=20.0'} @@ -2147,11 +2161,8 @@ packages: caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} - caniuse-lite@1.0.30001715: - resolution: {integrity: sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==} - - caniuse-lite@1.0.30001727: - resolution: {integrity: sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==} + caniuse-lite@1.0.30001802: + resolution: {integrity: sha512-vmv8ub2xwTNmljSKf82mtCk5JH7hC+YgzLj3P5zotvA0tPQ9016tdNNOG8WRca1IxOnhSsivB+J0z5FeE5LOUw==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -6573,6 +6584,8 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 + '@babel/runtime@7.29.7': {} + '@babel/template@7.27.0': dependencies: '@babel/code-frame': 7.26.2 @@ -7082,6 +7095,38 @@ snapshots: - uglify-js - webpack-cli + '@docusaurus/plugin-client-redirects@3.10.1(@mdx-js/react@3.1.0(@types/react@18.3.20)(react@18.3.1))(acorn@8.14.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.2.2)': + dependencies: + '@docusaurus/core': 3.10.1(@mdx-js/react@3.1.0(@types/react@18.3.20)(react@18.3.1))(acorn@8.14.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.2.2) + '@docusaurus/logger': 3.10.1 + '@docusaurus/utils': 3.10.1(acorn@8.14.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-common': 3.10.1(acorn@8.14.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.10.1(acorn@8.14.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + eta: 2.2.0 + fs-extra: 11.3.0 + lodash: 4.17.21 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + tslib: 2.8.1 + transitivePeerDependencies: + - '@docusaurus/faster' + - '@mdx-js/react' + - '@parcel/css' + - '@rspack/core' + - '@swc/core' + - '@swc/css' + - acorn + - bufferutil + - csso + - debug + - esbuild + - lightningcss + - supports-color + - typescript + - uglify-js + - utf-8-validate + - webpack-cli + '@docusaurus/plugin-content-blog@3.10.1(@docusaurus/plugin-content-docs@3.10.1(@mdx-js/react@3.1.0(@types/react@18.3.20)(react@18.3.1))(acorn@8.14.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.2.2))(@mdx-js/react@3.1.0(@types/react@18.3.20)(react@18.3.1))(acorn@8.14.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.2.2)': dependencies: '@docusaurus/core': 3.10.1(@mdx-js/react@3.1.0(@types/react@18.3.20)(react@18.3.1))(acorn@8.14.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.2.2) @@ -8194,7 +8239,7 @@ snapshots: '@slorber/react-helmet-async@1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.27.0 + '@babel/runtime': 7.29.7 invariant: 2.2.4 prop-types: 15.8.1 react: 18.3.1 @@ -8742,7 +8787,7 @@ snapshots: autoprefixer@10.4.21(postcss@8.5.3): dependencies: browserslist: 4.24.4 - caniuse-lite: 1.0.30001715 + caniuse-lite: 1.0.30001802 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -8752,7 +8797,7 @@ snapshots: autoprefixer@10.4.21(postcss@8.5.6): dependencies: browserslist: 4.24.4 - caniuse-lite: 1.0.30001715 + caniuse-lite: 1.0.30001802 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -8865,14 +8910,14 @@ snapshots: browserslist@4.24.4: dependencies: - caniuse-lite: 1.0.30001715 + caniuse-lite: 1.0.30001802 electron-to-chromium: 1.5.141 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.4) browserslist@4.25.1: dependencies: - caniuse-lite: 1.0.30001727 + caniuse-lite: 1.0.30001802 electron-to-chromium: 1.5.182 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.25.1) @@ -8934,13 +8979,11 @@ snapshots: caniuse-api@3.0.0: dependencies: browserslist: 4.25.1 - caniuse-lite: 1.0.30001727 + caniuse-lite: 1.0.30001802 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 - caniuse-lite@1.0.30001715: {} - - caniuse-lite@1.0.30001727: {} + caniuse-lite@1.0.30001802: {} ccount@2.0.1: {} diff --git a/scripts/check-config.json b/scripts/check-config.json new file mode 100644 index 00000000..763a3873 --- /dev/null +++ b/scripts/check-config.json @@ -0,0 +1,4 @@ +{ + "i18nParityStrict": true, + "frontmatterStrict": true +} diff --git a/scripts/check-frontmatter.mjs b/scripts/check-frontmatter.mjs new file mode 100644 index 00000000..4ced960e --- /dev/null +++ b/scripts/check-frontmatter.mjs @@ -0,0 +1,93 @@ +#!/usr/bin/env node +// Enforces the docs frontmatter/title conventions from REFACTOR_PROPOSAL.md §2.1/§2.4: +// - every doc has a frontmatter `title` +// - no body H1 (title alone drives the page heading), unless `hide_title: true` +// - no leftover `id:` / `sidebar_position:` overrides +// - no number-prefixed filenames (e.g. "2.sync.md") +// +// Controlled by scripts/check-config.json: { "frontmatterStrict": boolean }. +// While false, violations are printed as warnings and the script exits 0. + +import { readFileSync, existsSync, readdirSync, statSync } from "node:fs"; +import { join, relative, sep, basename } from "node:path"; + +const ROOT = new URL("..", import.meta.url).pathname; +const DOC_DIRS = [ + join(ROOT, "docs"), + join(ROOT, "i18n/en/docusaurus-plugin-content-docs/current"), +]; +const CONFIG_FILE = join(ROOT, "scripts", "check-config.json"); +const NUMBER_PREFIX = /^\d+\.[^/]/; + +function listDocs(dir) { + const results = []; + function recurse(current) { + for (const entry of readdirSync(current)) { + const full = join(current, entry); + const stat = statSync(full); + if (stat.isDirectory()) { + recurse(full); + } else if (/\.mdx?$/.test(entry)) { + results.push(full); + } + } + } + if (existsSync(dir)) recurse(dir); + return results; +} + +function parseFrontmatter(text) { + const match = /^---\n([\s\S]*?)\n---\n?/.exec(text); + if (!match) return { fm: {}, body: text }; + const fm = {}; + for (const line of match[1].split("\n")) { + const m = /^([\w-]+):\s*(.*)$/.exec(line); + if (m) fm[m[1]] = m[2].trim(); + } + return { fm, body: text.slice(match[0].length) }; +} + +function checkFile(file) { + const issues = []; + const rel = relative(ROOT, file); + const text = readFileSync(file, "utf8"); + const { fm, body } = parseFrontmatter(text); + + if (!fm.title) issues.push("missing frontmatter `title`"); + if (fm.id) issues.push(`leftover \`id: ${fm.id}\` override`); + if (fm.sidebar_position) issues.push(`leftover \`sidebar_position: ${fm.sidebar_position}\` override`); + if (NUMBER_PREFIX.test(basename(file))) issues.push("number-prefixed filename"); + + const hideTitle = fm.hide_title === "true"; + // Strip fenced code blocks first: sample "# Heading" lines inside example + // markdown/file snippets aren't real page headings. + const bodyWithoutCodeFences = body.replace(/```[\s\S]*?```/g, ""); + if (!hideTitle && /^#\s+.+$/m.test(bodyWithoutCodeFences)) { + issues.push("body contains an H1 (title should come from frontmatter `title` only)"); + } + + return issues.map((issue) => `${rel}: ${issue}`); +} + +function main() { + const config = JSON.parse(readFileSync(CONFIG_FILE, "utf8")); + const strict = Boolean(config.frontmatterStrict); + + const allIssues = DOC_DIRS.flatMap(listDocs).flatMap(checkFile); + + if (allIssues.length === 0) { + console.log("Frontmatter check passed: no violations."); + return; + } + + console.log(`Frontmatter violations (${allIssues.length}):`); + for (const issue of allIssues) console.log(` - ${issue}`); + + if (strict) { + console.error("\nFrontmatter check FAILED (strict mode enabled in scripts/check-config.json)."); + process.exit(1); + } + console.log("\nFrontmatter check: warnings only (strict mode disabled in scripts/check-config.json)."); +} + +main(); diff --git a/scripts/check-i18n-parity.mjs b/scripts/check-i18n-parity.mjs new file mode 100644 index 00000000..f8114b0b --- /dev/null +++ b/scripts/check-i18n-parity.mjs @@ -0,0 +1,68 @@ +#!/usr/bin/env node +// Verifies every zh-Hans doc under docs/ has an English mirror under +// i18n/en/docusaurus-plugin-content-docs/current/ (and vice versa). +// +// Controlled by scripts/check-config.json: { "i18nParityStrict": boolean }. +// While false, mismatches are printed as warnings and the script exits 0. +// Once the translation backlog is cleared, flip it to true to hard-fail CI. + +import { readFileSync, existsSync, readdirSync, statSync } from "node:fs"; +import { join, relative, sep } from "node:path"; + +const ROOT = new URL("..", import.meta.url).pathname; +const ZH_DIR = join(ROOT, "docs"); +const EN_DIR = join(ROOT, "i18n/en/docusaurus-plugin-content-docs/current"); +const CONFIG_FILE = join(ROOT, "scripts", "check-config.json"); + +// Node 18/20 (the CI runtime) lack fs.globSync (added in Node 22), so walk manually. +function listDocs(dir) { + const results = []; + function recurse(current) { + for (const entry of readdirSync(current)) { + const full = join(current, entry); + const stat = statSync(full); + if (stat.isDirectory()) { + recurse(full); + } else if (/\.mdx?$/.test(entry)) { + results.push(relative(dir, full).split(sep).join("/")); + } + } + } + recurse(dir); + return results.sort(); +} + +function main() { + const config = JSON.parse(readFileSync(CONFIG_FILE, "utf8")); + const strict = Boolean(config.i18nParityStrict); + + const zhDocs = listDocs(ZH_DIR); + const enDocs = existsSync(EN_DIR) ? listDocs(EN_DIR) : []; + const enSet = new Set(enDocs); + const zhSet = new Set(zhDocs); + + const missing = zhDocs.filter((d) => !enSet.has(d)); + const orphans = enDocs.filter((d) => !zhSet.has(d)); + + if (missing.length === 0 && orphans.length === 0) { + console.log(`i18n parity check passed: ${zhDocs.length} docs, all translated.`); + return; + } + + if (missing.length > 0) { + console.log(`Missing English translation (${missing.length}):`); + for (const m of missing) console.log(` - ${m}`); + } + if (orphans.length > 0) { + console.log(`English doc with no zh-Hans source (${orphans.length}):`); + for (const o of orphans) console.log(` - ${o}`); + } + + if (strict) { + console.error("\ni18n parity check FAILED (strict mode enabled in scripts/check-config.json)."); + process.exit(1); + } + console.log("\ni18n parity check: warnings only (strict mode disabled in scripts/check-config.json)."); +} + +main(); diff --git a/scripts/check-url-inventory.mjs b/scripts/check-url-inventory.mjs new file mode 100644 index 00000000..46328d4a --- /dev/null +++ b/scripts/check-url-inventory.mjs @@ -0,0 +1,80 @@ +#!/usr/bin/env node +// Verifies the built site exposes the exact same set of routes as the +// committed baseline in scripts/url-inventory.txt. Run after `pnpm run build`. +// +// Usage: +// node scripts/check-url-inventory.mjs # compare build/ against the baseline +// node scripts/check-url-inventory.mjs --write # regenerate the baseline from build/ + +import { readdirSync, statSync, readFileSync, writeFileSync, existsSync } from "node:fs"; +import { join, relative, sep } from "node:path"; + +const ROOT = new URL("..", import.meta.url).pathname; +const BUILD_DIR = join(ROOT, "build"); +const BASELINE_FILE = join(ROOT, "scripts", "url-inventory.txt"); +const PAGE_FILES = new Set(["index.html", "404.html", "opensearch.xml"]); + +function walkRoutes(dir) { + const routes = []; + function recurse(current) { + for (const entry of readdirSync(current)) { + const full = join(current, entry); + const stat = statSync(full); + if (stat.isDirectory()) { + recurse(full); + } else if (PAGE_FILES.has(entry)) { + const rel = relative(BUILD_DIR, full).split(sep).join("/"); + routes.push("/" + rel); + } + } + } + recurse(dir); + return routes; +} + +function main() { + if (!existsSync(BUILD_DIR)) { + console.error("build/ not found — run `pnpm run build` first."); + process.exit(1); + } + + const routes = walkRoutes(BUILD_DIR).sort(); + const content = routes.join("\n") + "\n"; + + if (process.argv.includes("--write")) { + writeFileSync(BASELINE_FILE, content); + console.log(`Wrote ${routes.length} routes to ${relative(ROOT, BASELINE_FILE)}`); + return; + } + + if (!existsSync(BASELINE_FILE)) { + console.error( + `No baseline at ${relative(ROOT, BASELINE_FILE)}. Run with --write once to create it.` + ); + process.exit(1); + } + + const baseline = readFileSync(BASELINE_FILE, "utf8").split("\n").filter(Boolean).sort(); + const baselineSet = new Set(baseline); + const currentSet = new Set(routes); + + const removed = baseline.filter((r) => !currentSet.has(r)); + const added = routes.filter((r) => !baselineSet.has(r)); + + if (removed.length === 0 && added.length === 0) { + console.log(`URL inventory check passed: ${routes.length} routes match the baseline.`); + return; + } + + if (removed.length > 0) { + console.error("Routes REMOVED from the site (URL contract violation):"); + for (const r of removed) console.error(` - ${r}`); + } + if (added.length > 0) { + console.error("Routes ADDED to the site (confirm this is intentional and update the baseline with --write):"); + for (const r of added) console.error(` + ${r}`); + } + process.exit(1); +} + +main(); diff --git a/scripts/url-inventory.txt b/scripts/url-inventory.txt new file mode 100644 index 00000000..ce0c6d31 --- /dev/null +++ b/scripts/url-inventory.txt @@ -0,0 +1,94 @@ +/404.html +/docs/about/index.html +/docs/change/beta-changelog/index.html +/docs/change/index.html +/docs/change/v0.16/index.html +/docs/change/v0.17/index.html +/docs/change/v1.1/index.html +/docs/change/v1.2/index.html +/docs/change/v1.3/index.html +/docs/change/v1.4/index.html +/docs/dev/agent/agent-builtin-tools/index.html +/docs/dev/agent/agent-conversation/index.html +/docs/dev/agent/agent-dom/index.html +/docs/dev/agent/agent-mcp/index.html +/docs/dev/agent/agent-model/index.html +/docs/dev/agent/agent-opfs/index.html +/docs/dev/agent/agent-skill-dev/index.html +/docs/dev/agent/agent-skill-install/index.html +/docs/dev/agent/agent-skill/index.html +/docs/dev/agent/agent-task/index.html +/docs/dev/agent/index.html +/docs/dev/api/index.html +/docs/dev/background/index.html +/docs/dev/cat-api/index.html +/docs/dev/cloudcat/index.html +/docs/dev/config/index.html +/docs/dev/index.html +/docs/dev/meta/index.html +/docs/dev/subscribe/index.html +/docs/script_installation/index.html +/docs/use/QA/index.html +/docs/use/from-other/migrate-from-tampermonkey/index.html +/docs/use/from-other/migrate-from-violentmonkey/index.html +/docs/use/index.html +/docs/use/install_comple/index.html +/docs/use/open-dev/index.html +/docs/use/policy/disclaimer/index.html +/docs/use/policy/privacy/index.html +/docs/use/policy/privacy_website/index.html +/docs/use/script_installation/index.html +/docs/use/sync/index.html +/docs/use/use/index.html +/docs/use/vscode/index.html +/en/404.html +/en/docs/about/index.html +/en/docs/change/beta-changelog/index.html +/en/docs/change/index.html +/en/docs/change/v0.16/index.html +/en/docs/change/v0.17/index.html +/en/docs/change/v1.1/index.html +/en/docs/change/v1.2/index.html +/en/docs/change/v1.3/index.html +/en/docs/change/v1.4/index.html +/en/docs/dev/agent/agent-builtin-tools/index.html +/en/docs/dev/agent/agent-conversation/index.html +/en/docs/dev/agent/agent-dom/index.html +/en/docs/dev/agent/agent-mcp/index.html +/en/docs/dev/agent/agent-model/index.html +/en/docs/dev/agent/agent-opfs/index.html +/en/docs/dev/agent/agent-skill-dev/index.html +/en/docs/dev/agent/agent-skill-install/index.html +/en/docs/dev/agent/agent-skill/index.html +/en/docs/dev/agent/agent-task/index.html +/en/docs/dev/agent/index.html +/en/docs/dev/api/index.html +/en/docs/dev/background/index.html +/en/docs/dev/cat-api/index.html +/en/docs/dev/cloudcat/index.html +/en/docs/dev/config/index.html +/en/docs/dev/index.html +/en/docs/dev/meta/index.html +/en/docs/dev/subscribe/index.html +/en/docs/script_installation/index.html +/en/docs/use/QA/index.html +/en/docs/use/from-other/migrate-from-tampermonkey/index.html +/en/docs/use/from-other/migrate-from-violentmonkey/index.html +/en/docs/use/index.html +/en/docs/use/install_comple/index.html +/en/docs/use/open-dev/index.html +/en/docs/use/policy/disclaimer/index.html +/en/docs/use/policy/privacy/index.html +/en/docs/use/policy/privacy_website/index.html +/en/docs/use/script_installation/index.html +/en/docs/use/sync/index.html +/en/docs/use/use/index.html +/en/docs/use/vscode/index.html +/en/index.html +/en/opensearch.xml +/en/search/index.html +/en/uninstall/index.html +/index.html +/opensearch.xml +/search/index.html +/uninstall/index.html diff --git a/sidebars.js b/sidebars.js index 38786010..3eaaaa1f 100644 --- a/sidebars.js +++ b/sidebars.js @@ -13,9 +13,35 @@ /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ const sidebars = { - use: [{ type: "autogenerated", dirName: "use" }], + use: [ + "use/use", + "use/script_installation", + "use/sync", + "use/QA", + { + type: "category", + label: "从其它管理器迁移", + items: [ + "use/from-other/migrate-from-tampermonkey", + "use/from-other/migrate-from-violentmonkey", + ], + }, + "use/open-dev", + "use/vscode", + { + type: "category", + label: "服务协议", + items: [ + "use/policy/disclaimer", + "use/policy/privacy", + "use/policy/privacy_website", + ], + }, + // use/install_comple and script_installation (top-level) are hidden + // extension-flow pages, intentionally not listed in any sidebar. + ], dev: [ - "dev/dev", + "dev/index", "dev/background", "dev/cloudcat", "dev/subscribe", @@ -25,7 +51,7 @@ const sidebars = { { type: "category", label: "Agent 智能助手", - link: { type: "doc", id: "dev/agent/agent" }, + link: { type: "doc", id: "dev/agent/index" }, items: [ "dev/agent/agent-conversation", "dev/agent/agent-dom", @@ -41,7 +67,16 @@ const sidebars = { }, "dev/meta", ], - change: [{ type: "autogenerated", dirName: "change" }], + change: [ + "change/index", + "change/beta-changelog", + "change/v1.4", + "change/v1.3", + "change/v1.2", + "change/v1.1", + "change/v0.17", + "change/v0.16", + ], }; module.exports = sidebars;