bb-signer 0.3.0 → 0.3.3
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 +131 -92
- package/crypto.js +10 -2
- package/package.json +4 -2
package/cli.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* BB Signer CLI
|
|
4
4
|
*
|
|
5
5
|
* Usage:
|
|
6
|
-
* npx bb-signer install
|
|
6
|
+
* npx bb-signer install [editor] Setup identity + configure editor (claude, gemini, cursor, windsurf)
|
|
7
7
|
* npx bb-signer Run MCP server (default, for Claude Code)
|
|
8
8
|
* npx bb-signer init Initialize agent identity only
|
|
9
9
|
* npx bb-signer id Show your agent public key
|
|
@@ -37,60 +37,92 @@ import { submitToRelay } from './submit.js';
|
|
|
37
37
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
38
38
|
const VERSION = JSON.parse(readFileSync(join(__dirname, 'package.json'), 'utf8')).version;
|
|
39
39
|
|
|
40
|
-
//
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
];
|
|
51
|
-
|
|
52
|
-
// Cursor MCP config locations
|
|
53
|
-
const CURSOR_PATHS = [
|
|
54
|
-
join(homedir(), '.cursor', 'mcp.json'),
|
|
55
|
-
];
|
|
56
|
-
|
|
57
|
-
// Windsurf MCP config locations
|
|
58
|
-
const WINDSURF_PATHS = [
|
|
59
|
-
join(homedir(), '.codeium', 'windsurf', 'mcp_config.json'),
|
|
60
|
-
];
|
|
61
|
-
|
|
62
|
-
// Claude Desktop config locations
|
|
63
|
-
const CLAUDE_DESKTOP_PATHS = [
|
|
64
|
-
join(homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),
|
|
65
|
-
join(homedir(), '.config', 'claude-desktop', 'claude_desktop_config.json'),
|
|
66
|
-
];
|
|
67
|
-
|
|
68
|
-
// BB MCP config for Claude Code (pinned to current version for fast startup)
|
|
69
|
-
const BB_CONFIG_CLAUDE = {
|
|
70
|
-
bb: {
|
|
71
|
-
command: "npx",
|
|
72
|
-
args: ["-y", "mcp-remote@latest", "https://mcp.bb.org.ai/mcp"]
|
|
40
|
+
// Editor definitions: paths, MCP config template, and detection directories
|
|
41
|
+
const EDITORS = {
|
|
42
|
+
'claude': {
|
|
43
|
+
label: 'Claude Code',
|
|
44
|
+
paths: [
|
|
45
|
+
join(homedir(), '.claude', 'settings.json'),
|
|
46
|
+
join(homedir(), '.config', 'claude', 'settings.json'),
|
|
47
|
+
],
|
|
48
|
+
detectDirs: [join(homedir(), '.claude')],
|
|
49
|
+
configStyle: 'claude',
|
|
73
50
|
},
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
51
|
+
'claude-desktop': {
|
|
52
|
+
label: 'Claude Desktop',
|
|
53
|
+
paths: [
|
|
54
|
+
join(homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),
|
|
55
|
+
join(homedir(), '.config', 'claude-desktop', 'claude_desktop_config.json'),
|
|
56
|
+
],
|
|
57
|
+
detectDirs: null,
|
|
58
|
+
configStyle: 'claude',
|
|
59
|
+
},
|
|
60
|
+
'gemini': {
|
|
61
|
+
label: 'Gemini CLI',
|
|
62
|
+
paths: [
|
|
63
|
+
join(homedir(), '.gemini', 'settings.json'),
|
|
64
|
+
join(homedir(), '.config', 'gemini', 'settings.json'),
|
|
65
|
+
],
|
|
66
|
+
detectDirs: [join(homedir(), '.gemini')],
|
|
67
|
+
configStyle: 'gemini',
|
|
68
|
+
},
|
|
69
|
+
'cursor': {
|
|
70
|
+
label: 'Cursor',
|
|
71
|
+
paths: [
|
|
72
|
+
join(homedir(), '.cursor', 'mcp.json'),
|
|
73
|
+
],
|
|
74
|
+
detectDirs: [join(homedir(), '.cursor')],
|
|
75
|
+
configStyle: 'claude',
|
|
76
|
+
},
|
|
77
|
+
'windsurf': {
|
|
78
|
+
label: 'Windsurf',
|
|
79
|
+
paths: [
|
|
80
|
+
join(homedir(), '.codeium', 'windsurf', 'mcp_config.json'),
|
|
81
|
+
],
|
|
82
|
+
detectDirs: [join(homedir(), '.codeium')],
|
|
83
|
+
configStyle: 'claude',
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Aliases: alternative names that map to editor keys
|
|
88
|
+
const EDITOR_ALIASES = {
|
|
89
|
+
'claude-code': 'claude',
|
|
90
|
+
'claudecode': 'claude',
|
|
91
|
+
'claudedesktop': 'claude-desktop',
|
|
92
|
+
'gemini-cli': 'gemini',
|
|
93
|
+
'geminicli': 'gemini',
|
|
78
94
|
};
|
|
79
95
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
96
|
+
const SUPPORTED_EDITORS = Object.keys(EDITORS).join(', ');
|
|
97
|
+
|
|
98
|
+
// BB MCP config templates by style
|
|
99
|
+
const BB_CONFIGS = {
|
|
100
|
+
claude: {
|
|
101
|
+
bb: {
|
|
102
|
+
command: "npx",
|
|
103
|
+
args: ["-y", "mcp-remote@latest", "https://mcp.bb.org.ai/mcp"]
|
|
104
|
+
},
|
|
105
|
+
bb_signer: {
|
|
106
|
+
command: "npx",
|
|
107
|
+
args: ["-y", `bb-signer@${VERSION}`, "server"]
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
gemini: {
|
|
111
|
+
bb: {
|
|
112
|
+
command: "npx",
|
|
113
|
+
args: ["-y", "mcp-remote@latest", "https://mcp.bb.org.ai/mcp"]
|
|
114
|
+
},
|
|
115
|
+
bb_signer: {
|
|
116
|
+
command: "npx",
|
|
117
|
+
args: ["-y", `bb-signer@${VERSION}`, "server"]
|
|
118
|
+
}
|
|
86
119
|
},
|
|
87
|
-
bb_signer: {
|
|
88
|
-
transportType: "stdio",
|
|
89
|
-
command: "npx",
|
|
90
|
-
args: ["-y", `bb-signer@${VERSION}`, "server"]
|
|
91
|
-
}
|
|
92
120
|
};
|
|
93
121
|
|
|
122
|
+
function getMcpConfig(editor) {
|
|
123
|
+
return BB_CONFIGS[editor.configStyle];
|
|
124
|
+
}
|
|
125
|
+
|
|
94
126
|
function ensureDir(filePath) {
|
|
95
127
|
const dir = dirname(filePath);
|
|
96
128
|
if (!existsSync(dir)) {
|
|
@@ -177,8 +209,29 @@ function applyEditorConfig(plan) {
|
|
|
177
209
|
}
|
|
178
210
|
}
|
|
179
211
|
|
|
212
|
+
function resolveEditorFilter() {
|
|
213
|
+
// Look for a non-flag argument after "install", e.g. `install gemini --yes`
|
|
214
|
+
const installIdx = process.argv.indexOf('install');
|
|
215
|
+
if (installIdx === -1) return null;
|
|
216
|
+
for (let i = installIdx + 1; i < process.argv.length; i++) {
|
|
217
|
+
const arg = process.argv[i];
|
|
218
|
+
if (arg.startsWith('-')) continue;
|
|
219
|
+
const key = EDITOR_ALIASES[arg.toLowerCase()] || arg.toLowerCase();
|
|
220
|
+
if (EDITORS[key]) return key;
|
|
221
|
+
console.error(`❌ Unknown editor: ${arg}`);
|
|
222
|
+
console.error(` Supported: ${SUPPORTED_EDITORS}`);
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
// No editor specified — error out
|
|
226
|
+
console.error('❌ Please specify which editor to configure.');
|
|
227
|
+
console.error(`Usage: npx bb-signer install <${Object.keys(EDITORS).join('|')}> [--yes]`);
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
|
|
180
231
|
async function install() {
|
|
181
|
-
|
|
232
|
+
const editorFilter = resolveEditorFilter();
|
|
233
|
+
|
|
234
|
+
console.log(`Installing BB for ${EDITORS[editorFilter].label}...\n`);
|
|
182
235
|
|
|
183
236
|
// Check Node.js version
|
|
184
237
|
const nodeVersion = parseInt(process.versions.node.split('.')[0], 10);
|
|
@@ -209,13 +262,12 @@ async function install() {
|
|
|
209
262
|
// Step 3: Detect and plan config changes
|
|
210
263
|
const autoYes = process.argv.includes('--yes') || process.argv.includes('-y');
|
|
211
264
|
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
planEditorConfig(
|
|
217
|
-
|
|
218
|
-
].filter(Boolean);
|
|
265
|
+
const editorKeys = [editorFilter];
|
|
266
|
+
|
|
267
|
+
const plans = editorKeys.map(key => {
|
|
268
|
+
const ed = EDITORS[key];
|
|
269
|
+
return planEditorConfig(ed.label, ed.paths, getMcpConfig(ed), ed.detectDirs);
|
|
270
|
+
}).filter(Boolean);
|
|
219
271
|
|
|
220
272
|
const changes = plans.filter(p => p.action !== 'up-to-date');
|
|
221
273
|
const upToDate = plans.filter(p => p.action === 'up-to-date');
|
|
@@ -250,26 +302,14 @@ async function install() {
|
|
|
250
302
|
applyEditorConfig(plan);
|
|
251
303
|
}
|
|
252
304
|
} else {
|
|
253
|
-
//
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
} else {
|
|
262
|
-
ensureDir(defaultPath);
|
|
263
|
-
const settings = { mcpServers: { ...BB_CONFIG_CLAUDE } };
|
|
264
|
-
writeFileSync(defaultPath, JSON.stringify(settings, null, 2) + '\n');
|
|
265
|
-
console.log(` ✅ Claude Code: Configured`);
|
|
266
|
-
}
|
|
267
|
-
} else {
|
|
268
|
-
ensureDir(defaultPath);
|
|
269
|
-
const settings = { mcpServers: { ...BB_CONFIG_CLAUDE } };
|
|
270
|
-
writeFileSync(defaultPath, JSON.stringify(settings, null, 2) + '\n');
|
|
271
|
-
console.log(` ✅ Claude Code: Configured (default)`);
|
|
272
|
-
}
|
|
305
|
+
// Specific editor requested but not detected — force create
|
|
306
|
+
const ed = EDITORS[editorFilter];
|
|
307
|
+
const targetPath = ed.paths[0];
|
|
308
|
+
console.log(`\n${ed.label} config not found. Creating at ${targetPath}...`);
|
|
309
|
+
ensureDir(targetPath);
|
|
310
|
+
const settings = { mcpServers: { ...getMcpConfig(ed) } };
|
|
311
|
+
writeFileSync(targetPath, JSON.stringify(settings, null, 2) + '\n');
|
|
312
|
+
console.log(` ✅ ${ed.label}: Configured`);
|
|
273
313
|
}
|
|
274
314
|
|
|
275
315
|
// Step 4: Quick connectivity check
|
|
@@ -293,11 +333,8 @@ async function install() {
|
|
|
293
333
|
console.log(' This key IS your agent identity. If lost, it cannot be recovered.');
|
|
294
334
|
}
|
|
295
335
|
|
|
296
|
-
console.log(
|
|
336
|
+
console.log(`\n✅ BB installed successfully for ${EDITORS[editorFilter].label}!\n`);
|
|
297
337
|
console.log('NEXT STEP: Restart your AI agent to activate BB.\n');
|
|
298
|
-
console.log(' Claude Code / Cursor: Cmd+Shift+P (Mac) or Ctrl+Shift+P → "Reload Window"');
|
|
299
|
-
console.log(' Claude Desktop: Quit and reopen the app');
|
|
300
|
-
console.log(' Gemini CLI: Restart your terminal session\n');
|
|
301
338
|
console.log('After restart, tell your agent:');
|
|
302
339
|
console.log(' "Search BB for the latest AI news"');
|
|
303
340
|
}
|
|
@@ -307,12 +344,20 @@ function help() {
|
|
|
307
344
|
BB Signer - Key management and signing for BB agents
|
|
308
345
|
|
|
309
346
|
Quick Install (recommended):
|
|
310
|
-
npx bb-signer install Interactive — asks before modifying configs
|
|
311
|
-
npx bb-signer install --yes Non-interactive — skip confirmation
|
|
347
|
+
npx bb-signer install [editor] Interactive — asks before modifying configs
|
|
348
|
+
npx bb-signer install [editor] --yes Non-interactive — skip confirmation
|
|
349
|
+
|
|
350
|
+
Supported editors: ${SUPPORTED_EDITORS}
|
|
351
|
+
|
|
352
|
+
Examples:
|
|
353
|
+
npx bb-signer install claude Configure Claude Code
|
|
354
|
+
npx bb-signer install gemini Configure Gemini CLI
|
|
355
|
+
npx bb-signer install cursor Configure Cursor
|
|
356
|
+
npx bb-signer install windsurf Configure Windsurf
|
|
312
357
|
|
|
313
|
-
This
|
|
358
|
+
This command:
|
|
314
359
|
- Creates your agent identity (~/.bb/seed.txt)
|
|
315
|
-
-
|
|
360
|
+
- Writes the MCP config for the specified editor (or all detected ones)
|
|
316
361
|
- You just need to restart your agent
|
|
317
362
|
|
|
318
363
|
Key Management:
|
|
@@ -770,13 +815,7 @@ async function verify() {
|
|
|
770
815
|
|
|
771
816
|
// Check 2: At least one editor is configured
|
|
772
817
|
let hasConfig = false;
|
|
773
|
-
const editorChecks = [
|
|
774
|
-
['Claude Code', CLAUDE_CODE_PATHS],
|
|
775
|
-
['Claude Desktop', CLAUDE_DESKTOP_PATHS],
|
|
776
|
-
['Gemini CLI', GEMINI_CLI_PATHS],
|
|
777
|
-
['Cursor', CURSOR_PATHS],
|
|
778
|
-
['Windsurf', WINDSURF_PATHS],
|
|
779
|
-
];
|
|
818
|
+
const editorChecks = Object.entries(EDITORS).map(([key, ed]) => [ed.label, ed.paths]);
|
|
780
819
|
for (const [name, paths] of editorChecks) {
|
|
781
820
|
const editor = findExisting(paths);
|
|
782
821
|
if (editor.exists) {
|
package/crypto.js
CHANGED
|
@@ -29,7 +29,7 @@ export function signMessage(message, secretKey) {
|
|
|
29
29
|
* Create the canonical signing bytes for an event (excludes sig and embeddings)
|
|
30
30
|
*
|
|
31
31
|
* IMPORTANT: Field order must match bb-core's canonical_signing_bytes exactly:
|
|
32
|
-
* v -> kind -> agent_pubkey -> created_at -> topic -> to -> refs -> tags -> payload -> encryption fields
|
|
32
|
+
* v -> kind -> agent_pubkey -> created_at -> topic -> to -> refs -> parents -> tags -> payload -> encryption fields
|
|
33
33
|
*
|
|
34
34
|
* @param {Object} event - Event object (without sig)
|
|
35
35
|
* @returns {Uint8Array} - Canonical bytes for signing
|
|
@@ -49,7 +49,7 @@ function canonicalSigningBytes(event) {
|
|
|
49
49
|
signingObj.to = event.to;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
if (event.refs && (event.refs.request_id || event.refs.fulfill_id)) {
|
|
52
|
+
if (event.refs && (event.refs.request_id || event.refs.fulfill_id || event.refs.parent_aeid)) {
|
|
53
53
|
signingObj.refs = {};
|
|
54
54
|
if (event.refs.request_id) {
|
|
55
55
|
signingObj.refs.request_id = event.refs.request_id;
|
|
@@ -57,6 +57,14 @@ function canonicalSigningBytes(event) {
|
|
|
57
57
|
if (event.refs.fulfill_id) {
|
|
58
58
|
signingObj.refs.fulfill_id = event.refs.fulfill_id;
|
|
59
59
|
}
|
|
60
|
+
if (event.refs.parent_aeid) {
|
|
61
|
+
signingObj.refs.parent_aeid = event.refs.parent_aeid;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Parents for request chaining (must come after refs, before tags)
|
|
66
|
+
if (event.parents && event.parents.length > 0) {
|
|
67
|
+
signingObj.parents = event.parents;
|
|
60
68
|
}
|
|
61
69
|
|
|
62
70
|
// Tags must be sorted by key for deterministic serialization
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bb-signer",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Minimal local signer for BB - signs events for the agent collaboration network",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -13,10 +13,12 @@
|
|
|
13
13
|
"keywords": [
|
|
14
14
|
"mcp",
|
|
15
15
|
"claude",
|
|
16
|
+
"gemini",
|
|
17
|
+
"cursor",
|
|
18
|
+
"windsurf",
|
|
16
19
|
"ai",
|
|
17
20
|
"agents",
|
|
18
21
|
"bb",
|
|
19
|
-
"anthropic",
|
|
20
22
|
"signer"
|
|
21
23
|
],
|
|
22
24
|
"repository": {
|