@dsh-plugin/dsh-synapse 0.1.0-dev.41044228975 → 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.
- package/LICENSE +661 -661
- package/README.md +0 -14
- package/package.json +1 -1
- package/vendor/gugle-chat-bot/LICENSE +661 -661
- package/vendor/gugle-chat-bot/package.json +57 -57
- package/vendor/gugle-chat-bot/src/allow-rule.yml +9345 -9345
- package/vendor/gugle-chat-bot/src/api.json +4284 -4284
- package/vendor/gugle-chat-bot/src/command/index.ts +141 -141
- package/vendor/gugle-chat-bot/src/config/features.ts +547 -547
- package/vendor/gugle-chat-bot/src/config/index.ts +184 -184
- package/vendor/gugle-chat-bot/src/config/manager.ts +356 -356
- package/vendor/gugle-chat-bot/src/constants/index.ts +13 -13
- package/vendor/gugle-chat-bot/src/custom.ts +548 -548
- package/vendor/gugle-chat-bot/src/event/index.ts +118 -118
- package/vendor/gugle-chat-bot/src/features/admin/index.ts +414 -414
- package/vendor/gugle-chat-bot/src/features/bili/image/impl/video.ts +39 -39
- package/vendor/gugle-chat-bot/src/features/bili/image/index.ts +37 -37
- package/vendor/gugle-chat-bot/src/features/bili/index.ts +65 -65
- package/vendor/gugle-chat-bot/src/features/bili/template/style/video.css +97 -97
- package/vendor/gugle-chat-bot/src/features/bili/template/video.html +56 -56
- package/vendor/gugle-chat-bot/src/features/discord-bridge/index.ts +1128 -1128
- package/vendor/gugle-chat-bot/src/features/discord-bridge/markdown.ts +105 -105
- package/vendor/gugle-chat-bot/src/features/discord-bridge/slash.ts +355 -355
- package/vendor/gugle-chat-bot/src/features/discord-bridge/source.ts +96 -96
- package/vendor/gugle-chat-bot/src/features/discord-bridge/template/message.html +14 -14
- package/vendor/gugle-chat-bot/src/features/discord-bridge/template/style/message.css +144 -144
- package/vendor/gugle-chat-bot/src/features/github/api.ts +93 -93
- package/vendor/gugle-chat-bot/src/features/github/binding.ts +161 -161
- package/vendor/gugle-chat-bot/src/features/github/image/impl/issue.ts +132 -132
- package/vendor/gugle-chat-bot/src/features/github/image/impl/pr.ts +144 -144
- package/vendor/gugle-chat-bot/src/features/github/image/impl/release.ts +160 -160
- package/vendor/gugle-chat-bot/src/features/github/image/index.ts +310 -310
- package/vendor/gugle-chat-bot/src/features/github/index.ts +302 -302
- package/vendor/gugle-chat-bot/src/features/github/template/issue.html +118 -118
- package/vendor/gugle-chat-bot/src/features/github/template/pull_request.html +125 -125
- package/vendor/gugle-chat-bot/src/features/github/template/release.html +53 -53
- package/vendor/gugle-chat-bot/src/features/github/template/style/issue.css +468 -468
- package/vendor/gugle-chat-bot/src/features/github/template/style/pull_request.css +468 -468
- package/vendor/gugle-chat-bot/src/features/github/template/style/release.css +412 -412
- package/vendor/gugle-chat-bot/src/features/hermes/client.ts +184 -184
- package/vendor/gugle-chat-bot/src/features/hermes/config.ts +210 -210
- package/vendor/gugle-chat-bot/src/features/hermes/context.ts +67 -67
- package/vendor/gugle-chat-bot/src/features/hermes/history.ts +86 -86
- package/vendor/gugle-chat-bot/src/features/hermes/index.ts +1533 -1533
- package/vendor/gugle-chat-bot/src/features/hermes/message.ts +319 -319
- package/vendor/gugle-chat-bot/src/features/hermes/reaction.ts +181 -181
- package/vendor/gugle-chat-bot/src/features/hermes/render.ts +118 -118
- package/vendor/gugle-chat-bot/src/features/hermes/reply-units.ts +331 -331
- package/vendor/gugle-chat-bot/src/features/hermes/skills.ts +406 -406
- package/vendor/gugle-chat-bot/src/features/hermes/template/approval.html +30 -30
- package/vendor/gugle-chat-bot/src/features/hermes/template/progress.html +21 -21
- package/vendor/gugle-chat-bot/src/features/hermes/template/style/approval.css +81 -81
- package/vendor/gugle-chat-bot/src/features/hermes/template/style/progress.css +120 -120
- package/vendor/gugle-chat-bot/src/features/hermes/trigger.ts +86 -86
- package/vendor/gugle-chat-bot/src/features/hermes/types.ts +327 -327
- package/vendor/gugle-chat-bot/src/features/management/index.ts +156 -156
- package/vendor/gugle-chat-bot/src/features/minecraft/index.ts +127 -127
- package/vendor/gugle-chat-bot/src/features/modrinth/index.ts +71 -71
- package/vendor/gugle-chat-bot/src/features/parentheses/index.ts +117 -117
- package/vendor/gugle-chat-bot/src/features/peak-valley-timer/index.ts +451 -451
- package/vendor/gugle-chat-bot/src/features/poke/index.ts +24 -24
- package/vendor/gugle-chat-bot/src/features/version-tracker/index.ts +77 -77
- package/vendor/gugle-chat-bot/src/features/welcome/index.ts +57 -57
- package/vendor/gugle-chat-bot/src/github-ip.json +5814 -5814
- package/vendor/gugle-chat-bot/src/image/index.ts +278 -278
- package/vendor/gugle-chat-bot/src/index.ts +695 -695
- package/vendor/gugle-chat-bot/src/logger/index.ts +54 -54
- package/vendor/gugle-chat-bot/src/result.json +359 -359
- package/vendor/gugle-chat-bot/src/type/bili.d.ts +825 -825
- package/vendor/gugle-chat-bot/src/type/event.d.ts +146 -146
- package/vendor/gugle-chat-bot/src/type/github.d.ts +446 -446
- package/vendor/gugle-chat-bot/src/type/index.d.ts +254 -254
- package/vendor/gugle-chat-bot/tsconfig.json +46 -46
- package/scripts/dump-npm-latest.mjs +0 -30
|
@@ -1,184 +1,184 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import Constants from '@/constants';
|
|
4
|
-
|
|
5
|
-
export type LogLevel = 'info' | 'error' | 'warn' | 'debug';
|
|
6
|
-
|
|
7
|
-
export interface BotConfig {
|
|
8
|
-
userAgent: string;
|
|
9
|
-
logLevel: LogLevel;
|
|
10
|
-
chromePath: string;
|
|
11
|
-
httpUrl: string;
|
|
12
|
-
wsUrl: string;
|
|
13
|
-
tokenParams: string;
|
|
14
|
-
wsToken: string;
|
|
15
|
-
httpToken: string;
|
|
16
|
-
githubPort: number;
|
|
17
|
-
githubAllowedRepositories: string[];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
type ConfigFile = Partial<BotConfig>;
|
|
21
|
-
|
|
22
|
-
const defaultBotConfig: BotConfig = {
|
|
23
|
-
userAgent: Constants.USER_AGENT,
|
|
24
|
-
logLevel: Constants.LOG_LEVEL,
|
|
25
|
-
chromePath: Constants.CHROME_PATH,
|
|
26
|
-
httpUrl: Constants.HTTP_URL,
|
|
27
|
-
wsUrl: Constants.WS_URL,
|
|
28
|
-
tokenParams: Constants.TOKEN_PARAMS,
|
|
29
|
-
wsToken: Constants.WS_TOKEN,
|
|
30
|
-
httpToken: Constants.HTTP_TOKEN,
|
|
31
|
-
githubPort: Constants.GITHUB_PORT,
|
|
32
|
-
githubAllowedRepositories: Constants.GITHUB_ALLOWED_REPOSITORIES
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const logLevels: readonly LogLevel[] = ['info', 'error', 'warn', 'debug'];
|
|
36
|
-
|
|
37
|
-
function isString(value: unknown): value is string {
|
|
38
|
-
return typeof value === 'string';
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function isLogLevel(value: unknown): value is LogLevel {
|
|
42
|
-
return isString(value) && logLevels.includes(value as LogLevel);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function isPort(value: unknown): value is number {
|
|
46
|
-
return typeof value === 'number' && Number.isInteger(value) && value > 0 && value <= 65535;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function isRepositoryPattern(value: unknown): value is string {
|
|
50
|
-
return isString(value) && /^[A-Za-z0-9_.-]+\/(?:[A-Za-z0-9_.-]+|\*)$/.test(value);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function isRepositoryPatternArray(value: unknown): value is string[] {
|
|
54
|
-
return Array.isArray(value) && value.every(isRepositoryPattern);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
interface LoadedConfigFile {
|
|
58
|
-
config: ConfigFile;
|
|
59
|
-
contents: string;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
interface NormalizedConfig {
|
|
63
|
-
config: BotConfig;
|
|
64
|
-
hasInvalidField: boolean;
|
|
65
|
-
needsWrite: boolean;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function writeConfigFile(configPath: string, config: BotConfig): void {
|
|
69
|
-
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
70
|
-
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function createDefaultConfigFile(configPath: string): void {
|
|
74
|
-
writeConfigFile(configPath, defaultBotConfig);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function createBackupConfigFile(configPath: string, contents: string): void {
|
|
78
|
-
const { dir, ext, name } = path.parse(configPath);
|
|
79
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
80
|
-
let backupPath = path.join(dir, `${name}.bak.${timestamp}${ext}`);
|
|
81
|
-
let index = 1;
|
|
82
|
-
|
|
83
|
-
while (fs.existsSync(backupPath)) {
|
|
84
|
-
backupPath = path.join(dir, `${name}.bak.${timestamp}.${index}${ext}`);
|
|
85
|
-
index++;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
fs.writeFileSync(backupPath, contents, 'utf8');
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function readConfigFile(configPath: string): LoadedConfigFile {
|
|
92
|
-
if (!fs.existsSync(configPath)) createDefaultConfigFile(configPath);
|
|
93
|
-
|
|
94
|
-
const contents = fs.readFileSync(configPath, 'utf8');
|
|
95
|
-
try {
|
|
96
|
-
const config = JSON.parse(contents) as unknown;
|
|
97
|
-
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
98
|
-
throw new Error('root must be an object');
|
|
99
|
-
}
|
|
100
|
-
return { config: config as ConfigFile, contents };
|
|
101
|
-
} catch (error) {
|
|
102
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
103
|
-
throw new Error(`Failed to load bot configuration from ${configPath}: ${message}`);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function normalizeConfig(config: ConfigFile): NormalizedConfig {
|
|
108
|
-
let hasInvalidField = false;
|
|
109
|
-
let needsWrite = false;
|
|
110
|
-
|
|
111
|
-
function valueOrDefault<T>(value: unknown, validator: (value: unknown) => value is T, fallback: T): T {
|
|
112
|
-
if (value === undefined) {
|
|
113
|
-
needsWrite = true;
|
|
114
|
-
return fallback;
|
|
115
|
-
}
|
|
116
|
-
if (!validator(value)) {
|
|
117
|
-
hasInvalidField = true;
|
|
118
|
-
needsWrite = true;
|
|
119
|
-
return fallback;
|
|
120
|
-
}
|
|
121
|
-
return value;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return {
|
|
125
|
-
config: {
|
|
126
|
-
userAgent: valueOrDefault(config.userAgent, isString, defaultBotConfig.userAgent),
|
|
127
|
-
logLevel: valueOrDefault(config.logLevel, isLogLevel, defaultBotConfig.logLevel),
|
|
128
|
-
chromePath: valueOrDefault(config.chromePath, isString, defaultBotConfig.chromePath),
|
|
129
|
-
httpUrl: valueOrDefault(config.httpUrl, isString, defaultBotConfig.httpUrl),
|
|
130
|
-
wsUrl: valueOrDefault(config.wsUrl, isString, defaultBotConfig.wsUrl),
|
|
131
|
-
tokenParams: valueOrDefault(config.tokenParams, isString, defaultBotConfig.tokenParams),
|
|
132
|
-
wsToken: valueOrDefault(config.wsToken, isString, defaultBotConfig.wsToken),
|
|
133
|
-
httpToken: valueOrDefault(config.httpToken, isString, defaultBotConfig.httpToken),
|
|
134
|
-
githubPort: valueOrDefault(config.githubPort, isPort, defaultBotConfig.githubPort),
|
|
135
|
-
githubAllowedRepositories: valueOrDefault(
|
|
136
|
-
config.githubAllowedRepositories,
|
|
137
|
-
isRepositoryPatternArray,
|
|
138
|
-
defaultBotConfig.githubAllowedRepositories
|
|
139
|
-
)
|
|
140
|
-
},
|
|
141
|
-
hasInvalidField,
|
|
142
|
-
needsWrite
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export function loadBotConfig(configPath: string = path.resolve(process.cwd(), 'configs', 'bot-config.json')): BotConfig {
|
|
147
|
-
const loadedConfig = readConfigFile(configPath);
|
|
148
|
-
const normalizedConfig = normalizeConfig(loadedConfig.config);
|
|
149
|
-
|
|
150
|
-
if (normalizedConfig.hasInvalidField) createBackupConfigFile(configPath, loadedConfig.contents);
|
|
151
|
-
if (normalizedConfig.needsWrite) writeConfigFile(configPath, normalizedConfig.config);
|
|
152
|
-
|
|
153
|
-
loadedConfigPath = configPath;
|
|
154
|
-
return normalizedConfig.config;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/** 生效配置的加载路径,写回配置时复用(由 loadBotConfig 记录) */
|
|
158
|
-
let loadedConfigPath: string = path.resolve(process.cwd(), 'configs', 'bot-config.json');
|
|
159
|
-
|
|
160
|
-
export const botConfig = loadBotConfig();
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* 把一个 GitHub 仓库或 owner 加入允许访问的仓库列表,并持久化到配置文件。
|
|
164
|
-
*
|
|
165
|
-
* 动机:管理员通过 /github allow 或 /github subscribe 授权仓库时,无需手工改配置文件。
|
|
166
|
-
* 传入 owner 时写入 `owner/*`(覆盖该 owner 下全部仓库,含后续新建的);
|
|
167
|
-
* 传入 owner/repo 时写入精确条目,只授权该仓库。
|
|
168
|
-
*
|
|
169
|
-
* @param target GitHub owner(如 Anvil-Dev)或仓库全名(如 Anvil-Dev/AnvilCraft)
|
|
170
|
-
* @returns 实际写入的允许列表条目
|
|
171
|
-
*/
|
|
172
|
-
export function addGithubAllowedRepository(target: string): string {
|
|
173
|
-
const pattern = target.includes('/') ? target : `${target}/*`;
|
|
174
|
-
if (botConfig.githubAllowedRepositories.includes(pattern)) return pattern;
|
|
175
|
-
botConfig.githubAllowedRepositories.push(pattern);
|
|
176
|
-
writeConfigFile(loadedConfigPath, botConfig);
|
|
177
|
-
return pattern;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/** 判断某条目是否已在允许列表中(不做任何写入) */
|
|
181
|
-
export function isGithubAllowedPattern(target: string): boolean {
|
|
182
|
-
const pattern = target.includes('/') ? target : `${target}/*`;
|
|
183
|
-
return botConfig.githubAllowedRepositories.includes(pattern);
|
|
184
|
-
}
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import Constants from '@/constants';
|
|
4
|
+
|
|
5
|
+
export type LogLevel = 'info' | 'error' | 'warn' | 'debug';
|
|
6
|
+
|
|
7
|
+
export interface BotConfig {
|
|
8
|
+
userAgent: string;
|
|
9
|
+
logLevel: LogLevel;
|
|
10
|
+
chromePath: string;
|
|
11
|
+
httpUrl: string;
|
|
12
|
+
wsUrl: string;
|
|
13
|
+
tokenParams: string;
|
|
14
|
+
wsToken: string;
|
|
15
|
+
httpToken: string;
|
|
16
|
+
githubPort: number;
|
|
17
|
+
githubAllowedRepositories: string[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type ConfigFile = Partial<BotConfig>;
|
|
21
|
+
|
|
22
|
+
const defaultBotConfig: BotConfig = {
|
|
23
|
+
userAgent: Constants.USER_AGENT,
|
|
24
|
+
logLevel: Constants.LOG_LEVEL,
|
|
25
|
+
chromePath: Constants.CHROME_PATH,
|
|
26
|
+
httpUrl: Constants.HTTP_URL,
|
|
27
|
+
wsUrl: Constants.WS_URL,
|
|
28
|
+
tokenParams: Constants.TOKEN_PARAMS,
|
|
29
|
+
wsToken: Constants.WS_TOKEN,
|
|
30
|
+
httpToken: Constants.HTTP_TOKEN,
|
|
31
|
+
githubPort: Constants.GITHUB_PORT,
|
|
32
|
+
githubAllowedRepositories: Constants.GITHUB_ALLOWED_REPOSITORIES
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const logLevels: readonly LogLevel[] = ['info', 'error', 'warn', 'debug'];
|
|
36
|
+
|
|
37
|
+
function isString(value: unknown): value is string {
|
|
38
|
+
return typeof value === 'string';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function isLogLevel(value: unknown): value is LogLevel {
|
|
42
|
+
return isString(value) && logLevels.includes(value as LogLevel);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isPort(value: unknown): value is number {
|
|
46
|
+
return typeof value === 'number' && Number.isInteger(value) && value > 0 && value <= 65535;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function isRepositoryPattern(value: unknown): value is string {
|
|
50
|
+
return isString(value) && /^[A-Za-z0-9_.-]+\/(?:[A-Za-z0-9_.-]+|\*)$/.test(value);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function isRepositoryPatternArray(value: unknown): value is string[] {
|
|
54
|
+
return Array.isArray(value) && value.every(isRepositoryPattern);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface LoadedConfigFile {
|
|
58
|
+
config: ConfigFile;
|
|
59
|
+
contents: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface NormalizedConfig {
|
|
63
|
+
config: BotConfig;
|
|
64
|
+
hasInvalidField: boolean;
|
|
65
|
+
needsWrite: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function writeConfigFile(configPath: string, config: BotConfig): void {
|
|
69
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
70
|
+
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function createDefaultConfigFile(configPath: string): void {
|
|
74
|
+
writeConfigFile(configPath, defaultBotConfig);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function createBackupConfigFile(configPath: string, contents: string): void {
|
|
78
|
+
const { dir, ext, name } = path.parse(configPath);
|
|
79
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
80
|
+
let backupPath = path.join(dir, `${name}.bak.${timestamp}${ext}`);
|
|
81
|
+
let index = 1;
|
|
82
|
+
|
|
83
|
+
while (fs.existsSync(backupPath)) {
|
|
84
|
+
backupPath = path.join(dir, `${name}.bak.${timestamp}.${index}${ext}`);
|
|
85
|
+
index++;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
fs.writeFileSync(backupPath, contents, 'utf8');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function readConfigFile(configPath: string): LoadedConfigFile {
|
|
92
|
+
if (!fs.existsSync(configPath)) createDefaultConfigFile(configPath);
|
|
93
|
+
|
|
94
|
+
const contents = fs.readFileSync(configPath, 'utf8');
|
|
95
|
+
try {
|
|
96
|
+
const config = JSON.parse(contents) as unknown;
|
|
97
|
+
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
98
|
+
throw new Error('root must be an object');
|
|
99
|
+
}
|
|
100
|
+
return { config: config as ConfigFile, contents };
|
|
101
|
+
} catch (error) {
|
|
102
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
103
|
+
throw new Error(`Failed to load bot configuration from ${configPath}: ${message}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function normalizeConfig(config: ConfigFile): NormalizedConfig {
|
|
108
|
+
let hasInvalidField = false;
|
|
109
|
+
let needsWrite = false;
|
|
110
|
+
|
|
111
|
+
function valueOrDefault<T>(value: unknown, validator: (value: unknown) => value is T, fallback: T): T {
|
|
112
|
+
if (value === undefined) {
|
|
113
|
+
needsWrite = true;
|
|
114
|
+
return fallback;
|
|
115
|
+
}
|
|
116
|
+
if (!validator(value)) {
|
|
117
|
+
hasInvalidField = true;
|
|
118
|
+
needsWrite = true;
|
|
119
|
+
return fallback;
|
|
120
|
+
}
|
|
121
|
+
return value;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
config: {
|
|
126
|
+
userAgent: valueOrDefault(config.userAgent, isString, defaultBotConfig.userAgent),
|
|
127
|
+
logLevel: valueOrDefault(config.logLevel, isLogLevel, defaultBotConfig.logLevel),
|
|
128
|
+
chromePath: valueOrDefault(config.chromePath, isString, defaultBotConfig.chromePath),
|
|
129
|
+
httpUrl: valueOrDefault(config.httpUrl, isString, defaultBotConfig.httpUrl),
|
|
130
|
+
wsUrl: valueOrDefault(config.wsUrl, isString, defaultBotConfig.wsUrl),
|
|
131
|
+
tokenParams: valueOrDefault(config.tokenParams, isString, defaultBotConfig.tokenParams),
|
|
132
|
+
wsToken: valueOrDefault(config.wsToken, isString, defaultBotConfig.wsToken),
|
|
133
|
+
httpToken: valueOrDefault(config.httpToken, isString, defaultBotConfig.httpToken),
|
|
134
|
+
githubPort: valueOrDefault(config.githubPort, isPort, defaultBotConfig.githubPort),
|
|
135
|
+
githubAllowedRepositories: valueOrDefault(
|
|
136
|
+
config.githubAllowedRepositories,
|
|
137
|
+
isRepositoryPatternArray,
|
|
138
|
+
defaultBotConfig.githubAllowedRepositories
|
|
139
|
+
)
|
|
140
|
+
},
|
|
141
|
+
hasInvalidField,
|
|
142
|
+
needsWrite
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function loadBotConfig(configPath: string = path.resolve(process.cwd(), 'configs', 'bot-config.json')): BotConfig {
|
|
147
|
+
const loadedConfig = readConfigFile(configPath);
|
|
148
|
+
const normalizedConfig = normalizeConfig(loadedConfig.config);
|
|
149
|
+
|
|
150
|
+
if (normalizedConfig.hasInvalidField) createBackupConfigFile(configPath, loadedConfig.contents);
|
|
151
|
+
if (normalizedConfig.needsWrite) writeConfigFile(configPath, normalizedConfig.config);
|
|
152
|
+
|
|
153
|
+
loadedConfigPath = configPath;
|
|
154
|
+
return normalizedConfig.config;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** 生效配置的加载路径,写回配置时复用(由 loadBotConfig 记录) */
|
|
158
|
+
let loadedConfigPath: string = path.resolve(process.cwd(), 'configs', 'bot-config.json');
|
|
159
|
+
|
|
160
|
+
export const botConfig = loadBotConfig();
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* 把一个 GitHub 仓库或 owner 加入允许访问的仓库列表,并持久化到配置文件。
|
|
164
|
+
*
|
|
165
|
+
* 动机:管理员通过 /github allow 或 /github subscribe 授权仓库时,无需手工改配置文件。
|
|
166
|
+
* 传入 owner 时写入 `owner/*`(覆盖该 owner 下全部仓库,含后续新建的);
|
|
167
|
+
* 传入 owner/repo 时写入精确条目,只授权该仓库。
|
|
168
|
+
*
|
|
169
|
+
* @param target GitHub owner(如 Anvil-Dev)或仓库全名(如 Anvil-Dev/AnvilCraft)
|
|
170
|
+
* @returns 实际写入的允许列表条目
|
|
171
|
+
*/
|
|
172
|
+
export function addGithubAllowedRepository(target: string): string {
|
|
173
|
+
const pattern = target.includes('/') ? target : `${target}/*`;
|
|
174
|
+
if (botConfig.githubAllowedRepositories.includes(pattern)) return pattern;
|
|
175
|
+
botConfig.githubAllowedRepositories.push(pattern);
|
|
176
|
+
writeConfigFile(loadedConfigPath, botConfig);
|
|
177
|
+
return pattern;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** 判断某条目是否已在允许列表中(不做任何写入) */
|
|
181
|
+
export function isGithubAllowedPattern(target: string): boolean {
|
|
182
|
+
const pattern = target.includes('/') ? target : `${target}/*`;
|
|
183
|
+
return botConfig.githubAllowedRepositories.includes(pattern);
|
|
184
|
+
}
|