luckytri 1.0.0 → 1.0.2

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 (139) hide show
  1. package/.github/SECURITY.md +4 -4
  2. package/README.en.md +252 -250
  3. package/README.md +252 -250
  4. package/bin/luckytri.js +5 -1
  5. package/docs/en/CHANGELOG.md +8 -0
  6. package/docs/en/connect.md +18 -18
  7. package/docs/en/guide.md +202 -216
  8. package/docs/en/npm-release.md +25 -25
  9. package/docs/zh/CHANGELOG.md +8 -0
  10. package/docs/zh/connect.md +17 -17
  11. package/docs/zh/guide.md +202 -216
  12. package/docs/zh/npm-release.md +33 -33
  13. package/package.json +110 -108
  14. package/plugins/sdk/index.d.ts +155 -155
  15. package/plugins/sdk/testing.js +58 -58
  16. package/plugins/weather/index.js +82 -82
  17. package/plugins/weather/luckytri-plugin.json +29 -29
  18. package/public/app/assets/ChatsPage-BhlJHseG.js +3 -0
  19. package/public/app/assets/Empty-DP6WMGHi.js +2 -0
  20. package/public/app/assets/Field-CtbdqaiB.js +1 -0
  21. package/public/app/assets/HeartPage-32BeTPn2.js +1 -0
  22. package/public/app/assets/LifePage-CxSm0XKI.js +1 -0
  23. package/public/app/assets/MemoryPage-BeKBcPCY.js +1 -0
  24. package/public/app/assets/NaturePage-NEPYl2HS.js +3 -0
  25. package/public/app/assets/PeoplePage-DxtpekwM.js +1 -0
  26. package/public/app/assets/PluginsPage-CVVQwEBI.css +1 -0
  27. package/public/app/assets/PluginsPage-DksEZbUU.js +2 -0
  28. package/public/app/assets/{SystemPage-CAMPoYqM.css → SystemPage-BkRu0Rvx.css} +1 -1
  29. package/public/app/assets/SystemPage-BvzJlHuY.js +1 -0
  30. package/public/app/assets/TimePage-7-awH5XL.js +3 -0
  31. package/public/app/assets/index-4rItIkD-.js +4 -0
  32. package/public/app/assets/{index-YDz1ree1.css → index-DY4e15Kh.css} +1 -1
  33. package/public/app/assets/{knowledge-DG0e0uKw.js → knowledge-C6_HvoyB.js} +1 -1
  34. package/public/app/assets/media-SMfTT-yc.js +1 -0
  35. package/public/app/index.html +3 -3
  36. package/public/guide.en.html +72 -99
  37. package/public/guide.html +44 -86
  38. package/public/tutorial.en.md +25 -39
  39. package/public/tutorial.md +25 -39
  40. package/scripts/backup.js +311 -311
  41. package/scripts/browser.js +41 -41
  42. package/scripts/import-data.js +128 -0
  43. package/scripts/launch.js +101 -94
  44. package/scripts/plugin.js +150 -150
  45. package/scripts/reset-password.js +22 -0
  46. package/scripts/runtime.js +25 -25
  47. package/scripts/service.js +56 -47
  48. package/scripts/setup.js +50 -50
  49. package/scripts/start-server.js +41 -41
  50. package/scripts/stop.js +36 -36
  51. package/server/app.js +112 -96
  52. package/server/auth.js +217 -0
  53. package/server/channels/contract.js +57 -57
  54. package/server/channels/hub.js +165 -165
  55. package/server/channels/index.js +28 -25
  56. package/server/channels/onebot/index.js +335 -336
  57. package/server/channels/onebot/token.js +22 -3
  58. package/server/core/capabilities.js +208 -208
  59. package/server/core/events.js +64 -60
  60. package/server/core/image-preprocessor.js +208 -208
  61. package/server/core/model-manager.js +1213 -1213
  62. package/server/core/net-guard.js +49 -49
  63. package/server/core/orchestrator.js +569 -569
  64. package/server/core/perceivers.js +91 -91
  65. package/server/core/persona-manager.js +243 -243
  66. package/server/core/repository.js +293 -293
  67. package/server/core/response-validator.js +508 -508
  68. package/server/core/turn-processor.js +630 -630
  69. package/server/core/turn.js +236 -236
  70. package/server/core/vision-manager.js +633 -633
  71. package/server/i18n/errors.js +548 -497
  72. package/server/i18n/labels.js +649 -653
  73. package/server/index.js +151 -102
  74. package/server/knowledge/manager.js +386 -386
  75. package/server/knowledge/schema.js +12 -8
  76. package/server/local-access.js +32 -0
  77. package/server/mind/anticipations.js +507 -507
  78. package/server/mind/api.js +703 -703
  79. package/server/mind/budget.js +152 -152
  80. package/server/mind/context-selection.js +61 -61
  81. package/server/mind/day-planner.js +324 -324
  82. package/server/mind/evidence.js +148 -148
  83. package/server/mind/index.js +445 -445
  84. package/server/mind/life/diary.js +786 -786
  85. package/server/mind/life/index.js +1049 -1049
  86. package/server/mind/observations.js +84 -84
  87. package/server/mind/own-day.js +324 -324
  88. package/server/mind/own-voice.js +318 -318
  89. package/server/mind/senses.js +53 -53
  90. package/server/mind/time/activity-clock.js +196 -196
  91. package/server/mind/time/availability.js +69 -69
  92. package/server/mind/time/commitment-review.js +198 -198
  93. package/server/mind/time/executor.js +512 -512
  94. package/server/mind/time/experiences.js +128 -128
  95. package/server/mind/time/games.js +562 -562
  96. package/server/mind/time/index.js +739 -739
  97. package/server/mind/time/intent.js +166 -166
  98. package/server/mind/time/kinds.js +171 -171
  99. package/server/mind/time/plugin-activity.js +207 -207
  100. package/server/mind/time/tasks.js +587 -587
  101. package/server/mind/util.js +110 -110
  102. package/server/mind/view.js +273 -273
  103. package/server/paths.js +102 -102
  104. package/server/plugins/api.js +204 -204
  105. package/server/plugins/host.js +967 -967
  106. package/server/plugins/install.js +295 -295
  107. package/server/plugins/manifest.js +201 -201
  108. package/server/plugins/permissions.js +42 -42
  109. package/server/plugins/runner/guard.mjs +36 -36
  110. package/server/plugins/runner/worker.mjs +250 -250
  111. package/server/plugins/schema.js +91 -91
  112. package/server/plugins/zip.js +112 -112
  113. package/server/startup-lock.js +118 -118
  114. package/server/storage/archive.js +242 -241
  115. package/server/storage/backup-cleanup-worker.js +8 -8
  116. package/server/storage/backup-cleanup.js +415 -414
  117. package/server/storage/backup-lock.js +76 -76
  118. package/server/storage/backup-scheduler.js +131 -131
  119. package/server/storage/data-package.js +298 -0
  120. package/server/storage/data-transfer-api.js +50 -0
  121. package/server/storage/data-transfer-worker.js +18 -0
  122. package/server/storage/data-transfer.js +415 -0
  123. package/server/storage/store.js +202 -199
  124. package/server/studio/readiness.js +181 -190
  125. package/server/studio/settings.js +236 -236
  126. package/public/app/assets/ChatsPage-C-FcRapR.js +0 -3
  127. package/public/app/assets/Empty-CpP5kQHH.js +0 -2
  128. package/public/app/assets/Field-D4gY-INU.js +0 -1
  129. package/public/app/assets/HeartPage-CPy_thQd.js +0 -1
  130. package/public/app/assets/LifePage-CxWvwmSf.js +0 -1
  131. package/public/app/assets/MemoryPage-DC4rhQ68.js +0 -1
  132. package/public/app/assets/NaturePage-IvYw04Zq.js +0 -3
  133. package/public/app/assets/PeoplePage-Cqefm9-q.js +0 -1
  134. package/public/app/assets/PluginsPage-DKSaKvXb.js +0 -2
  135. package/public/app/assets/PluginsPage-HyBe5D8w.css +0 -1
  136. package/public/app/assets/SystemPage-CJmtJkrK.js +0 -1
  137. package/public/app/assets/TimePage-Cw44inM4.js +0 -3
  138. package/public/app/assets/index-BheRW-1t.js +0 -4
  139. package/public/app/assets/media-BzPDBm7e.js +0 -1
