@theowlops/boombot 1.1.0 → 1.1.1
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/dist/cli/commands/setup.js +60 -46
- package/dist/package.json +1 -1
- package/package.json +1 -1
|
@@ -129,59 +129,69 @@ export function browserHost(host) {
|
|
|
129
129
|
return host === '0.0.0.0' || host === '::' ? '127.0.0.1' : host;
|
|
130
130
|
}
|
|
131
131
|
export async function runSetup() {
|
|
132
|
-
|
|
132
|
+
const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
|
|
133
|
+
const bold = (s) => `\x1b[1m${s}\x1b[0m`;
|
|
134
|
+
const green = (s) => `\x1b[32m${s}\x1b[0m`;
|
|
135
|
+
const dim = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
136
|
+
const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
|
|
137
|
+
console.log(`
|
|
138
|
+
${cyan('╭───────────────────────────────────────────────╮')}
|
|
139
|
+
${cyan('│')} ${bold('🦉 BoomBot — First-Run Setup Wizard')} ${cyan('│')}
|
|
140
|
+
${cyan('│')} ${dim('Thiết lập nhanh Gateway, API Key & LLM')} ${cyan('│')}
|
|
141
|
+
${cyan('╰───────────────────────────────────────────────╯')}
|
|
142
|
+
`);
|
|
133
143
|
const existing = loadConfig();
|
|
134
|
-
|
|
135
|
-
const
|
|
136
|
-
const
|
|
137
|
-
const
|
|
144
|
+
console.log(`${bold('1. Cấu hình mạng & đường dẫn (Network & Paths)')}`);
|
|
145
|
+
const host = await askDefault(` ${cyan('•')} Gateway host`, existing?.host ?? '127.0.0.1');
|
|
146
|
+
const defaultPort = existing?.port ?? 8788;
|
|
147
|
+
const port = parsePort(await ask(` ${cyan('•')} Gateway port [${defaultPort}]: `), defaultPort);
|
|
148
|
+
const dataDir = await askDefault(` ${cyan('•')} Thư mục dữ liệu (Data directory)`, existing?.dataDir ?? '~/.boombot/data');
|
|
138
149
|
// API key — kept at <config-dir>/api.key (0600) so it stays recoverable; the
|
|
139
150
|
// config only ever holds its sha256. An existing key is reused, never rotated.
|
|
151
|
+
console.log(`\n${bold('2. Khóa bảo mật Gateway (Security Keys)')}`);
|
|
140
152
|
const { apiKey, apiKeyHash, keyPath, created, fromEnv } = ensureApiKey();
|
|
141
153
|
if (fromEnv) {
|
|
142
|
-
console.log('
|
|
154
|
+
console.log(` ${green('✔')} Sử dụng API key từ biến môi trường BOOMBOT_API_KEY`);
|
|
143
155
|
}
|
|
144
156
|
else if (created) {
|
|
145
|
-
console.log('
|
|
146
|
-
console.log('
|
|
147
|
-
console.log(
|
|
148
|
-
console.log(`
|
|
149
|
-
console.log('there and signs your browser in automatically, so you can ignore this');
|
|
150
|
-
console.log('notice. Only the sha256 hash is written to config.json.');
|
|
151
|
-
console.log('────────────────────────────────────────\n');
|
|
157
|
+
console.log(` ${yellow('┌─ Gateway API Key của bạn (Lưu vào nơi an toàn) ───────────────┐')}`);
|
|
158
|
+
console.log(` ${yellow('│')} ${bold(apiKey)}`);
|
|
159
|
+
console.log(` ${yellow('└───────────────────────────────────────────────────────────────┘')}`);
|
|
160
|
+
console.log(` ${dim(`Đã lưu tại: ${keyPath} (tự động đăng nhập web)`)}`);
|
|
152
161
|
}
|
|
153
162
|
else {
|
|
154
|
-
console.log(
|
|
155
|
-
console.log('(delete that file and re-run setup to rotate it)\n');
|
|
163
|
+
console.log(` ${green('✔')} Giữ API key hiện có tại: ${dim(keyPath)}`);
|
|
156
164
|
}
|
|
157
|
-
// Master key — encrypts provider API keys at rest.
|
|
158
|
-
// as BOOMBOT_MASTER_KEY; `boombot gateway` loads this file automatically.
|
|
165
|
+
// Master key — encrypts provider API keys at rest.
|
|
159
166
|
const masterKeyPath = resolveMasterKeyPath();
|
|
160
167
|
const masterKey = process.env['BOOMBOT_MASTER_KEY'] || ensureMasterKey(masterKeyPath);
|
|
161
|
-
console.log(`Master key
|
|
162
|
-
console.log('(mode 0600 — it decrypts your provider keys, keep it safe)\n');
|
|
168
|
+
console.log(` ${green('✔')} Master key mã hóa AES-256: ${dim(masterKeyPath)}`);
|
|
163
169
|
// Telegram (optional).
|
|
170
|
+
console.log(`\n${bold('3. Kênh kết nối Chat (Messaging Channels)')}`);
|
|
164
171
|
let telegram = existing?.telegram;
|
|
165
|
-
if (await askYesNo('
|
|
166
|
-
const botToken = await readSecret('
|
|
167
|
-
const allowlist = parseAllowlist(await ask('
|
|
172
|
+
if (await askYesNo(` ${cyan('?')} Cấu hình bot Telegram?`, false)) {
|
|
173
|
+
const botToken = await readSecret(' Token bot Telegram: ');
|
|
174
|
+
const allowlist = parseAllowlist(await ask(' Chat IDs được phép (phân cách bằng dấu phẩy, để trống = tất cả): '));
|
|
168
175
|
telegram = { botToken: botToken.trim(), allowlistChatIds: allowlist };
|
|
176
|
+
console.log(` ${green('✔')} Đã cấu hình Telegram.`);
|
|
169
177
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
178
|
+
else {
|
|
179
|
+
console.log(` ${dim('Bỏ qua kết nối Telegram (có thể cấu hình sau trên Web UI).')}`);
|
|
180
|
+
}
|
|
181
|
+
// Default provider → the real encrypted store (<dataDir>/providers.json)
|
|
182
|
+
console.log(`\n${bold('4. Nhà cung cấp AI (LLM Provider)')}`);
|
|
183
|
+
if (await askYesNo(` ${cyan('?')} Thiết lập nhà cung cấp LLM mặc định?`, true)) {
|
|
184
|
+
console.log(` ${dim(`Các loại hỗ trợ: ${PROVIDER_KINDS.join(', ')}`)}`);
|
|
175
185
|
const kind = await askProviderKind();
|
|
176
186
|
if (kind !== null) {
|
|
177
|
-
const model = await askRequired('
|
|
187
|
+
const model = await askRequired(' Model mặc định (vd: gpt-4o, claude-3-7-sonnet): ');
|
|
178
188
|
const needsBaseUrl = kind === 'openai-compatible' || kind === 'local';
|
|
179
189
|
const baseUrl = needsBaseUrl
|
|
180
|
-
? await askRequired('Base URL (
|
|
181
|
-
: (await ask('Base URL (
|
|
190
|
+
? await askRequired(' Base URL (bắt buộc cho loại này): ')
|
|
191
|
+
: (await ask(' Base URL (để trống = mặc định): ')).trim();
|
|
182
192
|
const providerApiKey = kind === 'local'
|
|
183
|
-
? (await readSecret('Provider API key (
|
|
184
|
-
: await readRequiredSecret('Provider API key: ');
|
|
193
|
+
? (await readSecret(' Provider API key (để trống nếu không có): ')).trim()
|
|
194
|
+
: await readRequiredSecret(' Provider API key: ');
|
|
185
195
|
const service = createProviderService({
|
|
186
196
|
storagePath: path.join(expandTilde(dataDir), 'providers.json'),
|
|
187
197
|
masterKey,
|
|
@@ -195,11 +205,13 @@ export async function runSetup() {
|
|
|
195
205
|
...(providerApiKey !== '' ? { apiKey: providerApiKey } : {}),
|
|
196
206
|
active: true,
|
|
197
207
|
});
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
console.log(`\nSaved default provider '${saved.name}' (${saved.kind})${keyNote}.`);
|
|
208
|
+
const keyNote = providerApiKey !== '' ? ' (đã mã hóa an toàn)' : '';
|
|
209
|
+
console.log(` ${green('✔')} Đã lưu provider '${saved.name}' [${saved.kind}]${keyNote}`);
|
|
201
210
|
}
|
|
202
211
|
}
|
|
212
|
+
else {
|
|
213
|
+
console.log(` ${dim('Bỏ qua cấu hình LLM (bạn có thể thêm trực tiếp trên Web UI).')}`);
|
|
214
|
+
}
|
|
203
215
|
const config = {
|
|
204
216
|
...existing,
|
|
205
217
|
host,
|
|
@@ -210,21 +222,23 @@ export async function runSetup() {
|
|
|
210
222
|
};
|
|
211
223
|
const problems = validateConfig(config);
|
|
212
224
|
if (problems.length > 0) {
|
|
213
|
-
console.error(`\
|
|
225
|
+
console.error(`\n❌ Cấu hình không hợp lệ: ${problems.join('; ')}`);
|
|
214
226
|
process.exitCode = 1;
|
|
215
227
|
return;
|
|
216
228
|
}
|
|
217
229
|
const configPath = resolveConfigPath();
|
|
218
230
|
saveConfig(config, configPath);
|
|
219
|
-
const permsNote = process.platform === 'win32'
|
|
220
|
-
? 'permissions NOT enforced on Windows (chmod is a no-op) — see SECURITY.md §5'
|
|
221
|
-
: 'mode 0600 — secrets protected';
|
|
222
|
-
console.log(`\nSaved config to ${configPath} (${permsNote}).`);
|
|
223
231
|
const url = `http://${browserHost(host)}:${port}`;
|
|
224
|
-
console.log(
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
232
|
+
console.log(`
|
|
233
|
+
${green('╭───────────────────────────────────────────────╮')}
|
|
234
|
+
${green('│')} ${bold('🎉 CÀI ĐẶT HOÀN TẤT THÀNH CÔNG!')} ${green('│')}
|
|
235
|
+
${green('╰───────────────────────────────────────────────╯')}
|
|
236
|
+
|
|
237
|
+
${bold('Tệp cấu hình:')} ${dim(configPath)}
|
|
238
|
+
${bold('Giao diện Web:')} ${cyan(url)}
|
|
239
|
+
|
|
240
|
+
${bold('Bắt đầu sử dụng:')}
|
|
241
|
+
${cyan('1.')} ${bold('boombot')} Khởi động Gateway và mở Web UI
|
|
242
|
+
${cyan('2.')} ${bold('boombot doctor')} Kiểm tra toàn diện tình trạng hệ thống
|
|
243
|
+
`);
|
|
230
244
|
}
|
package/dist/package.json
CHANGED