twskin 0.6.2 → 0.6.4

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.md CHANGED
@@ -5,6 +5,36 @@ All notable changes to this package are documented here. This project follows
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.6.4] - 2026-07-29
9
+
10
+ ### Fixed
11
+
12
+ - Mapped the legacy `text-text-default-reverse` alias to the foreground derived
13
+ from `surface.invert`. Older host primary buttons now retain readable text on
14
+ both light and dark inverse surfaces.
15
+
16
+ ### For contributors
17
+
18
+ - Extended the official-theme action-contrast audit to cover this legacy
19
+ inverse-action foreground alias.
20
+
21
+ ## [0.6.3] - 2026-07-29
22
+
23
+ ### Fixed
24
+
25
+ - Corrected the semantic foreground for TRAE's inverted primary actions. Settings,
26
+ Automation, Marketplace and their dialogs now use a high-contrast foreground
27
+ independently from the brand-color foreground in every official theme.
28
+ - Removed the fixed pale strip behind the Templates tabs and the Automation Run
29
+ History filter bar, while preserving the hierarchy of their interactive controls.
30
+ - Made injected runtime payloads read their version from the packaged manifest,
31
+ preventing a current runtime from being mistaken for an older injection.
32
+
33
+ ### For contributors
34
+
35
+ - Added full-catalog regression coverage for primary-action foreground contrast
36
+ across every official theme and all TRAE token namespaces.
37
+
8
38
  ## [0.6.2] - 2026-07-29
9
39
 
10
40
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "twskin",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "An unofficial community theme manager and CLI for TRAE Work on macOS.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,14 @@ import { spawnSync } from "node:child_process";
16
16
  import { fileURLToPath } from "node:url";
17
17
 
18
18
  const ROOT = path.dirname(fileURLToPath(import.meta.url));
19
- const VERSION = "0.5.10";
19
+ const VERSION = (() => {
20
+ if (process.env.TWSKIN_RUNTIME_VERSION) return process.env.TWSKIN_RUNTIME_VERSION;
21
+ try {
22
+ const manifest = JSON.parse(fs.readFileSync(path.join(ROOT, "manifest.json"), "utf8"));
23
+ if (typeof manifest.packageVersion === "string" && manifest.packageVersion) return manifest.packageVersion;
24
+ } catch {}
25
+ return "development";
26
+ })();
20
27
  const DATA_DIR = process.env.TWSKIN_DATA_DIR || path.join(os.homedir(), ".trae-work-skin");
21
28
 
22
29
  function parseArgs(argv) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "packageVersion": "0.6.2",
3
+ "packageVersion": "0.6.4",
4
4
  "themesBundled": false,
5
5
  "files": [
6
6
  {
@@ -10,8 +10,8 @@
10
10
  },
11
11
  {
12
12
  "path": "injector.mjs",
13
- "size": 31309,
14
- "sha256": "7560f2353b03dd52a60fc6b7a87825b03e621e651a3f8c780c2ab03f91f88934"
13
+ "size": 31648,
14
+ "sha256": "7b0854c2b8b14323df1d5d469188ef3a0e290c7484aefd58bb3b29d19c0c056a"
15
15
  },
16
16
  {
17
17
  "path": "restore.sh",
@@ -20,8 +20,8 @@
20
20
  },
21
21
  {
22
22
  "path": "skin.js",
23
- "size": 62024,
24
- "sha256": "4cc53fd2534ba09b15ffe8260f3684430c2fd2477cfdb254f4bd5d31a7eb184b"
23
+ "size": 62070,
24
+ "sha256": "c2c259652046286048ee0a298ab08210ae3dd8dd226e6410ee888610b41cd96c"
25
25
  },
26
26
  {
27
27
  "path": "start.sh",
@@ -30,8 +30,8 @@
30
30
  },
31
31
  {
32
32
  "path": "styles/base.css",
33
- "size": 35586,
34
- "sha256": "a8bb84a963b8353372bb226c05b81bcaebe982ff18a45355a241f4d24b47e8ba"
33
+ "size": 36601,
34
+ "sha256": "4fb182ba011d330b9ff668d12a25c10eec07ff1c20cb924dbb2598a44a1b8d49"
35
35
  },
36
36
  {
37
37
  "path": "styles/manager.css",
@@ -40,8 +40,8 @@
40
40
  },
41
41
  {
42
42
  "path": "token-map.mjs",
43
- "size": 24446,
44
- "sha256": "7c79c75e7ba634febc9817c55eef2e314a9e92362b6f190ea903e363a65557df"
43
+ "size": 25102,
44
+ "sha256": "5655ad4b3cfab19b569005a64b6a70972e86328129e4ac104323d81427e21559"
45
45
  }
46
46
  ]
47
47
  }
package/runtime/skin.js CHANGED
@@ -416,6 +416,7 @@
416
416
  setVar("--trae-skin-success", state.success);
417
417
  setVar("--trae-skin-input", surface.input);
418
418
  setVar("--trae-skin-menu", surface.menu);
419
+ setVar("--trae-skin-card", surface.card);
419
420
  setVar("--trae-skin-card-hover", surface.cardHover);
420
421
  setVar("--trae-skin-border-subtle", border.subtle);
421
422
  setVar("--trae-skin-border-default", border.default);
@@ -311,6 +311,23 @@ body.trae-skin-v2 [role="menuitem"][data-state="checked"] {
311
311
  background: var(--trae-skin-popover-selected) !important;
312
312
  }
313
313
 
