50c 3.9.4 → 3.9.6
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/bin/50c.js +2284 -2226
- package/lib/backdoor-checker.js +991 -230
- package/lib/ip-utils.js +47 -0
- package/lib/pre-publish.js +1361 -812
- package/lib/team.js +714 -691
- package/lib/tools-registry.js +226 -223
- package/package.json +7 -2
package/bin/50c.js
CHANGED
|
@@ -1,2226 +1,2284 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* 50c - AI developer tools via MCP
|
|
4
|
-
* Pay-per-use from $0.01. No subscriptions.
|
|
5
|
-
* https://50c.ai
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const https = require('https');
|
|
9
|
-
const http = require('http');
|
|
10
|
-
const readline = require('readline');
|
|
11
|
-
const fs = require('fs');
|
|
12
|
-
const path = require('path');
|
|
13
|
-
const os = require('os');
|
|
14
|
-
const { spawn } = require('child_process');
|
|
15
|
-
|
|
16
|
-
// Early imports for CLI commands that need these
|
|
17
|
-
let call50cTool, subagent, httpFetch, sshExec, localExec, KNOWN_SERVERS;
|
|
18
|
-
let team, matchTaskToTools;
|
|
19
|
-
try {
|
|
20
|
-
const subagentModule = require('../lib/subagent.js');
|
|
21
|
-
call50cTool = subagentModule.call50cTool;
|
|
22
|
-
subagent = subagentModule.subagent;
|
|
23
|
-
httpFetch = subagentModule.httpFetch;
|
|
24
|
-
sshExec = subagentModule.sshExec;
|
|
25
|
-
localExec = subagentModule.localExec;
|
|
26
|
-
KNOWN_SERVERS = subagentModule.KNOWN_SERVERS;
|
|
27
|
-
|
|
28
|
-
const teamModule = require('../lib/team.js');
|
|
29
|
-
team = teamModule.team;
|
|
30
|
-
matchTaskToTools = teamModule.matchTaskToTools;
|
|
31
|
-
} catch (e) {
|
|
32
|
-
// Graceful fallback if libs not available (shouldn't happen in normal install)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const VERSION = require('../package.json').version;
|
|
36
|
-
const HOME = os.homedir();
|
|
37
|
-
const HUB_DIR = path.join(HOME, '.50c');
|
|
38
|
-
const CONFIG_FILE = path.join(HUB_DIR, 'config.json');
|
|
39
|
-
const LOCKFILE = path.join(HUB_DIR, 'lockfile.json');
|
|
40
|
-
const CACHE_DIR = path.join(HUB_DIR, 'cache');
|
|
41
|
-
|
|
42
|
-
const API_ENDPOINT = process.env.FIFTYC_ENDPOINT || 'https://api.50c.ai';
|
|
43
|
-
const MCP_ENDPOINT = API_ENDPOINT + '/mcp';
|
|
44
|
-
const BEACON_ENDPOINT = process.env.FIFTYC_BEACON || 'https://beacon.50c.ai/mcp';
|
|
45
|
-
const BEACON_TOOLS = ['tip', 'notip', 'health', 'compress', 'extract', 'mint', 'recall', 'remember', 'checkpoint', 'restore', 'drift', 'summarize', 'diff', 'scan', 'rank', 'focus'];
|
|
46
|
-
|
|
47
|
-
// Ensure hub directory exists
|
|
48
|
-
if (!fs.existsSync(HUB_DIR)) {
|
|
49
|
-
fs.mkdirSync(HUB_DIR, { recursive: true });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Load config
|
|
53
|
-
function loadConfig() {
|
|
54
|
-
try {
|
|
55
|
-
if (fs.existsSync(CONFIG_FILE)) {
|
|
56
|
-
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
57
|
-
}
|
|
58
|
-
} catch (e) {}
|
|
59
|
-
return { api_key: process.env.FIFTYC_API_KEY || null, packs: ['core'] };
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function saveConfig(config) {
|
|
63
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const CONFIG = loadConfig();
|
|
67
|
-
const API_KEY = process.env.FIFTYC_API_KEY || CONFIG.api_key;
|
|
68
|
-
|
|
69
|
-
// ═══════════════════════════════════════════════════════════════
|
|
70
|
-
// CLI ROUTER
|
|
71
|
-
// ═══════════════════════════════════════════════════════════════
|
|
72
|
-
|
|
73
|
-
const args = process.argv.slice(2);
|
|
74
|
-
const command = args[0];
|
|
75
|
-
const subargs = args.slice(1);
|
|
76
|
-
|
|
77
|
-
// Version
|
|
78
|
-
if (command === '--version' || command === '-v') {
|
|
79
|
-
console.log(VERSION);
|
|
80
|
-
process.exit(0);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Help
|
|
84
|
-
if (command === '--help' || command === '-h' || command === 'help') {
|
|
85
|
-
showHelp();
|
|
86
|
-
process.exit(0);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Install to IDEs
|
|
90
|
-
if (command === 'install') {
|
|
91
|
-
installMCP();
|
|
92
|
-
process.exit(0);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Hub commands (no API key needed)
|
|
96
|
-
const HUB_COMMANDS = {
|
|
97
|
-
'status': cmdStatus,
|
|
98
|
-
'packs': cmdPacks,
|
|
99
|
-
'search': cmdSearch,
|
|
100
|
-
'add': cmdAdd,
|
|
101
|
-
'remove': cmdRemove,
|
|
102
|
-
'pin': cmdPin,
|
|
103
|
-
'update': cmdUpdate,
|
|
104
|
-
'balance': cmdBalance,
|
|
105
|
-
'snapshots': cmdSnapshots,
|
|
106
|
-
'restore': cmdRestore,
|
|
107
|
-
'tip': cmdTip,
|
|
108
|
-
'notip': cmdNoTip,
|
|
109
|
-
'mint': cmdMint,
|
|
110
|
-
'config': cmdConfig,
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
// Tool commands (need API key)
|
|
114
|
-
const TOOL_COMMANDS = {
|
|
115
|
-
'hints': { tool: 'hints', arg: 'query', cost: '$0.05' },
|
|
116
|
-
'hints+': { tool: 'hints_plus', arg: 'query', cost: '$0.10' },
|
|
117
|
-
'vibe': { tool: 'quick_vibe', arg: 'working_on', cost: '$0.05' },
|
|
118
|
-
'one-liner': { tool: 'one_liner', arg: 'product', cost: '$0.02' },
|
|
119
|
-
'roast': { tool: 'roast', arg: 'code', cost: '$0.05' },
|
|
120
|
-
'name-it': { tool: 'name_it', arg: 'does', cost: '$0.03' },
|
|
121
|
-
'price-it': { tool: 'price_it', arg: 'product', cost: '$0.05' },
|
|
122
|
-
'genius': { tool: 'genius', arg: 'problem', cost: '$0.50' },
|
|
123
|
-
'compute': { tool: 'compute', arg: 'code', cost: '$0.02' },
|
|
124
|
-
'chat': { tool: 'ide_conversation', special: 'chat' },
|
|
125
|
-
'refocus': { tool: 'llm_refocus', special: 'refocus' },
|
|
126
|
-
'invent': { tool: 'auto_invent', special: 'invent', cost: '$2.00' },
|
|
127
|
-
'invent-ui': { tool: 'auto_invent', special: 'invent-ui', cost: '$2.00' },
|
|
128
|
-
'tv': { tool: null, special: 'mcp-tv', cost: 'FREE' },
|
|
129
|
-
'adopt': { tool: 'adoption_calc', special: 'adopt', cost: 'FREE' },
|
|
130
|
-
'adopt-dx': { tool: 'adoption_diagnose', special: 'adopt-dx', cost: 'FREE' },
|
|
131
|
-
'adopt-sim': { tool: 'adoption_simulate', special: 'adopt-sim', cost: 'FREE' },
|
|
132
|
-
'team': { tool: null, special: 'team', cost: 'FREE' },
|
|
133
|
-
'team-create': { tool: null, special: 'team-create', cost: 'FREE' },
|
|
134
|
-
'team-mint': { tool: null, special: 'team-mint', cost: 'FREE' },
|
|
135
|
-
'team-recall': { tool: null, special: 'team-recall', cost: 'FREE' },
|
|
136
|
-
'team-analytics': { tool: null, special: 'team-analytics', cost: 'FREE' },
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
// Route command
|
|
140
|
-
if (command && HUB_COMMANDS[command]) {
|
|
141
|
-
HUB_COMMANDS[command](subargs).catch(err => {
|
|
142
|
-
console.error('Error:', err.message);
|
|
143
|
-
process.exit(1);
|
|
144
|
-
});
|
|
145
|
-
} else if (command && TOOL_COMMANDS[command]) {
|
|
146
|
-
if (!API_KEY) {
|
|
147
|
-
console.error('Error: API key required. Run: 50c config key <your_key>');
|
|
148
|
-
console.error('Get key at: https://50c.ai');
|
|
149
|
-
process.exit(1);
|
|
150
|
-
}
|
|
151
|
-
runToolCommand(command, subargs).catch(err => {
|
|
152
|
-
console.error('Error:', err.message);
|
|
153
|
-
process.exit(1);
|
|
154
|
-
});
|
|
155
|
-
} else if (command && command.includes('.')) {
|
|
156
|
-
// Pack.tool format: 50c beacon.compress "text"
|
|
157
|
-
runPackTool(command, subargs).catch(err => {
|
|
158
|
-
console.error('Error:', err.message);
|
|
159
|
-
process.exit(1);
|
|
160
|
-
});
|
|
161
|
-
} else if (!command || command === 'mcp') {
|
|
162
|
-
// MCP mode (stdin JSON-RPC)
|
|
163
|
-
startMCPMode();
|
|
164
|
-
} else {
|
|
165
|
-
console.error(`Unknown command: ${command}`);
|
|
166
|
-
console.error('Run: 50c help');
|
|
167
|
-
process.exit(1);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// ═══════════════════════════════════════════════════════════════
|
|
171
|
-
// HUB COMMANDS
|
|
172
|
-
// ═══════════════════════════════════════════════════════════════
|
|
173
|
-
|
|
174
|
-
async function cmdStatus() {
|
|
175
|
-
console.log('50c Hub v' + VERSION);
|
|
176
|
-
console.log('');
|
|
177
|
-
console.log('Config:', CONFIG_FILE);
|
|
178
|
-
console.log('API Key:', API_KEY ? API_KEY.slice(0, 6) + '...' : '(not set)');
|
|
179
|
-
console.log('');
|
|
180
|
-
|
|
181
|
-
// Check connectivity
|
|
182
|
-
try {
|
|
183
|
-
const health = await callAPI('/health', 'GET');
|
|
184
|
-
console.log('API Status: online');
|
|
185
|
-
} catch (e) {
|
|
186
|
-
console.log('API Status: offline (using cache)');
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Show enabled packs
|
|
190
|
-
console.log('');
|
|
191
|
-
console.log('Enabled Packs:');
|
|
192
|
-
const packs = CONFIG.packs || ['core'];
|
|
193
|
-
for (const p of packs) {
|
|
194
|
-
console.log(' - ' + p);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
async function cmdPacks() {
|
|
199
|
-
console.log('Enabled Packs:');
|
|
200
|
-
const packs = CONFIG.packs || ['core'];
|
|
201
|
-
for (const p of packs) {
|
|
202
|
-
console.log(' ' + p);
|
|
203
|
-
}
|
|
204
|
-
console.log('');
|
|
205
|
-
console.log('Run: 50c search <query> to find more');
|
|
206
|
-
console.log('Run: 50c add <pack> to enable');
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
async function cmdSearch(args) {
|
|
210
|
-
const query = args.join(' ');
|
|
211
|
-
if (!query) {
|
|
212
|
-
console.log('Available Packs:');
|
|
213
|
-
console.log('');
|
|
214
|
-
console.log(' core - hints, vibe, roast, name-it, price-it (FREE basics)');
|
|
215
|
-
console.log(' labs - genius, compute, mind-opener ($0.02-$0.65)');
|
|
216
|
-
console.log(' beacon - compress, extract, mint, checkpoint ($0.01-$0.02)');
|
|
217
|
-
console.log(' router - compare, battle (multi-model) ($0.05-$0.10)');
|
|
218
|
-
console.log('');
|
|
219
|
-
console.log('Run: 50c add <pack> to enable');
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Search API or show hardcoded for now
|
|
224
|
-
console.log(`Searching for "${query}"...`);
|
|
225
|
-
console.log('');
|
|
226
|
-
|
|
227
|
-
// TODO: Call registry.50c.ai when ready
|
|
228
|
-
const results = searchPacks(query);
|
|
229
|
-
if (results.length === 0) {
|
|
230
|
-
console.log('No packs found. Try: 50c search');
|
|
231
|
-
} else {
|
|
232
|
-
for (const r of results) {
|
|
233
|
-
console.log(` ${r.pack}.${r.tool} - ${r.desc} (${r.cost})`);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
function searchPacks(query) {
|
|
239
|
-
const q = query.toLowerCase();
|
|
240
|
-
const all = [
|
|
241
|
-
{ pack: 'core', tool: 'hints', desc: '5 brutal hints', cost: '$0.05' },
|
|
242
|
-
{ pack: 'core', tool: 'hints_plus', desc: '10 expanded hints', cost: '$0.10' },
|
|
243
|
-
{ pack: 'core', tool: 'vibe', desc: '3 unconventional ideas', cost: '$0.05' },
|
|
244
|
-
{ pack: 'core', tool: 'roast', desc: 'Brutal code review', cost: '$0.05' },
|
|
245
|
-
{ pack: 'core', tool: 'name_it', desc: '5 names + domain', cost: '$0.03' },
|
|
246
|
-
{ pack: 'core', tool: 'price_it', desc: 'SaaS pricing', cost: '$0.05' },
|
|
247
|
-
{ pack: 'core', tool: 'one_liner', desc: 'Elevator pitch', cost: '$0.02' },
|
|
248
|
-
{ pack: 'labs', tool: 'genius', desc: 'Deep problem solving', cost: '$0.50' },
|
|
249
|
-
{ pack: 'labs', tool: 'genius_plus', desc: 'Self-improving code', cost: '$0.65' },
|
|
250
|
-
{ pack: 'labs', tool: 'compute', desc: 'Python sandbox', cost: '$0.02' },
|
|
251
|
-
{ pack: 'labs', tool: 'mind_opener', desc: '5 curious angles', cost: '$0.08' },
|
|
252
|
-
{ pack: 'beacon', tool: 'health', desc: 'Context health', cost: 'FREE' },
|
|
253
|
-
{ pack: 'beacon', tool: 'compress', desc: 'Smart compression', cost: '$0.02' },
|
|
254
|
-
{ pack: 'beacon', tool: 'extract', desc: 'Extract decisions', cost: '$0.02' },
|
|
255
|
-
{ pack: 'beacon', tool: 'mint', desc: 'Permanent memory', cost: '$0.01' },
|
|
256
|
-
{ pack: 'beacon', tool: 'recall', desc: 'Read memories', cost: 'FREE' },
|
|
257
|
-
{ pack: 'beacon', tool: 'checkpoint', desc: 'Save state', cost: '$0.02' },
|
|
258
|
-
{ pack: 'router', tool: 'compare', desc: 'Multi-model compare', cost: '$0.05' },
|
|
259
|
-
{ pack: 'router', tool: 'battle', desc: 'Model battle', cost: '$0.10' },
|
|
260
|
-
{ pack: 'adoption', tool: 'adoption_calc', desc: 'P(adopt) calculator', cost: 'FREE' },
|
|
261
|
-
{ pack: 'adoption', tool: 'adoption_diagnose', desc: 'Bottleneck diagnosis', cost: 'FREE' },
|
|
262
|
-
{ pack: 'adoption', tool: 'adoption_simulate', desc: 'Time-series ODE sim', cost: 'FREE' },
|
|
263
|
-
];
|
|
264
|
-
|
|
265
|
-
return all.filter(t =>
|
|
266
|
-
t.pack.includes(q) ||
|
|
267
|
-
t.tool.includes(q) ||
|
|
268
|
-
t.desc.toLowerCase().includes(q)
|
|
269
|
-
);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
async function cmdAdd(args) {
|
|
273
|
-
const pack = args[0];
|
|
274
|
-
if (!pack) {
|
|
275
|
-
console.error('Usage: 50c add <pack>');
|
|
276
|
-
console.error('Run: 50c search to see available packs');
|
|
277
|
-
process.exit(1);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const valid = ['core', 'labs', 'beacon', 'router', 'adoption'];
|
|
281
|
-
if (!valid.includes(pack)) {
|
|
282
|
-
console.error(`Unknown pack: ${pack}`);
|
|
283
|
-
console.error('Available: ' + valid.join(', '));
|
|
284
|
-
process.exit(1);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
if (!CONFIG.packs) CONFIG.packs = ['core'];
|
|
288
|
-
if (CONFIG.packs.includes(pack)) {
|
|
289
|
-
console.log(`Pack "${pack}" already enabled`);
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
CONFIG.packs.push(pack);
|
|
294
|
-
saveConfig(CONFIG);
|
|
295
|
-
console.log(`Added pack: ${pack}`);
|
|
296
|
-
console.log('Enabled packs: ' + CONFIG.packs.join(', '));
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
async function cmdRemove(args) {
|
|
300
|
-
const pack = args[0];
|
|
301
|
-
if (!pack) {
|
|
302
|
-
console.error('Usage: 50c remove <pack>');
|
|
303
|
-
process.exit(1);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
if (pack === 'core') {
|
|
307
|
-
console.error('Cannot remove core pack');
|
|
308
|
-
process.exit(1);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
if (!CONFIG.packs || !CONFIG.packs.includes(pack)) {
|
|
312
|
-
console.log(`Pack "${pack}" not enabled`);
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
CONFIG.packs = CONFIG.packs.filter(p => p !== pack);
|
|
317
|
-
saveConfig(CONFIG);
|
|
318
|
-
console.log(`Removed pack: ${pack}`);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
async function cmdPin(args) {
|
|
322
|
-
const spec = args[0];
|
|
323
|
-
if (!spec || !spec.includes('@')) {
|
|
324
|
-
console.error('Usage: 50c pin <pack>@<version>');
|
|
325
|
-
console.error('Example: 50c pin beacon@2.0.0');
|
|
326
|
-
process.exit(1);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
const [pack, version] = spec.split('@');
|
|
330
|
-
|
|
331
|
-
let lockfile = {};
|
|
332
|
-
try {
|
|
333
|
-
if (fs.existsSync(LOCKFILE)) {
|
|
334
|
-
lockfile = JSON.parse(fs.readFileSync(LOCKFILE, 'utf8'));
|
|
335
|
-
}
|
|
336
|
-
} catch (e) {}
|
|
337
|
-
|
|
338
|
-
lockfile[pack] = version;
|
|
339
|
-
fs.writeFileSync(LOCKFILE, JSON.stringify(lockfile, null, 2));
|
|
340
|
-
console.log(`Pinned ${pack} to version ${version}`);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
async function cmdUpdate() {
|
|
344
|
-
console.log('Checking for updates...');
|
|
345
|
-
// TODO: Check registry for newer versions
|
|
346
|
-
console.log('All packs up to date');
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
async function cmdBalance() {
|
|
350
|
-
if (!API_KEY) {
|
|
351
|
-
console.log('Balance: (no API key)');
|
|
352
|
-
console.log('Run: 50c config key <your_key>');
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
try {
|
|
357
|
-
const result = await callMCPTool('check_balance', {});
|
|
358
|
-
console.log('Balance:', result);
|
|
359
|
-
} catch (e) {
|
|
360
|
-
console.error('Could not fetch balance:', e.message);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
async function cmdSnapshots() {
|
|
365
|
-
console.log('Recent Snapshots:');
|
|
366
|
-
console.log(' (snapshot system coming soon)');
|
|
367
|
-
// TODO: Query local + Turso for snapshots
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
async function cmdRestore(args) {
|
|
371
|
-
const id = args[0];
|
|
372
|
-
if (!id) {
|
|
373
|
-
console.error('Usage: 50c restore <snapshot_id>');
|
|
374
|
-
console.error('Run: 50c snapshots to list');
|
|
375
|
-
process.exit(1);
|
|
376
|
-
}
|
|
377
|
-
console.log(`Restoring snapshot ${id}...`);
|
|
378
|
-
// TODO: Implement restore
|
|
379
|
-
console.log('(restore coming soon)');
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
async function cmdTip(args) {
|
|
383
|
-
const amount = parseInt(args[0]) || null;
|
|
384
|
-
const reason = args.slice(1).join(' ') || null;
|
|
385
|
-
|
|
386
|
-
if (!API_KEY) {
|
|
387
|
-
console.error('Need API key to tip. Run: 50c config key <your_key>');
|
|
388
|
-
process.exit(1);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
try {
|
|
392
|
-
const result = await callMCPTool('beacon_tip', { amount, reason });
|
|
393
|
-
if (result.ask) {
|
|
394
|
-
console.log(result.ask);
|
|
395
|
-
console.log('Run: 50c tip <amount> [reason]');
|
|
396
|
-
} else if (result.thanks) {
|
|
397
|
-
console.log(result.thanks);
|
|
398
|
-
if (result.impact) console.log(result.impact);
|
|
399
|
-
console.log(`Balance: ${result.balance} | Tip #${result.tip_number}`);
|
|
400
|
-
if (result.tip_pool) {
|
|
401
|
-
console.log(`Refund pool: ${result.tip_pool.refund_available} credits`);
|
|
402
|
-
}
|
|
403
|
-
} else {
|
|
404
|
-
console.log(JSON.stringify(result, null, 2));
|
|
405
|
-
}
|
|
406
|
-
} catch (e) {
|
|
407
|
-
console.error('Tip failed:', e.message);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
async function cmdNoTip(args) {
|
|
412
|
-
const tool = args[0];
|
|
413
|
-
const reason = args[1];
|
|
414
|
-
const details = args.slice(2).join(' ') || null;
|
|
415
|
-
|
|
416
|
-
if (!tool) {
|
|
417
|
-
console.log('Usage: 50c notip <tool> <reason> [details]');
|
|
418
|
-
console.log('');
|
|
419
|
-
console.log('Reasons: wrong_answer, too_slow, confusing, not_helpful, crashed, other');
|
|
420
|
-
console.log('');
|
|
421
|
-
console.log('Example: 50c notip compress not_helpful "output was garbage"');
|
|
422
|
-
return;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
if (!API_KEY) {
|
|
426
|
-
console.error('Need API key. Run: 50c config key <your_key>');
|
|
427
|
-
process.exit(1);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
try {
|
|
431
|
-
const result = await callMCPTool('beacon_notip', { tool, reason, details });
|
|
432
|
-
console.log(result.acknowledged || 'Feedback received');
|
|
433
|
-
if (result.refund) {
|
|
434
|
-
console.log(`Refunded: ${result.refund.credits} credits`);
|
|
435
|
-
}
|
|
436
|
-
if (result.refund_denied) {
|
|
437
|
-
console.log('No refund:', result.refund_denied);
|
|
438
|
-
}
|
|
439
|
-
if (result.diagnosis) {
|
|
440
|
-
console.log('');
|
|
441
|
-
console.log('Diagnosis:', result.diagnosis.likely_cause);
|
|
442
|
-
console.log('Try:', result.diagnosis.try_tools?.map(t => t.tool).join(', '));
|
|
443
|
-
}
|
|
444
|
-
} catch (e) {
|
|
445
|
-
console.error('No-tip failed:', e.message);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
async function cmdMint(args) {
|
|
450
|
-
const content = args.join(' ');
|
|
451
|
-
if (!content) {
|
|
452
|
-
console.error('Usage: 50c mint <content>');
|
|
453
|
-
console.error('Example: 50c mint "API key rotated on 2026-01-29"');
|
|
454
|
-
process.exit(1);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
if (!API_KEY) {
|
|
458
|
-
console.error('Need API key. Run: 50c config key <your_key>');
|
|
459
|
-
process.exit(1);
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
try {
|
|
463
|
-
const result = await callMCPTool('beacon_remember', { content, category: 'mint' });
|
|
464
|
-
console.log('Minted:', content.slice(0, 50) + (content.length > 50 ? '...' : ''));
|
|
465
|
-
console.log('Total memories:', result.total);
|
|
466
|
-
} catch (e) {
|
|
467
|
-
console.error('Mint failed:', e.message);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
async function cmdConfig(args) {
|
|
472
|
-
const action = args[0];
|
|
473
|
-
const value = args.slice(1).join(' ');
|
|
474
|
-
|
|
475
|
-
if (!action) {
|
|
476
|
-
console.log('Current config:');
|
|
477
|
-
console.log(JSON.stringify(CONFIG, null, 2));
|
|
478
|
-
console.log('');
|
|
479
|
-
console.log('Commands:');
|
|
480
|
-
console.log(' 50c config key <api_key> Set API key');
|
|
481
|
-
console.log(' 50c config show Show config');
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
if (action === 'key') {
|
|
486
|
-
if (!value) {
|
|
487
|
-
console.log('API Key:', CONFIG.api_key || '(not set)');
|
|
488
|
-
return;
|
|
489
|
-
}
|
|
490
|
-
CONFIG.api_key = value;
|
|
491
|
-
saveConfig(CONFIG);
|
|
492
|
-
console.log('API key saved to ~/.50c/config.json');
|
|
493
|
-
} else if (action === 'show') {
|
|
494
|
-
console.log(JSON.stringify(CONFIG, null, 2));
|
|
495
|
-
} else {
|
|
496
|
-
console.error('Unknown config action:', action);
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
// ═══════════════════════════════════════════════════════════════
|
|
501
|
-
// TOOL COMMANDS
|
|
502
|
-
// ═══════════════════════════════════════════════════════════════
|
|
503
|
-
|
|
504
|
-
async function runToolCommand(cmd, args) {
|
|
505
|
-
const spec = TOOL_COMMANDS[cmd];
|
|
506
|
-
if (!spec) throw new Error('Unknown command: ' + cmd);
|
|
507
|
-
|
|
508
|
-
// Special handling for chat/refocus
|
|
509
|
-
if (spec.special === 'chat') {
|
|
510
|
-
if (args.length < 2) {
|
|
511
|
-
console.error('Usage: 50c chat <session_id> <message>');
|
|
512
|
-
process.exit(1);
|
|
513
|
-
}
|
|
514
|
-
const sessionId = args[0];
|
|
515
|
-
const message = args.slice(1).join(' ');
|
|
516
|
-
const result = await callMCPTool('ide_conversation', {
|
|
517
|
-
session_id: sessionId,
|
|
518
|
-
message,
|
|
519
|
-
mode: 'chat'
|
|
520
|
-
});
|
|
521
|
-
console.log(result.response || JSON.stringify(result, null, 2));
|
|
522
|
-
return;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
if (spec.special === 'refocus') {
|
|
526
|
-
if (args.length < 2) {
|
|
527
|
-
console.error('Usage: 50c refocus <situation> <goal>');
|
|
528
|
-
process.exit(1);
|
|
529
|
-
}
|
|
530
|
-
const situation = args[0];
|
|
531
|
-
const goal = args.slice(1).join(' ');
|
|
532
|
-
const result = await callMCPTool('llm_refocus', { situation, goal, tone: 'gentle' });
|
|
533
|
-
console.log(result.response || result.redirect || JSON.stringify(result, null, 2));
|
|
534
|
-
return;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
// INVENT-UI: Visual invention pipeline with browser UI
|
|
538
|
-
if (spec.special === 'invent-ui') {
|
|
539
|
-
let problem = '';
|
|
540
|
-
let rigor = 'deep';
|
|
541
|
-
let domain = 'code';
|
|
542
|
-
|
|
543
|
-
for (const arg of args) {
|
|
544
|
-
if (arg.startsWith('--rigor=')) rigor = arg.split('=')[1];
|
|
545
|
-
else if (arg.startsWith('--domain=')) domain = arg.split('=')[1];
|
|
546
|
-
else if (!arg.startsWith('--')) problem += (problem ? ' ' : '') + arg;
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
if (!problem) {
|
|
550
|
-
console.error('Usage: 50c invent-ui "problem" [--rigor=deep] [--domain=math]');
|
|
551
|
-
console.error('Opens a browser window with real-time swarm visualization.');
|
|
552
|
-
process.exit(1);
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
const { runInventWithUI } = require('../lib/invent-ui.js');
|
|
556
|
-
await runInventWithUI(problem, { domain, rigor });
|
|
557
|
-
return;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
// MCP-TV: Universal MCP Visualization Platform (FREE)
|
|
561
|
-
if (spec.special === 'mcp-tv') {
|
|
562
|
-
let port = 50888;
|
|
563
|
-
let noOpen = false;
|
|
564
|
-
|
|
565
|
-
for (const arg of args) {
|
|
566
|
-
if (arg.startsWith('--port=')) port = parseInt(arg.split('=')[1]);
|
|
567
|
-
if (arg === '--no-open') noOpen = true;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
const { createServer } = require('../lib/mcp-tv.js');
|
|
571
|
-
const { spawn } = require('child_process');
|
|
572
|
-
|
|
573
|
-
createServer(port);
|
|
574
|
-
|
|
575
|
-
if (!noOpen) {
|
|
576
|
-
setTimeout(() => {
|
|
577
|
-
const url = `http://localhost:${port}`;
|
|
578
|
-
const platform = process.platform;
|
|
579
|
-
if (platform === 'win32') {
|
|
580
|
-
spawn('cmd', ['/c', 'start', url], { detached: true, stdio: 'ignore' }).unref();
|
|
581
|
-
} else if (platform === 'darwin') {
|
|
582
|
-
spawn('open', [url], { detached: true, stdio: 'ignore' }).unref();
|
|
583
|
-
} else {
|
|
584
|
-
spawn('xdg-open', [url], { detached: true, stdio: 'ignore' }).unref();
|
|
585
|
-
}
|
|
586
|
-
}, 500);
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
// Keep process alive
|
|
590
|
-
return new Promise(() => {});
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
// INVENT: Enterprise invention pipeline
|
|
594
|
-
if (spec.special === 'invent') {
|
|
595
|
-
// Parse args: 50c invent "problem" --rigor=deep --domain=math --constraint="must be fast"
|
|
596
|
-
let problem = '';
|
|
597
|
-
let rigor = 'deep';
|
|
598
|
-
let domain = 'code';
|
|
599
|
-
const constraints = [];
|
|
600
|
-
|
|
601
|
-
for (const arg of args) {
|
|
602
|
-
if (arg.startsWith('--rigor=')) {
|
|
603
|
-
rigor = arg.split('=')[1];
|
|
604
|
-
} else if (arg.startsWith('--domain=')) {
|
|
605
|
-
domain = arg.split('=')[1];
|
|
606
|
-
} else if (arg.startsWith('--constraint=')) {
|
|
607
|
-
constraints.push(arg.split('=')[1].replace(/^["']|["']$/g, ''));
|
|
608
|
-
} else if (!arg.startsWith('--')) {
|
|
609
|
-
problem += (problem ? ' ' : '') + arg;
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
if (!problem) {
|
|
614
|
-
console.error('Usage: 50c invent "problem description" [options]');
|
|
615
|
-
console.error('Options:');
|
|
616
|
-
console.error(' --rigor=fast|standard|deep|exhaustive (default: deep)');
|
|
617
|
-
console.error(' --domain=math|physics|code|business (default: code)');
|
|
618
|
-
console.error(' --constraint="constraint text" (can repeat)');
|
|
619
|
-
console.error('');
|
|
620
|
-
console.error('Examples:');
|
|
621
|
-
console.error(' 50c invent "faster sorting algorithm" --rigor=deep');
|
|
622
|
-
console.error(' 50c invent "prove Riemann hypothesis" --domain=math --rigor=exhaustive');
|
|
623
|
-
console.error(' 50c invent "novel auth system" --constraint="must be passwordless"');
|
|
624
|
-
process.exit(1);
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
console.log(`\n🔬 50c Auto-Invent Pipeline`);
|
|
628
|
-
console.log(` Problem: ${problem.slice(0, 60)}${problem.length > 60 ? '...' : ''}`);
|
|
629
|
-
console.log(` Rigor: ${rigor} | Domain: ${domain}`);
|
|
630
|
-
if (constraints.length) console.log(` Constraints: ${constraints.length}`);
|
|
631
|
-
console.log(` Cost: $2.00\n`);
|
|
632
|
-
|
|
633
|
-
// Call auto_invent directly (not via remote API - it's local)
|
|
634
|
-
const inventArgs = { problem, rigor, domain, constraints };
|
|
635
|
-
const result = await autoInvent(inventArgs);
|
|
636
|
-
|
|
637
|
-
// Format output
|
|
638
|
-
if (result.ok && result.invention) {
|
|
639
|
-
console.log('═══════════════════════════════════════════════════════════════');
|
|
640
|
-
console.log(' INVENTION RESULT');
|
|
641
|
-
console.log('═══════════════════════════════════════════════════════════════\n');
|
|
642
|
-
|
|
643
|
-
if (result.angles && result.angles.length > 0) {
|
|
644
|
-
console.log('📐 CREATIVE ANGLES:');
|
|
645
|
-
result.angles.slice(0, 5).forEach((a, i) => console.log(` ${i+1}. ${a}`));
|
|
646
|
-
console.log('');
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
if (result.invention.solution) {
|
|
650
|
-
console.log('💡 SOLUTION:');
|
|
651
|
-
console.log(result.invention.solution);
|
|
652
|
-
console.log('');
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
if (result.proofs && result.proofs.length > 0) {
|
|
656
|
-
console.log('✓ PROOFS:', result.proofs.length, 'verification(s)');
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
if (result.prior_art && result.prior_art.length > 0) {
|
|
660
|
-
console.log('📚 PRIOR ART:', result.prior_art.length, 'related work(s) found');
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
console.log('\n═══════════════════════════════════════════════════════════════');
|
|
664
|
-
console.log(`⏱ Duration: ${(result.total_duration_ms / 1000).toFixed(1)}s | Verified: ${result.verified ? '✓' : '○'}`);
|
|
665
|
-
console.log('═══════════════════════════════════════════════════════════════\n');
|
|
666
|
-
} else {
|
|
667
|
-
console.log('Result:', JSON.stringify(result, null, 2));
|
|
668
|
-
}
|
|
669
|
-
return;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
// ADOPTION EQUATION TOOLS (FREE, local compute)
|
|
673
|
-
if (spec.special === 'adopt') {
|
|
674
|
-
// 50c adopt 2.0 0.3 0.8 [churn] [lambda]
|
|
675
|
-
const R = parseFloat(args[0]);
|
|
676
|
-
const N = parseFloat(args[1]);
|
|
677
|
-
const W = parseFloat(args[2]);
|
|
678
|
-
const churn = parseFloat(args[3]) || 0;
|
|
679
|
-
const lambda = parseFloat(args[4]) || 1.0;
|
|
680
|
-
|
|
681
|
-
if (isNaN(R) || isNaN(N) || isNaN(W)) {
|
|
682
|
-
console.error('Usage: 50c adopt <reward> <network> <window> [churn] [lambda]');
|
|
683
|
-
console.error('Example: 50c adopt 2.0 0.3 0.8');
|
|
684
|
-
process.exit(1);
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
const result = adoptionCalc({ reward: R, network: N, window: W, churn, lambda });
|
|
688
|
-
console.log('\n=== ADOPTION PROBABILITY ===');
|
|
689
|
-
console.log(`P(adopt) = ${(result.probability * 100).toFixed(2)}%`);
|
|
690
|
-
console.log(`Equation: ${result.equation}`);
|
|
691
|
-
console.log(`\nTerms:`);
|
|
692
|
-
console.log(` Reward: ${(result.reward_term * 100).toFixed(1)}%`);
|
|
693
|
-
console.log(` Network: ${(result.network_effect * 100).toFixed(1)}%`);
|
|
694
|
-
console.log(` Window: ${(result.upheaval_window * 100).toFixed(1)}%`);
|
|
695
|
-
console.log(`\nDiagnosis: ${result.diagnosis}`);
|
|
696
|
-
console.log(`Bottleneck: ${result.bottleneck} (${(result.bottleneck_value * 100).toFixed(1)}%)`);
|
|
697
|
-
if (result.threshold_R_for_50pct !== 'impossible') {
|
|
698
|
-
console.log(`R needed for 50%: ${result.threshold_R_for_50pct}`);
|
|
699
|
-
}
|
|
700
|
-
console.log(`Past bifurcation (viral threshold): ${result.past_bifurcation ? 'YES' : 'NO'}`);
|
|
701
|
-
return;
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
if (spec.special === 'adopt-dx') {
|
|
705
|
-
// 50c adopt-dx 2.0 0.3 0.8
|
|
706
|
-
const R = parseFloat(args[0]);
|
|
707
|
-
const N = parseFloat(args[1]);
|
|
708
|
-
const W = parseFloat(args[2]);
|
|
709
|
-
|
|
710
|
-
if (isNaN(R) || isNaN(N) || isNaN(W)) {
|
|
711
|
-
console.error('Usage: 50c adopt-dx <reward> <network> <window>');
|
|
712
|
-
process.exit(1);
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
const result = adoptionDiagnose({ reward: R, network: N, window: W });
|
|
716
|
-
console.log('\n=== ADOPTION DIAGNOSIS ===');
|
|
717
|
-
console.log(`P(adopt) = ${(result.probability * 100).toFixed(2)}%`);
|
|
718
|
-
console.log(`\nDiagnosis: ${result.diagnosis.toUpperCase()}`);
|
|
719
|
-
console.log(`Priority: ${result.prescription.priority}`);
|
|
720
|
-
console.log(`\nProblem: ${result.prescription.problem}`);
|
|
721
|
-
console.log(`Fix: ${result.prescription.fix}`);
|
|
722
|
-
if (result.kill_switches.length > 0) {
|
|
723
|
-
console.log('\n⚠️ KILL SWITCHES:');
|
|
724
|
-
result.kill_switches.forEach(k => console.log(` ${k}`));
|
|
725
|
-
}
|
|
726
|
-
console.log(`\nInsight: ${result.insight}`);
|
|
727
|
-
return;
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
if (spec.special === 'adopt-sim') {
|
|
731
|
-
// 50c adopt-sim 2.0 [steps]
|
|
732
|
-
const R = parseFloat(args[0]) || 2.0;
|
|
733
|
-
const steps = parseInt(args[1]) || 100;
|
|
734
|
-
|
|
735
|
-
const result = adoptionSimulate({ reward: R, steps });
|
|
736
|
-
console.log('\n=== ADOPTION SIMULATION ===');
|
|
737
|
-
console.log(`Initial: R=${R}, N0=0.1, W0=0.9, alpha=1.5, churn=0.05`);
|
|
738
|
-
console.log(`\nTrajectory:`);
|
|
739
|
-
result.series.forEach(p => {
|
|
740
|
-
const bar = '█'.repeat(Math.round(p.P * 40));
|
|
741
|
-
console.log(`t=${p.t.toFixed(1).padStart(4)}: ${(p.P * 100).toFixed(1).padStart(5)}% ${bar}`);
|
|
742
|
-
});
|
|
743
|
-
console.log(`\nFinal P: ${(result.summary.final_adoption * 100).toFixed(2)}%`);
|
|
744
|
-
console.log(`Peak P: ${(result.summary.peak_adoption * 100).toFixed(2)}% at t=${result.summary.peak_time}`);
|
|
745
|
-
console.log(`Tipped viral: ${result.summary.tipped_at !== 'never' ? 'YES at t=' + result.summary.tipped_at : 'NO'}`);
|
|
746
|
-
console.log(`Trajectory: ${result.summary.trajectory}`);
|
|
747
|
-
return;
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
// TEAM COMMANDS (FREE, uses API)
|
|
751
|
-
if (spec.special === 'team') {
|
|
752
|
-
const res = await fetch('https://api.50c.ai/v1/team/info', {
|
|
753
|
-
method: 'POST',
|
|
754
|
-
headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
|
|
755
|
-
body: '{}'
|
|
756
|
-
});
|
|
757
|
-
const data = await res.json();
|
|
758
|
-
if (data.error === 'Not in a team') {
|
|
759
|
-
console.log('\n=== NO TEAM ===');
|
|
760
|
-
console.log('You are not in a team yet.');
|
|
761
|
-
console.log('Create one with: 50c team-create "My Team"');
|
|
762
|
-
} else if (data.team) {
|
|
763
|
-
console.log('\n=== TEAM INFO ===');
|
|
764
|
-
console.log(`Name: ${data.team.name}`);
|
|
765
|
-
console.log(`Plan: ${data.team.plan}`);
|
|
766
|
-
console.log(`Members: ${data.members.length}/${data.team.max_members}`);
|
|
767
|
-
console.log(`Your role: ${data.your_role}`);
|
|
768
|
-
console.log('\nMembers:');
|
|
769
|
-
data.members.forEach(m => console.log(` ${m.email || m.customer_id} (${m.role})`));
|
|
770
|
-
} else {
|
|
771
|
-
console.log(JSON.stringify(data, null, 2));
|
|
772
|
-
}
|
|
773
|
-
return;
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
if (spec.special === 'team-create') {
|
|
777
|
-
const name = args.join(' ') || 'My Team';
|
|
778
|
-
const res = await fetch('https://api.50c.ai/v1/team/create', {
|
|
779
|
-
method: 'POST',
|
|
780
|
-
headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
|
|
781
|
-
body: JSON.stringify({ name })
|
|
782
|
-
});
|
|
783
|
-
const data = await res.json();
|
|
784
|
-
console.log('\n=== TEAM CREATED ===');
|
|
785
|
-
console.log(`ID: ${data.team_id}`);
|
|
786
|
-
console.log(`Name: ${data.name}`);
|
|
787
|
-
console.log(`Plan: ${data.plan}`);
|
|
788
|
-
return;
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
if (spec.special === 'team-mint') {
|
|
792
|
-
if (args.length < 2) {
|
|
793
|
-
console.error('Usage: 50c team-mint <key> <value> [scope]');
|
|
794
|
-
process.exit(1);
|
|
795
|
-
}
|
|
796
|
-
const key = args[0];
|
|
797
|
-
const value = args.slice(1, -1).join(' ') || args[1];
|
|
798
|
-
const scope = args.length > 2 ? args[args.length - 1] : 'general';
|
|
799
|
-
const res = await fetch('https://api.50c.ai/v1/team/mint', {
|
|
800
|
-
method: 'POST',
|
|
801
|
-
headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
|
|
802
|
-
body: JSON.stringify({ key, value, scope })
|
|
803
|
-
});
|
|
804
|
-
const data = await res.json();
|
|
805
|
-
console.log('\n=== MEMORY SHARED ===');
|
|
806
|
-
console.log(`ID: ${data.id}`);
|
|
807
|
-
console.log(`Team: ${data.team_id}`);
|
|
808
|
-
console.log(`Shared: ${data.shared}`);
|
|
809
|
-
return;
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
if (spec.special === 'team-recall') {
|
|
813
|
-
const query = args.join(' ') || null;
|
|
814
|
-
const res = await fetch('https://api.50c.ai/v1/team/recall', {
|
|
815
|
-
method: 'POST',
|
|
816
|
-
headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
|
|
817
|
-
body: JSON.stringify({ query, limit: 20 })
|
|
818
|
-
});
|
|
819
|
-
const data = await res.json();
|
|
820
|
-
console.log('\n=== TEAM MEMORIES ===');
|
|
821
|
-
console.log(`Team: ${data.team_id}`);
|
|
822
|
-
console.log(`Found: ${data.count} memories\n`);
|
|
823
|
-
data.memories.forEach(m => {
|
|
824
|
-
console.log(`[${m.scope}] ${m.key}`);
|
|
825
|
-
console.log(` ${m.value}`);
|
|
826
|
-
console.log('');
|
|
827
|
-
});
|
|
828
|
-
return;
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
if (spec.special === 'team-analytics') {
|
|
832
|
-
const res = await fetch('https://api.50c.ai/v1/team/analytics', {
|
|
833
|
-
method: 'POST',
|
|
834
|
-
headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
|
|
835
|
-
body: '{}'
|
|
836
|
-
});
|
|
837
|
-
const data = await res.json();
|
|
838
|
-
if (data.error) {
|
|
839
|
-
console.log(data.error);
|
|
840
|
-
return;
|
|
841
|
-
}
|
|
842
|
-
const t = data.totals;
|
|
843
|
-
console.log('\n=== TEAM ROI ANALYTICS ===');
|
|
844
|
-
console.log(`Team: ${data.team_id}\n`);
|
|
845
|
-
console.log(`Bugs Caught: ${t.bugs_caught}`);
|
|
846
|
-
console.log(`Hours Saved: ${t.hours_saved.toFixed(1)}`);
|
|
847
|
-
console.log(`Tool Calls: ${t.tool_calls}`);
|
|
848
|
-
console.log(`Spend: $${t.spend_dollars.toFixed(2)}`);
|
|
849
|
-
console.log(`Value Generated: $${t.roi_dollars.toFixed(2)}`);
|
|
850
|
-
console.log(`ROI Multiple: ${t.roi_multiple.toFixed(1)}x`);
|
|
851
|
-
return;
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
// Standard tool
|
|
855
|
-
const input = args.join(' ');
|
|
856
|
-
if (!input) {
|
|
857
|
-
console.error(`Usage: 50c ${cmd} <input>`);
|
|
858
|
-
process.exit(1);
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
const result = await callMCPTool(spec.tool, { [spec.arg]: input });
|
|
862
|
-
|
|
863
|
-
// Format output nicely
|
|
864
|
-
if (typeof result === 'string') {
|
|
865
|
-
console.log(result);
|
|
866
|
-
} else if (result.hints) {
|
|
867
|
-
result.hints.forEach((h, i) => console.log(`${i+1}. ${h}`));
|
|
868
|
-
} else if (result.ideas) {
|
|
869
|
-
result.ideas.forEach((h, i) => console.log(`${i+1}. ${h}`));
|
|
870
|
-
} else if (result.pitch) {
|
|
871
|
-
console.log(result.pitch);
|
|
872
|
-
} else if (result.flaws) {
|
|
873
|
-
result.flaws.forEach((f, i) => {
|
|
874
|
-
console.log(`\n[${i+1}] ${f.flaw}`);
|
|
875
|
-
console.log(` Fix: ${f.fix}`);
|
|
876
|
-
});
|
|
877
|
-
} else if (result.names) {
|
|
878
|
-
result.names.forEach(n => {
|
|
879
|
-
const avail = n.available ? '✓' : '✗';
|
|
880
|
-
console.log(` ${avail} ${n.name} - ${n.domain}`);
|
|
881
|
-
});
|
|
882
|
-
} else if (result.strategy) {
|
|
883
|
-
console.log(result.strategy);
|
|
884
|
-
} else {
|
|
885
|
-
console.log(JSON.stringify(result, null, 2));
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
async function runPackTool(packTool, args) {
|
|
890
|
-
const [pack, tool] = packTool.split('.');
|
|
891
|
-
if (!pack || !tool) {
|
|
892
|
-
console.error('Usage: 50c <pack>.<tool> <input>');
|
|
893
|
-
console.error('Example: 50c beacon.compress "long text here"');
|
|
894
|
-
process.exit(1);
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
// Check pack is enabled
|
|
898
|
-
if (!CONFIG.packs?.includes(pack) && pack !== 'core') {
|
|
899
|
-
console.error(`Pack "${pack}" not enabled. Run: 50c add ${pack}`);
|
|
900
|
-
process.exit(1);
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
if (!API_KEY) {
|
|
904
|
-
console.error('Need API key. Run: 50c config key <your_key>');
|
|
905
|
-
process.exit(1);
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
const input = args.join(' ');
|
|
909
|
-
|
|
910
|
-
// Map pack.tool to MCP tool name
|
|
911
|
-
const toolName = `${pack}_${tool}`;
|
|
912
|
-
|
|
913
|
-
// Build args object based on tool
|
|
914
|
-
let toolArgs = {};
|
|
915
|
-
if (tool === 'compress' || tool === 'extract' || tool === 'summarize') {
|
|
916
|
-
toolArgs = { messages: [input] };
|
|
917
|
-
} else if (tool === 'health') {
|
|
918
|
-
toolArgs = { messages: input ? [input] : [] };
|
|
919
|
-
} else if (tool === 'remember' || tool === 'mint') {
|
|
920
|
-
toolArgs = { content: input };
|
|
921
|
-
} else if (tool === 'recall') {
|
|
922
|
-
toolArgs = { query: input || null };
|
|
923
|
-
} else if (tool === 'drift') {
|
|
924
|
-
toolArgs = { messages: [input], goal: args[0] || 'stay on topic' };
|
|
925
|
-
} else if (tool === 'checkpoint') {
|
|
926
|
-
toolArgs = { name: args[0] || 'default', messages: args.slice(1) };
|
|
927
|
-
} else if (tool === 'restore') {
|
|
928
|
-
toolArgs = { name: input || 'default' };
|
|
929
|
-
} else {
|
|
930
|
-
toolArgs = { input };
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
const result = await callMCPTool(toolName, toolArgs);
|
|
934
|
-
console.log(JSON.stringify(result, null, 2));
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
// ═══════════════════════════════════════════════════════════════
|
|
938
|
-
// MCP MODE
|
|
939
|
-
// ═══════════════════════════════════════════════════════════════
|
|
940
|
-
|
|
941
|
-
function startMCPMode() {
|
|
942
|
-
const rl = readline.createInterface({
|
|
943
|
-
input: process.stdin,
|
|
944
|
-
output: process.stdout,
|
|
945
|
-
terminal: false
|
|
946
|
-
});
|
|
947
|
-
|
|
948
|
-
rl.on('line', async (line) => {
|
|
949
|
-
try {
|
|
950
|
-
const clean = line.trim();
|
|
951
|
-
if (!clean) return;
|
|
952
|
-
const request = JSON.parse(clean);
|
|
953
|
-
|
|
954
|
-
// Notifications (no id) don't get responses per JSON-RPC spec
|
|
955
|
-
if (request.method && request.method.startsWith('notifications/')) {
|
|
956
|
-
return;
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
// Handle initialize locally
|
|
960
|
-
if (request.method === 'initialize') {
|
|
961
|
-
process.stdout.write(JSON.stringify({
|
|
962
|
-
jsonrpc: '2.0',
|
|
963
|
-
id: request.id,
|
|
964
|
-
result: {
|
|
965
|
-
protocolVersion: '2024-11-05',
|
|
966
|
-
serverInfo: { name: '50c', version: VERSION },
|
|
967
|
-
capabilities: { tools: {} }
|
|
968
|
-
}
|
|
969
|
-
}) + '\n');
|
|
970
|
-
return;
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
const response = await handleMCPRequest(request);
|
|
974
|
-
if (response) {
|
|
975
|
-
process.stdout.write(JSON.stringify(response) + '\n');
|
|
976
|
-
}
|
|
977
|
-
} catch (e) {
|
|
978
|
-
process.stdout.write(JSON.stringify({
|
|
979
|
-
jsonrpc: '2.0',
|
|
980
|
-
id: null,
|
|
981
|
-
error: { code: -32603, message: e.message }
|
|
982
|
-
}) + '\n');
|
|
983
|
-
}
|
|
984
|
-
});
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
async function handleMCPRequest(request) {
|
|
988
|
-
// Handle local file-memory tools first (FREE, no API call)
|
|
989
|
-
const localResult = await handleLocalTools(request);
|
|
990
|
-
if (localResult) return localResult;
|
|
991
|
-
|
|
992
|
-
// Forward to remote MCP endpoint
|
|
993
|
-
return callRemoteMCP(request);
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
// Local file-memory tools (FREE, runs on user machine)
|
|
997
|
-
const { FILE_TOOLS, indexFile, findSymbol, getLines, searchFile, fileSummary } = require('../lib/file-memory.js');
|
|
998
|
-
// Note: subagent, team already imported at top for CLI commands
|
|
999
|
-
|
|
1000
|
-
const LOCAL_TOOLS = [
|
|
1001
|
-
// THE MAIN TOOL - Ask the 50c team to do anything
|
|
1002
|
-
{ name: "team", description: "Ask the 50c team to do anything. Natural language → auto-picks the right tools. Example: 'roast my code and suggest fixes'", inputSchema: { type: "object", properties: { task: { type: "string", description: "What you want done in plain English" }, context: { type: "string", description: "Code, text, or data to work with (optional)" }, dryRun: { type: "boolean", description: "Preview plan without executing" } }, required: ["task"] } },
|
|
1003
|
-
|
|
1004
|
-
// File memory tools
|
|
1005
|
-
{ name: "fm_index", description: "Index a large file for fast symbol/line lookup. Auto-detects Python/JS/TS. FREE.", inputSchema: { type: "object", properties: { filepath: { type: "string", description: "Absolute or relative path to file" } }, required: ["filepath"] } },
|
|
1006
|
-
{ name: "fm_find", description: "Find where a function/class is defined across all indexed files. FREE.", inputSchema: { type: "object", properties: { name: { type: "string", description: "Symbol name (function, class, variable)" }, filepath: { type: "string", description: "Optional: limit search to one file" } }, required: ["name"] } },
|
|
1007
|
-
{ name: "fm_lines", description: "Get specific line range from a file with line numbers. FREE.", inputSchema: { type: "object", properties: { filepath: { type: "string" }, start: { type: "number", description: "Start line number" }, end: { type: "number", description: "End line number" } }, required: ["filepath", "start", "end"] } },
|
|
1008
|
-
{ name: "fm_search", description: "Search for symbols and content in a file. Auto-indexes if needed. FREE.", inputSchema: { type: "object", properties: { filepath: { type: "string" }, query: { type: "string", description: "Search term" } }, required: ["filepath", "query"] } },
|
|
1009
|
-
{ name: "fm_summary", description: "Get summary of a file: line count, all functions, classes. FREE.", inputSchema: { type: "object", properties: { filepath: { type: "string" } }, required: ["filepath"] } },
|
|
1010
|
-
{ name: "fm_list", description: "List all indexed files with stats. FREE.", inputSchema: { type: "object", properties: {} } },
|
|
1011
|
-
{ name: "fm_context", description: "Get context around a symbol (function body, class methods). FREE.", inputSchema: { type: "object", properties: { filepath: { type: "string" }, symbol: { type: "string", description: "Function or class name" }, lines_after: { type: "number", description: "Lines to include after definition (default 50)" } }, required: ["filepath", "symbol"] } },
|
|
1012
|
-
|
|
1013
|
-
// 50c Team utilities - for power users who want granular control
|
|
1014
|
-
{ name: "team_http", description: "50c Team: HTTP/HTTPS fetch. Bypasses IDE restrictions. FREE.", inputSchema: { type: "object", properties: { url: { type: "string", description: "Full URL to fetch" }, method: { type: "string", description: "HTTP method (default GET)" }, headers: { type: "object", description: "Request headers" }, body: { type: "string", description: "Request body for POST/PUT" }, timeout: { type: "number", description: "Timeout in ms (default 30000)" } }, required: ["url"] } },
|
|
1015
|
-
{ name: "team_ssh", description: "50c Team: SSH remote command. Configure servers in ~/.50c/servers.json. FREE.", inputSchema: { type: "object", properties: { server: { type: "string", description: "Server alias (nj/zurich/chicago) or {host,user,port}" }, command: { type: "string", description: "Command to execute on remote server" }, timeout: { type: "number", description: "Timeout in ms (default 30000)" } }, required: ["server", "command"] } },
|
|
1016
|
-
{ name: "team_exec", description: "50c Team: Local command execution. Bypasses shell restrictions. FREE.", inputSchema: { type: "object", properties: { command: { type: "string", description: "Command to execute locally" }, cwd: { type: "string", description: "Working directory" }, timeout: { type: "number", description: "Timeout in ms (default 30000)" } }, required: ["command"] } },
|
|
1017
|
-
{ name: "team_multi", description: "50c Team: Execute multiple tasks in parallel. FREE.", inputSchema: { type: "object", properties: { tasks: { type: "array", description: "Array of task objects [{type, ...params}]", items: { type: "object" } } }, required: ["tasks"] } },
|
|
1018
|
-
{ name: "team_servers", description: "50c Team: List known SSH servers. FREE.", inputSchema: { type: "object", properties: {} } },
|
|
1019
|
-
{ name: "team_ask", description: "50c Team: Ask the team to run any 50c tool. Uses your API key.", inputSchema: { type: "object", properties: { tool: { type: "string", description: "50c tool name (e.g., hints, roast, genius, bcalc)" }, args: { type: "object", description: "Tool arguments" } }, required: ["tool"] } },
|
|
1020
|
-
{ name: "team_chain", description: "50c Team: Chain multiple tools together. Output flows via $prev placeholder.", inputSchema: { type: "object", properties: { steps: { type: "array", description: "Array of {tool, args} - use $prev for previous result", items: { type: "object" } }, input: { type: "string", description: "Initial input (optional)" } }, required: ["steps"] } },
|
|
1021
|
-
{ name: "
|
|
1022
|
-
|
|
1023
|
-
// Security audit tool - runs locally, FREE
|
|
1024
|
-
{ name: "
|
|
1025
|
-
|
|
1026
|
-
//
|
|
1027
|
-
{ name: "
|
|
1028
|
-
|
|
1029
|
-
//
|
|
1030
|
-
{ name: "
|
|
1031
|
-
|
|
1032
|
-
//
|
|
1033
|
-
{ name: "
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
]
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
*
|
|
1043
|
-
*
|
|
1044
|
-
*
|
|
1045
|
-
*
|
|
1046
|
-
*
|
|
1047
|
-
* -
|
|
1048
|
-
*
|
|
1049
|
-
*
|
|
1050
|
-
* -
|
|
1051
|
-
*
|
|
1052
|
-
* Phase
|
|
1053
|
-
* -
|
|
1054
|
-
*
|
|
1055
|
-
*
|
|
1056
|
-
*
|
|
1057
|
-
*
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
*
|
|
1065
|
-
*
|
|
1066
|
-
*
|
|
1067
|
-
*
|
|
1068
|
-
* -
|
|
1069
|
-
* -
|
|
1070
|
-
*
|
|
1071
|
-
*
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
results.
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
results.
|
|
1172
|
-
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
const
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
//
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
call50cTool('
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
results.
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
}
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
return {
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
// ═══════════════════════════════════════════════════════════════
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
const
|
|
1513
|
-
const
|
|
1514
|
-
|
|
1515
|
-
const
|
|
1516
|
-
const
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
const
|
|
1520
|
-
const
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
const
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
}
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
const
|
|
1597
|
-
const
|
|
1598
|
-
const
|
|
1599
|
-
const
|
|
1600
|
-
const
|
|
1601
|
-
const
|
|
1602
|
-
const
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
const
|
|
1606
|
-
|
|
1607
|
-
let
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
const
|
|
1615
|
-
const
|
|
1616
|
-
const
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
if (
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
else trajectory = '
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
if (name === '
|
|
1728
|
-
return mcpResult(id,
|
|
1729
|
-
}
|
|
1730
|
-
if (name === '
|
|
1731
|
-
return mcpResult(id,
|
|
1732
|
-
}
|
|
1733
|
-
if (name === '
|
|
1734
|
-
return mcpResult(id,
|
|
1735
|
-
}
|
|
1736
|
-
if (name === '
|
|
1737
|
-
return mcpResult(id,
|
|
1738
|
-
}
|
|
1739
|
-
if (name === '
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
const
|
|
1744
|
-
const
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
const
|
|
1758
|
-
return mcpResult(id, {
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
const
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
}
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
}
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
const
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
}
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
}
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
}
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
}
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 50c - AI developer tools via MCP
|
|
4
|
+
* Pay-per-use from $0.01. No subscriptions.
|
|
5
|
+
* https://50c.ai
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const https = require('https');
|
|
9
|
+
const http = require('http');
|
|
10
|
+
const readline = require('readline');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const os = require('os');
|
|
14
|
+
const { spawn } = require('child_process');
|
|
15
|
+
|
|
16
|
+
// Early imports for CLI commands that need these
|
|
17
|
+
let call50cTool, subagent, httpFetch, sshExec, localExec, KNOWN_SERVERS;
|
|
18
|
+
let team, matchTaskToTools;
|
|
19
|
+
try {
|
|
20
|
+
const subagentModule = require('../lib/subagent.js');
|
|
21
|
+
call50cTool = subagentModule.call50cTool;
|
|
22
|
+
subagent = subagentModule.subagent;
|
|
23
|
+
httpFetch = subagentModule.httpFetch;
|
|
24
|
+
sshExec = subagentModule.sshExec;
|
|
25
|
+
localExec = subagentModule.localExec;
|
|
26
|
+
KNOWN_SERVERS = subagentModule.KNOWN_SERVERS;
|
|
27
|
+
|
|
28
|
+
const teamModule = require('../lib/team.js');
|
|
29
|
+
team = teamModule.team;
|
|
30
|
+
matchTaskToTools = teamModule.matchTaskToTools;
|
|
31
|
+
} catch (e) {
|
|
32
|
+
// Graceful fallback if libs not available (shouldn't happen in normal install)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const VERSION = require('../package.json').version;
|
|
36
|
+
const HOME = os.homedir();
|
|
37
|
+
const HUB_DIR = path.join(HOME, '.50c');
|
|
38
|
+
const CONFIG_FILE = path.join(HUB_DIR, 'config.json');
|
|
39
|
+
const LOCKFILE = path.join(HUB_DIR, 'lockfile.json');
|
|
40
|
+
const CACHE_DIR = path.join(HUB_DIR, 'cache');
|
|
41
|
+
|
|
42
|
+
const API_ENDPOINT = process.env.FIFTYC_ENDPOINT || 'https://api.50c.ai';
|
|
43
|
+
const MCP_ENDPOINT = API_ENDPOINT + '/mcp';
|
|
44
|
+
const BEACON_ENDPOINT = process.env.FIFTYC_BEACON || 'https://beacon.50c.ai/mcp';
|
|
45
|
+
const BEACON_TOOLS = ['tip', 'notip', 'health', 'compress', 'extract', 'mint', 'recall', 'remember', 'checkpoint', 'restore', 'drift', 'summarize', 'diff', 'scan', 'rank', 'focus'];
|
|
46
|
+
|
|
47
|
+
// Ensure hub directory exists
|
|
48
|
+
if (!fs.existsSync(HUB_DIR)) {
|
|
49
|
+
fs.mkdirSync(HUB_DIR, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Load config
|
|
53
|
+
function loadConfig() {
|
|
54
|
+
try {
|
|
55
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
56
|
+
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
57
|
+
}
|
|
58
|
+
} catch (e) {}
|
|
59
|
+
return { api_key: process.env.FIFTYC_API_KEY || null, packs: ['core'] };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function saveConfig(config) {
|
|
63
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const CONFIG = loadConfig();
|
|
67
|
+
const API_KEY = process.env.FIFTYC_API_KEY || CONFIG.api_key;
|
|
68
|
+
|
|
69
|
+
// ═══════════════════════════════════════════════════════════════
|
|
70
|
+
// CLI ROUTER
|
|
71
|
+
// ═══════════════════════════════════════════════════════════════
|
|
72
|
+
|
|
73
|
+
const args = process.argv.slice(2);
|
|
74
|
+
const command = args[0];
|
|
75
|
+
const subargs = args.slice(1);
|
|
76
|
+
|
|
77
|
+
// Version
|
|
78
|
+
if (command === '--version' || command === '-v') {
|
|
79
|
+
console.log(VERSION);
|
|
80
|
+
process.exit(0);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Help
|
|
84
|
+
if (command === '--help' || command === '-h' || command === 'help') {
|
|
85
|
+
showHelp();
|
|
86
|
+
process.exit(0);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Install to IDEs
|
|
90
|
+
if (command === 'install') {
|
|
91
|
+
installMCP();
|
|
92
|
+
process.exit(0);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Hub commands (no API key needed)
|
|
96
|
+
const HUB_COMMANDS = {
|
|
97
|
+
'status': cmdStatus,
|
|
98
|
+
'packs': cmdPacks,
|
|
99
|
+
'search': cmdSearch,
|
|
100
|
+
'add': cmdAdd,
|
|
101
|
+
'remove': cmdRemove,
|
|
102
|
+
'pin': cmdPin,
|
|
103
|
+
'update': cmdUpdate,
|
|
104
|
+
'balance': cmdBalance,
|
|
105
|
+
'snapshots': cmdSnapshots,
|
|
106
|
+
'restore': cmdRestore,
|
|
107
|
+
'tip': cmdTip,
|
|
108
|
+
'notip': cmdNoTip,
|
|
109
|
+
'mint': cmdMint,
|
|
110
|
+
'config': cmdConfig,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// Tool commands (need API key)
|
|
114
|
+
const TOOL_COMMANDS = {
|
|
115
|
+
'hints': { tool: 'hints', arg: 'query', cost: '$0.05' },
|
|
116
|
+
'hints+': { tool: 'hints_plus', arg: 'query', cost: '$0.10' },
|
|
117
|
+
'vibe': { tool: 'quick_vibe', arg: 'working_on', cost: '$0.05' },
|
|
118
|
+
'one-liner': { tool: 'one_liner', arg: 'product', cost: '$0.02' },
|
|
119
|
+
'roast': { tool: 'roast', arg: 'code', cost: '$0.05' },
|
|
120
|
+
'name-it': { tool: 'name_it', arg: 'does', cost: '$0.03' },
|
|
121
|
+
'price-it': { tool: 'price_it', arg: 'product', cost: '$0.05' },
|
|
122
|
+
'genius': { tool: 'genius', arg: 'problem', cost: '$0.50' },
|
|
123
|
+
'compute': { tool: 'compute', arg: 'code', cost: '$0.02' },
|
|
124
|
+
'chat': { tool: 'ide_conversation', special: 'chat' },
|
|
125
|
+
'refocus': { tool: 'llm_refocus', special: 'refocus' },
|
|
126
|
+
'invent': { tool: 'auto_invent', special: 'invent', cost: '$2.00' },
|
|
127
|
+
'invent-ui': { tool: 'auto_invent', special: 'invent-ui', cost: '$2.00' },
|
|
128
|
+
'tv': { tool: null, special: 'mcp-tv', cost: 'FREE' },
|
|
129
|
+
'adopt': { tool: 'adoption_calc', special: 'adopt', cost: 'FREE' },
|
|
130
|
+
'adopt-dx': { tool: 'adoption_diagnose', special: 'adopt-dx', cost: 'FREE' },
|
|
131
|
+
'adopt-sim': { tool: 'adoption_simulate', special: 'adopt-sim', cost: 'FREE' },
|
|
132
|
+
'team': { tool: null, special: 'team', cost: 'FREE' },
|
|
133
|
+
'team-create': { tool: null, special: 'team-create', cost: 'FREE' },
|
|
134
|
+
'team-mint': { tool: null, special: 'team-mint', cost: 'FREE' },
|
|
135
|
+
'team-recall': { tool: null, special: 'team-recall', cost: 'FREE' },
|
|
136
|
+
'team-analytics': { tool: null, special: 'team-analytics', cost: 'FREE' },
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Route command
|
|
140
|
+
if (command && HUB_COMMANDS[command]) {
|
|
141
|
+
HUB_COMMANDS[command](subargs).catch(err => {
|
|
142
|
+
console.error('Error:', err.message);
|
|
143
|
+
process.exit(1);
|
|
144
|
+
});
|
|
145
|
+
} else if (command && TOOL_COMMANDS[command]) {
|
|
146
|
+
if (!API_KEY) {
|
|
147
|
+
console.error('Error: API key required. Run: 50c config key <your_key>');
|
|
148
|
+
console.error('Get key at: https://50c.ai');
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
runToolCommand(command, subargs).catch(err => {
|
|
152
|
+
console.error('Error:', err.message);
|
|
153
|
+
process.exit(1);
|
|
154
|
+
});
|
|
155
|
+
} else if (command && command.includes('.')) {
|
|
156
|
+
// Pack.tool format: 50c beacon.compress "text"
|
|
157
|
+
runPackTool(command, subargs).catch(err => {
|
|
158
|
+
console.error('Error:', err.message);
|
|
159
|
+
process.exit(1);
|
|
160
|
+
});
|
|
161
|
+
} else if (!command || command === 'mcp') {
|
|
162
|
+
// MCP mode (stdin JSON-RPC)
|
|
163
|
+
startMCPMode();
|
|
164
|
+
} else {
|
|
165
|
+
console.error(`Unknown command: ${command}`);
|
|
166
|
+
console.error('Run: 50c help');
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ═══════════════════════════════════════════════════════════════
|
|
171
|
+
// HUB COMMANDS
|
|
172
|
+
// ═══════════════════════════════════════════════════════════════
|
|
173
|
+
|
|
174
|
+
async function cmdStatus() {
|
|
175
|
+
console.log('50c Hub v' + VERSION);
|
|
176
|
+
console.log('');
|
|
177
|
+
console.log('Config:', CONFIG_FILE);
|
|
178
|
+
console.log('API Key:', API_KEY ? API_KEY.slice(0, 6) + '...' : '(not set)');
|
|
179
|
+
console.log('');
|
|
180
|
+
|
|
181
|
+
// Check connectivity
|
|
182
|
+
try {
|
|
183
|
+
const health = await callAPI('/health', 'GET');
|
|
184
|
+
console.log('API Status: online');
|
|
185
|
+
} catch (e) {
|
|
186
|
+
console.log('API Status: offline (using cache)');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Show enabled packs
|
|
190
|
+
console.log('');
|
|
191
|
+
console.log('Enabled Packs:');
|
|
192
|
+
const packs = CONFIG.packs || ['core'];
|
|
193
|
+
for (const p of packs) {
|
|
194
|
+
console.log(' - ' + p);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function cmdPacks() {
|
|
199
|
+
console.log('Enabled Packs:');
|
|
200
|
+
const packs = CONFIG.packs || ['core'];
|
|
201
|
+
for (const p of packs) {
|
|
202
|
+
console.log(' ' + p);
|
|
203
|
+
}
|
|
204
|
+
console.log('');
|
|
205
|
+
console.log('Run: 50c search <query> to find more');
|
|
206
|
+
console.log('Run: 50c add <pack> to enable');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async function cmdSearch(args) {
|
|
210
|
+
const query = args.join(' ');
|
|
211
|
+
if (!query) {
|
|
212
|
+
console.log('Available Packs:');
|
|
213
|
+
console.log('');
|
|
214
|
+
console.log(' core - hints, vibe, roast, name-it, price-it (FREE basics)');
|
|
215
|
+
console.log(' labs - genius, compute, mind-opener ($0.02-$0.65)');
|
|
216
|
+
console.log(' beacon - compress, extract, mint, checkpoint ($0.01-$0.02)');
|
|
217
|
+
console.log(' router - compare, battle (multi-model) ($0.05-$0.10)');
|
|
218
|
+
console.log('');
|
|
219
|
+
console.log('Run: 50c add <pack> to enable');
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Search API or show hardcoded for now
|
|
224
|
+
console.log(`Searching for "${query}"...`);
|
|
225
|
+
console.log('');
|
|
226
|
+
|
|
227
|
+
// TODO: Call registry.50c.ai when ready
|
|
228
|
+
const results = searchPacks(query);
|
|
229
|
+
if (results.length === 0) {
|
|
230
|
+
console.log('No packs found. Try: 50c search');
|
|
231
|
+
} else {
|
|
232
|
+
for (const r of results) {
|
|
233
|
+
console.log(` ${r.pack}.${r.tool} - ${r.desc} (${r.cost})`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function searchPacks(query) {
|
|
239
|
+
const q = query.toLowerCase();
|
|
240
|
+
const all = [
|
|
241
|
+
{ pack: 'core', tool: 'hints', desc: '5 brutal hints', cost: '$0.05' },
|
|
242
|
+
{ pack: 'core', tool: 'hints_plus', desc: '10 expanded hints', cost: '$0.10' },
|
|
243
|
+
{ pack: 'core', tool: 'vibe', desc: '3 unconventional ideas', cost: '$0.05' },
|
|
244
|
+
{ pack: 'core', tool: 'roast', desc: 'Brutal code review', cost: '$0.05' },
|
|
245
|
+
{ pack: 'core', tool: 'name_it', desc: '5 names + domain', cost: '$0.03' },
|
|
246
|
+
{ pack: 'core', tool: 'price_it', desc: 'SaaS pricing', cost: '$0.05' },
|
|
247
|
+
{ pack: 'core', tool: 'one_liner', desc: 'Elevator pitch', cost: '$0.02' },
|
|
248
|
+
{ pack: 'labs', tool: 'genius', desc: 'Deep problem solving', cost: '$0.50' },
|
|
249
|
+
{ pack: 'labs', tool: 'genius_plus', desc: 'Self-improving code', cost: '$0.65' },
|
|
250
|
+
{ pack: 'labs', tool: 'compute', desc: 'Python sandbox', cost: '$0.02' },
|
|
251
|
+
{ pack: 'labs', tool: 'mind_opener', desc: '5 curious angles', cost: '$0.08' },
|
|
252
|
+
{ pack: 'beacon', tool: 'health', desc: 'Context health', cost: 'FREE' },
|
|
253
|
+
{ pack: 'beacon', tool: 'compress', desc: 'Smart compression', cost: '$0.02' },
|
|
254
|
+
{ pack: 'beacon', tool: 'extract', desc: 'Extract decisions', cost: '$0.02' },
|
|
255
|
+
{ pack: 'beacon', tool: 'mint', desc: 'Permanent memory', cost: '$0.01' },
|
|
256
|
+
{ pack: 'beacon', tool: 'recall', desc: 'Read memories', cost: 'FREE' },
|
|
257
|
+
{ pack: 'beacon', tool: 'checkpoint', desc: 'Save state', cost: '$0.02' },
|
|
258
|
+
{ pack: 'router', tool: 'compare', desc: 'Multi-model compare', cost: '$0.05' },
|
|
259
|
+
{ pack: 'router', tool: 'battle', desc: 'Model battle', cost: '$0.10' },
|
|
260
|
+
{ pack: 'adoption', tool: 'adoption_calc', desc: 'P(adopt) calculator', cost: 'FREE' },
|
|
261
|
+
{ pack: 'adoption', tool: 'adoption_diagnose', desc: 'Bottleneck diagnosis', cost: 'FREE' },
|
|
262
|
+
{ pack: 'adoption', tool: 'adoption_simulate', desc: 'Time-series ODE sim', cost: 'FREE' },
|
|
263
|
+
];
|
|
264
|
+
|
|
265
|
+
return all.filter(t =>
|
|
266
|
+
t.pack.includes(q) ||
|
|
267
|
+
t.tool.includes(q) ||
|
|
268
|
+
t.desc.toLowerCase().includes(q)
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async function cmdAdd(args) {
|
|
273
|
+
const pack = args[0];
|
|
274
|
+
if (!pack) {
|
|
275
|
+
console.error('Usage: 50c add <pack>');
|
|
276
|
+
console.error('Run: 50c search to see available packs');
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const valid = ['core', 'labs', 'beacon', 'router', 'adoption'];
|
|
281
|
+
if (!valid.includes(pack)) {
|
|
282
|
+
console.error(`Unknown pack: ${pack}`);
|
|
283
|
+
console.error('Available: ' + valid.join(', '));
|
|
284
|
+
process.exit(1);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (!CONFIG.packs) CONFIG.packs = ['core'];
|
|
288
|
+
if (CONFIG.packs.includes(pack)) {
|
|
289
|
+
console.log(`Pack "${pack}" already enabled`);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
CONFIG.packs.push(pack);
|
|
294
|
+
saveConfig(CONFIG);
|
|
295
|
+
console.log(`Added pack: ${pack}`);
|
|
296
|
+
console.log('Enabled packs: ' + CONFIG.packs.join(', '));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
async function cmdRemove(args) {
|
|
300
|
+
const pack = args[0];
|
|
301
|
+
if (!pack) {
|
|
302
|
+
console.error('Usage: 50c remove <pack>');
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (pack === 'core') {
|
|
307
|
+
console.error('Cannot remove core pack');
|
|
308
|
+
process.exit(1);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (!CONFIG.packs || !CONFIG.packs.includes(pack)) {
|
|
312
|
+
console.log(`Pack "${pack}" not enabled`);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
CONFIG.packs = CONFIG.packs.filter(p => p !== pack);
|
|
317
|
+
saveConfig(CONFIG);
|
|
318
|
+
console.log(`Removed pack: ${pack}`);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
async function cmdPin(args) {
|
|
322
|
+
const spec = args[0];
|
|
323
|
+
if (!spec || !spec.includes('@')) {
|
|
324
|
+
console.error('Usage: 50c pin <pack>@<version>');
|
|
325
|
+
console.error('Example: 50c pin beacon@2.0.0');
|
|
326
|
+
process.exit(1);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const [pack, version] = spec.split('@');
|
|
330
|
+
|
|
331
|
+
let lockfile = {};
|
|
332
|
+
try {
|
|
333
|
+
if (fs.existsSync(LOCKFILE)) {
|
|
334
|
+
lockfile = JSON.parse(fs.readFileSync(LOCKFILE, 'utf8'));
|
|
335
|
+
}
|
|
336
|
+
} catch (e) {}
|
|
337
|
+
|
|
338
|
+
lockfile[pack] = version;
|
|
339
|
+
fs.writeFileSync(LOCKFILE, JSON.stringify(lockfile, null, 2));
|
|
340
|
+
console.log(`Pinned ${pack} to version ${version}`);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
async function cmdUpdate() {
|
|
344
|
+
console.log('Checking for updates...');
|
|
345
|
+
// TODO: Check registry for newer versions
|
|
346
|
+
console.log('All packs up to date');
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
async function cmdBalance() {
|
|
350
|
+
if (!API_KEY) {
|
|
351
|
+
console.log('Balance: (no API key)');
|
|
352
|
+
console.log('Run: 50c config key <your_key>');
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
try {
|
|
357
|
+
const result = await callMCPTool('check_balance', {});
|
|
358
|
+
console.log('Balance:', result);
|
|
359
|
+
} catch (e) {
|
|
360
|
+
console.error('Could not fetch balance:', e.message);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
async function cmdSnapshots() {
|
|
365
|
+
console.log('Recent Snapshots:');
|
|
366
|
+
console.log(' (snapshot system coming soon)');
|
|
367
|
+
// TODO: Query local + Turso for snapshots
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
async function cmdRestore(args) {
|
|
371
|
+
const id = args[0];
|
|
372
|
+
if (!id) {
|
|
373
|
+
console.error('Usage: 50c restore <snapshot_id>');
|
|
374
|
+
console.error('Run: 50c snapshots to list');
|
|
375
|
+
process.exit(1);
|
|
376
|
+
}
|
|
377
|
+
console.log(`Restoring snapshot ${id}...`);
|
|
378
|
+
// TODO: Implement restore
|
|
379
|
+
console.log('(restore coming soon)');
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
async function cmdTip(args) {
|
|
383
|
+
const amount = parseInt(args[0]) || null;
|
|
384
|
+
const reason = args.slice(1).join(' ') || null;
|
|
385
|
+
|
|
386
|
+
if (!API_KEY) {
|
|
387
|
+
console.error('Need API key to tip. Run: 50c config key <your_key>');
|
|
388
|
+
process.exit(1);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
try {
|
|
392
|
+
const result = await callMCPTool('beacon_tip', { amount, reason });
|
|
393
|
+
if (result.ask) {
|
|
394
|
+
console.log(result.ask);
|
|
395
|
+
console.log('Run: 50c tip <amount> [reason]');
|
|
396
|
+
} else if (result.thanks) {
|
|
397
|
+
console.log(result.thanks);
|
|
398
|
+
if (result.impact) console.log(result.impact);
|
|
399
|
+
console.log(`Balance: ${result.balance} | Tip #${result.tip_number}`);
|
|
400
|
+
if (result.tip_pool) {
|
|
401
|
+
console.log(`Refund pool: ${result.tip_pool.refund_available} credits`);
|
|
402
|
+
}
|
|
403
|
+
} else {
|
|
404
|
+
console.log(JSON.stringify(result, null, 2));
|
|
405
|
+
}
|
|
406
|
+
} catch (e) {
|
|
407
|
+
console.error('Tip failed:', e.message);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
async function cmdNoTip(args) {
|
|
412
|
+
const tool = args[0];
|
|
413
|
+
const reason = args[1];
|
|
414
|
+
const details = args.slice(2).join(' ') || null;
|
|
415
|
+
|
|
416
|
+
if (!tool) {
|
|
417
|
+
console.log('Usage: 50c notip <tool> <reason> [details]');
|
|
418
|
+
console.log('');
|
|
419
|
+
console.log('Reasons: wrong_answer, too_slow, confusing, not_helpful, crashed, other');
|
|
420
|
+
console.log('');
|
|
421
|
+
console.log('Example: 50c notip compress not_helpful "output was garbage"');
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (!API_KEY) {
|
|
426
|
+
console.error('Need API key. Run: 50c config key <your_key>');
|
|
427
|
+
process.exit(1);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
try {
|
|
431
|
+
const result = await callMCPTool('beacon_notip', { tool, reason, details });
|
|
432
|
+
console.log(result.acknowledged || 'Feedback received');
|
|
433
|
+
if (result.refund) {
|
|
434
|
+
console.log(`Refunded: ${result.refund.credits} credits`);
|
|
435
|
+
}
|
|
436
|
+
if (result.refund_denied) {
|
|
437
|
+
console.log('No refund:', result.refund_denied);
|
|
438
|
+
}
|
|
439
|
+
if (result.diagnosis) {
|
|
440
|
+
console.log('');
|
|
441
|
+
console.log('Diagnosis:', result.diagnosis.likely_cause);
|
|
442
|
+
console.log('Try:', result.diagnosis.try_tools?.map(t => t.tool).join(', '));
|
|
443
|
+
}
|
|
444
|
+
} catch (e) {
|
|
445
|
+
console.error('No-tip failed:', e.message);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
async function cmdMint(args) {
|
|
450
|
+
const content = args.join(' ');
|
|
451
|
+
if (!content) {
|
|
452
|
+
console.error('Usage: 50c mint <content>');
|
|
453
|
+
console.error('Example: 50c mint "API key rotated on 2026-01-29"');
|
|
454
|
+
process.exit(1);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (!API_KEY) {
|
|
458
|
+
console.error('Need API key. Run: 50c config key <your_key>');
|
|
459
|
+
process.exit(1);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
try {
|
|
463
|
+
const result = await callMCPTool('beacon_remember', { content, category: 'mint' });
|
|
464
|
+
console.log('Minted:', content.slice(0, 50) + (content.length > 50 ? '...' : ''));
|
|
465
|
+
console.log('Total memories:', result.total);
|
|
466
|
+
} catch (e) {
|
|
467
|
+
console.error('Mint failed:', e.message);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
async function cmdConfig(args) {
|
|
472
|
+
const action = args[0];
|
|
473
|
+
const value = args.slice(1).join(' ');
|
|
474
|
+
|
|
475
|
+
if (!action) {
|
|
476
|
+
console.log('Current config:');
|
|
477
|
+
console.log(JSON.stringify(CONFIG, null, 2));
|
|
478
|
+
console.log('');
|
|
479
|
+
console.log('Commands:');
|
|
480
|
+
console.log(' 50c config key <api_key> Set API key');
|
|
481
|
+
console.log(' 50c config show Show config');
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (action === 'key') {
|
|
486
|
+
if (!value) {
|
|
487
|
+
console.log('API Key:', CONFIG.api_key || '(not set)');
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
CONFIG.api_key = value;
|
|
491
|
+
saveConfig(CONFIG);
|
|
492
|
+
console.log('API key saved to ~/.50c/config.json');
|
|
493
|
+
} else if (action === 'show') {
|
|
494
|
+
console.log(JSON.stringify(CONFIG, null, 2));
|
|
495
|
+
} else {
|
|
496
|
+
console.error('Unknown config action:', action);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// ═══════════════════════════════════════════════════════════════
|
|
501
|
+
// TOOL COMMANDS
|
|
502
|
+
// ═══════════════════════════════════════════════════════════════
|
|
503
|
+
|
|
504
|
+
async function runToolCommand(cmd, args) {
|
|
505
|
+
const spec = TOOL_COMMANDS[cmd];
|
|
506
|
+
if (!spec) throw new Error('Unknown command: ' + cmd);
|
|
507
|
+
|
|
508
|
+
// Special handling for chat/refocus
|
|
509
|
+
if (spec.special === 'chat') {
|
|
510
|
+
if (args.length < 2) {
|
|
511
|
+
console.error('Usage: 50c chat <session_id> <message>');
|
|
512
|
+
process.exit(1);
|
|
513
|
+
}
|
|
514
|
+
const sessionId = args[0];
|
|
515
|
+
const message = args.slice(1).join(' ');
|
|
516
|
+
const result = await callMCPTool('ide_conversation', {
|
|
517
|
+
session_id: sessionId,
|
|
518
|
+
message,
|
|
519
|
+
mode: 'chat'
|
|
520
|
+
});
|
|
521
|
+
console.log(result.response || JSON.stringify(result, null, 2));
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (spec.special === 'refocus') {
|
|
526
|
+
if (args.length < 2) {
|
|
527
|
+
console.error('Usage: 50c refocus <situation> <goal>');
|
|
528
|
+
process.exit(1);
|
|
529
|
+
}
|
|
530
|
+
const situation = args[0];
|
|
531
|
+
const goal = args.slice(1).join(' ');
|
|
532
|
+
const result = await callMCPTool('llm_refocus', { situation, goal, tone: 'gentle' });
|
|
533
|
+
console.log(result.response || result.redirect || JSON.stringify(result, null, 2));
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// INVENT-UI: Visual invention pipeline with browser UI
|
|
538
|
+
if (spec.special === 'invent-ui') {
|
|
539
|
+
let problem = '';
|
|
540
|
+
let rigor = 'deep';
|
|
541
|
+
let domain = 'code';
|
|
542
|
+
|
|
543
|
+
for (const arg of args) {
|
|
544
|
+
if (arg.startsWith('--rigor=')) rigor = arg.split('=')[1];
|
|
545
|
+
else if (arg.startsWith('--domain=')) domain = arg.split('=')[1];
|
|
546
|
+
else if (!arg.startsWith('--')) problem += (problem ? ' ' : '') + arg;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (!problem) {
|
|
550
|
+
console.error('Usage: 50c invent-ui "problem" [--rigor=deep] [--domain=math]');
|
|
551
|
+
console.error('Opens a browser window with real-time swarm visualization.');
|
|
552
|
+
process.exit(1);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const { runInventWithUI } = require('../lib/invent-ui.js');
|
|
556
|
+
await runInventWithUI(problem, { domain, rigor });
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// MCP-TV: Universal MCP Visualization Platform (FREE)
|
|
561
|
+
if (spec.special === 'mcp-tv') {
|
|
562
|
+
let port = 50888;
|
|
563
|
+
let noOpen = false;
|
|
564
|
+
|
|
565
|
+
for (const arg of args) {
|
|
566
|
+
if (arg.startsWith('--port=')) port = parseInt(arg.split('=')[1]);
|
|
567
|
+
if (arg === '--no-open') noOpen = true;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
const { createServer } = require('../lib/mcp-tv.js');
|
|
571
|
+
const { spawn } = require('child_process');
|
|
572
|
+
|
|
573
|
+
createServer(port);
|
|
574
|
+
|
|
575
|
+
if (!noOpen) {
|
|
576
|
+
setTimeout(() => {
|
|
577
|
+
const url = `http://localhost:${port}`;
|
|
578
|
+
const platform = process.platform;
|
|
579
|
+
if (platform === 'win32') {
|
|
580
|
+
spawn('cmd', ['/c', 'start', url], { detached: true, stdio: 'ignore' }).unref();
|
|
581
|
+
} else if (platform === 'darwin') {
|
|
582
|
+
spawn('open', [url], { detached: true, stdio: 'ignore' }).unref();
|
|
583
|
+
} else {
|
|
584
|
+
spawn('xdg-open', [url], { detached: true, stdio: 'ignore' }).unref();
|
|
585
|
+
}
|
|
586
|
+
}, 500);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Keep process alive
|
|
590
|
+
return new Promise(() => {});
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// INVENT: Enterprise invention pipeline
|
|
594
|
+
if (spec.special === 'invent') {
|
|
595
|
+
// Parse args: 50c invent "problem" --rigor=deep --domain=math --constraint="must be fast"
|
|
596
|
+
let problem = '';
|
|
597
|
+
let rigor = 'deep';
|
|
598
|
+
let domain = 'code';
|
|
599
|
+
const constraints = [];
|
|
600
|
+
|
|
601
|
+
for (const arg of args) {
|
|
602
|
+
if (arg.startsWith('--rigor=')) {
|
|
603
|
+
rigor = arg.split('=')[1];
|
|
604
|
+
} else if (arg.startsWith('--domain=')) {
|
|
605
|
+
domain = arg.split('=')[1];
|
|
606
|
+
} else if (arg.startsWith('--constraint=')) {
|
|
607
|
+
constraints.push(arg.split('=')[1].replace(/^["']|["']$/g, ''));
|
|
608
|
+
} else if (!arg.startsWith('--')) {
|
|
609
|
+
problem += (problem ? ' ' : '') + arg;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
if (!problem) {
|
|
614
|
+
console.error('Usage: 50c invent "problem description" [options]');
|
|
615
|
+
console.error('Options:');
|
|
616
|
+
console.error(' --rigor=fast|standard|deep|exhaustive (default: deep)');
|
|
617
|
+
console.error(' --domain=math|physics|code|business (default: code)');
|
|
618
|
+
console.error(' --constraint="constraint text" (can repeat)');
|
|
619
|
+
console.error('');
|
|
620
|
+
console.error('Examples:');
|
|
621
|
+
console.error(' 50c invent "faster sorting algorithm" --rigor=deep');
|
|
622
|
+
console.error(' 50c invent "prove Riemann hypothesis" --domain=math --rigor=exhaustive');
|
|
623
|
+
console.error(' 50c invent "novel auth system" --constraint="must be passwordless"');
|
|
624
|
+
process.exit(1);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
console.log(`\n🔬 50c Auto-Invent Pipeline`);
|
|
628
|
+
console.log(` Problem: ${problem.slice(0, 60)}${problem.length > 60 ? '...' : ''}`);
|
|
629
|
+
console.log(` Rigor: ${rigor} | Domain: ${domain}`);
|
|
630
|
+
if (constraints.length) console.log(` Constraints: ${constraints.length}`);
|
|
631
|
+
console.log(` Cost: $2.00\n`);
|
|
632
|
+
|
|
633
|
+
// Call auto_invent directly (not via remote API - it's local)
|
|
634
|
+
const inventArgs = { problem, rigor, domain, constraints };
|
|
635
|
+
const result = await autoInvent(inventArgs);
|
|
636
|
+
|
|
637
|
+
// Format output
|
|
638
|
+
if (result.ok && result.invention) {
|
|
639
|
+
console.log('═══════════════════════════════════════════════════════════════');
|
|
640
|
+
console.log(' INVENTION RESULT');
|
|
641
|
+
console.log('═══════════════════════════════════════════════════════════════\n');
|
|
642
|
+
|
|
643
|
+
if (result.angles && result.angles.length > 0) {
|
|
644
|
+
console.log('📐 CREATIVE ANGLES:');
|
|
645
|
+
result.angles.slice(0, 5).forEach((a, i) => console.log(` ${i+1}. ${a}`));
|
|
646
|
+
console.log('');
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
if (result.invention.solution) {
|
|
650
|
+
console.log('💡 SOLUTION:');
|
|
651
|
+
console.log(result.invention.solution);
|
|
652
|
+
console.log('');
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
if (result.proofs && result.proofs.length > 0) {
|
|
656
|
+
console.log('✓ PROOFS:', result.proofs.length, 'verification(s)');
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
if (result.prior_art && result.prior_art.length > 0) {
|
|
660
|
+
console.log('📚 PRIOR ART:', result.prior_art.length, 'related work(s) found');
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
console.log('\n═══════════════════════════════════════════════════════════════');
|
|
664
|
+
console.log(`⏱ Duration: ${(result.total_duration_ms / 1000).toFixed(1)}s | Verified: ${result.verified ? '✓' : '○'}`);
|
|
665
|
+
console.log('═══════════════════════════════════════════════════════════════\n');
|
|
666
|
+
} else {
|
|
667
|
+
console.log('Result:', JSON.stringify(result, null, 2));
|
|
668
|
+
}
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// ADOPTION EQUATION TOOLS (FREE, local compute)
|
|
673
|
+
if (spec.special === 'adopt') {
|
|
674
|
+
// 50c adopt 2.0 0.3 0.8 [churn] [lambda]
|
|
675
|
+
const R = parseFloat(args[0]);
|
|
676
|
+
const N = parseFloat(args[1]);
|
|
677
|
+
const W = parseFloat(args[2]);
|
|
678
|
+
const churn = parseFloat(args[3]) || 0;
|
|
679
|
+
const lambda = parseFloat(args[4]) || 1.0;
|
|
680
|
+
|
|
681
|
+
if (isNaN(R) || isNaN(N) || isNaN(W)) {
|
|
682
|
+
console.error('Usage: 50c adopt <reward> <network> <window> [churn] [lambda]');
|
|
683
|
+
console.error('Example: 50c adopt 2.0 0.3 0.8');
|
|
684
|
+
process.exit(1);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
const result = adoptionCalc({ reward: R, network: N, window: W, churn, lambda });
|
|
688
|
+
console.log('\n=== ADOPTION PROBABILITY ===');
|
|
689
|
+
console.log(`P(adopt) = ${(result.probability * 100).toFixed(2)}%`);
|
|
690
|
+
console.log(`Equation: ${result.equation}`);
|
|
691
|
+
console.log(`\nTerms:`);
|
|
692
|
+
console.log(` Reward: ${(result.reward_term * 100).toFixed(1)}%`);
|
|
693
|
+
console.log(` Network: ${(result.network_effect * 100).toFixed(1)}%`);
|
|
694
|
+
console.log(` Window: ${(result.upheaval_window * 100).toFixed(1)}%`);
|
|
695
|
+
console.log(`\nDiagnosis: ${result.diagnosis}`);
|
|
696
|
+
console.log(`Bottleneck: ${result.bottleneck} (${(result.bottleneck_value * 100).toFixed(1)}%)`);
|
|
697
|
+
if (result.threshold_R_for_50pct !== 'impossible') {
|
|
698
|
+
console.log(`R needed for 50%: ${result.threshold_R_for_50pct}`);
|
|
699
|
+
}
|
|
700
|
+
console.log(`Past bifurcation (viral threshold): ${result.past_bifurcation ? 'YES' : 'NO'}`);
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
if (spec.special === 'adopt-dx') {
|
|
705
|
+
// 50c adopt-dx 2.0 0.3 0.8
|
|
706
|
+
const R = parseFloat(args[0]);
|
|
707
|
+
const N = parseFloat(args[1]);
|
|
708
|
+
const W = parseFloat(args[2]);
|
|
709
|
+
|
|
710
|
+
if (isNaN(R) || isNaN(N) || isNaN(W)) {
|
|
711
|
+
console.error('Usage: 50c adopt-dx <reward> <network> <window>');
|
|
712
|
+
process.exit(1);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
const result = adoptionDiagnose({ reward: R, network: N, window: W });
|
|
716
|
+
console.log('\n=== ADOPTION DIAGNOSIS ===');
|
|
717
|
+
console.log(`P(adopt) = ${(result.probability * 100).toFixed(2)}%`);
|
|
718
|
+
console.log(`\nDiagnosis: ${result.diagnosis.toUpperCase()}`);
|
|
719
|
+
console.log(`Priority: ${result.prescription.priority}`);
|
|
720
|
+
console.log(`\nProblem: ${result.prescription.problem}`);
|
|
721
|
+
console.log(`Fix: ${result.prescription.fix}`);
|
|
722
|
+
if (result.kill_switches.length > 0) {
|
|
723
|
+
console.log('\n⚠️ KILL SWITCHES:');
|
|
724
|
+
result.kill_switches.forEach(k => console.log(` ${k}`));
|
|
725
|
+
}
|
|
726
|
+
console.log(`\nInsight: ${result.insight}`);
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
if (spec.special === 'adopt-sim') {
|
|
731
|
+
// 50c adopt-sim 2.0 [steps]
|
|
732
|
+
const R = parseFloat(args[0]) || 2.0;
|
|
733
|
+
const steps = parseInt(args[1]) || 100;
|
|
734
|
+
|
|
735
|
+
const result = adoptionSimulate({ reward: R, steps });
|
|
736
|
+
console.log('\n=== ADOPTION SIMULATION ===');
|
|
737
|
+
console.log(`Initial: R=${R}, N0=0.1, W0=0.9, alpha=1.5, churn=0.05`);
|
|
738
|
+
console.log(`\nTrajectory:`);
|
|
739
|
+
result.series.forEach(p => {
|
|
740
|
+
const bar = '█'.repeat(Math.round(p.P * 40));
|
|
741
|
+
console.log(`t=${p.t.toFixed(1).padStart(4)}: ${(p.P * 100).toFixed(1).padStart(5)}% ${bar}`);
|
|
742
|
+
});
|
|
743
|
+
console.log(`\nFinal P: ${(result.summary.final_adoption * 100).toFixed(2)}%`);
|
|
744
|
+
console.log(`Peak P: ${(result.summary.peak_adoption * 100).toFixed(2)}% at t=${result.summary.peak_time}`);
|
|
745
|
+
console.log(`Tipped viral: ${result.summary.tipped_at !== 'never' ? 'YES at t=' + result.summary.tipped_at : 'NO'}`);
|
|
746
|
+
console.log(`Trajectory: ${result.summary.trajectory}`);
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// TEAM COMMANDS (FREE, uses API)
|
|
751
|
+
if (spec.special === 'team') {
|
|
752
|
+
const res = await fetch('https://api.50c.ai/v1/team/info', {
|
|
753
|
+
method: 'POST',
|
|
754
|
+
headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
|
|
755
|
+
body: '{}'
|
|
756
|
+
});
|
|
757
|
+
const data = await res.json();
|
|
758
|
+
if (data.error === 'Not in a team') {
|
|
759
|
+
console.log('\n=== NO TEAM ===');
|
|
760
|
+
console.log('You are not in a team yet.');
|
|
761
|
+
console.log('Create one with: 50c team-create "My Team"');
|
|
762
|
+
} else if (data.team) {
|
|
763
|
+
console.log('\n=== TEAM INFO ===');
|
|
764
|
+
console.log(`Name: ${data.team.name}`);
|
|
765
|
+
console.log(`Plan: ${data.team.plan}`);
|
|
766
|
+
console.log(`Members: ${data.members.length}/${data.team.max_members}`);
|
|
767
|
+
console.log(`Your role: ${data.your_role}`);
|
|
768
|
+
console.log('\nMembers:');
|
|
769
|
+
data.members.forEach(m => console.log(` ${m.email || m.customer_id} (${m.role})`));
|
|
770
|
+
} else {
|
|
771
|
+
console.log(JSON.stringify(data, null, 2));
|
|
772
|
+
}
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
if (spec.special === 'team-create') {
|
|
777
|
+
const name = args.join(' ') || 'My Team';
|
|
778
|
+
const res = await fetch('https://api.50c.ai/v1/team/create', {
|
|
779
|
+
method: 'POST',
|
|
780
|
+
headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
|
|
781
|
+
body: JSON.stringify({ name })
|
|
782
|
+
});
|
|
783
|
+
const data = await res.json();
|
|
784
|
+
console.log('\n=== TEAM CREATED ===');
|
|
785
|
+
console.log(`ID: ${data.team_id}`);
|
|
786
|
+
console.log(`Name: ${data.name}`);
|
|
787
|
+
console.log(`Plan: ${data.plan}`);
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
if (spec.special === 'team-mint') {
|
|
792
|
+
if (args.length < 2) {
|
|
793
|
+
console.error('Usage: 50c team-mint <key> <value> [scope]');
|
|
794
|
+
process.exit(1);
|
|
795
|
+
}
|
|
796
|
+
const key = args[0];
|
|
797
|
+
const value = args.slice(1, -1).join(' ') || args[1];
|
|
798
|
+
const scope = args.length > 2 ? args[args.length - 1] : 'general';
|
|
799
|
+
const res = await fetch('https://api.50c.ai/v1/team/mint', {
|
|
800
|
+
method: 'POST',
|
|
801
|
+
headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
|
|
802
|
+
body: JSON.stringify({ key, value, scope })
|
|
803
|
+
});
|
|
804
|
+
const data = await res.json();
|
|
805
|
+
console.log('\n=== MEMORY SHARED ===');
|
|
806
|
+
console.log(`ID: ${data.id}`);
|
|
807
|
+
console.log(`Team: ${data.team_id}`);
|
|
808
|
+
console.log(`Shared: ${data.shared}`);
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
if (spec.special === 'team-recall') {
|
|
813
|
+
const query = args.join(' ') || null;
|
|
814
|
+
const res = await fetch('https://api.50c.ai/v1/team/recall', {
|
|
815
|
+
method: 'POST',
|
|
816
|
+
headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
|
|
817
|
+
body: JSON.stringify({ query, limit: 20 })
|
|
818
|
+
});
|
|
819
|
+
const data = await res.json();
|
|
820
|
+
console.log('\n=== TEAM MEMORIES ===');
|
|
821
|
+
console.log(`Team: ${data.team_id}`);
|
|
822
|
+
console.log(`Found: ${data.count} memories\n`);
|
|
823
|
+
data.memories.forEach(m => {
|
|
824
|
+
console.log(`[${m.scope}] ${m.key}`);
|
|
825
|
+
console.log(` ${m.value}`);
|
|
826
|
+
console.log('');
|
|
827
|
+
});
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
if (spec.special === 'team-analytics') {
|
|
832
|
+
const res = await fetch('https://api.50c.ai/v1/team/analytics', {
|
|
833
|
+
method: 'POST',
|
|
834
|
+
headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
|
|
835
|
+
body: '{}'
|
|
836
|
+
});
|
|
837
|
+
const data = await res.json();
|
|
838
|
+
if (data.error) {
|
|
839
|
+
console.log(data.error);
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
const t = data.totals;
|
|
843
|
+
console.log('\n=== TEAM ROI ANALYTICS ===');
|
|
844
|
+
console.log(`Team: ${data.team_id}\n`);
|
|
845
|
+
console.log(`Bugs Caught: ${t.bugs_caught}`);
|
|
846
|
+
console.log(`Hours Saved: ${t.hours_saved.toFixed(1)}`);
|
|
847
|
+
console.log(`Tool Calls: ${t.tool_calls}`);
|
|
848
|
+
console.log(`Spend: $${t.spend_dollars.toFixed(2)}`);
|
|
849
|
+
console.log(`Value Generated: $${t.roi_dollars.toFixed(2)}`);
|
|
850
|
+
console.log(`ROI Multiple: ${t.roi_multiple.toFixed(1)}x`);
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// Standard tool
|
|
855
|
+
const input = args.join(' ');
|
|
856
|
+
if (!input) {
|
|
857
|
+
console.error(`Usage: 50c ${cmd} <input>`);
|
|
858
|
+
process.exit(1);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
const result = await callMCPTool(spec.tool, { [spec.arg]: input });
|
|
862
|
+
|
|
863
|
+
// Format output nicely
|
|
864
|
+
if (typeof result === 'string') {
|
|
865
|
+
console.log(result);
|
|
866
|
+
} else if (result.hints) {
|
|
867
|
+
result.hints.forEach((h, i) => console.log(`${i+1}. ${h}`));
|
|
868
|
+
} else if (result.ideas) {
|
|
869
|
+
result.ideas.forEach((h, i) => console.log(`${i+1}. ${h}`));
|
|
870
|
+
} else if (result.pitch) {
|
|
871
|
+
console.log(result.pitch);
|
|
872
|
+
} else if (result.flaws) {
|
|
873
|
+
result.flaws.forEach((f, i) => {
|
|
874
|
+
console.log(`\n[${i+1}] ${f.flaw}`);
|
|
875
|
+
console.log(` Fix: ${f.fix}`);
|
|
876
|
+
});
|
|
877
|
+
} else if (result.names) {
|
|
878
|
+
result.names.forEach(n => {
|
|
879
|
+
const avail = n.available ? '✓' : '✗';
|
|
880
|
+
console.log(` ${avail} ${n.name} - ${n.domain}`);
|
|
881
|
+
});
|
|
882
|
+
} else if (result.strategy) {
|
|
883
|
+
console.log(result.strategy);
|
|
884
|
+
} else {
|
|
885
|
+
console.log(JSON.stringify(result, null, 2));
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
async function runPackTool(packTool, args) {
|
|
890
|
+
const [pack, tool] = packTool.split('.');
|
|
891
|
+
if (!pack || !tool) {
|
|
892
|
+
console.error('Usage: 50c <pack>.<tool> <input>');
|
|
893
|
+
console.error('Example: 50c beacon.compress "long text here"');
|
|
894
|
+
process.exit(1);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
// Check pack is enabled
|
|
898
|
+
if (!CONFIG.packs?.includes(pack) && pack !== 'core') {
|
|
899
|
+
console.error(`Pack "${pack}" not enabled. Run: 50c add ${pack}`);
|
|
900
|
+
process.exit(1);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
if (!API_KEY) {
|
|
904
|
+
console.error('Need API key. Run: 50c config key <your_key>');
|
|
905
|
+
process.exit(1);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
const input = args.join(' ');
|
|
909
|
+
|
|
910
|
+
// Map pack.tool to MCP tool name
|
|
911
|
+
const toolName = `${pack}_${tool}`;
|
|
912
|
+
|
|
913
|
+
// Build args object based on tool
|
|
914
|
+
let toolArgs = {};
|
|
915
|
+
if (tool === 'compress' || tool === 'extract' || tool === 'summarize') {
|
|
916
|
+
toolArgs = { messages: [input] };
|
|
917
|
+
} else if (tool === 'health') {
|
|
918
|
+
toolArgs = { messages: input ? [input] : [] };
|
|
919
|
+
} else if (tool === 'remember' || tool === 'mint') {
|
|
920
|
+
toolArgs = { content: input };
|
|
921
|
+
} else if (tool === 'recall') {
|
|
922
|
+
toolArgs = { query: input || null };
|
|
923
|
+
} else if (tool === 'drift') {
|
|
924
|
+
toolArgs = { messages: [input], goal: args[0] || 'stay on topic' };
|
|
925
|
+
} else if (tool === 'checkpoint') {
|
|
926
|
+
toolArgs = { name: args[0] || 'default', messages: args.slice(1) };
|
|
927
|
+
} else if (tool === 'restore') {
|
|
928
|
+
toolArgs = { name: input || 'default' };
|
|
929
|
+
} else {
|
|
930
|
+
toolArgs = { input };
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
const result = await callMCPTool(toolName, toolArgs);
|
|
934
|
+
console.log(JSON.stringify(result, null, 2));
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
// ═══════════════════════════════════════════════════════════════
|
|
938
|
+
// MCP MODE
|
|
939
|
+
// ═══════════════════════════════════════════════════════════════
|
|
940
|
+
|
|
941
|
+
function startMCPMode() {
|
|
942
|
+
const rl = readline.createInterface({
|
|
943
|
+
input: process.stdin,
|
|
944
|
+
output: process.stdout,
|
|
945
|
+
terminal: false
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
rl.on('line', async (line) => {
|
|
949
|
+
try {
|
|
950
|
+
const clean = line.trim();
|
|
951
|
+
if (!clean) return;
|
|
952
|
+
const request = JSON.parse(clean);
|
|
953
|
+
|
|
954
|
+
// Notifications (no id) don't get responses per JSON-RPC spec
|
|
955
|
+
if (request.method && request.method.startsWith('notifications/')) {
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// Handle initialize locally
|
|
960
|
+
if (request.method === 'initialize') {
|
|
961
|
+
process.stdout.write(JSON.stringify({
|
|
962
|
+
jsonrpc: '2.0',
|
|
963
|
+
id: request.id,
|
|
964
|
+
result: {
|
|
965
|
+
protocolVersion: '2024-11-05',
|
|
966
|
+
serverInfo: { name: '50c', version: VERSION },
|
|
967
|
+
capabilities: { tools: {} }
|
|
968
|
+
}
|
|
969
|
+
}) + '\n');
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
const response = await handleMCPRequest(request);
|
|
974
|
+
if (response) {
|
|
975
|
+
process.stdout.write(JSON.stringify(response) + '\n');
|
|
976
|
+
}
|
|
977
|
+
} catch (e) {
|
|
978
|
+
process.stdout.write(JSON.stringify({
|
|
979
|
+
jsonrpc: '2.0',
|
|
980
|
+
id: null,
|
|
981
|
+
error: { code: -32603, message: e.message }
|
|
982
|
+
}) + '\n');
|
|
983
|
+
}
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
async function handleMCPRequest(request) {
|
|
988
|
+
// Handle local file-memory tools first (FREE, no API call)
|
|
989
|
+
const localResult = await handleLocalTools(request);
|
|
990
|
+
if (localResult) return localResult;
|
|
991
|
+
|
|
992
|
+
// Forward to remote MCP endpoint
|
|
993
|
+
return callRemoteMCP(request);
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// Local file-memory tools (FREE, runs on user machine)
|
|
997
|
+
const { FILE_TOOLS, indexFile, findSymbol, getLines, searchFile, fileSummary } = require('../lib/file-memory.js');
|
|
998
|
+
// Note: subagent, team already imported at top for CLI commands
|
|
999
|
+
|
|
1000
|
+
const LOCAL_TOOLS = [
|
|
1001
|
+
// THE MAIN TOOL - Ask the 50c team to do anything
|
|
1002
|
+
{ name: "team", description: "Ask the 50c team to do anything. Natural language → auto-picks the right tools. Example: 'roast my code and suggest fixes'", inputSchema: { type: "object", properties: { task: { type: "string", description: "What you want done in plain English" }, context: { type: "string", description: "Code, text, or data to work with (optional)" }, dryRun: { type: "boolean", description: "Preview plan without executing" } }, required: ["task"] } },
|
|
1003
|
+
|
|
1004
|
+
// File memory tools
|
|
1005
|
+
{ name: "fm_index", description: "Index a large file for fast symbol/line lookup. Auto-detects Python/JS/TS. FREE.", inputSchema: { type: "object", properties: { filepath: { type: "string", description: "Absolute or relative path to file" } }, required: ["filepath"] } },
|
|
1006
|
+
{ name: "fm_find", description: "Find where a function/class is defined across all indexed files. FREE.", inputSchema: { type: "object", properties: { name: { type: "string", description: "Symbol name (function, class, variable)" }, filepath: { type: "string", description: "Optional: limit search to one file" } }, required: ["name"] } },
|
|
1007
|
+
{ name: "fm_lines", description: "Get specific line range from a file with line numbers. FREE.", inputSchema: { type: "object", properties: { filepath: { type: "string" }, start: { type: "number", description: "Start line number" }, end: { type: "number", description: "End line number" } }, required: ["filepath", "start", "end"] } },
|
|
1008
|
+
{ name: "fm_search", description: "Search for symbols and content in a file. Auto-indexes if needed. FREE.", inputSchema: { type: "object", properties: { filepath: { type: "string" }, query: { type: "string", description: "Search term" } }, required: ["filepath", "query"] } },
|
|
1009
|
+
{ name: "fm_summary", description: "Get summary of a file: line count, all functions, classes. FREE.", inputSchema: { type: "object", properties: { filepath: { type: "string" } }, required: ["filepath"] } },
|
|
1010
|
+
{ name: "fm_list", description: "List all indexed files with stats. FREE.", inputSchema: { type: "object", properties: {} } },
|
|
1011
|
+
{ name: "fm_context", description: "Get context around a symbol (function body, class methods). FREE.", inputSchema: { type: "object", properties: { filepath: { type: "string" }, symbol: { type: "string", description: "Function or class name" }, lines_after: { type: "number", description: "Lines to include after definition (default 50)" } }, required: ["filepath", "symbol"] } },
|
|
1012
|
+
|
|
1013
|
+
// 50c Team utilities - for power users who want granular control
|
|
1014
|
+
{ name: "team_http", description: "50c Team: HTTP/HTTPS fetch. Bypasses IDE restrictions. FREE.", inputSchema: { type: "object", properties: { url: { type: "string", description: "Full URL to fetch" }, method: { type: "string", description: "HTTP method (default GET)" }, headers: { type: "object", description: "Request headers" }, body: { type: "string", description: "Request body for POST/PUT" }, timeout: { type: "number", description: "Timeout in ms (default 30000)" } }, required: ["url"] } },
|
|
1015
|
+
{ name: "team_ssh", description: "50c Team: SSH remote command. Configure servers in ~/.50c/servers.json. FREE.", inputSchema: { type: "object", properties: { server: { type: "string", description: "Server alias (nj/zurich/chicago) or {host,user,port}" }, command: { type: "string", description: "Command to execute on remote server" }, timeout: { type: "number", description: "Timeout in ms (default 30000)" } }, required: ["server", "command"] } },
|
|
1016
|
+
{ name: "team_exec", description: "50c Team: Local command execution. Bypasses shell restrictions. FREE.", inputSchema: { type: "object", properties: { command: { type: "string", description: "Command to execute locally" }, cwd: { type: "string", description: "Working directory" }, timeout: { type: "number", description: "Timeout in ms (default 30000)" } }, required: ["command"] } },
|
|
1017
|
+
{ name: "team_multi", description: "50c Team: Execute multiple tasks in parallel. FREE.", inputSchema: { type: "object", properties: { tasks: { type: "array", description: "Array of task objects [{type, ...params}]", items: { type: "object" } } }, required: ["tasks"] } },
|
|
1018
|
+
{ name: "team_servers", description: "50c Team: List known SSH servers. FREE.", inputSchema: { type: "object", properties: {} } },
|
|
1019
|
+
{ name: "team_ask", description: "50c Team: Ask the team to run any 50c tool. Uses your API key.", inputSchema: { type: "object", properties: { tool: { type: "string", description: "50c tool name (e.g., hints, roast, genius, bcalc)" }, args: { type: "object", description: "Tool arguments" } }, required: ["tool"] } },
|
|
1020
|
+
{ name: "team_chain", description: "50c Team: Chain multiple tools together. Output flows via $prev placeholder.", inputSchema: { type: "object", properties: { steps: { type: "array", description: "Array of {tool, args} - use $prev for previous result", items: { type: "object" } }, input: { type: "string", description: "Initial input (optional)" } }, required: ["steps"] } },
|
|
1021
|
+
{ name: "guardian_publish", description: "Guardian: Pre-publish supply chain verification. Thorough checks before npm/github/arxiv/medical publish. Profiles: npm, github, arxiv, medical, science, math. Uses AI tools (bCalc, genius+, web_search) for academic verification. FREE.", inputSchema: { type: "object", properties: { profile: { type: "string", description: "Verification profile: npm, github, arxiv, medical, science, math", enum: ["npm", "github", "arxiv", "medical", "science", "math"] }, cwd: { type: "string", description: "Directory to check (default: current)" }, save_receipt: { type: "boolean", description: "Save receipt as markdown file" } } } },
|
|
1022
|
+
|
|
1023
|
+
// Security audit tool - runs locally, FREE
|
|
1024
|
+
{ name: "guardian_audit", description: "Guardian: Security audit for backdoors, unauthorized RDP/SSH, persistence, suspicious connections. Geo-IP tags foreign IPs. Cross-platform. FREE.", inputSchema: { type: "object", properties: { skipGeo: { type: "boolean", description: "Skip geo-IP lookups (faster, offline)" } } } },
|
|
1025
|
+
|
|
1026
|
+
// Combined security suite - pre-publish + backdoor check, FREE
|
|
1027
|
+
{ name: "guardian", description: "50c Guardian: Combined supply chain verification + machine backdoor audit. Catches injected IPs/URLs/eval AND system compromise. Cross-platform. FREE.", inputSchema: { type: "object", properties: { profile: { type: "string", description: "Verification profile (default: npm)", enum: ["npm", "github"], default: "npm" }, cwd: { type: "string", description: "Directory to check (default: current)" }, skipGeo: { type: "boolean", description: "Skip geo-IP lookups (faster)" }, save_receipt: { type: "boolean", description: "Save receipt as markdown file" } } } },
|
|
1028
|
+
|
|
1029
|
+
// ENTERPRISE PRESET - Auto-Invent Swarm Pipeline ($2.00)
|
|
1030
|
+
{ name: "auto_invent", description: "ENTERPRISE ($2.00): Full invention pipeline. Chains mind_opener → idea_fold → bcalc → genius_plus → compute → cvi_verify. Produces provable, verified solutions. Requires Enterprise tier.", inputSchema: { type: "object", properties: { problem: { type: "string", description: "Problem or hypothesis to solve/prove" }, constraints: { type: "array", items: { type: "string" }, description: "Hard constraints the solution must satisfy" }, domain: { type: "string", description: "Domain hint: math, physics, engineering, business, code", enum: ["math", "physics", "engineering", "business", "code"] }, rigor: { type: "string", description: "Rigor level: fast, standard, deep, exhaustive (all $2.00)", enum: ["fast", "standard", "deep", "exhaustive"], default: "deep" } }, required: ["problem"] } },
|
|
1031
|
+
|
|
1032
|
+
// PROGRAMMATIC INVENTION - JSON-defined executable pipeline (ENTERPRISE $2.00)
|
|
1033
|
+
{ name: "invent_program", description: "ENTERPRISE ($2.00): Execute a JSON-defined invention program in one shot. Steps: generate/compute (Python), assert (verify), call (50c tool), return. All steps compile to single compute execution. Requires Enterprise tier.", inputSchema: { type: "object", properties: { program: { type: "object", description: "JSON program with 'problem' and 'steps' array", properties: { problem: { type: "string" }, steps: { type: "array", items: { type: "object", properties: { id: { type: "string" }, action: { type: "string", enum: ["generate", "compute", "assert", "call", "return"] }, code: { type: "string" }, tool: { type: "string" }, args: { type: "object" }, depends: { type: "array", items: { type: "string" } } }, required: ["id", "action"] } } }, required: ["problem", "steps"] } }, required: ["program"] } },
|
|
1034
|
+
|
|
1035
|
+
// ADOPTION EQUATION TOOLS - P(adopt) = (1-e^(-λR)) × N × W
|
|
1036
|
+
{ name: "adoption_calc", description: "Adoption probability calculator. P=(1-e^(-λR))×Network×Window. Returns probability, diagnosis, bottleneck, and threshold. FREE.", inputSchema: { type: "object", properties: { lambda: { type: "number", description: "Reward sensitivity (default 1.0)" }, reward: { type: "number", description: "Reward magnitude (0+)" }, network: { type: "number", description: "Network effect 0-1" }, window: { type: "number", description: "Upheaval window 0-1" }, churn: { type: "number", description: "Churn rate 0-1 (default 0)" } }, required: ["reward", "network", "window"] } },
|
|
1037
|
+
{ name: "adoption_diagnose", description: "Diagnose WHY adoption is failing. Finds which term (reward/network/window) is the bottleneck. Prescribes fix. FREE.", inputSchema: { type: "object", properties: { reward: { type: "number", description: "Reward magnitude" }, network: { type: "number", description: "Network effect 0-1" }, window: { type: "number", description: "Upheaval window 0-1" }, lambda: { type: "number", description: "Reward sensitivity (default 1.0)" }, context: { type: "string", description: "Optional: product/market context for richer diagnosis" } }, required: ["reward", "network", "window"] } },
|
|
1038
|
+
{ name: "adoption_simulate", description: "Simulate adoption over time with feedback loops. Network grows with adoption, upheaval windows decay. Returns time-series trajectory. FREE.", inputSchema: { type: "object", properties: { reward: { type: "number", description: "Reward magnitude" }, lambda: { type: "number", description: "Reward sensitivity (default 1.0)" }, n0: { type: "number", description: "Initial network effect (default 0.1)" }, w0: { type: "number", description: "Initial upheaval window (default 0.9)" }, churn: { type: "number", description: "Churn rate (default 0.05)" }, decay: { type: "number", description: "Window decay rate (default 0.05)" }, alpha: { type: "number", description: "Network exponent: 1=linear, 1.5=super, 2=Metcalfe (default 1.5)" }, steps: { type: "number", description: "Simulation steps (default 100)" } }, required: ["reward"] } },
|
|
1039
|
+
];
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* AUTO-INVENT: Enterprise Swarm Invention Pipeline
|
|
1043
|
+
* Orchestrates parallel sub-MCPs to produce provable, verified inventions
|
|
1044
|
+
*
|
|
1045
|
+
* SWARM ARCHITECTURE:
|
|
1046
|
+
* Phase 1 (Parallel Exploration):
|
|
1047
|
+
* - 3x mind_opener (temp 0.3, 0.7, 1.0) - diverse creative angles
|
|
1048
|
+
* - idea_fold - STEM lens analysis
|
|
1049
|
+
* - bcalc - mathematical discovery
|
|
1050
|
+
* - web_search - prior art research
|
|
1051
|
+
*
|
|
1052
|
+
* Phase 2 (Synthesis):
|
|
1053
|
+
* - genius_plus - self-improving solution generation
|
|
1054
|
+
*
|
|
1055
|
+
* Phase 3 (Verification Swarm):
|
|
1056
|
+
* - compute - execute proofs
|
|
1057
|
+
* - cvi_verify - constraint checking
|
|
1058
|
+
* - roast (peer_review) - adversarial critique
|
|
1059
|
+
*
|
|
1060
|
+
* Cost: $2.00 flat for full invention pipeline
|
|
1061
|
+
*/
|
|
1062
|
+
|
|
1063
|
+
/**
|
|
1064
|
+
* INVENT_PROGRAM: JSON-defined Executable Invention Pipeline
|
|
1065
|
+
* Enterprise-only ($2.00/request) - programmatic multi-step invention
|
|
1066
|
+
*
|
|
1067
|
+
* Actions:
|
|
1068
|
+
* - generate: Create data/variables (Python code in compute sandbox)
|
|
1069
|
+
* - compute: Calculate/transform (Python code)
|
|
1070
|
+
* - assert: Verify condition (must return truthy or throws)
|
|
1071
|
+
* - call: Invoke a 50c tool (genius, bcalc, hints, etc.)
|
|
1072
|
+
* - return: Final output
|
|
1073
|
+
*
|
|
1074
|
+
* GATED: Requires Enterprise tier + $2.00 balance
|
|
1075
|
+
*/
|
|
1076
|
+
async function inventProgram(args) {
|
|
1077
|
+
const { program } = args;
|
|
1078
|
+
const startTime = Date.now();
|
|
1079
|
+
|
|
1080
|
+
if (!program || !program.problem || !program.steps) {
|
|
1081
|
+
return { ok: false, error: 'Invalid program: must have "problem" and "steps" array' };
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
const results = {
|
|
1085
|
+
ok: true,
|
|
1086
|
+
problem: program.problem,
|
|
1087
|
+
steps_completed: 0,
|
|
1088
|
+
steps_total: program.steps.length,
|
|
1089
|
+
outputs: {},
|
|
1090
|
+
assertions: [],
|
|
1091
|
+
tool_calls: [],
|
|
1092
|
+
final_result: null,
|
|
1093
|
+
cost: '$2.00',
|
|
1094
|
+
tier_required: 'enterprise'
|
|
1095
|
+
};
|
|
1096
|
+
|
|
1097
|
+
// Build execution context for Python code
|
|
1098
|
+
let pythonContext = `
|
|
1099
|
+
import json, math, re, itertools, functools, collections
|
|
1100
|
+
from decimal import Decimal, getcontext
|
|
1101
|
+
getcontext().prec = 100
|
|
1102
|
+
|
|
1103
|
+
# Shared context between steps
|
|
1104
|
+
_ctx = {}
|
|
1105
|
+
_results = {}
|
|
1106
|
+
|
|
1107
|
+
`;
|
|
1108
|
+
|
|
1109
|
+
// Execute steps sequentially
|
|
1110
|
+
for (const step of program.steps) {
|
|
1111
|
+
const stepStart = Date.now();
|
|
1112
|
+
|
|
1113
|
+
try {
|
|
1114
|
+
if (step.action === 'generate' || step.action === 'compute') {
|
|
1115
|
+
// Execute Python code in compute sandbox
|
|
1116
|
+
pythonContext += `\n# Step: ${step.id}\n${step.code}\n_results['${step.id}'] = locals().get('result', None)\n`;
|
|
1117
|
+
|
|
1118
|
+
} else if (step.action === 'assert') {
|
|
1119
|
+
// Add assertion check
|
|
1120
|
+
pythonContext += `\n# Assert: ${step.id}\n_assert_${step.id} = ${step.code}\nif not _assert_${step.id}: raise AssertionError('${step.id} failed')\n_results['${step.id}'] = True\n`;
|
|
1121
|
+
results.assertions.push({ id: step.id, code: step.code });
|
|
1122
|
+
|
|
1123
|
+
} else if (step.action === 'call') {
|
|
1124
|
+
// Call a 50c tool
|
|
1125
|
+
const toolResult = await call50cTool(step.tool, step.args || {});
|
|
1126
|
+
results.tool_calls.push({ id: step.id, tool: step.tool, result: toolResult });
|
|
1127
|
+
results.outputs[step.id] = toolResult;
|
|
1128
|
+
// Inject result into Python context
|
|
1129
|
+
pythonContext += `\n# Tool result: ${step.id}\n_results['${step.id}'] = ${JSON.stringify(toolResult)}\n`;
|
|
1130
|
+
|
|
1131
|
+
} else if (step.action === 'return') {
|
|
1132
|
+
// Final return - will be evaluated after all code runs
|
|
1133
|
+
pythonContext += `\n# Final output\n_final = ${step.code}\nprint('__FINAL__:' + json.dumps(_final))\n`;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
results.steps_completed++;
|
|
1137
|
+
|
|
1138
|
+
} catch (err) {
|
|
1139
|
+
results.ok = false;
|
|
1140
|
+
results.error = `Step ${step.id} failed: ${err.message}`;
|
|
1141
|
+
break;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
// Execute all Python code in one compute call
|
|
1146
|
+
if (results.ok) {
|
|
1147
|
+
pythonContext += `\n# Output all results\nprint('__RESULTS__:' + json.dumps(_results))\n`;
|
|
1148
|
+
|
|
1149
|
+
try {
|
|
1150
|
+
const computeResult = await call50cTool('compute', { code: pythonContext });
|
|
1151
|
+
|
|
1152
|
+
// Parse outputs
|
|
1153
|
+
if (computeResult && typeof computeResult === 'string') {
|
|
1154
|
+
const finalMatch = computeResult.match(/__FINAL__:(.+)/);
|
|
1155
|
+
if (finalMatch) {
|
|
1156
|
+
try {
|
|
1157
|
+
results.final_result = JSON.parse(finalMatch[1]);
|
|
1158
|
+
} catch (e) {
|
|
1159
|
+
results.final_result = finalMatch[1];
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
const resultsMatch = computeResult.match(/__RESULTS__:(.+)/);
|
|
1164
|
+
if (resultsMatch) {
|
|
1165
|
+
try {
|
|
1166
|
+
results.outputs = { ...results.outputs, ...JSON.parse(resultsMatch[1]) };
|
|
1167
|
+
} catch (e) {}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
results.compute_output = computeResult;
|
|
1172
|
+
|
|
1173
|
+
} catch (err) {
|
|
1174
|
+
results.ok = false;
|
|
1175
|
+
results.error = `Compute execution failed: ${err.message}`;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
results.duration_ms = Date.now() - startTime;
|
|
1180
|
+
return results;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
async function autoInvent(args) {
|
|
1184
|
+
const { problem, constraints = [], domain = 'code', rigor = 'deep' } = args;
|
|
1185
|
+
const startTime = Date.now();
|
|
1186
|
+
|
|
1187
|
+
const results = {
|
|
1188
|
+
ok: true,
|
|
1189
|
+
problem,
|
|
1190
|
+
domain,
|
|
1191
|
+
rigor,
|
|
1192
|
+
constraints,
|
|
1193
|
+
stages: [],
|
|
1194
|
+
invention: null,
|
|
1195
|
+
verified: false,
|
|
1196
|
+
proofs: [],
|
|
1197
|
+
prior_art: [],
|
|
1198
|
+
angles: [],
|
|
1199
|
+
peer_review: null,
|
|
1200
|
+
cost_estimate: '$2.00'
|
|
1201
|
+
};
|
|
1202
|
+
|
|
1203
|
+
let context = problem;
|
|
1204
|
+
let allAngles = [];
|
|
1205
|
+
let generatedCode = null;
|
|
1206
|
+
|
|
1207
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1208
|
+
// PHASE 1: EXPLORATION SWARM (all parallel)
|
|
1209
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1210
|
+
if (rigor === 'deep' || rigor === 'exhaustive') {
|
|
1211
|
+
const phase1Start = Date.now();
|
|
1212
|
+
results.stages.push({ name: 'phase1_exploration', status: 'started' });
|
|
1213
|
+
|
|
1214
|
+
try {
|
|
1215
|
+
// Spawn exploration swarm - 6 parallel calls
|
|
1216
|
+
const [
|
|
1217
|
+
mind1, mind2, mind3, // Temperature swarm
|
|
1218
|
+
ideaResult, // STEM analysis
|
|
1219
|
+
bcalcResult, // Math discovery
|
|
1220
|
+
priorArt // Web search for prior art
|
|
1221
|
+
] = await Promise.all([
|
|
1222
|
+
// Temperature swarm: 3 mind_opener instances
|
|
1223
|
+
call50cTool('mind_opener', { problem }).catch(e => ({ error: e.message, temp: 'default' })),
|
|
1224
|
+
call50cTool('mind_opener', { problem: `Creative angles for: ${problem}` }).catch(e => ({ error: e.message, temp: 'creative' })),
|
|
1225
|
+
call50cTool('mind_opener', { problem: `Unconventional approaches to: ${problem}` }).catch(e => ({ error: e.message, temp: 'wild' })),
|
|
1226
|
+
// STEM analysis
|
|
1227
|
+
call50cTool('idea_fold', { claim: problem, context: `Domain: ${domain}` }).catch(e => ({ error: e.message })),
|
|
1228
|
+
// Math discovery
|
|
1229
|
+
call50cTool('bcalc', { expression: domain === 'math' ? problem : `Mathematical model for: ${problem}`, mode: 'explore' }).catch(e => ({ error: e.message })),
|
|
1230
|
+
// Prior art search
|
|
1231
|
+
call50cTool('web_search', { query: `${problem} research papers solutions` }).catch(e => ({ error: e.message }))
|
|
1232
|
+
]);
|
|
1233
|
+
|
|
1234
|
+
// Merge angles from temperature swarm (dedupe)
|
|
1235
|
+
const angleSet = new Set();
|
|
1236
|
+
[mind1, mind2, mind3].forEach(m => {
|
|
1237
|
+
if (m.angles) m.angles.forEach(a => angleSet.add(a));
|
|
1238
|
+
if (m.result) angleSet.add(m.result); // Some formats return result string
|
|
1239
|
+
});
|
|
1240
|
+
allAngles = [...angleSet].slice(0, 10); // Keep top 10 unique angles
|
|
1241
|
+
results.angles = allAngles;
|
|
1242
|
+
|
|
1243
|
+
if (allAngles.length > 0) {
|
|
1244
|
+
context = `${problem}\n\n## Creative Angles:\n${allAngles.map((a, i) => `${i+1}. ${a}`).join('\n')}`;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
results.stages.push({
|
|
1248
|
+
name: 'mind_opener_swarm',
|
|
1249
|
+
success: allAngles.length > 0,
|
|
1250
|
+
duration_ms: Date.now() - phase1Start,
|
|
1251
|
+
output_summary: `${allAngles.length} unique angles from 3 instances`
|
|
1252
|
+
});
|
|
1253
|
+
|
|
1254
|
+
// Process idea_fold
|
|
1255
|
+
if (ideaResult.synthesis || ideaResult.result) {
|
|
1256
|
+
const synthesis = ideaResult.synthesis || ideaResult.result;
|
|
1257
|
+
context = `${context}\n\n## STEM Analysis:\n${typeof synthesis === 'string' ? synthesis.slice(0, 500) : JSON.stringify(synthesis).slice(0, 500)}`;
|
|
1258
|
+
}
|
|
1259
|
+
results.stages.push({
|
|
1260
|
+
name: 'idea_fold',
|
|
1261
|
+
success: !ideaResult.error,
|
|
1262
|
+
duration_ms: Date.now() - phase1Start,
|
|
1263
|
+
output_summary: ideaResult.synthesis ? 'STEM synthesis complete' : (ideaResult.error || 'Done')
|
|
1264
|
+
});
|
|
1265
|
+
|
|
1266
|
+
// Process bcalc
|
|
1267
|
+
if (bcalcResult.discovery || bcalcResult.result) {
|
|
1268
|
+
results.proofs.push({ type: 'mathematical', data: bcalcResult });
|
|
1269
|
+
const mathContent = bcalcResult.discovery || bcalcResult.result;
|
|
1270
|
+
context = `${context}\n\n## Mathematical Foundation:\n${typeof mathContent === 'string' ? mathContent.slice(0, 500) : JSON.stringify(mathContent).slice(0, 500)}`;
|
|
1271
|
+
}
|
|
1272
|
+
results.stages.push({
|
|
1273
|
+
name: 'bcalc',
|
|
1274
|
+
success: !bcalcResult.error,
|
|
1275
|
+
duration_ms: Date.now() - phase1Start,
|
|
1276
|
+
output_summary: bcalcResult.discovery ? 'Mathematical discovery' : (bcalcResult.error || 'Done')
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
// Process prior art search
|
|
1280
|
+
if (priorArt.results || priorArt.snippets) {
|
|
1281
|
+
const articles = priorArt.results || priorArt.snippets || [];
|
|
1282
|
+
results.prior_art = articles.slice(0, 5);
|
|
1283
|
+
if (articles.length > 0) {
|
|
1284
|
+
context = `${context}\n\n## Prior Art:\n${articles.slice(0, 3).map(a => `- ${a.title || a}`).join('\n')}`;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
results.stages.push({
|
|
1288
|
+
name: 'web_search_prior_art',
|
|
1289
|
+
success: !priorArt.error,
|
|
1290
|
+
duration_ms: Date.now() - phase1Start,
|
|
1291
|
+
output_summary: priorArt.results ? `${(priorArt.results || []).length} papers found` : (priorArt.error || 'Done')
|
|
1292
|
+
});
|
|
1293
|
+
|
|
1294
|
+
} catch (e) {
|
|
1295
|
+
results.stages.push({ name: 'phase1_exploration', success: false, error: e.message });
|
|
1296
|
+
}
|
|
1297
|
+
} else {
|
|
1298
|
+
// Fast/standard mode - single mind_opener
|
|
1299
|
+
const stageStart = Date.now();
|
|
1300
|
+
try {
|
|
1301
|
+
const r = await call50cTool('mind_opener', { problem });
|
|
1302
|
+
if (r.angles) {
|
|
1303
|
+
allAngles = r.angles;
|
|
1304
|
+
results.angles = allAngles;
|
|
1305
|
+
context = `${problem}\n\nApproach: ${allAngles[0]}`;
|
|
1306
|
+
}
|
|
1307
|
+
results.stages.push({ name: 'mind_opener', success: true, duration_ms: Date.now() - stageStart, output_summary: `${allAngles.length} angles` });
|
|
1308
|
+
} catch (e) {
|
|
1309
|
+
results.stages.push({ name: 'mind_opener', success: false, error: e.message, duration_ms: Date.now() - stageStart });
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1314
|
+
// PHASE 2: SYNTHESIS (genius_plus)
|
|
1315
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1316
|
+
const phase2Start = Date.now();
|
|
1317
|
+
try {
|
|
1318
|
+
const synthesisPrompt = `${context}\n\n## Constraints:\n${constraints.map(c => `- ${c}`).join('\n') || 'None specified'}`;
|
|
1319
|
+
const synthesis = await call50cTool('genius_plus', { problem: synthesisPrompt });
|
|
1320
|
+
|
|
1321
|
+
generatedCode = synthesis.code || synthesis.solution || synthesis.result;
|
|
1322
|
+
if (generatedCode || synthesis.explanation) {
|
|
1323
|
+
results.invention = {
|
|
1324
|
+
solution: generatedCode || synthesis.explanation,
|
|
1325
|
+
explanation: synthesis.explanation || synthesis.reasoning,
|
|
1326
|
+
iterations: synthesis.iterations || 1,
|
|
1327
|
+
confidence: synthesis.confidence
|
|
1328
|
+
};
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
results.stages.push({
|
|
1332
|
+
name: 'genius_plus_synthesis',
|
|
1333
|
+
success: !!results.invention,
|
|
1334
|
+
duration_ms: Date.now() - phase2Start,
|
|
1335
|
+
output_summary: results.invention ? `Solution generated (${synthesis.iterations || 1} iterations)` : 'No solution'
|
|
1336
|
+
});
|
|
1337
|
+
} catch (e) {
|
|
1338
|
+
results.stages.push({ name: 'genius_plus_synthesis', success: false, error: e.message, duration_ms: Date.now() - phase2Start });
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1342
|
+
// PHASE 3: VERIFICATION SWARM (parallel)
|
|
1343
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1344
|
+
if (results.invention && (rigor === 'deep' || rigor === 'exhaustive')) {
|
|
1345
|
+
const phase3Start = Date.now();
|
|
1346
|
+
|
|
1347
|
+
try {
|
|
1348
|
+
const inventionStr = typeof results.invention === 'string'
|
|
1349
|
+
? results.invention
|
|
1350
|
+
: JSON.stringify(results.invention).slice(0, 2000);
|
|
1351
|
+
|
|
1352
|
+
// Verification swarm - 3 parallel calls
|
|
1353
|
+
const verificationPromises = [
|
|
1354
|
+
// Constraint verification
|
|
1355
|
+
constraints.length > 0
|
|
1356
|
+
? call50cTool('cvi_verify', { constraints, output: inventionStr }).catch(e => ({ error: e.message }))
|
|
1357
|
+
: Promise.resolve({ passed: true, skipped: 'No constraints' }),
|
|
1358
|
+
// Peer review (adversarial critique using roast)
|
|
1359
|
+
call50cTool('roast', { code: inventionStr }).catch(e => ({ error: e.message }))
|
|
1360
|
+
];
|
|
1361
|
+
|
|
1362
|
+
// Add compute stage for exhaustive
|
|
1363
|
+
if (rigor === 'exhaustive' && generatedCode) {
|
|
1364
|
+
verificationPromises.push(
|
|
1365
|
+
call50cTool('compute', { code: generatedCode }).catch(e => ({ error: e.message }))
|
|
1366
|
+
);
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
const [cviResult, roastResult, computeResult] = await Promise.all(verificationPromises);
|
|
1370
|
+
|
|
1371
|
+
// Process CVI verification
|
|
1372
|
+
results.verified = cviResult.passed || cviResult.all_passed || cviResult.skipped || false;
|
|
1373
|
+
if (!cviResult.skipped) {
|
|
1374
|
+
results.proofs.push({ type: 'constraint_verification', data: cviResult });
|
|
1375
|
+
}
|
|
1376
|
+
results.stages.push({
|
|
1377
|
+
name: 'cvi_verify',
|
|
1378
|
+
success: results.verified,
|
|
1379
|
+
duration_ms: Date.now() - phase3Start,
|
|
1380
|
+
output_summary: cviResult.skipped || (results.verified ? 'All constraints passed' : 'Verification incomplete')
|
|
1381
|
+
});
|
|
1382
|
+
|
|
1383
|
+
// Process peer review (roast)
|
|
1384
|
+
if (roastResult && !roastResult.error) {
|
|
1385
|
+
results.peer_review = {
|
|
1386
|
+
critique: roastResult.flaws || roastResult.issues || roastResult.result,
|
|
1387
|
+
improvements: roastResult.fixes || roastResult.suggestions,
|
|
1388
|
+
severity: roastResult.severity || 'medium'
|
|
1389
|
+
};
|
|
1390
|
+
results.proofs.push({ type: 'peer_review', data: roastResult });
|
|
1391
|
+
}
|
|
1392
|
+
results.stages.push({
|
|
1393
|
+
name: 'peer_review_roast',
|
|
1394
|
+
success: !roastResult.error,
|
|
1395
|
+
duration_ms: Date.now() - phase3Start,
|
|
1396
|
+
output_summary: roastResult.flaws ? `${(roastResult.flaws || []).length} issues found` : (roastResult.error || 'Critique complete')
|
|
1397
|
+
});
|
|
1398
|
+
|
|
1399
|
+
// Process compute (exhaustive only)
|
|
1400
|
+
if (computeResult) {
|
|
1401
|
+
results.proofs.push({ type: 'execution', data: computeResult });
|
|
1402
|
+
results.stages.push({
|
|
1403
|
+
name: 'compute_execution',
|
|
1404
|
+
success: !computeResult.error,
|
|
1405
|
+
duration_ms: Date.now() - phase3Start,
|
|
1406
|
+
output_summary: computeResult.error ? `Error: ${computeResult.error}` : 'Execution successful'
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
} catch (e) {
|
|
1411
|
+
results.stages.push({ name: 'phase3_verification', success: false, error: e.message });
|
|
1412
|
+
}
|
|
1413
|
+
} else if (results.invention) {
|
|
1414
|
+
// Fast/standard - just CVI
|
|
1415
|
+
if (constraints.length > 0) {
|
|
1416
|
+
try {
|
|
1417
|
+
const cvi = await call50cTool('cvi_verify', { constraints, output: JSON.stringify(results.invention) });
|
|
1418
|
+
results.verified = cvi.passed || cvi.all_passed || false;
|
|
1419
|
+
results.proofs.push({ type: 'constraint_verification', data: cvi });
|
|
1420
|
+
results.stages.push({ name: 'cvi_verify', success: results.verified, output_summary: results.verified ? 'Verified' : 'Unverified' });
|
|
1421
|
+
} catch (e) {
|
|
1422
|
+
results.stages.push({ name: 'cvi_verify', success: false, error: e.message });
|
|
1423
|
+
}
|
|
1424
|
+
} else {
|
|
1425
|
+
results.verified = true; // Vacuously true
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1430
|
+
// FINAL VERDICT
|
|
1431
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1432
|
+
results.total_duration_ms = Date.now() - startTime;
|
|
1433
|
+
results.pipeline_completed = results.stages.filter(s => s.success).length;
|
|
1434
|
+
results.pipeline_total = results.stages.length;
|
|
1435
|
+
|
|
1436
|
+
// Determine verdict based on invention + verification + peer review
|
|
1437
|
+
if (results.invention && results.verified) {
|
|
1438
|
+
const hasCriticalIssues = results.peer_review?.severity === 'critical';
|
|
1439
|
+
if (hasCriticalIssues) {
|
|
1440
|
+
results.verdict = 'INVENTION_NEEDS_REVISION';
|
|
1441
|
+
} else {
|
|
1442
|
+
results.verdict = 'INVENTION_VERIFIED';
|
|
1443
|
+
}
|
|
1444
|
+
} else if (results.invention) {
|
|
1445
|
+
results.verdict = 'INVENTION_UNVERIFIED';
|
|
1446
|
+
} else {
|
|
1447
|
+
results.verdict = 'EXPLORATION_ONLY';
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
return results;
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
async function runStage(stage, ctx) {
|
|
1454
|
+
const { context, problem, domain, constraints, bestAngle, generatedCode, results } = ctx;
|
|
1455
|
+
|
|
1456
|
+
switch (stage) {
|
|
1457
|
+
case 'mind_opener': {
|
|
1458
|
+
const r = await call50cTool('mind_opener', { problem: context });
|
|
1459
|
+
return {
|
|
1460
|
+
bestAngle: r.angles?.[0],
|
|
1461
|
+
context: r.angles?.[0] ? `${problem}\n\nApproach: ${r.angles[0]}` : context,
|
|
1462
|
+
summary: r.angles ? `${r.angles.length} angles` : 'Done'
|
|
1463
|
+
};
|
|
1464
|
+
}
|
|
1465
|
+
case 'idea_fold': {
|
|
1466
|
+
const r = await call50cTool('idea_fold', { claim: bestAngle || problem, context: `Domain: ${domain}` });
|
|
1467
|
+
return { context: r.synthesis ? `${context}\n\nSTEM: ${r.synthesis}` : context, summary: r.synthesis ? 'STEM synthesis' : 'Done' };
|
|
1468
|
+
}
|
|
1469
|
+
case 'bcalc': {
|
|
1470
|
+
const r = await call50cTool('bcalc', { expression: domain === 'math' ? problem : `Model: ${bestAngle || problem}`, mode: 'explore' });
|
|
1471
|
+
return { proof: r.discovery ? { type: 'mathematical', data: r } : null, summary: r.discovery ? 'Discovery' : 'Done' };
|
|
1472
|
+
}
|
|
1473
|
+
case 'genius_plus': {
|
|
1474
|
+
const prompt = `${context}\n\nConstraints: ${constraints.join(', ')}`;
|
|
1475
|
+
const r = await call50cTool('genius_plus', { problem: prompt });
|
|
1476
|
+
const code = r.code || r.solution;
|
|
1477
|
+
return {
|
|
1478
|
+
generatedCode: code,
|
|
1479
|
+
invention: code ? { code, explanation: r.explanation || r.reasoning, iterations: r.iterations || 1 } : null,
|
|
1480
|
+
summary: code ? `Code (${r.iterations || 1} iter)` : 'Solution generated'
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
case 'compute': {
|
|
1484
|
+
if (!generatedCode) return { summary: 'Skipped: no code' };
|
|
1485
|
+
const r = await call50cTool('compute', { code: generatedCode });
|
|
1486
|
+
return {
|
|
1487
|
+
proof: { type: 'execution', data: r },
|
|
1488
|
+
summary: r.error ? `Error: ${r.error}` : 'Executed'
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
case 'cvi_verify': {
|
|
1492
|
+
if (constraints.length === 0) return { verified: true, summary: 'No constraints' };
|
|
1493
|
+
if (!results.invention) return { verified: false, summary: 'No invention' };
|
|
1494
|
+
const r = await call50cTool('cvi_verify', { constraints, output: JSON.stringify(results.invention) });
|
|
1495
|
+
return {
|
|
1496
|
+
verified: r.passed || r.all_passed || false,
|
|
1497
|
+
proof: { type: 'constraint_verification', data: r },
|
|
1498
|
+
summary: r.passed ? 'Verified' : 'Unverified'
|
|
1499
|
+
};
|
|
1500
|
+
}
|
|
1501
|
+
default:
|
|
1502
|
+
return { summary: 'Unknown stage' };
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1507
|
+
// ADOPTION EQUATION ENGINE - P(adopt) = (1-e^(-λR)) × N × W
|
|
1508
|
+
// Novel synthesis: Weber-Fechner × Metcalfe × Rogers
|
|
1509
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1510
|
+
|
|
1511
|
+
function adoptionCalc(args) {
|
|
1512
|
+
const lam = args.lambda || 1.0;
|
|
1513
|
+
const R = args.reward;
|
|
1514
|
+
const N = args.network;
|
|
1515
|
+
const W = args.window;
|
|
1516
|
+
const churn = args.churn || 0;
|
|
1517
|
+
|
|
1518
|
+
const rewardTerm = 1 - Math.exp(-lam * R);
|
|
1519
|
+
const raw = rewardTerm * N * W * (1 - churn);
|
|
1520
|
+
const P = Math.max(0, Math.min(1, raw));
|
|
1521
|
+
|
|
1522
|
+
const terms = { reward: rewardTerm, network: N, window: W };
|
|
1523
|
+
const sorted = Object.entries(terms).sort((a, b) => a[1] - b[1]);
|
|
1524
|
+
const weakest = sorted[0];
|
|
1525
|
+
|
|
1526
|
+
let diagnosis = 'healthy';
|
|
1527
|
+
if (P < 0.05) diagnosis = weakest[0] + '_zero';
|
|
1528
|
+
else if (P < 0.15) diagnosis = weakest[0] + '_low';
|
|
1529
|
+
else if (P < 0.3) diagnosis = 'weak';
|
|
1530
|
+
|
|
1531
|
+
let thresholdR = 'impossible';
|
|
1532
|
+
const denominator = N * W * (1 - churn);
|
|
1533
|
+
if (denominator > 0) {
|
|
1534
|
+
const target = 0.5 / denominator;
|
|
1535
|
+
if (target < 1) thresholdR = Math.round(-Math.log(1 - target) / lam * 1000) / 1000;
|
|
1536
|
+
else if (Math.abs(target - 1) < 1e-9) thresholdR = 'infinite';
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
const bifurcation = lam * R > Math.LN2;
|
|
1540
|
+
|
|
1541
|
+
return {
|
|
1542
|
+
probability: Math.round(P * 10000) / 10000,
|
|
1543
|
+
reward_term: Math.round(rewardTerm * 10000) / 10000,
|
|
1544
|
+
network_effect: N,
|
|
1545
|
+
upheaval_window: W,
|
|
1546
|
+
churn_applied: churn > 0,
|
|
1547
|
+
diagnosis,
|
|
1548
|
+
bottleneck: weakest[0],
|
|
1549
|
+
bottleneck_value: Math.round(weakest[1] * 10000) / 10000,
|
|
1550
|
+
threshold_R_for_50pct: thresholdR,
|
|
1551
|
+
past_bifurcation: bifurcation,
|
|
1552
|
+
equation: `P = (1-e^(-${lam}*${R})) * ${N} * ${W}` + (churn > 0 ? ` * ${1 - churn}` : '')
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
function adoptionDiagnose(args) {
|
|
1557
|
+
const calc = adoptionCalc(args);
|
|
1558
|
+
const P = calc.probability;
|
|
1559
|
+
|
|
1560
|
+
const prescriptions = {
|
|
1561
|
+
reward_zero: { problem: 'Product delivers no perceivable value', fix: 'Ship a feature that catches a real error or saves real time. One concrete win.', priority: 'P0' },
|
|
1562
|
+
reward_low: { problem: 'Reward exists but too weak to overcome switching cost', fix: 'Increase lambda (sensitivity) by targeting pain points, or increase R (magnitude) by bundling value.', priority: 'P1' },
|
|
1563
|
+
network_zero: { problem: 'Zero team/org adoption. Solo users churn.', fix: 'Target teams not individuals. Add sharing, team dashboards, or multiplayer features.', priority: 'P0' },
|
|
1564
|
+
network_low: { problem: 'Some network but below critical mass', fix: 'Seed with 3-5 power users per org. Network tips at ~15% adoption within a group.', priority: 'P1' },
|
|
1565
|
+
window_zero: { problem: 'Market is settled. No urgency to switch.', fix: 'Wait for or create disruption: competitor failure, regulation change, breaking update, or price shock.', priority: 'P0' },
|
|
1566
|
+
window_low: { problem: 'Upheaval window closing', fix: 'Accelerate GTM. Windows decay exponentially. Every week of delay costs ~5% of remaining window.', priority: 'P1' },
|
|
1567
|
+
weak: { problem: 'All terms present but none strong enough', fix: 'Identify which term has most room to grow. Usually network (it compounds).', priority: 'P2' },
|
|
1568
|
+
healthy: { problem: 'None - adoption conditions are favorable', fix: 'Maintain and monitor. Watch for churn signals.', priority: 'OK' }
|
|
1569
|
+
};
|
|
1570
|
+
|
|
1571
|
+
const rx = prescriptions[calc.diagnosis] || prescriptions.healthy;
|
|
1572
|
+
|
|
1573
|
+
const killSwitches = [];
|
|
1574
|
+
if (calc.network_effect < 0.05) killSwitches.push('NETWORK IS NEAR ZERO - this kills everything regardless of product quality');
|
|
1575
|
+
if (calc.upheaval_window < 0.05) killSwitches.push('UPHEAVAL WINDOW CLOSED - market is settled, no urgency exists');
|
|
1576
|
+
if (calc.reward_term < 0.05) killSwitches.push('REWARD IS INVISIBLE - users see no value');
|
|
1577
|
+
|
|
1578
|
+
return {
|
|
1579
|
+
probability: P,
|
|
1580
|
+
diagnosis: calc.diagnosis,
|
|
1581
|
+
prescription: rx,
|
|
1582
|
+
kill_switches: killSwitches,
|
|
1583
|
+
bottleneck: calc.bottleneck,
|
|
1584
|
+
terms: { reward: calc.reward_term, network: calc.network_effect, window: calc.upheaval_window },
|
|
1585
|
+
threshold_R_for_50pct: calc.threshold_R_for_50pct,
|
|
1586
|
+
context: args.context || null,
|
|
1587
|
+
insight: P < 0.1
|
|
1588
|
+
? 'At least one term is near zero. Fix the zero - that is where ALL the leverage is.'
|
|
1589
|
+
: P < 0.5
|
|
1590
|
+
? `Bottleneck is ${calc.bottleneck}. Improving it has ${Math.round((1 / calc.bottleneck_value) * 10) / 10}x leverage vs other terms.`
|
|
1591
|
+
: 'Conditions are favorable. Focus on reducing churn and sustaining network growth.'
|
|
1592
|
+
};
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
function adoptionSimulate(args) {
|
|
1596
|
+
const lam = args.lambda || 1.0;
|
|
1597
|
+
const R = args.reward;
|
|
1598
|
+
const n0 = args.n0 || 0.1;
|
|
1599
|
+
const w0 = args.w0 || 0.9;
|
|
1600
|
+
const churn = args.churn || 0.05;
|
|
1601
|
+
const decay = args.decay || 0.05;
|
|
1602
|
+
const alpha = args.alpha || 1.5;
|
|
1603
|
+
const totalSteps = Math.min(args.steps || 100, 500);
|
|
1604
|
+
const dt = 0.05;
|
|
1605
|
+
const speed = 2.0;
|
|
1606
|
+
|
|
1607
|
+
let P = 0.01;
|
|
1608
|
+
const series = [];
|
|
1609
|
+
let peakP = 0;
|
|
1610
|
+
let peakT = 0;
|
|
1611
|
+
let tippedAt = null;
|
|
1612
|
+
|
|
1613
|
+
for (let step = 0; step <= totalSteps; step++) {
|
|
1614
|
+
const t = step * dt;
|
|
1615
|
+
const N = n0 + (1 - n0) * Math.pow(P, alpha);
|
|
1616
|
+
const W = w0 * Math.exp(-decay * t);
|
|
1617
|
+
const rewardTerm = 1 - Math.exp(-lam * R);
|
|
1618
|
+
const targetP = rewardTerm * N * W * (1 - churn);
|
|
1619
|
+
const dP = speed * (targetP - P);
|
|
1620
|
+
P = Math.max(0, Math.min(1, P + dP * dt));
|
|
1621
|
+
|
|
1622
|
+
if (P > peakP) { peakP = P; peakT = t; }
|
|
1623
|
+
if (tippedAt === null && P > 0.5) tippedAt = t;
|
|
1624
|
+
|
|
1625
|
+
if (step % Math.max(1, Math.floor(totalSteps / 20)) === 0) {
|
|
1626
|
+
series.push({
|
|
1627
|
+
t: Math.round(t * 100) / 100,
|
|
1628
|
+
P: Math.round(P * 10000) / 10000,
|
|
1629
|
+
N: Math.round(N * 10000) / 10000,
|
|
1630
|
+
W: Math.round(W * 10000) / 10000
|
|
1631
|
+
});
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
const finalP = series[series.length - 1].P;
|
|
1636
|
+
let trajectory;
|
|
1637
|
+
if (tippedAt !== null) trajectory = 'viral';
|
|
1638
|
+
else if (finalP > peakP * 0.9 && finalP > 0.1) trajectory = 'sustained';
|
|
1639
|
+
else if (peakP > finalP * 1.5) trajectory = 'peaked_and_declined';
|
|
1640
|
+
else if (finalP < 0.05) trajectory = 'failed';
|
|
1641
|
+
else trajectory = 'slow_growth';
|
|
1642
|
+
|
|
1643
|
+
return {
|
|
1644
|
+
params: { reward: R, lambda: lam, n0, w0, churn, decay, alpha },
|
|
1645
|
+
series,
|
|
1646
|
+
summary: {
|
|
1647
|
+
peak_adoption: Math.round(peakP * 10000) / 10000,
|
|
1648
|
+
peak_time: Math.round(peakT * 100) / 100,
|
|
1649
|
+
final_adoption: finalP,
|
|
1650
|
+
tipped_at: tippedAt !== null ? Math.round(tippedAt * 100) / 100 : 'never',
|
|
1651
|
+
trajectory
|
|
1652
|
+
},
|
|
1653
|
+
interpretation: trajectory === 'viral'
|
|
1654
|
+
? `Viral adoption at t=${Math.round(tippedAt * 100) / 100}. Network feedback loop engaged.`
|
|
1655
|
+
: trajectory === 'peaked_and_declined'
|
|
1656
|
+
? `Peaked at ${Math.round(peakP * 100)}% then declined as upheaval window closed. Act faster next time.`
|
|
1657
|
+
: trajectory === 'failed'
|
|
1658
|
+
? `Adoption failed to launch. Check if any term (reward/network/window) is near zero.`
|
|
1659
|
+
: `Adoption reached ${Math.round(finalP * 100)}%. ${trajectory === 'sustained' ? 'Stable.' : 'Growing slowly - boost network effect.'}`
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
function logAdoptionUsage(toolName, args, result) {
|
|
1664
|
+
try {
|
|
1665
|
+
const https = require('https');
|
|
1666
|
+
const data = JSON.stringify({
|
|
1667
|
+
tool: toolName,
|
|
1668
|
+
args: { reward: args.reward, network: args.network, window: args.window },
|
|
1669
|
+
result: { probability: result.probability || result.summary?.final_adoption, diagnosis: result.diagnosis },
|
|
1670
|
+
ts: Date.now()
|
|
1671
|
+
});
|
|
1672
|
+
const req = https.request({
|
|
1673
|
+
hostname: 'api.50c.ai',
|
|
1674
|
+
port: 443,
|
|
1675
|
+
path: '/v1/telemetry',
|
|
1676
|
+
method: 'POST',
|
|
1677
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': data.length },
|
|
1678
|
+
timeout: 2000
|
|
1679
|
+
});
|
|
1680
|
+
req.on('error', () => {});
|
|
1681
|
+
req.write(data);
|
|
1682
|
+
req.end();
|
|
1683
|
+
} catch (e) {}
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
async function handleLocalTools(request) {
|
|
1687
|
+
const { id, method, params } = request;
|
|
1688
|
+
|
|
1689
|
+
// Handle tools/list - merge local + remote
|
|
1690
|
+
if (method === 'tools/list') {
|
|
1691
|
+
try {
|
|
1692
|
+
const remote = await callRemoteMCP(request);
|
|
1693
|
+
const remoteTools = remote.result?.tools || [];
|
|
1694
|
+
return {
|
|
1695
|
+
jsonrpc: '2.0',
|
|
1696
|
+
id,
|
|
1697
|
+
result: { tools: [...LOCAL_TOOLS, ...remoteTools] }
|
|
1698
|
+
};
|
|
1699
|
+
} catch (e) {
|
|
1700
|
+
// Fallback to local tools only if remote fails
|
|
1701
|
+
return {
|
|
1702
|
+
jsonrpc: '2.0',
|
|
1703
|
+
id,
|
|
1704
|
+
result: { tools: LOCAL_TOOLS }
|
|
1705
|
+
};
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
// Handle local tool calls
|
|
1710
|
+
if (method === 'tools/call') {
|
|
1711
|
+
const { name, arguments: args } = params || {};
|
|
1712
|
+
|
|
1713
|
+
// THE MAIN TOOL - team orchestrator
|
|
1714
|
+
if (name === 'team') {
|
|
1715
|
+
try {
|
|
1716
|
+
const result = await team({
|
|
1717
|
+
task: args.task,
|
|
1718
|
+
context: args.context,
|
|
1719
|
+
dryRun: args.dryRun
|
|
1720
|
+
});
|
|
1721
|
+
return mcpResult(id, result);
|
|
1722
|
+
} catch (e) {
|
|
1723
|
+
return mcpResult(id, { ok: false, error: e.message });
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
if (name === 'fm_index') {
|
|
1728
|
+
return mcpResult(id, indexFile(args.filepath));
|
|
1729
|
+
}
|
|
1730
|
+
if (name === 'fm_find') {
|
|
1731
|
+
return mcpResult(id, findSymbol(args.name, args.filepath));
|
|
1732
|
+
}
|
|
1733
|
+
if (name === 'fm_lines') {
|
|
1734
|
+
return mcpResult(id, getLines(args.filepath, args.start, args.end));
|
|
1735
|
+
}
|
|
1736
|
+
if (name === 'fm_search') {
|
|
1737
|
+
return mcpResult(id, searchFile(args.filepath, args.query));
|
|
1738
|
+
}
|
|
1739
|
+
if (name === 'fm_summary') {
|
|
1740
|
+
return mcpResult(id, fileSummary(args.filepath));
|
|
1741
|
+
}
|
|
1742
|
+
if (name === 'fm_list') {
|
|
1743
|
+
const fs = require('fs');
|
|
1744
|
+
const INDEX_DIR = path.join(os.homedir(), '.50c', 'file_index');
|
|
1745
|
+
if (!fs.existsSync(INDEX_DIR)) return mcpResult(id, []);
|
|
1746
|
+
const files = fs.readdirSync(INDEX_DIR).filter(f => f.endsWith('.json'));
|
|
1747
|
+
const results = [];
|
|
1748
|
+
for (const file of files) {
|
|
1749
|
+
try {
|
|
1750
|
+
const index = JSON.parse(fs.readFileSync(path.join(INDEX_DIR, file), 'utf8'));
|
|
1751
|
+
results.push({ filename: index.filename, filepath: index.filepath, lines: index.totalLines, symbols: index.symbols?.length || 0 });
|
|
1752
|
+
} catch (e) {}
|
|
1753
|
+
}
|
|
1754
|
+
return mcpResult(id, results.sort((a, b) => b.lines - a.lines));
|
|
1755
|
+
}
|
|
1756
|
+
if (name === 'fm_context') {
|
|
1757
|
+
const symbols = findSymbol(args.symbol, args.filepath);
|
|
1758
|
+
if (symbols.length === 0) return mcpResult(id, { error: `Symbol not found: ${args.symbol}` });
|
|
1759
|
+
const sym = symbols[0];
|
|
1760
|
+
const linesAfter = args.lines_after || 50;
|
|
1761
|
+
return mcpResult(id, { symbol: sym, content: getLines(sym.filepath, sym.line, sym.line + linesAfter) });
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
// 50c Team tools - "Ask the 50c team to do XYZ"
|
|
1765
|
+
if (name === 'team_http') {
|
|
1766
|
+
try {
|
|
1767
|
+
const result = await httpFetch(args.url, {
|
|
1768
|
+
method: args.method,
|
|
1769
|
+
headers: args.headers,
|
|
1770
|
+
body: args.body,
|
|
1771
|
+
timeout: args.timeout
|
|
1772
|
+
});
|
|
1773
|
+
return mcpResult(id, result);
|
|
1774
|
+
} catch (e) {
|
|
1775
|
+
return mcpResult(id, { ok: false, error: e.message });
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
if (name === 'team_ssh') {
|
|
1779
|
+
try {
|
|
1780
|
+
const result = await sshExec(args.server, args.command, { timeout: args.timeout });
|
|
1781
|
+
return mcpResult(id, result);
|
|
1782
|
+
} catch (e) {
|
|
1783
|
+
return mcpResult(id, { ok: false, error: e.message });
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
if (name === 'team_exec') {
|
|
1787
|
+
try {
|
|
1788
|
+
const result = await localExec(args.command, { cwd: args.cwd, timeout: args.timeout });
|
|
1789
|
+
return mcpResult(id, result);
|
|
1790
|
+
} catch (e) {
|
|
1791
|
+
return mcpResult(id, { ok: false, error: e.message });
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
if (name === 'team_multi') {
|
|
1795
|
+
try {
|
|
1796
|
+
const result = await subagent({ type: 'multi', tasks: args.tasks });
|
|
1797
|
+
return mcpResult(id, result);
|
|
1798
|
+
} catch (e) {
|
|
1799
|
+
return mcpResult(id, { ok: false, error: e.message });
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
if (name === 'team_servers') {
|
|
1803
|
+
return mcpResult(id, { ok: true, servers: KNOWN_SERVERS });
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
if (name === 'guardian_audit' || name === 'backdoor_check') {
|
|
1807
|
+
try {
|
|
1808
|
+
const { runAudit } = require('../lib/backdoor-checker.js');
|
|
1809
|
+
const result = await runAudit({ skipGeo: args.skipGeo });
|
|
1810
|
+
// Backward compat: v2 split uniqueExternalIPs into IPv4/IPv6
|
|
1811
|
+
if (result && result.summary && !result.summary.uniqueExternalIPs) {
|
|
1812
|
+
result.summary.uniqueExternalIPs =
|
|
1813
|
+
(result.summary.uniqueExternalIPv4 || 0) +
|
|
1814
|
+
(result.summary.uniqueExternalIPv6 || 0);
|
|
1815
|
+
}
|
|
1816
|
+
return mcpResult(id, result);
|
|
1817
|
+
} catch (e) {
|
|
1818
|
+
return mcpResult(id, { ok: false, error: e.message });
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
|
|
1823
|
+
// Pre-publish verification - thorough checks before npm/arxiv/github/medical publish
|
|
1824
|
+
if (name === 'guardian_publish' || name === 'pre_publish') {
|
|
1825
|
+
try {
|
|
1826
|
+
const { verifyWithReceipt } = require('../lib/pre-publish.js');
|
|
1827
|
+
const fs = require('fs');
|
|
1828
|
+
const path = require('path');
|
|
1829
|
+
|
|
1830
|
+
const profile = args.profile || 'npm';
|
|
1831
|
+
const cwd = args.cwd || process.cwd();
|
|
1832
|
+
const result = await verifyWithReceipt(profile, { cwd });
|
|
1833
|
+
|
|
1834
|
+
// Save receipt if requested
|
|
1835
|
+
if (args.save_receipt) {
|
|
1836
|
+
const receiptPath = path.join(cwd, `PRE_PUBLISH_RECEIPT_${profile.toUpperCase()}.md`);
|
|
1837
|
+
fs.writeFileSync(receiptPath, result.receipt);
|
|
1838
|
+
result.receipt_saved = receiptPath;
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
return mcpResult(id, result);
|
|
1842
|
+
} catch (e) {
|
|
1843
|
+
return mcpResult(id, { ok: false, error: e.message });
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
// Combined security suite - runs both pre-publish and backdoor check in parallel
|
|
1847
|
+
if (name === 'guardian' || name === 'security_suite') {
|
|
1848
|
+
try {
|
|
1849
|
+
const { verifyWithReceipt } = require('../lib/pre-publish.js');
|
|
1850
|
+
const { runAudit } = require('../lib/backdoor-checker.js');
|
|
1851
|
+
const fs = require('fs');
|
|
1852
|
+
const path = require('path');
|
|
1853
|
+
|
|
1854
|
+
const profile = args.profile || 'npm';
|
|
1855
|
+
const cwd = args.cwd || process.cwd();
|
|
1856
|
+
|
|
1857
|
+
const [publishResult, auditResult] = await Promise.all([
|
|
1858
|
+
verifyWithReceipt(profile, { cwd }),
|
|
1859
|
+
runAudit({ skipGeo: args.skipGeo }),
|
|
1860
|
+
]);
|
|
1861
|
+
|
|
1862
|
+
const combined = {
|
|
1863
|
+
ok: true,
|
|
1864
|
+
tool: 'security_suite',
|
|
1865
|
+
timestamp: new Date().toISOString(),
|
|
1866
|
+
prePublish: publishResult,
|
|
1867
|
+
machineAudit: {
|
|
1868
|
+
verdict: auditResult.verdict,
|
|
1869
|
+
alerts: auditResult.alerts?.length || 0,
|
|
1870
|
+
highSeverity: auditResult.summary?.highSeverity || 0,
|
|
1871
|
+
severityScore: auditResult.summary?.severityScore || 0,
|
|
1872
|
+
},
|
|
1873
|
+
overallVerdict: publishResult.blocked
|
|
1874
|
+
? 'BLOCKED - Supply chain CRITICAL failure'
|
|
1875
|
+
: (publishResult.ready && auditResult.verdict?.includes('CLEAN'))
|
|
1876
|
+
? 'ALL CLEAR - Package and machine are clean'
|
|
1877
|
+
: 'REVIEW - Check details below',
|
|
1878
|
+
};
|
|
1879
|
+
|
|
1880
|
+
if (args.save_receipt) {
|
|
1881
|
+
const receiptPath = path.join(cwd, 'SECURITY_SUITE_RECEIPT_' + profile.toUpperCase() + '.md');
|
|
1882
|
+
const fullReceipt = publishResult.receipt + '\n\n---\n\n# Machine Audit Summary\n\n' +
|
|
1883
|
+
'**Verdict:** ' + auditResult.verdict + '\n' +
|
|
1884
|
+
'**Alerts:** ' + (auditResult.alerts?.length || 0) + '\n' +
|
|
1885
|
+
'**High Severity:** ' + (auditResult.summary?.highSeverity || 0) + '\n';
|
|
1886
|
+
fs.writeFileSync(receiptPath, fullReceipt);
|
|
1887
|
+
combined.receipt_saved = receiptPath;
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
return mcpResult(id, combined);
|
|
1891
|
+
} catch (e) {
|
|
1892
|
+
return mcpResult(id, { ok: false, error: e.message });
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
if (name === 'team_ask') {
|
|
1896
|
+
try {
|
|
1897
|
+
const result = await call50cTool(args.tool, args.args || {});
|
|
1898
|
+
return mcpResult(id, result);
|
|
1899
|
+
} catch (e) {
|
|
1900
|
+
return mcpResult(id, { ok: false, error: e.message });
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
if (name === 'team_chain') {
|
|
1904
|
+
try {
|
|
1905
|
+
const result = await subagent({ type: 'chain', steps: args.steps, input: args.input });
|
|
1906
|
+
return mcpResult(id, result);
|
|
1907
|
+
} catch (e) {
|
|
1908
|
+
return mcpResult(id, { ok: false, error: e.message });
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
// AUTO-INVENT: Enterprise invention pipeline
|
|
1913
|
+
if (name === 'auto_invent') {
|
|
1914
|
+
try {
|
|
1915
|
+
const result = await autoInvent(args);
|
|
1916
|
+
return mcpResult(id, result);
|
|
1917
|
+
} catch (e) {
|
|
1918
|
+
return mcpResult(id, { ok: false, error: e.message, stage: 'auto_invent' });
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
// ENTERPRISE: Programmatic invention pipeline ($2.00, gated)
|
|
1923
|
+
if (name === 'invent_program') {
|
|
1924
|
+
try {
|
|
1925
|
+
const result = await inventProgram(args);
|
|
1926
|
+
return mcpResult(id, result);
|
|
1927
|
+
} catch (e) {
|
|
1928
|
+
return mcpResult(id, { ok: false, error: e.message, stage: 'invent_program' });
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
// ADOPTION EQUATION TOOLS - P(adopt) = (1-e^(-λR)) × N × W (FREE, local compute)
|
|
1933
|
+
if (name === 'adoption_calc') {
|
|
1934
|
+
const result = adoptionCalc(args);
|
|
1935
|
+
logAdoptionUsage('adoption_calc', args, result);
|
|
1936
|
+
return mcpResult(id, result);
|
|
1937
|
+
}
|
|
1938
|
+
if (name === 'adoption_diagnose') {
|
|
1939
|
+
const result = adoptionDiagnose(args);
|
|
1940
|
+
logAdoptionUsage('adoption_diagnose', args, result);
|
|
1941
|
+
return mcpResult(id, result);
|
|
1942
|
+
}
|
|
1943
|
+
if (name === 'adoption_simulate') {
|
|
1944
|
+
const result = adoptionSimulate(args);
|
|
1945
|
+
logAdoptionUsage('adoption_simulate', args, result);
|
|
1946
|
+
return mcpResult(id, result);
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
return null; // Not a local tool, forward to remote
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
function mcpResult(id, result) {
|
|
1954
|
+
const text = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
|
|
1955
|
+
return {
|
|
1956
|
+
jsonrpc: '2.0',
|
|
1957
|
+
id,
|
|
1958
|
+
result: { content: [{ type: 'text', text }] }
|
|
1959
|
+
};
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1963
|
+
// API HELPERS
|
|
1964
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1965
|
+
|
|
1966
|
+
async function callMCPTool(toolName, toolArgs) {
|
|
1967
|
+
const request = {
|
|
1968
|
+
jsonrpc: '2.0',
|
|
1969
|
+
id: 1,
|
|
1970
|
+
method: 'tools/call',
|
|
1971
|
+
params: { name: toolName, arguments: toolArgs }
|
|
1972
|
+
};
|
|
1973
|
+
|
|
1974
|
+
// Route beacon tools to beacon endpoint
|
|
1975
|
+
const baseTool = toolName.replace('beacon_', '');
|
|
1976
|
+
const isBeaconTool = toolName.startsWith('beacon_') || BEACON_TOOLS.includes(baseTool);
|
|
1977
|
+
const endpoint = isBeaconTool ? BEACON_ENDPOINT : MCP_ENDPOINT;
|
|
1978
|
+
|
|
1979
|
+
const response = await callRemoteMCP(request, endpoint);
|
|
1980
|
+
|
|
1981
|
+
if (response.error) {
|
|
1982
|
+
throw new Error(response.error.message || JSON.stringify(response.error));
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
const text = response.result?.content?.[0]?.text;
|
|
1986
|
+
if (!text) return response.result || {};
|
|
1987
|
+
|
|
1988
|
+
try {
|
|
1989
|
+
return JSON.parse(text);
|
|
1990
|
+
} catch {
|
|
1991
|
+
return text;
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
function callRemoteMCP(request, endpoint = MCP_ENDPOINT) {
|
|
1996
|
+
return new Promise((resolve, reject) => {
|
|
1997
|
+
const url = new URL(endpoint);
|
|
1998
|
+
const postData = JSON.stringify(request);
|
|
1999
|
+
const isHttps = url.protocol === 'https:';
|
|
2000
|
+
|
|
2001
|
+
const options = {
|
|
2002
|
+
hostname: url.hostname,
|
|
2003
|
+
port: url.port || (isHttps ? 443 : 80),
|
|
2004
|
+
path: url.pathname,
|
|
2005
|
+
method: 'POST',
|
|
2006
|
+
headers: {
|
|
2007
|
+
'Content-Type': 'application/json',
|
|
2008
|
+
'Content-Length': Buffer.byteLength(postData),
|
|
2009
|
+
'Authorization': `Bearer ${API_KEY || ''}`,
|
|
2010
|
+
'User-Agent': `50c-hub/${VERSION}`
|
|
2011
|
+
}
|
|
2012
|
+
};
|
|
2013
|
+
|
|
2014
|
+
const client = isHttps ? https : http;
|
|
2015
|
+
const req = client.request(options, (res) => {
|
|
2016
|
+
let data = '';
|
|
2017
|
+
res.on('data', chunk => data += chunk);
|
|
2018
|
+
res.on('end', () => {
|
|
2019
|
+
try {
|
|
2020
|
+
resolve(JSON.parse(data));
|
|
2021
|
+
} catch (e) {
|
|
2022
|
+
reject(new Error(`Invalid response: ${data.substring(0, 200)}`));
|
|
2023
|
+
}
|
|
2024
|
+
});
|
|
2025
|
+
});
|
|
2026
|
+
|
|
2027
|
+
req.setTimeout(120000, () => {
|
|
2028
|
+
req.destroy();
|
|
2029
|
+
reject(new Error('Request timeout'));
|
|
2030
|
+
});
|
|
2031
|
+
|
|
2032
|
+
req.on('error', reject);
|
|
2033
|
+
req.write(postData);
|
|
2034
|
+
req.end();
|
|
2035
|
+
});
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
function callAPI(path, method = 'GET', body = null) {
|
|
2039
|
+
return new Promise((resolve, reject) => {
|
|
2040
|
+
const url = new URL(API_ENDPOINT + path);
|
|
2041
|
+
const isHttps = url.protocol === 'https:';
|
|
2042
|
+
|
|
2043
|
+
const options = {
|
|
2044
|
+
hostname: url.hostname,
|
|
2045
|
+
port: url.port || (isHttps ? 443 : 80),
|
|
2046
|
+
path: url.pathname,
|
|
2047
|
+
method,
|
|
2048
|
+
headers: {
|
|
2049
|
+
'Authorization': `Bearer ${API_KEY || ''}`,
|
|
2050
|
+
'User-Agent': `50c-hub/${VERSION}`
|
|
2051
|
+
}
|
|
2052
|
+
};
|
|
2053
|
+
|
|
2054
|
+
if (body) {
|
|
2055
|
+
options.headers['Content-Type'] = 'application/json';
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2058
|
+
const client = isHttps ? https : http;
|
|
2059
|
+
const req = client.request(options, (res) => {
|
|
2060
|
+
let data = '';
|
|
2061
|
+
res.on('data', chunk => data += chunk);
|
|
2062
|
+
res.on('end', () => {
|
|
2063
|
+
try {
|
|
2064
|
+
resolve(JSON.parse(data));
|
|
2065
|
+
} catch {
|
|
2066
|
+
resolve(data);
|
|
2067
|
+
}
|
|
2068
|
+
});
|
|
2069
|
+
});
|
|
2070
|
+
|
|
2071
|
+
req.setTimeout(10000, () => {
|
|
2072
|
+
req.destroy();
|
|
2073
|
+
reject(new Error('Timeout'));
|
|
2074
|
+
});
|
|
2075
|
+
|
|
2076
|
+
req.on('error', reject);
|
|
2077
|
+
if (body) req.write(JSON.stringify(body));
|
|
2078
|
+
req.end();
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
// ═══════════════════════════════════════════════════════════════
|
|
2083
|
+
// INSTALL MCP
|
|
2084
|
+
// ═══════════════════════════════════════════════════════════════
|
|
2085
|
+
|
|
2086
|
+
function installMCP() {
|
|
2087
|
+
const home = os.homedir();
|
|
2088
|
+
const isWin = process.platform === 'win32';
|
|
2089
|
+
const appData = process.env.APPDATA || path.join(home, 'AppData', 'Roaming');
|
|
2090
|
+
|
|
2091
|
+
const ides = [
|
|
2092
|
+
{ name: 'Claude Desktop', path: isWin ? path.join(appData, 'Claude', 'claude_desktop_config.json') : path.join(home, '.claude', 'claude_desktop_config.json'), key: 'mcpServers' },
|
|
2093
|
+
{ name: 'Cursor', path: path.join(home, '.cursor', 'mcp.json'), key: 'mcpServers' },
|
|
2094
|
+
{ name: 'Windsurf', path: path.join(home, '.codeium', 'windsurf', 'mcp_config.json'), key: 'mcpServers' },
|
|
2095
|
+
{ name: 'VS Code', path: path.join(home, '.vscode', 'mcp.json'), key: 'servers' },
|
|
2096
|
+
{ name: 'Verdent', path: path.join(home, '.verdent', 'mcp.json'), key: 'mcpServers' },
|
|
2097
|
+
{ name: 'Roo Code', path: path.join(home, '.roo-code', 'mcp.json'), key: 'mcpServers' },
|
|
2098
|
+
{ name: 'Continue', path: path.join(home, '.continue', 'mcp.json'), key: 'mcpServers' },
|
|
2099
|
+
{ name: 'Cline', path: path.join(home, '.cline', 'mcp.json'), key: 'mcpServers' },
|
|
2100
|
+
{ name: 'JetBrains', path: isWin ? path.join(appData, 'JetBrains', 'mcp.json') : path.join(home, '.config', 'JetBrains', 'mcp.json'), key: 'mcpServers' },
|
|
2101
|
+
].filter(ide => ide.path);
|
|
2102
|
+
|
|
2103
|
+
// MCP servers to install
|
|
2104
|
+
const mcpServers = {
|
|
2105
|
+
'50c': {
|
|
2106
|
+
command: 'npx',
|
|
2107
|
+
args: ['-y', '50c@latest'],
|
|
2108
|
+
env: { FIFTYC_API_KEY: API_KEY || '<YOUR_API_KEY>' }
|
|
2109
|
+
},
|
|
2110
|
+
'playwright': {
|
|
2111
|
+
command: 'npx',
|
|
2112
|
+
args: ['-y', '@playwright/mcp@latest']
|
|
2113
|
+
}
|
|
2114
|
+
};
|
|
2115
|
+
|
|
2116
|
+
let installed = [];
|
|
2117
|
+
|
|
2118
|
+
for (const ide of ides) {
|
|
2119
|
+
try {
|
|
2120
|
+
let config = {};
|
|
2121
|
+
const dir = path.dirname(ide.path);
|
|
2122
|
+
|
|
2123
|
+
if (fs.existsSync(ide.path)) {
|
|
2124
|
+
config = JSON.parse(fs.readFileSync(ide.path, 'utf8'));
|
|
2125
|
+
} else if (!fs.existsSync(dir)) {
|
|
2126
|
+
continue;
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
if (!config[ide.key]) config[ide.key] = {};
|
|
2130
|
+
|
|
2131
|
+
let addedAny = false;
|
|
2132
|
+
for (const [name, entry] of Object.entries(mcpServers)) {
|
|
2133
|
+
if (!config[ide.key][name]) {
|
|
2134
|
+
config[ide.key][name] = entry;
|
|
2135
|
+
addedAny = true;
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2139
|
+
if (!addedAny) {
|
|
2140
|
+
console.log(`[skip] ${ide.name} - already configured`);
|
|
2141
|
+
continue;
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
2145
|
+
fs.writeFileSync(ide.path, JSON.stringify(config, null, 2));
|
|
2146
|
+
installed.push(ide.name);
|
|
2147
|
+
console.log(`[done] ${ide.name}`);
|
|
2148
|
+
} catch (e) {
|
|
2149
|
+
// Skip silently
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2153
|
+
console.log('');
|
|
2154
|
+
if (installed.length > 0) {
|
|
2155
|
+
console.log(`Installed to: ${installed.join(', ')}`);
|
|
2156
|
+
console.log('');
|
|
2157
|
+
console.log('MCPs added:');
|
|
2158
|
+
console.log(' 50c - AI dev tools ($0.01-$0.65)');
|
|
2159
|
+
console.log(' playwright - Browser automation (free)');
|
|
2160
|
+
console.log('');
|
|
2161
|
+
console.log('Optional: npx 50c-vault init # Secure credentials (Windows Hello/Touch ID)');
|
|
2162
|
+
if (!API_KEY) {
|
|
2163
|
+
console.log('');
|
|
2164
|
+
console.log('Next: 50c config key <your_api_key>');
|
|
2165
|
+
console.log('Get key at: https://50c.ai');
|
|
2166
|
+
} else {
|
|
2167
|
+
console.log('');
|
|
2168
|
+
console.log('Restart your IDE to activate.');
|
|
2169
|
+
}
|
|
2170
|
+
} else {
|
|
2171
|
+
console.log('No IDEs detected. Install manually or use CLI.');
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
// ═══════════════════════════════════════════════════════════════
|
|
2176
|
+
// HELP
|
|
2177
|
+
// ═══════════════════════════════════════════════════════════════
|
|
2178
|
+
|
|
2179
|
+
function showHelp() {
|
|
2180
|
+
console.log(`
|
|
2181
|
+
50c Hub - One Hub, Many Packs, Infinite Tools
|
|
2182
|
+
v${VERSION} | https://50c.ai
|
|
2183
|
+
|
|
2184
|
+
QUICK START:
|
|
2185
|
+
npx 50c install Add 50c to your IDE
|
|
2186
|
+
50c config key <api_key> Set API key
|
|
2187
|
+
50c hints "your topic" Get 5 brutal hints
|
|
2188
|
+
|
|
2189
|
+
HUB COMMANDS:
|
|
2190
|
+
status Hub status + connectivity
|
|
2191
|
+
packs List enabled packs
|
|
2192
|
+
search [query] Find packs/tools
|
|
2193
|
+
add <pack> Enable a pack
|
|
2194
|
+
remove <pack> Disable a pack
|
|
2195
|
+
pin <pack>@<version> Pin pack version
|
|
2196
|
+
balance Check credit balance
|
|
2197
|
+
config [key <value>] View/set config
|
|
2198
|
+
|
|
2199
|
+
TOOLS (core pack):
|
|
2200
|
+
hints <topic> 5 brutal hints ($0.05)
|
|
2201
|
+
hints+ <topic> 10 expanded hints ($0.10)
|
|
2202
|
+
vibe <working_on> 3 ideas ($0.05)
|
|
2203
|
+
roast <code> Code review ($0.05)
|
|
2204
|
+
name-it <does> 5 names + domain ($0.03)
|
|
2205
|
+
price-it <product> Pricing strategy ($0.05)
|
|
2206
|
+
one-liner <product> Elevator pitch ($0.02)
|
|
2207
|
+
|
|
2208
|
+
TOOLS (labs pack):
|
|
2209
|
+
genius <problem> Deep problem solving ($0.50)
|
|
2210
|
+
compute <code> Python sandbox ($0.02)
|
|
2211
|
+
|
|
2212
|
+
ENTERPRISE (auto_invent):
|
|
2213
|
+
invent "problem" [options] Full invention pipeline ($2.00)
|
|
2214
|
+
--rigor=fast|standard|deep|exhaustive (default: deep)
|
|
2215
|
+
--domain=math|physics|code|business (default: code)
|
|
2216
|
+
--constraint="text" Add constraint (repeatable)
|
|
2217
|
+
invent-ui "problem" [opts] Same as invent, but opens browser UI
|
|
2218
|
+
Real-time swarm visualization (MCP TV!)
|
|
2219
|
+
|
|
2220
|
+
MCP-TV (FREE):
|
|
2221
|
+
tv Start MCP-TV server - universal MCP visualizer
|
|
2222
|
+
tv --port=3000 Custom port (default: 50888)
|
|
2223
|
+
|
|
2224
|
+
Any MCP can stream events to MCP-TV:
|
|
2225
|
+
POST http://localhost:50888/stream
|
|
2226
|
+
{ "channel": "my-mcp", "event": "stage", "data": {...} }
|
|
2227
|
+
|
|
2228
|
+
TOOLS (beacon pack):
|
|
2229
|
+
50c beacon.health Context health check (FREE)
|
|
2230
|
+
50c beacon.compress <text> Smart compression ($0.02)
|
|
2231
|
+
50c beacon.extract <text> Extract decisions ($0.02)
|
|
2232
|
+
50c beacon.mint <content> Permanent memory ($0.01)
|
|
2233
|
+
50c beacon.recall [query] Read memories (FREE)
|
|
2234
|
+
|
|
2235
|
+
FEEDBACK:
|
|
2236
|
+
tip [amount] [reason] Tip (builds refund pool)
|
|
2237
|
+
notip <tool> <reason> Report bad result (refund)
|
|
2238
|
+
mint <content> Save to permanent memory
|
|
2239
|
+
|
|
2240
|
+
ADOPTION EQUATION (FREE):
|
|
2241
|
+
adopt R N W Calculate P(adopt) = (1-e^(-R)) * N * W
|
|
2242
|
+
adopt-dx R N W Diagnose bottleneck + prescribe fix
|
|
2243
|
+
adopt-sim R Simulate time-series with feedback loops
|
|
2244
|
+
|
|
2245
|
+
Examples:
|
|
2246
|
+
50c adopt 2.0 0.3 0.8 "R=2, network=30%, window=80%"
|
|
2247
|
+
50c adopt-dx 1.5 0.05 0.7 "Why is adoption failing?"
|
|
2248
|
+
50c adopt-sim 3.0 "Project adoption trajectory"
|
|
2249
|
+
|
|
2250
|
+
TEAMS (FREE with API key):
|
|
2251
|
+
team Show your team info
|
|
2252
|
+
team-create "Name" Create a new team
|
|
2253
|
+
team-mint <key> <value> Share memory with team
|
|
2254
|
+
team-recall [query] Recall team memories
|
|
2255
|
+
team-analytics View ROI dashboard
|
|
2256
|
+
|
|
2257
|
+
Examples:
|
|
2258
|
+
50c team "Show team members"
|
|
2259
|
+
50c team-mint decision "Use React" engineering
|
|
2260
|
+
50c team-recall "Show all team memories"
|
|
2261
|
+
50c team-analytics "See bugs caught, hours saved, ROI"
|
|
2262
|
+
|
|
2263
|
+
SNAPSHOTS:
|
|
2264
|
+
snapshots List saved states
|
|
2265
|
+
restore <id> Restore a snapshot
|
|
2266
|
+
|
|
2267
|
+
EXAMPLES:
|
|
2268
|
+
50c hints "api design"
|
|
2269
|
+
50c genius "optimize this algorithm"
|
|
2270
|
+
50c invent "novel sorting algorithm" --rigor=deep --domain=code
|
|
2271
|
+
50c beacon.compress "long context here..."
|
|
2272
|
+
50c tip 10 "saved my deploy"
|
|
2273
|
+
50c notip compress wrong_answer "output was garbage"
|
|
2274
|
+
|
|
2275
|
+
MCP MODE:
|
|
2276
|
+
50c Start JSON-RPC mode for IDEs
|
|
2277
|
+
`);
|
|
2278
|
+
}
|
|
2279
|
+
|
|
2280
|
+
process.on('SIGINT', () => process.exit(130));
|
|
2281
|
+
process.on('SIGTERM', () => process.exit(143));
|
|
2282
|
+
|
|
2283
|
+
// Export enterprise functions for team.js integration
|
|
2284
|
+
module.exports = { autoInvent, inventProgram };
|