dsh-fonttune 0.7.5 → 0.7.6

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/CHANGELOG.en.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  All notable changes to **dsh-fonttune** are documented here. Chinese version: [CHANGELOG.md](CHANGELOG.md).
4
4
 
5
+ ## [0.7.6] - 2026-11-04
6
+
7
+ ### Fixed
8
+ - **The plugin did not actually load on some hosts**: the Font tune settings card and the first-frame type stylesheet were missing while the conversation still looked completely normal, so it was easy to miss; the plugin now waits for its dependency to finish loading before it registers, and no longer starts half-loaded.
9
+
5
10
  ## [0.7.5] - 2026-11-01
6
11
 
7
12
  ### Fixed
package/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  **dsh-fonttune** 的重要变更都记录在这里。英文版见 [CHANGELOG.en.md](CHANGELOG.en.md)。
4
4
 
5
+ ## [0.7.6] - 2026-11-04
6
+
7
+ ### 修复
8
+ - **部分环境下插件启动后没有真正加载**:字体增强的设置卡片与首帧字体样式会缺失,而对话外观看起来一切正常,所以很难发现;现在启动时会等依赖就绪再注册,不再出现这种「看着正常、其实没加载」的状态。
9
+
5
10
  ## [0.7.5] - 2026-11-01
6
11
 
7
12
  ### 修复
package/lib/index.js CHANGED
@@ -22,7 +22,7 @@
22
22
  */
23
23
  import { createRequire } from "node:module";
24
24
  import { dirname, sep } from "node:path";
25
- import { fileURLToPath } from "node:url";
25
+ import { fileURLToPath, pathToFileURL } from "node:url";
26
26
  // Default import, not named: `shared.cjs` is a CommonJS module, and Node's
27
27
  // CJS-to-ESM interop only guarantees `module.exports` as the default binding
28
28
  // (statically-detected named exports would break this half at boot).
@@ -47,26 +47,73 @@ import shared from "./shared.cjs";
47
47
  * entry (its `node_modules` holds the authoritative copy); anything resolving
48
48
  * back inside THIS package is skipped, so the offline suites — which have no
49
49
  * host — still fall through to the devDependency.
50
- * @returns {object} the schemastery export.
50
+ *
51
+ * RESOLVE with `require`, LOAD with the ESM loader. The package resolves to its
52
+ * CommonJS build, and that build `require`s `@deepseek-ai/cosmokit`, which ships
53
+ * as ES module only. Requiring it while the host is still loading that same
54
+ * module graph throws `ERR_REQUIRE_ESM_RACE_CONDITION` — "Cannot require() ES
55
+ * Module … because it is not yet fully loaded" — and then the whole host half
56
+ * fails to import: no settings namespace, no first-frame stylesheet, while the
57
+ * browser half keeps working and hides the damage (issue #7, reproduced here).
58
+ * `import()` waits for the graph instead of racing it, and it lands on the same
59
+ * instance: a `.cjs` file loaded through the ESM loader goes through the
60
+ * CommonJS cache, so the host's copy is still the only copy.
61
+ * @returns {Promise<object>} the schemastery export.
51
62
  */
52
- function loadSchemastery() {
63
+ async function loadSchemastery() {
53
64
  const own = dirname(dirname(fileURLToPath(import.meta.url))) + sep;
54
65
  const bases = [process.argv[1], fileURLToPath(import.meta.url)];
55
66
  for (const base of bases) {
56
67
  if (typeof base !== "string" || base === "") continue;
57
- try {
58
- const from = createRequire(base);
59
- if (!from.resolve("@deepseek-ai/schemastery").startsWith(own)) {
60
- return from("@deepseek-ai/schemastery");
61
- }
62
- } catch {
63
- // Not resolvable from that anchor: try the next one.
64
- }
68
+ const resolved = resolveSchemastery(createRequire(base), own);
69
+ if (resolved !== null) return importSchemastery(resolved);
70
+ }
71
+ // Nothing outside this package offers it (the offline suites have no host), so
72
+ // the devDependency is the answer — still loaded through the ESM loader.
73
+ const fallback = resolveSchemastery(createRequire(import.meta.url), "");
74
+ if (fallback === null) {
75
+ throw new Error("@deepseek-ai/schemastery is not resolvable from the host or this package");
76
+ }
77
+ return importSchemastery(fallback);
78
+ }
79
+
80
+ /**
81
+ * Locate the schema library from one anchor WITHOUT loading it.
82
+ *
83
+ * Only the resolution is anchored to the host: `createRequire(base).resolve()`
84
+ * answers "which file would the host use", while nothing is executed. An answer
85
+ * that points back inside this package is refused, so a linked install cannot
86
+ * shadow the host's copy with this package's devDependency.
87
+ * @param {NodeRequire} from - the resolver anchored at the host entry.
88
+ * @param {string} own - this package's directory prefix, "" to accept anything.
89
+ * @returns {string|null} the file to load, or null when this anchor cannot offer it.
90
+ */
91
+ function resolveSchemastery(from, own) {
92
+ try {
93
+ const resolved = from.resolve("@deepseek-ai/schemastery");
94
+ if (typeof resolved !== "string" || resolved === "") return null;
95
+ if (own !== "" && resolved.startsWith(own)) return null;
96
+ return resolved;
97
+ } catch {
98
+ // Not resolvable from that anchor (or has no `require` entry): try the next.
99
+ return null;
65
100
  }
66
- return createRequire(import.meta.url)("@deepseek-ai/schemastery");
67
101
  }
68
102
 
69
- const z = loadSchemastery();
103
+ /**
104
+ * Load one resolved file through the ESM loader.
105
+ *
106
+ * A CommonJS build arrives as its `default` binding, which is the module's own
107
+ * `module.exports`; a build that is already ESM answers with itself.
108
+ * @param {string} resolved - an absolute path, from `resolveSchemastery`.
109
+ * @returns {Promise<object>} the schemastery export.
110
+ */
111
+ async function importSchemastery(resolved) {
112
+ const loaded = await import(pathToFileURL(resolved).href);
113
+ return loaded.default ?? loaded;
114
+ }
115
+
116
+ const z = await loadSchemastery();
70
117
 
71
118
  const {
72
119
  buildFontCss,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-fonttune",
3
- "version": "0.7.5",
3
+ "version": "0.7.6",
4
4
  "description": "Font plugin for the DeepSeek Harness Web GUI: the conversation gets its own font, size, line height and weight, the interface font and weight follow it, code keeps its own axis with ligature control, and whole setups save as presets.",
5
5
  "type": "module",
6
6
  "icon": "icon.svg",