From 8388487ab653be1f5892cdab711764fde1908ef4 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 7 Jul 2026 02:12:47 +0900 Subject: [PATCH 01/10] docs: add technical proposal for structure refactor + i18n completion Captures the current-state audit (URL contract, title/H1 mismatches, translation gaps, broken links/anchors) and the phased plan to fix folder structure, sidebar/title consistency, and English translation without changing any published URL. --- REFACTOR_PROPOSAL.md | 300 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 REFACTOR_PROPOSAL.md diff --git a/REFACTOR_PROPOSAL.md b/REFACTOR_PROPOSAL.md new file mode 100644 index 0000000..880ed35 --- /dev/null +++ b/REFACTOR_PROPOSAL.md @@ -0,0 +1,300 @@ +# Technical Proposal — Docs Structure Refactor, Title Consistency & Full English Translation + +Repo: `scriptscat/scriptcat.org` (docs.scriptcat.org) · Branch: `refactor-001` · Date: 2026-07-07 +Stack: Docusaurus 3.10 (classic preset), pnpm, Gitea Actions → Docker/nginx → Helm/k8s + +## 0. Goals & Non-Goals + +**Goals** + +1. Make the folder structure self-describing: **file path = doc ID = published URL**, with zero frontmatter indirection. +2. Eliminate the sidebar-label / page-title mismatch class (e.g. `使用文档` sidebar shows "VSCode 扩展开发脚本" but the page H1 is "使用 VSCode 开发脚本") — by construction, not by discipline. +3. Complete the English translation (25 files currently missing) and keep it complete with a CI parity gate. +4. Improve workflow/config so regressions (URL changes, broken links, missing translations) are caught mechanically. +5. Optimize for maintainability by **both humans and coding agents**: one greppable convention per concern, documented in-repo. + +**Hard constraint (non-negotiable)** + +> **No published URL may change.** All 43 zh-Hans routes, their 43 `/en/` mirrors, plus `/uninstall/`, `/404.html`, `/opensearch.xml` must be byte-identical in the sitemap/route inventory before and after every phase. Several URLs are load-bearing (opened programmatically by the ScriptCat extension): `/docs/script_installation/`, `/docs/use/install_comple/`, `/uninstall/`. + +**Non-goals (explicitly out of scope)** + +- URL beautification (`/docs/use/use/` → `/docs/use/`, fixing the `install_comple` typo). Listed as an optional, separately-approved Phase 6 using redirects only. +- Content rewrites beyond title alignment and translation. + +--- + +## 1. Current-State Audit (verified against a local `pnpm run build` on this branch) + +### 1.1 The URL contract (baseline, from `build/sitemap.xml`) + +43 zh URLs; `build/en/sitemap.xml` mirrors them 1:1 under `/en/` (verified by diff). Key routes and how they are derived today: + +| URL | Source file | Derivation quirk | +|---|---|---| +| `/docs/use/use/` | `docs/use/1.README.md` | number prefix `1.` stripped; `id: use` overrides filename; **not** an index page — `/docs/use/` itself 404s today | +| `/docs/use/script_installation/` | `docs/use/2.script_installation.md` | prefix stripped | +| `/docs/use/sync/` | `docs/use/2.sync.md` | duplicate `2.` prefix (ordering collision with the above) | +| `/docs/use/QA/` | `docs/use/3.QA.md` | prefix stripped | +| `/docs/use/from-other/...` | `docs/use/4.from-other/...` | dir prefix stripped; label via `_category_.json` | +| `/docs/use/open-dev/`, `/docs/use/vscode/` | `5.open-dev.md`, `6.vscode.md` | prefix stripped | +| `/docs/use/policy/...` | `docs/use/99.policy/...` | dir prefix stripped | +| `/docs/use/install_comple/` | `docs/use/install_comple.md` | typo (`comple`) is live; **hardcoded in the extension** | +| `/docs/dev/` | `docs/dev/README.md` | README-as-index convention + `id: dev` | +| `/docs/dev/agent/` | `docs/dev/agent/index.md` | index convention + `id: agent` | +| `/docs/dev/agent/agent-conversation/` etc. | `docs/dev/agent/conversation.md` etc. | `id: agent-conversation` frontmatter renames every agent doc | +| `/docs/change/` | `docs/change/README.md` | index convention + `id: change` | +| `/docs/change/beta-changelog/` | `docs/change/beta.md` | `id: beta-changelog` | +| `/docs/change/v1.4/` … | `docs/change/v1.4.md` … | descending `sidebar_position: 9995…10000` hack for newest-first ordering | +| `/docs/script_installation/` | `docs/script_installation.md` | extension install intermediate page | +| `/docs/about/` | `docs/about/README.md` | carries dead VuePress-era keys (`sidebar: false`, `icon: info`) | +| `/uninstall/` | `src/pages/uninstall.tsx` | extension uninstall-feedback page | + +**Three URL-derivation mechanisms coexist** (number-prefix stripping, `id:` overrides, README/index convention). An agent or new contributor cannot map URL → file without reading frontmatter of every candidate. This is the root maintainability problem. + +### 1.2 Sidebar/ordering mechanisms — three coexist + +- `use`: autogenerated from number prefixes (already collided: two `2.` files). +- `dev`: explicit list in `sidebars.js`, referencing frontmatter-overridden IDs. +- `change`: autogenerated + descending `sidebar_position` hack. + +### 1.3 Title/label mismatches (frontmatter `title` drives the sidebar; body `# H1` drives the page) + +Found by script (zh; mirrored in en where translated): + +| File | `title` (sidebar/``) | Body H1 (page heading) | +|---|---|---| +| `docs/use/6.vscode.md` | VSCode 扩展开发脚本 | 使用 VSCode 开发脚本 | +| `docs/use/99.policy/disclaimer.md` | 免责声明 | ScriptCat 免责协议 | +| `docs/use/99.policy/privacy.md` | 隐私政策 | ScriptCat 隐私政策 | +| `docs/use/99.policy/privacy_website.md` | 脚本站点 隐私政策 | ScriptCat 脚本站点 隐私政策 | +| `docs/use/install_comple.md` | 安装完成 | 🎉 欢迎使用脚本猫 (intentional: `hide_title: true`) | + +Root cause: two competing sources of truth with no rule and no lint. + +### 1.4 Translation gaps (en) + +Missing entirely (falls back to Chinese on `/en/` pages): **all 13 `dev/` docs** (incl. the whole `agent/` section), `about/README.md`, and changelogs `v0.16`, `v0.17`, `v1.1`, `v1.2`, `v1.4` — 25 files. Additionally the en asset tree diverges from zh in naming (`i18n/en/.../use/4.from-other/img/migrate-from-violentmonkey.assets/` vs zh `img/migrate-from-violentmonkey/`). + +### 1.5 Broken links/anchors already shipping (build warns; `onBrokenLinks: "warn"` lets them through) + +- `/en/docs/use/vscode/` → links `/en/docs/use/` (**404 — `/docs/use/` and `/en/docs/use/` do not exist**; the site footer also links `/docs/use`). +- `docs/dev/agent/skill-install.md` uses URL-style relative links (`./agent-skill/`) that resolve incorrectly. +- 7 broken anchors across `/docs/dev/`, `/docs/dev/api/`, `/docs/dev/meta/`, `/docs/change/` (stale `#定时脚本`/`#后台脚本`/`#gm_cookie`/`#storagename-🧪` targets). + +### 1.6 Repo/CI hygiene + +- 15+ `.DS_Store` files committed; not in `.gitignore`. +- No PR/CI validation workflow — only the deploy workflow, which builds and ships without link/translation/URL checks. +- Deprecation warning: `onBrokenMarkdownLinks` must move to `markdown.hooks.onBrokenMarkdownLinks` (removed in Docusaurus v4). +- Asset conventions: four patterns coexist (`X.assets/` sibling, `img/X.assets/`, `img/X/`, section-level `img/`). +- `editUrl` does not set `editLocalizedFiles`, so "Edit this page" on `/en/` pages edits the zh source. + +--- + +## 2. Target Design + +### 2.1 Principle: one convention per concern + +| Concern | Single source of truth | +|---|---| +| URL / doc ID | File path, verbatim (no `id:`, no number prefixes) | +| Page title, sidebar label, `<title>` | Frontmatter `title:` (+ optional `sidebar_label:` for deliberate short labels) | +| Sidebar ordering | `sidebars.js`, explicit for all three sidebars | +| Images | `<doc-name>.assets/` sibling folder | +| Internal links | File-relative paths to the `.md` file (Docusaurus validates them at build time) | +| URL contract | Committed `scripts/url-inventory.txt`, enforced in CI | + +### 2.2 File renames (path ⇒ today's URL, then delete all `id:` overrides) + +All renames use `git mv`. The i18n/en tree is renamed identically in the same commit. Resulting doc IDs equal today's IDs, so URLs are provably unchanged. + +```text +docs/use/1.README.md → docs/use/use.md # id use/use, URL /docs/use/use/ (unchanged) +docs/use/2.script_installation.md → docs/use/script_installation.md +docs/use/2.sync.md → docs/use/sync.md +docs/use/3.QA.md → docs/use/QA.md # keep exact case +docs/use/4.from-other/ → docs/use/from-other/ +docs/use/5.open-dev.md → docs/use/open-dev.md +docs/use/6.vscode.md → docs/use/vscode.md +docs/use/99.policy/ → docs/use/policy/ +docs/use/install_comple.md → (keep; URL typo is load-bearing — add a NOTE comment in the file) + +docs/dev/README.md → docs/dev/index.md # id dev/index, URL /docs/dev/ (unchanged) +docs/dev/agent/index.md → (keep name; drop id: agent → id dev/agent/index, URL /docs/dev/agent/) +docs/dev/agent/conversation.md → docs/dev/agent/agent-conversation.md +docs/dev/agent/dom.md → docs/dev/agent/agent-dom.md +docs/dev/agent/skill-install.md → docs/dev/agent/agent-skill-install.md +docs/dev/agent/skill.md → docs/dev/agent/agent-skill.md +docs/dev/agent/skill-dev.md → docs/dev/agent/agent-skill-dev.md +docs/dev/agent/task.md → docs/dev/agent/agent-task.md +docs/dev/agent/model.md → docs/dev/agent/agent-model.md +docs/dev/agent/opfs.md → docs/dev/agent/agent-opfs.md +docs/dev/agent/mcp.md → docs/dev/agent/agent-mcp.md +docs/dev/agent/builtin-tools.md → docs/dev/agent/agent-builtin-tools.md + +docs/change/README.md → docs/change/index.md # id change/index, URL /docs/change/ +docs/change/beta.md → docs/change/beta-changelog.md + +docs/about/README.md → docs/about/index.md # URL /docs/about/; delete dead keys sidebar:/icon: +``` + +Then delete **every** `id:` and `sidebar_position:` frontmatter key repo-wide. The `agent/agent-*.md` names look redundant, but the alternative (keeping short filenames + `id:` overrides) preserves exactly the indirection we are removing; filename==URL is worth the redundancy. (Renaming URLs to drop the `agent-` prefix is forbidden by the constraint.) + +`docs/use/use.md` is admittedly an odd name — it is the price of the pre-existing `/docs/use/use/` URL. Phase 6 (optional) can promote it to `index.md` + redirect later. + +### 2.3 Sidebars: fully explicit `sidebars.js` + +Replace all autogeneration and `sidebar_position` with three explicit arrays (dev is already explicit — just update IDs): + +```js +const sidebars = { + use: [ + "use/use", + "use/script_installation", + "use/sync", + "use/QA", + { + type: "category", + label: "从其它管理器迁移", // translation key format unchanged: + items: [ // sidebar.use.category.从其它管理器迁移 + "use/from-other/migrate-from-tampermonkey", + "use/from-other/migrate-from-violentmonkey", + ], + }, + "use/open-dev", + "use/vscode", + { + type: "category", + label: "服务协议", // sidebar.use.category.服务协议 + items: ["use/policy/disclaimer", "use/policy/privacy", "use/policy/privacy_website"], + }, + // use/install_comple intentionally unlisted (hidden page) + ], + dev: [ + "dev/index", "dev/background", "dev/cloudcat", "dev/subscribe", + "dev/config", "dev/api", "dev/cat-api", + { + type: "category", + label: "Agent 智能助手", + link: { type: "doc", id: "dev/agent/index" }, + items: [ + "dev/agent/agent-conversation", "dev/agent/agent-dom", + "dev/agent/agent-skill-install", "dev/agent/agent-skill", + "dev/agent/agent-task", "dev/agent/agent-model", + "dev/agent/agent-opfs", "dev/agent/agent-mcp", + "dev/agent/agent-skill-dev", "dev/agent/agent-builtin-tools", + ], + }, + "dev/meta", + ], + change: [ + "change/index", + "change/beta-changelog", + "change/v1.4", "change/v1.3", "change/v1.2", "change/v1.1", + "change/v0.17", "change/v0.16", // newest-first; adding a release = insert one line + ], +}; +``` + +Consequences: delete both `_category_.json` files; delete the `9995…10000` position hack; `use/install_comple.md` no longer needs `sidebar_class_name: hidden` CSS hackery (unlisted docs are simply not in the sidebar — verify the hidden behavior is preserved, else keep the class). Category-label translation keys in `i18n/*/docusaurus-plugin-content-docs/current.json` keep the same `sidebar.use.category.<label>` format because the zh labels are unchanged. + +Update references: navbar `docId`s in `docusaurus.config.js` become `use/use` (unchanged), `dev/index`, `change/index`. + +Why explicit over autogenerated-everywhere: ordering lives in one greppable file, review diffs show sidebar changes explicitly, no renumber churn, no prefix collisions, and an agent can update navigation without inferring numeric conventions. Cost: adding a doc touches two files — acceptable and lint-checkable (a doc not referenced by any sidebar and not allowlisted fails CI). + +### 2.4 Title policy — mismatch impossible by construction + +**Rule: frontmatter `title:` is the only title. Body markdown contains no `# H1`** (Docusaurus renders `title` as the page H1 automatically). `sidebar_label:` allowed when a deliberately shorter nav label is wanted. `hide_title: true` pages (only `install_comple`) may keep a decorative body H1. + +Migration decisions for the current mismatches (needs maintainer eyes on wording; defaults below keep today's *visible page heading* and change only the metadata/sidebar to match): + +| File | New `title` | `sidebar_label` (optional) | +|---|---|---| +| `use/vscode.md` | 使用 VSCode 开发脚本 | — (sidebar text changes accordingly; en: "Develop Scripts with VSCode") | +| `use/policy/disclaimer.md` | ScriptCat 免责协议 | 免责声明 (keeps sidebar identical) | +| `use/policy/privacy.md` | ScriptCat 隐私政策 | 隐私政策 | +| `use/policy/privacy_website.md` | ScriptCat 脚本站点 隐私政策 | 脚本站点 隐私政策 | +| `use/install_comple.md` | 安装完成 (unchanged; `hide_title` exemption) | — | + +All other docs: move their current H1 text into `title:` and delete the H1 line (a mechanical script; see 2.7). Note `<title>`/OG metadata may change wording on the five fixed pages — that is the point of the fix; URLs do not change. + +### 2.5 Assets — one convention + +`<doc-name>.assets/` sibling folder (Typora's default; already used by `dev/*.assets` and `change/v1.3.assets`). Migrate `docs/use/img/**`, `docs/use/from-other/img/**`, `docs/change/img/**` into per-doc `.assets/` folders and rewrite the relative links. **Output-safe**: markdown-referenced images are emitted as content-hashed files under `/assets/images/`; their public URLs are derived from basename+content, not source directory. `static/` is untouched. + +i18n rule: locale-specific screenshots (e.g. English-UI browser screenshots) live beside the en markdown in the mirrored path with **identical folder names** to zh; genuinely language-neutral shared images should be referenced with `@site/docs/...` absolute source paths from both locales to avoid duplication (apply opportunistically during translation, not as a bulk migration). + +### 2.6 Full English translation + +Translate the 25 missing files (mirrored paths under `i18n/en/docusaurus-plugin-content-docs/current/`), in priority order: + +1. **`dev/` (13 files)** — the whole developer guide incl. `agent/` section; highest reader value. +2. **`about/index.md`**, **`change/index.md` deltas**, **`change/v1.4.md`** — current-facing pages. +3. **Historical changelogs** `v1.2`, `v1.1`, `v0.17`, `v0.16` — required for "fully translated"; low urgency, translate last. + +Also: run `pnpm run write-translations -- --locale en` and diff to catch untranslated `code.json`/theme keys (e.g. the `uninstall` page strings already use the translation API — verify coverage). + +Translation conventions (record in CONTRIBUTING.md): ScriptCat=脚本猫, user script=用户脚本, background script=后台脚本, scheduled script=定时脚本, Tampermonkey=油猴; en pages must keep identical heading *structure* so anchors and cross-links stay parallel; frontmatter keys identical to zh except translated `title`/`sidebar_label`. + +### 2.7 Guardrail scripts (`scripts/`, run via `pnpm run check` and in CI) + +1. **`check-url-inventory.mjs`** — after `docusaurus build`, collect `find build -name index.html` (both locales, normalized to routes) **plus** both sitemaps; compare against committed `scripts/url-inventory.txt`. Any diff fails CI; changing the contract requires editing the inventory file in the same PR (visible in review). *This is the mechanical guarantee that the refactor changes no URL.* +2. **`check-i18n-parity.mjs`** — the set of `docs/**/*.md(x)` must equal `i18n/en/docusaurus-plugin-content-docs/current/**/*.md(x)`; report missing and orphan files. Warn-only until Phase 5 completes, then hard-fail. +3. **`check-frontmatter.mjs`** — per doc: `title:` present; no body `# H1` (unless `hide_title: true`); no `id:`; no `sidebar_position:`; filename has no `N.` prefix; doc is referenced by exactly one sidebar or is in the hidden-pages allowlist (`use/install_comple`, `script_installation`, `about/index`); images referenced only from `./<doc>.assets/`, `@site/`, or `/img/`. +4. **H1→title migration script** (one-off, used in Phase 4): moves the first H1 of each doc into frontmatter `title`, deleting the H1 line; flags conflicts (the five mismatches) for manual resolution. + +### 2.8 Config changes (`docusaurus.config.js`) + +- `onBrokenLinks: "throw"` and `onBrokenAnchors: "throw"` (after Phase 2 fixes the pre-existing 3 links + 7 anchors; until then keep `warn` locally but CI treats warnings as failures via the checks). +- Migrate `onBrokenMarkdownLinks` → `markdown: { hooks: { onBrokenMarkdownLinks: "throw" } }` (v4-removal deprecation observed in build). +- `editUrl` → object form with `editLocalizedFiles: true` so `/en/` pages edit the en source. Verify the target repo slug (`scriptscat/scriptcat.org/edit/main`) matches the actual upstream default branch. +- Add `@docusaurus/plugin-client-redirects` with a single redirect `/docs/use/` → `/docs/use/use/`. This **adds** a route (fixing the currently-404 footer link `使用指南` and the `/docs/use/` links inside `vscode.md`/`use.md` without touching content everywhere) and changes no existing route. Add `/docs/use/` to the inventory as an intentional addition in that PR. (Alternative: rewrite the ~4 in-content links to `/docs/use/use/` and the footer `to:`; the redirect additionally rescues external bookmarks, so prefer the redirect **and** fix the footer link.) +- Internal-link style rule (enforced socially + by build validation): file-relative links to `.md` files. After 2.2, file path == URL so existing URL-style links keep working; new content should use file paths, which `onBrokenMarkdownLinks: throw` validates even for moved files. + +### 2.9 Workflow changes (`.gitea/workflows/`) + +- **New `ci.yaml`** (on `pull_request` + push to non-main): `pnpm install --frozen-lockfile` → `pnpm run typecheck` → `pnpm run build` → `pnpm run check` (inventory, parity, frontmatter). Cache pnpm store; no Docker/deploy steps. +- **`deploy.yaml`**: insert `pnpm run check` between Build and Docker steps, so a bad merge cannot ship. +- Keep the (Gitea-mirrored) action names as-is; they are environment-specific. + +### 2.10 Hygiene & docs-for-maintainers + +- Add `.DS_Store` to `.gitignore`; `git rm --cached` the ~15 committed instances. +- `npx update-browserslist-db@latest` (build warns; caniuse data 13–15 months old). +- **`CONTRIBUTING.md`** (root, bilingual or zh with en summary) capturing: the one-convention table (§2.1), "how to add a doc" (create file → add sidebar line → create en mirror → `pnpm run check`), "how to add a changelog release", the load-bearing URL list, and the translation glossary. This file is the agent-facing operating manual; keep it under ~150 lines so it fits in any agent's context. Optionally mirror the key rules into a root `AGENTS.md`/`CLAUDE.md` pointer. + +--- + +## 3. Execution Plan (one PR per phase; each PR must pass the inventory check) + +| Phase | Content | Risk | Verification | +|---|---|---|---| +| **0. Guardrails first** | Add `scripts/check-url-inventory.mjs` + committed `url-inventory.txt` (generated from current `main` build), `ci.yaml`, `pnpm run check` wiring, `.DS_Store` purge + gitignore | none | CI green on unchanged site | +| **1. Config & link fixes** | `onBrokenMarkdownLinks` migration; fix 3 broken links (incl. `skill-install.md` relative links) + 7 broken anchors; add `/docs/use/` redirect + fix footer `to`; flip `onBrokenLinks`/`onBrokenAnchors` to `throw`; `editLocalizedFiles: true`; browserslist update | low | build passes with `throw`; inventory diff shows exactly one intentional addition (`/docs/use/`) | +| **2. Structural renames** | §2.2 renames (zh + en trees, `git mv`), delete `id:`/`sidebar_position:`, explicit `sidebars.js` (§2.3), delete `_category_.json`, update navbar `docId`s | medium | **inventory byte-identical**; manual sidebar screenshot compare zh+en; `git log --follow` spot-check | +| **3. Asset normalization** | §2.5 `.assets/` migration + link rewrites; align en asset folder names to zh | low | inventory identical; build has zero broken markdown links (now `throw`) | +| **4. Title policy** | H1→`title` migration script; resolve the 5 mismatches per §2.4 table (maintainer confirms wording); enable `check-frontmatter.mjs` hard-fail | low | inventory identical; visual sidebar/title review; Algolia re-crawl picks up corrected titles automatically | +| **5. English translation** | Translate 25 files (priority order §2.6); fix `write-translations` gaps; flip `check-i18n-parity.mjs` to hard-fail | low (content-only) | parity check green; `/en/` spot review; inventory identical | +| **6. (Optional, separate approval)** | URL cleanup via redirects only: `/docs/use/use/`→`/docs/use/`, `install_comple`→`install_complete`, etc. **Requires coordinated extension release** for hardcoded URLs; old URLs redirect forever | medium | explicitly out of default scope | + +Sequencing rationale: the guardrail lands **before** any file moves, so every subsequent phase is machine-verified against the constraint rather than eyeballed. + +## 4. Risks & Mitigations + +- **`README.md` → `index.md` slug equivalence**: both are Docusaurus index conventions producing the directory slug; Phase 2's inventory check proves it. If any edge case differs, fall back to keeping `README.md` (also convention-compliant) — the check catches it before merge. +- **Docusaurus number-prefix parser**: after removing prefixes, no stripping is in play at all — one failure mode deleted. +- **Git history**: `git mv` in dedicated rename-only commits keeps `--follow` working; avoid mixing renames with content edits in the same commit. +- **Algolia**: URLs stable ⇒ index remains valid; corrected titles update on next crawl. No action needed. +- **Sidebar visual change**: only `use/vscode` label wording changes (intended fix); policy pages keep labels via `sidebar_label`. Screenshot compare in Phase 4 review. +- **en fallback pages during Phase 5**: untranslated `/en/` pages continue falling back to zh content exactly as today — no regression window. +- **Extension-hardcoded URLs**: never touched (inventory + CONTRIBUTING list them). + +## 5. Acceptance Criteria + +1. `scripts/url-inventory.txt` unchanged from the pre-refactor baseline (except the single documented `/docs/use/` addition), enforced in CI on every PR. +2. Zero `id:`/`sidebar_position:` frontmatter; zero number-prefixed filenames; `grep -rl '^# ' docs | wc -l` = allowlisted count. +3. Zero broken links/anchors with `throw` enabled, both locales. +4. `docs/**` ↔ `i18n/en/.../current/**` file sets identical; all 25 gap files translated. +5. Sidebar label == page H1 == `<title>` (modulo explicit `sidebar_label`) for every doc, both locales. +6. `CONTRIBUTING.md` present; a new doc can be added by following it verbatim (add file → sidebar line → en mirror → `pnpm run check` green). From 8d73ad5da7e884ad81667cc43dd950d0af8d5ea9 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 7 Jul 2026 02:18:06 +0900 Subject: [PATCH 02/10] ci: add URL/i18n/frontmatter guardrail scripts (Phase 0) Adds three checks wired into `pnpm run check`: - check-url-inventory.mjs: diffs the built site's routes against a committed baseline (scripts/url-inventory.txt), generated from the current build. This is the mechanical guarantee that later refactor phases don't change any published URL. - check-i18n-parity.mjs: reports zh-Hans docs missing an English mirror and vice versa (warn-only via scripts/check-config.json until the translation backlog in Phase 5 is cleared). - check-frontmatter.mjs: reports missing titles, leftover id:/ sidebar_position: overrides, number-prefixed filenames, and stray body H1s (warn-only until Phase 4 normalizes titles). Also adds a Gitea Actions CI workflow that runs build + check on PRs, and inserts `pnpm run check` into the deploy workflow so a bad merge can't ship. .DS_Store was already gitignored and untracked, so no cleanup was needed there. --- .gitea/workflows/ci.yaml | 36 +++++++++++++ .gitea/workflows/deploy.yaml | 1 + package.json | 6 ++- scripts/check-config.json | 4 ++ scripts/check-frontmatter.mjs | 90 ++++++++++++++++++++++++++++++++ scripts/check-i18n-parity.mjs | 68 ++++++++++++++++++++++++ scripts/check-url-inventory.mjs | 80 ++++++++++++++++++++++++++++ scripts/url-inventory.txt | 92 +++++++++++++++++++++++++++++++++ 8 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 .gitea/workflows/ci.yaml create mode 100644 scripts/check-config.json create mode 100644 scripts/check-frontmatter.mjs create mode 100644 scripts/check-i18n-parity.mjs create mode 100644 scripts/check-url-inventory.mjs create mode 100644 scripts/url-inventory.txt diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml new file mode 100644 index 0000000..a26d2c2 --- /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 f0ffc17..3f96a94 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/package.json b/package.json index 1aab14a..0e905cc 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,11 @@ "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", diff --git a/scripts/check-config.json b/scripts/check-config.json new file mode 100644 index 0000000..c472c15 --- /dev/null +++ b/scripts/check-config.json @@ -0,0 +1,4 @@ +{ + "i18nParityStrict": false, + "frontmatterStrict": false +} diff --git a/scripts/check-frontmatter.mjs b/scripts/check-frontmatter.mjs new file mode 100644 index 0000000..5c4a82c --- /dev/null +++ b/scripts/check-frontmatter.mjs @@ -0,0 +1,90 @@ +#!/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"; + if (!hideTitle && /^#\s+.+$/m.test(body)) { + 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 0000000..f8114b0 --- /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 0000000..46328d4 --- /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 0000000..7b967c8 --- /dev/null +++ b/scripts/url-inventory.txt @@ -0,0 +1,92 @@ +/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/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/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 From 1848f027111048a848d8225adf2908af6ec9e294 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 7 Jul 2026 02:29:35 +0900 Subject: [PATCH 03/10] fix: broken links/anchors, deprecated config, add /docs/use/ redirect (Phase 1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Migrate onBrokenMarkdownLinks to markdown.hooks.onBrokenMarkdownLinks (deprecated top-level option, removed in Docusaurus v4) and flip onBrokenLinks/onBrokenAnchors to "throw" now that the build is clean. - Fix the 2 broken links and 7 broken anchors the previous "warn" setting let ship: - dev/agent/skill-install.md linked to non-existent ./agent-skill and ./agent-skill-dev paths instead of the actual sibling filenames ./skill.md and ./skill-dev.md. - use/6.vscode.md (zh + en) and the footer "使用指南" link pointed at /docs/use/, which has never resolved (the quick-start doc lives at /docs/use/use/) — pointed them at the real path. - change/README.md's historical changelog entry linked to a non-existent dev/meta.md#console anchor; retargeted to dev/background.md#日志, the section it was actually describing. - dev/README.md, dev/api.md, dev/meta.md referenced heading anchors using the raw Chinese heading text, which doesn't match Docusaurus's generated slugs once backticks/parens/emoji are stripped (e.g. #定时脚本 -> #定时脚本crontab, #storagename-🧪 -> #storagename-, #gm_cookie -> #gm_cookie-). - Add @docusaurus/plugin-client-redirects with a single redirect, /docs/use/ -> /docs/use/use/, as a safety net for old bookmarks/search engines (the broken-link checker doesn't recognize plugin-generated redirect targets, so in-content links were fixed directly instead). - editUrl now sets editLocalizedFiles: true so "Edit this page" on /en/ docs opens the English source instead of the zh one. - Add blog: false to the classic preset: bumping @docusaurus/core to the already-pinned ^3.10.1 (previously resolved to a stale 3.9.2 in the lockfile) caused the default-enabled, content-less blog plugin to start emitting empty /blog/ and /en/blog/ routes that never existed on the site; disabling it restores the original route set. - Ran update-browserslist-db (caniuse-lite was 13-15 months stale). scripts/url-inventory.txt gains exactly 2 routes (/docs/use/index.html, /en/docs/use/index.html) for the new redirect; no existing route changed, verified by `pnpm run check`. --- docs/change/README.md | 2 +- docs/dev/README.md | 2 +- docs/dev/agent/skill-install.md | 4 +- docs/dev/api.md | 6 +- docs/dev/meta.md | 4 +- docs/use/6.vscode.md | 2 +- docusaurus.config.js | 35 +++++++-- .../current/use/6.vscode.md | 2 +- package.json | 1 + pnpm-lock.yaml | 71 +++++++++++++++---- scripts/url-inventory.txt | 2 + 11 files changed, 102 insertions(+), 29 deletions(-) diff --git a/docs/change/README.md b/docs/change/README.md index cb393d5..bf499e1 100644 --- a/docs/change/README.md +++ b/docs/change/README.md @@ -2124,7 +2124,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/dev/README.md b/docs/dev/README.md index 996fb8b..6a15e0e 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -8,7 +8,7 @@ id: dev - 前台脚本 - [后台脚本](./background.md) -- [定时脚本](./background.md#定时脚本) +- [定时脚本](./background.md#定时脚本crontab) 前台脚本为通常意义上的油猴脚本,后台脚本与定时脚本为本脚本猫扩展所特有支持的脚本,详情请看相对应的文档. diff --git a/docs/dev/agent/skill-install.md b/docs/dev/agent/skill-install.md index 7f6129f..1d783f6 100644 --- a/docs/dev/agent/skill-install.md +++ b/docs/dev/agent/skill-install.md @@ -95,5 +95,5 @@ const conv = await CAT.agent.conversation.create({ ## 了解更多 -- [Skill 管理 API](./agent-skill) — 通过脚本编程式管理 Skill -- [Skill 开发指南](./agent-skill-dev) — 创建自己的 Skill +- [Skill 管理 API](./skill.md) — 通过脚本编程式管理 Skill +- [Skill 开发指南](./skill-dev.md) — 创建自己的 Skill diff --git a/docs/dev/api.md b/docs/dev/api.md index d065cef..8b05f1c 100644 --- a/docs/dev/api.md +++ b/docs/dev/api.md @@ -44,7 +44,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 +103,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/meta.md b/docs/dev/meta.md index 7281cbb..f43afe7 100644 --- a/docs/dev/meta.md +++ b/docs/dev/meta.md @@ -84,11 +84,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/use/6.vscode.md b/docs/use/6.vscode.md index 4304b6f..a9175d7 100644 --- a/docs/use/6.vscode.md +++ b/docs/use/6.vscode.md @@ -10,7 +10,7 @@ ScriptCat 提供了 VSCode 扩展,让你可以在 VSCode 中编写用户脚本 你需要安装以下两个工具: -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 bfb7a41..4b76478 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"), }, @@ -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/use/6.vscode.md b/i18n/en/docusaurus-plugin-content-docs/current/use/6.vscode.md index 08885c6..f2a245e 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/6.vscode.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/6.vscode.md @@ -10,7 +10,7 @@ ScriptCat provides a VSCode extension that lets you write user scripts in VSCode 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 0e905cc..183f5ca 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "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 e536bff..3ea2146 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/url-inventory.txt b/scripts/url-inventory.txt index 7b967c8..ce0c6d3 100644 --- a/scripts/url-inventory.txt +++ b/scripts/url-inventory.txt @@ -31,6 +31,7 @@ /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 @@ -73,6 +74,7 @@ /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 From e1f44cb066783dc04aad9a9a46b0154987c29072 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 7 Jul 2026 02:38:28 +0900 Subject: [PATCH 04/10] refactor: file path = doc ID = URL, explicit sidebars (Phase 2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renames every doc so its file path matches its doc id/URL verbatim, then deletes the id:/sidebar_position: frontmatter overrides that existed only to paper over the mismatch: - docs/use/N.foo.md -> docs/use/foo.md (numbered-prefix files); the numeric prefix was already being stripped from the id/URL by Docusaurus, so this is a pure rename with no id override needed. - docs/use/4.from-other/ -> docs/use/from-other/, docs/use/99.policy/ -> docs/use/policy/ (same reasoning for dirs). - docs/dev/agent/{conversation,dom,skill,skill-dev,skill-install, task,model,opfs,mcp,builtin-tools}.md -> agent-*.md, matching the id: overrides they previously needed (dev/agent/agent-conversation etc.) so the override can be deleted instead of the filename staying arbitrary. - docs/dev/README.md -> docs/dev/index.md, docs/change/README.md -> docs/change/index.md, docs/about/README.md -> docs/about/index.md: README-as-index needed an explicit id: override before; index.md is Docusaurus's native landing-page convention, no override needed. - docs/change/beta.md -> docs/change/beta-changelog.md to match its id: beta-changelog override (now deleted). - docs/use/1.README.md -> docs/use/use.md keeps a `slug: /use/use` frontmatter override — Docusaurus auto-collapses a doc whose filename matches its enclosing folder name (here "use/use.md") to the parent path, which would have silently changed the published URL from /docs/use/use/ to /docs/use/; the explicit slug pins it. - Deleted the two _category_.json files; their labels move into sidebars.js as explicit category items. - sidebars.js is now fully explicit for all three sidebars (use, dev, change), replacing autogeneration (which had a real ordering collision between the two files both prefixed "2.") and the descending sidebar_position: 9995..10000 changelog-ordering hack. - Updated the two internal cross-references that pointed at renamed files by relative path (change/index.md <-> beta-changelog.md, dev/agent/agent-skill-install.md -> agent-skill.md/agent-skill-dev.md), and updated the two navbar docId references (dev/dev -> dev/index, change/change -> change/index) to match. Every file was moved in both docs/ and its i18n/en mirror (where a mirror exists) so ids stay aligned across locales. Verified via `pnpm run check`: the URL inventory is still exactly the 94 routes from Phase 1 (zero drift from ~35 file renames), and the build has zero broken links/anchors under the "throw" settings from Phase 1. --- docs/about/{README.md => index.md} | 0 docs/change/{beta.md => beta-changelog.md} | 6 +-- docs/change/{README.md => index.md} | 6 +-- docs/change/v0.16.md | 3 -- docs/change/v0.17.md | 3 -- docs/change/v1.1.md | 3 -- docs/change/v1.2.md | 3 -- docs/change/v1.3.md | 3 -- docs/change/v1.4.md | 3 -- ...uiltin-tools.md => agent-builtin-tools.md} | 4 -- ...{conversation.md => agent-conversation.md} | 4 -- docs/dev/agent/{dom.md => agent-dom.md} | 4 -- docs/dev/agent/{mcp.md => agent-mcp.md} | 4 -- docs/dev/agent/{model.md => agent-model.md} | 4 -- docs/dev/agent/{opfs.md => agent-opfs.md} | 4 -- .../{skill-dev.md => agent-skill-dev.md} | 4 -- ...kill-install.md => agent-skill-install.md} | 8 +--- docs/dev/agent/{skill.md => agent-skill.md} | 4 -- docs/dev/agent/{task.md => agent-task.md} | 4 -- docs/dev/agent/index.md | 4 -- docs/dev/api.md | 3 -- docs/dev/background.md | 3 -- docs/dev/cat-api.md | 3 -- docs/dev/cloudcat.md | 3 -- docs/dev/config.md | 3 -- docs/dev/{README.md => index.md} | 3 -- docs/dev/meta.md | 3 -- docs/dev/subscribe.md | 3 -- docs/use/4.from-other/_category_.json | 3 -- docs/use/99.policy/_category_.json | 3 -- docs/use/{3.QA.md => QA.md} | 0 .../image-20250716221722742.webp | Bin .../image-20250716222132062.webp | Bin .../image-20250716222326368.webp | Bin .../image-20250716222403452.webp | Bin .../image-20250716223536305.webp | Bin .../image-20250716223849488.webp | Bin .../migrate-from-tampermonkey.md | 0 .../migrate-from-violentmonkey.md | 0 docs/use/{5.open-dev.md => open-dev.md} | 0 docs/use/{99.policy => policy}/disclaimer.md | 1 - docs/use/{99.policy => policy}/privacy.md | 1 - .../{99.policy => policy}/privacy_website.md | 1 - ...installation.md => script_installation.md} | 0 docs/use/{2.sync.md => sync.md} | 3 -- docs/use/{1.README.md => use.md} | 2 +- docs/use/{6.vscode.md => vscode.md} | 0 docusaurus.config.js | 4 +- .../change/{beta.md => beta-changelog.md} | 6 +-- .../current/change/{README.md => index.md} | 6 +-- .../current/change/v1.3.md | 3 -- .../current/use/{3.QA.md => QA.md} | 0 .../image-20250716225507707.webp | Bin .../image-20250716225611932.webp | Bin .../image-20250716225719787.webp | Bin .../image-20250716225741428.webp | Bin .../image-20250716225900597.webp | Bin .../image-20250716225935258.webp | Bin .../migrate-from-tampermonkey.md | 0 .../migrate-from-violentmonkey.md | 0 .../use/{5.open-dev.md => open-dev.md} | 0 .../use/{99.policy => policy}/disclaimer.md | 1 - .../use/{99.policy => policy}/privacy.md | 1 - .../{99.policy => policy}/privacy_website.md | 1 - ...installation.md => script_installation.md} | 0 .../current/use/{2.sync.md => sync.md} | 3 -- .../current/use/{1.README.md => use.md} | 2 +- .../current/use/{6.vscode.md => vscode.md} | 0 sidebars.js | 43 ++++++++++++++++-- 69 files changed, 49 insertions(+), 137 deletions(-) rename docs/about/{README.md => index.md} (100%) rename docs/change/{beta.md => beta-changelog.md} (99%) rename docs/change/{README.md => index.md} (99%) rename docs/dev/agent/{builtin-tools.md => agent-builtin-tools.md} (99%) rename docs/dev/agent/{conversation.md => agent-conversation.md} (99%) rename docs/dev/agent/{dom.md => agent-dom.md} (99%) rename docs/dev/agent/{mcp.md => agent-mcp.md} (99%) rename docs/dev/agent/{model.md => agent-model.md} (98%) rename docs/dev/agent/{opfs.md => agent-opfs.md} (99%) rename docs/dev/agent/{skill-dev.md => agent-skill-dev.md} (99%) rename docs/dev/agent/{skill-install.md => agent-skill-install.md} (95%) rename docs/dev/agent/{skill.md => agent-skill.md} (98%) rename docs/dev/agent/{task.md => agent-task.md} (99%) rename docs/dev/{README.md => index.md} (97%) delete mode 100644 docs/use/4.from-other/_category_.json delete mode 100644 docs/use/99.policy/_category_.json rename docs/use/{3.QA.md => QA.md} (100%) rename docs/use/{4.from-other => from-other}/img/migrate-from-tampermonkey/image-20250716221722742.webp (100%) rename docs/use/{4.from-other => from-other}/img/migrate-from-tampermonkey/image-20250716222132062.webp (100%) rename docs/use/{4.from-other => from-other}/img/migrate-from-tampermonkey/image-20250716222326368.webp (100%) rename docs/use/{4.from-other => from-other}/img/migrate-from-tampermonkey/image-20250716222403452.webp (100%) rename docs/use/{4.from-other => from-other}/img/migrate-from-violentmonkey/image-20250716223536305.webp (100%) rename docs/use/{4.from-other => from-other}/img/migrate-from-violentmonkey/image-20250716223849488.webp (100%) rename docs/use/{4.from-other => from-other}/migrate-from-tampermonkey.md (100%) rename docs/use/{4.from-other => from-other}/migrate-from-violentmonkey.md (100%) rename docs/use/{5.open-dev.md => open-dev.md} (100%) rename docs/use/{99.policy => policy}/disclaimer.md (99%) rename docs/use/{99.policy => policy}/privacy.md (99%) rename docs/use/{99.policy => policy}/privacy_website.md (99%) rename docs/use/{2.script_installation.md => script_installation.md} (100%) rename docs/use/{2.sync.md => sync.md} (96%) rename docs/use/{1.README.md => use.md} (99%) rename docs/use/{6.vscode.md => vscode.md} (100%) rename i18n/en/docusaurus-plugin-content-docs/current/change/{beta.md => beta-changelog.md} (99%) rename i18n/en/docusaurus-plugin-content-docs/current/change/{README.md => index.md} (99%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{3.QA.md => QA.md} (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{4.from-other => from-other}/img/migrate-from-tampermonkey/image-20250716225507707.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{4.from-other => from-other}/img/migrate-from-tampermonkey/image-20250716225611932.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{4.from-other => from-other}/img/migrate-from-tampermonkey/image-20250716225719787.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{4.from-other => from-other}/img/migrate-from-tampermonkey/image-20250716225741428.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{4.from-other => from-other}/img/migrate-from-violentmonkey.assets/image-20250716225900597.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{4.from-other => from-other}/img/migrate-from-violentmonkey.assets/image-20250716225935258.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{4.from-other => from-other}/migrate-from-tampermonkey.md (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{4.from-other => from-other}/migrate-from-violentmonkey.md (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{5.open-dev.md => open-dev.md} (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{99.policy => policy}/disclaimer.md (99%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{99.policy => policy}/privacy.md (99%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{99.policy => policy}/privacy_website.md (99%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{2.script_installation.md => script_installation.md} (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{2.sync.md => sync.md} (96%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{1.README.md => use.md} (99%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{6.vscode.md => vscode.md} (100%) 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 6c80e5a..b15ba60 100644 --- a/docs/change/beta.md +++ b/docs/change/beta-changelog.md @@ -1,7 +1,3 @@ ---- -id: beta-changelog -sidebar_position: 1 ---- import GithubStar from '@site/src/components/GithubStar'; import SponsorBlock from '@site/src/components/SponsorBlock/zh.mdx'; @@ -12,7 +8,7 @@ import SponsorBlock from '@site/src/components/SponsorBlock/zh.mdx'; <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 bf499e1..010fd99 100644 --- a/docs/change/README.md +++ b/docs/change/index.md @@ -1,7 +1,3 @@ ---- -id: change -sidebar_position: 1 ---- import GithubStar from '@site/src/components/GithubStar'; import SponsorBlock from '@site/src/components/SponsorBlock/zh.mdx'; @@ -12,7 +8,7 @@ import SponsorBlock from '@site/src/components/SponsorBlock/zh.mdx'; <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)。 diff --git a/docs/change/v0.16.md b/docs/change/v0.16.md index 9ba3ecf..39455b1 100644 --- a/docs/change/v0.16.md +++ b/docs/change/v0.16.md @@ -1,6 +1,3 @@ ---- -sidebar_position: 10000 ---- # v0.16 diff --git a/docs/change/v0.17.md b/docs/change/v0.17.md index 2577c2c..9058c23 100644 --- a/docs/change/v0.17.md +++ b/docs/change/v0.17.md @@ -1,6 +1,3 @@ ---- -sidebar_position: 9999 ---- # v0.17 diff --git a/docs/change/v1.1.md b/docs/change/v1.1.md index 15995c9..e31a04d 100644 --- a/docs/change/v1.1.md +++ b/docs/change/v1.1.md @@ -1,6 +1,3 @@ ---- -sidebar_position: 9998 ---- # v1.1 diff --git a/docs/change/v1.2.md b/docs/change/v1.2.md index 97356c0..7bce340 100644 --- a/docs/change/v1.2.md +++ b/docs/change/v1.2.md @@ -1,6 +1,3 @@ ---- -sidebar_position: 9997 ---- # v1.2 diff --git a/docs/change/v1.3.md b/docs/change/v1.3.md index 7cbd0a7..f669c6c 100644 --- a/docs/change/v1.3.md +++ b/docs/change/v1.3.md @@ -1,6 +1,3 @@ ---- -sidebar_position: 9996 ---- # v1.3 diff --git a/docs/change/v1.4.md b/docs/change/v1.4.md index c5ab598..9859fee 100644 --- a/docs/change/v1.4.md +++ b/docs/change/v1.4.md @@ -1,6 +1,3 @@ ---- -sidebar_position: 9995 ---- # v1.4 — Agent 智能助手 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 9971ac2..8599a83 100644 --- a/docs/dev/agent/builtin-tools.md +++ b/docs/dev/agent/agent-builtin-tools.md @@ -1,7 +1,3 @@ ---- -id: agent-builtin-tools -sidebar_position: 10 ---- # 内置工具参考 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 7888fcb..bf42ba0 100644 --- a/docs/dev/agent/conversation.md +++ b/docs/dev/agent/agent-conversation.md @@ -1,7 +1,3 @@ ---- -id: agent-conversation -sidebar_position: 2 ---- # 对话 API 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 963aeed..59d15ba 100644 --- a/docs/dev/agent/dom.md +++ b/docs/dev/agent/agent-dom.md @@ -1,7 +1,3 @@ ---- -id: agent-dom -sidebar_position: 3 ---- # DOM 操作 API diff --git a/docs/dev/agent/mcp.md b/docs/dev/agent/agent-mcp.md similarity index 99% rename from docs/dev/agent/mcp.md rename to docs/dev/agent/agent-mcp.md index 06f27de..2820bea 100644 --- a/docs/dev/agent/mcp.md +++ b/docs/dev/agent/agent-mcp.md @@ -1,7 +1,3 @@ ---- -id: agent-mcp -sidebar_position: 8 ---- # MCP 管理 API diff --git a/docs/dev/agent/model.md b/docs/dev/agent/agent-model.md similarity index 98% rename from docs/dev/agent/model.md rename to docs/dev/agent/agent-model.md index 9d5dd69..9f095c8 100644 --- a/docs/dev/agent/model.md +++ b/docs/dev/agent/agent-model.md @@ -1,7 +1,3 @@ ---- -id: agent-model -sidebar_position: 6 ---- # 模型查询 API 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 8720511..84479a5 100644 --- a/docs/dev/agent/opfs.md +++ b/docs/dev/agent/agent-opfs.md @@ -1,7 +1,3 @@ ---- -id: agent-opfs -sidebar_position: 7 ---- # OPFS 文件 API 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 5ee0d89..2d9e459 100644 --- a/docs/dev/agent/skill-dev.md +++ b/docs/dev/agent/agent-skill-dev.md @@ -1,7 +1,3 @@ ---- -id: agent-skill-dev -sidebar_position: 9 ---- # 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 1d783f6..ab6fb84 100644 --- a/docs/dev/agent/skill-install.md +++ b/docs/dev/agent/agent-skill-install.md @@ -1,7 +1,3 @@ ---- -id: agent-skill-install -sidebar_position: 3.5 ---- # Skill 安装与使用 @@ -95,5 +91,5 @@ const conv = await CAT.agent.conversation.create({ ## 了解更多 -- [Skill 管理 API](./skill.md) — 通过脚本编程式管理 Skill -- [Skill 开发指南](./skill-dev.md) — 创建自己的 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 52629b3..4c9301b 100644 --- a/docs/dev/agent/skill.md +++ b/docs/dev/agent/agent-skill.md @@ -1,7 +1,3 @@ ---- -id: agent-skill -sidebar_position: 4 ---- # Skill 管理 API diff --git a/docs/dev/agent/task.md b/docs/dev/agent/agent-task.md similarity index 99% rename from docs/dev/agent/task.md rename to docs/dev/agent/agent-task.md index 6659038..dbc07f7 100644 --- a/docs/dev/agent/task.md +++ b/docs/dev/agent/agent-task.md @@ -1,7 +1,3 @@ ---- -id: agent-task -sidebar_position: 5 ---- # 定时任务 API diff --git a/docs/dev/agent/index.md b/docs/dev/agent/index.md index 02b3029..b03f22c 100644 --- a/docs/dev/agent/index.md +++ b/docs/dev/agent/index.md @@ -1,7 +1,3 @@ ---- -id: agent -sidebar_position: 1 ---- # Agent 智能助手 diff --git a/docs/dev/api.md b/docs/dev/api.md index 8b05f1c..b02bd90 100644 --- a/docs/dev/api.md +++ b/docs/dev/api.md @@ -1,6 +1,3 @@ ---- -id: api ---- # API 文档 diff --git a/docs/dev/background.md b/docs/dev/background.md index 2d7296a..ef0b850 100644 --- a/docs/dev/background.md +++ b/docs/dev/background.md @@ -1,6 +1,3 @@ ---- -id: background ---- # 后台脚本 diff --git a/docs/dev/cat-api.md b/docs/dev/cat-api.md index 2e2fbc9..d4c5aa8 100644 --- a/docs/dev/cat-api.md +++ b/docs/dev/cat-api.md @@ -1,6 +1,3 @@ ---- -id: cat-api ---- # CatApi 文档 diff --git a/docs/dev/cloudcat.md b/docs/dev/cloudcat.md index 0d489b9..1b33aac 100644 --- a/docs/dev/cloudcat.md +++ b/docs/dev/cloudcat.md @@ -1,6 +1,3 @@ ---- -id: cloudcat ---- # 云端执行 diff --git a/docs/dev/config.md b/docs/dev/config.md index 57bb660..427bbb2 100644 --- a/docs/dev/config.md +++ b/docs/dev/config.md @@ -1,6 +1,3 @@ ---- -id: config ---- # 用户配置 diff --git a/docs/dev/README.md b/docs/dev/index.md similarity index 97% rename from docs/dev/README.md rename to docs/dev/index.md index 6a15e0e..f5aaa16 100644 --- a/docs/dev/README.md +++ b/docs/dev/index.md @@ -1,6 +1,3 @@ ---- -id: dev ---- # 简介 diff --git a/docs/dev/meta.md b/docs/dev/meta.md index f43afe7..d14e911 100644 --- a/docs/dev/meta.md +++ b/docs/dev/meta.md @@ -1,6 +1,3 @@ ---- -id: meta ---- # 描述文档 diff --git a/docs/dev/subscribe.md b/docs/dev/subscribe.md index 29120ed..fe27d64 100644 --- a/docs/dev/subscribe.md +++ b/docs/dev/subscribe.md @@ -1,6 +1,3 @@ ---- -id: subscribe ---- # 订阅模式 diff --git a/docs/use/4.from-other/_category_.json b/docs/use/4.from-other/_category_.json deleted file mode 100644 index 3fae840..0000000 --- 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 a546350..0000000 --- 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/img/migrate-from-tampermonkey/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/img/migrate-from-tampermonkey/image-20250716221722742.webp diff --git a/docs/use/4.from-other/img/migrate-from-tampermonkey/image-20250716222132062.webp b/docs/use/from-other/img/migrate-from-tampermonkey/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/img/migrate-from-tampermonkey/image-20250716222132062.webp diff --git a/docs/use/4.from-other/img/migrate-from-tampermonkey/image-20250716222326368.webp b/docs/use/from-other/img/migrate-from-tampermonkey/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/img/migrate-from-tampermonkey/image-20250716222326368.webp diff --git a/docs/use/4.from-other/img/migrate-from-tampermonkey/image-20250716222403452.webp b/docs/use/from-other/img/migrate-from-tampermonkey/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/img/migrate-from-tampermonkey/image-20250716222403452.webp diff --git a/docs/use/4.from-other/img/migrate-from-violentmonkey/image-20250716223536305.webp b/docs/use/from-other/img/migrate-from-violentmonkey/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/img/migrate-from-violentmonkey/image-20250716223536305.webp diff --git a/docs/use/4.from-other/img/migrate-from-violentmonkey/image-20250716223849488.webp b/docs/use/from-other/img/migrate-from-violentmonkey/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/img/migrate-from-violentmonkey/image-20250716223849488.webp diff --git a/docs/use/4.from-other/migrate-from-tampermonkey.md b/docs/use/from-other/migrate-from-tampermonkey.md similarity index 100% rename from docs/use/4.from-other/migrate-from-tampermonkey.md rename to docs/use/from-other/migrate-from-tampermonkey.md diff --git a/docs/use/4.from-other/migrate-from-violentmonkey.md b/docs/use/from-other/migrate-from-violentmonkey.md similarity index 100% rename from docs/use/4.from-other/migrate-from-violentmonkey.md rename to docs/use/from-other/migrate-from-violentmonkey.md diff --git a/docs/use/5.open-dev.md b/docs/use/open-dev.md similarity index 100% rename from docs/use/5.open-dev.md rename to docs/use/open-dev.md diff --git a/docs/use/99.policy/disclaimer.md b/docs/use/policy/disclaimer.md similarity index 99% rename from docs/use/99.policy/disclaimer.md rename to docs/use/policy/disclaimer.md index f6e8603..9edfe4d 100644 --- a/docs/use/99.policy/disclaimer.md +++ b/docs/use/policy/disclaimer.md @@ -1,5 +1,4 @@ --- -id: disclaimer title: 免责声明 --- diff --git a/docs/use/99.policy/privacy.md b/docs/use/policy/privacy.md similarity index 99% rename from docs/use/99.policy/privacy.md rename to docs/use/policy/privacy.md index 7475d02..b1d5535 100644 --- a/docs/use/99.policy/privacy.md +++ b/docs/use/policy/privacy.md @@ -1,5 +1,4 @@ --- -id: privacy title: 隐私政策 --- diff --git a/docs/use/99.policy/privacy_website.md b/docs/use/policy/privacy_website.md similarity index 99% rename from docs/use/99.policy/privacy_website.md rename to docs/use/policy/privacy_website.md index cb0ddfb..31d46cb 100644 --- a/docs/use/99.policy/privacy_website.md +++ b/docs/use/policy/privacy_website.md @@ -1,5 +1,4 @@ --- -id: privacy_website title: 脚本站点 隐私政策 --- 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 96% rename from docs/use/2.sync.md rename to docs/use/sync.md index 42566d5..b4e7822 100644 --- a/docs/use/2.sync.md +++ b/docs/use/sync.md @@ -1,6 +1,3 @@ ---- -id: sync ---- # 同步与备份 diff --git a/docs/use/1.README.md b/docs/use/use.md similarity index 99% rename from docs/use/1.README.md rename to docs/use/use.md index adb5d12..4844de9 100644 --- a/docs/use/1.README.md +++ b/docs/use/use.md @@ -1,5 +1,5 @@ --- -id: use +slug: /use/use --- # 快速开始 diff --git a/docs/use/6.vscode.md b/docs/use/vscode.md similarity index 100% rename from docs/use/6.vscode.md rename to docs/use/vscode.md diff --git a/docusaurus.config.js b/docusaurus.config.js index 4b76478..5b92de7 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -124,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: "更新日志", }, 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 043c114..78b43b7 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,7 +1,3 @@ ---- -id: beta-changelog -sidebar_position: 1 ---- import GithubStar from '@site/src/components/GithubStar'; import SponsorBlock from '@site/src/components/SponsorBlock/en.mdx'; @@ -12,7 +8,7 @@ import SponsorBlock from '@site/src/components/SponsorBlock/en.mdx'; <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 e25dd3b..19b1db2 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/change/README.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/change/index.md @@ -1,7 +1,3 @@ ---- -id: change -sidebar_position: 1 ---- import GithubStar from '@site/src/components/GithubStar'; import SponsorBlock from '@site/src/components/SponsorBlock/en.mdx'; @@ -12,7 +8,7 @@ import SponsorBlock from '@site/src/components/SponsorBlock/en.mdx'; <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/v1.3.md b/i18n/en/docusaurus-plugin-content-docs/current/change/v1.3.md index 344a1e4..4853ef7 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,6 +1,3 @@ ---- -sidebar_position: 9996 ---- # v1.3 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/img/migrate-from-tampermonkey/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/img/migrate-from-tampermonkey/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/img/migrate-from-tampermonkey/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/img/migrate-from-tampermonkey/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/img/migrate-from-tampermonkey/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/img/migrate-from-tampermonkey/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/img/migrate-from-tampermonkey/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/img/migrate-from-tampermonkey/image-20250716225741428.webp 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/img/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/img/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/img/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/img/migrate-from-violentmonkey.assets/image-20250716225935258.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 100% 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 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 100% 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 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 100% 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 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 99% 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 6bf6da7..23c3211 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,5 +1,4 @@ --- -id: disclaimer title: Disclaimer --- 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 21a66c8..5d1998e 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 17c499d..d9b18f7 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 96% 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 d3d5956..f810096 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,6 +1,3 @@ ---- -id: sync ---- # Synchronization and Backup 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 99% 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 1b448b3..1bfedec 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,5 +1,5 @@ --- -id: use +slug: /use/use --- # Quick Start 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 100% 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 diff --git a/sidebars.js b/sidebars.js index 3878601..3eaaaa1 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; From 51c4e38d3f11eadf5b2af8f1ffe8efc637d1c2f5 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 7 Jul 2026 02:44:12 +0900 Subject: [PATCH 05/10] refactor: normalize image assets to <doc-name>.assets/ (Phase 3) Migrates every img/*.assets/ nested folder to a plain sibling <doc-name>.assets/ directory next to its .md file, matching the convention already used by dev/background.assets, dev/cloudcat.assets, dev/config.assets, and change/v1.3.assets: - docs/use/img/README.assets/ split by actual consumer: the 5 images used by use/use.md moved to use/use.assets/, the 4 images used by use/open-dev.md merged into use/open-dev.assets/ alongside the 6 images that were already in use/img/5.open-dev.assets/. - docs/use/from-other/img/{migrate-from-tampermonkey, migrate-from-violentmonkey}/ -> sibling migrate-from-tampermonkey.assets/ and migrate-from-violentmonkey.assets/. Two screenshots of the ScriptCat import step are genuinely shared between both migration guides; they stay in migrate-from-tampermonkey.assets/ and migrate-from-violentmonkey.md references them cross-folder rather than duplicating the files. - docs/change/img/{README,v0.16}.assets/ (3 + 1 images, both only ever referenced from v0.16.md) merged into docs/change/v0.16.assets/; img/v0.17.assets/ and img/v1.2.assets/ promoted to plain siblings. - Same treatment for the i18n/en mirror tree (README.assets/ -> use.assets/, 5.open-dev.assets/ -> open-dev.assets/, etc.); the en from-other assets were already correctly split per-doc, just needed the folder rename. - All docs/**/img/ directories are now gone; every remaining image reference is a relative path to a same-directory *.assets/ folder. Verified via `pnpm run check`: URL inventory still exactly the 94 routes from Phase 1/2, and a clean rebuild confirms every image (including the two shared migration-guide screenshots) still resolves in both locales. --- .../iShot_2024-04-23_11.14.37.gif | Bin .../image-20240423111623608.png | Bin .../v0.16.assets/image-20240423113515332.png | Bin .../setting.png | Bin docs/change/v0.16.md | 8 +++--- .../v0.17.assets/image-20250620165421754.png | Bin .../v0.17.assets/image-20250620165529101.png | Bin .../v0.17.assets/image-20250620165640030.png | Bin docs/change/v0.17.md | 6 ++--- .../08c2889f-3029-4d3c-b180-c52d77c8077c.png | Bin .../v1.2.assets/image-20251016225931823.png | Bin .../v1.2.assets/image-20251016230129315.png | Bin .../v1.2.assets/image-20251023103730266.png | Bin .../v1.2.assets/image-20251204174034940.png | Bin docs/change/v1.2.md | 10 ++++---- .../image-20250716221722742.webp | Bin .../image-20250716222132062.webp | Bin .../image-20250716222326368.webp | Bin .../image-20250716222403452.webp | Bin .../from-other/migrate-from-tampermonkey.md | 8 +++--- .../image-20250716223536305.webp | Bin .../image-20250716223849488.webp | Bin .../from-other/migrate-from-violentmonkey.md | 8 +++--- .../chrome-open-dev.webp | Bin .../chrome-open-settings.webp | Bin .../edge mobile 138.png | Bin .../edge mobile.png | Bin .../edge-open-dev.webp | Bin .../edge-open-settings.webp | Bin .../image-20250623140940401.webp | Bin .../image-20250623141002831.webp | Bin .../image-20260130233429385.png | Bin .../image-20260130233818464.png | Bin docs/use/open-dev.md | 24 +++++++++--------- .../chrome-load-unpacked-img.webp | Bin .../chrome-load-unpacked.webp | Bin .../download-zip.webp | Bin .../edge-load-unpacked-img.webp | Bin .../edge-load-unpacked.webp | Bin docs/use/use.md | 10 ++++---- .../image-20250716225507707.webp | Bin .../image-20250716225611932.webp | Bin .../image-20250716225719787.webp | Bin .../image-20250716225741428.webp | Bin .../from-other/migrate-from-tampermonkey.md | 8 +++--- .../image-20250716225900597.webp | Bin .../image-20250716225935258.webp | Bin .../from-other/migrate-from-violentmonkey.md | 8 +++--- .../allow-user-scripts-toggle.webp | Bin .../chrome-developer-mode-toggle.webp | Bin .../chrome-extensions-page.webp | Bin .../edge mobile 138.png | Bin .../edge mobile.png | Bin .../edge-allow-user-scripts.png | Bin .../edge-developer-mode-toggle.webp | Bin .../edge-extensions-details.png | Bin .../edge-extensions-page.webp | Bin .../scriptcat-extension-details.webp | Bin .../current/use/open-dev.md | 24 +++++++++--------- .../chrome-load-unpacked-img.webp | Bin .../chrome-load-unpacked.webp | Bin .../download-zip.webp | Bin .../edge-load-unpacked-img.webp | Bin .../edge-load-unpacked.webp | Bin .../current/use/use.md | 10 ++++---- 65 files changed, 62 insertions(+), 62 deletions(-) rename docs/change/{img/README.assets => v0.16.assets}/iShot_2024-04-23_11.14.37.gif (100%) rename docs/change/{img/README.assets => v0.16.assets}/image-20240423111623608.png (100%) rename docs/change/{img => }/v0.16.assets/image-20240423113515332.png (100%) rename docs/change/{img/README.assets => v0.16.assets}/setting.png (100%) rename docs/change/{img => }/v0.17.assets/image-20250620165421754.png (100%) rename docs/change/{img => }/v0.17.assets/image-20250620165529101.png (100%) rename docs/change/{img => }/v0.17.assets/image-20250620165640030.png (100%) rename docs/change/{img => }/v1.2.assets/08c2889f-3029-4d3c-b180-c52d77c8077c.png (100%) rename docs/change/{img => }/v1.2.assets/image-20251016225931823.png (100%) rename docs/change/{img => }/v1.2.assets/image-20251016230129315.png (100%) rename docs/change/{img => }/v1.2.assets/image-20251023103730266.png (100%) rename docs/change/{img => }/v1.2.assets/image-20251204174034940.png (100%) rename docs/use/from-other/{img/migrate-from-tampermonkey => migrate-from-tampermonkey.assets}/image-20250716221722742.webp (100%) rename docs/use/from-other/{img/migrate-from-tampermonkey => migrate-from-tampermonkey.assets}/image-20250716222132062.webp (100%) rename docs/use/from-other/{img/migrate-from-tampermonkey => migrate-from-tampermonkey.assets}/image-20250716222326368.webp (100%) rename docs/use/from-other/{img/migrate-from-tampermonkey => migrate-from-tampermonkey.assets}/image-20250716222403452.webp (100%) rename docs/use/from-other/{img/migrate-from-violentmonkey => migrate-from-violentmonkey.assets}/image-20250716223536305.webp (100%) rename docs/use/from-other/{img/migrate-from-violentmonkey => migrate-from-violentmonkey.assets}/image-20250716223849488.webp (100%) rename docs/use/{img/README.assets => open-dev.assets}/chrome-open-dev.webp (100%) rename docs/use/{img/README.assets => open-dev.assets}/chrome-open-settings.webp (100%) rename docs/use/{img/5.open-dev.assets => open-dev.assets}/edge mobile 138.png (100%) rename docs/use/{img/5.open-dev.assets => open-dev.assets}/edge mobile.png (100%) rename docs/use/{img/README.assets => open-dev.assets}/edge-open-dev.webp (100%) rename docs/use/{img/README.assets => open-dev.assets}/edge-open-settings.webp (100%) rename docs/use/{img/5.open-dev.assets => open-dev.assets}/image-20250623140940401.webp (100%) rename docs/use/{img/5.open-dev.assets => open-dev.assets}/image-20250623141002831.webp (100%) rename docs/use/{img/5.open-dev.assets => open-dev.assets}/image-20260130233429385.png (100%) rename docs/use/{img/5.open-dev.assets => open-dev.assets}/image-20260130233818464.png (100%) rename docs/use/{img/README.assets => use.assets}/chrome-load-unpacked-img.webp (100%) rename docs/use/{img/README.assets => use.assets}/chrome-load-unpacked.webp (100%) rename docs/use/{img/README.assets => use.assets}/download-zip.webp (100%) rename docs/use/{img/README.assets => use.assets}/edge-load-unpacked-img.webp (100%) rename docs/use/{img/README.assets => use.assets}/edge-load-unpacked.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/from-other/{img/migrate-from-tampermonkey => migrate-from-tampermonkey.assets}/image-20250716225507707.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/from-other/{img/migrate-from-tampermonkey => migrate-from-tampermonkey.assets}/image-20250716225611932.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/from-other/{img/migrate-from-tampermonkey => migrate-from-tampermonkey.assets}/image-20250716225719787.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/from-other/{img/migrate-from-tampermonkey => migrate-from-tampermonkey.assets}/image-20250716225741428.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/from-other/{img => }/migrate-from-violentmonkey.assets/image-20250716225900597.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/from-other/{img => }/migrate-from-violentmonkey.assets/image-20250716225935258.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{img/5.open-dev.assets => open-dev.assets}/allow-user-scripts-toggle.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{img/5.open-dev.assets => open-dev.assets}/chrome-developer-mode-toggle.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{img/5.open-dev.assets => open-dev.assets}/chrome-extensions-page.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{img/5.open-dev.assets => open-dev.assets}/edge mobile 138.png (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{img/5.open-dev.assets => open-dev.assets}/edge mobile.png (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{img/5.open-dev.assets => open-dev.assets}/edge-allow-user-scripts.png (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{img/5.open-dev.assets => open-dev.assets}/edge-developer-mode-toggle.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{img/5.open-dev.assets => open-dev.assets}/edge-extensions-details.png (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{img/5.open-dev.assets => open-dev.assets}/edge-extensions-page.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{img/5.open-dev.assets => open-dev.assets}/scriptcat-extension-details.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{img/README.assets => use.assets}/chrome-load-unpacked-img.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{img/README.assets => use.assets}/chrome-load-unpacked.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{img/README.assets => use.assets}/download-zip.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{img/README.assets => use.assets}/edge-load-unpacked-img.webp (100%) rename i18n/en/docusaurus-plugin-content-docs/current/use/{img/README.assets => use.assets}/edge-load-unpacked.webp (100%) 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 39455b1..b10bd10 100644 --- a/docs/change/v0.16.md +++ b/docs/change/v0.16.md @@ -5,7 +5,7 @@ ## 最后更新添加排序功能 -![image-20240423113515332](img/v0.16.assets/image-20240423113515332.png) +![image-20240423113515332](v0.16.assets/image-20240423113515332.png) ## v0.16.2 @@ -13,13 +13,13 @@ 默认配置为 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 9058c23..a114f2e 100644 --- a/docs/change/v0.17.md +++ b/docs/change/v0.17.md @@ -15,16 +15,16 @@ ### 弹出页面增加快速检查脚本更新 -![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/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 7bce340..5351475 100644 --- a/docs/change/v1.2.md +++ b/docs/change/v1.2.md @@ -7,31 +7,31 @@ 增加了侧边栏可以进行高级筛选,增加了标签功能,在脚本->设置中可以对标签进行修改调整 -![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/use/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/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/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/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/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/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/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/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/from-other/migrate-from-tampermonkey.md b/docs/use/from-other/migrate-from-tampermonkey.md index 10ec553..0eda6df 100644 --- a/docs/use/from-other/migrate-from-tampermonkey.md +++ b/docs/use/from-other/migrate-from-tampermonkey.md @@ -6,20 +6,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/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/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/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/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/from-other/migrate-from-violentmonkey.md b/docs/use/from-other/migrate-from-violentmonkey.md index 6dbafad..ce065d0 100644 --- a/docs/use/from-other/migrate-from-violentmonkey.md +++ b/docs/use/from-other/migrate-from-violentmonkey.md @@ -6,20 +6,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/open-dev.md b/docs/use/open-dev.md index 08c9e3d..c06bbcb 100644 --- a/docs/use/open-dev.md +++ b/docs/use/open-dev.md @@ -47,32 +47,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 +86,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 +98,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 +111,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 +125,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/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/use.md b/docs/use/use.md index 4844de9..93e59dd 100644 --- a/docs/use/use.md +++ b/docs/use/use.md @@ -24,17 +24,17 @@ slug: /use/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/i18n/en/docusaurus-plugin-content-docs/current/use/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/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/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/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/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/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/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/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/from-other/migrate-from-tampermonkey.md b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-tampermonkey.md index 06ba484..693b081 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-tampermonkey.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-tampermonkey.md @@ -6,20 +6,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/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/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/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/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/from-other/migrate-from-violentmonkey.md b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-violentmonkey.md index 800e4ec..332d151 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-violentmonkey.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-violentmonkey.md @@ -6,20 +6,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/open-dev.md b/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.md index 032cfbb..8979bb8 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.md @@ -47,32 +47,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 +86,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 +98,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 +111,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 +125,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/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/use.md b/i18n/en/docusaurus-plugin-content-docs/current/use/use.md index 1bfedec..92b8ed3 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/use.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/use.md @@ -24,17 +24,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. From 5996642976e05f7a742aa5afd231273ae5c6734a Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 7 Jul 2026 02:49:13 +0900 Subject: [PATCH 06/10] refactor: title = sidebar label = H1, enforce frontmatter lint (Phase 4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moves every doc's body H1 into frontmatter `title` and removes the H1 line, so Docusaurus renders the page heading from `title` alone — making a sidebar/title/H1 mismatch impossible by construction instead of by convention: - 42 docs (zh + en) had no frontmatter title at all; a mechanical pass lifted their existing H1 text into `title` and deleted the H1 line. - 6 docs had a title that didn't match their H1 (the actual bugs this refactor targets, including the reported "VSCode 扩展开发脚本" vs "使用 VSCode 开发脚本" mismatch): - use/vscode.md (zh + en): title replaced with the H1 text so the sidebar now shows what the page actually says. - use/policy/{disclaimer,privacy,privacy_website}.md (zh) and policy/disclaimer.md (en): title replaced with the fuller H1 text, with the previous short title preserved as `sidebar_label` so the sidebar entry stays uncluttered while the page title is accurate. - use/policy/privacy.md and privacy_website.md (en) already had no body H1, so were left untouched. - use/install_comple.md keeps its `hide_title: true` exemption (its decorative "🎉 欢迎使用脚本猫" H1 is intentional). Fixed a false positive in check-frontmatter.mjs: it was flagging example "# Heading" lines inside fenced ```markdown code samples (dev/agent/agent-skill-dev.md's SKILL.cat.md examples) as real H1s. The check now strips fenced code blocks before scanning. With zero real violations left, scripts/check-config.json flips frontmatterStrict to true, so this class of mismatch fails CI instead of just warning. Verified via `pnpm run check`: URL inventory still the same 94 routes, build is clean, and the frontmatter check now passes in strict mode. --- docs/change/beta-changelog.md | 4 +++- docs/change/index.md | 4 +++- docs/change/v0.16.md | 5 +++-- docs/change/v0.17.md | 5 +++-- docs/change/v1.1.md | 5 +++-- docs/change/v1.2.md | 5 +++-- docs/change/v1.3.md | 5 +++-- docs/change/v1.4.md | 5 +++-- docs/dev/agent/agent-builtin-tools.md | 5 +++-- docs/dev/agent/agent-conversation.md | 5 +++-- docs/dev/agent/agent-dom.md | 5 +++-- docs/dev/agent/agent-mcp.md | 5 +++-- docs/dev/agent/agent-model.md | 5 +++-- docs/dev/agent/agent-opfs.md | 5 +++-- docs/dev/agent/agent-skill-dev.md | 5 +++-- docs/dev/agent/agent-skill-install.md | 5 +++-- docs/dev/agent/agent-skill.md | 5 +++-- docs/dev/agent/agent-task.md | 5 +++-- docs/dev/agent/index.md | 5 +++-- docs/dev/api.md | 5 +++-- docs/dev/background.md | 5 +++-- docs/dev/cat-api.md | 5 +++-- docs/dev/cloudcat.md | 6 +++--- docs/dev/config.md | 5 +++-- docs/dev/index.md | 5 +++-- docs/dev/meta.md | 5 +++-- docs/dev/subscribe.md | 6 +++--- docs/script_installation.md | 4 +++- docs/use/from-other/migrate-from-tampermonkey.md | 4 +++- docs/use/from-other/migrate-from-violentmonkey.md | 4 +++- docs/use/open-dev.md | 1 - docs/use/policy/disclaimer.md | 5 ++--- docs/use/policy/privacy.md | 5 ++--- docs/use/policy/privacy_website.md | 5 ++--- docs/use/sync.md | 5 +++-- docs/use/use.md | 3 +-- docs/use/vscode.md | 4 +--- .../current/change/beta-changelog.md | 4 +++- .../docusaurus-plugin-content-docs/current/change/index.md | 4 +++- .../docusaurus-plugin-content-docs/current/change/v1.3.md | 5 +++-- .../current/script_installation.md | 4 +++- .../current/use/from-other/migrate-from-tampermonkey.md | 4 +++- .../current/use/from-other/migrate-from-violentmonkey.md | 4 +++- .../docusaurus-plugin-content-docs/current/use/open-dev.md | 1 - .../current/use/policy/disclaimer.md | 5 ++--- i18n/en/docusaurus-plugin-content-docs/current/use/sync.md | 5 +++-- i18n/en/docusaurus-plugin-content-docs/current/use/use.md | 3 +-- .../en/docusaurus-plugin-content-docs/current/use/vscode.md | 4 +--- scripts/check-config.json | 2 +- scripts/check-frontmatter.mjs | 5 ++++- 50 files changed, 131 insertions(+), 94 deletions(-) diff --git a/docs/change/beta-changelog.md b/docs/change/beta-changelog.md index b15ba60..8b5b450 100644 --- a/docs/change/beta-changelog.md +++ b/docs/change/beta-changelog.md @@ -1,8 +1,10 @@ +--- +title: Beta 更新日志 +--- import GithubStar from '@site/src/components/GithubStar'; import SponsorBlock from '@site/src/components/SponsorBlock/zh.mdx'; -# Beta 更新日志 <GithubStar variant="bar" scene="changelog" /> diff --git a/docs/change/index.md b/docs/change/index.md index 010fd99..bd7cf7e 100644 --- a/docs/change/index.md +++ b/docs/change/index.md @@ -1,8 +1,10 @@ +--- +title: 更新日志 +--- import GithubStar from '@site/src/components/GithubStar'; import SponsorBlock from '@site/src/components/SponsorBlock/zh.mdx'; -# 更新日志 <GithubStar variant="bar" scene="changelog" /> diff --git a/docs/change/v0.16.md b/docs/change/v0.16.md index b10bd10..5816011 100644 --- a/docs/change/v0.16.md +++ b/docs/change/v0.16.md @@ -1,5 +1,6 @@ - -# v0.16 +--- +title: v0.16 +--- ## v0.16.1 diff --git a/docs/change/v0.17.md b/docs/change/v0.17.md index a114f2e..b03e2b6 100644 --- a/docs/change/v0.17.md +++ b/docs/change/v0.17.md @@ -1,5 +1,6 @@ - -# v0.17 +--- +title: v0.17 +--- 从 v0.17.0 开始,脚本猫升级为 manifest v3,并且切换储存引擎`indexedDB`为`chrome.storage.local`,储存引擎切换会自动打开本页面并重启扩展,如果发现数据出现问题,请前往[Github](https://github.com/scriptscat/scriptcat/issues)给我们反馈。 diff --git a/docs/change/v1.1.md b/docs/change/v1.1.md index e31a04d..4d9fb84 100644 --- a/docs/change/v1.1.md +++ b/docs/change/v1.1.md @@ -1,5 +1,6 @@ - -# v1.1 +--- +title: v1.1 +--- ## 网盘平台 diff --git a/docs/change/v1.2.md b/docs/change/v1.2.md index 5351475..9ced4b4 100644 --- a/docs/change/v1.2.md +++ b/docs/change/v1.2.md @@ -1,5 +1,6 @@ - -# v1.2 +--- +title: v1.2 +--- 修复版本更新不会再主动打开更新日志页面 diff --git a/docs/change/v1.3.md b/docs/change/v1.3.md index f669c6c..637adfe 100644 --- a/docs/change/v1.3.md +++ b/docs/change/v1.3.md @@ -1,5 +1,6 @@ - -# v1.3 +--- +title: 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 9859fee..4cd87d9 100644 --- a/docs/change/v1.4.md +++ b/docs/change/v1.4.md @@ -1,5 +1,6 @@ - -# v1.4 — Agent 智能助手 +--- +title: v1.4 — Agent 智能助手 +--- :::caution 测试阶段 v1.4 目前仍处于测试阶段,以下功能和 API 可能会在正式发布前进行调整。欢迎试用并反馈问题。 diff --git a/docs/dev/agent/agent-builtin-tools.md b/docs/dev/agent/agent-builtin-tools.md index 8599a83..528e983 100644 --- a/docs/dev/agent/agent-builtin-tools.md +++ b/docs/dev/agent/agent-builtin-tools.md @@ -1,5 +1,6 @@ - -# 内置工具参考 +--- +title: 内置工具参考 +--- Agent 内置了一系列工具供 AI 在对话中自动调用。这些工具在持久化对话中默认可用,脚本开发者通常不需要直接调用它们——AI 会根据用户意图自动选择合适的工具。 diff --git a/docs/dev/agent/agent-conversation.md b/docs/dev/agent/agent-conversation.md index bf42ba0..d26de51 100644 --- a/docs/dev/agent/agent-conversation.md +++ b/docs/dev/agent/agent-conversation.md @@ -1,5 +1,6 @@ - -# 对话 API +--- +title: 对话 API +--- `@grant CAT.agent.conversation` diff --git a/docs/dev/agent/agent-dom.md b/docs/dev/agent/agent-dom.md index 59d15ba..049b535 100644 --- a/docs/dev/agent/agent-dom.md +++ b/docs/dev/agent/agent-dom.md @@ -1,5 +1,6 @@ - -# DOM 操作 API +--- +title: DOM 操作 API +--- `@grant CAT.agent.dom` diff --git a/docs/dev/agent/agent-mcp.md b/docs/dev/agent/agent-mcp.md index 2820bea..5f95d33 100644 --- a/docs/dev/agent/agent-mcp.md +++ b/docs/dev/agent/agent-mcp.md @@ -1,5 +1,6 @@ - -# MCP 管理 API +--- +title: MCP 管理 API +--- `@grant CAT.agent.mcp` diff --git a/docs/dev/agent/agent-model.md b/docs/dev/agent/agent-model.md index 9f095c8..fcfb8bc 100644 --- a/docs/dev/agent/agent-model.md +++ b/docs/dev/agent/agent-model.md @@ -1,5 +1,6 @@ - -# 模型查询 API +--- +title: 模型查询 API +--- `@grant CAT.agent.model` diff --git a/docs/dev/agent/agent-opfs.md b/docs/dev/agent/agent-opfs.md index 84479a5..cd396c8 100644 --- a/docs/dev/agent/agent-opfs.md +++ b/docs/dev/agent/agent-opfs.md @@ -1,5 +1,6 @@ - -# OPFS 文件 API +--- +title: OPFS 文件 API +--- `@grant CAT.agent.opfs` diff --git a/docs/dev/agent/agent-skill-dev.md b/docs/dev/agent/agent-skill-dev.md index 2d9e459..1351f0b 100644 --- a/docs/dev/agent/agent-skill-dev.md +++ b/docs/dev/agent/agent-skill-dev.md @@ -1,5 +1,6 @@ - -# Skill 开发指南 +--- +title: Skill 开发指南 +--- Skill 是 Agent 系统的扩展包,由**提示词 + 工具脚本 + 参考资料**组合而成。通过 Skill,可以为 AI 注入专业领域知识和自定义工具能力。 diff --git a/docs/dev/agent/agent-skill-install.md b/docs/dev/agent/agent-skill-install.md index ab6fb84..39cdc56 100644 --- a/docs/dev/agent/agent-skill-install.md +++ b/docs/dev/agent/agent-skill-install.md @@ -1,5 +1,6 @@ - -# Skill 安装与使用 +--- +title: Skill 安装与使用 +--- Skill 是 Agent 的扩展能力包,为 AI 注入专业领域知识和自定义工具。本页介绍如何安装、配置和管理 Skill。 diff --git a/docs/dev/agent/agent-skill.md b/docs/dev/agent/agent-skill.md index 4c9301b..02fd6d1 100644 --- a/docs/dev/agent/agent-skill.md +++ b/docs/dev/agent/agent-skill.md @@ -1,5 +1,6 @@ - -# Skill 管理 API +--- +title: Skill 管理 API +--- `@grant CAT.agent.skills` diff --git a/docs/dev/agent/agent-task.md b/docs/dev/agent/agent-task.md index dbc07f7..a81fda9 100644 --- a/docs/dev/agent/agent-task.md +++ b/docs/dev/agent/agent-task.md @@ -1,5 +1,6 @@ - -# 定时任务 API +--- +title: 定时任务 API +--- `@grant CAT.agent.task` diff --git a/docs/dev/agent/index.md b/docs/dev/agent/index.md index b03f22c..e4cc18b 100644 --- a/docs/dev/agent/index.md +++ b/docs/dev/agent/index.md @@ -1,5 +1,6 @@ - -# Agent 智能助手 +--- +title: Agent 智能助手 +--- :::caution 测试阶段 Agent 功能目前仍处于测试阶段,以下 API 和行为可能会在正式发布前进行调整。 diff --git a/docs/dev/api.md b/docs/dev/api.md index b02bd90..fa33e1c 100644 --- a/docs/dev/api.md +++ b/docs/dev/api.md @@ -1,5 +1,6 @@ - -# API 文档 +--- +title: API 文档 +--- ## 说明 diff --git a/docs/dev/background.md b/docs/dev/background.md index ef0b850..0e8984b 100644 --- a/docs/dev/background.md +++ b/docs/dev/background.md @@ -1,5 +1,6 @@ - -# 后台脚本 +--- +title: 后台脚本 +--- 后台脚本适用于持续运行类型的脚本。后台脚本是脚本猫特有的脚本,后台脚本运行在沙盒中,无法操作 DOM 对象。可使用与油猴一致的 GM API 进行开发,对于兼容性会在文档中标出。 diff --git a/docs/dev/cat-api.md b/docs/dev/cat-api.md index d4c5aa8..a5d62ec 100644 --- a/docs/dev/cat-api.md +++ b/docs/dev/cat-api.md @@ -1,5 +1,6 @@ - -# CatApi 文档 +--- +title: CatApi 文档 +--- ## 说明 diff --git a/docs/dev/cloudcat.md b/docs/dev/cloudcat.md index 1b33aac..74f0965 100644 --- a/docs/dev/cloudcat.md +++ b/docs/dev/cloudcat.md @@ -1,6 +1,6 @@ - - -# 云端执行 +--- +title: 云端执行 +--- > 提供了多种云端的运行方式,详情请看[运行环境](#运行环境)。另外[CloudCat](https://github.com/scriptscat/cloudcat)是用于云端执行后台脚本的服务,是一个FAAS平台,还在开发中。 diff --git a/docs/dev/config.md b/docs/dev/config.md index 427bbb2..3b5250c 100644 --- a/docs/dev/config.md +++ b/docs/dev/config.md @@ -1,5 +1,6 @@ - -# 用户配置 +--- +title: 用户配置 +--- `==UserConfig==` 中的内容,应该在`==UserScript==` 后方,表示脚本的一些用户配置.配置信息的描述使用[yaml](https://yaml.org/)格式来进行编写: diff --git a/docs/dev/index.md b/docs/dev/index.md index f5aaa16..183b3f6 100644 --- a/docs/dev/index.md +++ b/docs/dev/index.md @@ -1,5 +1,6 @@ - -# 简介 +--- +title: 简介 +--- 本扩展支持三种类型的脚本,分别为: diff --git a/docs/dev/meta.md b/docs/dev/meta.md index d14e911..3b4ca38 100644 --- a/docs/dev/meta.md +++ b/docs/dev/meta.md @@ -1,5 +1,6 @@ - -# 描述文档 +--- +title: 描述文档 +--- `==UserScript==` 中的内容,用于描述脚本所需要的权限和脚本的信息作用等,在脚本的最开始的位置. diff --git a/docs/dev/subscribe.md b/docs/dev/subscribe.md index fe27d64..540ba23 100644 --- a/docs/dev/subscribe.md +++ b/docs/dev/subscribe.md @@ -1,6 +1,6 @@ - - -# 订阅模式 +--- +title: 订阅模式 +--- 文件开头必须使用`UserSubscribe`而不是`UserScript`,安装时的链接推荐使用`user.sub.js`后缀,必须使用`https`链接。 diff --git a/docs/script_installation.md b/docs/script_installation.md index 7b47c75..e0d920b 100644 --- a/docs/script_installation.md +++ b/docs/script_installation.md @@ -1,4 +1,6 @@ -# 脚本安装 +--- +title: 脚本安装 +--- 此页面用作在 `脚本猫` 中安装新用户脚本的中间步骤。 diff --git a/docs/use/from-other/migrate-from-tampermonkey.md b/docs/use/from-other/migrate-from-tampermonkey.md index 0eda6df..e159f1a 100644 --- a/docs/use/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,以下是一些步骤和提示,帮助你顺利完成迁移。 diff --git a/docs/use/from-other/migrate-from-violentmonkey.md b/docs/use/from-other/migrate-from-violentmonkey.md index ce065d0..e71da73 100644 --- a/docs/use/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,以下是一些步骤和提示,帮助你顺利完成迁移。 diff --git a/docs/use/open-dev.md b/docs/use/open-dev.md index c06bbcb..574134e 100644 --- a/docs/use/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" /> diff --git a/docs/use/policy/disclaimer.md b/docs/use/policy/disclaimer.md index 9edfe4d..bb31fc6 100644 --- a/docs/use/policy/disclaimer.md +++ b/docs/use/policy/disclaimer.md @@ -1,9 +1,8 @@ --- -title: 免责声明 +title: ScriptCat 免责协议 +sidebar_label: 免责声明 --- -# ScriptCat 免责协议 - ScriptCat 相关产品和服务(包括但不限于浏览器扩展、脚本站点、API服务等,以下统称"服务")由 ScriptCat 团队(以下简称"我们"或"开发者")开发和提供。在您开始使用我们的服务之前,请仔细阅读以下免责协议。用户访问、下载、安装、使用我们的任何产品或服务的⾏为,都将被视作是对本声明全部内容的⽆异议的认可。 一、我们的服务及其所有内容和功能均按"现状"和"可用"基础提供,无任何明示或暗示的保证。我们不保证服务的性能、功能或可用性,也不保证服务将无错误运行或任何错误将被纠正。 diff --git a/docs/use/policy/privacy.md b/docs/use/policy/privacy.md index b1d5535..a6cb66c 100644 --- a/docs/use/policy/privacy.md +++ b/docs/use/policy/privacy.md @@ -1,9 +1,8 @@ --- -title: 隐私政策 +title: ScriptCat 隐私政策 +sidebar_label: 隐私政策 --- -# ScriptCat 隐私政策 - 欢迎您使用 ScriptCat 浏览器扩展!ScriptCat(以下简称"我们的产品")是由 scriptcat.org(以下简称"我们")开发并运营的浏览器扩展。 **我们深知隐私保护的重要性,因此在设计之初就坚持隐私优先的原则。** diff --git a/docs/use/policy/privacy_website.md b/docs/use/policy/privacy_website.md index 31d46cb..a010910 100644 --- a/docs/use/policy/privacy_website.md +++ b/docs/use/policy/privacy_website.md @@ -1,9 +1,8 @@ --- -title: 脚本站点 隐私政策 +title: ScriptCat 脚本站点 隐私政策 +sidebar_label: 脚本站点 隐私政策 --- -# ScriptCat 脚本站点 隐私政策 - 欢迎您访问我们的产品。 ScriptCat (包括 App 及网站等产品提供的服务,以下简称“产品和服务”)是由 scriptcat.org (以下简称“我们”)开发并运营的。 确保用户的数据安全和隐私保护是我们的首要任务, 本隐私政策载明了您访问和使用我们的产品和服务时所收集的数据及其处理方式。 请您在继续使用我们的产品前务必认真仔细阅读并确认充分理解本隐私政策全部规则和要点, 一旦您选择使用,即视为您同意本隐私政策的全部内容,同意我们按其收集和使用您的相关信息。 如您在在阅读过程中,对本政策有任何疑问,可联系我们的客服咨询, 请通过 yz@ggnb.top 或产品中的反馈方式与我们取得联系。 如您不同意相关协议或其中的任何条款的,您应停止使用我们的产品和服务。 diff --git a/docs/use/sync.md b/docs/use/sync.md index b4e7822..cbc04b1 100644 --- a/docs/use/sync.md +++ b/docs/use/sync.md @@ -1,5 +1,6 @@ - -# 同步与备份 +--- +title: 同步与备份 +--- 支持以下云储存: diff --git a/docs/use/use.md b/docs/use/use.md index 93e59dd..93f0021 100644 --- a/docs/use/use.md +++ b/docs/use/use.md @@ -1,9 +1,8 @@ --- slug: /use/use +title: 快速开始 --- -# 快速开始 - 脚本猫是一个可以执行用户脚本的浏览器扩展,兼容油猴脚本,并提供更多功能。如果您发现 BUG 或者建议可以前往[GitHub Repo](https://github.com/scriptscat/scriptcat)进行反馈。 ## 安装扩展 diff --git a/docs/use/vscode.md b/docs/use/vscode.md index a9175d7..af159ff 100644 --- a/docs/use/vscode.md +++ b/docs/use/vscode.md @@ -1,9 +1,7 @@ --- -title: VSCode 扩展开发脚本 +title: 使用 VSCode 开发脚本 --- -# 使用 VSCode 开发脚本 - ScriptCat 提供了 VSCode 扩展,让你可以在 VSCode 中编写用户脚本,保存后自动同步到浏览器中的 ScriptCat,无需手动复制粘贴,大幅提升开发效率。 ## 安装准备 diff --git a/i18n/en/docusaurus-plugin-content-docs/current/change/beta-changelog.md b/i18n/en/docusaurus-plugin-content-docs/current/change/beta-changelog.md index 78b43b7..3d18361 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/change/beta-changelog.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/change/beta-changelog.md @@ -1,8 +1,10 @@ +--- +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" /> diff --git a/i18n/en/docusaurus-plugin-content-docs/current/change/index.md b/i18n/en/docusaurus-plugin-content-docs/current/change/index.md index 19b1db2..ce3ef83 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/change/index.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/change/index.md @@ -1,8 +1,10 @@ +--- +title: Changelog +--- import GithubStar from '@site/src/components/GithubStar'; import SponsorBlock from '@site/src/components/SponsorBlock/en.mdx'; -# Changelog <GithubStar variant="bar" scene="changelog" /> 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 4853ef7..50d53ac 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,5 +1,6 @@ - -# v1.3 +--- +title: v1.3 +--- ## New Script Installation Flow [#842](https://github.com/scriptscat/scriptcat/issues/842) 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 00da617..3c21209 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/from-other/migrate-from-tampermonkey.md b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-tampermonkey.md index 693b081..54aaabc 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/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. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-violentmonkey.md b/i18n/en/docusaurus-plugin-content-docs/current/use/from-other/migrate-from-violentmonkey.md index 332d151..4140346 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/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. diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.md b/i18n/en/docusaurus-plugin-content-docs/current/use/open-dev.md index 8979bb8..ad93b05 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/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" /> diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/policy/disclaimer.md b/i18n/en/docusaurus-plugin-content-docs/current/use/policy/disclaimer.md index 23c3211..617118a 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/policy/disclaimer.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/policy/disclaimer.md @@ -1,9 +1,8 @@ --- -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/sync.md b/i18n/en/docusaurus-plugin-content-docs/current/use/sync.md index f810096..35d8287 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/sync.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/sync.md @@ -1,5 +1,6 @@ - -# Synchronization and Backup +--- +title: Synchronization and Backup +--- Supports the following cloud storage: diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/use.md b/i18n/en/docusaurus-plugin-content-docs/current/use/use.md index 92b8ed3..403e1f2 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/use.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/use.md @@ -1,9 +1,8 @@ --- 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 diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use/vscode.md b/i18n/en/docusaurus-plugin-content-docs/current/use/vscode.md index f2a245e..ffb3271 100644 --- a/i18n/en/docusaurus-plugin-content-docs/current/use/vscode.md +++ b/i18n/en/docusaurus-plugin-content-docs/current/use/vscode.md @@ -1,9 +1,7 @@ --- -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 diff --git a/scripts/check-config.json b/scripts/check-config.json index c472c15..4201b1b 100644 --- a/scripts/check-config.json +++ b/scripts/check-config.json @@ -1,4 +1,4 @@ { "i18nParityStrict": false, - "frontmatterStrict": false + "frontmatterStrict": true } diff --git a/scripts/check-frontmatter.mjs b/scripts/check-frontmatter.mjs index 5c4a82c..4ced960 100644 --- a/scripts/check-frontmatter.mjs +++ b/scripts/check-frontmatter.mjs @@ -59,7 +59,10 @@ function checkFile(file) { if (NUMBER_PREFIX.test(basename(file))) issues.push("number-prefixed filename"); const hideTitle = fm.hide_title === "true"; - if (!hideTitle && /^#\s+.+$/m.test(body)) { + // 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)"); } From f5f928ef19019b20377b5a6b92e2e1ac307716cb Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 7 Jul 2026 03:01:27 +0900 Subject: [PATCH 07/10] docs(i18n): complete English translation, flip i18n parity to strict (Phase 5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translates the 25 zh-Hans docs that had no English mirror: - about/index.md - change/{v0.16,v0.17,v1.1,v1.2,v1.4}.md - dev/{index,api,background,cat-api,cloudcat,config,meta,subscribe}.md - dev/agent/{index,agent-conversation,agent-dom,agent-mcp,agent-model, agent-opfs,agent-skill,agent-skill-dev,agent-skill-install, agent-task,agent-builtin-tools}.md Cross-reference anchors were translated to match the actual heading slugs Docusaurus generates for the English headings (e.g. background.md's "## Scheduled Script (`@crontab`)" produces #scheduled-script-crontab, not the zh slug) — verified by rebuilding with onBrokenAnchors: throw. Screenshots referenced by the newly translated change/v0.16.md, v0.17.md, v1.2.md, and dev/background.md, cloudcat.md, config.md are genuinely language-neutral UI screenshots; rather than duplicating the binary files into the en tree, these six docs reference the existing zh screenshots via @site/docs/... absolute paths. scripts/check-config.json flips i18nParityStrict to true now that the translation backlog is cleared, so a doc added to one locale without its mirror will fail CI going forward. Verified via `pnpm run check`: URL inventory still the same 94 routes, i18n parity passes (41/41 docs translated), frontmatter check passes, and the build is clean with zero broken links/anchors/images in both locales. --- .../current/about/index.md | 20 + .../current/change/v0.16.md | 36 + .../current/change/v0.17.md | 31 + .../current/change/v1.1.md | 11 + .../current/change/v1.2.md | 41 ++ .../current/change/v1.4.md | 50 ++ .../current/dev/agent/agent-builtin-tools.md | 275 ++++++++ .../current/dev/agent/agent-conversation.md | 285 ++++++++ .../current/dev/agent/agent-dom.md | 336 ++++++++++ .../current/dev/agent/agent-mcp.md | 169 +++++ .../current/dev/agent/agent-model.md | 91 +++ .../current/dev/agent/agent-opfs.md | 204 ++++++ .../current/dev/agent/agent-skill-dev.md | 420 ++++++++++++ .../current/dev/agent/agent-skill-install.md | 96 +++ .../current/dev/agent/agent-skill.md | 122 ++++ .../current/dev/agent/agent-task.md | 197 ++++++ .../current/dev/agent/index.md | 104 +++ .../current/dev/api.md | 634 ++++++++++++++++++ .../current/dev/background.md | 343 ++++++++++ .../current/dev/cat-api.md | 135 ++++ .../current/dev/cloudcat.md | 91 +++ .../current/dev/config.md | 69 ++ .../current/dev/index.md | 15 + .../current/dev/meta.md | 212 ++++++ .../current/dev/subscribe.md | 56 ++ scripts/check-config.json | 2 +- 26 files changed, 4044 insertions(+), 1 deletion(-) create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/about/index.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/change/v0.16.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/change/v0.17.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/change/v1.1.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/change/v1.2.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/change/v1.4.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-builtin-tools.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-conversation.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-dom.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-mcp.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-model.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-opfs.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-skill-dev.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-skill-install.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-skill.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/agent/agent-task.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/agent/index.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/api.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/background.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/cat-api.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/cloudcat.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/config.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/index.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/meta.md create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/dev/subscribe.md 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 0000000..fe8a917 --- /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/v0.16.md b/i18n/en/docusaurus-plugin-content-docs/current/change/v0.16.md new file mode 100644 index 0000000..6d5b2ec --- /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 0000000..268cc6b --- /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 0000000..93847d5 --- /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 0000000..a396700 --- /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.4.md b/i18n/en/docusaurus-plugin-content-docs/current/change/v1.4.md new file mode 100644 index 0000000..a9f44bf --- /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 0000000..2a2abd2 --- /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 0000000..3630098 --- /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 0000000..311a762 --- /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 0000000..5da784a --- /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 0000000..087261c --- /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 0000000..7fcbc58 --- /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 0000000..8a9d482 --- /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 0000000..abdc545 --- /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 0000000..b3fded1 --- /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 0000000..4a580dd --- /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 0000000..33cf780 --- /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 0000000..837881b --- /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 0000000..29f4570 --- /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 0000000..6b6e761 --- /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 0000000..932327b --- /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 0000000..79affd9 --- /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 0000000..84daac1 --- /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 0000000..006cfe0 --- /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 0000000..2530021 --- /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/scripts/check-config.json b/scripts/check-config.json index 4201b1b..763a387 100644 --- a/scripts/check-config.json +++ b/scripts/check-config.json @@ -1,4 +1,4 @@ { - "i18nParityStrict": false, + "i18nParityStrict": true, "frontmatterStrict": true } From 6ba1ad6ba648e40cbaadfdcc49cb0c87589d9329 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 7 Jul 2026 03:02:21 +0900 Subject: [PATCH 08/10] docs: add CONTRIBUTING.md capturing the doc structure conventions Documents the one-convention-per-concern rules from REFACTOR_PROPOSAL.md (file path = URL, title-only frontmatter, sidebar ordering, asset folders, i18n mirroring) plus the load-bearing URLs that must never change and the zh/en terminology glossary, so future contributors and agents don't need to rediscover these rules from the proposal doc or git history. --- CONTRIBUTING.md | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..519a3e4 --- /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 `<doc-name>.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:`、不使用数字前缀) | +| 页面标题 / 侧边栏文字 / `<title>` | 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 规范检查 +``` From 9720445ad102045c1138982d8c6ec2672cff600b Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 7 Jul 2026 03:06:07 +0900 Subject: [PATCH 09/10] i18n: translate the Agent sidebar category label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "dev" sidebar's "Agent 智能助手" category had no i18n string, so the English site was falling back to the raw Chinese label in the sidebar and breadcrumbs. Adds sidebar.dev.category.Agent 智能助手 -> "Agent" to i18n/en/docusaurus-plugin-content-docs/current.json, verified in the browser preview (breadcrumb now reads "Agent > Installing and Using Skills" instead of "Agent 智能助手 > ..."). --- i18n/en/docusaurus-plugin-content-docs/current.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/i18n/en/docusaurus-plugin-content-docs/current.json b/i18n/en/docusaurus-plugin-content-docs/current.json index b06e894..fae992e 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" } } From 7a90524a6e8dc77cd4e56ae4e849b4701a61f769 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 7 Jul 2026 07:04:21 +0900 Subject: [PATCH 10/10] Delete REFACTOR_PROPOSAL.md --- REFACTOR_PROPOSAL.md | 300 ------------------------------------------- 1 file changed, 300 deletions(-) delete mode 100644 REFACTOR_PROPOSAL.md diff --git a/REFACTOR_PROPOSAL.md b/REFACTOR_PROPOSAL.md deleted file mode 100644 index 880ed35..0000000 --- a/REFACTOR_PROPOSAL.md +++ /dev/null @@ -1,300 +0,0 @@ -# Technical Proposal — Docs Structure Refactor, Title Consistency & Full English Translation - -Repo: `scriptscat/scriptcat.org` (docs.scriptcat.org) · Branch: `refactor-001` · Date: 2026-07-07 -Stack: Docusaurus 3.10 (classic preset), pnpm, Gitea Actions → Docker/nginx → Helm/k8s - -## 0. Goals & Non-Goals - -**Goals** - -1. Make the folder structure self-describing: **file path = doc ID = published URL**, with zero frontmatter indirection. -2. Eliminate the sidebar-label / page-title mismatch class (e.g. `使用文档` sidebar shows "VSCode 扩展开发脚本" but the page H1 is "使用 VSCode 开发脚本") — by construction, not by discipline. -3. Complete the English translation (25 files currently missing) and keep it complete with a CI parity gate. -4. Improve workflow/config so regressions (URL changes, broken links, missing translations) are caught mechanically. -5. Optimize for maintainability by **both humans and coding agents**: one greppable convention per concern, documented in-repo. - -**Hard constraint (non-negotiable)** - -> **No published URL may change.** All 43 zh-Hans routes, their 43 `/en/` mirrors, plus `/uninstall/`, `/404.html`, `/opensearch.xml` must be byte-identical in the sitemap/route inventory before and after every phase. Several URLs are load-bearing (opened programmatically by the ScriptCat extension): `/docs/script_installation/`, `/docs/use/install_comple/`, `/uninstall/`. - -**Non-goals (explicitly out of scope)** - -- URL beautification (`/docs/use/use/` → `/docs/use/`, fixing the `install_comple` typo). Listed as an optional, separately-approved Phase 6 using redirects only. -- Content rewrites beyond title alignment and translation. - ---- - -## 1. Current-State Audit (verified against a local `pnpm run build` on this branch) - -### 1.1 The URL contract (baseline, from `build/sitemap.xml`) - -43 zh URLs; `build/en/sitemap.xml` mirrors them 1:1 under `/en/` (verified by diff). Key routes and how they are derived today: - -| URL | Source file | Derivation quirk | -|---|---|---| -| `/docs/use/use/` | `docs/use/1.README.md` | number prefix `1.` stripped; `id: use` overrides filename; **not** an index page — `/docs/use/` itself 404s today | -| `/docs/use/script_installation/` | `docs/use/2.script_installation.md` | prefix stripped | -| `/docs/use/sync/` | `docs/use/2.sync.md` | duplicate `2.` prefix (ordering collision with the above) | -| `/docs/use/QA/` | `docs/use/3.QA.md` | prefix stripped | -| `/docs/use/from-other/...` | `docs/use/4.from-other/...` | dir prefix stripped; label via `_category_.json` | -| `/docs/use/open-dev/`, `/docs/use/vscode/` | `5.open-dev.md`, `6.vscode.md` | prefix stripped | -| `/docs/use/policy/...` | `docs/use/99.policy/...` | dir prefix stripped | -| `/docs/use/install_comple/` | `docs/use/install_comple.md` | typo (`comple`) is live; **hardcoded in the extension** | -| `/docs/dev/` | `docs/dev/README.md` | README-as-index convention + `id: dev` | -| `/docs/dev/agent/` | `docs/dev/agent/index.md` | index convention + `id: agent` | -| `/docs/dev/agent/agent-conversation/` etc. | `docs/dev/agent/conversation.md` etc. | `id: agent-conversation` frontmatter renames every agent doc | -| `/docs/change/` | `docs/change/README.md` | index convention + `id: change` | -| `/docs/change/beta-changelog/` | `docs/change/beta.md` | `id: beta-changelog` | -| `/docs/change/v1.4/` … | `docs/change/v1.4.md` … | descending `sidebar_position: 9995…10000` hack for newest-first ordering | -| `/docs/script_installation/` | `docs/script_installation.md` | extension install intermediate page | -| `/docs/about/` | `docs/about/README.md` | carries dead VuePress-era keys (`sidebar: false`, `icon: info`) | -| `/uninstall/` | `src/pages/uninstall.tsx` | extension uninstall-feedback page | - -**Three URL-derivation mechanisms coexist** (number-prefix stripping, `id:` overrides, README/index convention). An agent or new contributor cannot map URL → file without reading frontmatter of every candidate. This is the root maintainability problem. - -### 1.2 Sidebar/ordering mechanisms — three coexist - -- `use`: autogenerated from number prefixes (already collided: two `2.` files). -- `dev`: explicit list in `sidebars.js`, referencing frontmatter-overridden IDs. -- `change`: autogenerated + descending `sidebar_position` hack. - -### 1.3 Title/label mismatches (frontmatter `title` drives the sidebar; body `# H1` drives the page) - -Found by script (zh; mirrored in en where translated): - -| File | `title` (sidebar/`<title>`) | Body H1 (page heading) | -|---|---|---| -| `docs/use/6.vscode.md` | VSCode 扩展开发脚本 | 使用 VSCode 开发脚本 | -| `docs/use/99.policy/disclaimer.md` | 免责声明 | ScriptCat 免责协议 | -| `docs/use/99.policy/privacy.md` | 隐私政策 | ScriptCat 隐私政策 | -| `docs/use/99.policy/privacy_website.md` | 脚本站点 隐私政策 | ScriptCat 脚本站点 隐私政策 | -| `docs/use/install_comple.md` | 安装完成 | 🎉 欢迎使用脚本猫 (intentional: `hide_title: true`) | - -Root cause: two competing sources of truth with no rule and no lint. - -### 1.4 Translation gaps (en) - -Missing entirely (falls back to Chinese on `/en/` pages): **all 13 `dev/` docs** (incl. the whole `agent/` section), `about/README.md`, and changelogs `v0.16`, `v0.17`, `v1.1`, `v1.2`, `v1.4` — 25 files. Additionally the en asset tree diverges from zh in naming (`i18n/en/.../use/4.from-other/img/migrate-from-violentmonkey.assets/` vs zh `img/migrate-from-violentmonkey/`). - -### 1.5 Broken links/anchors already shipping (build warns; `onBrokenLinks: "warn"` lets them through) - -- `/en/docs/use/vscode/` → links `/en/docs/use/` (**404 — `/docs/use/` and `/en/docs/use/` do not exist**; the site footer also links `/docs/use`). -- `docs/dev/agent/skill-install.md` uses URL-style relative links (`./agent-skill/`) that resolve incorrectly. -- 7 broken anchors across `/docs/dev/`, `/docs/dev/api/`, `/docs/dev/meta/`, `/docs/change/` (stale `#定时脚本`/`#后台脚本`/`#gm_cookie`/`#storagename-🧪` targets). - -### 1.6 Repo/CI hygiene - -- 15+ `.DS_Store` files committed; not in `.gitignore`. -- No PR/CI validation workflow — only the deploy workflow, which builds and ships without link/translation/URL checks. -- Deprecation warning: `onBrokenMarkdownLinks` must move to `markdown.hooks.onBrokenMarkdownLinks` (removed in Docusaurus v4). -- Asset conventions: four patterns coexist (`X.assets/` sibling, `img/X.assets/`, `img/X/`, section-level `img/`). -- `editUrl` does not set `editLocalizedFiles`, so "Edit this page" on `/en/` pages edits the zh source. - ---- - -## 2. Target Design - -### 2.1 Principle: one convention per concern - -| Concern | Single source of truth | -|---|---| -| URL / doc ID | File path, verbatim (no `id:`, no number prefixes) | -| Page title, sidebar label, `<title>` | Frontmatter `title:` (+ optional `sidebar_label:` for deliberate short labels) | -| Sidebar ordering | `sidebars.js`, explicit for all three sidebars | -| Images | `<doc-name>.assets/` sibling folder | -| Internal links | File-relative paths to the `.md` file (Docusaurus validates them at build time) | -| URL contract | Committed `scripts/url-inventory.txt`, enforced in CI | - -### 2.2 File renames (path ⇒ today's URL, then delete all `id:` overrides) - -All renames use `git mv`. The i18n/en tree is renamed identically in the same commit. Resulting doc IDs equal today's IDs, so URLs are provably unchanged. - -```text -docs/use/1.README.md → docs/use/use.md # id use/use, URL /docs/use/use/ (unchanged) -docs/use/2.script_installation.md → docs/use/script_installation.md -docs/use/2.sync.md → docs/use/sync.md -docs/use/3.QA.md → docs/use/QA.md # keep exact case -docs/use/4.from-other/ → docs/use/from-other/ -docs/use/5.open-dev.md → docs/use/open-dev.md -docs/use/6.vscode.md → docs/use/vscode.md -docs/use/99.policy/ → docs/use/policy/ -docs/use/install_comple.md → (keep; URL typo is load-bearing — add a NOTE comment in the file) - -docs/dev/README.md → docs/dev/index.md # id dev/index, URL /docs/dev/ (unchanged) -docs/dev/agent/index.md → (keep name; drop id: agent → id dev/agent/index, URL /docs/dev/agent/) -docs/dev/agent/conversation.md → docs/dev/agent/agent-conversation.md -docs/dev/agent/dom.md → docs/dev/agent/agent-dom.md -docs/dev/agent/skill-install.md → docs/dev/agent/agent-skill-install.md -docs/dev/agent/skill.md → docs/dev/agent/agent-skill.md -docs/dev/agent/skill-dev.md → docs/dev/agent/agent-skill-dev.md -docs/dev/agent/task.md → docs/dev/agent/agent-task.md -docs/dev/agent/model.md → docs/dev/agent/agent-model.md -docs/dev/agent/opfs.md → docs/dev/agent/agent-opfs.md -docs/dev/agent/mcp.md → docs/dev/agent/agent-mcp.md -docs/dev/agent/builtin-tools.md → docs/dev/agent/agent-builtin-tools.md - -docs/change/README.md → docs/change/index.md # id change/index, URL /docs/change/ -docs/change/beta.md → docs/change/beta-changelog.md - -docs/about/README.md → docs/about/index.md # URL /docs/about/; delete dead keys sidebar:/icon: -``` - -Then delete **every** `id:` and `sidebar_position:` frontmatter key repo-wide. The `agent/agent-*.md` names look redundant, but the alternative (keeping short filenames + `id:` overrides) preserves exactly the indirection we are removing; filename==URL is worth the redundancy. (Renaming URLs to drop the `agent-` prefix is forbidden by the constraint.) - -`docs/use/use.md` is admittedly an odd name — it is the price of the pre-existing `/docs/use/use/` URL. Phase 6 (optional) can promote it to `index.md` + redirect later. - -### 2.3 Sidebars: fully explicit `sidebars.js` - -Replace all autogeneration and `sidebar_position` with three explicit arrays (dev is already explicit — just update IDs): - -```js -const sidebars = { - use: [ - "use/use", - "use/script_installation", - "use/sync", - "use/QA", - { - type: "category", - label: "从其它管理器迁移", // translation key format unchanged: - items: [ // sidebar.use.category.从其它管理器迁移 - "use/from-other/migrate-from-tampermonkey", - "use/from-other/migrate-from-violentmonkey", - ], - }, - "use/open-dev", - "use/vscode", - { - type: "category", - label: "服务协议", // sidebar.use.category.服务协议 - items: ["use/policy/disclaimer", "use/policy/privacy", "use/policy/privacy_website"], - }, - // use/install_comple intentionally unlisted (hidden page) - ], - dev: [ - "dev/index", "dev/background", "dev/cloudcat", "dev/subscribe", - "dev/config", "dev/api", "dev/cat-api", - { - type: "category", - label: "Agent 智能助手", - link: { type: "doc", id: "dev/agent/index" }, - items: [ - "dev/agent/agent-conversation", "dev/agent/agent-dom", - "dev/agent/agent-skill-install", "dev/agent/agent-skill", - "dev/agent/agent-task", "dev/agent/agent-model", - "dev/agent/agent-opfs", "dev/agent/agent-mcp", - "dev/agent/agent-skill-dev", "dev/agent/agent-builtin-tools", - ], - }, - "dev/meta", - ], - change: [ - "change/index", - "change/beta-changelog", - "change/v1.4", "change/v1.3", "change/v1.2", "change/v1.1", - "change/v0.17", "change/v0.16", // newest-first; adding a release = insert one line - ], -}; -``` - -Consequences: delete both `_category_.json` files; delete the `9995…10000` position hack; `use/install_comple.md` no longer needs `sidebar_class_name: hidden` CSS hackery (unlisted docs are simply not in the sidebar — verify the hidden behavior is preserved, else keep the class). Category-label translation keys in `i18n/*/docusaurus-plugin-content-docs/current.json` keep the same `sidebar.use.category.<label>` format because the zh labels are unchanged. - -Update references: navbar `docId`s in `docusaurus.config.js` become `use/use` (unchanged), `dev/index`, `change/index`. - -Why explicit over autogenerated-everywhere: ordering lives in one greppable file, review diffs show sidebar changes explicitly, no renumber churn, no prefix collisions, and an agent can update navigation without inferring numeric conventions. Cost: adding a doc touches two files — acceptable and lint-checkable (a doc not referenced by any sidebar and not allowlisted fails CI). - -### 2.4 Title policy — mismatch impossible by construction - -**Rule: frontmatter `title:` is the only title. Body markdown contains no `# H1`** (Docusaurus renders `title` as the page H1 automatically). `sidebar_label:` allowed when a deliberately shorter nav label is wanted. `hide_title: true` pages (only `install_comple`) may keep a decorative body H1. - -Migration decisions for the current mismatches (needs maintainer eyes on wording; defaults below keep today's *visible page heading* and change only the metadata/sidebar to match): - -| File | New `title` | `sidebar_label` (optional) | -|---|---|---| -| `use/vscode.md` | 使用 VSCode 开发脚本 | — (sidebar text changes accordingly; en: "Develop Scripts with VSCode") | -| `use/policy/disclaimer.md` | ScriptCat 免责协议 | 免责声明 (keeps sidebar identical) | -| `use/policy/privacy.md` | ScriptCat 隐私政策 | 隐私政策 | -| `use/policy/privacy_website.md` | ScriptCat 脚本站点 隐私政策 | 脚本站点 隐私政策 | -| `use/install_comple.md` | 安装完成 (unchanged; `hide_title` exemption) | — | - -All other docs: move their current H1 text into `title:` and delete the H1 line (a mechanical script; see 2.7). Note `<title>`/OG metadata may change wording on the five fixed pages — that is the point of the fix; URLs do not change. - -### 2.5 Assets — one convention - -`<doc-name>.assets/` sibling folder (Typora's default; already used by `dev/*.assets` and `change/v1.3.assets`). Migrate `docs/use/img/**`, `docs/use/from-other/img/**`, `docs/change/img/**` into per-doc `.assets/` folders and rewrite the relative links. **Output-safe**: markdown-referenced images are emitted as content-hashed files under `/assets/images/`; their public URLs are derived from basename+content, not source directory. `static/` is untouched. - -i18n rule: locale-specific screenshots (e.g. English-UI browser screenshots) live beside the en markdown in the mirrored path with **identical folder names** to zh; genuinely language-neutral shared images should be referenced with `@site/docs/...` absolute source paths from both locales to avoid duplication (apply opportunistically during translation, not as a bulk migration). - -### 2.6 Full English translation - -Translate the 25 missing files (mirrored paths under `i18n/en/docusaurus-plugin-content-docs/current/`), in priority order: - -1. **`dev/` (13 files)** — the whole developer guide incl. `agent/` section; highest reader value. -2. **`about/index.md`**, **`change/index.md` deltas**, **`change/v1.4.md`** — current-facing pages. -3. **Historical changelogs** `v1.2`, `v1.1`, `v0.17`, `v0.16` — required for "fully translated"; low urgency, translate last. - -Also: run `pnpm run write-translations -- --locale en` and diff to catch untranslated `code.json`/theme keys (e.g. the `uninstall` page strings already use the translation API — verify coverage). - -Translation conventions (record in CONTRIBUTING.md): ScriptCat=脚本猫, user script=用户脚本, background script=后台脚本, scheduled script=定时脚本, Tampermonkey=油猴; en pages must keep identical heading *structure* so anchors and cross-links stay parallel; frontmatter keys identical to zh except translated `title`/`sidebar_label`. - -### 2.7 Guardrail scripts (`scripts/`, run via `pnpm run check` and in CI) - -1. **`check-url-inventory.mjs`** — after `docusaurus build`, collect `find build -name index.html` (both locales, normalized to routes) **plus** both sitemaps; compare against committed `scripts/url-inventory.txt`. Any diff fails CI; changing the contract requires editing the inventory file in the same PR (visible in review). *This is the mechanical guarantee that the refactor changes no URL.* -2. **`check-i18n-parity.mjs`** — the set of `docs/**/*.md(x)` must equal `i18n/en/docusaurus-plugin-content-docs/current/**/*.md(x)`; report missing and orphan files. Warn-only until Phase 5 completes, then hard-fail. -3. **`check-frontmatter.mjs`** — per doc: `title:` present; no body `# H1` (unless `hide_title: true`); no `id:`; no `sidebar_position:`; filename has no `N.` prefix; doc is referenced by exactly one sidebar or is in the hidden-pages allowlist (`use/install_comple`, `script_installation`, `about/index`); images referenced only from `./<doc>.assets/`, `@site/`, or `/img/`. -4. **H1→title migration script** (one-off, used in Phase 4): moves the first H1 of each doc into frontmatter `title`, deleting the H1 line; flags conflicts (the five mismatches) for manual resolution. - -### 2.8 Config changes (`docusaurus.config.js`) - -- `onBrokenLinks: "throw"` and `onBrokenAnchors: "throw"` (after Phase 2 fixes the pre-existing 3 links + 7 anchors; until then keep `warn` locally but CI treats warnings as failures via the checks). -- Migrate `onBrokenMarkdownLinks` → `markdown: { hooks: { onBrokenMarkdownLinks: "throw" } }` (v4-removal deprecation observed in build). -- `editUrl` → object form with `editLocalizedFiles: true` so `/en/` pages edit the en source. Verify the target repo slug (`scriptscat/scriptcat.org/edit/main`) matches the actual upstream default branch. -- Add `@docusaurus/plugin-client-redirects` with a single redirect `/docs/use/` → `/docs/use/use/`. This **adds** a route (fixing the currently-404 footer link `使用指南` and the `/docs/use/` links inside `vscode.md`/`use.md` without touching content everywhere) and changes no existing route. Add `/docs/use/` to the inventory as an intentional addition in that PR. (Alternative: rewrite the ~4 in-content links to `/docs/use/use/` and the footer `to:`; the redirect additionally rescues external bookmarks, so prefer the redirect **and** fix the footer link.) -- Internal-link style rule (enforced socially + by build validation): file-relative links to `.md` files. After 2.2, file path == URL so existing URL-style links keep working; new content should use file paths, which `onBrokenMarkdownLinks: throw` validates even for moved files. - -### 2.9 Workflow changes (`.gitea/workflows/`) - -- **New `ci.yaml`** (on `pull_request` + push to non-main): `pnpm install --frozen-lockfile` → `pnpm run typecheck` → `pnpm run build` → `pnpm run check` (inventory, parity, frontmatter). Cache pnpm store; no Docker/deploy steps. -- **`deploy.yaml`**: insert `pnpm run check` between Build and Docker steps, so a bad merge cannot ship. -- Keep the (Gitea-mirrored) action names as-is; they are environment-specific. - -### 2.10 Hygiene & docs-for-maintainers - -- Add `.DS_Store` to `.gitignore`; `git rm --cached` the ~15 committed instances. -- `npx update-browserslist-db@latest` (build warns; caniuse data 13–15 months old). -- **`CONTRIBUTING.md`** (root, bilingual or zh with en summary) capturing: the one-convention table (§2.1), "how to add a doc" (create file → add sidebar line → create en mirror → `pnpm run check`), "how to add a changelog release", the load-bearing URL list, and the translation glossary. This file is the agent-facing operating manual; keep it under ~150 lines so it fits in any agent's context. Optionally mirror the key rules into a root `AGENTS.md`/`CLAUDE.md` pointer. - ---- - -## 3. Execution Plan (one PR per phase; each PR must pass the inventory check) - -| Phase | Content | Risk | Verification | -|---|---|---|---| -| **0. Guardrails first** | Add `scripts/check-url-inventory.mjs` + committed `url-inventory.txt` (generated from current `main` build), `ci.yaml`, `pnpm run check` wiring, `.DS_Store` purge + gitignore | none | CI green on unchanged site | -| **1. Config & link fixes** | `onBrokenMarkdownLinks` migration; fix 3 broken links (incl. `skill-install.md` relative links) + 7 broken anchors; add `/docs/use/` redirect + fix footer `to`; flip `onBrokenLinks`/`onBrokenAnchors` to `throw`; `editLocalizedFiles: true`; browserslist update | low | build passes with `throw`; inventory diff shows exactly one intentional addition (`/docs/use/`) | -| **2. Structural renames** | §2.2 renames (zh + en trees, `git mv`), delete `id:`/`sidebar_position:`, explicit `sidebars.js` (§2.3), delete `_category_.json`, update navbar `docId`s | medium | **inventory byte-identical**; manual sidebar screenshot compare zh+en; `git log --follow` spot-check | -| **3. Asset normalization** | §2.5 `.assets/` migration + link rewrites; align en asset folder names to zh | low | inventory identical; build has zero broken markdown links (now `throw`) | -| **4. Title policy** | H1→`title` migration script; resolve the 5 mismatches per §2.4 table (maintainer confirms wording); enable `check-frontmatter.mjs` hard-fail | low | inventory identical; visual sidebar/title review; Algolia re-crawl picks up corrected titles automatically | -| **5. English translation** | Translate 25 files (priority order §2.6); fix `write-translations` gaps; flip `check-i18n-parity.mjs` to hard-fail | low (content-only) | parity check green; `/en/` spot review; inventory identical | -| **6. (Optional, separate approval)** | URL cleanup via redirects only: `/docs/use/use/`→`/docs/use/`, `install_comple`→`install_complete`, etc. **Requires coordinated extension release** for hardcoded URLs; old URLs redirect forever | medium | explicitly out of default scope | - -Sequencing rationale: the guardrail lands **before** any file moves, so every subsequent phase is machine-verified against the constraint rather than eyeballed. - -## 4. Risks & Mitigations - -- **`README.md` → `index.md` slug equivalence**: both are Docusaurus index conventions producing the directory slug; Phase 2's inventory check proves it. If any edge case differs, fall back to keeping `README.md` (also convention-compliant) — the check catches it before merge. -- **Docusaurus number-prefix parser**: after removing prefixes, no stripping is in play at all — one failure mode deleted. -- **Git history**: `git mv` in dedicated rename-only commits keeps `--follow` working; avoid mixing renames with content edits in the same commit. -- **Algolia**: URLs stable ⇒ index remains valid; corrected titles update on next crawl. No action needed. -- **Sidebar visual change**: only `use/vscode` label wording changes (intended fix); policy pages keep labels via `sidebar_label`. Screenshot compare in Phase 4 review. -- **en fallback pages during Phase 5**: untranslated `/en/` pages continue falling back to zh content exactly as today — no regression window. -- **Extension-hardcoded URLs**: never touched (inventory + CONTRIBUTING list them). - -## 5. Acceptance Criteria - -1. `scripts/url-inventory.txt` unchanged from the pre-refactor baseline (except the single documented `/docs/use/` addition), enforced in CI on every PR. -2. Zero `id:`/`sidebar_position:` frontmatter; zero number-prefixed filenames; `grep -rl '^# ' docs | wc -l` = allowlisted count. -3. Zero broken links/anchors with `throw` enabled, both locales. -4. `docs/**` ↔ `i18n/en/.../current/**` file sets identical; all 25 gap files translated. -5. Sidebar label == page H1 == `<title>` (modulo explicit `sidebar_label`) for every doc, both locales. -6. `CONTRIBUTING.md` present; a new doc can be added by following it verbatim (add file → sidebar line → en mirror → `pnpm run check` green).