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,256 @@
1
+ /**
2
+ * 主题的数据与纯函数:token 词表、内置调色板、部署主题记录的规范化。
3
+ * 浏览器、控制台服务端与启动器共用这一份;不依赖 DOM,token 的中文标签由浏览器侧贴。
4
+ */
5
+
6
+ export type ThemeMode = 'light' | 'dark' | 'system';
7
+
8
+ /** `system` 解析之后只剩两种。CSS 变量真正落地时看的是这个。 */
9
+ export type ThemeAppearance = 'light' | 'dark';
10
+
11
+ /** token key → `#rrggbb`。缺格由 `normalizePalette` 用回退表补齐。 */
12
+ export type ThemePalette = Record<string, string>;
13
+
14
+ export interface ThemeScheme {
15
+ id: string;
16
+ name: string;
17
+ note: string;
18
+ /** 浅色与黑夜是**两份独立配色**,不是同一份的明暗算法推导。 */
19
+ palettes: Record<ThemeAppearance, ThemePalette>;
20
+ builtin?: boolean;
21
+ custom?: boolean;
22
+ }
23
+
24
+ /** 一份部署的主题记录,存在 `<部署>/theme.json`。内置方案不进记录。 */
25
+ export interface StoredTheme {
26
+ /** 选中的方案 id(可能指向一个已被删掉的自定义方案,取用时再兜底)。 */
27
+ selectedId: string;
28
+ mode: ThemeMode;
29
+ custom: ThemeScheme[];
30
+ }
31
+
32
+ export const THEME_MODES: readonly ThemeMode[] = ['light', 'dark', 'system'];
33
+
34
+ /** 词表分组与顺序。组标题与逐个 token 的标签在浏览器侧按 id 取。 */
35
+ export const THEME_TOKEN_GROUPS = [
36
+ { id: 'paper', keys: ['paper', 'paper-2', 'sheet', 'sheet-2', 'sheet-3'] },
37
+ { id: 'ink', keys: ['ink', 'ink-soft', 'ink-dim', 'line', 'line-2', 'line-strong'] },
38
+ { id: 'state', keys: ['accent', 'accent-2', 'on-accent', 'ok', 'warn', 'danger'] },
39
+ {
40
+ id: 'timeline',
41
+ keys: ['ink-blue', 'violet', 'agent-surface', 'world-bg', 'world-ink', 'bubble-bg', 'bubble-ink', 'tool-result'],
42
+ },
43
+ {
44
+ id: 'chart',
45
+ keys: [
46
+ 'chart-hit', 'chart-miss', 'chart-output',
47
+ 'chart-1', 'chart-2', 'chart-3', 'chart-4', 'chart-5', 'chart-6', 'chart-7', 'chart-8',
48
+ ],
49
+ },
50
+ ] as const;
51
+
52
+ export const THEME_TOKEN_KEYS: readonly string[] = THEME_TOKEN_GROUPS.flatMap((g) => [...g.keys]);
53
+
54
+ /** 主强调取自明暗版 Logo;正文使用加深或调亮的同色系绿色。 */
55
+ const mintLight: ThemePalette = {
56
+ paper: '#f4f5f4', 'paper-2': '#ecedec', sheet: '#fbfbfb', 'sheet-2': '#f2f3f2', 'sheet-3': '#e8e9e8',
57
+ ink: '#1b1a1e', 'ink-soft': '#5c5c60', 'ink-dim': '#8b8b8f', line: '#e3e4e3', 'line-2': '#d0d2d0', 'line-strong': '#aeb0ae',
58
+ accent: '#00a870', 'accent-2': '#54b494', 'on-accent': '#082a1e', ok: '#19815e', warn: '#96743b', danger: '#b45950',
59
+ 'ink-blue': '#238268', violet: '#25765e', 'agent-surface': '#f4f5f4', 'world-bg': '#f0f1f0', 'world-ink': '#4a4a4e',
60
+ 'bubble-bg': '#e6e9e7', 'bubble-ink': '#1f2221', 'tool-result': '#087452',
61
+ 'chart-hit': '#19815e', 'chart-miss': '#96743b', 'chart-output': '#00a870',
62
+ 'chart-1': '#00a870', 'chart-2': '#54b494', 'chart-3': '#348f86', 'chart-4': '#72967f',
63
+ 'chart-5': '#b59564', 'chart-6': '#9b8071', 'chart-7': '#4a8f9a', 'chart-8': '#889460',
64
+ };
65
+
66
+ const mintDark: ThemePalette = {
67
+ paper: '#121312', 'paper-2': '#181a19', sheet: '#1d1f1e', 'sheet-2': '#242726', 'sheet-3': '#2c302e',
68
+ ink: '#e9eae9', 'ink-soft': '#b0b2b1', 'ink-dim': '#828584', line: '#292c2b', 'line-2': '#383c3a', 'line-strong': '#535856',
69
+ accent: '#2fd59b', 'accent-2': '#78cbae', 'on-accent': '#082a1e', ok: '#76ca9f', warn: '#c4a372', danger: '#d18c83',
70
+ 'ink-blue': '#53bda0', violet: '#91d8bb', 'agent-surface': '#181a19', 'world-bg': '#1e211f', 'world-ink': '#adb2b0',
71
+ 'bubble-bg': '#2c3230', 'bubble-ink': '#e6eae8', 'tool-result': '#75cfa8',
72
+ 'chart-hit': '#76ca9f', 'chart-miss': '#c4a372', 'chart-output': '#2fd59b',
73
+ 'chart-1': '#2fd59b', 'chart-2': '#78cbae', 'chart-3': '#64b8ad', 'chart-4': '#91b99d',
74
+ 'chart-5': '#c4a372', 'chart-6': '#b69b8c', 'chart-7': '#76afb9', 'chart-8': '#a8b17e',
75
+ };
76
+
77
+ const navigatorLight: ThemePalette = {
78
+ paper: '#f5f7fa', 'paper-2': '#e9eef4', sheet: '#ffffff', 'sheet-2': '#f1f4f8', 'sheet-3': '#e3eaf2',
79
+ ink: '#383d43', 'ink-soft': '#536174', 'ink-dim': '#7d8a9c', line: '#dce3eb', 'line-2': '#c6d1df', 'line-strong': '#9dacc0',
80
+ accent: '#6591c3', 'accent-2': '#383d43', 'on-accent': '#111820', ok: '#357389', warn: '#865963', danger: '#a34f63',
81
+ 'ink-blue': '#426c99', violet: '#383d43', 'agent-surface': '#f5f7fa', 'world-bg': '#edf3f8', 'world-ink': '#485665',
82
+ 'bubble-bg': '#e4eef8', 'bubble-ink': '#383d43', 'tool-result': '#355c84',
83
+ 'chart-hit': '#529bbd', 'chart-miss': '#383d43', 'chart-output': '#6591c3',
84
+ 'chart-1': '#6591c3', 'chart-2': '#383d43', 'chart-3': '#81c9ef', 'chart-4': '#a9bed6',
85
+ 'chart-5': '#bc8f9a', 'chart-6': '#637489', 'chart-7': '#4f91ad', 'chart-8': '#c6d3e2',
86
+ };
87
+
88
+ /** 深色背景上的海军蓝边线与文字使用提亮的同色系蓝色。 */
89
+ const navigatorDark: ThemePalette = {
90
+ paper: '#12171d', 'paper-2': '#171d24', sheet: '#202730', 'sheet-2': '#28313c', 'sheet-3': '#323d4a',
91
+ ink: '#f2f5fa', 'ink-soft': '#b8c5d6', 'ink-dim': '#8594a7', line: '#2d3743', 'line-2': '#3c4959', 'line-strong': '#596b80',
92
+ accent: '#81c9ef', 'accent-2': '#6591c3', 'on-accent': '#162331', ok: '#85c8dc', warn: '#d6aeb8', danger: '#e99bae',
93
+ 'ink-blue': '#81c9ef', violet: '#a9bed6', 'agent-surface': '#171d24', 'world-bg': '#202b38', 'world-ink': '#b8c5d6',
94
+ 'bubble-bg': '#2e3d50', 'bubble-ink': '#f2f5fa', 'tool-result': '#9dbfe2',
95
+ 'chart-hit': '#81c9ef', 'chart-miss': '#6591c3', 'chart-output': '#adc7e4',
96
+ 'chart-1': '#81c9ef', 'chart-2': '#6591c3', 'chart-3': '#9dbfe2', 'chart-4': '#b8c5d6',
97
+ 'chart-5': '#fae6e8', 'chart-6': '#8e9fb5', 'chart-7': '#73aec9', 'chart-8': '#cbd6e4',
98
+ };
99
+
100
+ /** Claude 灰阶配赤陶与灰玫瑰强调色;浅色文字使用同色系的深色。 */
101
+ const crabDaisyLight: ThemePalette = {
102
+ paper: '#fcfcfb', 'paper-2': '#f9f9f7', sheet: '#ffffff', 'sheet-2': '#f3f3f0', 'sheet-3': '#f0efec',
103
+ ink: '#0b0b0b', 'ink-soft': '#52514e', 'ink-dim': '#7b7974', line: '#e1e0d9', 'line-2': '#d2d1c7', 'line-strong': '#b4b3a8',
104
+ accent: '#c87c5d', 'accent-2': '#cb7c78', 'on-accent': '#131313', ok: '#006300', warn: '#835100', danger: '#8e2626',
105
+ 'ink-blue': '#cb7c78', violet: '#a15d59', 'agent-surface': '#fcfcfb', 'world-bg': '#f3f3f0', 'world-ink': '#52514e',
106
+ 'bubble-bg': '#f0efec', 'bubble-ink': '#131313', 'tool-result': '#995b43',
107
+ 'chart-hit': '#009300', 'chart-miss': '#a66a00', 'chart-output': '#c87c5d',
108
+ 'chart-1': '#c87c5d', 'chart-2': '#cb7c78', 'chart-3': '#7161e0', 'chart-4': '#009300',
109
+ 'chart-5': '#c6613f', 'chart-6': '#a66a00', 'chart-7': '#7b7974', 'chart-8': '#c04873',
110
+ };
111
+
112
+ const crabDaisyDark: ThemePalette = {
113
+ paper: '#151515', 'paper-2': '#111111', sheet: '#20201f', 'sheet-2': '#1e1e1d', 'sheet-3': '#2c2c2a',
114
+ ink: '#f0efec', 'ink-soft': '#c3c2b7', 'ink-dim': '#97958d', line: '#383835', 'line-2': '#454442', 'line-strong': '#5f5e5a',
115
+ accent: '#c87c5d', 'accent-2': '#cb7c78', 'on-accent': '#131313', ok: '#91d68b', warn: '#db9300', danger: '#ec7e7e',
116
+ 'ink-blue': '#cb7c78', violet: '#cb7c78', 'agent-surface': '#151515', 'world-bg': '#20201f', 'world-ink': '#c3c2b7',
117
+ 'bubble-bg': '#2c2c2a', 'bubble-ink': '#f0efec', 'tool-result': '#c87c5d',
118
+ 'chart-hit': '#91d68b', 'chart-miss': '#db9300', 'chart-output': '#c87c5d',
119
+ 'chart-1': '#c87c5d', 'chart-2': '#cb7c78', 'chart-3': '#a096eb', 'chart-4': '#91d68b',
120
+ 'chart-5': '#ec835a', 'chart-6': '#db9300', 'chart-7': '#97958d', 'chart-8': '#e87ba4',
121
+ };
122
+
123
+ /** 内置方案的调色板,按 id。名称与说明是界面文案,由浏览器侧按 id 贴。 */
124
+ export const BUILTIN_PALETTES: Readonly<Record<string, Record<ThemeAppearance, ThemePalette>>> = {
125
+ mint: { light: mintLight, dark: mintDark },
126
+ navigator: { light: navigatorLight, dark: navigatorDark },
127
+ 'crab-daisy': { light: crabDaisyLight, dark: crabDaisyDark },
128
+ };
129
+
130
+ /** 内置方案 id,第一个是框架默认方案。 */
131
+ export const BUILTIN_SCHEME_IDS: readonly string[] = Object.keys(BUILTIN_PALETTES);
132
+
133
+ /** 记录里没有可用选择时落到哪一个。 */
134
+ export const DEFAULT_SCHEME_ID = BUILTIN_SCHEME_IDS[0];
135
+
136
+ /** `#rrggbb`(大小写不限)。三位简写**不算**——记录里只留规范形式。 */
137
+ export function isHexColor(value: unknown): boolean {
138
+ return /^#[0-9a-f]{6}$/i.test(String(value ?? ''));
139
+ }
140
+
141
+ /**
142
+ * 用户输入 → 规范 `#rrggbb`(小写);认不出给 `null`。
143
+ *
144
+ * 收 `#abc` 简写是因为手打十六进制的人真会那么写,而 `<input type="color">`
145
+ * 永远吐六位——两边喂进同一个函数,编辑器里就不必分两条路。
146
+ */
147
+ export function normalizeHex(value: unknown): string | null {
148
+ const raw = String(value ?? '').trim();
149
+ const short = /^#([0-9a-f]{3})$/i.exec(raw);
150
+ const full = short ? '#' + short[1].split('').map((c) => c + c).join('') : raw;
151
+ return isHexColor(full) ? full.toLowerCase() : null;
152
+ }
153
+
154
+ /** 该明暗变体的兜底调色板(默认方案)。 */
155
+ export function fallbackPalette(appearance: ThemeAppearance): ThemePalette {
156
+ return BUILTIN_PALETTES[DEFAULT_SCHEME_ID][appearance];
157
+ }
158
+
159
+ /**
160
+ * 逐 token 校验 + 补齐。**只留词表里的键**:记录里混进来的野键不该被原样写回
161
+ * `documentElement`,那等于让一份主题记录往全站注入任意 CSS 变量。
162
+ */
163
+ export function normalizePalette(palette: unknown, fallback: ThemePalette): ThemePalette {
164
+ const src = (palette ?? {}) as Record<string, unknown>;
165
+ const out: ThemePalette = {};
166
+ for (const key of THEME_TOKEN_KEYS) {
167
+ const value = src[key];
168
+ out[key] = isHexColor(value) ? String(value).toLowerCase() : fallback[key];
169
+ }
170
+ return out;
171
+ }
172
+
173
+ export function clonePalette(palette: ThemePalette): ThemePalette {
174
+ return { ...palette };
175
+ }
176
+
177
+ export function cloneScheme(scheme: ThemeScheme): ThemeScheme {
178
+ return {
179
+ ...scheme,
180
+ palettes: {
181
+ light: clonePalette(scheme.palettes.light),
182
+ dark: clonePalette(scheme.palettes.dark),
183
+ },
184
+ };
185
+ }
186
+
187
+ /** 方案卡上那条四格色带:底纸 / 主卡纸 / 主强调 / 一个图表系列色。 */
188
+ export function schemeSwatches(scheme: ThemeScheme, appearance: ThemeAppearance): string[] {
189
+ const p = scheme.palettes[appearance];
190
+ return [p.paper, p.sheet, p.accent, p['chart-2']];
191
+ }
192
+
193
+ export function defaultStoredTheme(): StoredTheme {
194
+ return { selectedId: DEFAULT_SCHEME_ID, mode: 'system', custom: [] };
195
+ }
196
+
197
+ /** 自定义方案的名称上限 40 字、说明上限 80 字;缺 id 的记录返回 null。 */
198
+ function normalizeCustomScheme(raw: unknown): ThemeScheme | null {
199
+ if (!raw || typeof raw !== 'object') return null;
200
+ const scheme = raw as Partial<ThemeScheme>;
201
+ if (typeof scheme.id !== 'string' || scheme.id === '') return null;
202
+ const palettes = (scheme.palettes ?? {}) as Partial<ThemeScheme['palettes']>;
203
+ return {
204
+ id: scheme.id,
205
+ name: String(scheme.name ?? '').slice(0, 40),
206
+ note: String(scheme.note ?? '').slice(0, 80),
207
+ palettes: {
208
+ light: normalizePalette(palettes.light, fallbackPalette('light')),
209
+ dark: normalizePalette(palettes.dark, fallbackPalette('dark')),
210
+ },
211
+ custom: true,
212
+ };
213
+ }
214
+
215
+ /** 任意值 → 一份可用的主题记录。字段类型不对的按缺省算,绝不抛。 */
216
+ export function normalizeStoredTheme(value: unknown): StoredTheme {
217
+ if (!value || typeof value !== 'object') return defaultStoredTheme();
218
+ const raw = value as Partial<StoredTheme>;
219
+ return {
220
+ selectedId: typeof raw.selectedId === 'string' ? raw.selectedId : DEFAULT_SCHEME_ID,
221
+ mode: THEME_MODES.includes(raw.mode as ThemeMode) ? (raw.mode as ThemeMode) : 'system',
222
+ custom: Array.isArray(raw.custom)
223
+ ? raw.custom.map(normalizeCustomScheme).filter((s): s is ThemeScheme => s !== null)
224
+ : [],
225
+ };
226
+ }
227
+
228
+ /** JSON 文本 → 主题记录。解析不了或是空串给默认值。 */
229
+ export function parseStoredTheme(raw: string | null | undefined): StoredTheme {
230
+ if (raw == null || raw === '') return defaultStoredTheme();
231
+ try {
232
+ return normalizeStoredTheme(JSON.parse(raw));
233
+ } catch {
234
+ return defaultStoredTheme();
235
+ }
236
+ }
237
+
238
+ /**
239
+ * 记录里选中的那份调色板。选中的自定义方案被删掉、或 id 认不出时落到默认方案。
240
+ * `mode` 为 `system` 时由调用方决定明暗:浏览器问系统,终端按深色。
241
+ */
242
+ export function resolvePalette(state: StoredTheme, appearance: ThemeAppearance): ThemePalette {
243
+ const custom = state.custom.find((s) => s.id === state.selectedId);
244
+ if (custom) return custom.palettes[appearance];
245
+ const builtin = BUILTIN_PALETTES[state.selectedId] ?? BUILTIN_PALETTES[DEFAULT_SCHEME_ID];
246
+ return builtin[appearance];
247
+ }
248
+
249
+ /** 服务端把部署的主题记录注入到这个 id 的 `<script type="application/json">`。 */
250
+ export const THEME_SCRIPT_ID = 'cortico-theme';
251
+
252
+ /** 随首页发出的主题:部署默认方案 id,以及这份部署已保存的记录(没保存过为 null)。 */
253
+ export interface InjectedTheme {
254
+ defaultScheme: string;
255
+ theme: StoredTheme | null;
256
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * 部署的控制台配色记录:`<部署>/theme.json`。控制台读写,启动器只读。
3
+ * 文件内容就是浏览器侧的主题记录形状,写入前逐个 token 规范化。
4
+ */
5
+ import { existsSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ import { normalizeStoredTheme, type StoredTheme } from './shared/theme.ts';
8
+
9
+ export const THEME_FILE = 'theme.json';
10
+
11
+ export interface DeploymentTheme {
12
+ /** 部署还没有记录时为 null;调用方落到框架默认方案。 */
13
+ state: StoredTheme | null;
14
+ /** 文件在但读不成 JSON 时的原因。此时 state 为 null,下一次保存会覆盖它。 */
15
+ error?: string;
16
+ }
17
+
18
+ export function readDeploymentTheme(botDir: string): DeploymentTheme {
19
+ const file = join(botDir, THEME_FILE);
20
+ if (!existsSync(file)) return { state: null };
21
+ try {
22
+ return { state: normalizeStoredTheme(JSON.parse(readFileSync(file, 'utf8')) as unknown) };
23
+ } catch (err) {
24
+ return { state: null, error: err instanceof Error ? err.message : String(err) };
25
+ }
26
+ }
27
+
28
+ /** 规范化后整份替换,返回真正写进去的记录。 */
29
+ export function writeDeploymentTheme(botDir: string, value: unknown): StoredTheme {
30
+ const state = normalizeStoredTheme(value);
31
+ const file = join(botDir, THEME_FILE);
32
+ const temporary = join(botDir, `.${THEME_FILE}.${process.pid}.tmp`);
33
+ writeFileSync(temporary, JSON.stringify(state, null, 2) + '\n', 'utf8');
34
+ rmSync(file, { force: true });
35
+ renameSync(temporary, file);
36
+ return state;
37
+ }