314
+ /* Templates 的 CSS module 固定用纯白 tab strip;让容器回归透明,
315
+ 仅由搜索框与选中态承担控件层级。只匹配含 tabRow 的栏目导航,
316
+ 避免影响其他同前缀的内部 tab 容器。 */
317
+ body.trae-skin-v2 :is([class^="tabsBar-"], [class*=" tabsBar-"]):has(> :is([class^="tabRow-"], [class*=" tabRow-"])) {
318
+ background: transparent !important;
319
+ }
320
+
321
+ /* Automation Run History 的筛选条在宿主中强制占用基础背景,形成一整块
322
+ 不透明色带。条本身应融入页面,仅让可操作的筛选控件使用 input 表面。 */
323
+ body.trae-skin-v2 :is([class^="filterBar-"], [class*=" filterBar-"]):has(> :is([class^="statusSelect-"], [class*=" statusSelect-"])) {
324
+ background: transparent !important;
325
+ }
326
+ body.trae-skin-v2 :is([class^="filterBar-"], [class*=" filterBar-"]):has(> :is([class^="statusSelect-"], [class*=" statusSelect-"]))
327
+ :is([role="combobox"], [class^="trigger-"], [class*=" trigger-"]) {
328
+ background: var(--trae-skin-input) !important;
329
+ }
330
+
314
331
  /* Account card:Trae Work 使用独立 CSS module,不走通用 popover。 */
315
332
  body.trae-skin-v2 [class*="account-module__card___"],
316
333
  body.trae-skin-v2 [class*="account-module__subMenuInner___"] {
@@ -78,7 +78,7 @@
78
78
 
79
79
  // ---------- 命名空间普查清单(2026-07 实地盘点,见 docs/验证记录)----------
80
80
  const NS_BG = ["base-default", "base-secondary", "base-tertiary", "brand", "brand-active", "brand-disabled", "brand-disabled-sub", "brand-hover", "brand-hover-sub", "brand-old", "brand-popup", "brand-popup-sub", "brand-sub", "card", "card-hover", "input", "invert", "invert-active", "invert-disabled", "invert-hover", "menu", "menu-old", "overlay-l0", "overlay-l1", "overlay-l2", "overlay-l3", "overlay-l4", "tooltip", "white"];
81
- const NS_TEXT = ["brand", "brand-hover", "brand-hover-sub", "brand-sub", "default", "default-active", "default-hover", "disabled", "onaccent", "onbrand", "preformat-foreground", "secondary", "secondary-active", "secondary-hover", "tertiary"];
81
+ const NS_TEXT = ["brand", "brand-hover", "brand-hover-sub", "brand-sub", "default", "default-active", "default-hover", "default-reverse", "disabled", "onaccent", "onbrand", "preformat-foreground", "secondary", "secondary-active", "secondary-hover", "tertiary"];
82
82
  const NS_ICON = ["brand", "brand-hover", "brand-hover-sub", "brand-sub", "default", "default-active", "default-hover", "disabled", "onaccent", "onbrand", "secondary", "secondary-active", "secondary-hover", "tertiary", "white"];
83
83
  const NS_BORDER = ["brand", "brand-sub", "contrast", "neutral-l1", "neutral-l2", "neutral-l3"];
84
84
  // --vscode-icube-- 别名层(组件真正消费的那层)
@@ -179,6 +179,11 @@
179
179
  function buildVarMap(tokens, opts) {
180
180
  const r = deriveRoles(tokens, opts);
181
181
  const { accent, surface, text, icons, border, state } = r;
182
+ // TRAE 的原生语义并不对称:`*-onbrand` 配对 `bg-bg-brand`,
183
+ // 而 Marketplace / Automation / Settings 的主操作使用
184
+ // `bg-bg-invert` + `*-onaccent`。不能把二者都绑定到 accent,
185
+ // 否则浅色主题的深色 invert 表面会拿到同色文字。
186
+ const onInvert = pickOnColor(surface.invert);
182
187
  const out = {};
183
188
 
184
189
  // bg 语义(后缀共享:--bg-bg-* / --vscode-icube--bg-bg-* / --ras-bg-bg-*)
@@ -216,12 +221,16 @@
216
221
  const textValue = (suffix) => {
217
222
  switch (suffix) {
218
223
  case "default": case "default-hover": case "default-active": return text.primary;
224
+ // 少数旧 CSS module 使用这个别名配对 bg-bg-invert;它不是“正文反色”,
225
+ // 仍须从实际 invert 表面推导,避免浅色 invert 按钮得到白字。
226
+ case "default-reverse": return onInvert;
219
227
  case "secondary": case "secondary-hover": case "secondary-active": return text.secondary;
220
228
  case "tertiary": return text.tertiary;
221
229
  case "disabled": return text.disabled;
222
230
  case "brand": case "brand-sub": case "brand-design": return accent.base;
223
231
  case "brand-hover": case "brand-hover-sub": case "brand-hover-design": return accent.hover;
224
- case "onaccent": case "onbrand": return accent.onAccent;
232
+ case "onaccent": return onInvert;
233
+ case "onbrand": return accent.onAccent;
225
234
  case "preformat-foreground": return text.secondary;
226
235
  default: return undefined;
227
236
  }
@@ -234,7 +243,8 @@
234
243
  case "disabled": return icons.disabled;
235
244
  case "brand": case "brand-sub": case "brand-design": return accent.base;
236
245
  case "brand-hover": case "brand-hover-sub": case "brand-hover-design": return accent.hover;
237
- case "onaccent": case "onbrand": return accent.onAccent;
246
+ case "onaccent": return onInvert;
247
+ case "onbrand": return accent.onAccent;
238
248
  case "white": return "#ffffff";
239
249
  default: return undefined;
240
250
  }