{"owner":"obgnail","repo":"typora_plugin","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md"],"skills":{"AGENTS.md":"# AGENTS.md\n\nThis file provides guidance to AI coding assistants and agents when working with code in this repository.\n\n## Project Overview\n\nTypora Plugin is an extensible plugin system for the Typora Markdown editor. It injects into Typora's Electron-based runtime (via `window.html`) and provides 50+ plugins. The project is pure JavaScript (no TypeScript), requires Typora >= 0.9.98, and supports Windows and Linux.\n\n**Compatibility Target:**\n\nBecause this project must support Typora 0.9.98, any code injected into the Typora runtime must be compatible with its underlying legacy Electron version. The minimum supported environment limits are:\n\n- **Chrome**: 84 (do not rely on features introduced after Chrome 84)\n- **Node.js**: 12.14.1\n\n## Project Constraints\n\n### Storage and Concurrency\n\n- For small amounts of plugin data, use `utils.getStorage` instead of writing files under `user_space`. The latter is prone to permission errors.\n- Keep this storage flow simple: do not add file locking when using `utils.getStorage` for these small data sets.\n\n### Legacy Runtime Compatibility\n\n- Code running inside Typora must remain compatible with Typora 0.9.98 and Chrome 84. Avoid JavaScript, DOM, and CSS features introduced after that browser version.\n- In particular, do not use Flexbox `gap`. Use compatible DOM operations and spacing techniques instead.\n- If a newer JavaScript or DOM API is truly needed, add an appropriate compatibility implementation to `plugin/global/core/polyfill.js`. CSS features still require a compatible CSS fallback.\n\n### Theme-safe Plugin UI\n\n- Typora Plugin is not an official Typora project, so user themes may contain broad selectors that affect plugin UI. For plugin-owned UI markup, prefer `div` elements and avoid other HTML tags whenever practical.\n- Do not introduce native `select`, `option`, or `button` elements in plugin UI. Use the existing `fast-dropdown` component instead of `select`/`option`, and use a regular `div` for button-like controls.\n- Refer to the `commander` plugin for established `fast-dropdown` usage. The shared `fast-dropdown` component may be adjusted when the required behavior cannot be expressed by its current API.\n- Plugin dialogs should first consider reusing the shared `fast-window` component, following examples such as `search_multi` and `commander`. Reuse is preferred for dialogs such as `.repository-dialog`, but is not mandatory when the component is unsuitable.\n\n### Text Input Handling\n\n- For search and similar live text inputs, use `utils.createSmartInputHandler` so IME composition (including Chinese input) is handled correctly. Do not implement these handlers as `addEventListener(\"input\", utils.debounce(...))`.\n\n## Commands\n\nAll commands run from the `develop/` directory. Requires Node.js >= 22.\n\n```bash\ncd develop\nnpm install          # Install dev dependencies\n\n# Testing (uses Node.js built-in test runner: node:test + node:assert)\nnpm test                                    # Run all tests\nnode --require ../plugin/global/core/polyfill.js --test test/utils.test.js   # Run single test file\n\n# Building vendored dependencies (esbuild bundles NPM packages into plugin/global/core/lib/)\nnpm run build:all                           # Build all vendors\nnpm run build:single                        # Build a single vendor (edit arg in package.json, e.g. \"katex\")\nnpm run build:download                      # Build download-type vendors (js-yaml, markdown-it, etc.)\n\n# Development (requires TYPORA_PATH set in develop/.env)\nnpm run dev                                 # Development mode\nnpm run sync                                # Watch plugin/ for changes, sync to Typora install dir\nnpm run serve                               # Sync + auto-restart Typora via JSON-RPC\nnpm run rpc                                 # JSON-RPC connection to running Typora\n```\n\n## Architecture\n\n### Entry Point Flow\n\n1. `plugin/index.js` -- loaded by modified `window.html`, requires `plugin/global/core/index.js`\n2. `plugin/global/core/index.js` -- `entry()` function: checks Typora version, reads TOML settings, sets up globals, initializes i18n, loads all plugins via mixin chain, publishes `allPluginsHadInjected` event\n\n### Core Framework (`plugin/global/core/`)\n\n- **`plugin.js`** -- `BasePlugin` classes, and `LoadPlugins()` which drives the plugin lifecycle\n- **`serviceContainer.js`** -- Singleton storing all plugin instances and settings; provides lookup APIs (`getPlugin()`)\n- **`i18n.js`** -- i18n system supporting `en`, `zh-CN`, `zh-TW`; loads JSON locale files from `plugin/global/locales/`\n- **`polyfill.js`** -- Polyfills for older Electron/Node (`Object.hasOwn`, `Promise.withResolvers`, etc.)\n\n### Core Utilities (`plugin/global/core/utils/`)\n\n- **`index.js`** -- Large utility class (~200+ static methods): DOM manipulation, file ops, path handling, HTML/CSS injection. Instantiates all mixins.\n- **`eventHub.js`** -- Event bus with typed events (`fileOpened`, `fileEdited`, `outlineUpdated`, etc.). Uses MutationObserver and decorator hooks.\n- **`hotkeyHub.js`** -- Global hotkey registration/dispatch. Normalizes key combos (Ctrl+Shift+Alt+Key).\n- **`decorator.js`** -- AOP system. Wraps Typora's internal functions with before/after hooks, argument/result modification, call prevention. Supports decorator chaining with priorities.\n- **`settings.js`** -- TOML settings reader (default + user), supports save/import/export, auto-save via Proxy.\n- **`styleManager.js`** -- CSS loading with template variable substitution (`${config.value}`).\n- **`thirdPartyDiagramParser.js`** -- Extended diagram framework with lazy-loading and export support.\n\n### Plugin System\n\n**Plugin Lifecycle** (in order): `prepare()` -> `style()` -> `html()` -> `hotkey()` -> `init()` -> `process()` -> `postprocess()`\n\n### Settings System (`plugin/global/settings/`)\n\n- `settings.default.toml` (~120KB) -- Default config for all base plugins. Each plugin has `[plugin_name]` section with `ENABLE`, `NAME`, and plugin-specific options.\n- `settings.user.toml` -- User overrides\n- Supports home directory override (`~/.config/typora_plugin/`) for persistence across updates\n\n### Key Patterns\n\n- **Service Container / DI**: `ServiceContainer` singleton holds all plugin instances, accessible via `utils.container`\n- **AOP (Aspect-Oriented Programming)**: `decorator.js` wraps Typora internals without modifying source. Used by `eventHub`, `exportHelper`, and many plugins.\n- **Mixin Architecture**: Core features (eventHub, hotkeyHub, styleManager, etc.) are mixins on the `utils` class, each with `process()` and optional `postprocess()` lifecycle methods\n- **Vendored Dependencies**: All NPM dependencies are pre-bundled via esbuild into `plugin/global/core/lib/` -- no runtime `npm install` needed in `plugin/`\n- **Event-Driven**: Rich event system for file operations, code block changes, sidebar toggling, etc.\n\n## Code Style\n\n- Pure JavaScript, no TypeScript\n- UTF-8, 2-space indent, LF line endings (see `.editorconfig`)\n- All UI strings go through the i18n system (locale files in `plugin/global/locales/`)\n- When adding a new plugin: add a `[plugin_name]` section to `settings.default.toml` with at least `ENABLE` and `NAME` keys, add translations to all three locale JSON files, and optionally add a CSS file to `plugin/global/styles/`\n\n## Debugging\n\n- **Open DevTools**: To open Typora's Developer Tools for debugging or inspecting the DOM and console logs, use the following JS command:\n\n  ```javascript\n  JSBridge.invoke(\"window.toggleDevTools\")\n  ```\n\n## Testing\n\n- Framework: Node.js built-in `node:test` + `node:assert`\n- Test files are in `develop/test/`\n- Tests use JSDOM for DOM mocking (`develop/test/mocks/dom.mock.js`), proxyquire for module mocking (`utils.mock.js`), and fixture files for integration-style tests\n- The polyfill (`plugin/global/core/polyfill.js`) must be loaded via `--require` before tests\n\n## Build System\n\nThe build (`develop/build/index.cjs`) uses esbuild to bundle NPM dependencies into standalone files under `plugin/global/core/lib/` and individual plugin directories. Three vendor types:\n- **download**: Fetch minified files from CDN/GitHub\n- **bundle**: esbuild bundles NPM packages (options: `{ bundle: true, minify: true, platform: \"node\", target: \"node12.14\" }`)\n- **dist**: Copy NPM package assets directly (e.g., katex fonts + CSS)\n\n## CI/CD\n\n- `TestOnCommit.yaml` -- Runs `npm ci && npm test` on push to `develop/**`, `plugin/**`, `.github/**` (Node 20.x and 24.x matrix)\n- `PublishOnTag.yaml` -- On tag `X.Y.Z`, creates VERSION.json, zips `plugin/`, publishes GitHub Release\n"},"files":{"AGENTS.md":"# AGENTS.md\n\nThis file provides guidance to AI coding assistants and agents when working with code in this repository.\n\n## Project Overview\n\nTypora Plugin is an extensible plugin system for the Typora Markdown editor. It injects into Typora's Electron-based runtime (via `window.html`) and provides 50+ plugins. The project is pure JavaScript (no TypeScript), requires Typora >= 0.9.98, and supports Windows and Linux.\n\n**Compatibility Target:**\n\nBecause this project must support Typora 0.9.98, any code injected into the Typora runtime must be compatible with its underlying legacy Electron version. The minimum supported environment limits are:\n\n- **Chrome**: 84 (do not rely on features introduced after Chrome 84)\n- **Node.js**: 12.14.1\n\n## Project Constraints\n\n### Storage and Concurrency\n\n- For small amounts of plugin data, use `utils.getStorage` instead of writing files under `user_space`. The latter is prone to permission errors.\n- Keep this storage flow simple: do not add file locking when using `utils.getStorage` for these small data sets.\n\n### Legacy Runtime Compatibility\n\n- Code running inside Typora must remain compatible with Typora 0.9.98 and Chrome 84. Avoid JavaScript, DOM, and CSS features introduced after that browser version.\n- In particular, do not use Flexbox `gap`. Use compatible DOM operations and spacing techniques instead.\n- If a newer JavaScript or DOM API is truly needed, add an appropriate compatibility implementation to `plugin/global/core/polyfill.js`. CSS features still require a compatible CSS fallback.\n\n### Theme-safe Plugin UI\n\n- Typora Plugin is not an official Typora project, so user themes may contain broad selectors that affect plugin UI. For plugin-owned UI markup, prefer `div` elements and avoid other HTML tags whenever practical.\n- Do not introduce native `select`, `option`, or `button` elements in plugin UI. Use the existing `fast-dropdown` component instead of `select`/`option`, and use a regular `div` for button-like controls.\n- Refer to the `commander` plugin for established `fast-dropdown` usage. The shared `fast-dropdown` component may be adjusted when the required behavior cannot be expressed by its current API.\n- Plugin dialogs should first consider reusing the shared `fast-window` component, following examples such as `search_multi` and `commander`. Reuse is preferred for dialogs such as `.repository-dialog`, but is not mandatory when the component is unsuitable.\n\n### Text Input Handling\n\n- For search and similar live text inputs, use `utils.createSmartInputHandler` so IME composition (including Chinese input) is handled correctly. Do not implement these handlers as `addEventListener(\"input\", utils.debounce(...))`.\n\n## Commands\n\nAll commands run from the `develop/` directory. Requires Node.js >= 22.\n\n```bash\ncd develop\nnpm install          # Install dev dependencies\n\n# Testing (uses Node.js built-in test runner: node:test + node:assert)\nnpm test                                    # Run all tests\nnode --require ../plugin/global/core/polyfill.js --test test/utils.test.js   # Run single test file\n\n# Building vendored dependencies (esbuild bundles NPM packages into plugin/global/core/lib/)\nnpm run build:all                           # Build all vendors\nnpm run build:single                        # Build a single vendor (edit arg in package.json, e.g. \"katex\")\nnpm run build:download                      # Build download-type vendors (js-yaml, markdown-it, etc.)\n\n# Development (requires TYPORA_PATH set in develop/.env)\nnpm run dev                                 # Development mode\nnpm run sync                                # Watch plugin/ for changes, sync to Typora install dir\nnpm run serve                               # Sync + auto-restart Typora via JSON-RPC\nnpm run rpc                                 # JSON-RPC connection to running Typora\n```\n\n## Architecture\n\n### Entry Point Flow\n\n1. `plugin/index.js` -- loaded by modified `window.html`, requires `plugin/global/core/index.js`\n2. `plugin/global/core/index.js` -- `entry()` function: checks Typora version, reads TOML settings, sets up globals, initializes i18n, loads all plugins via mixin chain, publishes `allPluginsHadInjected` event\n\n### Core Framework (`plugin/global/core/`)\n\n- **`plugin.js`** -- `BasePlugin` classes, and `LoadPlugins()` which drives the plugin lifecycle\n- **`serviceContainer.js`** -- Singleton storing all plugin instances and settings; provides lookup APIs (`getPlugin()`)\n- **`i18n.js`** -- i18n system supporting `en`, `zh-CN`, `zh-TW`; loads JSON locale files from `plugin/global/locales/`\n- **`polyfill.js`** -- Polyfills for older Electron/Node (`Object.hasOwn`, `Promise.withResolvers`, etc.)\n\n### Core Utilities (`plugin/global/core/utils/`)\n\n- **`index.js`** -- Large utility class (~200+ static methods): DOM manipulation, file ops, path handling, HTML/CSS injection. Instantiates all mixins.\n- **`eventHub.js`** -- Event bus with typed events (`fileOpened`, `fileEdited`, `outlineUpdated`, etc.). Uses MutationObserver and decorator hooks.\n- **`hotkeyHub.js`** -- Global hotkey registration/dispatch. Normalizes key combos (Ctrl+Shift+Alt+Key).\n- **`decorator.js`** -- AOP system. Wraps Typora's internal functions with before/after hooks, argument/result modification, call prevention. Supports decorator chaining with priorities.\n- **`settings.js`** -- TOML settings reader (default + user), supports save/import/export, auto-save via Proxy.\n- **`styleManager.js`** -- CSS loading with template variable substitution (`${config.value}`).\n- **`thirdPartyDiagramParser.js`** -- Extended diagram framework with lazy-loading and export support.\n\n### Plugin System\n\n**Plugin Lifecycle** (in order): `prepare()` -> `style()` -> `html()` -> `hotkey()` -> `init()` -> `process()` -> `postprocess()`\n\n### Settings System (`plugin/global/settings/`)\n\n- `settings.default.toml` (~120KB) -- Default config for all base plugins. Each plugin has `[plugin_name]` section with `ENABLE`, `NAME`, and plugin-specific options.\n- `settings.user.toml` -- User overrides\n- Supports home directory override (`~/.config/typora_plugin/`) for persistence across updates\n\n### Key Patterns\n\n- **Service Container / DI**: `ServiceContainer` singleton holds all plugin instances, accessible via `utils.container`\n- **AOP (Aspect-Oriented Programming)**: `decorator.js` wraps Typora internals without modifying source. Used by `eventHub`, `exportHelper`, and many plugins.\n- **Mixin Architecture**: Core features (eventHub, hotkeyHub, styleManager, etc.) are mixins on the `utils` class, each with `process()` and optional `postprocess()` lifecycle methods\n- **Vendored Dependencies**: All NPM dependencies are pre-bundled via esbuild into `plugin/global/core/lib/` -- no runtime `npm install` needed in `plugin/`\n- **Event-Driven**: Rich event system for file operations, code block changes, sidebar toggling, etc.\n\n## Code Style\n\n- Pure JavaScript, no TypeScript\n- UTF-8, 2-space indent, LF line endings (see `.editorconfig`)\n- All UI strings go through the i18n system (locale files in `plugin/global/locales/`)\n- When adding a new plugin: add a `[plugin_name]` section to `settings.default.toml` with at least `ENABLE` and `NAME` keys, add translations to all three locale JSON files, and optionally add a CSS file to `plugin/global/styles/`\n\n## Debugging\n\n- **Open DevTools**: To open Typora's Developer Tools for debugging or inspecting the DOM and console logs, use the following JS command:\n\n  ```javascript\n  JSBridge.invoke(\"window.toggleDevTools\")\n  ```\n\n## Testing\n\n- Framework: Node.js built-in `node:test` + `node:assert`\n- Test files are in `develop/test/`\n- Tests use JSDOM for DOM mocking (`develop/test/mocks/dom.mock.js`), proxyquire for module mocking (`utils.mock.js`), and fixture files for integration-style tests\n- The polyfill (`plugin/global/core/polyfill.js`) must be loaded via `--require` before tests\n\n## Build System\n\nThe build (`develop/build/index.cjs`) uses esbuild to bundle NPM dependencies into standalone files under `plugin/global/core/lib/` and individual plugin directories. Three vendor types:\n- **download**: Fetch minified files from CDN/GitHub\n- **bundle**: esbuild bundles NPM packages (options: `{ bundle: true, minify: true, platform: \"node\", target: \"node12.14\" }`)\n- **dist**: Copy NPM package assets directly (e.g., katex fonts + CSS)\n\n## CI/CD\n\n- `TestOnCommit.yaml` -- Runs `npm ci && npm test` on push to `develop/**`, `plugin/**`, `.github/**` (Node 20.x and 24.x matrix)\n- `PublishOnTag.yaml` -- On tag `X.Y.Z`, creates VERSION.json, zips `plugin/`, publishes GitHub Release\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"# AGENTS.md\n\nThis file provides guidance to AI coding assistants and agents when working with code in this repository.\n\n## Project Overview\n\nTypora Plugin is an extensible plugin system for the Typora Markdown editor. It injects into Typora's Electron-based runtime (via `window.html`) and provides 50+ plugins. The project is pure JavaScript (no TypeScript), requires Typora >= 0.9.98, and supports Windows and Linux.\n\n**Compatibility Target:**\n\nBecause this project must support Typora 0.9.98, any code injected into the Typora runtime must be compatible with its underlying legacy Electron version. The minimum supported environment limits are:\n\n- **Chrome**: 84 (do not rely on features introduced after Chrome 84)\n- **Node.js**: 12.14.1\n\n## Project Constraints\n\n### Storage and Concurrency\n\n- For small amounts of plugin data, use `utils.getStorage` instead of writing files under `user_space`. The latter is prone to permission errors.\n- Keep this storage flow simple: do not add file locking when using `utils.getStorage` for these small data sets.\n\n### Legacy Runtime Compatibility\n\n- Code running inside Typora must remain compatible with Typora 0.9.98 and Chrome 84. Avoid JavaScript, DOM, and CSS features introduced after that browser version.\n- In particular, do not use Flexbox `gap`. Use compatible DOM operations and spacing techniques instead.\n- If a newer JavaScript or DOM API is truly needed, add an appropriate compatibility implementation to `plugin/global/core/polyfill.js`. CSS features still require a compatible CSS fallback.\n\n### Theme-safe Plugin UI\n\n- Typora Plugin is not an official Typora project, so user themes may contain broad selectors that affect plugin UI. For plugin-owned UI markup, prefer `div` elements and avoid other HTML tags whenever practical.\n- Do not introduce native `select`, `option`, or `button` elements in plugin UI. Use the existing `fast-dropdown` component instead of `select`/`option`, and use a regular `div` for button-like controls.\n- Refer to the `commander` plugin for established `fast-dropdown` usage. The shared `fast-dropdown` component may be adjusted when the required behavior cannot be expressed by its current API.\n- Plugin dialogs should first consider reusing the shared `fast-window` component, following examples such as `search_multi` and `commander`. Reuse is preferred for dialogs such as `.repository-dialog`, but is not mandatory when the component is unsuitable.\n\n### Text Input Handling\n\n- For search and similar live text inputs, use `utils.createSmartInputHandler` so IME composition (including Chinese input) is handled correctly. Do not implement these handlers as `addEventListener(\"input\", utils.debounce(...))`.\n\n## Commands\n\nAll commands run from the `develop/` directory. Requires Node.js >= 22.\n\n```bash\ncd develop\nnpm install          # Install dev dependencies\n\n# Testing (uses Node.js built-in test runner: node:test + node:assert)\nnpm test                                    # Run all tests\nnode --require ../plugin/global/core/polyfill.js --test test/utils.test.js   # Run single test file\n\n# Building vendored dependencies (esbuild bundles NPM packages into plugin/global/core/lib/)\nnpm run build:all                           # Build all vendors\nnpm run build:single                        # Build a single vendor (edit arg in package.json, e.g. \"katex\")\nnpm run build:download                      # Build download-type vendors (js-yaml, markdown-it, etc.)\n\n# Development (requires TYPORA_PATH set in develop/.env)\nnpm run dev                                 # Development mode\nnpm run sync                                # Watch plugin/ for changes, sync to Typora install dir\nnpm run serve                               # Sync + auto-restart Typora via JSON-RPC\nnpm run rpc                                 # JSON-RPC connection to running Typora\n```\n\n## Architecture\n\n### Entry Point Flow\n\n1. `plugin/index.js` -- loaded by modified `window.html`, requires `plugin/global/core/index.js`\n2. `plugin/global/core/index.js` -- `entry()` function: checks Typora version, reads TOML settings, sets up globals, initializes i18n, loads all plugins via mixin chain, publishes `allPluginsHadInjected` event\n\n### Core Framework (`plugin/global/core/`)\n\n- **`plugin.js`** -- `BasePlugin` classes, and `LoadPlugins()` which drives the plugin lifecycle\n- **`serviceContainer.js`** -- Singleton storing all plugin instances and settings; provides lookup APIs (`getPlugin()`)\n- **`i18n.js`** -- i18n system supporting `en`, `zh-CN`, `zh-TW`; loads JSON locale files from `plugin/global/locales/`\n- **`polyfill.js`** -- Polyfills for older Electron/Node (`Object.hasOwn`, `Promise.withResolvers`, etc.)\n\n### Core Utilities (`plugin/global/core/utils/`)\n\n- **`index.js`** -- Large utility class (~200+ static methods): DOM manipulation, file ops, path handling, HTML/CSS injection. Instantiates all mixins.\n- **`eventHub.js`** -- Event bus with typed events (`fileOpened`, `fileEdited`, `outlineUpdated`, etc.). Uses MutationObserver and decorator hooks.\n- **`hotkeyHub.js`** -- Global hotkey registration/dispatch. Normalizes key combos (Ctrl+Shift+Alt+Key).\n- **`decorator.js`** -- AOP system. Wraps Typora's internal functions with before/after hooks, argument/result modification, call prevention. Supports decorator chaining with priorities.\n- **`settings.js`** -- TOML settings reader (default + user), supports save/import/export, auto-save via Proxy.\n- **`styleManager.js`** -- CSS loading with template variable substitution (`${config.value}`).\n- **`thirdPartyDiagramParser.js`** -- Extended diagram framework with lazy-loading and export support.\n\n### Plugin System\n\n**Plugin Lifecycle** (in order): `prepare()` -> `style()` -> `html()` -> `hotkey()` -> `init()` -> `process()` -> `postprocess()`\n\n### Settings System (`plugin/global/settings/`)\n\n- `settings.default.toml` (~120KB) -- Default config for all base plugins. Each plugin has `[plugin_name]` section with `ENABLE`, `NAME`, and plugin-specific options.\n- `settings.user.toml` -- User overrides\n- Supports home directory override (`~/.config/typora_plugin/`) for persistence across updates\n\n### Key Patterns\n\n- **Service Container / DI**: `ServiceContainer` singleton holds all plugin instances, accessible via `utils.container`\n- **AOP (Aspect-Oriented Programming)**: `decorator.js` wraps Typora internals without modifying source. Used by `eventHub`, `exportHelper`, and many plugins.\n- **Mixin Architecture**: Core features (eventHub, hotkeyHub, styleManager, etc.) are mixins on the `utils` class, each with `process()` and optional `postprocess()` lifecycle methods\n- **Vendored Dependencies**: All NPM dependencies are pre-bundled via esbuild into `plugin/global/core/lib/` -- no runtime `npm install` needed in `plugin/`\n- **Event-Driven**: Rich event system for file operations, code block changes, sidebar toggling, etc.\n\n## Code Style\n\n- Pure JavaScript, no TypeScript\n- UTF-8, 2-space indent, LF line endings (see `.editorconfig`)\n- All UI strings go through the i18n system (locale files in `plugin/global/locales/`)\n- When adding a new plugin: add a `[plugin_name]` section to `settings.default.toml` with at least `ENABLE` and `NAME` keys, add translations to all three locale JSON files, and optionally add a CSS file to `plugin/global/styles/`\n\n## Debugging\n\n- **Open DevTools**: To open Typora's Developer Tools for debugging or inspecting the DOM and console logs, use the following JS command:\n\n  ```javascript\n  JSBridge.invoke(\"window.toggleDevTools\")\n  ```\n\n## Testing\n\n- Framework: Node.js built-in `node:test` + `node:assert`\n- Test files are in `develop/test/`\n- Tests use JSDOM for DOM mocking (`develop/test/mocks/dom.mock.js`), proxyquire for module mocking (`utils.mock.js`), and fixture files for integration-style tests\n- The polyfill (`plugin/global/core/polyfill.js`) must be loaded via `--require` before tests\n\n## Build System\n\nThe build (`develop/build/index.cjs`) uses esbuild to bundle NPM dependencies into standalone files under `plugin/global/core/lib/` and individual plugin directories. Three vendor types:\n- **download**: Fetch minified files from CDN/GitHub\n- **bundle**: esbuild bundles NPM packages (options: `{ bundle: true, minify: true, platform: \"node\", target: \"node12.14\" }`)\n- **dist**: Copy NPM package assets directly (e.g., katex fonts + CSS)\n\n## CI/CD\n\n- `TestOnCommit.yaml` -- Runs `npm ci && npm test` on push to `develop/**`, `plugin/**`, `.github/**` (Node 20.x and 24.x matrix)\n- `PublishOnTag.yaml` -- On tag `X.Y.Z`, creates VERSION.json, zips `plugin/`, publishes GitHub Release\n","category":"root","tokens":2151}]}