Repository navigation
Conversation
fix: navbar font mismatch and overlap before Bootstrap loads
…-migration # Conflicts: # Update.json
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5dr7XTsCeoamqLSiT9rLp
Fork PRs get no secrets and the bot cannot push to forks, so their version cannot be bumped before merge. On a push to dev that touches XMOJ.user.js, look up the PR whose merge commit it is; if it came from a fork, run UpdateVersion in fork-merged mode: bump on actions/version-<PR> from dev and open an auto-merging PR as the GitHub App. Runs only on the trusted push, never on fork events, and never checks out fork code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5dr7XTsCeoamqLSiT9rLp
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5dr7XTsCeoamqLSiT9rLp
- UpdateVersionFork processes every merged fork PR to dev that has no Update.json entry, oldest first, each from the latest dev. A run dropped by the concurrency group loses nothing: the next run picks its PR up. - fork-merged mode reuses an open version PR on a rerun and waits for it to merge, so the next bump starts from a dev with this version. - Prerelease only skips when the version is already a stable release; an existing prerelease of the same version is still refreshed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5dr7XTsCeoamqLSiT9rLp
Qodana is no longer used and the workflow is disabled on GitHub; this also drops the fork guard added to it earlier in this PR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5dr7XTsCeoamqLSiT9rLp
Address stable release review findings; retire extern-contrib
|
Sorry @boomzero, your pull request is larger than the review limit of 150,000 diff characters |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Rename the stable 3.9.0 entry to 4.0.0 in Update.json, XMOJ.user.js and package.json, and lead the release notes with the rating change. The //!ci-no-touch marker keeps UpdateVersion from bumping this to 4.0.1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5dr7XTsCeoamqLSiT9rLp
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 75dd908536
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| PRS=$(gh pr list --repo "$REPOSITORY" --base dev --state merged --limit 50 --json number,isCrossRepository,mergedAt \ | ||
| --jq "map(select(.isCrossRepository and .mergedAt >= \"$SINCE\")) | sort_by(.mergedAt) | .[].number") |
There was a problem hiding this comment.
Filter non-script PRs before invoking the versioner
This query selects every merged cross-repository PR, including documentation-only PRs that are intentionally absent from Update.json. For such a PR, UpdateVersion.js runs npm version patch before checking gh pr diff and exiting; the installed npm documentation confirms that this creates a version commit and tag. When the loop then reaches the actual XMOJ.user.js PR that triggered the workflow, it attempts to create the same local tag and fails with fatal: tag 'v…' already exists, preventing that fork PR from receiving a version bump. Check each PR's changed files before calling the versioner, or move the changed-file check ahead of npm version patch.
Useful? React with 👍 / 👎.
Restores 4.0.0 and re-adds //!ci-no-touch so UpdateVersion strips it instead of bumping again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5dr7XTsCeoamqLSiT9rLp
Release as 4.0.0: the rating redesign is a breaking change
Deploying xmoj-script-dev-channel with
|
| Latest commit: |
e486b31
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://b043dce1.xmoj-script-dev-channel.pages.dev |
There was a problem hiding this comment.
19 issues found and verified against the latest diff
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="tests/navbar-styler.test.cjs">
<violation number="1" location="tests/navbar-styler.test.cjs:174">
P3: `before.cards` is hardcoded to 15, coupling this test to the exact number of entries in the `NewDownload` software list. Adding or removing one entry in XMOJ.user.js breaks the assertion without touching the feature this test guards (navbar scrolling/placement). Derive the expected count from the extracted downloads source, or assert `>= 1` plus the placement/geometry checks that are the actual regression being tested.</violation>
</file>
<file name="tests/account-settings.test.cjs">
<violation number="1" location="tests/account-settings.test.cjs:162">
P3: This selector never checks the retry button: it is inserted outside `#UserScriptBadgeEditor`, so `isHidden()` passes when no element matches. Use a page-level locator to catch a visible retry button.</violation>
<violation number="2" location="tests/account-settings.test.cjs:356">
P2: The user-menu tests call `CreateUserMenuItems()`, but the script assembled by `Page()` never extracts or injects that function. Both menu cases therefore fail with `ReferenceError: CreateUserMenuItems is not defined`; include this function in the injected fixture code (or extract the relevant range containing it).</violation>
</file>
<file name="tests/contest-web.test.cjs">
<violation number="1" location="tests/contest-web.test.cjs:198">
P3: If this assertion trips, the message identifies only the pathname, leaving the failing dimension (cachedBootstrap vs headReady, each `false`/`true`) unreported across the 8 combinations in the nested loops. Include both flags in the message so a regression is directly attributable.</violation>
</file>
<file name=".github/workflows/UpdateVersionFork.yml">
<violation number="1" location=".github/workflows/UpdateVersionFork.yml:14">
P2: Bot-authored version-bump pushes enter this workflow-level concurrency group even though the job's later `if` skips them, so a bot run can replace a queued maintainer run. The active run snapshots `PRS` only once, leaving that newly merged fork PR unprocessed; keep bot events out of this concurrency group.</violation>
<violation number="2" location=".github/workflows/UpdateVersionFork.yml:42">
P2: This fixed 50-PR page can permanently skip older merged fork PRs once more than 50 qualifying PRs exist, leaving their version entries missing. Paginate the merged-PR query (or use a sufficiently large limit) before filtering and sorting.</violation>
</file>
<file name="index.html">
<violation number="1" location="index.html:46">
P3: External links open in a new tab without any accessible indication. The `.ext` arrow is drawn with `content: ''` plus a CSS mask (site.css), so it is purely decorative and screen readers only hear the link text. Add a visually hidden "(新窗口打开)" span (or a dynamically appended sr-only notice) inside every `target="_blank"` link with the `.ext` class. Note the footer links (site-footer) don't even carry the `.ext` class, so they get neither arrow nor new-tab hint.</violation>
</file>
<file name=".github/workflows/Release.yml">
<violation number="1" location=".github/workflows/Release.yml:21">
P2: This PR deletes the Cloudflare Pages and GitHub Pages deploy steps from both Release.yml and Prerelease.yml, and none of the 13 remaining files in `.github/workflows/` deploys Pages or Cloudflare anymore. Unless the Pages/Cloudflare connections were reconfigured out-of-band (direct Git integration), xmoj-script.uk / the docs site stop receiving updates after this release while `CLAUDE.md` still documents that both push paths deploy to Cloudflare Pages and GitHub Pages. Confirm the deploys still happen, or keep the deploy steps.</violation>
<violation number="2" location=".github/workflows/Release.yml:21">
P1: Downgrading to Node 16 breaks the `Get version` step: `Update/GetVersion.js` starts with `import { readFileSync } from "fs"` (ESM) and `package.json` has no `"type": "module"`, so Node 16 throws `SyntaxError: Cannot use import statement outside a module` — the script only executes via Node 22+'s module-syntax detection (verified by running it under the sandbox's Node v22.22.3). The job aborts before `create_release`, so this merge's 3.9.0 release is never created. Keep `node-version: 22`. Note also that the release now fires only on `XMOJ.user.js` pushes and `workflow_dispatch` was removed, so a Release.yml-only fix commit will not re-trigger the release.</violation>
</file>
<file name="terms.html">
<violation number="1" location="terms.html:60">
P2: This disclaims responsibility for any resulting loss without the previous legal-limit qualifier, which can make the terms misleading and the disclaimer unenforceable. Restore a limitation tied to what applicable law permits.</violation>
</file>
<file name="sitemap.xml">
<violation number="1" location="sitemap.xml:5">
P3: The homepage, privacy, and child-protection pages changed on October 6, but their sitemap entries still report October 4. Set each `lastmod` to the page’s actual latest modification date so crawlers receive an accurate update signal.</violation>
</file>
<file name=".github/workflows/UpdateToRelease.yml">
<violation number="1" location=".github/workflows/UpdateToRelease.yml:15">
P2: This job-level guard also skips the existing auto-close check for every fork PR. A non-`dev` fork PR changing `XMOJ.user.js` is therefore never commented on or closed by this workflow; keep that policy check independent of the App-token update path.</violation>
</file>
<file name="404.html">
<violation number="1" location="404.html:13">
P3: The `<base>` href hardcodes the GitHub Pages project path `/XMOJ-Script/`, guarded only by a hostname regex. If the repo is ever renamed, a fork enables Pages, or the project is served under a different subpath, every relative resource and link on this page (site.css, site.js, favicon, nav/footer) resolves against the wrong URL and the 404 page renders unstyled. Derive the path from `location.pathname`'s first segment instead of hardcoding it, since on `*.github.io` the site root is always `/<repo>/` regardless of the requested (missing) path.</violation>
</file>
<file name="privacy.html">
<violation number="1" location="privacy.html:64">
P2: This section omits code and drafts that the submission editor persistently saves in browser storage. Disclose that data, its retention, and how users can delete it so readers know their source code remains on the device.</violation>
</file>
<file name=".github/dependabot.yml">
<violation number="1" location=".github/dependabot.yml:12">
P2: A daily gitsubmodule interval opens a Dependabot PR every time XMOJ-bbs's master advances, and each merged bump rides into the next stable release via the wholesale dev→master merge with no version bump and no test coverage: Test.yml's actions/checkout doesn't fetch submodules, so these updates are never executed by CI and only get whatever verification the release review provides. Align the interval with the release cadence (weekly/monthly), or cap the noise with open-pull-requests-limit, so backend code isn't promoted to dev (and eventually stable) on an automatic daily cadence.</violation>
</file>
<file name="Update/UpdateVersion.js">
<violation number="1" location="Update/UpdateVersion.js:13">
P1: Fork mode version-bumps before checking whether the merged PR changed `XMOJ.user.js`. For a fork PR without that file, `npm version patch` creates a local tag and the script exits; the next eligible PR then fails because the same tag already exists. Check the changed-file list before running npm version, or clean up the local tag on the no-op path.</violation>
</file>
<file name="site.js">
<violation number="1" location="site.js:101">
P2: During Bootstrap’s opening transition, `SiteNav` has `.collapsing`, not `.show`, so this check lets hash-link clicks scroll without closing the menu. The expanded sticky nav can cover the destination; track the opening transition and defer the link until `shown.bs.collapse` before hiding and scrolling.</violation>
</file>
<file name="site.css">
<violation number="1" location="site.css:142">
P3: Using `:focus` here makes every nav link keep the black/white pressed style after a mouse click, because anchors retain focus until the user clicks elsewhere; it is indistinguishable from `.active`. Style only `:focus-visible` so mouse clicks revert to the idle look, while keyboard focus keeps both the highlight and the global outline.</violation>
<violation number="2" location="site.css:330">
P3: `.status-tag` hardcodes white text on `--mono-ok` (#52c41a), `--mono-err` (#fe4c61), and `--mono-warn` (#ffa900), giving ~2.3:1, ~3.3:1, and ~1.9:1 contrast — well below the 4.5:1 WCAG AA floor for the small text on the 404 page. Use dark text instead; these tag backgrounds are identical in both themes, so a hardcoded dark color works in light and dark mode.</violation>
</file>
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Re-trigger cubic
| if (lastCommitAuthor === "github-actions[bot]" && eventAction !== "edited") { | ||
| console.log("Last commit was made by github-actions[bot]. Skipping to prevent infinite loop."); | ||
| process.exit(0); | ||
| if (ForkMerged) { |
There was a problem hiding this comment.
P1: Fork mode version-bumps before checking whether the merged PR changed XMOJ.user.js. For a fork PR without that file, npm version patch creates a local tag and the script exits; the next eligible PR then fails because the same tag already exists. Check the changed-file list before running npm version, or clean up the local tag on the no-op path.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At Update/UpdateVersion.js, line 13:
<comment>Fork mode version-bumps before checking whether the merged PR changed `XMOJ.user.js`. For a fork PR without that file, `npm version patch` creates a local tag and the script exits; the next eligible PR then fails because the same tag already exists. Check the changed-file list before running npm version, or clean up the local tag on the no-op path.</comment>
<file context>
@@ -4,20 +4,29 @@ import {execSync} from "child_process";
-if (lastCommitAuthor === "github-actions[bot]" && eventAction !== "edited") {
- console.log("Last commit was made by github-actions[bot]. Skipping to prevent infinite loop.");
- process.exit(0);
+if (ForkMerged) {
+ execSync("git checkout -B " + ForkBranch);
+ console.info("Bumping the version for merged fork PR #" + PRNumber + " on " + ForkBranch + ".");
</file context>
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 22 | ||
| node-version: 16 |
There was a problem hiding this comment.
P1: Downgrading to Node 16 breaks the Get version step: Update/GetVersion.js starts with import { readFileSync } from "fs" (ESM) and package.json has no "type": "module", so Node 16 throws SyntaxError: Cannot use import statement outside a module — the script only executes via Node 22+'s module-syntax detection (verified by running it under the sandbox's Node v22.22.3). The job aborts before create_release, so this merge's 3.9.0 release is never created. Keep node-version: 22. Note also that the release now fires only on XMOJ.user.js pushes and workflow_dispatch was removed, so a Release.yml-only fix commit will not re-trigger the release.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At .github/workflows/Release.yml, line 21:
<comment>Downgrading to Node 16 breaks the `Get version` step: `Update/GetVersion.js` starts with `import { readFileSync } from "fs"` (ESM) and `package.json` has no `"type": "module"`, so Node 16 throws `SyntaxError: Cannot use import statement outside a module` — the script only executes via Node 22+'s module-syntax detection (verified by running it under the sandbox's Node v22.22.3). The job aborts before `create_release`, so this merge's 3.9.0 release is never created. Keep `node-version: 22`. Note also that the release now fires only on `XMOJ.user.js` pushes and `workflow_dispatch` was removed, so a Release.yml-only fix commit will not re-trigger the release.</comment>
<file context>
@@ -20,7 +18,7 @@ jobs:
- uses: actions/setup-node@v4
with:
- node-version: 22
+ node-version: 16
registry-url: https://registry.npmjs.org/
- uses: actions/checkout@v6
</file context>
| node-version: 16 | |
| node-version: 22 |
| for (const [label, route] of [['修改帐号', '/modify_user_info.php'], ['插件更新日志', '/modify_user_info.php?ByUserScript=1']]) { | ||
| await t.test('user menu sends ' + label + ' to the migrated route', async () => { | ||
| const page = await Page('/index.php'); | ||
| await page.evaluate(() => CreateUserMenuItems().forEach(item => document.body.appendChild(item))); |
There was a problem hiding this comment.
P2: The user-menu tests call CreateUserMenuItems(), but the script assembled by Page() never extracts or injects that function. Both menu cases therefore fail with ReferenceError: CreateUserMenuItems is not defined; include this function in the injected fixture code (or extract the relevant range containing it).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At tests/account-settings.test.cjs, line 356:
<comment>The user-menu tests call `CreateUserMenuItems()`, but the script assembled by `Page()` never extracts or injects that function. Both menu cases therefore fail with `ReferenceError: CreateUserMenuItems is not defined`; include this function in the injected fixture code (or extract the relevant range containing it).</comment>
<file context>
@@ -0,0 +1,396 @@
+ for (const [label, route] of [['修改帐号', '/modify_user_info.php'], ['插件更新日志', '/modify_user_info.php?ByUserScript=1']]) {
+ await t.test('user menu sends ' + label + ' to the migrated route', async () => {
+ const page = await Page('/index.php');
+ await page.evaluate(() => CreateUserMenuItems().forEach(item => document.body.appendChild(item)));
+ await Promise.all([page.waitForURL('https://www.xmoj.tech' + route), page.getByText(label, {exact: true}).click()]);
+ assert.equal(page.url(), 'https://www.xmoj.tech' + route);
</file context>
| - XMOJ.user.js | ||
| workflow_dispatch: | ||
| concurrency: | ||
| group: update-version-fork |
There was a problem hiding this comment.
P2: Bot-authored version-bump pushes enter this workflow-level concurrency group even though the job's later if skips them, so a bot run can replace a queued maintainer run. The active run snapshots PRS only once, leaving that newly merged fork PR unprocessed; keep bot events out of this concurrency group.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At .github/workflows/UpdateVersionFork.yml, line 14:
<comment>Bot-authored version-bump pushes enter this workflow-level concurrency group even though the job's later `if` skips them, so a bot run can replace a queued maintainer run. The active run snapshots `PRS` only once, leaving that newly merged fork PR unprocessed; keep bot events out of this concurrency group.</comment>
<file context>
@@ -0,0 +1,54 @@
+ - XMOJ.user.js
+ workflow_dispatch:
+concurrency:
+ group: update-version-fork
+ cancel-in-progress: false
+jobs:
</file context>
| group: update-version-fork | |
| group: ${{ endsWith(github.actor, '[bot]') && format('update-version-fork-{0}', github.run_id) || 'update-version-fork' }} |
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 22 | ||
| node-version: 16 |
There was a problem hiding this comment.
P2: This PR deletes the Cloudflare Pages and GitHub Pages deploy steps from both Release.yml and Prerelease.yml, and none of the 13 remaining files in .github/workflows/ deploys Pages or Cloudflare anymore. Unless the Pages/Cloudflare connections were reconfigured out-of-band (direct Git integration), xmoj-script.uk / the docs site stop receiving updates after this release while CLAUDE.md still documents that both push paths deploy to Cloudflare Pages and GitHub Pages. Confirm the deploys still happen, or keep the deploy steps.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At .github/workflows/Release.yml, line 21:
<comment>This PR deletes the Cloudflare Pages and GitHub Pages deploy steps from both Release.yml and Prerelease.yml, and none of the 13 remaining files in `.github/workflows/` deploys Pages or Cloudflare anymore. Unless the Pages/Cloudflare connections were reconfigured out-of-band (direct Git integration), xmoj-script.uk / the docs site stop receiving updates after this release while `CLAUDE.md` still documents that both push paths deploy to Cloudflare Pages and GitHub Pages. Confirm the deploys still happen, or keep the deploy steps.</comment>
<file context>
@@ -20,7 +18,7 @@ jobs:
- uses: actions/setup-node@v4
with:
- node-version: 22
+ node-version: 16
registry-url: https://registry.npmjs.org/
- uses: actions/checkout@v6
</file context>
| <loc>https://xmoj-bbs.me/</loc> | ||
| <lastmod>2024-08-15T23:16:10+08:00</lastmod> | ||
| <loc>https://www.xmoj-script.uk/</loc> | ||
| <lastmod>2026-10-04</lastmod> |
There was a problem hiding this comment.
P3: The homepage, privacy, and child-protection pages changed on October 6, but their sitemap entries still report October 4. Set each lastmod to the page’s actual latest modification date so crawlers receive an accurate update signal.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At sitemap.xml, line 5:
<comment>The homepage, privacy, and child-protection pages changed on October 6, but their sitemap entries still report October 4. Set each `lastmod` to the page’s actual latest modification date so crawlers receive an accurate update signal.</comment>
<file context>
@@ -1,15 +1,23 @@
-<loc>https://xmoj-bbs.me/</loc>
-<lastmod>2024-08-15T23:16:10+08:00</lastmod>
+<loc>https://www.xmoj-script.uk/</loc>
+<lastmod>2026-10-04</lastmod>
</url>
<url>
</file context>
| <script> | ||
| (function () { | ||
| var base = document.createElement("base"); | ||
| base.href = /\.github\.io$/.test(location.hostname) ? "/XMOJ-Script/" : "/"; |
There was a problem hiding this comment.
P3: The <base> href hardcodes the GitHub Pages project path /XMOJ-Script/, guarded only by a hostname regex. If the repo is ever renamed, a fork enables Pages, or the project is served under a different subpath, every relative resource and link on this page (site.css, site.js, favicon, nav/footer) resolves against the wrong URL and the 404 page renders unstyled. Derive the path from location.pathname's first segment instead of hardcoding it, since on *.github.io the site root is always /<repo>/ regardless of the requested (missing) path.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At 404.html, line 13:
<comment>The `<base>` href hardcodes the GitHub Pages project path `/XMOJ-Script/`, guarded only by a hostname regex. If the repo is ever renamed, a fork enables Pages, or the project is served under a different subpath, every relative resource and link on this page (site.css, site.js, favicon, nav/footer) resolves against the wrong URL and the 404 page renders unstyled. Derive the path from `location.pathname`'s first segment instead of hardcoding it, since on `*.github.io` the site root is always `/<repo>/` regardless of the requested (missing) path.</comment>
<file context>
@@ -1,362 +1,119 @@
+ <script>
+ (function () {
+ var base = document.createElement("base");
+ base.href = /\.github\.io$/.test(location.hostname) ? "/XMOJ-Script/" : "/";
+ document.head.appendChild(base);
+ })();
</file context>
| } | ||
|
|
||
| .site-nav .nav-link:hover, | ||
| .site-nav .nav-link:focus, |
There was a problem hiding this comment.
P3: Using :focus here makes every nav link keep the black/white pressed style after a mouse click, because anchors retain focus until the user clicks elsewhere; it is indistinguishable from .active. Style only :focus-visible so mouse clicks revert to the idle look, while keyboard focus keeps both the highlight and the global outline.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At site.css, line 142:
<comment>Using `:focus` here makes every nav link keep the black/white pressed style after a mouse click, because anchors retain focus until the user clicks elsewhere; it is indistinguishable from `.active`. Style only `:focus-visible` so mouse clicks revert to the idle look, while keyboard focus keeps both the highlight and the global outline.</comment>
<file context>
@@ -0,0 +1,605 @@
+}
+
+.site-nav .nav-link:hover,
+.site-nav .nav-link:focus,
+.site-nav .nav-link.active {
+ background-color: var(--mono-black);
</file context>
| .site-nav .nav-link:focus, | |
| .site-nav .nav-link:hover, | |
| .site-nav .nav-link:focus-visible, | |
| .site-nav .nav-link.active { |
| display: inline-block; | ||
| min-width: 3em; | ||
| text-align: center; | ||
| color: #fff; |
There was a problem hiding this comment.
P3: .status-tag hardcodes white text on --mono-ok (#52c41a), --mono-err (#fe4c61), and --mono-warn (#ffa900), giving ~2.3:1, ~3.3:1, and ~1.9:1 contrast — well below the 4.5:1 WCAG AA floor for the small text on the 404 page. Use dark text instead; these tag backgrounds are identical in both themes, so a hardcoded dark color works in light and dark mode.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At site.css, line 330:
<comment>`.status-tag` hardcodes white text on `--mono-ok` (#52c41a), `--mono-err` (#fe4c61), and `--mono-warn` (#ffa900), giving ~2.3:1, ~3.3:1, and ~1.9:1 contrast — well below the 4.5:1 WCAG AA floor for the small text on the 404 page. Use dark text instead; these tag backgrounds are identical in both themes, so a hardcoded dark color works in light and dark mode.</comment>
<file context>
@@ -0,0 +1,605 @@
+ display: inline-block;
+ min-width: 3em;
+ text-align: center;
+ color: #fff;
+ font-weight: 500;
+ padding: 0 0.4em;
</file context>
| color: #fff; | |
| color: #000; |
| const editor = page.locator('#UserScriptBadgeEditor'); | ||
| assert.equal(await editor.isHidden(), true); | ||
| assert.equal(await editor.locator('[role="status"]').textContent(), ''); | ||
| assert.equal(await editor.locator('button:has-text("重试加载标签")').isHidden(), true); |
There was a problem hiding this comment.
P3: This selector never checks the retry button: it is inserted outside #UserScriptBadgeEditor, so isHidden() passes when no element matches. Use a page-level locator to catch a visible retry button.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At tests/account-settings.test.cjs, line 162:
<comment>This selector never checks the retry button: it is inserted outside `#UserScriptBadgeEditor`, so `isHidden()` passes when no element matches. Use a page-level locator to catch a visible retry button.</comment>
<file context>
@@ -0,0 +1,396 @@
+ const editor = page.locator('#UserScriptBadgeEditor');
+ assert.equal(await editor.isHidden(), true);
+ assert.equal(await editor.locator('[role="status"]').textContent(), '');
+ assert.equal(await editor.locator('button:has-text("重试加载标签")').isHidden(), true);
+ assert.equal(await page.locator('#UserScriptBadgeContent').inputValue(), '');
+ assert.equal(await page.locator('#UserScriptBadgeContent').isDisabled(), true);
</file context>
| assert.equal(await editor.locator('button:has-text("重试加载标签")').isHidden(), true); | |
| assert.equal(await page.getByRole('button', {name: '重试加载标签', exact: true}).isHidden(), true); |
UpdateVersion also runs on edited events, and AI reviewers (cubic, Sourcery) edit PR descriptions on the author's behalf, so the [bot] actor guard does not catch them. On #1057 such an edit bumped the manual 4.0.0 to 4.0.1 minutes after the PR was opened; the same path explains the prerelease-only 3.0.0. An edit now only refreshes this PR's own latest entry and otherwise exits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5dr7XTsCeoamqLSiT9rLp
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Signed-off-by: Zhu Chenrui <boomzero_zcr@outlook.com>
…-bump Never bump the version on a PR edit
What does this PR aim to accomplish?:
Promote
devtomasteras stable release 4.0.0. This replaces #1052, now that its review follow-ups (#1055) are ondev. Since stable 3.8.0,devhas accumulated fixes that resolve every GitHub issue that was open; there are currently no open issues.Issues resolved by changes in this release:
How does this PR accomplish the above?:
Merge
devintomaster. The stable entry is already in Update.json: #1054 (generated by UpdateToRelease on #1052) created it as 3.9.0, and #1057 renamed it to 4.0.0 because the rating redesign (#1048) is a breaking change. UpdateToRelease on this PR found the last version already stable and made no changes. The merge is clean; the merged tree is identical todev. No new implementation commits or history rewrites are introduced by this release PR.Userscript changes included since 3.8.0:
Also on
dev, not affecting the userscript:Redesign xmoj-script.uk and deploy the site on every push #1043 — website redesign and deploy on every push
Run xmoj-code-navigator on Sonnet #1046 — tooling
Address stable release review findings; retire extern-contrib #1055 — review follow-ups from Stable release: merge dev into master #1052:
extern-contribretired; fork PRs now targetdevand get post-merge version bumps (UpdateVersionFork)Its workflow commits are already cherry-picked to
master.The contributor guide and organization template have been read. The ready-for-review checkbox remains unchecked: item 11 requires human verification in both the new and old/classic XMOJ UI, which a maintainer should perform before confirming. This release preserves the existing merge history, so item 6 is not newly asserted.
By submitting this pull request, I confirm the following:
git rebase)🤖 Generated with Claude Code
https://claude.ai/code/session_01E5dr7XTsCeoamqLSiT9rLp