fix(theme): emit the fixed-theme value with tojson, not a hand-quoted string - #4
Merged
Conversation
… string
Autoescaping applies inside <script> too, so building the value as
`'"' + config.style + '"'` reached the page as
var fixed = "dark";
A classic script is not HTML-parsed, so those entities never decode: it is a
SyntaxError, and a syntax error takes down the whole element. The visible
symptom was just "theme.style: dark does nothing", but the same IIFE also
carries the pre-paint language redirect, so setting a theming option silently
disabled i18n on every page. Measured on a consumer index:
document.documentElement.dataset.theme came back "(unset)" and no locale
redirect fired.
`tojson` emits "dark" / "light" / null and escapes for a script context, so
it fixes the instance and the class.
The test asserts on the class rather than the string: it scans every inline
script in the generated site for HTML entities that are meaningful in JS, and
parses the emitted value with json.loads instead of comparing text. Reverting
the template makes 4 of its 6 cases fail.
Sunrisepeak
added a commit
to Sunrisepeak/dsh-index
that referenced
this pull request
Aug 13, 2026
1. Install command drops pnpm. Plugins already declare xim:pnpm in their own deps via template.lua, so it pulls in when a plugin is installed; making every reader type it to install dsh itself was noise. 2. Forum and docs icons removed from the header. 3. About now points at openxlings/xlings rather than this index. 4. The license axis is gone from the facet row. License stays on the package page -- it is what gates mirroring -- but nobody browses by SPDX id. 5. Categories and keywords are now real per-package values, surfaced as the two new facet axes. Categories come from tools/classify.py, which reads three author-written signals: the plugin name, the repo's GitHub topics, and the repo description. Bundle patches were evaluated as a fourth and rejected -- almost every one just inserts the plugin by name, so it carries no taxonomy. Topics alone covered only 74/169 and names alone 94/169; adding descriptions (matched bilingually, since most of this ecosystem writes Chinese) reaches 133/169. The remaining 36 stay 'uncategorized' rather than being pushed into a bucket that would look authoritative. A facet whose counts are honest is worth more than one that is merely full. theme.style is back to 'dark' now that openxlings/xpkgindex#4 is merged and the value reaches the page as valid JS.
Sunrisepeak
added a commit
to Sunrisepeak/dsh-index
that referenced
this pull request
Aug 13, 2026
Bootstraps the DeepSeek Harness plugin index: 168 data-only descriptors plus
one shared template.lua, appended at index-build time by pkgindex-build.lua.
The upstream install paradigm is uniform enough to justify templating it --
169 of 281 repos on the dsh-plugin topic declare dsh.bundle, and 166 of those
use the same ./cordis.patch.yml path -- so writing the four lifecycle hooks
169 times would be 169 copies that rot independently.
One template covers both delivery architectures behind a single branch on
package.dsh.mirror. Mirrored packages carry a real xpm resource with a sha256
and, once the GitCode release is confirmed, a CN URL; un-mirrored ones carry {}
and pnpm fetches from the pinned upstream commit. Which one a package gets is
decided by its license, because mirroring is redistribution: of the 169 bundles
surveyed, 29 ship no LICENSE and 13 are unclassifiable, and this index has no
right to mirror those. The site labels every package accordingly rather than
implying a guarantee it cannot make.
Also ships tools/mirror.py and the first real mirror (dsh-cc-tui-0.1.6),
published to xlings-res/dsh-plugins on both GitHub and GitCode and verified
three ways -- the bytes built here, what GitHub serves and what GitCode serves
all hash to b8016904a72e7bf4858a0bb24e6eb952357ecdc7e963a482f33e143ea2312d1b.
Three defects were found by the checks rather than by review:
- 19 of 169 descriptors had a version key that did not match package.json at
their own pinned commit, because version and sha came from two surveys taken
minutes apart. gen_descriptors.py now reads both from the pinned sha, making
the mismatch unrepresentable rather than merely detected.
- The card strip printed `dsh plugin add <bundle_name>`, a command that fails:
package names are not resolvable identifiers in this ecosystem.
- theme.style "dark" emitted invalid JS, which killed the language redirect
sharing that script. Fixed upstream in openxlings/xpkgindex#4.
Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
Autoescaping applies inside
<script>too. The pre-paint bootstrap built itsvalue by hand as
'"' + config.style + '"', so a consumer index settingtheme.style: "dark"got this on every page:A classic script is not HTML-parsed, so those entities never decode. It is a
SyntaxError— and a syntax error takes down the entire script element,not just that line.
Why it is worse than a broken theme
That IIFE does two unrelated things: the pre-paint theme, and the language
redirect. So setting a theming option silently disabled i18n on every
page of the site.
Measured on a consumer index (
Sunrisepeak/dsh-index) withstyle: "dark":After switching that index back to
"auto"(var fixed = null, which parses),both the theme and the redirect started working again — the redirect landing on
/zh/was how I confirmed it had been dead.This is also why it went unnoticed:
"auto"is the default and rendersnull,so only an index that explicitly pins a theme hits it.
xim-pkgindexuses"auto".The fix
tojsoninstead of a hand-quoted string. It emits"dark"/"light"/nulland escapes for a script context, so it fixes the instance and the class.Test
tests/test_script_escaping.pyasserts on the class, not the string:that are meaningful in JS (
" " ' ' & < >),across
style= auto / dark / light;json.loadsrather than comparing text, so afuture change that produces valid-but-wrong JS still fails.
Verified it catches the bug: reverting the template makes 4 of its 6 cases
fail; with the fix, 6 pass.
Full suite:
42 passed.I also scanned every other
{{ }}interpolation inside a<script>in thetemplates — this was the only one.