cortico 0.1.0

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.
Files changed (311) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +47 -0
  3. package/package.json +43 -0
  4. package/src/boot.ts +46 -0
  5. package/src/bot.ts +1342 -0
  6. package/src/config-file.ts +41 -0
  7. package/src/core/README.md +92 -0
  8. package/src/core/billing.ts +26 -0
  9. package/src/core/blobs.ts +106 -0
  10. package/src/core/bus.ts +311 -0
  11. package/src/core/config-schema.ts +201 -0
  12. package/src/core/config.ts +262 -0
  13. package/src/core/core.ts +699 -0
  14. package/src/core/cost.ts +244 -0
  15. package/src/core/event-store.ts +304 -0
  16. package/src/core/fork.ts +113 -0
  17. package/src/core/generation.ts +118 -0
  18. package/src/core/instance-lock.ts +215 -0
  19. package/src/core/ipc-logger.ts +105 -0
  20. package/src/core/language.ts +62 -0
  21. package/src/core/log-context.ts +38 -0
  22. package/src/core/loop.ts +1858 -0
  23. package/src/core/markers.ts +48 -0
  24. package/src/core/prefix.ts +121 -0
  25. package/src/core/run.ts +95 -0
  26. package/src/core/secrets.ts +18 -0
  27. package/src/core/session.ts +56 -0
  28. package/src/core/sessions.ts +261 -0
  29. package/src/core/state.ts +104 -0
  30. package/src/core/template.ts +72 -0
  31. package/src/core/timers.ts +129 -0
  32. package/src/core/tool-log.ts +135 -0
  33. package/src/core/transcript.ts +92 -0
  34. package/src/core/truncate.ts +121 -0
  35. package/src/core/types.ts +1140 -0
  36. package/src/core/usage-log.ts +79 -0
  37. package/src/core/util.ts +386 -0
  38. package/src/deploy-listing.ts +160 -0
  39. package/src/deploy.ts +162 -0
  40. package/src/extensions/README.md +72 -0
  41. package/src/extensions/dry-mount.ts +390 -0
  42. package/src/extensions/manifest.ts +153 -0
  43. package/src/extensions/runtime.ts +42 -0
  44. package/src/extensions.ts +519 -0
  45. package/src/launcher.ts +285 -0
  46. package/src/paths.ts +155 -0
  47. package/src/protocol/open-responses/LICENSE +201 -0
  48. package/src/protocol/open-responses/README.md +14 -0
  49. package/src/protocol/open-responses/context-helpers.ts +27 -0
  50. package/src/protocol/open-responses/context-log.ts +59 -0
  51. package/src/protocol/open-responses/context.ts +89 -0
  52. package/src/protocol/open-responses/generated.ts +115 -0
  53. package/src/protocol/open-responses/index.ts +33 -0
  54. package/src/protocol/open-responses/openapi.json +4230 -0
  55. package/src/protocol/open-responses/stream.ts +146 -0
  56. package/src/protocol/open-responses/tokens.ts +31 -0
  57. package/src/providers/README.md +86 -0
  58. package/src/providers/base.ts +111 -0
  59. package/src/providers/configuration.ts +97 -0
  60. package/src/providers/console/config.ts +21 -0
  61. package/src/providers/console/settings.ts +443 -0
  62. package/src/providers/console/strings.ts +74 -0
  63. package/src/providers/console/types.ts +11 -0
  64. package/src/providers/llamacpp/archive.ts +148 -0
  65. package/src/providers/llamacpp/catalog.ts +247 -0
  66. package/src/providers/llamacpp/config.ts +36 -0
  67. package/src/providers/llamacpp/console/client.ts +6 -0
  68. package/src/providers/llamacpp/console/models-panel.ts +120 -0
  69. package/src/providers/llamacpp/console/runtime-panel.ts +173 -0
  70. package/src/providers/llamacpp/console/server.ts +153 -0
  71. package/src/providers/llamacpp/index.ts +95 -0
  72. package/src/providers/llamacpp/native.ts +51 -0
  73. package/src/providers/llamacpp/options.ts +117 -0
  74. package/src/providers/llamacpp/runtime-store.ts +139 -0
  75. package/src/providers/llamacpp/runtime.ts +214 -0
  76. package/src/providers/llamacpp/server.ts +286 -0
  77. package/src/providers/llamacpp/strings.ts +230 -0
  78. package/src/providers/openai-responses-compat/config.ts +20 -0
  79. package/src/providers/openai-responses-compat/index.ts +89 -0
  80. package/src/providers/openai-responses-compat/native.ts +127 -0
  81. package/src/providers/openai-responses-compat/strings.ts +19 -0
  82. package/src/providers/pricebook.ts +75 -0
  83. package/src/providers/registry.ts +137 -0
  84. package/src/providers/strings.ts +71 -0
  85. package/src/providers/transport/chat.ts +156 -0
  86. package/src/providers/transport/errors.ts +48 -0
  87. package/src/providers/transport/history.ts +68 -0
  88. package/src/providers/transport/native-input.ts +83 -0
  89. package/src/providers/transport/native-types.ts +13 -0
  90. package/src/providers/transport/response-assembly.ts +191 -0
  91. package/src/providers/transport/response-http.ts +196 -0
  92. package/src/providers/transport/response-meters.ts +27 -0
  93. package/src/providers/transport/responses-input.ts +56 -0
  94. package/src/web/README.md +84 -0
  95. package/src/web/client/console-pages/builtins/llm-settings/panel.ts +625 -0
  96. package/src/web/client/console-pages/builtins/llm-settings/pricing-panel.ts +168 -0
  97. package/src/web/client/console-pages/builtins/llm-settings/strings.ts +213 -0
  98. package/src/web/client/console-pages/builtins.ts +10 -0
  99. package/src/web/client/console-pages/context.ts +135 -0
  100. package/src/web/client/console-pages/host.ts +633 -0
  101. package/src/web/client/console-pages/loader.ts +132 -0
  102. package/src/web/client/console-pages/strings.ts +90 -0
  103. package/src/web/client/console-pages/tools/strings.ts +49 -0
  104. package/src/web/client/console-pages/tools/view.ts +215 -0
  105. package/src/web/client/core/api.ts +200 -0
  106. package/src/web/client/core/language.ts +56 -0
  107. package/src/web/client/core/lifecycle.ts +132 -0
  108. package/src/web/client/core/router.ts +199 -0
  109. package/src/web/client/core/stream.ts +157 -0
  110. package/src/web/client/core/websocket.ts +82 -0
  111. package/src/web/client/features/appearance/index.ts +333 -0
  112. package/src/web/client/features/appearance/strings.ts +87 -0
  113. package/src/web/client/features/config/index.ts +11 -0
  114. package/src/web/client/features/config/strings.ts +41 -0
  115. package/src/web/client/features/config/view.ts +428 -0
  116. package/src/web/client/features/core/events.ts +197 -0
  117. package/src/web/client/features/core/index.ts +254 -0
  118. package/src/web/client/features/core/run.ts +56 -0
  119. package/src/web/client/features/core/runlog.ts +214 -0
  120. package/src/web/client/features/core/sessions.ts +53 -0
  121. package/src/web/client/features/core/strings.ts +157 -0
  122. package/src/web/client/features/extensions/index.ts +422 -0
  123. package/src/web/client/features/extensions/strings.ts +164 -0
  124. package/src/web/client/features/feature.ts +93 -0
  125. package/src/web/client/features/live/context.ts +280 -0
  126. package/src/web/client/features/live/fork.ts +156 -0
  127. package/src/web/client/features/live/index.ts +392 -0
  128. package/src/web/client/features/live/onboarding.ts +113 -0
  129. package/src/web/client/features/live/protocol.ts +122 -0
  130. package/src/web/client/features/live/sessions.ts +71 -0
  131. package/src/web/client/features/live/status.ts +68 -0
  132. package/src/web/client/features/live/strings.ts +252 -0
  133. package/src/web/client/features/live/timeline.ts +590 -0
  134. package/src/web/client/features/prompts/editor.ts +292 -0
  135. package/src/web/client/features/prompts/index.ts +346 -0
  136. package/src/web/client/features/prompts/strings.ts +136 -0
  137. package/src/web/client/features/prompts/view.ts +256 -0
  138. package/src/web/client/features/providers/index.ts +100 -0
  139. package/src/web/client/features/providers/strings.ts +23 -0
  140. package/src/web/client/features/settings/general.ts +28 -0
  141. package/src/web/client/features/settings/index.ts +82 -0
  142. package/src/web/client/features/settings/strings.ts +33 -0
  143. package/src/web/client/features/storage/index.ts +1 -0
  144. package/src/web/client/features/storage/strings.ts +45 -0
  145. package/src/web/client/features/storage/view.ts +154 -0
  146. package/src/web/client/features/usage/chart.ts +486 -0
  147. package/src/web/client/features/usage/index.ts +407 -0
  148. package/src/web/client/features/usage/labels.ts +46 -0
  149. package/src/web/client/features/usage/range.ts +36 -0
  150. package/src/web/client/features/usage/state.ts +37 -0
  151. package/src/web/client/features/usage/strings.ts +191 -0
  152. package/src/web/client/features/usage/tooltip.ts +86 -0
  153. package/src/web/client/features/usage/types.ts +96 -0
  154. package/src/web/client/features/worlds/index.ts +424 -0
  155. package/src/web/client/features/worlds/strings.ts +121 -0
  156. package/src/web/client/main.ts +273 -0
  157. package/src/web/client/shell/avatar.ts +233 -0
  158. package/src/web/client/shell/index.ts +549 -0
  159. package/src/web/client/shell/strings.ts +89 -0
  160. package/src/web/client/theme/handoff.ts +43 -0
  161. package/src/web/client/theme/palette.ts +109 -0
  162. package/src/web/client/theme/registry.ts +130 -0
  163. package/src/web/client/theme/storage.ts +72 -0
  164. package/src/web/client/theme/strings.ts +123 -0
  165. package/src/web/client/theme/studio.ts +366 -0
  166. package/src/web/client/ui/actions.ts +109 -0
  167. package/src/web/client/ui/data.ts +185 -0
  168. package/src/web/client/ui/dom.ts +23 -0
  169. package/src/web/client/ui/fields.ts +191 -0
  170. package/src/web/client/ui/format.ts +75 -0
  171. package/src/web/client/ui/icons.ts +183 -0
  172. package/src/web/client/ui/images.ts +91 -0
  173. package/src/web/client/ui/index.ts +89 -0
  174. package/src/web/client/ui/lamp.ts +125 -0
  175. package/src/web/client/ui/log.ts +98 -0
  176. package/src/web/client/ui/overlay.ts +184 -0
  177. package/src/web/client/ui/page.ts +8 -0
  178. package/src/web/client/ui/prompt-input.tsx +311 -0
  179. package/src/web/client/ui/sheet.ts +131 -0
  180. package/src/web/client/ui/strings.ts +71 -0
  181. package/src/web/console-pages.ts +367 -0
  182. package/src/web/files.ts +107 -0
  183. package/src/web/path-picker.ts +296 -0
  184. package/src/web/public/index.html +17 -0
  185. package/src/web/public/styles.css +1715 -0
  186. package/src/web/server.ts +1883 -0
  187. package/src/web/shared/client-panel.ts +603 -0
  188. package/src/web/shared/console-protocol.ts +560 -0
  189. package/src/web/shared/css.d.ts +1 -0
  190. package/src/web/shared/path-picker.ts +23 -0
  191. package/src/web/shared/theme.ts +256 -0
  192. package/src/web/theme-store.ts +37 -0
  193. package/src/world.ts +449 -0
  194. package/src/worlds/bilibili/ENV_PROMPT.md +5 -0
  195. package/src/worlds/bilibili/README.md +176 -0
  196. package/src/worlds/bilibili/audience-admission.ts +995 -0
  197. package/src/worlds/bilibili/client.ts +528 -0
  198. package/src/worlds/bilibili/coalescing-buffer.ts +125 -0
  199. package/src/worlds/bilibili/config.ts +185 -0
  200. package/src/worlds/bilibili/console/client.ts +202 -0
  201. package/src/worlds/bilibili/definition.ts +35 -0
  202. package/src/worlds/bilibili/gift-frame.ts +131 -0
  203. package/src/worlds/bilibili/normalize.ts +452 -0
  204. package/src/worlds/bilibili/overlay/announcement.ts +76 -0
  205. package/src/worlds/bilibili/overlay/assets.ts +82 -0
  206. package/src/worlds/bilibili/overlay/model.ts +494 -0
  207. package/src/worlds/bilibili/overlay/project.ts +202 -0
  208. package/src/worlds/bilibili/overlay/server.ts +286 -0
  209. package/src/worlds/bilibili/overlay/types.ts +217 -0
  210. package/src/worlds/bilibili/overlay/web/app.js +690 -0
  211. package/src/worlds/bilibili/overlay/web/editor.css +297 -0
  212. package/src/worlds/bilibili/overlay/web/editor.html +102 -0
  213. package/src/worlds/bilibili/overlay/web/editor.js +2116 -0
  214. package/src/worlds/bilibili/overlay/web/overlay.html +13 -0
  215. package/src/worlds/bilibili/overlay/web/styles.css +258 -0
  216. package/src/worlds/bilibili/protobuf.ts +123 -0
  217. package/src/worlds/bilibili/wire.ts +94 -0
  218. package/src/worlds/bilibili/world.ts +1389 -0
  219. package/src/worlds/console-fixture/ENV_PROMPT.md +1 -0
  220. package/src/worlds/console-fixture/console/client.ts +72 -0
  221. package/src/worlds/console-fixture/world.ts +73 -0
  222. package/src/worlds/index.ts +15 -0
  223. package/src/worlds/minecraft/ENV_PROMPT.md +32 -0
  224. package/src/worlds/minecraft/ENV_PROMPT_CAMERA.md +2 -0
  225. package/src/worlds/minecraft/LICENSE-mineflayer-pathfinder.txt +21 -0
  226. package/src/worlds/minecraft/README.md +917 -0
  227. package/src/worlds/minecraft/blueprint-plan.ts +915 -0
  228. package/src/worlds/minecraft/blueprint-registry.ts +566 -0
  229. package/src/worlds/minecraft/blueprint-repair.ts +236 -0
  230. package/src/worlds/minecraft/blueprint-resource.ts +272 -0
  231. package/src/worlds/minecraft/blueprint.ts +492 -0
  232. package/src/worlds/minecraft/body-lease.ts +340 -0
  233. package/src/worlds/minecraft/bridge.ts +749 -0
  234. package/src/worlds/minecraft/check.ts +651 -0
  235. package/src/worlds/minecraft/chests.ts +292 -0
  236. package/src/worlds/minecraft/client-launch.ts +272 -0
  237. package/src/worlds/minecraft/client-options.ts +85 -0
  238. package/src/worlds/minecraft/client-skins.ts +164 -0
  239. package/src/worlds/minecraft/client-window.ps1 +91 -0
  240. package/src/worlds/minecraft/client.ts +423 -0
  241. package/src/worlds/minecraft/combat-context.ts +109 -0
  242. package/src/worlds/minecraft/combat.ts +1552 -0
  243. package/src/worlds/minecraft/config.ts +499 -0
  244. package/src/worlds/minecraft/console/access.ts +218 -0
  245. package/src/worlds/minecraft/console/client.ts +244 -0
  246. package/src/worlds/minecraft/console/log.ts +110 -0
  247. package/src/worlds/minecraft/console/mount.ts +420 -0
  248. package/src/worlds/minecraft/console/skin.ts +257 -0
  249. package/src/worlds/minecraft/console/style.css +154 -0
  250. package/src/worlds/minecraft/console/world.ts +449 -0
  251. package/src/worlds/minecraft/deaths.ts +135 -0
  252. package/src/worlds/minecraft/definition.ts +18 -0
  253. package/src/worlds/minecraft/engine-child.ts +274 -0
  254. package/src/worlds/minecraft/engine-ipc.ts +98 -0
  255. package/src/worlds/minecraft/entity-facts.ts +132 -0
  256. package/src/worlds/minecraft/escape.ts +407 -0
  257. package/src/worlds/minecraft/executor.ts +14494 -0
  258. package/src/worlds/minecraft/explored.ts +156 -0
  259. package/src/worlds/minecraft/geometry.ts +205 -0
  260. package/src/worlds/minecraft/goal-plan.ts +647 -0
  261. package/src/worlds/minecraft/item-break.ts +126 -0
  262. package/src/worlds/minecraft/item-facts.ts +146 -0
  263. package/src/worlds/minecraft/item-pick.ts +67 -0
  264. package/src/worlds/minecraft/level-dat.ts +176 -0
  265. package/src/worlds/minecraft/log.ts +132 -0
  266. package/src/worlds/minecraft/mineflayer-fixes.ts +1180 -0
  267. package/src/worlds/minecraft/names.ts +377 -0
  268. package/src/worlds/minecraft/pathfinder-lib.d.ts +13 -0
  269. package/src/worlds/minecraft/pathfinder-perf.ts +796 -0
  270. package/src/worlds/minecraft/piglin.ts +49 -0
  271. package/src/worlds/minecraft/policy.ts +547 -0
  272. package/src/worlds/minecraft/precheck.ts +655 -0
  273. package/src/worlds/minecraft/proxy.ts +445 -0
  274. package/src/worlds/minecraft/ranged.ts +635 -0
  275. package/src/worlds/minecraft/readouts.ts +102 -0
  276. package/src/worlds/minecraft/round.ts +26 -0
  277. package/src/worlds/minecraft/search-observation.ts +92 -0
  278. package/src/worlds/minecraft/server-config.ts +467 -0
  279. package/src/worlds/minecraft/server.ts +658 -0
  280. package/src/worlds/minecraft/show.ts +84 -0
  281. package/src/worlds/minecraft/skills.ts +1763 -0
  282. package/src/worlds/minecraft/terrain.ts +1735 -0
  283. package/src/worlds/minecraft/window.ts +96 -0
  284. package/src/worlds/minecraft/works.ts +179 -0
  285. package/src/worlds/minecraft/world.ts +6438 -0
  286. package/src/worlds/qq/ENV_PROMPT.md +5 -0
  287. package/src/worlds/qq/config.ts +108 -0
  288. package/src/worlds/qq/console/client.ts +126 -0
  289. package/src/worlds/qq/console/events.ts +155 -0
  290. package/src/worlds/qq/console/gate.ts +232 -0
  291. package/src/worlds/qq/console/roster.ts +203 -0
  292. package/src/worlds/qq/console/style.css +65 -0
  293. package/src/worlds/qq/conversation.ts +28 -0
  294. package/src/worlds/qq/definition.ts +62 -0
  295. package/src/worlds/qq/driver.ts +375 -0
  296. package/src/worlds/qq/history-tools.ts +209 -0
  297. package/src/worlds/qq/normalize.ts +323 -0
  298. package/src/worlds/qq/qface-map.ts +282 -0
  299. package/src/worlds/qq/vision-prompt.ts +27 -0
  300. package/src/worlds/qq/vision.ts +642 -0
  301. package/src/worlds/qq/vlm.ts +142 -0
  302. package/src/worlds/qq/world.ts +1503 -0
  303. package/src/worlds/terminal/ENV_PROMPT.md +11 -0
  304. package/src/worlds/terminal/config.ts +9 -0
  305. package/src/worlds/terminal/definition.ts +14 -0
  306. package/src/worlds/terminal/world.ts +700 -0
  307. package/src/worlds/websearch/ENV_PROMPT.md +1 -0
  308. package/src/worlds/websearch/brave-client.ts +261 -0
  309. package/src/worlds/websearch/config.ts +75 -0
  310. package/src/worlds/websearch/definition.ts +20 -0
  311. package/src/worlds/websearch/world.ts +171 -0
