@allbluecn/shared 0.2.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 (95) hide show
  1. package/package.json +117 -0
  2. package/src/constants/perf.ts +21 -0
  3. package/src/i18n/client.ts +32 -0
  4. package/src/i18n/config.ts +104 -0
  5. package/src/i18n/detect.ts +43 -0
  6. package/src/i18n/locales/en/agents.json +134 -0
  7. package/src/i18n/locales/en/apps.json +6 -0
  8. package/src/i18n/locales/en/auth.json +88 -0
  9. package/src/i18n/locales/en/billing.json +78 -0
  10. package/src/i18n/locales/en/chat.json +194 -0
  11. package/src/i18n/locales/en/common.json +203 -0
  12. package/src/i18n/locales/en/dashboard.json +38 -0
  13. package/src/i18n/locales/en/design.json +70 -0
  14. package/src/i18n/locales/en/desktop.json +35 -0
  15. package/src/i18n/locales/en/display.json +37 -0
  16. package/src/i18n/locales/en/editor.json +304 -0
  17. package/src/i18n/locales/en/enterprise.json +1 -0
  18. package/src/i18n/locales/en/invite.json +11 -0
  19. package/src/i18n/locales/en/knowledge.json +451 -0
  20. package/src/i18n/locales/en/mindmap.json +28 -0
  21. package/src/i18n/locales/en/prd.json +43 -0
  22. package/src/i18n/locales/en/projects.json +133 -0
  23. package/src/i18n/locales/en/settings.json +375 -0
  24. package/src/i18n/locales/en/share.json +20 -0
  25. package/src/i18n/locales/en/story.json +785 -0
  26. package/src/i18n/locales/en/tags.json +42 -0
  27. package/src/i18n/locales/en/workspace.json +90 -0
  28. package/src/i18n/locales/zh/agents.json +134 -0
  29. package/src/i18n/locales/zh/apps.json +6 -0
  30. package/src/i18n/locales/zh/auth.json +88 -0
  31. package/src/i18n/locales/zh/billing.json +78 -0
  32. package/src/i18n/locales/zh/chat.json +194 -0
  33. package/src/i18n/locales/zh/common.json +203 -0
  34. package/src/i18n/locales/zh/dashboard.json +38 -0
  35. package/src/i18n/locales/zh/design.json +70 -0
  36. package/src/i18n/locales/zh/desktop.json +35 -0
  37. package/src/i18n/locales/zh/display.json +37 -0
  38. package/src/i18n/locales/zh/editor.json +304 -0
  39. package/src/i18n/locales/zh/enterprise.json +1 -0
  40. package/src/i18n/locales/zh/invite.json +11 -0
  41. package/src/i18n/locales/zh/knowledge.json +451 -0
  42. package/src/i18n/locales/zh/mindmap.json +28 -0
  43. package/src/i18n/locales/zh/prd.json +43 -0
  44. package/src/i18n/locales/zh/projects.json +133 -0
  45. package/src/i18n/locales/zh/settings.json +375 -0
  46. package/src/i18n/locales/zh/share.json +20 -0
  47. package/src/i18n/locales/zh/story.json +785 -0
  48. package/src/i18n/locales/zh/tags.json +42 -0
  49. package/src/i18n/locales/zh/workspace.json +90 -0
  50. package/src/i18n/server.ts +18 -0
  51. package/src/i18n/types.ts +5 -0
  52. package/src/index.ts +90 -0
  53. package/src/infrastructure/ai/adapter.ts +59 -0
  54. package/src/infrastructure/ai/cli-detector.ts +64 -0
  55. package/src/infrastructure/ip-location.ts +76 -0
  56. package/src/infrastructure/references/engine.ts +104 -0
  57. package/src/infrastructure/ua-parser.ts +107 -0
  58. package/src/interfaces/ai.ts +38 -0
  59. package/src/interfaces/avatar.ts +22 -0
  60. package/src/interfaces/module.ts +60 -0
  61. package/src/interfaces/references.ts +44 -0
  62. package/src/interfaces/transport.ts +26 -0
  63. package/src/lib/annotation-template.ts +33 -0
  64. package/src/lib/comment-utils.ts +47 -0
  65. package/src/lib/datetime.ts +115 -0
  66. package/src/lib/desktop-detect.ts +27 -0
  67. package/src/lib/outline-utils.ts +57 -0
  68. package/src/lib/pacer.ts +96 -0
  69. package/src/lib/prd/stack-layout.ts +53 -0
  70. package/src/lib/prd-tree-utils.ts +94 -0
  71. package/src/lib/prototype-registry.ts +24 -0
  72. package/src/lib/query-client-seam.ts +14 -0
  73. package/src/lib/share-events.ts +78 -0
  74. package/src/lib/sidebar-utils.ts +21 -0
  75. package/src/lib/stores/prd-canvas-store.ts +69 -0
  76. package/src/lib/tag-colors.ts +35 -0
  77. package/src/lib/time-format.ts +50 -0
  78. package/src/modules/ai-providers/constants.ts +79 -0
  79. package/src/modules/ai-providers/index.ts +21 -0
  80. package/src/modules/ai-providers/seed-data.ts +222 -0
  81. package/src/modules/ai-providers/types.ts +95 -0
  82. package/src/modules/billing/feature-registry.ts +63 -0
  83. package/src/modules/billing/plan-features-schema.ts +11 -0
  84. package/src/modules/billing/resource-registry.ts +80 -0
  85. package/src/modules/definitions/plugin.module.ts +38 -0
  86. package/src/modules/definitions/prd.module.ts +45 -0
  87. package/src/modules/definitions/prototype.module.ts +38 -0
  88. package/src/modules/dependencies/index.ts +186 -0
  89. package/src/modules/register-defaults.ts +27 -0
  90. package/src/modules/registry.ts +53 -0
  91. package/src/server-seam.ts +51 -0
  92. package/src/types/outline.ts +26 -0
  93. package/src/types/prd.ts +90 -0
  94. package/src/types/prototype.ts +12 -0
  95. package/src/virtual.d.ts +4 -0
