bb-signer 0.3.6 → 0.3.8
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/cli.js +99 -52
- package/index.js +1 -1
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
29
29
|
import { createInterface } from 'readline';
|
|
30
|
+
import { execSync } from 'child_process';
|
|
30
31
|
import { homedir } from 'os';
|
|
31
32
|
import { join, dirname } from 'path';
|
|
32
33
|
import { fileURLToPath } from 'url';
|
|
@@ -39,6 +40,25 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
39
40
|
const VERSION = JSON.parse(readFileSync(join(__dirname, 'package.json'), 'utf8')).version;
|
|
40
41
|
|
|
41
42
|
// Editor definitions: paths, MCP config template, and detection directories
|
|
43
|
+
function hasClaude() {
|
|
44
|
+
try {
|
|
45
|
+
execSync('claude --version', { stdio: 'pipe' });
|
|
46
|
+
return true;
|
|
47
|
+
} catch { return false; }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function installViaClaude(mcpConfig) {
|
|
51
|
+
// Remove existing servers first (ignore errors if they don't exist)
|
|
52
|
+
for (const name of Object.keys(mcpConfig)) {
|
|
53
|
+
try { execSync(`claude mcp remove ${name}`, { stdio: 'pipe' }); } catch {}
|
|
54
|
+
}
|
|
55
|
+
// Add servers
|
|
56
|
+
for (const [name, config] of Object.entries(mcpConfig)) {
|
|
57
|
+
const args = config.args.map(a => `"${a}"`).join(' ');
|
|
58
|
+
execSync(`claude mcp add ${name} -- ${config.command} ${args}`, { stdio: 'pipe' });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
42
62
|
const EDITORS = {
|
|
43
63
|
'claude': {
|
|
44
64
|
label: 'Claude Code',
|
|
@@ -48,6 +68,7 @@ const EDITORS = {
|
|
|
48
68
|
],
|
|
49
69
|
detectDirs: [join(homedir(), '.claude')],
|
|
50
70
|
configStyle: 'claude',
|
|
71
|
+
usesCli: true, // prefer `claude mcp add` over settings.json
|
|
51
72
|
},
|
|
52
73
|
'claude-desktop': {
|
|
53
74
|
label: 'Claude Desktop',
|
|
@@ -210,7 +231,16 @@ function applyEditorConfig(plan) {
|
|
|
210
231
|
}
|
|
211
232
|
}
|
|
212
233
|
|
|
213
|
-
function
|
|
234
|
+
function fallbackToSettingsFile(ed, mcpConfig) {
|
|
235
|
+
const targetPath = ed.paths[0];
|
|
236
|
+
console.log(`\n${ed.label} config not found. Creating at ${targetPath}...`);
|
|
237
|
+
ensureDir(targetPath);
|
|
238
|
+
const settings = { mcpServers: { ...mcpConfig } };
|
|
239
|
+
writeFileSync(targetPath, JSON.stringify(settings, null, 2) + '\n');
|
|
240
|
+
console.log(` ✅ ${ed.label}: Configured`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async function resolveEditorFilter() {
|
|
214
244
|
// Look for a non-flag argument after "install", e.g. `install gemini --yes`
|
|
215
245
|
const installIdx = process.argv.indexOf('install');
|
|
216
246
|
if (installIdx === -1) return null;
|
|
@@ -223,14 +253,30 @@ function resolveEditorFilter() {
|
|
|
223
253
|
console.error(` Supported: ${SUPPORTED_EDITORS}`);
|
|
224
254
|
process.exit(1);
|
|
225
255
|
}
|
|
226
|
-
// No editor specified —
|
|
227
|
-
|
|
228
|
-
console.
|
|
229
|
-
|
|
256
|
+
// No editor specified — ask interactively
|
|
257
|
+
const editorKeys = Object.keys(EDITORS);
|
|
258
|
+
console.log('Which editor do you want to configure?\n');
|
|
259
|
+
editorKeys.forEach((key, i) => {
|
|
260
|
+
console.log(` ${i + 1}. ${EDITORS[key].label}`);
|
|
261
|
+
});
|
|
262
|
+
console.log();
|
|
263
|
+
|
|
264
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
265
|
+
const answer = await new Promise(resolve => {
|
|
266
|
+
rl.question(`Pick [1-${editorKeys.length}]: `, resolve);
|
|
267
|
+
});
|
|
268
|
+
rl.close();
|
|
269
|
+
|
|
270
|
+
const idx = parseInt(answer, 10) - 1;
|
|
271
|
+
if (isNaN(idx) || idx < 0 || idx >= editorKeys.length) {
|
|
272
|
+
console.error('Invalid choice.');
|
|
273
|
+
process.exit(1);
|
|
274
|
+
}
|
|
275
|
+
return editorKeys[idx];
|
|
230
276
|
}
|
|
231
277
|
|
|
232
278
|
async function install() {
|
|
233
|
-
const editorFilter = resolveEditorFilter();
|
|
279
|
+
const editorFilter = await resolveEditorFilter();
|
|
234
280
|
|
|
235
281
|
console.log(`Installing BB for ${EDITORS[editorFilter].label}...\n`);
|
|
236
282
|
|
|
@@ -260,57 +306,58 @@ async function install() {
|
|
|
260
306
|
saveConfig({ ...config, proxy_url: "https://mcp.bb.org.ai" });
|
|
261
307
|
}
|
|
262
308
|
|
|
263
|
-
// Step 3:
|
|
309
|
+
// Step 3: Configure MCP servers
|
|
264
310
|
const autoYes = process.argv.includes('--yes') || process.argv.includes('-y');
|
|
265
|
-
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
console.log('\nAI agent configs:');
|
|
279
|
-
for (const plan of upToDate) {
|
|
280
|
-
console.log(` ✅ ${plan.name}: Up to date`);
|
|
281
|
-
}
|
|
282
|
-
} else if (changes.length > 0) {
|
|
283
|
-
// Show what will change and ask confirmation
|
|
284
|
-
console.log('\nThe following config files will be modified:\n');
|
|
285
|
-
for (const plan of changes) {
|
|
286
|
-
const label = plan.action === 'create' ? 'create' : 'update bb + bb_signer';
|
|
287
|
-
console.log(` ${plan.path} (${label})`);
|
|
288
|
-
}
|
|
289
|
-
for (const plan of upToDate) {
|
|
290
|
-
console.log(` ${plan.path} (no changes needed)`);
|
|
311
|
+
const ed = EDITORS[editorFilter];
|
|
312
|
+
const mcpConfig = getMcpConfig(ed);
|
|
313
|
+
|
|
314
|
+
// For Claude Code: use `claude mcp add` (settings.json alone doesn't work)
|
|
315
|
+
if (ed.usesCli && hasClaude()) {
|
|
316
|
+
console.log('\nConfiguring via Claude CLI...');
|
|
317
|
+
try {
|
|
318
|
+
installViaClaude(mcpConfig);
|
|
319
|
+
console.log(` ✅ ${ed.label}: Configured via \`claude mcp add\``);
|
|
320
|
+
} catch (e) {
|
|
321
|
+
console.error(` ❌ claude mcp add failed: ${e.message}`);
|
|
322
|
+
console.error(' Falling back to settings.json...');
|
|
323
|
+
fallbackToSettingsFile(ed, mcpConfig);
|
|
291
324
|
}
|
|
325
|
+
} else {
|
|
326
|
+
// All other editors: write to config file
|
|
327
|
+
const plans = [planEditorConfig(ed.label, ed.paths, mcpConfig, ed.detectDirs)].filter(Boolean);
|
|
328
|
+
const changes = plans.filter(p => p.action !== 'up-to-date');
|
|
329
|
+
const upToDate = plans.filter(p => p.action === 'up-to-date');
|
|
330
|
+
|
|
331
|
+
if (changes.length === 0 && plans.length > 0) {
|
|
332
|
+
console.log('\nAI agent configs:');
|
|
333
|
+
for (const plan of upToDate) {
|
|
334
|
+
console.log(` ✅ ${plan.name}: Up to date`);
|
|
335
|
+
}
|
|
336
|
+
} else if (changes.length > 0) {
|
|
337
|
+
console.log('\nThe following config files will be modified:\n');
|
|
338
|
+
for (const plan of changes) {
|
|
339
|
+
const label = plan.action === 'create' ? 'create' : 'update bb + bb_signer';
|
|
340
|
+
console.log(` ${plan.path} (${label})`);
|
|
341
|
+
}
|
|
342
|
+
for (const plan of upToDate) {
|
|
343
|
+
console.log(` ${plan.path} (no changes needed)`);
|
|
344
|
+
}
|
|
292
345
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
346
|
+
if (!autoYes) {
|
|
347
|
+
const proceed = await confirm('\nProceed? [Y/n] ');
|
|
348
|
+
if (!proceed) {
|
|
349
|
+
console.log('\nAborted. Run `npx bb-signer install` when ready.');
|
|
350
|
+
process.exit(0);
|
|
351
|
+
}
|
|
298
352
|
}
|
|
299
|
-
}
|
|
300
353
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
354
|
+
console.log('\nConfiguring AI agents...');
|
|
355
|
+
for (const plan of plans) {
|
|
356
|
+
applyEditorConfig(plan);
|
|
357
|
+
}
|
|
358
|
+
} else {
|
|
359
|
+
fallbackToSettingsFile(ed, mcpConfig);
|
|
304
360
|
}
|
|
305
|
-
} else {
|
|
306
|
-
// Specific editor requested but not detected — force create
|
|
307
|
-
const ed = EDITORS[editorFilter];
|
|
308
|
-
const targetPath = ed.paths[0];
|
|
309
|
-
console.log(`\n${ed.label} config not found. Creating at ${targetPath}...`);
|
|
310
|
-
ensureDir(targetPath);
|
|
311
|
-
const settings = { mcpServers: { ...getMcpConfig(ed) } };
|
|
312
|
-
writeFileSync(targetPath, JSON.stringify(settings, null, 2) + '\n');
|
|
313
|
-
console.log(` ✅ ${ed.label}: Configured`);
|
|
314
361
|
}
|
|
315
362
|
|
|
316
363
|
// Step 4: Quick connectivity check
|
|
@@ -532,7 +579,7 @@ async function verifySocial() {
|
|
|
532
579
|
const status = data.is_new_account ? 'New account created' : 'Agent linked to existing account';
|
|
533
580
|
console.log('\n🎉 VERIFICATION SUCCESSFUL!\n');
|
|
534
581
|
console.log(`${status}.`);
|
|
535
|
-
console.log(`Verified via ${data.platform} (@${data.
|
|
582
|
+
console.log(`Verified via ${data.platform} (@${data.platform_handle}).`);
|
|
536
583
|
console.log(`Credits: ${data.credits}`);
|
|
537
584
|
console.log('\nYou can now publish events, create requests, and post bounties!');
|
|
538
585
|
} catch (e) {
|
package/index.js
CHANGED