@harness-mix/cli 0.1.8 → 0.1.9
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/NOTICE +12 -0
- package/README.md +51 -43
- package/docs/harness-management.md +1 -1
- package/docs/native-acp.md +7 -2
- package/docs/task-handoff-design.md +65 -0
- package/licenses/codex-styler-Apache-2.0.txt +193 -0
- package/licenses/heige-codex-skin-studio-MIT.txt +22 -0
- package/output/native-build/desktop-controller.mjs +2 -1
- package/output/native-build/renderer-extension.js +651 -9
- package/package.json +188 -188
- package/scripts/acp-capabilities-probe.cjs +1 -0
- package/scripts/build-native.cjs +1 -1
- package/scripts/codex-adapter-test.cjs +44 -0
- package/scripts/collaboration-recovery-test.cjs +3 -0
- package/scripts/e2e-codex.cjs +3 -1
- package/scripts/e2e-native-acp.cjs +1 -1
- package/scripts/error-kind-test.cjs +107 -0
- package/scripts/handoff-checkpoint-test.cjs +38 -0
- package/scripts/integrations-test.cjs +5 -2
- package/scripts/kiro-cursor-adapters-test.cjs +18 -0
- package/scripts/native-acp-depth-test.cjs +1 -1
- package/scripts/native-protocol-test.cjs +60 -4
- package/scripts/native-ui-smoke.cjs +92 -2
- package/scripts/switch-harness-test.cjs +79 -12
- package/scripts/tool-concurrency-regression-test.cjs +8 -6
- package/src/assets/icons/cline-color.svg +1 -0
- package/src/assets/skins/codex-styler/ASSET_LICENSES.md +36 -0
- package/src/assets/skins/codex-styler/NOTICE +11 -0
- package/src/assets/skins/codex-styler/themes/gilded-grandeur/hero.webp +0 -0
- package/src/assets/skins/codex-styler/themes/merry-big-top/hero.webp +0 -0
- package/src/assets/skins/codex-styler/themes/nocturne-studio/hero.webp +0 -0
- package/src/assets/skins/codex-styler/themes/quiet-garden/hero.webp +0 -0
- package/src/assets/skins/heige/ASSET_PROVENANCE.md +56 -0
- package/src/assets/skins/heige/NOTICE.md +13 -0
- package/src/assets/skins/heige/themes/dalao-dianyan/hero.webp +0 -0
- package/src/assets/skins/heige/themes/dalao-dianyan/theme.json +14 -0
- package/src/assets/skins/heige/themes/deepspace-dawn/hero.webp +0 -0
- package/src/assets/skins/heige/themes/deepspace-dawn/theme.json +14 -0
- package/src/assets/skins/heige/themes/deepspace-star/hero.webp +0 -0
- package/src/assets/skins/heige/themes/deepspace-star/theme.json +14 -0
- package/src/assets/skins/heige/themes/dragonball-nimbus/hero.webp +0 -0
- package/src/assets/skins/heige/themes/dragonball-nimbus/theme.json +16 -0
- package/src/assets/skins/heige/themes/dragonball-super-saiyan/hero.webp +0 -0
- package/src/assets/skins/heige/themes/dragonball-super-saiyan/theme.json +16 -0
- package/src/assets/skins/heige/themes/genshin-dawn/hero.webp +0 -0
- package/src/assets/skins/heige/themes/genshin-dawn/theme.json +14 -0
- package/src/assets/skins/heige/themes/genshin-night/hero.webp +0 -0
- package/src/assets/skins/heige/themes/genshin-night/theme.json +14 -0
- package/src/assets/skins/heige/themes/miku-488137/hero.webp +0 -0
- package/src/assets/skins/heige/themes/miku-488137/logo.webp +0 -0
- package/src/assets/skins/heige/themes/miku-488137/polaroid.webp +0 -0
- package/src/assets/skins/heige/themes/miku-488137/theme.json +16 -0
- package/src/assets/skins/heige/themes/naruto-hokage/hero.webp +0 -0
- package/src/assets/skins/heige/themes/naruto-hokage/theme.json +14 -0
- package/src/assets/skins/heige/themes/naruto-sasuke/hero.webp +0 -0
- package/src/assets/skins/heige/themes/naruto-sasuke/theme.json +14 -0
- package/src/assets/skins/heige/themes/wuthering-echo/hero.webp +0 -0
- package/src/assets/skins/heige/themes/wuthering-echo/theme.json +14 -0
- package/src/assets/skins/heige/themes/wuthering-tide/hero.webp +0 -0
- package/src/assets/skins/heige/themes/wuthering-tide/theme.json +14 -0
- package/src/main/adapters/cline.js +22 -0
- package/src/main/adapters/codex.js +78 -8
- package/src/main/adapters/index.js +2 -1
- package/src/main/adapters/native-acp-command.js +1 -0
- package/src/main/harness-adapter/error-kind.js +82 -0
- package/src/main/harness-adapter/event-normalizer.js +7 -1
- package/src/main/host/core-session.js +1 -1
- package/src/main/host/handoff-access.js +23 -4
- package/src/main/host/handoff-checkpoints.js +9 -2
- package/src/main/host/handoff-tools.js +3 -0
- package/src/main/host/handoff.js +11 -2
- package/src/main/host/runtime.js +272 -163
- package/src/main/host/session-history.js +54 -15
- package/src/main/native/icons.js +3 -2
- package/src/main/native/pets.js +234 -0
- package/src/main/native/protocol.js +197 -56
- package/src/main/protocol-core/projector.js +44 -41
- package/src/native-ui/desktop-control/dist/production-controller.d.ts.map +1 -1
- package/src/native-ui/desktop-control/dist/production-controller.js +1 -0
- package/src/native-ui/desktop-control/dist/production-controller.js.map +1 -1
- package/src/native-ui/desktop-control/dist/tsconfig.tsbuildinfo +1 -1
- package/src/native-ui/desktop-control/src/production-controller.ts +1 -0
- package/src/native-ui/desktop-control/test/production-controller.test.ts +1 -0
- package/src/native-ui/renderer-extension/dist/types/agent-selection-state.d.ts +4 -2
- package/src/native-ui/renderer-extension/dist/types/agent-selection-state.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-agent-icon.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-agent-picker.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-binding-probe.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-harness-mentions.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-settings-lifecycle.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-sidebar-agent-icons.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/connections-page.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/icons.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/icons.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/localization.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/shell.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/skin-market.d.ts +4 -0
- package/src/native-ui/renderer-extension/dist/types/settings/skin-market.d.ts.map +1 -0
- package/src/native-ui/renderer-extension/dist/types/settings/skin-runtime.d.ts +31 -0
- package/src/native-ui/renderer-extension/dist/types/settings/skin-runtime.d.ts.map +1 -0
- package/src/native-ui/renderer-extension/dist/types/tsconfig.tsbuildinfo +1 -1
- package/src/native-ui/renderer-extension/dist/types/versioned-renderer-adapter.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/package.json +1 -1
- package/src/native-ui/renderer-extension/src/agent-selection-state.ts +16 -0
- package/src/native-ui/renderer-extension/src/assets.d.ts +5 -0
- package/src/native-ui/renderer-extension/src/renderer-agent-icon.ts +5 -4
- package/src/native-ui/renderer-extension/src/renderer-agent-picker.ts +1 -0
- package/src/native-ui/renderer-extension/src/renderer-binding-probe.ts +9 -6
- package/src/native-ui/renderer-extension/src/renderer-harness-handoff.ts +2 -2
- package/src/native-ui/renderer-extension/src/renderer-harness-mentions.ts +2 -0
- package/src/native-ui/renderer-extension/src/renderer-settings-lifecycle.ts +2 -0
- package/src/native-ui/renderer-extension/src/renderer-sidebar-agent-icons.ts +1 -0
- package/src/native-ui/renderer-extension/src/settings/connections-page.ts +2 -0
- package/src/native-ui/renderer-extension/src/settings/icons.ts +6 -0
- package/src/native-ui/renderer-extension/src/settings/localization.ts +4 -2
- package/src/native-ui/renderer-extension/src/settings/pages.ts +5 -2
- package/src/native-ui/renderer-extension/src/settings/shell.ts +3 -2
- package/src/native-ui/renderer-extension/src/settings/skin-market.css +213 -0
- package/src/native-ui/renderer-extension/src/settings/skin-market.ts +174 -0
- package/src/native-ui/renderer-extension/src/settings/skin-runtime.ts +399 -0
- package/src/native-ui/renderer-extension/src/versioned-renderer-adapter.ts +2 -1
- package/src/native-ui/renderer-extension/test/settings/localization.test.ts +11 -1
- package/src/native-ui/renderer-extension/test/settings/shell.test.ts +3 -0
- package/src/native-ui/renderer-extension/test/settings/skin-runtime.test.ts +136 -0
- package/src/native-ui/shared-contracts/dist/thread-harness-switch.d.ts +7 -0
- package/src/native-ui/shared-contracts/dist/thread-harness-switch.d.ts.map +1 -1
- package/src/native-ui/shared-contracts/dist/thread-harness-switch.js +3 -0
- package/src/native-ui/shared-contracts/dist/thread-harness-switch.js.map +1 -1
- package/src/native-ui/shared-contracts/dist/tsconfig.tsbuildinfo +1 -1
- package/src/native-ui/shared-contracts/src/thread-harness-switch.ts +3 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import dalaoDianyanHero from "../../../../assets/skins/heige/themes/dalao-dianyan/hero.webp";
|
|
2
|
+
import deepspaceDawnHero from "../../../../assets/skins/heige/themes/deepspace-dawn/hero.webp";
|
|
3
|
+
import deepspaceStarHero from "../../../../assets/skins/heige/themes/deepspace-star/hero.webp";
|
|
4
|
+
import dragonballNimbusHero from "../../../../assets/skins/heige/themes/dragonball-nimbus/hero.webp";
|
|
5
|
+
import dragonballSuperSaiyanHero from "../../../../assets/skins/heige/themes/dragonball-super-saiyan/hero.webp";
|
|
6
|
+
import genshinDawnHero from "../../../../assets/skins/heige/themes/genshin-dawn/hero.webp";
|
|
7
|
+
import genshinNightHero from "../../../../assets/skins/heige/themes/genshin-night/hero.webp";
|
|
8
|
+
import mikuHero from "../../../../assets/skins/heige/themes/miku-488137/hero.webp";
|
|
9
|
+
import mikuLogo from "../../../../assets/skins/heige/themes/miku-488137/logo.webp";
|
|
10
|
+
import mikuPolaroid from "../../../../assets/skins/heige/themes/miku-488137/polaroid.webp";
|
|
11
|
+
import narutoHokageHero from "../../../../assets/skins/heige/themes/naruto-hokage/hero.webp";
|
|
12
|
+
import narutoSasukeHero from "../../../../assets/skins/heige/themes/naruto-sasuke/hero.webp";
|
|
13
|
+
import wutheringEchoHero from "../../../../assets/skins/heige/themes/wuthering-echo/hero.webp";
|
|
14
|
+
import wutheringTideHero from "../../../../assets/skins/heige/themes/wuthering-tide/hero.webp";
|
|
15
|
+
import gildedGrandeurHero from "../../../../assets/skins/codex-styler/themes/gilded-grandeur/hero.webp";
|
|
16
|
+
import merryBigTopHero from "../../../../assets/skins/codex-styler/themes/merry-big-top/hero.webp";
|
|
17
|
+
import nocturneStudioHero from "../../../../assets/skins/codex-styler/themes/nocturne-studio/hero.webp";
|
|
18
|
+
import quietGardenHero from "../../../../assets/skins/codex-styler/themes/quiet-garden/hero.webp";
|
|
19
|
+
|
|
20
|
+
export const RENDERER_SKIN_STORAGE_KEY = "harness-mix.renderer-skin.v1";
|
|
21
|
+
export const RENDERER_SKIN_STYLE_ID = "harness-mix-renderer-skin";
|
|
22
|
+
export const RENDERER_SKIN_ATTRIBUTE = "data-harness-mix-skin";
|
|
23
|
+
|
|
24
|
+
export const RENDERER_SKIN_IDS = [
|
|
25
|
+
"native", "miku-488137", "genshin-dawn", "genshin-night", "wuthering-echo",
|
|
26
|
+
"wuthering-tide", "naruto-hokage", "naruto-sasuke", "deepspace-dawn",
|
|
27
|
+
"deepspace-star", "dragonball-nimbus", "dragonball-super-saiyan", "dalao-dianyan",
|
|
28
|
+
"styler-gilded-grandeur", "styler-merry-big-top", "styler-nocturne-studio",
|
|
29
|
+
"styler-quiet-garden",
|
|
30
|
+
] as const;
|
|
31
|
+
|
|
32
|
+
export type RendererSkinId = (typeof RENDERER_SKIN_IDS)[number];
|
|
33
|
+
|
|
34
|
+
export interface RendererSkinDefinition {
|
|
35
|
+
readonly id: RendererSkinId;
|
|
36
|
+
readonly name: string;
|
|
37
|
+
readonly sourceName: string;
|
|
38
|
+
readonly sourceUrl: string | null;
|
|
39
|
+
readonly heroUrl: string | null;
|
|
40
|
+
readonly logoUrl: string | null;
|
|
41
|
+
readonly polaroidUrl: string | null;
|
|
42
|
+
readonly palette: readonly [surface: string, secondary: string, accent: string, text: string];
|
|
43
|
+
readonly preview: string;
|
|
44
|
+
readonly focus: string;
|
|
45
|
+
readonly dark: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const HEIGE_SOURCE_URL = "https://github.com/HeiGeAi/heige-codex-skin-studio";
|
|
49
|
+
const CODEX_STYLER_SOURCE_URL = "https://github.com/xuhuanstudio/codex-styler";
|
|
50
|
+
|
|
51
|
+
function heigeSkin(
|
|
52
|
+
id: Exclude<RendererSkinId, "native">,
|
|
53
|
+
name: string,
|
|
54
|
+
heroUrl: string,
|
|
55
|
+
palette: RendererSkinDefinition["palette"],
|
|
56
|
+
focus: string,
|
|
57
|
+
dark: boolean,
|
|
58
|
+
decorations: Pick<RendererSkinDefinition, "logoUrl" | "polaroidUrl"> = {
|
|
59
|
+
logoUrl: null,
|
|
60
|
+
polaroidUrl: null,
|
|
61
|
+
},
|
|
62
|
+
): RendererSkinDefinition {
|
|
63
|
+
return Object.freeze({
|
|
64
|
+
id, name, heroUrl, palette, focus, dark, ...decorations,
|
|
65
|
+
sourceName: "HeiGe Codex Skin Studio",
|
|
66
|
+
sourceUrl: HEIGE_SOURCE_URL,
|
|
67
|
+
preview: `linear-gradient(${dark ? "rgb(3 7 12 / 16%)" : "rgb(255 255 255 / 8%)"}, transparent)`,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function codexStylerSkin(
|
|
72
|
+
id: Exclude<RendererSkinId, "native">,
|
|
73
|
+
name: string,
|
|
74
|
+
heroUrl: string,
|
|
75
|
+
palette: RendererSkinDefinition["palette"],
|
|
76
|
+
focus: string,
|
|
77
|
+
): RendererSkinDefinition {
|
|
78
|
+
return Object.freeze({
|
|
79
|
+
id, name, heroUrl, logoUrl: null, polaroidUrl: null, palette, focus, dark: true,
|
|
80
|
+
sourceName: "Codex Styler · CC BY 4.0",
|
|
81
|
+
sourceUrl: CODEX_STYLER_SOURCE_URL,
|
|
82
|
+
preview: "linear-gradient(rgb(3 7 12 / 16%), transparent)",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const RENDERER_SKINS: readonly RendererSkinDefinition[] = Object.freeze([
|
|
87
|
+
Object.freeze({
|
|
88
|
+
id: "native", name: "Native Codex", sourceName: "OpenAI Codex", sourceUrl: null,
|
|
89
|
+
heroUrl: null, logoUrl: null, polaroidUrl: null,
|
|
90
|
+
palette: ["#f7f7f7", "#d7d7d7", "#171717", "#171717"] as const,
|
|
91
|
+
preview: "linear-gradient(145deg, #f8f8f8 0 58%, #ececec 58% 100%)",
|
|
92
|
+
focus: "50% 50%", dark: false,
|
|
93
|
+
}),
|
|
94
|
+
heigeSkin(
|
|
95
|
+
"miku-488137",
|
|
96
|
+
"Miku 488137",
|
|
97
|
+
mikuHero,
|
|
98
|
+
["#f5f6fc", "#ed6ec1", "#19c9e5", "#122c60"],
|
|
99
|
+
"50% 33%",
|
|
100
|
+
false,
|
|
101
|
+
{ logoUrl: mikuLogo, polaroidUrl: mikuPolaroid },
|
|
102
|
+
),
|
|
103
|
+
heigeSkin("genshin-dawn", "原神 · 晨曦", genshinDawnHero, ["#f2f1fb", "#e0aa3e", "#5b7fd6", "#2c3a6b"], "50% 24%", false),
|
|
104
|
+
heigeSkin("genshin-night", "原神 · 星夜", genshinNightHero, ["#171a2e", "#7a86d8", "#e0b458", "#f0e6c8"], "50% 17%", true),
|
|
105
|
+
heigeSkin("wuthering-echo", "鸣潮 · 共鸣", wutheringEchoHero, ["#16121f", "#a98fe8", "#56e0d8", "#e4def2"], "50% 27%", true),
|
|
106
|
+
heigeSkin("wuthering-tide", "鸣潮 · 声骸", wutheringTideHero, ["#0d1418", "#9aa8b0", "#3fd6d0", "#d8eef0"], "50% 30%", true),
|
|
107
|
+
heigeSkin("naruto-hokage", "火影 · 鸣人", narutoHokageHero, ["#17110b", "#ffd166", "#f2801e", "#ffe3c2"], "50% 27%", true),
|
|
108
|
+
heigeSkin("naruto-sasuke", "火影 · 佐助", narutoSasukeHero, ["#171019", "#7fb3ff", "#d8443c", "#ffd9d2"], "50% 24%", true),
|
|
109
|
+
heigeSkin("deepspace-dawn", "恋与深空 · 晨曦", deepspaceDawnHero, ["#f6f2fb", "#f097c8", "#8f7fe8", "#4a4668"], "50% 8%", false),
|
|
110
|
+
heigeSkin("deepspace-star", "恋与深空 · 星辰", deepspaceStarHero, ["#201a40", "#f097c8", "#9d8bff", "#e8e2ff"], "50% 8%", true),
|
|
111
|
+
heigeSkin("dragonball-nimbus", "龙珠 · 筋斗云", dragonballNimbusHero, ["#f3f7ff", "#f6c445", "#4fc3f7", "#14213d"], "72% 24%", false),
|
|
112
|
+
heigeSkin("dragonball-super-saiyan", "龙珠 · 超级赛亚人", dragonballSuperSaiyanHero, ["#fff8e8", "#52c7f2", "#f5c451", "#282033"], "67% 3%", false),
|
|
113
|
+
heigeSkin("dalao-dianyan", "大佬 · 点烟", dalaoDianyanHero, ["#111111", "#9aa3b0", "#e09a52", "#f2e8da"], "50% 8%", true),
|
|
114
|
+
codexStylerSkin("styler-gilded-grandeur", "金辉盛境", gildedGrandeurHero, ["#090704", "#5b4721", "#e8bd55", "#fff2cd"], "54% 48%"),
|
|
115
|
+
codexStylerSkin("styler-merry-big-top", "欢乐大帐篷", merryBigTopHero, ["#100b14", "#5a3d4b", "#ff755e", "#fff2dc"], "55% 48%"),
|
|
116
|
+
codexStylerSkin("styler-nocturne-studio", "夜曲工作室", nocturneStudioHero, ["#090b0d", "#34383a", "#e9a066", "#f5efe6"], "58% 46%"),
|
|
117
|
+
codexStylerSkin("styler-quiet-garden", "静谧花园", quietGardenHero, ["#101612", "#364339", "#9fc29a", "#edf2e8"], "52% 50%"),
|
|
118
|
+
]);
|
|
119
|
+
|
|
120
|
+
interface RendererSkinStorage {
|
|
121
|
+
getItem(key: string): string | null;
|
|
122
|
+
setItem(key: string, value: string): void;
|
|
123
|
+
removeItem(key: string): void;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function documentSkinStorage(ownerDocument: Document): RendererSkinStorage | null {
|
|
127
|
+
try { return ownerDocument.defaultView?.localStorage ?? null; } catch { return null; }
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function isRendererSkinId(value: string | null): value is RendererSkinId {
|
|
131
|
+
return (RENDERER_SKIN_IDS as readonly string[]).includes(value ?? "");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function rendererSkinDefinition(id: RendererSkinId): RendererSkinDefinition {
|
|
135
|
+
return RENDERER_SKINS.find((skin) => skin.id === id) ?? RENDERER_SKINS[0]!;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function readRendererSkin(storage?: RendererSkinStorage | null): RendererSkinId {
|
|
139
|
+
try {
|
|
140
|
+
const stored = storage?.getItem(RENDERER_SKIN_STORAGE_KEY) ?? null;
|
|
141
|
+
return isRendererSkinId(stored) ? stored : "native";
|
|
142
|
+
} catch { return "native"; }
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function readActiveRendererSkin(ownerDocument: Document = document): RendererSkinId {
|
|
146
|
+
const active = ownerDocument.documentElement.getAttribute(RENDERER_SKIN_ATTRIBUTE);
|
|
147
|
+
return isRendererSkinId(active) ? active : readRendererSkin(documentSkinStorage(ownerDocument));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function skinCss(skin: RendererSkinDefinition): string {
|
|
151
|
+
const [surface, secondary, accent, text] = skin.palette;
|
|
152
|
+
const image = skin.heroUrl ? `url("${skin.heroUrl}")` : skin.preview;
|
|
153
|
+
const sidebarVeil = skin.dark
|
|
154
|
+
? `color-mix(in srgb, ${surface} 91%, transparent)`
|
|
155
|
+
: `color-mix(in srgb, ${surface} 88%, transparent)`;
|
|
156
|
+
const lowerVeil = skin.dark
|
|
157
|
+
? `color-mix(in srgb, ${surface} 68%, transparent)`
|
|
158
|
+
: `color-mix(in srgb, ${surface} 72%, transparent)`;
|
|
159
|
+
const panelOpacity = skin.dark ? "84%" : "82%";
|
|
160
|
+
const secondaryText = `color-mix(in srgb, ${text} 72%, transparent)`;
|
|
161
|
+
const tertiaryText = `color-mix(in srgb, ${text} 54%, transparent)`;
|
|
162
|
+
const logoCss = skin.logoUrl ? `
|
|
163
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] .app-shell-left-panel button[aria-haspopup="menu"][aria-label*="ChatGPT"],
|
|
164
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] .app-shell-left-panel button[aria-haspopup="menu"][aria-label*="Codex"] {
|
|
165
|
+
width: min(214px, calc(100% - 12px)); height: 72px !important; margin: 4px 6px 0;
|
|
166
|
+
background: url("${skin.logoUrl}") left center / contain no-repeat !important;
|
|
167
|
+
}
|
|
168
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] .app-shell-left-panel button[aria-haspopup="menu"][aria-label*="ChatGPT"] > :where(span, svg),
|
|
169
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] .app-shell-left-panel button[aria-haspopup="menu"][aria-label*="Codex"] > :where(span, svg) { visibility: hidden !important; }
|
|
170
|
+
` : "";
|
|
171
|
+
const polaroidCss = skin.polaroidUrl ? `
|
|
172
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] body::after {
|
|
173
|
+
content: ""; position: fixed; right: clamp(12px, 2vw, 24px); bottom: clamp(72px, 11vh, 108px);
|
|
174
|
+
width: clamp(108px, 11.5vw, 168px); aspect-ratio: 2 / 3;
|
|
175
|
+
background: url("${skin.polaroidUrl}") center / contain no-repeat;
|
|
176
|
+
filter: drop-shadow(0 12px 26px color-mix(in srgb, ${text} 24%, transparent));
|
|
177
|
+
pointer-events: none; z-index: 15;
|
|
178
|
+
}
|
|
179
|
+
@media (max-width: 760px) {
|
|
180
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] body::after { display: none; }
|
|
181
|
+
}
|
|
182
|
+
` : "";
|
|
183
|
+
return `
|
|
184
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] {
|
|
185
|
+
color-scheme: ${skin.dark ? "dark" : "light"};
|
|
186
|
+
--color-text: ${text}; --color-text-primary: ${text}; --color-token-text-primary: ${text};
|
|
187
|
+
--color-token-foreground: ${text}; --color-text-prose: ${text}; --color-text-emphasis: ${text};
|
|
188
|
+
--color-text-primary-surface: ${text}; --color-text-primary-soft: ${text};
|
|
189
|
+
--color-text-primary-soft-alt: ${text}; --color-text-primary-ghost: ${text};
|
|
190
|
+
--color-text-primary-ghost-hover: ${text}; --color-text-primary-outline: ${text};
|
|
191
|
+
--color-text-primary-outline-hover: ${text};
|
|
192
|
+
--color-text-secondary: ${secondaryText}; --color-token-text-secondary: ${secondaryText};
|
|
193
|
+
--color-text-secondary-soft: ${secondaryText}; --color-text-secondary-soft-alt: ${secondaryText};
|
|
194
|
+
--color-text-secondary-ghost: ${secondaryText}; --color-text-secondary-ghost-hover: ${text};
|
|
195
|
+
--color-text-secondary-outline: ${secondaryText}; --color-text-secondary-outline-hover: ${text};
|
|
196
|
+
--color-text-secondary-solid: ${secondaryText};
|
|
197
|
+
--color-text-tertiary: ${tertiaryText}; --color-token-text-tertiary: ${tertiaryText};
|
|
198
|
+
--color-token-description-foreground: ${tertiaryText};
|
|
199
|
+
--color-token-dropdown-foreground: ${text};
|
|
200
|
+
--app-color-text-foreground: ${text}; --app-color-text-foreground-secondary: ${secondaryText};
|
|
201
|
+
--app-color-text-foreground-tertiary: ${tertiaryText};
|
|
202
|
+
--app-color-foreground-application-menu: ${text};
|
|
203
|
+
--app-color-text-button-secondary: ${text}; --app-color-text-button-tertiary: ${tertiaryText};
|
|
204
|
+
--wb-text-primary: ${text}; --wb-text-secondary: ${secondaryText}; --wb-text-tertiary: ${tertiaryText};
|
|
205
|
+
--color-control-thumb-foreground: ${text};
|
|
206
|
+
--color-text-mode-toggle-inactive: ${secondaryText};
|
|
207
|
+
--color-surface: color-mix(in srgb, ${surface} 92%, transparent);
|
|
208
|
+
--color-surface-secondary: color-mix(in srgb, ${surface} 88%, transparent);
|
|
209
|
+
--color-surface-tertiary: color-mix(in srgb, ${surface} 94%, transparent);
|
|
210
|
+
--color-surface-elevated: color-mix(in srgb, ${surface} 96%, transparent);
|
|
211
|
+
--color-surface-elevated-secondary: color-mix(in srgb, ${surface} 96%, transparent);
|
|
212
|
+
--color-background-surface: color-mix(in srgb, ${surface} 90%, transparent);
|
|
213
|
+
--color-background-panel: color-mix(in srgb, ${surface} 94%, transparent);
|
|
214
|
+
--color-background-callout-surface: color-mix(in srgb, ${surface} 94%, transparent);
|
|
215
|
+
--color-background-control-opaque: ${surface};
|
|
216
|
+
--color-background-page-search: color-mix(in srgb, ${surface} 92%, transparent);
|
|
217
|
+
--color-background-composer-action-bar: color-mix(in srgb, ${surface} 88%, transparent);
|
|
218
|
+
--color-background-execution-output: color-mix(in srgb, ${surface} 88%, transparent);
|
|
219
|
+
--color-background-primary-soft: color-mix(in srgb, ${surface} 92%, transparent);
|
|
220
|
+
--color-background-primary-soft-alpha: color-mix(in srgb, ${surface} 88%, transparent);
|
|
221
|
+
--color-background-primary-soft-hover: color-mix(in srgb, ${surface} 80%, ${accent});
|
|
222
|
+
--color-background-primary-soft-active: color-mix(in srgb, ${surface} 72%, ${accent});
|
|
223
|
+
--color-background-primary-ghost-hover: color-mix(in srgb, ${text} 8%, transparent);
|
|
224
|
+
--color-background-secondary-soft: color-mix(in srgb, ${text} 7%, transparent);
|
|
225
|
+
--color-background-secondary-soft-alpha: color-mix(in srgb, ${text} 7%, transparent);
|
|
226
|
+
--color-background-secondary-soft-hover: color-mix(in srgb, ${text} 11%, transparent);
|
|
227
|
+
--color-background-other-user-message: color-mix(in srgb, ${surface} 76%, transparent);
|
|
228
|
+
--color-background-user-message-compact: color-mix(in srgb, ${surface} 88%, transparent);
|
|
229
|
+
--color-border: color-mix(in srgb, ${text} 16%, transparent);
|
|
230
|
+
--color-border-subtle: color-mix(in srgb, ${text} 8%, transparent);
|
|
231
|
+
--color-border-strong: color-mix(in srgb, ${text} 20%, transparent);
|
|
232
|
+
--color-token-main-surface-primary: color-mix(in srgb, ${surface} 92%, transparent);
|
|
233
|
+
--color-token-dropdown-background: color-mix(in srgb, ${surface} 96%, transparent);
|
|
234
|
+
--color-token-list-hover-background: color-mix(in srgb, ${text} 8%, transparent);
|
|
235
|
+
--color-token-border: color-mix(in srgb, ${text} 16%, transparent);
|
|
236
|
+
--color-token-border-default: color-mix(in srgb, ${text} 16%, transparent);
|
|
237
|
+
--color-token-border-light: color-mix(in srgb, ${text} 9%, transparent);
|
|
238
|
+
--color-token-border-heavy: color-mix(in srgb, ${text} 22%, transparent);
|
|
239
|
+
--color-token-input-border: color-mix(in srgb, ${text} 20%, transparent);
|
|
240
|
+
--color-codex-diff-surface: color-mix(in srgb, ${surface} 94%, ${text});
|
|
241
|
+
--color-token-diff-surface: color-mix(in srgb, ${surface} 94%, ${text});
|
|
242
|
+
--color-codex-editor-inline-code-background: color-mix(in srgb, ${surface} 92%, transparent);
|
|
243
|
+
--color-codex-terminal-background: ${surface};
|
|
244
|
+
--codex-base-surface: ${surface};
|
|
245
|
+
--app-color-background-surface: color-mix(in srgb, ${surface} 92%, transparent);
|
|
246
|
+
--app-color-background-surface-under: color-mix(in srgb, ${surface} 88%, transparent);
|
|
247
|
+
--app-color-background-control: color-mix(in srgb, ${surface} 96%, transparent);
|
|
248
|
+
--app-color-background-elevated-primary: color-mix(in srgb, ${surface} 96%, transparent);
|
|
249
|
+
--app-color-background-elevated-primary-opaque: ${surface};
|
|
250
|
+
--app-color-background-elevated-secondary: color-mix(in srgb, ${surface} 96%, transparent);
|
|
251
|
+
--app-color-background-elevated-secondary-opaque: ${surface};
|
|
252
|
+
--app-color-background-editor-opaque: ${surface};
|
|
253
|
+
--app-color-background-application-menu: color-mix(in srgb, ${surface} 96%, transparent);
|
|
254
|
+
--app-color-background-button-secondary: color-mix(in srgb, ${text} 7%, transparent);
|
|
255
|
+
--app-color-background-button-secondary-hover: color-mix(in srgb, ${text} 11%, transparent);
|
|
256
|
+
--app-color-border: color-mix(in srgb, ${text} 16%, transparent);
|
|
257
|
+
--app-color-border-light: color-mix(in srgb, ${text} 9%, transparent);
|
|
258
|
+
--app-color-border-heavy: color-mix(in srgb, ${text} 22%, transparent);
|
|
259
|
+
--wb-surface-primary: color-mix(in srgb, ${surface} 92%, transparent);
|
|
260
|
+
--wb-surface-secondary: color-mix(in srgb, ${surface} 88%, transparent);
|
|
261
|
+
--wb-border: color-mix(in srgb, ${text} 16%, transparent);
|
|
262
|
+
--wb-border-hover: color-mix(in srgb, ${text} 22%, transparent);
|
|
263
|
+
--vscode-foreground: ${text}; --vscode-descriptionForeground: ${secondaryText};
|
|
264
|
+
--vscode-editor-foreground: ${text}; --vscode-input-foreground: ${text};
|
|
265
|
+
--vscode-editor-background: ${surface}; --vscode-editorPane-background: ${surface};
|
|
266
|
+
--vscode-input-background: color-mix(in srgb, ${surface} 96%, transparent);
|
|
267
|
+
--vscode-dropdown-background: color-mix(in srgb, ${surface} 96%, transparent);
|
|
268
|
+
--vscode-menu-background: color-mix(in srgb, ${surface} 96%, transparent);
|
|
269
|
+
--vscode-panel-background: color-mix(in srgb, ${surface} 96%, transparent);
|
|
270
|
+
--vscode-terminal-background: ${surface};
|
|
271
|
+
--vscode-list-hoverBackground: color-mix(in srgb, ${text} 8%, transparent);
|
|
272
|
+
--vscode-list-activeSelectionBackground: color-mix(in srgb, ${accent} 24%, transparent);
|
|
273
|
+
--vscode-list-activeSelectionForeground: ${text};
|
|
274
|
+
--vscode-list-inactiveSelectionBackground: color-mix(in srgb, ${accent} 16%, transparent);
|
|
275
|
+
--vscode-list-inactiveSelectionForeground: ${text};
|
|
276
|
+
--background: color-mix(in srgb, ${surface} ${panelOpacity}, transparent);
|
|
277
|
+
--foreground: ${text}; --card: color-mix(in srgb, ${surface} 88%, transparent);
|
|
278
|
+
--card-foreground: ${text}; --popover: color-mix(in srgb, ${surface} 94%, transparent);
|
|
279
|
+
--popover-foreground: ${text}; --primary: ${accent}; --primary-foreground: ${surface};
|
|
280
|
+
--secondary: color-mix(in srgb, ${surface} 82%, ${secondary}); --secondary-foreground: ${text};
|
|
281
|
+
--muted: color-mix(in srgb, ${surface} 88%, ${secondary});
|
|
282
|
+
--muted-foreground: color-mix(in srgb, ${text} 68%, ${surface});
|
|
283
|
+
--accent: color-mix(in srgb, ${surface} 74%, ${accent}); --accent-foreground: ${text};
|
|
284
|
+
--border: color-mix(in srgb, ${text} 16%, transparent); --input: color-mix(in srgb, ${text} 18%, transparent); --ring: ${accent};
|
|
285
|
+
--sidebar: color-mix(in srgb, ${surface} 88%, transparent); --sidebar-background: color-mix(in srgb, ${surface} 88%, transparent);
|
|
286
|
+
--sidebar-foreground: ${text}; --sidebar-primary: ${accent}; --sidebar-primary-foreground: ${surface};
|
|
287
|
+
--sidebar-accent: color-mix(in srgb, ${surface} 74%, ${accent}); --sidebar-accent-foreground: ${text};
|
|
288
|
+
--sidebar-border: color-mix(in srgb, ${text} 14%, transparent); --sidebar-ring: ${accent};
|
|
289
|
+
--main-surface-primary: color-mix(in srgb, ${surface} 84%, transparent);
|
|
290
|
+
--main-surface-secondary: color-mix(in srgb, ${surface} 72%, transparent);
|
|
291
|
+
--sidebar-surface-primary: color-mix(in srgb, ${surface} 88%, transparent);
|
|
292
|
+
--sidebar-surface-secondary: color-mix(in srgb, ${surface} 76%, transparent);
|
|
293
|
+
--message-surface: color-mix(in srgb, ${surface} 82%, transparent);
|
|
294
|
+
--composer-surface: color-mix(in srgb, ${surface} 88%, transparent);
|
|
295
|
+
}
|
|
296
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] body {
|
|
297
|
+
color: ${text}; background: ${surface} !important;
|
|
298
|
+
}
|
|
299
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] body > #root {
|
|
300
|
+
min-height: 100vh; color: ${text} !important;
|
|
301
|
+
background-color: transparent !important;
|
|
302
|
+
background-image:
|
|
303
|
+
linear-gradient(90deg, ${sidebarVeil} 0 22%, transparent 46%),
|
|
304
|
+
linear-gradient(180deg, transparent 0 43%, ${lowerVeil} 100%),
|
|
305
|
+
${image} !important;
|
|
306
|
+
background-position: left top, left top, ${skin.focus} !important;
|
|
307
|
+
background-repeat: no-repeat !important;
|
|
308
|
+
background-size: 100% 100%, 100% 100%, cover !important;
|
|
309
|
+
}
|
|
310
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] :where(
|
|
311
|
+
.main-surface,
|
|
312
|
+
.browser-main-surface,
|
|
313
|
+
[data-app-shell-main-surface="default"],
|
|
314
|
+
main[class*="_MainContentSurface_"]
|
|
315
|
+
) {
|
|
316
|
+
background: linear-gradient(180deg, transparent 0 40%, color-mix(in srgb, ${surface} 70%, transparent) 100%) !important;
|
|
317
|
+
}
|
|
318
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] .app-shell-left-panel {
|
|
319
|
+
background: color-mix(in srgb, ${surface} 88%, transparent) !important;
|
|
320
|
+
border-right-color: color-mix(in srgb, ${accent} 32%, transparent) !important;
|
|
321
|
+
backdrop-filter: none !important;
|
|
322
|
+
}
|
|
323
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] :where(.bg-background, .bg-sidebar, .bg-card, .bg-token-main-surface-primary, .bg-token-sidebar-surface-primary) {
|
|
324
|
+
background: color-mix(in srgb, ${surface} ${panelOpacity}, transparent) !important;
|
|
325
|
+
}
|
|
326
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] :where(
|
|
327
|
+
[data-response-annotation-conversation],
|
|
328
|
+
[data-local-conversation-final-assistant]:not(:has([data-response-annotation-conversation]))
|
|
329
|
+
) {
|
|
330
|
+
box-sizing: border-box;
|
|
331
|
+
color: ${text} !important;
|
|
332
|
+
background: color-mix(in srgb, ${surface} 90%, transparent) !important;
|
|
333
|
+
border: 1px solid color-mix(in srgb, ${accent} 16%, transparent) !important;
|
|
334
|
+
border-radius: 18px;
|
|
335
|
+
padding: 14px 16px 12px;
|
|
336
|
+
box-shadow: 0 8px 24px color-mix(in srgb, ${text} 8%, transparent) !important;
|
|
337
|
+
backdrop-filter: none !important;
|
|
338
|
+
}
|
|
339
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] :where(.composer-surface-chrome, [data-user-message-bubble], [data-codex-approval-surface]) {
|
|
340
|
+
color: ${text} !important;
|
|
341
|
+
background: color-mix(in srgb, ${surface} 82%, transparent) !important;
|
|
342
|
+
border-color: color-mix(in srgb, ${accent} 24%, transparent) !important;
|
|
343
|
+
box-shadow: 0 8px 24px color-mix(in srgb, ${accent} 12%, transparent) !important;
|
|
344
|
+
backdrop-filter: none !important;
|
|
345
|
+
}
|
|
346
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] [data-app-action-sidebar-thread-active="true"] {
|
|
347
|
+
background: linear-gradient(90deg, color-mix(in srgb, ${accent} 22%, transparent), color-mix(in srgb, ${secondary} 16%, transparent)) !important;
|
|
348
|
+
}
|
|
349
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] :where(.border-border, .border-sidebar-border) { border-color: color-mix(in srgb, ${text} 14%, transparent) !important; }
|
|
350
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] [data-codexhost-settings-shell] {
|
|
351
|
+
--settings-bg: color-mix(in srgb, ${surface} 90%, transparent);
|
|
352
|
+
--settings-sidebar: color-mix(in srgb, ${surface} 86%, ${secondary});
|
|
353
|
+
--settings-panel: color-mix(in srgb, ${surface} 90%, transparent);
|
|
354
|
+
--settings-surface: color-mix(in srgb, ${surface} 82%, ${secondary});
|
|
355
|
+
--settings-surface-hover: color-mix(in srgb, ${surface} 72%, ${accent});
|
|
356
|
+
--settings-inset: color-mix(in srgb, ${surface} 92%, ${secondary});
|
|
357
|
+
--settings-text: ${text}; --settings-muted: color-mix(in srgb, ${text} 68%, ${surface});
|
|
358
|
+
--settings-subtle: color-mix(in srgb, ${text} 52%, ${surface});
|
|
359
|
+
--settings-border: color-mix(in srgb, ${text} 14%, transparent); --settings-focus: ${accent};
|
|
360
|
+
--settings-primary: ${accent}; --settings-primary-hover: color-mix(in srgb, ${accent} 82%, white);
|
|
361
|
+
--settings-primary-text: ${surface};
|
|
362
|
+
}
|
|
363
|
+
${logoCss}${polaroidCss}
|
|
364
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
365
|
+
html[${RENDERER_SKIN_ATTRIBUTE}="${skin.id}"] :where(.app-shell-left-panel, [data-response-annotation-conversation], .composer-surface-chrome, [data-user-message-bubble], [data-codex-approval-surface]) {
|
|
366
|
+
background-color: ${surface} !important;
|
|
367
|
+
}
|
|
368
|
+
}`;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export function applyRendererSkin(
|
|
372
|
+
id: RendererSkinId,
|
|
373
|
+
ownerDocument: Document = document,
|
|
374
|
+
storage?: RendererSkinStorage | null,
|
|
375
|
+
): RendererSkinId {
|
|
376
|
+
const resolvedStorage = storage === undefined ? documentSkinStorage(ownerDocument) : storage;
|
|
377
|
+
const currentStyle = ownerDocument.getElementById(RENDERER_SKIN_STYLE_ID);
|
|
378
|
+
if (id === "native") {
|
|
379
|
+
currentStyle?.remove();
|
|
380
|
+
ownerDocument.documentElement.removeAttribute(RENDERER_SKIN_ATTRIBUTE);
|
|
381
|
+
try { resolvedStorage?.removeItem(RENDERER_SKIN_STORAGE_KEY); } catch { /* visual reset succeeded */ }
|
|
382
|
+
return id;
|
|
383
|
+
}
|
|
384
|
+
const skin = rendererSkinDefinition(id);
|
|
385
|
+
const style = currentStyle ?? ownerDocument.createElement("style");
|
|
386
|
+
style.id = RENDERER_SKIN_STYLE_ID;
|
|
387
|
+
style.textContent = skinCss(skin);
|
|
388
|
+
if (!currentStyle) ownerDocument.head.append(style);
|
|
389
|
+
ownerDocument.documentElement.setAttribute(RENDERER_SKIN_ATTRIBUTE, id);
|
|
390
|
+
try { resolvedStorage?.setItem(RENDERER_SKIN_STORAGE_KEY, id); } catch { /* session-only fallback */ }
|
|
391
|
+
return id;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export function restoreRendererSkin(ownerWindow: Window = window): RendererSkinId {
|
|
395
|
+
const storage = documentSkinStorage(ownerWindow.document);
|
|
396
|
+
const id = readRendererSkin(storage);
|
|
397
|
+
if (id === "native") return id;
|
|
398
|
+
return applyRendererSkin(id, ownerWindow.document, storage);
|
|
399
|
+
}
|
|
@@ -156,6 +156,7 @@ function transportModelIdForAgent(agent: RendererAgent): string | null {
|
|
|
156
156
|
if (agent === "zcode") return encodeHarnessPluginRoute({ harnessId: harnessIdSchema.parse("zcode") });
|
|
157
157
|
if (agent === "trae") return encodeHarnessPluginRoute({ harnessId: harnessIdSchema.parse("trae") });
|
|
158
158
|
if (agent === "cursor-cli") return encodeHarnessPluginRoute({ harnessId: harnessIdSchema.parse("cursor-cli") });
|
|
159
|
+
if (agent === "cline") return encodeHarnessPluginRoute({ harnessId: harnessIdSchema.parse("cline") });
|
|
159
160
|
if (agent === 'codex-harness') return encodeHarnessPluginRoute({ harnessId: harnessIdSchema.parse(agent) });
|
|
160
161
|
return null;
|
|
161
162
|
}
|
|
@@ -955,7 +956,7 @@ export function modelSelectionForAgent(
|
|
|
955
956
|
...(thinkingOptionId ? { thinkingOptionId } : {}),
|
|
956
957
|
...(permissionModeId ? { permissionModeId } : {}),
|
|
957
958
|
})
|
|
958
|
-
: agent === "openclaw" || agent === "hermes" || agent === 'codex-harness' || agent === 'qoder' || agent === 'codebuddy' || agent === 'zcode' || agent === 'trae' || agent === 'cursor-cli'
|
|
959
|
+
: agent === "openclaw" || agent === "hermes" || agent === 'codex-harness' || agent === 'qoder' || agent === 'codebuddy' || agent === 'zcode' || agent === 'trae' || agent === 'cursor-cli' || agent === 'cline'
|
|
959
960
|
? encodeHarnessPluginRoute({
|
|
960
961
|
harnessId: harnessIdSchema.parse(agent),
|
|
961
962
|
...(model ? { model } : {}),
|
|
@@ -75,6 +75,16 @@ describe("Renderer settings localization", () => {
|
|
|
75
75
|
createDefaultRendererSettingsPages(rendererSettingsMessages("zh-CN")).map(
|
|
76
76
|
({ label }) => label,
|
|
77
77
|
),
|
|
78
|
-
).toEqual([
|
|
78
|
+
).toEqual([
|
|
79
|
+
"连接",
|
|
80
|
+
"账号",
|
|
81
|
+
"MCP",
|
|
82
|
+
"Skills",
|
|
83
|
+
"会话导入",
|
|
84
|
+
"存储与验证",
|
|
85
|
+
"皮肤",
|
|
86
|
+
"更新",
|
|
87
|
+
"关于",
|
|
88
|
+
]);
|
|
79
89
|
});
|
|
80
90
|
});
|
|
@@ -27,6 +27,7 @@ describe("Renderer settings foundation", () => {
|
|
|
27
27
|
"Skills",
|
|
28
28
|
"Session Import",
|
|
29
29
|
"Storage & verification",
|
|
30
|
+
"Skins",
|
|
30
31
|
"Updates",
|
|
31
32
|
"About",
|
|
32
33
|
]);
|
|
@@ -37,6 +38,7 @@ describe("Renderer settings foundation", () => {
|
|
|
37
38
|
"session-import",
|
|
38
39
|
"session-import",
|
|
39
40
|
"storage",
|
|
41
|
+
"palette",
|
|
40
42
|
"updates",
|
|
41
43
|
"about",
|
|
42
44
|
]);
|
|
@@ -73,6 +75,7 @@ describe("Renderer settings foundation", () => {
|
|
|
73
75
|
"skills",
|
|
74
76
|
"session-import",
|
|
75
77
|
"storage",
|
|
78
|
+
"skins",
|
|
76
79
|
"updates",
|
|
77
80
|
"about",
|
|
78
81
|
]);
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
RENDERER_SKIN_ATTRIBUTE,
|
|
5
|
+
RENDERER_SKIN_STORAGE_KEY,
|
|
6
|
+
RENDERER_SKIN_STYLE_ID,
|
|
7
|
+
RENDERER_SKINS,
|
|
8
|
+
applyRendererSkin,
|
|
9
|
+
readRendererSkin,
|
|
10
|
+
} from "../../src/settings/skin-runtime.js";
|
|
11
|
+
|
|
12
|
+
class MemoryStorage {
|
|
13
|
+
readonly values = new Map<string, string>();
|
|
14
|
+
|
|
15
|
+
getItem(key: string): string | null {
|
|
16
|
+
return this.values.get(key) ?? null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
setItem(key: string, value: string): void {
|
|
20
|
+
this.values.set(key, value);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
removeItem(key: string): void {
|
|
24
|
+
this.values.delete(key);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function fakeDocument() {
|
|
29
|
+
const attributes = new Map<string, string>();
|
|
30
|
+
let style: { id: string; textContent: string; remove(): void } | null = null;
|
|
31
|
+
const document = {
|
|
32
|
+
documentElement: {
|
|
33
|
+
setAttribute(name: string, value: string) {
|
|
34
|
+
attributes.set(name, value);
|
|
35
|
+
},
|
|
36
|
+
removeAttribute(name: string) {
|
|
37
|
+
attributes.delete(name);
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
head: {
|
|
41
|
+
append(next: typeof style) {
|
|
42
|
+
style = next;
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
getElementById(id: string) {
|
|
46
|
+
return style?.id === id ? style : null;
|
|
47
|
+
},
|
|
48
|
+
createElement() {
|
|
49
|
+
const element = {
|
|
50
|
+
id: "",
|
|
51
|
+
textContent: "",
|
|
52
|
+
remove() {
|
|
53
|
+
style = null;
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
return element;
|
|
57
|
+
},
|
|
58
|
+
} as unknown as Document;
|
|
59
|
+
return { document, attributes, getStyle: () => style };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
describe("renderer skin runtime", () => {
|
|
63
|
+
it("ships a native escape hatch and visual-only attributed references", () => {
|
|
64
|
+
expect(RENDERER_SKINS.map(({ id }) => id)).toEqual([
|
|
65
|
+
"native",
|
|
66
|
+
"miku-488137",
|
|
67
|
+
"genshin-dawn",
|
|
68
|
+
"genshin-night",
|
|
69
|
+
"wuthering-echo",
|
|
70
|
+
"wuthering-tide",
|
|
71
|
+
"naruto-hokage",
|
|
72
|
+
"naruto-sasuke",
|
|
73
|
+
"deepspace-dawn",
|
|
74
|
+
"deepspace-star",
|
|
75
|
+
"dragonball-nimbus",
|
|
76
|
+
"dragonball-super-saiyan",
|
|
77
|
+
"dalao-dianyan",
|
|
78
|
+
"styler-gilded-grandeur",
|
|
79
|
+
"styler-merry-big-top",
|
|
80
|
+
"styler-nocturne-studio",
|
|
81
|
+
"styler-quiet-garden",
|
|
82
|
+
]);
|
|
83
|
+
expect(RENDERER_SKINS[0]?.sourceUrl).toBeNull();
|
|
84
|
+
expect(RENDERER_SKINS.slice(1).every(({ sourceUrl }) => sourceUrl?.startsWith("https://github.com/"))).toBe(true);
|
|
85
|
+
expect(RENDERER_SKINS.slice(1).every(({ heroUrl }) => Boolean(heroUrl))).toBe(true);
|
|
86
|
+
const miku = RENDERER_SKINS.find(({ id }) => id === "miku-488137");
|
|
87
|
+
expect(miku?.logoUrl).toContain("logo.webp");
|
|
88
|
+
expect(miku?.polaroidUrl).toContain("polaroid.webp");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("applies, persists, and fully removes a skin override", () => {
|
|
92
|
+
const storage = new MemoryStorage();
|
|
93
|
+
const fixture = fakeDocument();
|
|
94
|
+
|
|
95
|
+
applyRendererSkin("miku-488137", fixture.document, storage);
|
|
96
|
+
expect(fixture.attributes.get(RENDERER_SKIN_ATTRIBUTE)).toBe("miku-488137");
|
|
97
|
+
expect(fixture.getStyle()?.id).toBe(RENDERER_SKIN_STYLE_ID);
|
|
98
|
+
expect(fixture.getStyle()?.textContent).toContain("--sidebar-background");
|
|
99
|
+
expect(fixture.getStyle()?.textContent).not.toContain("<script");
|
|
100
|
+
expect(fixture.getStyle()?.textContent).toContain("background-image");
|
|
101
|
+
expect(fixture.getStyle()?.textContent).toContain('main[class*="_MainContentSurface_"]');
|
|
102
|
+
expect(fixture.getStyle()?.textContent).toContain('.main-surface');
|
|
103
|
+
expect(fixture.getStyle()?.textContent).toContain('[data-app-shell-main-surface="default"]');
|
|
104
|
+
expect(fixture.getStyle()?.textContent).toContain("[data-response-annotation-conversation]");
|
|
105
|
+
expect(fixture.getStyle()?.textContent).toContain("90%, transparent");
|
|
106
|
+
expect(fixture.getStyle()?.textContent).not.toContain("background: transparent !important; border-color: transparent");
|
|
107
|
+
expect(fixture.getStyle()?.textContent).toContain("--color-text-primary");
|
|
108
|
+
expect(fixture.getStyle()?.textContent).toContain("--color-token-foreground");
|
|
109
|
+
expect(fixture.getStyle()?.textContent).toContain("--app-color-text-foreground");
|
|
110
|
+
expect(fixture.getStyle()?.textContent).toContain("--wb-text-primary");
|
|
111
|
+
expect(fixture.getStyle()?.textContent).toContain("--color-surface-elevated-secondary");
|
|
112
|
+
expect(fixture.getStyle()?.textContent).toContain("--color-background-primary-soft-alpha");
|
|
113
|
+
expect(fixture.getStyle()?.textContent).toContain("--app-color-background-elevated-secondary");
|
|
114
|
+
expect(fixture.getStyle()?.textContent).toContain("--color-codex-diff-surface");
|
|
115
|
+
expect(fixture.getStyle()?.textContent).toContain("--vscode-editor-background");
|
|
116
|
+
expect(fixture.getStyle()?.textContent).toContain("logo.webp");
|
|
117
|
+
expect(fixture.getStyle()?.textContent).toContain("polaroid.webp");
|
|
118
|
+
expect(fixture.getStyle()?.textContent).toContain("body::after");
|
|
119
|
+
expect(fixture.getStyle()?.textContent).not.toContain("background-attachment: fixed");
|
|
120
|
+
expect(fixture.getStyle()?.textContent).not.toContain("backdrop-filter: blur");
|
|
121
|
+
expect(fixture.getStyle()?.textContent).toContain("hero.webp");
|
|
122
|
+
expect(storage.getItem(RENDERER_SKIN_STORAGE_KEY)).toBe("miku-488137");
|
|
123
|
+
expect(readRendererSkin(storage)).toBe("miku-488137");
|
|
124
|
+
|
|
125
|
+
applyRendererSkin("native", fixture.document, storage);
|
|
126
|
+
expect(fixture.attributes.has(RENDERER_SKIN_ATTRIBUTE)).toBe(false);
|
|
127
|
+
expect(fixture.getStyle()).toBeNull();
|
|
128
|
+
expect(storage.getItem(RENDERER_SKIN_STORAGE_KEY)).toBeNull();
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("falls back to native for stale persisted values", () => {
|
|
132
|
+
const storage = new MemoryStorage();
|
|
133
|
+
storage.setItem(RENDERER_SKIN_STORAGE_KEY, "removed-theme");
|
|
134
|
+
expect(readRendererSkin(storage)).toBe("native");
|
|
135
|
+
});
|
|
136
|
+
});
|
|
@@ -40,6 +40,13 @@ export type ThreadHarnessSwitchParams = z.infer<typeof threadHarnessSwitchParams
|
|
|
40
40
|
export declare const threadHarnessSwitchResultSchema: z.ZodObject<{
|
|
41
41
|
threadId: z.core.$ZodBranded<z.ZodString, "HostThreadId", "out">;
|
|
42
42
|
checkpointId: z.ZodString;
|
|
43
|
+
phase: z.ZodOptional<z.ZodEnum<{
|
|
44
|
+
ready: "ready";
|
|
45
|
+
"rolled-back": "rolled-back";
|
|
46
|
+
cancelled: "cancelled";
|
|
47
|
+
}>>;
|
|
48
|
+
fromHarnessId: z.ZodOptional<z.ZodString>;
|
|
49
|
+
toHarnessId: z.ZodOptional<z.ZodString>;
|
|
43
50
|
}, z.core.$strict>;
|
|
44
51
|
export type ThreadHarnessSwitchResult = z.infer<typeof threadHarnessSwitchResultSchema>;
|
|
45
52
|
//# sourceMappingURL=thread-harness-switch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thread-harness-switch.d.ts","sourceRoot":"","sources":["../src/thread-harness-switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,0BAA0B;;;;;EAA8D,CAAC;AACtG,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E,eAAO,MAAM,4BAA4B;;;;;;kBAQ9B,CAAC;AACZ,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAElF;;;GAGG;AACH,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;kBAQjC,CAAC;AAEZ,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AAExF,eAAO,MAAM,+BAA+B
|
|
1
|
+
{"version":3,"file":"thread-harness-switch.d.ts","sourceRoot":"","sources":["../src/thread-harness-switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,0BAA0B;;;;;EAA8D,CAAC;AACtG,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E,eAAO,MAAM,4BAA4B;;;;;;kBAQ9B,CAAC;AACZ,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAElF;;;GAGG;AACH,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;kBAQjC,CAAC;AAEZ,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AAExF,eAAO,MAAM,+BAA+B;;;;;;;;;;kBAQjC,CAAC;AAEZ,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC"}
|
|
@@ -27,6 +27,9 @@ export const threadHarnessSwitchResultSchema = z
|
|
|
27
27
|
.object({
|
|
28
28
|
threadId: hostThreadIdSchema,
|
|
29
29
|
checkpointId: z.string().min(1),
|
|
30
|
+
phase: z.enum(["ready", "rolled-back", "cancelled"]).optional(),
|
|
31
|
+
fromHarnessId: z.string().min(1).optional(),
|
|
32
|
+
toHarnessId: z.string().min(1).optional(),
|
|
30
33
|
})
|
|
31
34
|
.strict();
|
|
32
35
|
//# sourceMappingURL=thread-harness-switch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thread-harness-switch.js","sourceRoot":"","sources":["../src/thread-harness-switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAE9C,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;AAGtG,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC;KAC1C,MAAM,CAAC;IACN,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE;IACzB,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE;IACjB,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;IACrB,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE;IAClB,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE;CACxB,CAAC;KACD,MAAM,EAAE,CAAC;AAGZ;;;GAGG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC;KAC7C,MAAM,CAAC;IACN,QAAQ,EAAE,kBAAkB;IAC5B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;IACrC,MAAM,EAAE,0BAA0B,CAAC,QAAQ,EAAE;IAC7C,QAAQ,EAAE,4BAA4B,CAAC,QAAQ,EAAE;CAClD,CAAC;KACD,MAAM,EAAE,CAAC;AAIZ,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC;KAC7C,MAAM,CAAC;IACN,QAAQ,EAAE,kBAAkB;IAC5B,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"thread-harness-switch.js","sourceRoot":"","sources":["../src/thread-harness-switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAE9C,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;AAGtG,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC;KAC1C,MAAM,CAAC;IACN,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE;IACzB,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE;IACjB,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;IACrB,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE;IAClB,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE;CACxB,CAAC;KACD,MAAM,EAAE,CAAC;AAGZ;;;GAGG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC;KAC7C,MAAM,CAAC;IACN,QAAQ,EAAE,kBAAkB;IAC5B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;IACrC,MAAM,EAAE,0BAA0B,CAAC,QAAQ,EAAE;IAC7C,QAAQ,EAAE,4BAA4B,CAAC,QAAQ,EAAE;CAClD,CAAC;KACD,MAAM,EAAE,CAAC;AAIZ,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC;KAC7C,MAAM,CAAC;IACN,QAAQ,EAAE,kBAAkB;IAC5B,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/B,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC/D,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC3C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;CAC1C,CAAC;KACD,MAAM,EAAE,CAAC"}
|