@@ -0,0 +1,109 @@
1
+ /** 将主题 token 写为 documentElement 的 CSS 变量,并更新明暗标记与 theme-color。 */
2
+
3
+ import {
4
+ THEME_TOKENS,
5
+ type ThemeAppearance,
6
+ type ThemePalette,
7
+ } from './registry.ts';
8
+
9
+ export interface ApplyPaletteOptions {
10
+ /** 解析之后的明暗,落到 `data-color-mode` 与 `color-scheme`(表单控件、滚动条随之变)。 */
11
+ appearance: ThemeAppearance;
12
+ /** 当前方案 id,落到 `data-theme-scheme`;给 CSS 留一个"某方案单独微调"的口子。 */
13
+ schemeId?: string;
14
+ }
15
+
16
+ /** 按 token 词表顺序映射 CSS 变量,仅包含词表中的键。 */
17
+ export function paletteVars(palette: ThemePalette): Array<[string, string]> {
18
+ const out: Array<[string, string]> = [];
19
+ for (const token of THEME_TOKENS) {
20
+ const value = palette[token.key];
21
+ if (typeof value === 'string' && value !== '') out.push(['--' + token.key, value]);
22
+ }
23
+ return out;
24
+ }
25
+
26
+ /**
27
+ * `<meta name="theme-color">` —— 移动端浏览器的地址栏底色。
28
+ * 没有就建一个;页面里已有(`index.html` 静态写的那一个)就改它的 `content`。
29
+ */
30
+ function applyThemeColorMeta(doc: Document, color: string | undefined): void {
31
+ const head = doc.head;
32
+ if (!head || !color) return;
33
+ let meta = doc.querySelector('meta[name="theme-color"]') as HTMLMetaElement | null;
34
+ if (!meta) {
35
+ meta = doc.createElement('meta');
36
+ meta.name = 'theme-color';
37
+ head.appendChild(meta);
38
+ }
39
+ meta.content = color;
40
+ }
41
+
42
+ /** 把一份调色板刷到文档根上。**同步、幂等**,重复调用只是把同样的值再写一遍。 */
43
+ export function applyPalette(
44
+ doc: Document,
45
+ palette: ThemePalette,
46
+ opts: ApplyPaletteOptions,
47
+ ): void {
48
+ const root = doc.documentElement;
49
+ if (!root) return;
50
+ for (const [name, value] of paletteVars(palette)) root.style.setProperty(name, value);
51
+ root.dataset.colorMode = opts.appearance;
52
+ if (opts.schemeId) root.dataset.themeScheme = opts.schemeId;
53
+ root.style.colorScheme = opts.appearance;
54
+ applyThemeColorMeta(doc, palette.paper);
55
+ }
56
+
57
+ /** 读取语义色的计算值;缺少合法颜色时回退到 --ink-dim。 */
58
+ export function readThemeColor(doc: Document, key: string): string {
59
+ const root = doc.documentElement;
60
+ const view = doc.defaultView;
61
+ if (!root || !view) return '';
62
+ const read = (k: string): string => view.getComputedStyle(root).getPropertyValue('--' + k).trim();
63
+ const value = read(key);
64
+ return /^#[0-9a-f]{6}$/i.test(value) ? value : read('ink-dim');
65
+ }
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // 颜色换算
69
+ // ---------------------------------------------------------------------------
70
+
71
+ export interface Hsl {
72
+ /** 0–360 */
73
+ h: number;
74
+ /** 0–100 */
75
+ s: number;
76
+ /** 0–100 */
77
+ l: number;
78
+ }
79
+
80
+ /** 将 #rrggbb 或 #rgb 转为 HSL。 */
81
+ export function hexToHsl(hex: string): Hsl {
82
+ let x = String(hex).replace('#', '');
83
+ if (x.length === 3) x = x.split('').map((c) => c + c).join('');
84
+ const r = parseInt(x.slice(0, 2), 16) / 255;
85
+ const g = parseInt(x.slice(2, 4), 16) / 255;
86
+ const b = parseInt(x.slice(4, 6), 16) / 255;
87
+ const mx = Math.max(r, g, b);
88
+ const mn = Math.min(r, g, b);
89
+ let h = 0;
90
+ let s = 0;
91
+ const l = (mx + mn) / 2;
92
+ if (mx !== mn) {
93
+ const d = mx - mn;
94
+ s = l > 0.5 ? d / (2 - mx - mn) : d / (mx + mn);
95
+ h = mx === r ? (g - b) / d + (g < b ? 6 : 0) : mx === g ? (b - r) / d + 2 : (r - g) / d + 4;
96
+ h *= 60;
97
+ }
98
+ return { h, s: s * 100, l: l * 100 };
99
+ }
100
+
101
+ /** HSL → `hsl(210,12%,40%)`。三个分量都取整——CSS 不需要那么多小数。 */
102
+ export function hslCss(hsl: Hsl): string {
103
+ return `hsl(${Math.round(hsl.h)},${Math.round(hsl.s)}%,${Math.round(hsl.l)}%)`;
104
+ }
105
+
106
+ /** 夹到区间。深浅派生时防止某一族滑到纯黑或纯白(那时候颜色就没有区分度了)。 */
107
+ export function clampNumber(value: number, lo: number, hi: number): number {
108
+ return value < lo ? lo : value > hi ? hi : value;
109
+ }
@@ -0,0 +1,130 @@
1
+ /** 主题的界面文案:方案名、token 标签与分组。数据与纯函数在 web/shared/theme.ts。 */
2
+
3
+ import {
4
+ BUILTIN_PALETTES,
5
+ BUILTIN_SCHEME_IDS,
6
+ THEME_TOKEN_GROUPS,
7
+ cloneScheme,
8
+ type ThemeAppearance,
9
+ type ThemeMode,
10
+ type ThemeScheme,
11
+ } from '../../shared/theme.ts';
12
+ import { S } from './strings.ts';
13
+
14
+ export {
15
+ BUILTIN_PALETTES,
16
+ BUILTIN_SCHEME_IDS,
17
+ DEFAULT_SCHEME_ID,
18
+ THEME_MODES,
19
+ THEME_TOKEN_KEYS,
20
+ clonePalette,
21
+ cloneScheme,
22
+ defaultStoredTheme,
23
+ fallbackPalette,
24
+ isHexColor,
25
+ normalizeHex,
26
+ normalizePalette,
27
+ normalizeStoredTheme,
28
+ parseStoredTheme,
29
+ resolvePalette,
30
+ schemeSwatches,
31
+ } from '../../shared/theme.ts';
32
+ export type {
33
+ InjectedTheme,
34
+ StoredTheme,
35
+ ThemeAppearance,
36
+ ThemeMode,
37
+ ThemePalette,
38
+ ThemeScheme,
39
+ } from '../../shared/theme.ts';
40
+
41
+ export interface ThemeToken {
42
+ /** 编辑器里的分组标题 */
43
+ readonly group: string;
44
+ /** CSS 变量名去掉 `--` 前缀,如 `paper` → `--paper` */
45
+ readonly key: string;
46
+ /** 编辑器里的中文标签 */
47
+ readonly label: string;
48
+ }
49
+
50
+ /** 明暗模式的中文挡位名。分段选择器与提示语共用一套措辞。 */
51
+ export const THEME_MODE_LABELS: Readonly<Record<ThemeMode, string>> = {
52
+ light: S.modeLight,
53
+ dark: S.modeDark,
54
+ system: S.modeSystem,
55
+ };
56
+
57
+ /** 提示语里的"当前变体"。`light`/`dark` 两个词全站只在这儿定义一次。 */
58
+ export const THEME_APPEARANCE_LABELS: Readonly<Record<ThemeAppearance, string>> = {
59
+ light: S.appearanceLight,
60
+ dark: S.appearanceDark,
61
+ };
62
+
63
+ const GROUP_TITLES: Readonly<Record<string, string>> = {
64
+ paper: S.groupPaper,
65
+ ink: S.groupInk,
66
+ state: S.groupState,
67
+ timeline: S.groupTimeline,
68
+ chart: S.groupChart,
69
+ };
70
+
71
+ const SCHEME_TEXT: Readonly<Record<string, { name: string; note: string }>> = {
72
+ mint: { name: S.schemeMint, note: S.schemeMintNote },
73
+ navigator: { name: S.schemeNavigator, note: S.schemeNavigatorNote },
74
+ 'crab-daisy': { name: S.schemeCrabDaisy, note: S.schemeCrabDaisyNote },
75
+ };
76
+
77
+ export const THEME_TOKENS: readonly ThemeToken[] = THEME_TOKEN_GROUPS.flatMap((group) =>
78
+ group.keys.map((key): ThemeToken => ({ group: GROUP_TITLES[group.id], key, label: S.token[key] })),
79
+ );
80
+
81
+ /** 内置方案,贴上界面语言的名称与说明。 */
82
+ export const BUILTIN_SCHEMES: readonly ThemeScheme[] = BUILTIN_SCHEME_IDS.map((id) => ({
83
+ id,
84
+ name: SCHEME_TEXT[id].name,
85
+ note: SCHEME_TEXT[id].note,
86
+ palettes: BUILTIN_PALETTES[id],
87
+ builtin: true,
88
+ }));
89
+
90
+ /** 方案名与说明:自定义方案没填名字时用通用称呼。 */
91
+ export function schemeText(scheme: ThemeScheme): { name: string; note: string } {
92
+ return {
93
+ name: scheme.name || SCHEME_TEXT[scheme.id]?.name || S.customScheme,
94
+ note: scheme.note || SCHEME_TEXT[scheme.id]?.note || S.customNote,
95
+ };
96
+ }
97
+
98
+ /** 全部内置方案的副本。主题记录里没有它们,每次现取。 */
99
+ export function builtinSchemes(): ThemeScheme[] {
100
+ return BUILTIN_SCHEMES.map((scheme) => ({ ...cloneScheme(scheme), builtin: true }));
101
+ }
102
+
103
+ /** 部署记录给的方案 id;不是内置方案就落到框架默认方案。 */
104
+ export function resolveDefaultSchemeId(value: unknown): string {
105
+ const id = String(value ?? '');
106
+ return BUILTIN_SCHEME_IDS.includes(id) ? id : BUILTIN_SCHEME_IDS[0];
107
+ }
108
+
109
+ /**
110
+ * 词表按 `group` 归并,**保持 `THEME_TOKENS` 里的出现顺序**。
111
+ *
112
+ * 编辑器要的就是这个形状;单独拿出来是因为"分组"是这一页唯一有分量的纯逻辑,
113
+ * 而它写在渲染函数里就只能靠看 DOM 来验。
114
+ */
115
+ export function groupedThemeTokens(
116
+ tokens: readonly ThemeToken[] = THEME_TOKENS,
117
+ ): Array<{ group: string; tokens: ThemeToken[] }> {
118
+ const out: Array<{ group: string; tokens: ThemeToken[] }> = [];
119
+ const index = new Map<string, { group: string; tokens: ThemeToken[] }>();
120
+ for (const token of tokens) {
121
+ let bucket = index.get(token.group);
122
+ if (!bucket) {
123
+ bucket = { group: token.group, tokens: [] };
124
+ index.set(token.group, bucket);
125
+ out.push(bucket);
126
+ }
127
+ bucket.tokens.push(token);
128
+ }
129
+ return out;
130
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * 主题记录归部署所有:首屏从服务端注入的 JSON 读,改动回写 `/api/theme`。
3
+ * 这台机器的 localStorage 只在部署还没有记录时读一次,把旧记录交上去。
4
+ */
5
+
6
+ import { post } from '../core/api.ts';
7
+ import {
8
+ DEFAULT_SCHEME_ID,
9
+ THEME_SCRIPT_ID,
10
+ normalizeStoredTheme,
11
+ type InjectedTheme,
12
+ type StoredTheme,
13
+ } from '../../shared/theme.ts';
14
+
15
+ export { THEME_SCRIPT_ID };
16
+
17
+ /** 搬进部署目录之前,主题记录存在这台机器上的两个键;新的在前。 */
18
+ export const LEGACY_THEME_STORAGE_KEYS: readonly string[] = [
19
+ 'cortico.theme.v1',
20
+ 'xuewu.theme-studio.v1',
21
+ ];
22
+
23
+ /** 首页里那段 JSON。`theme` 为 null = 这份部署还没保存过,此时才谈得上迁移本机旧记录。 */
24
+ export function readInjectedTheme(doc: Document): InjectedTheme {
25
+ const fallback: InjectedTheme = { defaultScheme: DEFAULT_SCHEME_ID, theme: null };
26
+ const raw = doc.getElementById(THEME_SCRIPT_ID)?.textContent;
27
+ if (raw == null || raw.trim() === '') return fallback;
28
+ try {
29
+ const value = JSON.parse(raw) as Partial<InjectedTheme> | null;
30
+ if (!value || typeof value !== 'object') return fallback;
31
+ return {
32
+ defaultScheme: typeof value.defaultScheme === 'string' && value.defaultScheme !== ''
33
+ ? value.defaultScheme
34
+ : DEFAULT_SCHEME_ID,
35
+ theme: value.theme == null ? null : normalizeStoredTheme(value.theme),
36
+ };
37
+ } catch {
38
+ return fallback;
39
+ }
40
+ }
41
+
42
+ /** 这台机器上的旧记录。两个键都没有内容时给 `null`;旧记录读完不删。 */
43
+ export function readLegacyLocalTheme(doc: Document): StoredTheme | null {
44
+ let storage: Pick<Storage, 'getItem'> | null = null;
45
+ try {
46
+ storage = doc.defaultView?.localStorage ?? null;
47
+ } catch {
48
+ // 沙箱 iframe 与无痕模式下访问会被拒。
49
+ return null;
50
+ }
51
+ if (!storage) return null;
52
+ for (const key of LEGACY_THEME_STORAGE_KEYS) {
53
+ let raw: string | null = null;
54
+ try {
55
+ raw = storage.getItem(key);
56
+ } catch {
57
+ return null;
58
+ }
59
+ if (raw == null || raw === '') continue;
60
+ try {
61
+ return normalizeStoredTheme(JSON.parse(raw) as unknown);
62
+ } catch {
63
+ continue;
64
+ }
65
+ }
66
+ return null;
67
+ }
68
+
69
+ /** 回写部署的主题记录。失败由调用方呈现,不吞。 */
70
+ export async function saveDeploymentTheme(state: StoredTheme): Promise<void> {
71
+ await post('/api/theme', state);
72
+ }
@@ -0,0 +1,123 @@
1
+ import { pick } from '../core/language.ts';
2
+
3
+ const zh = {
4
+ modeLight: '☀ 浅色',
5
+ modeDark: '◐ 黑夜',
6
+ modeSystem: '◒ 跟随系统',
7
+ appearanceLight: '浅色',
8
+ appearanceDark: '黑夜',
9
+ groupPaper: "背景层级",
10
+ groupInk: '文字与边界',
11
+ groupState: '交互与状态',
12
+ groupTimeline: '终端时间线',
13
+ groupChart: '图表系列',
14
+ token: {
15
+ paper: '页面背景',
16
+ 'paper-2': '侧栏背景',
17
+ sheet: '主卡片背景',
18
+ 'sheet-2': '次级卡片背景',
19
+ 'sheet-3': '压低底色',
20
+ ink: '主要文字',
21
+ 'ink-soft': '次级文字',
22
+ 'ink-dim': '弱化文字',
23
+ line: '细边界',
24
+ 'line-2': '常规边界',
25
+ 'line-strong': '强调边界',
26
+ accent: '主强调',
27
+ 'accent-2': '次强调',
28
+ 'on-accent': '强调色上文字',
29
+ ok: '成功 / 在线',
30
+ warn: '提醒 / 系统',
31
+ danger: '危险 / 失败',
32
+ 'ink-blue': 'Agent 标记',
33
+ violet: '思考标记',
34
+ 'agent-surface': 'Agent 卡片底色',
35
+ 'world-bg': '世界事件底色',
36
+ 'world-ink': '世界事件文字',
37
+ 'bubble-bg': '发送气泡底色',
38
+ 'bubble-ink': '发送气泡文字',
39
+ 'tool-result': '工具结果文字',
40
+ 'chart-hit': '缓存命中',
41
+ 'chart-miss': '未命中输入',
42
+ 'chart-output': '模型输出',
43
+ 'chart-1': '系列 1',
44
+ 'chart-2': '系列 2',
45
+ 'chart-3': '系列 3',
46
+ 'chart-4': '系列 4',
47
+ 'chart-5': '系列 5',
48
+ 'chart-6': '系列 6',
49
+ 'chart-7': '系列 7',
50
+ 'chart-8': '系列 8',
51
+ },
52
+ schemeMint: '脑皮质薄荷',
53
+ schemeMintNote: 'Logo 的薄荷绿、同色系层次与中性灰背景',
54
+ schemeNavigator: '未来领航员',
55
+ schemeNavigatorNote: '可缇 Corti 人设图的海军蓝、天蓝、白与淡粉',
56
+ schemeCrabDaisy: '螃蟹和雏菊',
57
+ schemeCrabDaisyNote: '赤陶、灰玫瑰与 Claude 网页灰阶',
58
+ customScheme: '自定义方案',
59
+ customNote: '自定义配色',
60
+ copyOf: (name: string) => `${name} 副本`,
61
+ };
62
+
63
+ const en: typeof zh = {
64
+ modeLight: '☀ Light',
65
+ modeDark: '◐ Dark',
66
+ modeSystem: '◒ System',
67
+ appearanceLight: 'Light',
68
+ appearanceDark: 'Dark',
69
+ groupPaper: "Background layers",
70
+ groupInk: 'Text & borders',
71
+ groupState: 'Interaction & state',
72
+ groupTimeline: 'Terminal timeline',
73
+ groupChart: 'Chart series',
74
+ token: {
75
+ paper: 'Page background',
76
+ 'paper-2': 'Sidebar background',
77
+ sheet: 'Main card',
78
+ 'sheet-2': 'Secondary card',
79
+ 'sheet-3': 'Recessed ground',
80
+ ink: 'Primary text',
81
+ 'ink-soft': 'Secondary text',
82
+ 'ink-dim': 'Muted text',
83
+ line: 'Hairline border',
84
+ 'line-2': 'Regular border',
85
+ 'line-strong': 'Strong border',
86
+ accent: 'Primary accent',
87
+ 'accent-2': 'Secondary accent',
88
+ 'on-accent': 'Text on accent',
89
+ ok: 'Success / online',
90
+ warn: 'Notice / system',
91
+ danger: 'Danger / failure',
92
+ 'ink-blue': 'Agent marker',
93
+ violet: 'Reasoning marker',
94
+ 'agent-surface': 'Agent card ground',
95
+ 'world-bg': 'World event ground',
96
+ 'world-ink': 'World event text',
97
+ 'bubble-bg': 'Sent bubble ground',
98
+ 'bubble-ink': 'Sent bubble text',
99
+ 'tool-result': 'Tool result text',
100
+ 'chart-hit': 'Cache hit',
101
+ 'chart-miss': 'Uncached input',
102
+ 'chart-output': 'Model output',
103
+ 'chart-1': 'Series 1',
104
+ 'chart-2': 'Series 2',
105
+ 'chart-3': 'Series 3',
106
+ 'chart-4': 'Series 4',
107
+ 'chart-5': 'Series 5',
108
+ 'chart-6': 'Series 6',
109
+ 'chart-7': 'Series 7',
110
+ 'chart-8': 'Series 8',
111
+ },
112
+ schemeMint: 'Cortex Mint',
113
+ schemeMintNote: 'Logo mint and tonal greens over neutral grey',
114
+ schemeNavigator: 'Future Navigator',
115
+ schemeNavigatorNote: 'Navy, sky blue, white and blush from Corti\'s character sheet',
116
+ schemeCrabDaisy: 'Crab & Daisy',
117
+ schemeCrabDaisyNote: 'Terracotta and dusty rose over Claude web greys',
118
+ customScheme: 'Custom scheme',
119
+ customNote: 'Custom palette',
120
+ copyOf: (name: string) => `${name} copy`,
121
+ };
122
+
123
+ export const S = pick({ zh, en });