@@ -0,0 +1,94 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ export interface PRDPage {
19
+ id: string;
20
+ name: string;
21
+ type: "folder" | "page";
22
+ parentId: string | null;
23
+ order: number;
24
+ version: number;
25
+ }
26
+
27
+ export interface TreeNode extends PRDPage {
28
+ children: TreeNode[];
29
+ }
30
+
31
+ export function buildTree(pages: PRDPage[]): TreeNode[] {
32
+ const map = new Map<string, TreeNode>();
33
+ const roots: TreeNode[] = [];
34
+
35
+ for (const p of pages) {
36
+ map.set(p.id, { ...p, children: [] });
37
+ }
38
+ for (const p of pages) {
39
+ const node = map.get(p.id)!;
40
+ if (p.parentId && map.has(p.parentId)) {
41
+ map.get(p.parentId)!.children.push(node);
42
+ } else {
43
+ roots.push(node);
44
+ }
45
+ }
46
+
47
+ const sortNodes = (nodes: TreeNode[]) => nodes.sort((a, b) => a.order - b.order);
48
+ sortNodes(roots);
49
+ for (const node of map.values()) sortNodes(node.children);
50
+ return roots;
51
+ }
52
+
53
+ export function flattenTree(nodes: TreeNode[]): PRDPage[] {
54
+ const result: PRDPage[] = [];
55
+ for (const n of nodes) {
56
+ result.push({ id: n.id, name: n.name, type: n.type, parentId: n.parentId, order: n.order, version: n.version });
57
+ result.push(...flattenTree(n.children));
58
+ }
59
+ return result;
60
+ }
61
+
62
+ export function findNode(nodes: TreeNode[], id: string): TreeNode | null {
63
+ for (const n of nodes) {
64
+ if (n.id === id) return n;
65
+ const found = findNode(n.children, id);
66
+ if (found) return found;
67
+ }
68
+ return null;
69
+ }
70
+
71
+ export function canMove(node: TreeNode, targetParentId: string | null, allPages: PRDPage[]): boolean {
72
+ if (node.type === "folder" && targetParentId !== null) return false;
73
+ if (targetParentId === node.id) return false;
74
+ const targetPage = allPages.find(p => p.id === targetParentId);
75
+ if (targetPage?.type === "folder") return false;
76
+ return true;
77
+ }
78
+
79
+ export function sortSnapshotsByTree<T extends { pageId: string }>(
80
+ snapshots: T[],
81
+ prdPages: PRDPage[],
82
+ ): T[] {
83
+ if (snapshots.length <= 1) return snapshots;
84
+ const ordered = flattenTree(buildTree(prdPages));
85
+ const indexMap = new Map(ordered.map((p, i) => [p.id, i]));
86
+ return [...snapshots].sort((a, b) => {
87
+ const ia = indexMap.get(a.pageId);
88
+ const ib = indexMap.get(b.pageId);
89
+ if (ia === undefined && ib === undefined) return 0;
90
+ if (ia === undefined) return 1;
91
+ if (ib === undefined) return -1;
92
+ return ia - ib;
93
+ });
94
+ }
@@ -0,0 +1,24 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ export {
19
+ registerComponent,
20
+ registerComponents,
21
+ unregisterComponent,
22
+ getAllComponents,
23
+ getComponent,
24
+ } from "@allblue/prototype";
@@ -0,0 +1,14 @@
1
+ import type { QueryClient } from '@tanstack/react-query'
2
+
3
+ let instance: QueryClient | null = null
4
+
5
+ export function setQueryClient(client: QueryClient) {
6
+ instance = client
7
+ }
8
+
9
+ export function getQueryClient(): QueryClient {
10
+ if (!instance) {
11
+ throw new Error('QueryClient 未注入:宿主需在 router 初始化时调用 setQueryClient()')
12
+ }
13
+ return instance
14
+ }
@@ -0,0 +1,78 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ const clients = new Map<string, Set<ReadableStreamDefaultController>>();
19
+
20
+ const MAX_CLIENTS_PER_PRD = 20;
21
+
22
+ const CLEANUP_INTERVAL = 60_000;
23
+ const IDLE_TIMEOUT = 5 * 60_000;
24
+
25
+ setInterval(() => {
26
+ const now = Date.now();
27
+ for (const [prdId, set] of clients) {
28
+ for (const controller of set) {
29
+ try {
30
+ controller.enqueue(new TextEncoder().encode(":cleanup-ping\n\n"));
31
+ } catch {
32
+ set.delete(controller);
33
+ }
34
+ }
35
+ if (set.size === 0) clients.delete(prdId);
36
+ }
37
+ }, CLEANUP_INTERVAL);
38
+
39
+ const controllerMeta = new WeakMap<ReadableStreamDefaultController, number>();
40
+
41
+ export function addClient(prdId: string, controller: ReadableStreamDefaultController) {
42
+ const set = clients.get(prdId);
43
+ if (set && set.size >= MAX_CLIENTS_PER_PRD) {
44
+ throw new Error("连接数已达上限");
45
+ }
46
+ if (!set) clients.set(prdId, new Set());
47
+ clients.get(prdId)!.add(controller);
48
+ controllerMeta.set(controller, Date.now());
49
+ }
50
+
51
+ export function removeClient(prdId: string, controller: ReadableStreamDefaultController) {
52
+ const set = clients.get(prdId);
53
+ if (!set) return;
54
+ set.delete(controller);
55
+ controllerMeta.delete(controller);
56
+ if (set.size === 0) clients.delete(prdId);
57
+ }
58
+
59
+ export function notifyClients(prdId: string, event: string, data: unknown) {
60
+ const set = clients.get(prdId);
61
+ if (!set) return;
62
+ const message = new TextEncoder().encode(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
63
+ for (const controller of set) {
64
+ try {
65
+ controller.enqueue(message);
66
+ controllerMeta.set(controller, Date.now());
67
+ } catch {
68
+ set.delete(controller);
69
+ controllerMeta.delete(controller);
70
+ }
71
+ }
72
+ }
73
+
74
+ export function getClientCount(): number {
75
+ let total = 0;
76
+ for (const set of clients.values()) total += set.size;
77
+ return total;
78
+ }
@@ -0,0 +1,21 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ export function isParentActive(pathname: string, parentLink: string): boolean {
19
+ if (!parentLink || parentLink === "#") return false;
20
+ return pathname === parentLink;
21
+ }
@@ -0,0 +1,69 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ import type { SetStateAction } from 'react'
19
+ import { createStore } from '@tanstack/store'
20
+ import type { CanvasElement } from '../../types/prototype'
21
+
22
+ interface PrdCanvasState {
23
+ elements: CanvasElement[]
24
+ selectedElementId: string | null
25
+ viewMode: 'edit' | 'preview' | 'prototype'
26
+ }
27
+
28
+ export type { CanvasElement, PrdCanvasState }
29
+
30
+ export const prdCanvasStore = createStore<PrdCanvasState>({
31
+ elements: [],
32
+ selectedElementId: null,
33
+ viewMode: 'edit',
34
+ })
35
+
36
+ export function setCanvasElements(value: SetStateAction<CanvasElement[]>) {
37
+ prdCanvasStore.setState((s) => ({
38
+ ...s,
39
+ elements: typeof value === 'function' ? value(s.elements) : value,
40
+ }))
41
+ }
42
+
43
+ export function setCanvasSelectedElementId(id: string | null) {
44
+ prdCanvasStore.setState((s) => ({
45
+ ...s,
46
+ selectedElementId: id,
47
+ }))
48
+ }
49
+
50
+ export function setCanvasViewMode(mode: PrdCanvasState['viewMode']) {
51
+ prdCanvasStore.setState((s) => ({
52
+ ...s,
53
+ viewMode: mode,
54
+ }))
55
+ }
56
+
57
+ export function updateCanvasElement(id: string, patch: Partial<CanvasElement>) {
58
+ prdCanvasStore.setState((s) => ({
59
+ ...s,
60
+ elements: s.elements.map((e) => (e.id === id ? { ...e, ...patch } : e)),
61
+ }))
62
+ }
63
+
64
+ export function deleteCanvasElement(id: string) {
65
+ prdCanvasStore.setState((s) => ({
66
+ ...s,
67
+ elements: s.elements.filter((e) => e.id !== id),
68
+ }))
69
+ }
@@ -0,0 +1,35 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ const TAG_COLORS = [
19
+ { bg: "bg-blue-100 dark:bg-blue-900/30", text: "text-blue-700 dark:text-blue-300", border: "border-blue-200 dark:border-blue-700", selected: "border-blue-500", check: "text-blue-700 dark:text-blue-300", label: "蓝色" },
20
+ { bg: "bg-emerald-100 dark:bg-emerald-900/30", text: "text-emerald-700 dark:text-emerald-300", border: "border-emerald-200 dark:border-emerald-700", selected: "border-emerald-500", check: "text-emerald-700 dark:text-emerald-300", label: "绿色" },
21
+ { bg: "bg-violet-100 dark:bg-violet-900/30", text: "text-violet-700 dark:text-violet-300", border: "border-violet-200 dark:border-violet-700", selected: "border-violet-500", check: "text-violet-700 dark:text-violet-300", label: "紫色" },
22
+ { bg: "bg-amber-100 dark:bg-amber-900/30", text: "text-amber-700 dark:text-amber-300", border: "border-amber-200 dark:border-amber-700", selected: "border-amber-500", check: "text-amber-700 dark:text-amber-300", label: "琥珀" },
23
+ { bg: "bg-rose-100 dark:bg-rose-900/30", text: "text-rose-700 dark:text-rose-300", border: "border-rose-200 dark:border-rose-700", selected: "border-rose-500", check: "text-rose-700 dark:text-rose-300", label: "玫红" },
24
+ { bg: "bg-cyan-100 dark:bg-cyan-900/30", text: "text-cyan-700 dark:text-cyan-300", border: "border-cyan-200 dark:border-cyan-700", selected: "border-cyan-500", check: "text-cyan-700 dark:text-cyan-300", label: "青色" },
25
+ { bg: "bg-orange-100 dark:bg-orange-900/30", text: "text-orange-700 dark:text-orange-300", border: "border-orange-200 dark:border-orange-700", selected: "border-orange-500", check: "text-orange-700 dark:text-orange-300", label: "橙色" },
26
+ { bg: "bg-pink-100 dark:bg-pink-900/30", text: "text-pink-700 dark:text-pink-300", border: "border-pink-200 dark:border-pink-700", selected: "border-pink-500", check: "text-pink-700 dark:text-pink-300", label: "粉色" },
27
+ ];
28
+
29
+ function hashColorIndex(name: string) {
30
+ let hash = 0;
31
+ for (let i = 0; i < name.length; i++) hash = ((hash << 5) - hash) + name.charCodeAt(i);
32
+ return Math.abs(hash) % TAG_COLORS.length;
33
+ }
34
+
35
+ export { TAG_COLORS, hashColorIndex };
@@ -0,0 +1,50 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ import { formatDate } from "./datetime";
19
+
20
+ function isSameDay(a: Date, b: Date, timezone: string): boolean {
21
+ const aDate = formatDate(a, timezone, "yyyy-MM-dd");
22
+ const bDate = formatDate(b, timezone, "yyyy-MM-dd");
23
+ return aDate === bDate;
24
+ }
25
+
26
+ export function formatSaveTime(savedAt: Date, type: "auto" | "manual", timezone: string): string {
27
+ const now = new Date();
28
+ const time = formatDate(savedAt, timezone, "HH:mm");
29
+ const label = type === "auto" ? "自动保存" : "手动保存";
30
+
31
+ if (isSameDay(savedAt, now, timezone)) {
32
+ return `${time} ${label}`;
33
+ }
34
+
35
+ const yesterday = new Date(now);
36
+ yesterday.setDate(yesterday.getDate() - 1);
37
+ if (isSameDay(savedAt, yesterday, timezone)) {
38
+ return `昨日 ${time} ${label}`;
39
+ }
40
+
41
+ const oneYearAgo = new Date(now);
42
+ oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);
43
+ if (savedAt > oneYearAgo) {
44
+ const month = formatDate(savedAt, timezone, "MM");
45
+ const day = formatDate(savedAt, timezone, "dd");
46
+ return `${month}-${day} ${time} ${label}`;
47
+ }
48
+
49
+ return `1年前 ${label}`;
50
+ }
@@ -0,0 +1,79 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ // packages/shared/src/modules/ai-providers/constants.ts
19
+ import type { AdapterKind, ProviderCategory } from './types'
20
+
21
+ export const ADAPTER_KINDS: Array<{ value: AdapterKind; label: string; description: string }> = [
22
+ { value: 'openai', label: 'OpenAI 官方', description: 'GPT 系列,OpenAI 协议' },
23
+ { value: 'anthropic', label: 'Anthropic', description: 'Claude 系列,Anthropic 协议' },
24
+ { value: 'gemini', label: 'Google Gemini', description: 'Gemini 系列,Google 协议' },
25
+ { value: 'groq', label: 'Groq', description: 'Groq 极速推理引擎' },
26
+ { value: 'grok', label: 'xAI Grok', description: 'Grok 系列,xAI 协议' },
27
+ { value: 'openrouter', label: 'OpenRouter 聚合', description: '一个 Key 访问 200+ 模型' },
28
+ { value: 'ollama', label: 'Ollama 本地', description: '本地部署开源模型,无需 API Key' },
29
+ { value: 'openai-compatible', label: 'OpenAI 兼容', description: 'DeepSeek/Moonshot/Mistral 等兼容协议' },
30
+ ]
31
+
32
+ export const PROVIDER_CATEGORIES: Array<{ value: ProviderCategory; label: string }> = [
33
+ { value: 'recommended', label: '推荐' },
34
+ { value: 'popular', label: '热门' },
35
+ { value: 'local', label: '本地' },
36
+ ]
37
+
38
+ export const ADAPTER_KIND_VALUES: AdapterKind[] = ADAPTER_KINDS.map((k) => k.value)
39
+ export const PROVIDER_CATEGORY_VALUES: ProviderCategory[] = PROVIDER_CATEGORIES.map((c) => c.value)
40
+
41
+ export const MODEL_CAPABILITY_OPTIONS: Array<{ value: import('./types').ModelCapability; label: string }> = [
42
+ { value: 'text', label: '文本' },
43
+ { value: 'vision', label: '视觉' },
44
+ { value: 'tools', label: '工具' },
45
+ { value: 'reasoning', label: '推理' },
46
+ { value: 'audio', label: '音频' },
47
+ ]
48
+
49
+ /**
50
+ * 模型管理 tabs 筛选项(参考 lobehub)。
51
+ * value 对应 ModelCapability,'all' 为全部,'video' 暂预留(无对应 capability)。
52
+ */
53
+ export type ModelTab = 'all' | 'text' | 'reasoning' | 'tools' | 'vision' | 'video'
54
+
55
+ export const MODEL_TABS: Array<{ value: ModelTab; label: string }> = [
56
+ { value: 'all', label: '全部' },
57
+ { value: 'text', label: '文本' },
58
+ { value: 'reasoning', label: '推理' },
59
+ { value: 'tools', label: '对话' },
60
+ { value: 'vision', label: '图片' },
61
+ { value: 'video', label: '视频' },
62
+ ]
63
+
64
+ /**
65
+ * our providerId → @lobehub/icons PascalCase 导出名
66
+ * 未知 providerId 返回 null,调用方 fallback 到首字母
67
+ */
68
+ export const LOBE_ICON_MAP: Record<string, string> = {
69
+ openai: 'OpenAI',
70
+ anthropic: 'Anthropic',
71
+ google: 'Gemini',
72
+ deepseek: 'DeepSeek',
73
+ groq: 'Groq',
74
+ xai: 'XAI',
75
+ openrouter: 'OpenRouter',
76
+ mistral: 'Mistral',
77
+ ollama: 'Ollama',
78
+ moonshot: 'Moonshot',
79
+ }
@@ -0,0 +1,21 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ // packages/shared/src/modules/ai-providers/index.ts
19
+ export * from './types'
20
+ export * from './constants'
21
+ export * from './seed-data'