@@ -1,201 +1,201 @@
1
- import { readFileSync } from "node:fs";
2
- import { join, normalize, sep } from "node:path";
3
- import { VERSION } from "../version.js";
4
- import { API_VERSION, permissionKnown } from "./permissions.js";
5
-
6
- export const RESERVED_IDS = new Set([
7
- "onebot",
8
- "qqbot",
9
- "preview",
10
- "core",
11
- "mind",
12
- "luckytri",
13
- ]);
14
- const ID = /^[a-z][a-z0-9-]{1,39}$/;
15
- const SETTING_KEY = /^[a-z][A-Za-z0-9-]{0,39}$/;
16
- const SEMVER =
17
- /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
18
- const HOST = /^[a-z0-9.-]+$/i;
19
-
20
- export function parseVersion(value) {
21
- const match = SEMVER.exec(String(value || ""));
22
- if (!match) return null;
23
- return match.slice(1, 4).map(Number);
24
- }
25
-
26
- export function satisfies(range, version) {
27
- const have = parseVersion(version);
28
- if (!have || typeof range !== "string") return false;
29
- const parts = range.trim().split(/\s+/);
30
- return parts.every((part) => {
31
- const match = /^(>=|>|<=|<)?(\d+\.\d+\.\d+)$/.exec(part);
32
- if (!match) return false;
33
- const op = match[1] || "=";
34
- const want = parseVersion(match[2]);
35
- const cmp = have[0] - want[0] || have[1] - want[1] || have[2] - want[2];
36
- if (op === ">=") return cmp >= 0;
37
- if (op === ">") return cmp > 0;
38
- if (op === "<=") return cmp <= 0;
39
- if (op === "<") return cmp < 0;
40
- return cmp === 0;
41
- });
42
- }
43
-
44
- export function apiCompatible(wanted, host = API_VERSION) {
45
- const plugin = parseVersion(`${wanted}.0`);
46
- const current = parseVersion(`${host}.0`);
47
- if (!plugin || !current) return false;
48
- return plugin[0] === current[0] && plugin[1] <= current[1];
49
- }
50
-
51
- function setting(field) {
52
- const types = [
53
- "text",
54
- "secret",
55
- "number",
56
- "boolean",
57
- "select",
58
- "textarea",
59
- "urls",
60
- ];
61
- if (
62
- !field ||
63
- !SETTING_KEY.test(field.key || "") ||
64
- !types.includes(field.type)
65
- )
66
- throw Error("插件设置项无效");
67
- if (typeof field.label !== "string" || !field.label.trim())
68
- throw Error("插件设置项无效");
69
- if (field.type === "select" && !Array.isArray(field.options))
70
- throw Error("插件设置项无效");
71
- return {
72
- key: field.key,
73
- type: field.type,
74
- label: String(field.label).slice(0, 80),
75
- required: !!field.required,
76
- default: field.default ?? (field.type === "boolean" ? false : ""),
77
- ...(field.allowNetwork ? { allowNetwork: true } : {}),
78
- ...(Array.isArray(field.options)
79
- ? {
80
- options: field.options.slice(0, 20).map((item) => ({
81
- value: String(item.value ?? item).slice(0, 80),
82
- label: String(item.label ?? item.value ?? item).slice(0, 80),
83
- })),
84
- }
85
- : {}),
86
- };
87
- }
88
-
89
- function named(list, pattern, map) {
90
- if (!Array.isArray(list)) return [];
91
- return list.map((item) => {
92
- const value = map(item);
93
- if (!pattern.test(value.name || value.kind || value.type || ""))
94
- throw Error("插件贡献的名字无效");
95
- return value;
96
- });
97
- }
98
-
99
- // A manifest is data. Anything that does not fit is refused before the
100
- // plugin process is ever started.
101
- export function readManifest(dir) {
102
- let raw;
103
- try {
104
- raw = JSON.parse(readFileSync(join(dir, "luckytri-plugin.json"), "utf8"));
105
- } catch {
106
- throw Error("插件清单无法读取");
107
- }
108
- return validateManifest(raw);
109
- }
110
-
111
- export function validateManifest(raw, version = VERSION) {
112
- if (!raw || typeof raw !== "object" || Array.isArray(raw))
113
- throw Error("插件清单无效");
114
- if (!ID.test(raw.id || "") || RESERVED_IDS.has(raw.id))
115
- throw Error("插件标识无效");
116
- if (!parseVersion(raw.version)) throw Error("插件版本号无效");
117
- if (!apiCompatible(raw.pluginApi)) throw Error("插件 API 版本不兼容");
118
- if (raw.luckytri && !satisfies(raw.luckytri, version))
119
- throw Error("插件不支持这个 LuckyTri 版本");
120
- const entry = normalize(String(raw.entry || "index.js"));
121
- if (
122
- !entry ||
123
- entry.startsWith("..") ||
124
- entry.startsWith("/") ||
125
- entry.includes(`..${sep}`) ||
126
- entry.includes("..\\") ||
127
- entry.includes("../")
128
- )
129
- throw Error("插件入口无效");
130
- const permissions = [...new Set(raw.permissions || [])];
131
- if (permissions.some((item) => !permissionKnown(item)))
132
- throw Error("插件权限无效");
133
- const network = [
134
- ...new Set((raw.network || []).map((host) => String(host).toLowerCase())),
135
- ];
136
- if (network.some((host) => !HOST.test(host) || host.length > 200))
137
- throw Error("插件网络主机无效");
138
- const name = String(raw.name || "")
139
- .trim()
140
- .slice(0, 40);
141
- if (!name) throw Error("插件清单无效");
142
- const contributes = raw.contributes || {};
143
- const short = /^[a-z][a-z0-9-]{0,40}$/;
144
- return {
145
- id: raw.id,
146
- name,
147
- version: raw.version,
148
- pluginApi: raw.pluginApi,
149
- luckytri: raw.luckytri || "",
150
- description: String(raw.description || "").slice(0, 400),
151
- author: String(raw.author || "").slice(0, 80),
152
- license: String(raw.license || "").slice(0, 40),
153
- entry,
154
- permissions,
155
- network,
156
- settings: (raw.settings || []).map(setting),
157
- contributes: {
158
- senses: (contributes.senses || []).map((key) => {
159
- if (!short.test(key)) throw Error("插件贡献的名字无效");
160
- return key;
161
- }),
162
- channels: named(contributes.channels, short, (item) => ({
163
- type: item.type === raw.id ? item.type : `${raw.id}-${item.type}`,
164
- label: String(item.label || item.type).slice(0, 40),
165
- capabilities: item.capabilities || {},
166
- mediaHosts: String(item.mediaHosts || "").slice(0, 200),
167
- })),
168
- activities: (contributes.activities || []).map((item) => {
169
- if (!short.test(item?.kind || "")) throw Error("插件贡献的名字无效");
170
- return {
171
- kind: `${raw.id}.${item.kind}`,
172
- label: String(item.label || item.kind).slice(0, 40),
173
- describe: String(item.describe || "").slice(0, 160),
174
- keywords: String(item.keywords || "").slice(0, 200),
175
- minutes: Number(item.minutes) || 15,
176
- energy: !!item.energy,
177
- };
178
- }),
179
- actions: (contributes.actions || []).map((item) => {
180
- if (!short.test(item?.name || "")) throw Error("插件贡献的名字无效");
181
- return {
182
- name: `${raw.id}.${item.name}`,
183
- label: String(item.label || item.name).slice(0, 40),
184
- describe: String(item.describe || "").slice(0, 160),
185
- input: Array.isArray(item.input) ? item.input.slice(0, 12) : [],
186
- risk: item.risk === "high" ? "high" : "low",
187
- confirm: item.confirm === "owner" ? "owner" : "none",
188
- where: item.where === "any" ? "any" : "private",
189
- dailyLimit: Number.isInteger(item.dailyLimit) ? item.dailyLimit : 20,
190
- };
191
- }),
192
- perceive: (contributes.perceive || []).map((type) => {
193
- const value = String(type).slice(0, 40);
194
- if (!value) throw Error("插件贡献的名字无效");
195
- return value;
196
- }),
197
- page: !!contributes.ui?.page,
198
- },
199
- i18n: raw.i18n && typeof raw.i18n === "object" ? raw.i18n : {},
200
- };
201
- }
1
+ import { readFileSync } from "node:fs";
2
+ import { join, normalize, sep } from "node:path";
3
+ import { VERSION } from "../version.js";
4
+ import { API_VERSION, permissionKnown } from "./permissions.js";
5
+
6
+ export const RESERVED_IDS = new Set([
7
+ "onebot",
8
+ "qqbot",
9
+ "preview",
10
+ "core",
11
+ "mind",
12
+ "luckytri",
13
+ ]);
14
+ const ID = /^[a-z][a-z0-9-]{1,39}$/;
15
+ const SETTING_KEY = /^[a-z][A-Za-z0-9-]{0,39}$/;
16
+ const SEMVER =
17
+ /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
18
+ const HOST = /^[a-z0-9.-]+$/i;
19
+
20
+ export function parseVersion(value) {
21
+ const match = SEMVER.exec(String(value || ""));
22
+ if (!match) return null;
23
+ return match.slice(1, 4).map(Number);
24
+ }
25
+
26
+ export function satisfies(range, version) {
27
+ const have = parseVersion(version);
28
+ if (!have || typeof range !== "string") return false;
29
+ const parts = range.trim().split(/\s+/);
30
+ return parts.every((part) => {
31
+ const match = /^(>=|>|<=|<)?(\d+\.\d+\.\d+)$/.exec(part);
32
+ if (!match) return false;
33
+ const op = match[1] || "=";
34
+ const want = parseVersion(match[2]);
35
+ const cmp = have[0] - want[0] || have[1] - want[1] || have[2] - want[2];
36
+ if (op === ">=") return cmp >= 0;
37
+ if (op === ">") return cmp > 0;
38
+ if (op === "<=") return cmp <= 0;
39
+ if (op === "<") return cmp < 0;
40
+ return cmp === 0;
41
+ });
42
+ }
43
+
44
+ export function apiCompatible(wanted, host = API_VERSION) {
45
+ const plugin = parseVersion(`${wanted}.0`);
46
+ const current = parseVersion(`${host}.0`);
47
+ if (!plugin || !current) return false;
48
+ return plugin[0] === current[0] && plugin[1] <= current[1];
49
+ }
50
+
51
+ function setting(field) {
52
+ const types = [
53
+ "text",
54
+ "secret",
55
+ "number",
56
+ "boolean",
57
+ "select",
58
+ "textarea",
59
+ "urls",
60
+ ];
61
+ if (
62
+ !field ||
63
+ !SETTING_KEY.test(field.key || "") ||
64
+ !types.includes(field.type)
65
+ )
66
+ throw Error("插件设置项无效");
67
+ if (typeof field.label !== "string" || !field.label.trim())
68
+ throw Error("插件设置项无效");
69
+ if (field.type === "select" && !Array.isArray(field.options))
70
+ throw Error("插件设置项无效");
71
+ return {
72
+ key: field.key,
73
+ type: field.type,
74
+ label: String(field.label).slice(0, 80),
75
+ required: !!field.required,
76
+ default: field.default ?? (field.type === "boolean" ? false : ""),
77
+ ...(field.allowNetwork ? { allowNetwork: true } : {}),
78
+ ...(Array.isArray(field.options)
79
+ ? {
80
+ options: field.options.slice(0, 20).map((item) => ({
81
+ value: String(item.value ?? item).slice(0, 80),
82
+ label: String(item.label ?? item.value ?? item).slice(0, 80),
83
+ })),
84
+ }
85
+ : {}),
86
+ };
87
+ }
88
+
89
+ function named(list, pattern, map) {
90
+ if (!Array.isArray(list)) return [];
91
+ return list.map((item) => {
92
+ const value = map(item);
93
+ if (!pattern.test(value.name || value.kind || value.type || ""))
94
+ throw Error("插件贡献的名字无效");
95
+ return value;
96
+ });
97
+ }
98
+
99
+ // A manifest is data. Anything that does not fit is refused before the
100
+ // plugin process is ever started.
101
+ export function readManifest(dir) {
102
+ let raw;
103
+ try {
104
+ raw = JSON.parse(readFileSync(join(dir, "luckytri-plugin.json"), "utf8"));
105
+ } catch {
106
+ throw Error("插件清单无法读取");
107
+ }
108
+ return validateManifest(raw);
109
+ }
110
+
111
+ export function validateManifest(raw, version = VERSION) {
112
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
113
+ throw Error("插件清单无效");
114
+ if (!ID.test(raw.id || "") || RESERVED_IDS.has(raw.id))
115
+ throw Error("插件标识无效");
116
+ if (!parseVersion(raw.version)) throw Error("插件版本号无效");
117
+ if (!apiCompatible(raw.pluginApi)) throw Error("插件 API 版本不兼容");
118
+ if (raw.luckytri && !satisfies(raw.luckytri, version))
119
+ throw Error("插件不支持这个 LuckyTri 版本");
120
+ const entry = normalize(String(raw.entry || "index.js"));
121
+ if (
122
+ !entry ||
123
+ entry.startsWith("..") ||
124
+ entry.startsWith("/") ||
125
+ entry.includes(`..${sep}`) ||
126
+ entry.includes("..\\") ||
127
+ entry.includes("../")
128
+ )
129
+ throw Error("插件入口无效");
130
+ const permissions = [...new Set(raw.permissions || [])];
131
+ if (permissions.some((item) => !permissionKnown(item)))
132
+ throw Error("插件权限无效");
133
+ const network = [
134
+ ...new Set((raw.network || []).map((host) => String(host).toLowerCase())),
135
+ ];
136
+ if (network.some((host) => !HOST.test(host) || host.length > 200))
137
+ throw Error("插件网络主机无效");
138
+ const name = String(raw.name || "")
139
+ .trim()
140
+ .slice(0, 40);
141
+ if (!name) throw Error("插件清单无效");
142
+ const contributes = raw.contributes || {};
143
+ const short = /^[a-z][a-z0-9-]{0,40}$/;
144
+ return {
145
+ id: raw.id,
146
+ name,
147
+ version: raw.version,
148
+ pluginApi: raw.pluginApi,
149
+ luckytri: raw.luckytri || "",
150
+ description: String(raw.description || "").slice(0, 400),
151
+ author: String(raw.author || "").slice(0, 80),
152
+ license: String(raw.license || "").slice(0, 40),
153
+ entry,
154
+ permissions,
155
+ network,
156
+ settings: (raw.settings || []).map(setting),
157
+ contributes: {
158
+ senses: (contributes.senses || []).map((key) => {
159
+ if (!short.test(key)) throw Error("插件贡献的名字无效");
160
+ return key;
161
+ }),
162
+ channels: named(contributes.channels, short, (item) => ({
163
+ type: item.type === raw.id ? item.type : `${raw.id}-${item.type}`,
164
+ label: String(item.label || item.type).slice(0, 40),
165
+ capabilities: item.capabilities || {},
166
+ mediaHosts: String(item.mediaHosts || "").slice(0, 200),
167
+ })),
168
+ activities: (contributes.activities || []).map((item) => {
169
+ if (!short.test(item?.kind || "")) throw Error("插件贡献的名字无效");
170
+ return {
171
+ kind: `${raw.id}.${item.kind}`,
172
+ label: String(item.label || item.kind).slice(0, 40),
173
+ describe: String(item.describe || "").slice(0, 160),
174
+ keywords: String(item.keywords || "").slice(0, 200),
175
+ minutes: Number(item.minutes) || 15,
176
+ energy: !!item.energy,
177
+ };
178
+ }),
179
+ actions: (contributes.actions || []).map((item) => {
180
+ if (!short.test(item?.name || "")) throw Error("插件贡献的名字无效");
181
+ return {
182
+ name: `${raw.id}.${item.name}`,
183
+ label: String(item.label || item.name).slice(0, 40),
184
+ describe: String(item.describe || "").slice(0, 160),
185
+ input: Array.isArray(item.input) ? item.input.slice(0, 12) : [],
186
+ risk: item.risk === "high" ? "high" : "low",
187
+ confirm: item.confirm === "owner" ? "owner" : "none",
188
+ where: item.where === "any" ? "any" : "private",
189
+ dailyLimit: Number.isInteger(item.dailyLimit) ? item.dailyLimit : 20,
190
+ };
191
+ }),
192
+ perceive: (contributes.perceive || []).map((type) => {
193
+ const value = String(type).slice(0, 40);
194
+ if (!value) throw Error("插件贡献的名字无效");
195
+ return value;
196
+ }),
197
+ page: !!contributes.ui?.page,
198
+ },
199
+ i18n: raw.i18n && typeof raw.i18n === "object" ? raw.i18n : {},
200
+ };
201
+ }
@@ -1,42 +1,42 @@
1
- // What a plugin may be given. The risk is shown when the owner agrees;
2
- // the host is what actually refuses a call the plugin was not given.
3
- export const PERMISSIONS = {
4
- "mind.read": {
5
- risk: "low",
6
- label: "知道她醒着没有、心情和在做什么",
7
- },
8
- notify: { risk: "low", label: "给工作室发一条通知" },
9
- ui: { risk: "low", label: "在工作室里放一个自己的页面" },
10
- "http.routes": { risk: "low", label: "给自己的页面提供接口" },
11
- senses: { risk: "medium", label: "把感知放进她的此刻" },
12
- observe: { risk: "medium", label: "把发生的事作为经历交给她" },
13
- "knowledge.offer": { risk: "medium", label: "往她的书架放资料" },
14
- activities: { risk: "medium", label: "给她一件可以自己做的事" },
15
- models: { risk: "medium", label: "使用她的模型服务" },
16
- "net.fetch": { risk: "medium", label: "访问声明过的网站" },
17
- actions: { risk: "high", label: "让她可以选择做一件事" },
18
- perceive: { risk: "high", label: "读取聊天里的附件" },
19
- channel: { risk: "high", label: "接入一个平台,并看到那里的消息" },
20
- "http.public": { risk: "high", label: "开放一个不需要令牌的地址" },
21
- "net.raw": { risk: "high", label: "自己直接联网" },
22
- };
23
-
24
- export const API_VERSION = "1.0";
25
- export const API_FEATURES = [
26
- "senses",
27
- "observe",
28
- "activities",
29
- "actions",
30
- "perceive",
31
- "channel",
32
- "knowledge",
33
- "models",
34
- "http",
35
- "notify",
36
- "mind.read",
37
- "ui",
38
- ];
39
-
40
- export function permissionKnown(name) {
41
- return Object.hasOwn(PERMISSIONS, name);
42
- }
1
+ // What a plugin may be given. The risk is shown when the owner agrees;
2
+ // the host is what actually refuses a call the plugin was not given.
3
+ export const PERMISSIONS = {
4
+ "mind.read": {
5
+ risk: "low",
6
+ label: "知道她醒着没有、心情和在做什么",
7
+ },
8
+ notify: { risk: "low", label: "给工作室发一条通知" },
9
+ ui: { risk: "low", label: "在工作室里放一个自己的页面" },
10
+ "http.routes": { risk: "low", label: "给自己的页面提供接口" },
11
+ senses: { risk: "medium", label: "把感知放进她的此刻" },
12
+ observe: { risk: "medium", label: "把发生的事作为经历交给她" },
13
+ "knowledge.offer": { risk: "medium", label: "往她的书架放资料" },
14
+ activities: { risk: "medium", label: "给她一件可以自己做的事" },
15
+ models: { risk: "medium", label: "使用她的模型服务" },
16
+ "net.fetch": { risk: "medium", label: "访问声明过的网站" },
17
+ actions: { risk: "high", label: "让她可以选择做一件事" },
18
+ perceive: { risk: "high", label: "读取聊天里的附件" },
19
+ channel: { risk: "high", label: "接入一个平台,并看到那里的消息" },
20
+ "http.public": { risk: "high", label: "开放一个不需要令牌的地址" },
21
+ "net.raw": { risk: "high", label: "自己直接联网" },
22
+ };
23
+
24
+ export const API_VERSION = "1.0";
25
+ export const API_FEATURES = [
26
+ "senses",
27
+ "observe",
28
+ "activities",
29
+ "actions",
30
+ "perceive",
31
+ "channel",
32
+ "knowledge",
33
+ "models",
34
+ "http",
35
+ "notify",
36
+ "mind.read",
37
+ "ui",
38
+ ];
39
+
40
+ export function permissionKnown(name) {
41
+ return Object.hasOwn(PERMISSIONS, name);
42
+ }
@@ -1,36 +1,36 @@
1
- import { registerHooks } from "node:module";
2
-
3
- // A plugin process may use the language. It may not open the database, start
4
- // another process, or reach the network unless it was explicitly allowed to.
5
- const raw = process.env.LUCKYTRI_NET_RAW === "1";
6
- const blocked = new Set([
7
- "sqlite",
8
- "child_process",
9
- "worker_threads",
10
- "cluster",
11
- "inspector",
12
- ...(raw
13
- ? []
14
- : ["net", "http", "https", "tls", "dgram", "dns", "http2", "tls"]),
15
- ]);
16
-
17
- function denied(specifier) {
18
- const name = String(specifier || "").replace(/^node:/, "");
19
- const root = name.split("/")[0];
20
- return blocked.has(name) || blocked.has(root);
21
- }
22
-
23
- registerHooks({
24
- resolve(specifier, context, next) {
25
- if (denied(specifier)) {
26
- const error = new Error("插件没有这个能力");
27
- error.code = "ERR_PLUGIN_DENIED";
28
- throw error;
29
- }
30
- return next(specifier, context);
31
- },
32
- });
33
-
34
- process.kill = () => {
35
- throw new Error("插件不能结束别的进程");
36
- };
1
+ import { registerHooks } from "node:module";
2
+
3
+ // A plugin process may use the language. It may not open the database, start
4
+ // another process, or reach the network unless it was explicitly allowed to.
5
+ const raw = process.env.LUCKYTRI_NET_RAW === "1";
6
+ const blocked = new Set([
7
+ "sqlite",
8
+ "child_process",
9
+ "worker_threads",
10
+ "cluster",
11
+ "inspector",
12
+ ...(raw
13
+ ? []
14
+ : ["net", "http", "https", "tls", "dgram", "dns", "http2", "tls"]),
15
+ ]);
16
+
17
+ function denied(specifier) {
18
+ const name = String(specifier || "").replace(/^node:/, "");
19
+ const root = name.split("/")[0];
20
+ return blocked.has(name) || blocked.has(root);
21
+ }
22
+
23
+ registerHooks({
24
+ resolve(specifier, context, next) {
25
+ if (denied(specifier)) {
26
+ const error = new Error("插件没有这个能力");
27
+ error.code = "ERR_PLUGIN_DENIED";
28
+ throw error;
29
+ }
30
+ return next(specifier, context);
31
+ },
32
+ });
33
+
34
+ process.kill = () => {
35
+ throw new Error("插件不能结束别的进程");
36
+ };