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,560 @@
1
+ /**
2
+ * 控制台贡献与 manifest 协议,供 Node 和浏览器共用,不依赖 DOM 或 node:*。
3
+ * 页面类别为 world、llm、persona;声明可含本地路径与回调,manifest 仅含可公开字段。
4
+ * 协议保持通用,具体页的语义和实现由贡献方提供。
5
+ */
6
+
7
+ import type { ConfigGroup, StoragePart } from '../../core/types.ts';
8
+
9
+ /** 前端拒绝渲染不支持的协议版本。 */
10
+ export const CONSOLE_PROTOCOL_VERSION = 1;
11
+
12
+ /**
13
+ * 界面语言随每个请求走:HTTP 请求带这个头,WebSocket 握手带这个查询参数(浏览器的
14
+ * WebSocket 构造器带不了头)。值是 `zh` / `en`;缺席或不认识时服务端用部署默认语言。
15
+ */
16
+ export const CONSOLE_LANGUAGE_HEADER = 'x-cortico-language';
17
+ export const CONSOLE_LANGUAGE_QUERY = 'language';
18
+
19
+ /** world:World 控制面;llm:LLM 供应模块;persona:bot/Persona 控制面;memory:Persona 的 Memory 页。framework 为保留类别,不经贡献协议提供页面。 */
20
+ export type ConsolePageKind = 'framework' | 'world' | 'persona' | 'llm' | 'memory';
21
+
22
+ /** 能真正贡献一页的类别(框架除外)。 */
23
+ export type ContributingKind = Exclude<ConsolePageKind, 'framework'>;
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // 1. 命名空间规则
27
+ // ---------------------------------------------------------------------------
28
+
29
+ /** Page ID 使用 kind:name 命名空间,如 world:chat、persona:demo、memory:demo、llm:sample;Panel ID 仅在页内唯一。 */
30
+ const PAGE_ID_RE = /^(world|persona|llm|memory):[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
31
+
32
+ /** Panel ID 只需在自己这一页内唯一,所以不带任何前缀。 */
33
+ const PANEL_ID_RE = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
34
+
35
+ export interface ParsedPageId {
36
+ kind: ContributingKind;
37
+ /** 冒号后的部分:`world:chat` → `chat` */
38
+ name: string;
39
+ }
40
+
41
+ /** 合法则返回拆解结果,否则 null。调用方负责报错措辞。 */
42
+ export function parsePageId(id: string): ParsedPageId | null {
43
+ if (!PAGE_ID_RE.test(id)) return null;
44
+ const idx = id.indexOf(':');
45
+ return { kind: id.slice(0, idx) as ContributingKind, name: id.slice(idx + 1) };
46
+ }
47
+
48
+ export function isPanelId(id: string): boolean {
49
+ return PANEL_ID_RE.test(id);
50
+ }
51
+
52
+ /** 内置面板名以小写字母开头,后续允许小写字母、数字和连字符。 */
53
+ const BUILTIN_PANEL_RE = /^[a-z][a-z0-9-]*$/;
54
+
55
+ export function isBuiltinPanel(name: unknown): name is string {
56
+ return typeof name === 'string' && BUILTIN_PANEL_RE.test(name);
57
+ }
58
+
59
+ /** 构建脚本与服务端注册表共用的目录到 page id 映射。 */
60
+ export function pageIdFor(kind: ContributingKind, name: string): string {
61
+ return `${kind}:${name}`;
62
+ }
63
+
64
+ // ---------------------------------------------------------------------------
65
+ // 2. Asset 安全模型
66
+ // ---------------------------------------------------------------------------
67
+
68
+ /** 资源 key:Memory 页与同名 Persona 页共用一份浏览器产物,其余等于 page id。资源 URL 由构建清单和服务端资源表提供,贡献声明不提供路径。 */
69
+ export function assetKeyForPage(pageId: string): string {
70
+ const parsed = parsePageId(pageId);
71
+ return parsed?.kind === 'memory' ? pageIdFor('persona', parsed.name) : pageId;
72
+ }
73
+
74
+ /** 构建产物里一页的浏览器资源。值是 URL 路径,不是文件系统路径。 */
75
+ export interface ConsoleAssetEntry {
76
+ js: string;
77
+ css?: string;
78
+ }
79
+
80
+ export interface ConsoleAssetManifest {
81
+ protocolVersion: typeof CONSOLE_PROTOCOL_VERSION;
82
+ /** 内核入口;尚未构建时为 null */
83
+ core: string | null;
84
+ /** key 为 page id。 */
85
+ providers: Record<string, ConsoleAssetEntry>;
86
+ }
87
+
88
+ /** 静态资源 URL 的唯一合法前缀。服务端把它映射到 `dist/web/`。 */
89
+ export const CONSOLE_ASSET_PREFIX = '/assets/';
90
+
91
+ /** 资源 URL 仅允许 /assets/ 下的字母、数字、点、下划线、横线和斜杠;拒绝路径回溯、编码、控制字符、反斜杠和查询串。 */
92
+ const ASSET_URL_RE = /^\/assets\/[A-Za-z0-9._/-]+$/;
93
+
94
+ export function isSafeAssetUrl(url: unknown): url is string {
95
+ if (typeof url !== 'string' || !ASSET_URL_RE.test(url)) return false;
96
+ if (url.includes('//')) return false;
97
+ return !url.split('/').includes('..');
98
+ }
99
+
100
+ /** 链接允许 HTTP(S)、单斜杠开头的同源路径及非执行类应用协议;拒绝执行类协议、协议相对 URL 与控制字符。 */
101
+ const EXECUTING_SCHEMES = new Set([
102
+ 'javascript:', 'data:', 'vbscript:', 'blob:', 'filesystem:',
103
+ ]);
104
+
105
+ /** 控制字符(含换行/回车/制表)。用码点构造,免得源码里真嵌进控制字符。 */
106
+ const CONTROL_CHARS_RE = new RegExp(`[${String.fromCharCode(0)}-${String.fromCharCode(31)}${String.fromCharCode(127)}]`);
107
+
108
+ export function isSafeLinkHref(href: unknown): href is string {
109
+ if (typeof href !== 'string' || href === '') return false;
110
+ if (CONTROL_CHARS_RE.test(href)) return false;
111
+ if (href.startsWith('//')) return false;
112
+ if (href.startsWith('/')) return true;
113
+ try {
114
+ return !EXECUTING_SCHEMES.has(new URL(href).protocol);
115
+ } catch {
116
+ return false;
117
+ }
118
+ }
119
+
120
+ // ---------------------------------------------------------------------------
121
+ // 3. 声明侧:贡献方交给框架的东西
122
+ // ---------------------------------------------------------------------------
123
+
124
+ /** 状态徽标。控制台原样显示,不解释语义。 */
125
+ export interface ConsoleBadge {
126
+ label: string;
127
+ value: string | number;
128
+ tone?: 'on' | 'off' | 'plain';
129
+ }
130
+
131
+ /** 贡献方自报的四态链路灯,与 core 的 WorldLamp 同形;浏览器协议独立声明该结构。 */
132
+ export interface ConsoleLamp {
133
+ /** 这是哪条链路。导航上没有它的位置,只进悬停说明。 */
134
+ label: string;
135
+ state: 'online' | 'loading' | 'error' | 'offline';
136
+ /** 悬停时的一句细节。不占版面,只进 title。 */
137
+ hint?: string;
138
+ }
139
+
140
+ const LAMP_STATES: readonly ConsoleLamp['state'][] = ['online', 'loading', 'error', 'offline'];
141
+
142
+ /**
143
+ * 一页最多点几颗灯。与 `src/core/types.ts` 的 `MODULE_LAMP_MAX` 同值——
144
+ * 数是版面给的(左栏一行放得下这么多颗 6px 的点),所以由渲染这一侧定。
145
+ */
146
+ export const LAMP_MAX = 7;
147
+
148
+ /** 丢弃缺少 label 或 state 非法的灯,并截断到 LAMP_MAX。 */
149
+ export function sanitizeLamps(value: unknown): ConsoleLamp[] {
150
+ if (!Array.isArray(value)) return [];
151
+ const out: ConsoleLamp[] = [];
152
+ for (const raw of value) {
153
+ if (out.length >= LAMP_MAX) break;
154
+ const lamp = raw as ConsoleLamp | null;
155
+ if (!lamp || !LAMP_STATES.includes(lamp.state)) continue;
156
+ if (typeof lamp.label !== 'string' || lamp.label === '') continue;
157
+ const one: ConsoleLamp = { label: lamp.label, state: lamp.state };
158
+ if (typeof lamp.hint === 'string' && lamp.hint !== '') one.hint = lamp.hint;
159
+ out.push(one);
160
+ }
161
+ return out;
162
+ }
163
+
164
+ /** 贡献方自带的独立页面入口。控制台不解析路径语义;主题交接只在显式请求时发生。 */
165
+ export interface ConsoleLink {
166
+ label: string;
167
+ href: string;
168
+ /** 打开时把控制台当前的已解析主题作为一次性快照放进 URL fragment。 */
169
+ inheritTheme?: boolean;
170
+ }
171
+
172
+ /**
173
+ * 一个专用面板的声明。
174
+ *
175
+ * **声明了 panel 就意味着有一份浏览器实现**——默认是这一页自己的扩展。声明式的
176
+ * 东西(badge / config / prompt / storage / link)不是 panel,它们由控制台通用
177
+ * 渲染,贡献方不必写一行浏览器代码。
178
+ *
179
+ * 判据:简单配置走 JSON Schema;复杂 UI 直接写 TS 扩展,
180
+ * **不为它发明 JSON DSL**。
181
+ */
182
+ export interface ConsolePanelDecl {
183
+ /** 一页内唯一,`[a-z0-9-]`。 */
184
+ id: string;
185
+ title: string;
186
+ /** 一句话说明,控制台可显示在标题旁 */
187
+ description?: string;
188
+ /** 允许经 HTTP GET 调用的方法,省略时只接受 POST;该声明只留在服务端,不进入 manifest。 */
189
+ getMethods?: readonly string[];
190
+ /**
191
+ * 这块面板的实现由控制台核心提供,值是它在内核那张内置表里的名字。
192
+ *
193
+ * 一页的面板全是内置时,这一页不需要浏览器产物。装在仓库外的贡献方(外部
194
+ * npm 包)拿不到框架的浏览器代码,通用面板只能走这条路。
195
+ */
196
+ builtin?: string;
197
+ /**
198
+ * 挂进同页某块面板开出的插槽,值是那块面板的插槽名。带 slot 的面板没有自己的页签,
199
+ * 由宿主面板调 `ctx.mountSlot` 挂进去,同一插槽的多块按声明顺序排列。
200
+ * 数据面照旧按自己的 panel id 分派。
201
+ */
202
+ slot?: string;
203
+ }
204
+
205
+ /**
206
+ * 一页自有的固定提示词源文件。`path` 是**本地绝对路径**,因此这个类型
207
+ * 只存在于声明侧——读文件、算 revision、原子写回都由框架代办,路径不上线。
208
+ */
209
+ export interface ConsolePromptDocDecl {
210
+ /** 全局唯一,惯例 `worlds.<World>.<名>` / `core.<名>` */
211
+ key: string;
212
+ title: string;
213
+ description: string;
214
+ path: string;
215
+ }
216
+
217
+ /**
218
+ * 一页交给框架的完整贡献。
219
+ *
220
+ * 每次组装 manifest 时重新取一遍(`badges` 是活数据),所以字段是值不是 thunk——
221
+ * 与既有的 `World.console()` 同一个用法。
222
+ */
223
+ export interface ConsolePageContribution {
224
+ /** `world:chat` / `persona:demo`;`parsePageId` 校验 */
225
+ id: string;
226
+ kind: ContributingKind;
227
+ /** 人类可读名,导航与卡片上显示 */
228
+ label: string;
229
+
230
+ /** 状态灯,一条链路一颗。不报 = 控制台不画灯(框架不替贡献方猜自己的状态)。 */
231
+ lamps?: ConsoleLamp[];
232
+ badges?: ConsoleBadge[];
233
+ panels?: ConsolePanelDecl[];
234
+ links?: ConsoleLink[];
235
+
236
+ /** 按 JSON Schema 声明的可调项,控制台通用渲染 */
237
+ config?: ConfigGroup[];
238
+ /** 可编辑的固定提示词源文件 */
239
+ promptDocs?: ConsolePromptDocDecl[];
240
+ /** 这一页自己攒下的、可清除的存储 */
241
+ storage?: StoragePart[];
242
+
243
+ /**
244
+ * 面板数据面。控制台只把 HTTP 请求翻译成一次 `(panel, method, args)` 调用——
245
+ * 语义、参数校验、结果形状全归这一页。返回 `{ $binary: { mime, base64 } }`
246
+ * 时按二进制响应(音频试听这类)。不声明 = 这一页的面板没有数据面。
247
+ */
248
+ invoke?(panel: string, method: string, args: unknown[]): Promise<unknown>;
249
+
250
+ /**
251
+ * 按 panel 分派的推送通道,消息语义归这一页;未声明此通道时拒绝对应 WS 握手。
252
+ * 每条 socket 连接调用一次 stream(),同一面板的 N 条连接产生 N 次独立调用;框架不广播、不去重、不保证单实例。
253
+ * 重连发起全新调用,不携带续播游标或重放断连期间的帧。当前协议无背压信号和二进制帧,onClose 不提供关闭原因。
254
+ */
255
+ stream?(panel: string, socket: ConsoleStream): void;
256
+
257
+ /**
258
+ * 装配态。框架对所有页一视同仁地报这三态;不适用的(persona 页)
259
+ * 恒为 `active`。
260
+ */
261
+ availability?: ConsolePageAvailability;
262
+ /** Persona定义的渠道(true),还是部署侧选配的外挂(false/缺省) */
263
+ declared?: boolean;
264
+ /** `missing` 时的原因,原样显示 */
265
+ reason?: string;
266
+ /** 当前对 agent 可见。不适用的页省略。 */
267
+ agentVisible?: boolean;
268
+ /** 可见性已改但 system 前缀还是旧的。不适用的页省略。 */
269
+ prefixDrifted?: boolean;
270
+ }
271
+
272
+ /**
273
+ * - `active` 已装配并运行
274
+ * - `inactive` 本地有实现但这次没载入(面板仍可露出,比如激活前的接入配置)
275
+ * - `missing` 不可用:缺少实现、构造失败或工具冲突;原因见 reason
276
+ */
277
+ export type ConsolePageAvailability = 'active' | 'inactive' | 'missing';
278
+
279
+ /** 运行期校验用的取值表。 */
280
+ const AVAILABILITY: readonly ConsolePageAvailability[] = ['active', 'inactive', 'missing'];
281
+
282
+ /**
283
+ * 一条已建立的流式连接,交给贡献方用。
284
+ *
285
+ * **故意不是 `ws.WebSocket`**:这份协议既被服务端也被浏览器 import,不能引宿主依赖;
286
+ * 而且把贡献方与某个具体 WS 实现解耦之后,跑在子进程里的贡献方也能实现它
287
+ * (高频与长阻塞的 World 本来就隔离成子进程)。服务端负责把真
288
+ * socket 包成这个形状。
289
+ */
290
+ export interface ConsoleStream {
291
+ /** 推一帧。连接已关时静默丢弃,不抛。 */
292
+ send(data: string): void;
293
+ /** 主动关闭。`reason` 原样带给对端。 */
294
+ close(reason?: string): void;
295
+ /** 对端来的帧。 */
296
+ onMessage(cb: (text: string) => void): void;
297
+ /** 连接结束(对端关、网络断、面板 unmount 都会到这里)。 */
298
+ onClose(cb: () => void): void;
299
+ /** 连接是否还活着。 */
300
+ readonly open: boolean;
301
+ }
302
+
303
+ /** 二进制返回的约定形状。 */
304
+ export interface ConsoleBinaryResult {
305
+ $binary: { mime: string; base64: string };
306
+ }
307
+
308
+ /** 服务端内部的流式文件返回;路径不会写入 JSON 响应。 */
309
+ export interface ConsoleFileResult {
310
+ $file: { mime: string; path: string; bytes: number; sha256: string };
311
+ }
312
+
313
+ export function isBinaryResult(v: unknown): v is ConsoleBinaryResult {
314
+ const bin = (v as ConsoleBinaryResult | null)?.$binary;
315
+ return !!bin && typeof bin.base64 === 'string';
316
+ }
317
+
318
+ export function isFileResult(v: unknown): v is ConsoleFileResult {
319
+ const file = (v as ConsoleFileResult | null)?.$file;
320
+ return !!file
321
+ && typeof file.mime === 'string'
322
+ && typeof file.path === 'string'
323
+ && Number.isSafeInteger(file.bytes)
324
+ && file.bytes >= 0
325
+ && typeof file.sha256 === 'string'
326
+ && /^[0-9a-f]{64}$/.test(file.sha256);
327
+ }
328
+
329
+ // ---------------------------------------------------------------------------
330
+ // 4. 线上侧:Manifest DTO
331
+ // ---------------------------------------------------------------------------
332
+
333
+ export interface ConsolePanelManifest {
334
+ id: string;
335
+ title: string;
336
+ description?: string;
337
+ /** 由内核那张内置表提供实现;缺省则去取这一页自己的扩展。 */
338
+ builtin?: string;
339
+ /** 挂进同页某块面板的插槽,没有自己的页签。 */
340
+ slot?: string;
341
+ }
342
+
343
+ /** 可安全上线的前缀源索引;本地路径与正文仍只走 `/api/prompts`。 */
344
+ export interface ConsolePromptManifest {
345
+ key: string;
346
+ title: string;
347
+ description: string;
348
+ }
349
+
350
+ export interface ConsolePageManifest {
351
+ id: string;
352
+ kind: ContributingKind;
353
+ label: string;
354
+ availability: ConsolePageAvailability;
355
+
356
+ lamps?: ConsoleLamp[];
357
+ badges?: ConsoleBadge[];
358
+ panels?: ConsolePanelManifest[];
359
+ prompts?: ConsolePromptManifest[];
360
+ /**
361
+ * 这一页通过 ConsolePageContribution.config 显式认领的配置组 id;schema 和值经 /api/config 提供。
362
+ * 归属不从 owner 推断;未认领的组显示在框架设置页。
363
+ */
364
+ configGroups?: string[];
365
+ /** 这一页声明的存储项 key;清单与清除仍走 /api/storage。 */
366
+ storageKeys?: string[];
367
+ links?: ConsoleLink[];
368
+
369
+ declared?: boolean;
370
+ reason?: string;
371
+ agentVisible?: boolean;
372
+ prefixDrifted?: boolean;
373
+
374
+ /** 浏览器扩展资源由服务端解析构建产物得到;缺省时非内置面板显示缺少产物错误,内置面板不依赖该字段。 */
375
+ client?: ConsoleAssetEntry;
376
+ }
377
+
378
+ export interface ConsoleManifest {
379
+ protocolVersion: typeof CONSOLE_PROTOCOL_VERSION;
380
+ /** 每一页一条。字段名是线协议形状,与自带前端的构建产物同步,故未改名。 */
381
+ providers: ConsolePageManifest[];
382
+ framework: {
383
+ /** 框架级表面挂没挂。前端据此决定不渲染哪一块,不必拿 503 当信号。 */
384
+ capabilities: Record<string, boolean>;
385
+ };
386
+ }
387
+
388
+ // ---------------------------------------------------------------------------
389
+ // 5. 路由
390
+ // ---------------------------------------------------------------------------
391
+
392
+ /** Manifest 端点。 */
393
+ export const CONSOLE_MANIFEST_ROUTE = '/api/console/manifest';
394
+
395
+ /** 状态灯接口:{ lamps: { [pageId]: ConsoleLamp[] } },用于独立轮询灯状态。 */
396
+ export const CONSOLE_LAMPS_ROUTE = '/api/console/lamps';
397
+
398
+ /** `CONSOLE_LAMPS_ROUTE` 的响应体:page id → 它那排灯。 */
399
+ export interface ConsoleLampsResponse {
400
+ lamps: Record<string, ConsoleLamp[]>;
401
+ }
402
+
403
+ /**
404
+ * 框架的 provider 状态灯键,与贡献页 id 使用不同的 kind。
405
+ */
406
+ export const PROVIDERS_LAMP_ID = 'framework:providers';
407
+
408
+ /**
409
+ * Panel RPC 路径。page id 含冒号,调用方**必须** `encodeURIComponent`。
410
+ * GET 用于轮询读与 `<audio src>` 这类只能带 URL 的场合(args 经 query 传 JSON 数组);
411
+ * POST 用于带参调用。
412
+ *
413
+ * 路径里的 `providers` 段是**线协议形状**,与自带前端的构建产物同步,故未随类型改名。
414
+ */
415
+ export function panelRoute(pageId: string, panelId: string, method: string): string {
416
+ return `/api/console/providers/${encodeURIComponent(pageId)}`
417
+ + `/panels/${encodeURIComponent(panelId)}`
418
+ + `/${encodeURIComponent(method)}`;
419
+ }
420
+
421
+ /**
422
+ * 流式通道的 WS 路径。与 `panelRoute` 同构:page + panel 定位,
423
+ * 之后的语义全归那一页。
424
+ */
425
+ export function panelStreamRoute(pageId: string, panelId: string): string {
426
+ return `/ws/providers/${encodeURIComponent(pageId)}/panels/${encodeURIComponent(panelId)}`;
427
+ }
428
+
429
+ // ---------------------------------------------------------------------------
430
+ // 6. 校验
431
+ // ---------------------------------------------------------------------------
432
+
433
+ export interface ContributionProblem {
434
+ pageId: string;
435
+ message: string;
436
+ }
437
+
438
+ /**
439
+ * 校验一批贡献,返回**所有**问题(不是遇到第一个就停)——注册表要能一次告诉
440
+ * 部署者他装的东西哪儿不对。校验只看协议规则,不看语义。
441
+ */
442
+ export function validateContributions(
443
+ contributions: readonly ConsolePageContribution[],
444
+ ): ContributionProblem[] {
445
+ const problems: ContributionProblem[] = [];
446
+ const seenPage = new Set<string>();
447
+
448
+ for (const c of contributions) {
449
+ const parsed = parsePageId(c.id);
450
+ if (!parsed) {
451
+ problems.push({
452
+ pageId: c.id,
453
+ message: `provider id 不合法「${c.id}」:应形如 world:chat / persona:demo(小写字母数字与连字符)`,
454
+ });
455
+ continue;
456
+ }
457
+ if (parsed.kind !== c.kind) {
458
+ problems.push({
459
+ pageId: c.id,
460
+ message: `provider id 的前缀是 ${parsed.kind},但 kind 声明为 ${c.kind}`,
461
+ });
462
+ }
463
+ if (seenPage.has(c.id)) {
464
+ problems.push({ pageId: c.id, message: `provider id 重复:${c.id}` });
465
+ continue;
466
+ }
467
+ seenPage.add(c.id);
468
+
469
+ if (!c.label) {
470
+ problems.push({ pageId: c.id, message: 'label 不能为空' });
471
+ }
472
+
473
+ // 类型只在 TS 侧管用。JS 侧的贡献方、或来自 JSON 配置的值,能塞任意字符串
474
+ // 给前端,所以运行期也要查一次。
475
+ if (c.availability !== undefined && !AVAILABILITY.includes(c.availability)) {
476
+ problems.push({
477
+ pageId: c.id,
478
+ message: `availability 不合法「${String(c.availability)}」:只能是 ${AVAILABILITY.join(' / ')}`,
479
+ });
480
+ }
481
+
482
+ const seenPanel = new Set<string>();
483
+ for (const p of c.panels ?? []) {
484
+ if (!isPanelId(p.id)) {
485
+ problems.push({
486
+ pageId: c.id,
487
+ message: `panel id 不合法「${p.id}」:只允许小写字母数字与连字符,且不带 provider 前缀`,
488
+ });
489
+ continue;
490
+ }
491
+ if (seenPanel.has(p.id)) {
492
+ problems.push({ pageId: c.id, message: `panel id 在本 provider 内重复:${p.id}` });
493
+ continue;
494
+ }
495
+ seenPanel.add(p.id);
496
+ if (!p.title) {
497
+ problems.push({ pageId: c.id, message: `panel「${p.id}」缺 title` });
498
+ }
499
+ if (p.slot !== undefined && !isPanelId(p.slot)) {
500
+ problems.push({
501
+ pageId: c.id,
502
+ message: `panel「${p.id}」的 slot 不合法「${String(p.slot)}」:只允许小写字母数字与连字符`,
503
+ });
504
+ }
505
+ }
506
+ }
507
+ return problems;
508
+ }
509
+
510
+ /** 序列化可公开的 manifest 字段,省略回调、本地路径、schema 与存储动作。独立过滤不安全链接和非法 builtin 面板;数组浅拷贝,调用方记录被过滤项。 */
511
+ export function toPageManifest(
512
+ c: ConsolePageContribution,
513
+ client?: ConsoleAssetEntry,
514
+ ): ConsolePageManifest {
515
+ const out: ConsolePageManifest = {
516
+ id: c.id,
517
+ kind: c.kind,
518
+ label: c.label,
519
+ availability: c.availability ?? 'active',
520
+ };
521
+ const lamps = sanitizeLamps(c.lamps);
522
+ if (lamps.length) out.lamps = lamps;
523
+ if (c.badges?.length) out.badges = c.badges.map((b) => ({ ...b }));
524
+ if (c.panels?.length) {
525
+ const panels = c.panels
526
+ .filter((p) => p.builtin === undefined || isBuiltinPanel(p.builtin))
527
+ .map((p) => {
528
+ const panel: ConsolePanelManifest = { id: p.id, title: p.title };
529
+ if (p.description) panel.description = p.description;
530
+ if (p.builtin !== undefined) panel.builtin = p.builtin;
531
+ if (p.slot !== undefined && isPanelId(p.slot)) panel.slot = p.slot;
532
+ return panel;
533
+ });
534
+ if (panels.length) out.panels = panels;
535
+ }
536
+ // 只上 id:归属够用了,schema 与当前值仍只走 /api/config。
537
+ if (c.config?.length) out.configGroups = c.config.map((g) => g.id);
538
+ if (c.storage?.length) out.storageKeys = c.storage.map((p) => p.key);
539
+ if (c.promptDocs?.length) {
540
+ out.prompts = c.promptDocs.map((doc) => ({
541
+ key: doc.key,
542
+ title: doc.title,
543
+ description: doc.description,
544
+ }));
545
+ }
546
+ const links = (c.links ?? [])
547
+ .filter((l) => isSafeLinkHref(l?.href))
548
+ .map((l) => ({
549
+ label: l.label,
550
+ href: l.href,
551
+ ...(l.inheritTheme === true ? { inheritTheme: true } : {}),
552
+ }));
553
+ if (links.length) out.links = links;
554
+ if (c.declared !== undefined) out.declared = c.declared;
555
+ if (c.reason) out.reason = c.reason;
556
+ if (c.agentVisible !== undefined) out.agentVisible = c.agentVisible;
557
+ if (c.prefixDrifted !== undefined) out.prefixDrifted = c.prefixDrifted;
558
+ if (client) out.client = client;
559
+ return out;
560
+ }
@@ -0,0 +1 @@
1
+ declare module '*.css';
@@ -0,0 +1,23 @@
1
+ /** 浏览器控制台发起的一次主机原生路径选择。 */
2
+ export interface PathPickerOptions {
3
+ kind: 'file' | 'directory';
4
+ /** 原生对话框标题。 */
5
+ title?: string;
6
+ /** 当前配置值;优先用作对话框起始位置。 */
7
+ currentPath?: string;
8
+ /** 当前值为空时使用的建议部署目录。 */
9
+ recommendedDir?: string;
10
+ /** 可选文件后缀,如 `.gguf` 或 `.model3.json`。 */
11
+ extensions?: string[];
12
+ }
13
+
14
+ export interface PathPicker {
15
+ /** 返回主机绝对路径;用户取消时返回 null。 */
16
+ pick(options: PathPickerOptions): Promise<string | null>;
17
+ }
18
+
19
+ export interface PathPickerResponse {
20
+ path: string | null;
21
+ }
22
+
23
+ export const PATH_PICKER_ROUTE = '/api/path-picker';