sourcemonkey 0.0.0-stage → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +87 -2
- package/dist/bytes.js +37 -0
- package/dist/channel-placeholder.js +5 -0
- package/dist/collection-scan.js +17 -0
- package/dist/collections.html +353 -0
- package/dist/compare.html +358 -0
- package/dist/composed-source.js +205 -0
- package/dist/connect-prompt.html +47 -0
- package/dist/debug/icons.html +211 -0
- package/dist/debug/storage.html +163 -0
- package/dist/debug-log.js +75 -0
- package/dist/diagnostic-location.js +64 -0
- package/dist/eval-hook.js +308 -0
- package/dist/extension/background.js +5263 -0
- package/dist/extension/channel.js +133 -0
- package/dist/extension/code-links.js +187 -0
- package/dist/extension/code-tabs.js +460 -0
- package/dist/extension/collection-dialog.js +619 -0
- package/dist/extension/collection-display.js +322 -0
- package/dist/extension/collections.js +2905 -0
- package/dist/extension/compare.js +867 -0
- package/dist/extension/concurrency.js +186 -0
- package/dist/extension/connect-grants.js +109 -0
- package/dist/extension/connect-prompt-page.js +70 -0
- package/dist/extension/connect-prompt.js +266 -0
- package/dist/extension/copy-button.js +63 -0
- package/dist/extension/copy-dialog.js +502 -0
- package/dist/extension/copy-preference.js +66 -0
- package/dist/extension/debug/icons.js +203 -0
- package/dist/extension/debug/storage.js +365 -0
- package/dist/extension/deep-link.js +77 -0
- package/dist/extension/delete-dialog.js +432 -0
- package/dist/extension/delete-icon.js +40 -0
- package/dist/extension/details-tooltips.js +66 -0
- package/dist/extension/directories.js +679 -0
- package/dist/extension/export-backup.js +407 -0
- package/dist/extension/export-dialog.js +142 -0
- package/dist/extension/file-access.js +74 -0
- package/dist/extension/file-changes.js +346 -0
- package/dist/extension/frame-info.js +85 -0
- package/dist/extension/github-provider.js +336 -0
- package/dist/extension/glyph.js +84 -0
- package/dist/extension/gm-bindings.js +601 -0
- package/dist/extension/gm-download.js +419 -0
- package/dist/extension/gm-menu.js +228 -0
- package/dist/extension/gm-notification.js +141 -0
- package/dist/extension/gm-originator-map.js +23 -0
- package/dist/extension/gm-tab-data.js +121 -0
- package/dist/extension/gm-tab.js +160 -0
- package/dist/extension/gm-url-change.js +111 -0
- package/dist/extension/gm-url-scheme.js +27 -0
- package/dist/extension/gm-values.js +176 -0
- package/dist/extension/gm-window-control.js +104 -0
- package/dist/extension/gm-xhr-headers.js +333 -0
- package/dist/extension/gm-xhr.js +584 -0
- package/dist/extension/injector.js +3145 -0
- package/dist/extension/install-capture.js +277 -0
- package/dist/extension/line-diff.js +233 -0
- package/dist/extension/local-copy.js +560 -0
- package/dist/extension/local-delete.js +276 -0
- package/dist/extension/location-kinds.js +108 -0
- package/dist/extension/log-format.js +158 -0
- package/dist/extension/managed-changes.js +361 -0
- package/dist/extension/managed-items.js +57 -0
- package/dist/extension/match-index.js +375 -0
- package/dist/extension/missing-scripts.js +66 -0
- package/dist/extension/more-menu.js +109 -0
- package/dist/extension/move-dialog.js +197 -0
- package/dist/extension/offscreen.js +37 -0
- package/dist/extension/options.js +504 -0
- package/dist/extension/page-heading.js +170 -0
- package/dist/extension/page-links.js +199 -0
- package/dist/extension/parse-check-client.js +70 -0
- package/dist/extension/parse-check.js +161 -0
- package/dist/extension/parse-sandbox-host.js +172 -0
- package/dist/extension/parse-sandbox.js +175 -0
- package/dist/extension/popup-commands-open.js +41 -0
- package/dist/extension/popup-view.js +387 -0
- package/dist/extension/popup.js +703 -0
- package/dist/extension/prism-userscript.js +53 -0
- package/dist/extension/refresh-error.js +136 -0
- package/dist/extension/refresh-targets.js +160 -0
- package/dist/extension/related-versions.js +1144 -0
- package/dist/extension/resize-observer-loop.js +19 -0
- package/dist/extension/row-cache.js +387 -0
- package/dist/extension/script-blobs.js +413 -0
- package/dist/extension/script-details.js +658 -0
- package/dist/extension/script-enablement.js +285 -0
- package/dist/extension/script-identity.js +310 -0
- package/dist/extension/script-keys.js +54 -0
- package/dist/extension/script-log-id.js +155 -0
- package/dist/extension/script-log.js +290 -0
- package/dist/extension/script-rejection.js +104 -0
- package/dist/extension/script-sites.js +158 -0
- package/dist/extension/script-store.js +3507 -0
- package/dist/extension/script-updater.js +991 -0
- package/dist/extension/script-url-hash.js +61 -0
- package/dist/extension/select-all.js +37 -0
- package/dist/extension/select-open-guard.js +90 -0
- package/dist/extension/site-icon.js +1261 -0
- package/dist/extension/sm-dev-link.js +302 -0
- package/dist/extension/solo-click.js +58 -0
- package/dist/extension/sticky-numbers.js +188 -0
- package/dist/extension/storage-breakdown.js +253 -0
- package/dist/extension/storage-scan.js +86 -0
- package/dist/extension/storage-usage.js +194 -0
- package/dist/extension/structural-keys.js +29 -0
- package/dist/extension/sw-teardown.js +36 -0
- package/dist/extension/tab-status.js +403 -0
- package/dist/extension/toolbar-summary.js +105 -0
- package/dist/extension/user-scripts-access.js +43 -0
- package/dist/extension/userscript.js +3672 -0
- package/dist/extension/value-store.js +204 -0
- package/dist/extension/version-probe-fetch.js +68 -0
- package/dist/extension/worker-client.js +109 -0
- package/dist/extension/worker-ops.js +171 -0
- package/dist/extension/zip-writer.js +24 -0
- package/dist/external-files.js +878 -0
- package/dist/file-loader.js +436 -0
- package/dist/file-locations.js +439 -0
- package/dist/generated-wrappers.js +5 -0
- package/dist/github-auth.js +148 -0
- package/dist/github-urls.js +46 -0
- package/dist/gm-api-catalog.js +217 -0
- package/dist/gm-connect.js +273 -0
- package/dist/gm-xhr-types.js +5 -0
- package/dist/http-read.js +142 -0
- package/dist/icons/icon-128.png +0 -0
- package/dist/icons/icon-16.png +0 -0
- package/dist/icons/icon-48.png +0 -0
- package/dist/local-file-overrides.js +558 -0
- package/dist/manifest.json +38 -0
- package/dist/markup-response.js +126 -0
- package/dist/match-targets.js +305 -0
- package/dist/menu-captions.js +22 -0
- package/dist/offscreen.html +39 -0
- package/dist/options.html +197 -0
- package/dist/parse-check-protocol.js +51 -0
- package/dist/parse-location.js +171 -0
- package/dist/parse-sandbox.html +56 -0
- package/dist/phase-timing.js +155 -0
- package/dist/popup.html +197 -0
- package/dist/public-suffixes.js +6957 -0
- package/dist/run-context.js +31 -0
- package/dist/runtime-messages.js +34 -0
- package/dist/sandboxed-page.js +35 -0
- package/dist/script-build.js +787 -0
- package/dist/script-display.js +383 -0
- package/dist/script-icon.js +43 -0
- package/dist/script-links.js +204 -0
- package/dist/script-source-url.js +214 -0
- package/dist/script-world.js +65 -0
- package/dist/sm-dev-protocol.js +84 -0
- package/dist/source-map.js +177 -0
- package/dist/stack-link.js +138 -0
- package/dist/styles.css +825 -0
- package/dist/unsafe-window-use.js +229 -0
- package/dist/url-match.js +734 -0
- package/dist/userscript-header.js +248 -0
- package/dist/userscript.html +1165 -0
- package/dist/vendor/fflate.LICENSE +21 -0
- package/dist/vendor/fflate.js +2692 -0
- package/dist/vendor/prism/prism-line-numbers.css +1 -0
- package/dist/vendor/prism/prism-line-numbers.js +1 -0
- package/dist/vendor/prism/prism.css +1 -0
- package/dist/vendor/prism/prism.js +1946 -0
- package/dist/version-compare.js +141 -0
- package/dist/version-probe.js +120 -0
- package/lib/build-info.json +1 -0
- package/lib/bytes.d.ts +3 -0
- package/lib/bytes.js +37 -0
- package/lib/channel-placeholder.d.ts +1 -0
- package/lib/channel-placeholder.js +5 -0
- package/lib/collection-scan.d.ts +8 -0
- package/lib/collection-scan.js +17 -0
- package/lib/composed-source.d.ts +28 -0
- package/lib/composed-source.js +205 -0
- package/lib/debug-log.d.ts +9 -0
- package/lib/debug-log.js +75 -0
- package/lib/diagnostic-location.d.ts +8 -0
- package/lib/diagnostic-location.js +64 -0
- package/lib/eval-hook.d.ts +34 -0
- package/lib/eval-hook.js +308 -0
- package/lib/external-files.d.ts +111 -0
- package/lib/external-files.js +878 -0
- package/lib/file-loader.d.ts +48 -0
- package/lib/file-loader.js +436 -0
- package/lib/file-locations.d.ts +44 -0
- package/lib/file-locations.js +439 -0
- package/lib/generated-wrappers.d.ts +11 -0
- package/lib/generated-wrappers.js +5 -0
- package/lib/github-auth.d.ts +12 -0
- package/lib/github-auth.js +148 -0
- package/lib/github-urls.d.ts +1 -0
- package/lib/github-urls.js +46 -0
- package/lib/gm-api-catalog.d.ts +24 -0
- package/lib/gm-api-catalog.js +217 -0
- package/lib/gm-connect.d.ts +34 -0
- package/lib/gm-connect.js +273 -0
- package/lib/gm-xhr-types.d.ts +68 -0
- package/lib/gm-xhr-types.js +5 -0
- package/lib/harness/browser-extensions.d.ts +73 -0
- package/lib/harness/browser-extensions.js +285 -0
- package/lib/harness/browser-lang.d.ts +20 -0
- package/lib/harness/browser-lang.js +86 -0
- package/lib/harness/browser-launch.d.ts +14 -0
- package/lib/harness/browser-launch.js +184 -0
- package/lib/harness/checks.d.ts +110 -0
- package/lib/harness/checks.js +321 -0
- package/lib/harness/cli.d.ts +2 -0
- package/lib/harness/cli.js +2259 -0
- package/lib/harness/command-args.d.ts +91 -0
- package/lib/harness/command-args.js +369 -0
- package/lib/harness/command-lines.d.ts +80 -0
- package/lib/harness/command-lines.js +180 -0
- package/lib/harness/command-list.d.ts +206 -0
- package/lib/harness/command-list.js +1475 -0
- package/lib/harness/console-commands.d.ts +463 -0
- package/lib/harness/console-commands.js +3216 -0
- package/lib/harness/download-watch.d.ts +21 -0
- package/lib/harness/download-watch.js +156 -0
- package/lib/harness/extension-backend.d.ts +41 -0
- package/lib/harness/extension-backend.js +100 -0
- package/lib/harness/extension-host.d.ts +112 -0
- package/lib/harness/extension-host.js +552 -0
- package/lib/harness/extension-launch.d.ts +67 -0
- package/lib/harness/extension-launch.js +285 -0
- package/lib/harness/extension-link.d.ts +315 -0
- package/lib/harness/extension-link.js +607 -0
- package/lib/harness/external-manager.d.ts +146 -0
- package/lib/harness/external-manager.js +414 -0
- package/lib/harness/fixture.d.ts +165 -0
- package/lib/harness/fixture.js +461 -0
- package/lib/harness/frame-sessions.d.ts +71 -0
- package/lib/harness/frame-sessions.js +248 -0
- package/lib/harness/frames.d.ts +68 -0
- package/lib/harness/frames.js +216 -0
- package/lib/harness/help-format.d.ts +17 -0
- package/lib/harness/help-format.js +127 -0
- package/lib/harness/host.d.ts +352 -0
- package/lib/harness/host.js +423 -0
- package/lib/harness/index.d.ts +8 -0
- package/lib/harness/index.js +10 -0
- package/lib/harness/input-file.d.ts +18 -0
- package/lib/harness/input-file.js +61 -0
- package/lib/harness/json-output.d.ts +565 -0
- package/lib/harness/json-output.js +71 -0
- package/lib/harness/manager-actions.d.ts +21 -0
- package/lib/harness/manager-actions.js +129 -0
- package/lib/harness/manager-commands.d.ts +142 -0
- package/lib/harness/manager-commands.js +1196 -0
- package/lib/harness/manager-fetch.d.ts +33 -0
- package/lib/harness/manager-fetch.js +239 -0
- package/lib/harness/managers.d.ts +24 -0
- package/lib/harness/managers.js +27 -0
- package/lib/harness/output-style.d.ts +125 -0
- package/lib/harness/output-style.js +322 -0
- package/lib/harness/page-commands.d.ts +134 -0
- package/lib/harness/page-commands.js +1141 -0
- package/lib/harness/page-output.d.ts +67 -0
- package/lib/harness/page-output.js +139 -0
- package/lib/harness/page-watch.d.ts +171 -0
- package/lib/harness/page-watch.js +607 -0
- package/lib/harness/parse-check-node.d.ts +3 -0
- package/lib/harness/parse-check-node.js +132 -0
- package/lib/harness/path-args.d.ts +22 -0
- package/lib/harness/path-args.js +148 -0
- package/lib/harness/playwright-chromium.d.ts +16 -0
- package/lib/harness/playwright-chromium.js +86 -0
- package/lib/harness/prepare.d.ts +168 -0
- package/lib/harness/prepare.js +364 -0
- package/lib/harness/prompt-editor.d.ts +17 -0
- package/lib/harness/prompt-editor.js +354 -0
- package/lib/harness/prompt-history.d.ts +13 -0
- package/lib/harness/prompt-history.js +89 -0
- package/lib/harness/rebuild-advice.d.ts +6 -0
- package/lib/harness/rebuild-advice.js +39 -0
- package/lib/harness/run-log.d.ts +47 -0
- package/lib/harness/run-log.js +140 -0
- package/lib/harness/run-logs.d.ts +132 -0
- package/lib/harness/run-logs.js +241 -0
- package/lib/harness/run.d.ts +194 -0
- package/lib/harness/run.js +1973 -0
- package/lib/harness/runs.d.ts +229 -0
- package/lib/harness/runs.js +726 -0
- package/lib/harness/save-html.d.ts +39 -0
- package/lib/harness/save-html.js +89 -0
- package/lib/harness/saved-pages.d.ts +120 -0
- package/lib/harness/saved-pages.js +275 -0
- package/lib/harness/script-mark.d.ts +17 -0
- package/lib/harness/script-mark.js +56 -0
- package/lib/harness/snapshot.d.ts +143 -0
- package/lib/harness/snapshot.js +474 -0
- package/lib/harness/stuck-tabs.d.ts +19 -0
- package/lib/harness/stuck-tabs.js +131 -0
- package/lib/harness/tab-refs.d.ts +20 -0
- package/lib/harness/tab-refs.js +80 -0
- package/lib/harness/tampermonkey.d.ts +71 -0
- package/lib/harness/tampermonkey.js +356 -0
- package/lib/harness/tm-ids.d.ts +18 -0
- package/lib/harness/tm-ids.js +88 -0
- package/lib/harness/violentmonkey.d.ts +34 -0
- package/lib/harness/violentmonkey.js +162 -0
- package/lib/harness/wait.d.ts +77 -0
- package/lib/harness/wait.js +458 -0
- package/lib/http-read.d.ts +30 -0
- package/lib/http-read.js +142 -0
- package/lib/local-file-overrides.d.ts +35 -0
- package/lib/local-file-overrides.js +558 -0
- package/lib/manifest.json +38 -0
- package/lib/markup-response.d.ts +11 -0
- package/lib/markup-response.js +126 -0
- package/lib/match-targets.d.ts +18 -0
- package/lib/match-targets.js +305 -0
- package/lib/menu-captions.d.ts +1 -0
- package/lib/menu-captions.js +22 -0
- package/lib/parse-check-protocol.d.ts +27 -0
- package/lib/parse-check-protocol.js +51 -0
- package/lib/parse-location.d.ts +12 -0
- package/lib/parse-location.js +171 -0
- package/lib/phase-timing.d.ts +12 -0
- package/lib/phase-timing.js +155 -0
- package/lib/public-suffixes.d.ts +1 -0
- package/lib/public-suffixes.js +6957 -0
- package/lib/run-context.d.ts +2 -0
- package/lib/run-context.js +31 -0
- package/lib/runtime-messages.d.ts +10 -0
- package/lib/runtime-messages.js +34 -0
- package/lib/sandboxed-page.d.ts +5 -0
- package/lib/sandboxed-page.js +35 -0
- package/lib/script-build.d.ts +111 -0
- package/lib/script-build.js +787 -0
- package/lib/script-display.d.ts +51 -0
- package/lib/script-display.js +383 -0
- package/lib/script-icon.d.ts +16 -0
- package/lib/script-icon.js +43 -0
- package/lib/script-links.d.ts +24 -0
- package/lib/script-links.js +204 -0
- package/lib/script-source-url.d.ts +8 -0
- package/lib/script-source-url.js +214 -0
- package/lib/script-world.d.ts +6 -0
- package/lib/script-world.js +65 -0
- package/lib/sm-dev-protocol.d.ts +251 -0
- package/lib/sm-dev-protocol.js +84 -0
- package/lib/source-map.d.ts +32 -0
- package/lib/source-map.js +177 -0
- package/lib/stack-link.d.ts +15 -0
- package/lib/stack-link.js +138 -0
- package/lib/unsafe-window-use.d.ts +1 -0
- package/lib/unsafe-window-use.js +229 -0
- package/lib/url-match.d.ts +40 -0
- package/lib/url-match.js +734 -0
- package/lib/userscript-header.d.ts +33 -0
- package/lib/userscript-header.js +248 -0
- package/lib/version-compare.d.ts +6 -0
- package/lib/version-compare.js +141 -0
- package/lib/version-probe.d.ts +17 -0
- package/lib/version-probe.js +120 -0
- package/package.json +55 -3
- package/skills/SourceMonkey-dev/SKILL.md +868 -0
- package/skills/SourceMonkey-dev/references/cdp.md +293 -0
- package/skills/SourceMonkey-dev/references/commands.md +297 -0
- package/skills/SourceMonkey-dev/references/other-managers.md +63 -0
- package/skills/SourceMonkey-dev/references/specs.md +46 -0
- package/skills/SourceMonkey-friction/SKILL.md +103 -0
- package/skills/SourceMonkey-friction/references/template.md +59 -0
|
@@ -0,0 +1,868 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: SourceMonkey-dev
|
|
3
|
+
description: Develop, debug and test userscripts with SourceMonkey's sm-dev tool and Playwright harness. Run a script in a real browser behind real GM_* APIs, drive and inspect the page, read the script's state, work from saved pages, go beyond sm-dev over raw CDP, and turn the result into specs. Use when writing, debugging or testing a userscript in a repo with the `sourcemonkey` dev dependency.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Userscript development with SourceMonkey
|
|
7
|
+
|
|
8
|
+
## What this is
|
|
9
|
+
|
|
10
|
+
- **SourceMonkey** is a Chrome userscript manager (like Tampermonkey).
|
|
11
|
+
It ships as a dev dependency, `sourcemonkey`, with its built
|
|
12
|
+
extension and install checks, so tests and tools use the manager's
|
|
13
|
+
real behavior instead of stubs.
|
|
14
|
+
- **`sm-dev`** (`pnpm sm-dev ...`; `scripts/sm-dev` in a SourceMonkey
|
|
15
|
+
checkout) is the interactive tool. It starts a
|
|
16
|
+
**run**: a background process that connects to a Chromium over CDP
|
|
17
|
+
(Chrome DevTools Protocol), pushes your scripts as they are on disk
|
|
18
|
+
into the SourceMonkey extension there, opens tabs, and streams what
|
|
19
|
+
the scripts do and log. You send the run commands to drive and read
|
|
20
|
+
the page.
|
|
21
|
+
- **The Playwright fixture** (`import { test, expect } from
|
|
22
|
+
'sourcemonkey/harness'`) runs scripts in specs, also in the real
|
|
23
|
+
SourceMonkey extension.
|
|
24
|
+
- So header rules, `@grant`, `@require`, `@run-at`, worlds, `GM_*`
|
|
25
|
+
storage and `GM_xmlhttpRequest` behave as they will for users (see
|
|
26
|
+
[How a run uses the extension](#how-a-run-uses-the-extension)).
|
|
27
|
+
- **A run can use Tampermonkey or Violentmonkey instead**: to check a
|
|
28
|
+
script is portable across managers, or to debug something that works
|
|
29
|
+
in one but not another. sm-dev downloads either. See
|
|
30
|
+
[Testing under other managers](#testing-under-other-managers).
|
|
31
|
+
- **The browser's CDP port stays open** to you as well.
|
|
32
|
+
- Anything sm-dev has no command for (back button, window size, mouse
|
|
33
|
+
wheel, drag), do over CDP directly, in the same tab, while
|
|
34
|
+
the run goes on.
|
|
35
|
+
- `$R cdp` sends raw calls to a tab. See
|
|
36
|
+
[Beyond sm-dev: raw CDP](#beyond-sm-dev-raw-cdp).
|
|
37
|
+
|
|
38
|
+
Paths below like `references/...` are relative
|
|
39
|
+
to this skill's directory (where this `SKILL.md` is, for example
|
|
40
|
+
`.claude/skills/SourceMonkey-dev/`).
|
|
41
|
+
|
|
42
|
+
Where to look:
|
|
43
|
+
|
|
44
|
+
- [references/commands.md](references/commands.md): the commands,
|
|
45
|
+
grouped by task.
|
|
46
|
+
- [references/cdp.md](references/cdp.md): raw CDP recipes.
|
|
47
|
+
- [references/specs.md](references/specs.md): writing Playwright specs
|
|
48
|
+
with the harness fixture.
|
|
49
|
+
- [references/other-managers.md](references/other-managers.md): testing
|
|
50
|
+
under Violentmonkey.
|
|
51
|
+
- `pnpm sm-dev help`: the authoritative, current reference. Alone it
|
|
52
|
+
lists the topics; `help <topic>`, `help <command>` or
|
|
53
|
+
`help <command> <subcommand>` (`help script save`) shows one,
|
|
54
|
+
`help commands` lists the commands, and `help all` everything.
|
|
55
|
+
- The `SourceMonkey-friction` skill, when installed: log where these
|
|
56
|
+
tools got in the way once the task is done.
|
|
57
|
+
- Full docs, when the above isn't enough:
|
|
58
|
+
[harness-guide.md](https://github.com/jshute96/SourceMonkey/blob/main/docs/harness-guide.md).
|
|
59
|
+
Long; search it rather than reading it through.
|
|
60
|
+
|
|
61
|
+
## Rules that save the most time
|
|
62
|
+
|
|
63
|
+
- **Never `sleep`.** Commands that act (`start`, `click`, `key`,
|
|
64
|
+
`type`, `reload`, `open`, `newtab`) return once the page has settled:
|
|
65
|
+
loaded, scripts started, no requests or DOM changes for a moment.
|
|
66
|
+
For anything later, wait for the signal itself: `wait log <text>`,
|
|
67
|
+
`wait selector <css>`, `wait selector-gone <css>`.
|
|
68
|
+
- Waits give up after 5 seconds (page loads: 30). Pass
|
|
69
|
+
`--timeout-seconds S` to any command that waits, after the command
|
|
70
|
+
name (`wait selector .x --timeout-seconds 20`), for a slow site, and keep
|
|
71
|
+
S under your shell tool's own time limit.
|
|
72
|
+
- With no signal to wait for (sampling something over time), use
|
|
73
|
+
`wait 2s`, not `sleep`.
|
|
74
|
+
- **Don't use `--stop-after-seconds`.** A run that expires mid-test leaves pages
|
|
75
|
+
with no script, and results that look like bugs. Use `--detach`, and
|
|
76
|
+
`stop` when done.
|
|
77
|
+
- **Name your run**: `pnpm sm-dev --run Dagent start ... --detach`,
|
|
78
|
+
then `--run Dagent` on each command. Run IDs start with `D`.
|
|
79
|
+
- The person may have runs of their own. `start --detach` without
|
|
80
|
+
`--run` stops earlier detached runs, and with several runs active,
|
|
81
|
+
commands without `--run` are refused (`status` and `list` show them all).
|
|
82
|
+
- Find and end runs with `sm-dev list` and `sm-dev stop <ID>`, never
|
|
83
|
+
`pkill`.
|
|
84
|
+
- **Name tabs by `T<n>` or `targetId`, never by URL.** Two tabs on the
|
|
85
|
+
same page are common, and acting on the wrong one looks like the
|
|
86
|
+
script didn't run.
|
|
87
|
+
- **Read the run's output before theorizing.** It says whether the
|
|
88
|
+
script started, was skipped (and which header rule decided), or
|
|
89
|
+
threw, with file and line.
|
|
90
|
+
- **Write scripts as they ship.** No guards for missing `GM_*`, no
|
|
91
|
+
test-only branches: they run in the real manager.
|
|
92
|
+
- **Real sites have real data.** Only do reversible actions on
|
|
93
|
+
account or shopping pages, and never submit or save. Use a saved
|
|
94
|
+
page when that isn't enough.
|
|
95
|
+
- The `--open-browser` browser may be signed in to the person's
|
|
96
|
+
accounts. Stay read-only there: don't change any data or settings,
|
|
97
|
+
or do anything else with side effects.
|
|
98
|
+
|
|
99
|
+
## Getting a browser
|
|
100
|
+
|
|
101
|
+
A line picks one browser mode:
|
|
102
|
+
|
|
103
|
+
- `pnpm sm-dev start ...` (the default): a temp, throwaway
|
|
104
|
+
browser for that run, on a random port, closed when the run ends,
|
|
105
|
+
with SourceMonkey loaded and ready. Good for pages with no login. Its
|
|
106
|
+
profile is empty. Hidden, unless the line goes to a prompt;
|
|
107
|
+
`--headed` or `--headless` says outright. Like the other browser
|
|
108
|
+
options, they go before the command: `pnpm sm-dev --headed start ...`.
|
|
109
|
+
- `pnpm sm-dev --open-browser`: a visible browser on port 9233 (or
|
|
110
|
+
`--browser PORT`) that stays open, with a kept profile, so sign-ins
|
|
111
|
+
persist. Use it for sites that need a login; ask the person to sign
|
|
112
|
+
in there. A no-op if one is already up. Then pass `--open-browser`
|
|
113
|
+
(or `--existing-browser`) to the `start` that uses it.
|
|
114
|
+
- `--existing-browser`: connect to the browser already on port 9233
|
|
115
|
+
(or `--browser PORT`), such as the person's own. Their tabs are left
|
|
116
|
+
alone, and only the run's own tabs are touched.
|
|
117
|
+
|
|
118
|
+
The run needs SourceMonkey in the browser, with "Allow User Scripts" on.
|
|
119
|
+
|
|
120
|
+
- A temp browser always has it. An `--open-browser` or
|
|
121
|
+
`--existing-browser` browser needs it loaded once:
|
|
122
|
+
`pnpm sm-dev --existing-browser manager install` loads it, with
|
|
123
|
+
"Allow User Scripts" on.
|
|
124
|
+
- The run's first line (`Connected to browser ... (Chrome ..., has
|
|
125
|
+
SourceMonkey)`) and `status` say which: `has SourceMonkey`,
|
|
126
|
+
`SourceMonkey disabled` or `no SourceMonkey`. `status` also lists the
|
|
127
|
+
browser's managers, marking one whose "Allow User Scripts" is off.
|
|
128
|
+
- When it is missing, use a temp browser if no login is needed.
|
|
129
|
+
Otherwise ask the person whether to install it into their browser
|
|
130
|
+
with `manager install`, or `manager enable` if it's disabled.
|
|
131
|
+
- Another manager enabled there (Tampermonkey, Violentmonkey) runs its
|
|
132
|
+
scripts in the run's tabs too. The run's first lines and `status`
|
|
133
|
+
warn of it: ask the person before turning it off with
|
|
134
|
+
`pnpm sm-dev --existing-browser --manager tm manager disable`.
|
|
135
|
+
|
|
136
|
+
A headless temp browser is often blocked by large sites (Reddit,
|
|
137
|
+
Google, Amazon, Vimeo, IMDb, parts of YouTube).
|
|
138
|
+
|
|
139
|
+
- The block page still loads, so `start` reports the script as
|
|
140
|
+
started on it. Check the page (`eval document.title`, `screenshot`)
|
|
141
|
+
before believing a result.
|
|
142
|
+
- Use `--open-browser` for those sites from the start.
|
|
143
|
+
|
|
144
|
+
In the shared `--open-browser` browser:
|
|
145
|
+
|
|
146
|
+
- Its background tabs are throttled, and a hidden tab can make
|
|
147
|
+
`click` fail. `focus` brings the run's tab to the front.
|
|
148
|
+
- `stop` leaves the run's tabs open. `closetab all` first.
|
|
149
|
+
|
|
150
|
+
## The core loop
|
|
151
|
+
|
|
152
|
+
```sh
|
|
153
|
+
R="pnpm sm-dev --run Dagent"
|
|
154
|
+
|
|
155
|
+
$R validate sites/x/y.user.js # header, @require, syntax (see below)
|
|
156
|
+
$R match sites/x/y.user.js https://x.com/some/page # would it run there, and why
|
|
157
|
+
$R start sites/x/y.user.js https://x.com/some/page --watch --detach
|
|
158
|
+
$R status # tabs, scripts, what's active
|
|
159
|
+
# ... drive and read the page (recipes below) ...
|
|
160
|
+
# ... edit and save: --watch re-pushes and reloads the affected tabs ...
|
|
161
|
+
$R stop
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
- `start --detach` returns once the page has settled, printing the
|
|
165
|
+
run's startup output: whether the script started, and what it
|
|
166
|
+
logged.
|
|
167
|
+
- Each later command prints its own output, including what the page
|
|
168
|
+
and scripts logged during it, and exits.
|
|
169
|
+
- After a save, the next command's output shows the reload and the
|
|
170
|
+
script's fresh startup lines. Without `--watch`, run `update`.
|
|
171
|
+
- The run's full stream, with timestamps, is in its log file. `status`
|
|
172
|
+
shows the path; `<ID>.log` beside it links to the run's latest.
|
|
173
|
+
|
|
174
|
+
What the stream looks like:
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
[sm-dev] Pushed to SourceMonkey: sites/x/y.user.js
|
|
178
|
+
[sm-dev] Opening https://x.com/some/page in T1 [targetId=61023580282B1D684FAF4072C201AB51]
|
|
179
|
+
[event] Y started on https://x.com/some/page
|
|
180
|
+
[script log] [y] toolbar found, button inserted
|
|
181
|
+
[event] GM_setValue lastItem = "42"
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
- Each line's prefix is its log source, narrowest first:
|
|
185
|
+
- `[sm error]` (or `info`, `warning`): SourceMonkey logs, as the
|
|
186
|
+
script's Log tab shows them;
|
|
187
|
+
- `[event]`: script and tab events: started, threw, page loads (in
|
|
188
|
+
`logs`), tabs opened and closed, dialog boxes, and some `GM_*`
|
|
189
|
+
calls (requests, downloads, menu commands, notifications, values
|
|
190
|
+
set or deleted);
|
|
191
|
+
- `[script log]`: Chrome console logs from the script, by its stack,
|
|
192
|
+
so a page helper it calls counts;
|
|
193
|
+
- `[page log]`, `[page error]`: the rest of Chrome's console, hidden
|
|
194
|
+
by default.
|
|
195
|
+
- A line can be in multiple sources: `--log-source page` shows all
|
|
196
|
+
the page's console, the script's lines too, and `[event] X threw`
|
|
197
|
+
also counts as `sm`, `script` and `page`.
|
|
198
|
+
- `[sm-dev]` lines are sm-dev's own notices.
|
|
199
|
+
- Lines from other tabs are prefixed with `[T2]`.
|
|
200
|
+
- A DOM node logged to the console prints as its opening tag,
|
|
201
|
+
`<div id="x" class="a b">`, cut at 120 characters.
|
|
202
|
+
- The site's own lines are hidden. Add `--log-source all` to `start`
|
|
203
|
+
when the script may be breaking the page, or runs code outside its
|
|
204
|
+
file (an added `<script>`, `eval`). `logs --log-source all` reads
|
|
205
|
+
them back afterwards.
|
|
206
|
+
- For a script that acts on the site's or browser's language, add
|
|
207
|
+
`--lang zh-CN` (or `--lang zh-CN,en`) to `start`: the run's tabs then
|
|
208
|
+
report it in `navigator.language(s)`, `Accept-Language` and `Intl`.
|
|
209
|
+
In a connected browser, cross-site iframes and workers keep the
|
|
210
|
+
browser's languages; use a temp browser for a script in frames.
|
|
211
|
+
|
|
212
|
+
A person at a terminal can use `pnpm sm-dev start ...` with no commands
|
|
213
|
+
after `start` for an interactive prompt. An agent should use `--detach`
|
|
214
|
+
and separate commands.
|
|
215
|
+
|
|
216
|
+
## Recipes
|
|
217
|
+
|
|
218
|
+
### Checking the header and script: `validate`
|
|
219
|
+
|
|
220
|
+
Run it after any edit, before loading the script anywhere. It is fast,
|
|
221
|
+
needs no browser or run, and runs the extension's own install checks:
|
|
222
|
+
the metadata block, `@match` / `@include`, `@require` loading (local
|
|
223
|
+
copies included), and a syntax check of the body.
|
|
224
|
+
|
|
225
|
+
```sh
|
|
226
|
+
$R validate sites/x/y.user.js
|
|
227
|
+
$R validate sites/x/ # all scripts under a directory
|
|
228
|
+
$R validate 'sites/**/*.user.js' # or a glob (quoted: sm-dev expands it)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
INVALID sites/x/bad.user.js
|
|
233
|
+
Syntax error: Unexpected token ';' (in sites/x/bad.user.js, line 5, column 11)
|
|
234
|
+
ok sites/x/y.user.js
|
|
235
|
+
warn: Ignoring unsupported @grant GM_frobnicate (in sites/x/y.user.js, line 6)
|
|
236
|
+
|
|
237
|
+
1 ok, 1 invalid
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
- Exit code 1 when any script is invalid, so it works as a gate.
|
|
241
|
+
- The message is the one the extension's viewer would show, with the
|
|
242
|
+
file and line. A script with no `@match` or `@include` is invalid
|
|
243
|
+
(it would never run).
|
|
244
|
+
- `warn:` lines don't make it invalid, but read them. An unsupported
|
|
245
|
+
or misspelled `@grant` is ignored, so that `GM_*` name won't exist
|
|
246
|
+
at runtime.
|
|
247
|
+
- `UNCHECKED` means the syntax check couldn't finish (e.g. very deep
|
|
248
|
+
nesting). The script still loads and the exit code is 0, but its
|
|
249
|
+
syntax wasn't verified.
|
|
250
|
+
- An invalid script is refused by `start` and `loadUserscript` with the
|
|
251
|
+
same message, so fixing it here saves a failed run.
|
|
252
|
+
- It doesn't check that `@grant` covers every `GM_*` the code calls; a
|
|
253
|
+
missing one shows up at runtime as `GM_x is not defined`.
|
|
254
|
+
- In a run, `validate` re-reads the selected script from disk, and
|
|
255
|
+
`validate all` checks all loaded scripts.
|
|
256
|
+
- Over many scripts, list only the ones that need a look:
|
|
257
|
+
`$R --json validate sites/ | jq -c '.results[] | select(.verdict != "ok" or .warnings)'`.
|
|
258
|
+
|
|
259
|
+
### Does the script run on this page?
|
|
260
|
+
|
|
261
|
+
```sh
|
|
262
|
+
$R match sites/x/y.user.js https://x.com/a https://x.com/b
|
|
263
|
+
$R start sites/x/y.user.js https://x.com/a --detach
|
|
264
|
+
$R status
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
- `match` names the rule that matched or excluded each URL. It is
|
|
268
|
+
cheap: run it after any header edit.
|
|
269
|
+
- `status` shows each script as `Active` or `Not active` on the current
|
|
270
|
+
tab, and the other tabs and frames it runs on.
|
|
271
|
+
- On a single-page app the URL can change without a load. `match` in a
|
|
272
|
+
run (no arguments) checks the selected script against the current
|
|
273
|
+
tab's URL now.
|
|
274
|
+
- A script also runs in each iframe whose own URL it matches; see
|
|
275
|
+
[Scripts in iframes](#scripts-in-iframes).
|
|
276
|
+
|
|
277
|
+
### Finding selectors
|
|
278
|
+
|
|
279
|
+
```sh
|
|
280
|
+
$R snapshot --visible # what's on screen, one line per element, with refs
|
|
281
|
+
$R snapshot --find 'Liked Songs' --context # only elements containing that, with their wrapper divs
|
|
282
|
+
$R probe --css e14 # a short unique CSS selector for a ref
|
|
283
|
+
$R probe --css --html '.titleline > a' # selector + HTML for the first 10 matches
|
|
284
|
+
$R probe '.title a' '[data-testid=post]' '#missing' # which match, how many
|
|
285
|
+
$R click e14 # refs work anywhere a selector does
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
- `snapshot` is the accessibility tree: roles, names, and a ref like
|
|
289
|
+
`e14`, or `f2e6` with a frame number. `snapshot <selector>` shows
|
|
290
|
+
each of its matches (the first 5; `--limit 0` for all); `--out file`
|
|
291
|
+
saves a large one.
|
|
292
|
+
- When you know some text on the page (from a screenshot, the person,
|
|
293
|
+
or an earlier look), use `snapshot --find <text>` instead of a full
|
|
294
|
+
snapshot piped to `grep`. It shows the matching elements with refs.
|
|
295
|
+
- With a selector, it looks only within the selector's matches.
|
|
296
|
+
- `--context` adds the wrapper divs and small containers around each
|
|
297
|
+
match (of `--find` or a selector); `--up N` climbs N levels.
|
|
298
|
+
- Refs only last until the page changes: take a new snapshot after a
|
|
299
|
+
reload or navigation. Refs from `snapshot <selector>` and from the
|
|
300
|
+
whole page both work.
|
|
301
|
+
- `snapshot` includes panels a script adds after `<body>` and inside
|
|
302
|
+
open shadow roots.
|
|
303
|
+
- `probe --css` skips ids and classes that look generated
|
|
304
|
+
(`css-1x2y3z`). Elements inside a shadow root or frame get no
|
|
305
|
+
selector; use the ref.
|
|
306
|
+
- Prefer selectors that describe purpose: ids and `data-*` the site
|
|
307
|
+
put there, then meaningful class prefixes and `aria-label`, then
|
|
308
|
+
role plus text. Avoid layout and SVG geometry.
|
|
309
|
+
- Verify the selector you'll put in the script with `probe` (count),
|
|
310
|
+
then `eval` for its content:
|
|
311
|
+
`$R eval "[...document.querySelectorAll('.titleline > a')].map(a => a.href).slice(0, 5)"`.
|
|
312
|
+
- Capture the states the script will walk before writing it: open each
|
|
313
|
+
menu or popup (`click`), then `snapshot` or `probe --html` again.
|
|
314
|
+
Menus often replace each other, and attributes like `aria-controls`
|
|
315
|
+
often exist only while open.
|
|
316
|
+
|
|
317
|
+
### Driving an interaction and checking the result
|
|
318
|
+
|
|
319
|
+
```sh
|
|
320
|
+
$R click '[aria-label="Next"]'
|
|
321
|
+
$R click e14 --button right # also middle; --modifiers Shift+Control
|
|
322
|
+
$R click '.word' --count 2 # double-click (3: triple)
|
|
323
|
+
$R key j j Shift+ArrowRight
|
|
324
|
+
$R type 'input[name=q]' 'hello world'
|
|
325
|
+
$R hover '.card:first-child'
|
|
326
|
+
$R wait selector '.result' # when the result comes later than the settle
|
|
327
|
+
$R eval 'document.querySelector(".result")?.textContent'
|
|
328
|
+
$R screenshot shot.png # then look at the PNG
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
- Clicks, hovers and keys are real input (scrolled into view, trusted
|
|
332
|
+
events), so the page can't tell them from a person's.
|
|
333
|
+
- A `click` or `hover` that fails says why: the element stayed hidden,
|
|
334
|
+
disabled or moving, or another element covered it (named). Fix that
|
|
335
|
+
(hover first, wait, close the overlay) rather than clicking its
|
|
336
|
+
pixels over `cdp`, which skips those checks.
|
|
337
|
+
- `--at x,y` clicks or hovers at a point in the element (pixels from
|
|
338
|
+
its top left corner), for a spot other than its center, e.g. a row's
|
|
339
|
+
empty space rather than the link in its middle. `hover` takes
|
|
340
|
+
`--modifiers` too.
|
|
341
|
+
- A scroll from `eval` (`scrollIntoView`, `scrollBy`) fires no
|
|
342
|
+
`wheel` event, so a script that watches for the user scrolling won't
|
|
343
|
+
see it. Send a real wheel event over `cdp` (see
|
|
344
|
+
[Mouse wheel](references/cdp.md#mouse-wheel)).
|
|
345
|
+
- Keys go to the page, not to Chrome: Chrome's shortcuts (back, reload,
|
|
346
|
+
zoom, Escape leaving fullscreen) don't fire.
|
|
347
|
+
- A command that opens a dialog (`alert`, `confirm`, `prompt`) returns
|
|
348
|
+
once it's up. Answer with `accept [tab] [text]` or `dismiss [tab]`;
|
|
349
|
+
until then the page is frozen, and most commands refuse.
|
|
350
|
+
- A `*PERMISSION PROMPT*` line needs an answer before that request
|
|
351
|
+
goes on: see [Permission prompts](#permission-prompts).
|
|
352
|
+
- `logs` reads the run's log back for the tab: its script's lines and
|
|
353
|
+
events, timestamped. `logs all`, `logs 2` (one script),
|
|
354
|
+
`--log-source all` (the site's own too), `--find <text|/re/>`,
|
|
355
|
+
`--tail 50` or `--tail 30s`.
|
|
356
|
+
- It ends with `Logs up to <log ID>`; pass that to `--since` next
|
|
357
|
+
time to read only what came after.
|
|
358
|
+
- Quoting: quote selectors with spaces or `#` for the shell
|
|
359
|
+
(`click '#submit'`).
|
|
360
|
+
|
|
361
|
+
### Seeing into the script: debug state and logging
|
|
362
|
+
|
|
363
|
+
`eval` runs inside the selected script (`--script=<script>` names
|
|
364
|
+
another), so it sees what the script's own code sees:
|
|
365
|
+
|
|
366
|
+
```sh
|
|
367
|
+
$R eval 'GM_info.script.version'
|
|
368
|
+
$R eval 'GM_getValue("prefs")'
|
|
369
|
+
$R eval 'config.mode' # a top-level const of the script
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
- That covers the script's `GM_*` functions, its `@require`
|
|
373
|
+
libraries, its top-level declarations, and its world's globals.
|
|
374
|
+
- A script that opens with a `(function () { ... })()` wrapper (or an
|
|
375
|
+
arrow or `async` one) gets it inside that wrapper, so its locals
|
|
376
|
+
there are in reach too.
|
|
377
|
+
- Locals inside other functions aren't. Expose them on `window`
|
|
378
|
+
(below).
|
|
379
|
+
- Use `eval --page` for the page's own globals (its `$`, an app's
|
|
380
|
+
state object) as the page sees them. An isolated script can't see
|
|
381
|
+
them, and a sandboxed one (below) may have its own `$` from a
|
|
382
|
+
`@require`.
|
|
383
|
+
|
|
384
|
+
For state inside other functions, expose state and functions on
|
|
385
|
+
`window`. Build this in while developing; it's cheap and can stay:
|
|
386
|
+
|
|
387
|
+
```js
|
|
388
|
+
const state = { slide: 0, zoom: 1 };
|
|
389
|
+
window.myScript = { state, currentSlide, relayout }; // for eval
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
```sh
|
|
393
|
+
$R eval 'myScript.state' # printed as JSON
|
|
394
|
+
$R eval 'myScript.currentSlide()'
|
|
395
|
+
$R eval 'myScript.relayout(); myScript.state'
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
- Unless the script has `@grant none` (no `@grant` line counts as
|
|
399
|
+
sandboxed too), its `window` is its own sandbox, as in Tampermonkey
|
|
400
|
+
and Violentmonkey, so a `window` property there is private to the
|
|
401
|
+
script.
|
|
402
|
+
- The sandbox shows only the browser's built-ins. Read the page's
|
|
403
|
+
globals by bare name (`$`, `appState`) or as `unsafeWindow.x`;
|
|
404
|
+
`window.x` is `undefined` for them.
|
|
405
|
+
- A `@grant none` script shares the page's `window`: pick a name the
|
|
406
|
+
site won't collide with. `eval --page` reaches it too.
|
|
407
|
+
|
|
408
|
+
Log what happens, and wait for it instead of sleeping:
|
|
409
|
+
|
|
410
|
+
```js
|
|
411
|
+
const log = (...args) => console.log('[my-script]', ...args);
|
|
412
|
+
log('applied preset', name);
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
```sh
|
|
416
|
+
$R click '.apply' -- wait log 'applied preset'
|
|
417
|
+
$R wait log '/saved record \d+/' # a regex
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
- `wait log` also matches lines printed since the previous command
|
|
421
|
+
began, so a line printed during the click counts.
|
|
422
|
+
- It sees every log source, including the site's own lines the stream
|
|
423
|
+
leaves out. Each is matched as the stream would print it:
|
|
424
|
+
`[page log] KEYUP 143`. `--log-source script,event` narrows it.
|
|
425
|
+
- It ends with `Found at <log ID>`, which `--since` takes.
|
|
426
|
+
- So a loose pattern (`error`, `done`) can match the site's own lines;
|
|
427
|
+
use the script's `[name]` prefix or a regex.
|
|
428
|
+
- A command returns once the page settles, which can come before a
|
|
429
|
+
script's delayed setup (a timer, a retry loop). `wait log` for the
|
|
430
|
+
script's own ready line before driving it.
|
|
431
|
+
- Errors a script throws later, from events and timers, show in the
|
|
432
|
+
output of whatever command was running, or only in `logs` if none
|
|
433
|
+
was. Check `logs` before calling a script clean.
|
|
434
|
+
- With several runs or long sessions, `logs --since <position>` from
|
|
435
|
+
the previous `Logs up to` reads only what's new.
|
|
436
|
+
- `GM_log` goes to the page console and the script's Log tab, so it
|
|
437
|
+
shows twice: `[script log] [SourceMonkey:...] ...` and
|
|
438
|
+
`[sm info] <name>: ...`.
|
|
439
|
+
- Async work fired from an event handler: have it log on completion
|
|
440
|
+
and `wait log` for that, rather than polling the DOM for a state
|
|
441
|
+
that may be intermediate.
|
|
442
|
+
|
|
443
|
+
Gate chatty logging on a stored value, so it can be switched live:
|
|
444
|
+
|
|
445
|
+
```js
|
|
446
|
+
let debug = GM_getValue('debug', false); // @grant GM_getValue
|
|
447
|
+
GM_addValueChangeListener('debug', (key, old, value) => { debug = value; });
|
|
448
|
+
const trace = (...args) => debug && console.log('[my-script]', ...args);
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
```sh
|
|
452
|
+
$R start sites/x/y.user.js --values '{"debug": true}' --detach # on from the start
|
|
453
|
+
$R set debug true # or flip it live
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
- `set` writes as another tab would, so the change listener fires.
|
|
457
|
+
- For state a spec should read too, mirror it into the DOM:
|
|
458
|
+
`document.documentElement.dataset.myScriptZoom = zoom`. Then
|
|
459
|
+
`eval document.documentElement.dataset` or a Playwright locator reads
|
|
460
|
+
it.
|
|
461
|
+
|
|
462
|
+
### Menu commands and stored values
|
|
463
|
+
|
|
464
|
+
```sh
|
|
465
|
+
$R menu # the tab's commands: M1, M2 ...
|
|
466
|
+
$R menu 'Toggle dark' # fire by label (or: menu M1)
|
|
467
|
+
$R menu 'Run this script' # run a @run-at context-menu script (again)
|
|
468
|
+
$R values # what the scripts stored
|
|
469
|
+
$R get lastItem
|
|
470
|
+
$R set units '"metric"' # JSON; running scripts' change listeners fire
|
|
471
|
+
$R set prefs --file prefs.json # long JSON, from a file
|
|
472
|
+
$R start ... --values '{"units": "metric"}' # seed before the script runs
|
|
473
|
+
$R start ... --values-file values.json # seed from a JSON file
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
- `set <key> {{` ... `}}` takes several lines of JSON, on stdin or at a
|
|
477
|
+
prompt, as `eval` does. Send it in a heredoc (see
|
|
478
|
+
[Multi-step sequences](#multi-step-sequences)).
|
|
479
|
+
- Reads wait for the script's write batching, so `menu X` then
|
|
480
|
+
`values` shows what X stored.
|
|
481
|
+
- Stored values belong to the script and survive `update` and reloads.
|
|
482
|
+
They live in the extension; `--values` seeds them as the script is
|
|
483
|
+
pushed.
|
|
484
|
+
|
|
485
|
+
### `@run-at context-menu` scripts
|
|
486
|
+
|
|
487
|
+
- These don't run on page load. The run says the script is waiting to
|
|
488
|
+
be run, and `menu` lists `Run this script` first under it.
|
|
489
|
+
- Fire that to run the script. Each fire runs it again on the same
|
|
490
|
+
page, so you can test what a second run does too.
|
|
491
|
+
- A reload or navigation leaves it unrun again.
|
|
492
|
+
- In a spec: `gm.runScript()`.
|
|
493
|
+
|
|
494
|
+
### Working from a saved page
|
|
495
|
+
|
|
496
|
+
Use a saved copy when the live page needs a login, keeps changing,
|
|
497
|
+
has state you mustn't touch, or a spec needs to be stable.
|
|
498
|
+
|
|
499
|
+
`--from-saved` opens a saved HTML file at the URL it was saved from,
|
|
500
|
+
with the scripts matching and running as on the live site. The file
|
|
501
|
+
can come from:
|
|
502
|
+
|
|
503
|
+
- sm-dev's `savehtml` (below).
|
|
504
|
+
- Chrome's Save Page As ("HTML only", or "Webpage, Complete" with its
|
|
505
|
+
`<name>_files` folder, which is served from disk);
|
|
506
|
+
- SeeWhatISee, a Chrome extension that captures screenshots and page
|
|
507
|
+
HTML. The person may already given you a snapshot you can use.
|
|
508
|
+
|
|
509
|
+
```sh
|
|
510
|
+
$R newtab page.html --from-saved # served at its recorded URL
|
|
511
|
+
$R newtab 'pages/*.html' --from-saved --offline # several; no network
|
|
512
|
+
$R open page.html --from-saved --url https://x.com/some/page # one that records no URL
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
- The tab shows the original URL, so `@match`, origin, cookies and
|
|
516
|
+
relative URLs behave as live.
|
|
517
|
+
- Without `--offline`, the page's requests (images, fetches) go to the
|
|
518
|
+
live site. A file that keeps the site's own JavaScript (Chrome's and
|
|
519
|
+
SeeWhatISee's do) runs it on replay, and it may re-fetch or redirect:
|
|
520
|
+
`--offline` stops that.
|
|
521
|
+
- `reload` re-reads the file, so it can be edited between loads.
|
|
522
|
+
- It sticks to that URL in that tab: other URLs load live, and coming
|
|
523
|
+
back serves the file again.
|
|
524
|
+
- In a spec: `await page.goto(await serveHtml('pages/some-page.html'))`.
|
|
525
|
+
|
|
526
|
+
Saving one with sm-dev:
|
|
527
|
+
|
|
528
|
+
```sh
|
|
529
|
+
$R newtab --noscript https://x.com/some/page # a tab without the scripts
|
|
530
|
+
$R savehtml pages/some-page.html # the DOM, with the URL recorded
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
- Save from a `--noscript` tab. A page saved with the script running
|
|
534
|
+
has its changes in it, and gets them twice on replay (sm-dev warns).
|
|
535
|
+
- Capture each state the script cares about (menu open, popup shown)
|
|
536
|
+
as its own file: bring it up in the `--noscript` tab, then `savehtml`.
|
|
537
|
+
- A `savehtml` file has the site's JavaScript disabled, so it can't
|
|
538
|
+
re-fetch or rebuild itself. Interactions that need the site's code
|
|
539
|
+
won't work there; the script's own code runs normally.
|
|
540
|
+
- It can't capture shadow roots, typed form values or canvas pixels.
|
|
541
|
+
Check selectors inside a shadow root on the live page.
|
|
542
|
+
|
|
543
|
+
### Multiple tabs
|
|
544
|
+
|
|
545
|
+
- Tabs the run's tab opens (links, `window.open`, `GM_openInTab`) get
|
|
546
|
+
the scripts too, as `T2`, `T3`. Tabs the person opens are left
|
|
547
|
+
alone.
|
|
548
|
+
- Such a tab is set up after its first load, so console lines from
|
|
549
|
+
that load aren't shown. Starts, errors and other reports are.
|
|
550
|
+
- `newtab <url>` opens another controlled tab and makes it current;
|
|
551
|
+
`tab T1` switches back. Page commands take a tab first:
|
|
552
|
+
`click T2 '.x'`, `eval T2 location.href`, `open T2 <url>`,
|
|
553
|
+
`wait T2 selector '.x'`, `menu T2.M1`.
|
|
554
|
+
- `closetab` closes the current tab; `closetab T2 T3` or `closetab all`
|
|
555
|
+
close others. A page that asks first ("Leave site?") shows its
|
|
556
|
+
dialog, answered with `accept` or `dismiss`; `--force` skips it.
|
|
557
|
+
- In a temp browser, closing the last tab quits it, which ends the
|
|
558
|
+
run. Use `stop` there instead of `closetab all`.
|
|
559
|
+
- `tabs` lists them with their `targetId`s, for your own CDP clients.
|
|
560
|
+
In a script: `$R --json tabs | jq -r '.tabs[] | select(.id == "T2") | .targetId'`.
|
|
561
|
+
- `reload all` reloads every tab; `wait all` waits for every tab to
|
|
562
|
+
settle.
|
|
563
|
+
|
|
564
|
+
### Scripts in iframes
|
|
565
|
+
|
|
566
|
+
A script runs in each frame whose own URL it matches (the top page
|
|
567
|
+
needn't match), unless it has `@noframes`. Each frame gets its own copy
|
|
568
|
+
of the script; they share stored values, and can talk to each other with
|
|
569
|
+
`postMessage`.
|
|
570
|
+
|
|
571
|
+
```sh
|
|
572
|
+
$R frames # List the tab's iframes as a tree, with the scripts running in each
|
|
573
|
+
$R match --frames # Check which iframes the script's rules match
|
|
574
|
+
$R snapshot --find Save # Find elements in all frames; refs in iframes look like f2e4
|
|
575
|
+
$R click f2e4 # Use a ref from any frame directly, with no --frame
|
|
576
|
+
$R probe --css f2e4 # Get a CSS selector for the element, and which frame it's in
|
|
577
|
+
$R eval --frame F2 'state' # Run code in the script instance in F2 (--page: in F2's page)
|
|
578
|
+
$R click --frame F2 '.play' # Look for a selector inside F2 (also hover, type, probe, snapshot, screenshot)
|
|
579
|
+
$R wait selector --frame F2 '.ready' # Wait for an element inside F2
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
- Iframes are named `F1`, `F2`, ... for the whole run; the top frame
|
|
583
|
+
is its tab (`T1`). An iframe keeps its id when it or the tab reloads,
|
|
584
|
+
so you can keep using `F2` after a reload.
|
|
585
|
+
- Where a script runs: `frames`, or `tabs` / `status`, which list a
|
|
586
|
+
script not only in the top frame as `(T1, F2)` or `(F2)`.
|
|
587
|
+
- `frames` marks iframes that aren't visible `(hidden)`: often ad or
|
|
588
|
+
tracking frames.
|
|
589
|
+
- A frame added after load (a widget opened by a click) shows up
|
|
590
|
+
once it exists. Run `frames` again after the click.
|
|
591
|
+
- A frame with no URL of its own (`about:blank`, `srcdoc`) never
|
|
592
|
+
runs scripts.
|
|
593
|
+
- To get at an element in a frame, a snapshot ref is the quickest: it
|
|
594
|
+
reaches into any frame, cross-origin ones included, with no
|
|
595
|
+
`--frame`. Refs change when the frame reloads, though, so for a
|
|
596
|
+
selector that lasts (in a spec, or across `--watch` reloads), use
|
|
597
|
+
`--frame F2 <selector>`.
|
|
598
|
+
- `wait` and the actions' own settling watch the top frame's page (and
|
|
599
|
+
every frame's requests). After an action that makes a frame load or
|
|
600
|
+
change, `wait selector --frame F2 ...` for what you need there.
|
|
601
|
+
- `eval --frame` reaches cross-origin frames too, and works like `eval`
|
|
602
|
+
in the top frame: the selected script's scope, `--script=<script>`,
|
|
603
|
+
or `--page`.
|
|
604
|
+
- Lines from a frame are prefixed with it: `[T1.F2] [event] ...
|
|
605
|
+
started in an iframe on <frame URL>`, `[T1.F2] [script log] ...`.
|
|
606
|
+
- `menu` shows the script's one menu for the tab, as SourceMonkey's
|
|
607
|
+
popup does, with every frame's commands in it. sm-dev labels a
|
|
608
|
+
command an iframe registered with its frame: `M3: Toggle (F2)`.
|
|
609
|
+
Firing it runs it in that frame. A command registered by the copies
|
|
610
|
+
in several frames is listed once per frame.
|
|
611
|
+
- For raw CDP, `frames` shows each frame's `[frameId=...]`, which CDP
|
|
612
|
+
calls on a frame take, and `--frame` accepts it too. A frame from
|
|
613
|
+
another site (another domain, not just another subdomain) also has a
|
|
614
|
+
`[targetId=...]` of its own to attach to. `cdp --frame F2 ...` sends
|
|
615
|
+
calls to the target the frame is in.
|
|
616
|
+
|
|
617
|
+
### Multi-step sequences
|
|
618
|
+
|
|
619
|
+
Commands on one line run in order and stop at the first failure (a
|
|
620
|
+
`click` with no element, an `eval` that threw, a `wait` that gives up),
|
|
621
|
+
like `&&`. A `match` or `validate` miss doesn't stop them, nor does an
|
|
622
|
+
`eval` or `cdp` call cut off by a navigation it set off. To check for
|
|
623
|
+
an element that may not be there, use `probe`, which doesn't fail.
|
|
624
|
+
|
|
625
|
+
Keep sm-dev's stderr: that's where a mistyped command says what was
|
|
626
|
+
wrong. To keep output short, filter stdout (`| tail`, `| grep`) or send
|
|
627
|
+
only stdout to `/dev/null`, never `2>/dev/null`.
|
|
628
|
+
|
|
629
|
+
```sh
|
|
630
|
+
$R start sites/x/y.user.js https://x.com/ --detach -- click '.open' -- wait selector '#modal' -- snapshot '#modal'
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
A longer script, or any command with quotes in its arguments (JSON
|
|
634
|
+
strings and selectors included), reads better as a heredoc (no shell
|
|
635
|
+
quoting).
|
|
636
|
+
Each line is a command:
|
|
637
|
+
|
|
638
|
+
```sh
|
|
639
|
+
$R --stdin <<'EOF'
|
|
640
|
+
click '.open-modal'
|
|
641
|
+
wait selector '#modal-dialog'
|
|
642
|
+
type '#input-name' 'Test User'
|
|
643
|
+
click '#modal-submit'
|
|
644
|
+
wait log /Saved record \d+/
|
|
645
|
+
eval myScript.state
|
|
646
|
+
EOF
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
- Blank lines and `# comments` are skipped.
|
|
650
|
+
- Quotes: most commands take one level of quotes off, as a shell
|
|
651
|
+
would (`menu 'Toggle dark'`). `set` takes off single quotes around
|
|
652
|
+
its JSON (`set k '["a"]'`), since double quotes are JSON's own.
|
|
653
|
+
`eval` takes off none: the rest of its line is JavaScript as
|
|
654
|
+
written, so `eval "abc"` is a string.
|
|
655
|
+
- A `{{` ... `}}` block spans several lines: JavaScript for
|
|
656
|
+
`eval {{`, JSON for `set <key> {{`, text for `type <selector> {{`,
|
|
657
|
+
CDP calls for `cdp {{` (see [references/commands.md](references/commands.md#eval)).
|
|
658
|
+
- `{{` ends its line, and the block's content starts on the next.
|
|
659
|
+
- `--file` reads the same from a file instead: `eval --file probe.js`,
|
|
660
|
+
`set <key> --file value.json`, `type <selector> --file notes.txt`,
|
|
661
|
+
`cdp --file calls.txt`.
|
|
662
|
+
- The whole input is checked before anything runs, so an invalid
|
|
663
|
+
command anywhere in it runs nothing.
|
|
664
|
+
|
|
665
|
+
### Reading results in a script: `--json`
|
|
666
|
+
|
|
667
|
+
Most commands that report state can print JSON instead of text, with
|
|
668
|
+
`--json`.
|
|
669
|
+
|
|
670
|
+
- **Use it when you'll process the answer** with `jq` or code:
|
|
671
|
+
- picking a few fields out of a long list (many scripts, tabs or
|
|
672
|
+
matches);
|
|
673
|
+
- checking a value in a script or a loop, rather than by reading;
|
|
674
|
+
- comparing state before and after an action.
|
|
675
|
+
- **Don't use it when you're reading the answer yourself.** The text is
|
|
676
|
+
shorter, and says what an empty answer means and where to look next.
|
|
677
|
+
- **Which commands:** `list`, `status`, `scripts`, `tabs`, `values`,
|
|
678
|
+
`get`, `match`, `validate`, `menu`, `logs`, `probe`, and every
|
|
679
|
+
`collection` and `script` verb (`script list`, `script show`, ...).
|
|
680
|
+
The rest print text as usual.
|
|
681
|
+
- **Output:** one JSON object per command on stdout. Other messages
|
|
682
|
+
and failures stay text, on stderr, with the usual exit code.
|
|
683
|
+
- **The fields**, and what each script `state` means:
|
|
684
|
+
[references/commands.md](references/commands.md#shape-of-a-command-line).
|
|
685
|
+
|
|
686
|
+
```sh
|
|
687
|
+
$R --json values | jq '.scripts[] | {name, units: .values.units}'
|
|
688
|
+
$R --json probe '.result' | jq '.selectors[0].count'
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
### Beyond sm-dev: raw CDP
|
|
692
|
+
|
|
693
|
+
For what sm-dev has no command for, `cdp` sends a raw CDP call to a
|
|
694
|
+
tab (the current one, or `T2` first), and prints the result as JSON.
|
|
695
|
+
A `{{` block, or `--file`, holds several calls, one per line, on one
|
|
696
|
+
session:
|
|
697
|
+
|
|
698
|
+
```sh
|
|
699
|
+
$R cdp Input.dispatchMouseEvent '{"type":"mouseWheel","x":400,"y":300,"deltaX":0,"deltaY":600}'
|
|
700
|
+
$R cdp T2 Page.getNavigationHistory
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
- [references/cdp.md](references/cdp.md) has details and recipes:
|
|
704
|
+
back and forward, window size, mouse wheel, clicks at a point,
|
|
705
|
+
drag, fullscreen, per-frame tracing.
|
|
706
|
+
- `cdp` doesn't wait for the page to settle. Run `wait` after it.
|
|
707
|
+
- For events, or state that outlasts one command, connect your own CDP
|
|
708
|
+
client alongside the run (see the reference).
|
|
709
|
+
- Things sm-dev can do itself are better done there: it waits for the
|
|
710
|
+
page to settle, and its output lands in the run's stream.
|
|
711
|
+
- Some things need no CDP: `eval history.back()` then `wait`,
|
|
712
|
+
`eval 'scrollBy(0, 800)'`.
|
|
713
|
+
|
|
714
|
+
### Fullscreen (images, videos, lightboxes)
|
|
715
|
+
|
|
716
|
+
- Enter it as a person would: `key f`, or `click` the site's button.
|
|
717
|
+
- Exit with `eval document.exitFullscreen()`: `key Escape` doesn't
|
|
718
|
+
exit (sm-dev says so).
|
|
719
|
+
- Checking the state, forcing it off, pitfalls, and tracing a
|
|
720
|
+
transition frame by frame:
|
|
721
|
+
[references/cdp.md](references/cdp.md#fullscreen).
|
|
722
|
+
|
|
723
|
+
### How a run uses the extension
|
|
724
|
+
|
|
725
|
+
```sh
|
|
726
|
+
$R start sites/x/y.user.js https://x.com/ --detach
|
|
727
|
+
$R stop # also removes the run's test collection
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
- The script is pushed into a test collection of the run's own
|
|
731
|
+
(`sm-dev test collection (run D2-a3f9)` in the extension, the id
|
|
732
|
+
`status` shows), removed when the run ends.
|
|
733
|
+
- Each run starts with no stored values but those `--values` seeds.
|
|
734
|
+
- `@require`s read from disk (relative ones, and local copies under
|
|
735
|
+
the collection root or `--local` roots) are pushed with it;
|
|
736
|
+
remote ones are fetched live.
|
|
737
|
+
- The run's tabs run only its own scripts: SourceMonkey-managed
|
|
738
|
+
scripts are kept out of them. The run's scripts run only in the
|
|
739
|
+
run's tabs, not in tabs you open yourself.
|
|
740
|
+
- `scripts` lists those others on the tab by their SourceMonkey
|
|
741
|
+
script numbers (`E12`, the same in every run);
|
|
742
|
+
`values E1` reads one's stored values, and `scripts E1` picks it
|
|
743
|
+
for `get`/`set` (`set key --force <json>` outside a temp
|
|
744
|
+
browser, since that's the person's real data).
|
|
745
|
+
- A `document-start` script may run after the page's first inline
|
|
746
|
+
scripts in a tab a run tab opened (a popup, a link to a new tab),
|
|
747
|
+
where SourceMonkey alone would run it first: every script there waits
|
|
748
|
+
for the extension's check before running. In the tabs the run opens
|
|
749
|
+
itself, the run's scripts run as they would alone.
|
|
750
|
+
- **Before building on a new request path, send one real request
|
|
751
|
+
from it.**
|
|
752
|
+
- A request that works from the page can still be refused from the
|
|
753
|
+
extension: different cookies, and headers a WAF (web application
|
|
754
|
+
firewall) rejects.
|
|
755
|
+
- A 403 the page can't reproduce often comes from the site's CDN
|
|
756
|
+
edge, not its origin server.
|
|
757
|
+
|
|
758
|
+
### Permission prompts
|
|
759
|
+
|
|
760
|
+
A `GM_xmlhttpRequest` to a site the script's `@connect` lines don't
|
|
761
|
+
cover waits on SourceMonkey's permission prompt, as it would for a
|
|
762
|
+
user. Any script that uses `GM_xmlhttpRequest` can hit one, and one
|
|
763
|
+
with no `@connect` lines likely will. Until it's answered, that request
|
|
764
|
+
and whatever the script does with its response wait.
|
|
765
|
+
|
|
766
|
+
- The run prints `*PERMISSION PROMPT*: <script> requests permission to
|
|
767
|
+
connect to <host> ...`. Answer it with `connect`:
|
|
768
|
+
- `connect allow` to test the script as a user who allowed it (the
|
|
769
|
+
usual case), or `connect allow-all` for one that reaches many sites;
|
|
770
|
+
- `connect deny` to test what the script does when refused;
|
|
771
|
+
- `connect once` or `connect cancel` for a one-time answer: the next
|
|
772
|
+
request asks again.
|
|
773
|
+
- `allow`, `deny` and `allow-all` are kept for the run's copy of the
|
|
774
|
+
script, so later requests to that site don't ask again in the run.
|
|
775
|
+
- `connect` answers the selected script's prompt; with several scripts
|
|
776
|
+
loaded, `script N` first.
|
|
777
|
+
- When testing a script's real behavior, note which sites it asked
|
|
778
|
+
about: its `@connect` lines may be missing some.
|
|
779
|
+
|
|
780
|
+
### Downloads
|
|
781
|
+
|
|
782
|
+
- Find a downloaded file at the path its `Download saved: <path>` line
|
|
783
|
+
names (for an http(s) `GM_download`, the `GM_download` line's
|
|
784
|
+
`-> <path>`).
|
|
785
|
+
- In a temp browser, `status` shows the folder as `Downloads:` once
|
|
786
|
+
something was downloaded.
|
|
787
|
+
|
|
788
|
+
### Turning it into a spec
|
|
789
|
+
|
|
790
|
+
```js
|
|
791
|
+
import { test, expect } from 'sourcemonkey/harness';
|
|
792
|
+
|
|
793
|
+
test('adds the button', async ({ page, loadUserscript, gm, reports }) => {
|
|
794
|
+
await loadUserscript('sites/x/y.user.js'); // before the goto
|
|
795
|
+
await page.goto('https://x.com/items/42');
|
|
796
|
+
await reports.waitForStart();
|
|
797
|
+
await expect(page.locator('#add-button')).toBeVisible();
|
|
798
|
+
expect(reports.errors()).toEqual([]);
|
|
799
|
+
});
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
- Run it with `pnpm exec playwright test sites/x/y.spec.mjs`.
|
|
803
|
+
- [references/specs.md](references/specs.md) has the rest: mapping
|
|
804
|
+
sm-dev commands to the fixture, network requests, and pages with no
|
|
805
|
+
site behind them.
|
|
806
|
+
|
|
807
|
+
## Testing under other managers
|
|
808
|
+
|
|
809
|
+
A run can load its scripts into **Tampermonkey** (`--manager tm`) or
|
|
810
|
+
**Violentmonkey** (`--manager vm`) instead of SourceMonkey: to check a
|
|
811
|
+
script is portable, or to debug a difference between managers by
|
|
812
|
+
running the same script and page under each.
|
|
813
|
+
|
|
814
|
+
```sh
|
|
815
|
+
pnpm sm-dev --manager tm manager fetch # once each: download Tampermonkey,
|
|
816
|
+
pnpm sm-dev --manager vm manager fetch # and Violentmonkey
|
|
817
|
+
pnpm sm-dev --manager tm --run Dtm start sites/x/y.user.js https://x.com/ --detach
|
|
818
|
+
pnpm sm-dev --manager vm --run Dvm start sites/x/y.user.js https://x.com/ --detach
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
It reports much less than SourceMonkey: which scripts a tab runs is
|
|
822
|
+
predicted from their match rules, and `values`, `menu` and the like are
|
|
823
|
+
refused. How it works and what differs:
|
|
824
|
+
[references/other-managers.md](references/other-managers.md).
|
|
825
|
+
|
|
826
|
+
## Troubleshooting
|
|
827
|
+
|
|
828
|
+
- **`skipped on <url>: ...`**: the header doesn't cover the page; the
|
|
829
|
+
extension would skip it too. `match` shows why.
|
|
830
|
+
- **`GM_x is not defined`**: missing `@grant GM_x`. Same in the
|
|
831
|
+
extension.
|
|
832
|
+
- **A page global is `undefined` in the script**: if it's read as
|
|
833
|
+
`window.x`, read it bare (`x`) or as `unsafeWindow.x`: unless the
|
|
834
|
+
script has `@grant none`, its `window` shows only the browser's
|
|
835
|
+
built-ins. Otherwise it's in the isolated world (`@inject-into
|
|
836
|
+
content` or `@sandbox DOM`); remove that line.
|
|
837
|
+
- **An early `document-start` change gets overwritten by the page
|
|
838
|
+
under sm-dev only**: in a tab a run tab opened, the script may run
|
|
839
|
+
after the page's first inline scripts (see
|
|
840
|
+
[How a run uses the extension](#how-a-run-uses-the-extension)).
|
|
841
|
+
- **`start` reports that Playwright needs a Chromium build that isn't
|
|
842
|
+
installed**: Playwright was updated. Run the install command the
|
|
843
|
+
error gives (`pnpm exec playwright install chromium` in a repo).
|
|
844
|
+
- **The run refuses to start, or says `no SourceMonkey` / `SourceMonkey
|
|
845
|
+
disabled`**: see [Getting a browser](#getting-a-browser).
|
|
846
|
+
- **A command these docs name is unknown**: sm-dev is older than the
|
|
847
|
+
docs. Ask the person whether to update it: `pnpm run build` in the
|
|
848
|
+
SourceMonkey checkout, then `pnpm install` in a userscript repo. A
|
|
849
|
+
run keeps the code it started with, so start it again after.
|
|
850
|
+
- **`start` says sm-dev or SourceMonkey is older than the other**:
|
|
851
|
+
ask the person whether to update it as the message says. Building
|
|
852
|
+
changes the code under other running sessions. If the run still
|
|
853
|
+
started, keep working meanwhile.
|
|
854
|
+
- **The script seems stale**: check the reload lines after the save, or
|
|
855
|
+
`update` (it skips files whose modification time hasn't changed; a
|
|
856
|
+
`touch` forces it).
|
|
857
|
+
- **After changing SourceMonkey itself**: `pnpm run build` there, then
|
|
858
|
+
`pnpm install` in the userscript repo. The dependency is a copy of
|
|
859
|
+
the build, taken at install time.
|
|
860
|
+
- **`start` hangs connecting**: a tab in that browser is showing a
|
|
861
|
+
dialog. The run names it; answer it or close the tab.
|
|
862
|
+
- **Commands refuse with a dialog open**: `accept` or `dismiss` first.
|
|
863
|
+
- **A `GM_xmlhttpRequest` never finishes, or the script stops after
|
|
864
|
+
one**: look for a `*PERMISSION PROMPT*` line; the request is waiting
|
|
865
|
+
for `connect` (see [Permission prompts](#permission-prompts)).
|
|
866
|
+
- **A wait gave up**: its message says what was still busy (requests,
|
|
867
|
+
DOM changes). A page with a slow API or a never-ending resource never
|
|
868
|
+
settles; `wait selector` for the element you need instead.
|