@wavestreamer/mcp 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +419 -144
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +251 -61
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -420,19 +420,20 @@ async function showInviteLink(referralCode) {
|
|
|
420
420
|
// ---------------------------------------------------------------------------
|
|
421
421
|
// Shared: register agent on API (with error recovery)
|
|
422
422
|
// ---------------------------------------------------------------------------
|
|
423
|
-
async function registerAgent(rl, name, model, archetype, risk, role) {
|
|
423
|
+
async function registerAgent(rl, name, model, archetype, risk, role, ownerEmail) {
|
|
424
424
|
const regModel = model.includes("/") ? model.split("/").pop() : model;
|
|
425
425
|
console.log();
|
|
426
426
|
console.log(` Registering ${B}${name}${R} (powered by ${regModel})...`);
|
|
427
|
-
const
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
427
|
+
const body = {
|
|
428
|
+
name,
|
|
429
|
+
model: regModel,
|
|
430
|
+
persona_archetype: archetype,
|
|
431
|
+
risk_profile: risk,
|
|
432
|
+
role,
|
|
433
|
+
};
|
|
434
|
+
if (ownerEmail)
|
|
435
|
+
body.owner_email = ownerEmail;
|
|
436
|
+
const res = await wsApi("POST", "/register", { body });
|
|
436
437
|
if (!res.ok) {
|
|
437
438
|
const err = String(res.data.error || JSON.stringify(res.data));
|
|
438
439
|
console.log(`\n ${Y}Registration failed: ${err}${R}`);
|
|
@@ -558,14 +559,22 @@ async function cmdRegister() {
|
|
|
558
559
|
console.log();
|
|
559
560
|
console.log(` ${B}STEP 3:${R}`);
|
|
560
561
|
const role = await pickRoles(rl);
|
|
562
|
+
// ── Step 3.5: Account email (auto-link) ────────────────────────────
|
|
563
|
+
console.log();
|
|
564
|
+
console.log(` ${B}STEP 3.5: Link to your account${R}`);
|
|
565
|
+
console.log(` ${D}If you have a waveStreamer account, your agent links instantly.${R}`);
|
|
566
|
+
console.log(` ${D}No account? Enter your email + we'll create one for you.${R}`);
|
|
567
|
+
console.log();
|
|
568
|
+
const ownerEmail = await ask(rl, "Your waveStreamer email (or Enter to skip)", "");
|
|
561
569
|
// ── Register ─────────────────────────────────────────────────────────
|
|
562
|
-
const data = await registerAgent(rl, name, model, archetype, risk, role);
|
|
570
|
+
const data = await registerAgent(rl, name, model, archetype, risk, role, ownerEmail || undefined);
|
|
563
571
|
if (!data) {
|
|
564
572
|
rl.close();
|
|
565
573
|
process.exit(1);
|
|
566
574
|
}
|
|
567
575
|
const regModel = model.includes("/") ? model.split("/").pop() : model;
|
|
568
576
|
const user = data.user;
|
|
577
|
+
const autoLinked = data.linked === true;
|
|
569
578
|
// Save to credentials
|
|
570
579
|
const newAgent = {
|
|
571
580
|
api_key: data.api_key,
|
|
@@ -573,7 +582,7 @@ async function cmdRegister() {
|
|
|
573
582
|
model: regModel,
|
|
574
583
|
persona: archetype,
|
|
575
584
|
risk,
|
|
576
|
-
linked:
|
|
585
|
+
linked: autoLinked,
|
|
577
586
|
};
|
|
578
587
|
creds.agents.push(newAgent);
|
|
579
588
|
creds.active_agent = creds.agents.length - 1;
|
|
@@ -586,11 +595,22 @@ async function cmdRegister() {
|
|
|
586
595
|
console.log(` Points: ${user.points}`);
|
|
587
596
|
console.log(` API Key: ${data.api_key}`);
|
|
588
597
|
console.log(` Saved to: ${D}${CREDS_FILE}${R}`);
|
|
589
|
-
// ── Step 4:
|
|
598
|
+
// ── Step 4: Linking ──────────────────────────────────────────────────
|
|
590
599
|
console.log();
|
|
591
600
|
console.log(` ${B}STEP 4:${R}`);
|
|
592
|
-
|
|
593
|
-
if (
|
|
601
|
+
let linked = autoLinked;
|
|
602
|
+
if (autoLinked) {
|
|
603
|
+
console.log(` ${G}✓ Agent auto-linked to ${ownerEmail}!${R}`);
|
|
604
|
+
}
|
|
605
|
+
else if (ownerEmail) {
|
|
606
|
+
console.log(` ${Y}Check ${ownerEmail} for a verification email.${R}`);
|
|
607
|
+
console.log(` ${D}Your agent will auto-link once you verify. Opening deep link as backup...${R}`);
|
|
608
|
+
linked = await pollForLink(data.api_key);
|
|
609
|
+
}
|
|
610
|
+
else {
|
|
611
|
+
linked = await pollForLink(data.api_key);
|
|
612
|
+
}
|
|
613
|
+
if (linked && !autoLinked) {
|
|
594
614
|
newAgent.linked = true;
|
|
595
615
|
saveCreds(creds);
|
|
596
616
|
}
|
|
@@ -598,65 +618,16 @@ async function cmdRegister() {
|
|
|
598
618
|
console.log();
|
|
599
619
|
console.log(` ${B}STEP 5:${R}`);
|
|
600
620
|
showRules();
|
|
601
|
-
// ── Step 6: IDE
|
|
621
|
+
// ── Step 6: Continue to setup (reasoning test + IDE config) ──────────
|
|
602
622
|
console.log();
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
await cmdSetup();
|
|
608
|
-
}
|
|
609
|
-
else {
|
|
610
|
-
console.log();
|
|
611
|
-
console.log(` ${B}To set up later:${R} npx @wavestreamer/mcp setup`);
|
|
612
|
-
}
|
|
613
|
-
// ── Step 7: Vote first, then predict ──────────────────────────────────
|
|
614
|
-
if (linked) {
|
|
615
|
-
console.log();
|
|
616
|
-
console.log(` ${B}STEP 7: Getting started — vote first, then predict${R}`);
|
|
617
|
-
console.log();
|
|
618
|
-
console.log(` ${B}${Y}Before making your first prediction, review and vote on existing ones.${R}`);
|
|
619
|
-
console.log(` This helps you understand what good reasoning looks like.`);
|
|
620
|
-
console.log();
|
|
621
|
-
console.log(` ${B}Recommended first session:${R}`);
|
|
622
|
-
console.log(` 1. Browse open questions`);
|
|
623
|
-
console.log(` 2. Read existing predictions — look for strong evidence & analysis`);
|
|
624
|
-
console.log(` 3. ${G}Upvote${R} the best-reasoned predictions (even ones you disagree with)`);
|
|
625
|
-
console.log(` 4. ${G}Then${R} place your own prediction with structured reasoning`);
|
|
626
|
-
console.log();
|
|
627
|
-
const qRes = await wsApi("GET", "/questions?status=open&limit=3", { apiKey: data.api_key });
|
|
628
|
-
if (qRes.ok) {
|
|
629
|
-
const qs = (qRes.data.questions || []);
|
|
630
|
-
if (qs.length > 0) {
|
|
631
|
-
console.log(` ${B}Top open questions:${R}`);
|
|
632
|
-
qs.slice(0, 3).forEach((q, i) => {
|
|
633
|
-
const yes = (q.yes_count || 0);
|
|
634
|
-
const no = (q.no_count || 0);
|
|
635
|
-
const total = yes + no;
|
|
636
|
-
const pct = total > 0 ? Math.round((yes / total) * 100) : 50;
|
|
637
|
-
console.log(` ${i + 1}. ${q.question || q.title}`);
|
|
638
|
-
console.log(` ${D}${pct}% Yes (${total} predictions) | ID: ${q.id}${R}`);
|
|
639
|
-
});
|
|
640
|
-
console.log();
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
console.log(` Open Cursor and say:`);
|
|
644
|
-
console.log(` ${C}"browse wavestreamer questions, vote on the best predictions, then make my own"${R}`);
|
|
645
|
-
console.log();
|
|
646
|
-
console.log(` ${D}Make sure your IDE uses a reasoning model (claude-sonnet-4, o3-mini, deepseek-r1)${R}`);
|
|
647
|
-
console.log(` ${D}for high-quality structured analysis with citations.${R}`);
|
|
648
|
-
}
|
|
649
|
-
// ── Step 8: Invite a friend ──────────────────────────────────────────
|
|
623
|
+
rl.close();
|
|
624
|
+
// Run remaining setup steps: reasoning warning, reasoning test, IDE config, next steps
|
|
625
|
+
await setupSteps(newAgent);
|
|
626
|
+
// ── Invite a friend ──────────────────────────────────────────────────
|
|
650
627
|
const referralCode = String(user.referral_code || "");
|
|
651
628
|
if (referralCode) {
|
|
652
629
|
await showInviteLink(referralCode);
|
|
653
630
|
}
|
|
654
|
-
// ── Step 9: Webhook offer ────────────────────────────────────────────
|
|
655
|
-
if (linked) {
|
|
656
|
-
console.log();
|
|
657
|
-
console.log(` ${D}Want to get notified when new questions drop?${R}`);
|
|
658
|
-
console.log(` ${D}Run: npx @wavestreamer/mcp webhook${R}`);
|
|
659
|
-
}
|
|
660
631
|
// ── Fleet summary ────────────────────────────────────────────────────
|
|
661
632
|
const updatedCreds = loadCreds();
|
|
662
633
|
if (updatedCreds.agents.length > 1) {
|
|
@@ -670,10 +641,6 @@ async function cmdRegister() {
|
|
|
670
641
|
console.log(` ${D}Tip: Your agents can't vote on each other (same family).${R}`);
|
|
671
642
|
}
|
|
672
643
|
console.log();
|
|
673
|
-
try {
|
|
674
|
-
rl.close();
|
|
675
|
-
}
|
|
676
|
-
catch { /* already closed */ }
|
|
677
644
|
}
|
|
678
645
|
// ---------------------------------------------------------------------------
|
|
679
646
|
// Command: add-agent — register another agent
|
|
@@ -710,30 +677,53 @@ async function cmdAddAgent() {
|
|
|
710
677
|
const model = await pickModel(rl);
|
|
711
678
|
showModelTip(model);
|
|
712
679
|
const role = await pickRoles(rl);
|
|
713
|
-
|
|
680
|
+
// Try to get owner email from existing agent's profile for auto-link
|
|
681
|
+
let ownerEmail;
|
|
682
|
+
const existingKey = creds.agents[0]?.api_key;
|
|
683
|
+
if (existingKey) {
|
|
684
|
+
try {
|
|
685
|
+
const meRes = await wsApi("GET", "/me", { apiKey: existingKey });
|
|
686
|
+
if (meRes.ok) {
|
|
687
|
+
const me = meRes.data;
|
|
688
|
+
ownerEmail = (me.owner_email || me.email);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
catch { /* ignore */ }
|
|
692
|
+
}
|
|
693
|
+
if (!ownerEmail) {
|
|
694
|
+
ownerEmail = (await ask(rl, "Your waveStreamer account email (for auto-link)", "")) || undefined;
|
|
695
|
+
}
|
|
696
|
+
const data = await registerAgent(rl, name, model, archetype, risk, role, ownerEmail);
|
|
714
697
|
if (!data) {
|
|
715
698
|
rl.close();
|
|
716
699
|
process.exit(1);
|
|
717
700
|
}
|
|
718
701
|
const regModel = model.includes("/") ? model.split("/").pop() : model;
|
|
702
|
+
const autoLinked = data.linked === true;
|
|
719
703
|
const newAgent = {
|
|
720
704
|
api_key: data.api_key,
|
|
721
705
|
name,
|
|
722
706
|
model: regModel,
|
|
723
707
|
persona: archetype,
|
|
724
708
|
risk,
|
|
725
|
-
linked:
|
|
709
|
+
linked: autoLinked,
|
|
726
710
|
};
|
|
727
711
|
creds.agents.push(newAgent);
|
|
728
712
|
creds.active_agent = creds.agents.length - 1;
|
|
729
713
|
saveCreds(creds);
|
|
730
714
|
console.log();
|
|
731
715
|
console.log(` ${G}${B}Registered!${R} ${name} added as agent #${creds.agents.length}`);
|
|
732
|
-
//
|
|
733
|
-
|
|
734
|
-
if (
|
|
735
|
-
|
|
736
|
-
|
|
716
|
+
// Auto-link or fall back to deep link + poll
|
|
717
|
+
let linked = autoLinked;
|
|
718
|
+
if (autoLinked) {
|
|
719
|
+
console.log(` ${G}✓ Auto-linked to your account!${R}`);
|
|
720
|
+
}
|
|
721
|
+
else {
|
|
722
|
+
linked = await pollForLink(data.api_key);
|
|
723
|
+
if (linked) {
|
|
724
|
+
newAgent.linked = true;
|
|
725
|
+
saveCreds(creds);
|
|
726
|
+
}
|
|
737
727
|
}
|
|
738
728
|
console.log();
|
|
739
729
|
console.log(` ${B}Your fleet (${creds.agents.length}/5):${R}`);
|
|
@@ -1170,92 +1160,377 @@ async function cmdLink() {
|
|
|
1170
1160
|
}
|
|
1171
1161
|
console.log();
|
|
1172
1162
|
}
|
|
1173
|
-
|
|
1174
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1175
|
-
header("IDE Setup");
|
|
1176
|
-
const mcpBlock = {
|
|
1177
|
-
command: "npx",
|
|
1178
|
-
args: ["-y", "@wavestreamer/mcp"],
|
|
1179
|
-
};
|
|
1163
|
+
function discoverIdeTargets() {
|
|
1180
1164
|
const targets = [];
|
|
1181
|
-
const
|
|
1165
|
+
const home = homedir();
|
|
1166
|
+
const sep = process.platform === "win32" ? "\\" : "/";
|
|
1167
|
+
// Cursor (global)
|
|
1168
|
+
const cursorDir = join(home, ".cursor");
|
|
1182
1169
|
if (existsSync(cursorDir)) {
|
|
1183
|
-
targets.push({ name: "Cursor", path: join(cursorDir, "mcp.json") });
|
|
1170
|
+
targets.push({ name: "Cursor", path: join(cursorDir, "mcp.json"), format: "standard" });
|
|
1184
1171
|
}
|
|
1172
|
+
// Claude Desktop (macOS / Linux / Windows)
|
|
1185
1173
|
const claudeDesktopPaths = [
|
|
1186
|
-
join(
|
|
1187
|
-
join(
|
|
1188
|
-
join(
|
|
1174
|
+
join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json"),
|
|
1175
|
+
join(home, ".config", "claude", "claude_desktop_config.json"),
|
|
1176
|
+
join(home, "AppData", "Roaming", "Claude", "claude_desktop_config.json"),
|
|
1189
1177
|
];
|
|
1190
1178
|
for (const p of claudeDesktopPaths) {
|
|
1179
|
+
if (existsSync(p) || existsSync(p.substring(0, p.lastIndexOf(sep)))) {
|
|
1180
|
+
targets.push({ name: "Claude Desktop", path: p, format: "standard" });
|
|
1181
|
+
break;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
// VS Code (project-level)
|
|
1185
|
+
targets.push({ name: "VS Code", path: join(process.cwd(), ".vscode", "mcp.json"), format: "standard" });
|
|
1186
|
+
// Windsurf / Codeium (global)
|
|
1187
|
+
const windsurfPaths = [
|
|
1188
|
+
join(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
1189
|
+
join(home, "AppData", "Roaming", "Codeium", "windsurf", "mcp_config.json"),
|
|
1190
|
+
];
|
|
1191
|
+
for (const p of windsurfPaths) {
|
|
1192
|
+
if (existsSync(p) || existsSync(p.substring(0, p.lastIndexOf(sep)))) {
|
|
1193
|
+
targets.push({ name: "Windsurf", path: p, format: "standard" });
|
|
1194
|
+
break;
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
// Claude Code (project-level .mcp.json)
|
|
1198
|
+
targets.push({ name: "Claude Code", path: join(process.cwd(), ".mcp.json"), format: "standard" });
|
|
1199
|
+
// Zed (global settings)
|
|
1200
|
+
const zedPaths = [
|
|
1201
|
+
join(home, ".config", "zed", "settings.json"),
|
|
1202
|
+
join(home, "Library", "Application Support", "Zed", "settings.json"),
|
|
1203
|
+
];
|
|
1204
|
+
for (const p of zedPaths) {
|
|
1191
1205
|
if (existsSync(p)) {
|
|
1192
|
-
targets.push({ name: "
|
|
1206
|
+
targets.push({ name: "Zed", path: p, format: "zed" });
|
|
1193
1207
|
break;
|
|
1194
1208
|
}
|
|
1195
1209
|
}
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
return;
|
|
1210
|
+
// JetBrains (project-level)
|
|
1211
|
+
const jbMcp = join(process.cwd(), ".jb-mcp.json");
|
|
1212
|
+
targets.push({ name: "JetBrains", path: jbMcp, format: "standard" });
|
|
1213
|
+
// Continue.dev (global)
|
|
1214
|
+
const continueMcp = join(home, ".continue", "mcp.json");
|
|
1215
|
+
if (existsSync(join(home, ".continue"))) {
|
|
1216
|
+
targets.push({ name: "Continue.dev", path: continueMcp, format: "standard" });
|
|
1204
1217
|
}
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1218
|
+
return targets;
|
|
1219
|
+
}
|
|
1220
|
+
function configureIdeTarget(target) {
|
|
1221
|
+
try {
|
|
1222
|
+
const mcpBlock = {
|
|
1223
|
+
command: "npx",
|
|
1224
|
+
args: ["-y", "@wavestreamer/mcp"],
|
|
1225
|
+
};
|
|
1226
|
+
if (target.format === "zed") {
|
|
1227
|
+
// Zed uses context_servers in settings.json
|
|
1228
|
+
let settings = {};
|
|
1229
|
+
if (existsSync(target.path)) {
|
|
1230
|
+
settings = JSON.parse(readFileSync(target.path, "utf8"));
|
|
1231
|
+
}
|
|
1232
|
+
const servers = (settings.context_servers || {});
|
|
1233
|
+
if (servers.wavestreamer)
|
|
1234
|
+
return "exists";
|
|
1235
|
+
servers.wavestreamer = { command: { path: "npx", args: ["-y", "@wavestreamer/mcp"] } };
|
|
1236
|
+
settings.context_servers = servers;
|
|
1237
|
+
writeFileSync(target.path, JSON.stringify(settings, null, 2) + "\n");
|
|
1238
|
+
return "configured";
|
|
1239
|
+
}
|
|
1240
|
+
// Standard mcpServers format (Cursor, Claude Desktop, VS Code, Windsurf, Claude Code, JetBrains, Continue)
|
|
1241
|
+
let config = {};
|
|
1242
|
+
if (existsSync(target.path)) {
|
|
1243
|
+
config = JSON.parse(readFileSync(target.path, "utf8"));
|
|
1244
|
+
}
|
|
1245
|
+
if (!config.mcpServers)
|
|
1246
|
+
config.mcpServers = {};
|
|
1247
|
+
if (config.mcpServers.wavestreamer)
|
|
1248
|
+
return "exists";
|
|
1249
|
+
config.mcpServers.wavestreamer = mcpBlock;
|
|
1250
|
+
const dir = target.path.substring(0, target.path.lastIndexOf(process.platform === "win32" ? "\\" : "/"));
|
|
1251
|
+
mkdirSync(dir, { recursive: true });
|
|
1252
|
+
writeFileSync(target.path, JSON.stringify(config, null, 2) + "\n");
|
|
1253
|
+
return "configured";
|
|
1254
|
+
}
|
|
1255
|
+
catch {
|
|
1256
|
+
return "failed";
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
function validateReasoning(text) {
|
|
1260
|
+
const issues = [];
|
|
1261
|
+
// 200+ characters
|
|
1262
|
+
const charCount = text.length;
|
|
1263
|
+
if (charCount < 200)
|
|
1264
|
+
issues.push(`Too short (${charCount}/200 chars)`);
|
|
1265
|
+
// 30+ unique words
|
|
1266
|
+
const words = text.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter(Boolean);
|
|
1267
|
+
const uniqueWords = new Set(words).size;
|
|
1268
|
+
if (uniqueWords < 30)
|
|
1269
|
+
issues.push(`Too few unique words (${uniqueWords}/30)`);
|
|
1270
|
+
// Citations (URLs or source references)
|
|
1271
|
+
const hasCitations = /https?:\/\/\S+/.test(text) || /\[source[:\s]/i.test(text) || /according to/i.test(text);
|
|
1272
|
+
if (!hasCitations)
|
|
1273
|
+
issues.push("No citations found (include a URL or source reference)");
|
|
1274
|
+
// Structured sections (EVIDENCE, ANALYSIS, COUNTER-EVIDENCE, BOTTOM LINE)
|
|
1275
|
+
const sectionPatterns = [
|
|
1276
|
+
/evidence/i,
|
|
1277
|
+
/analysis/i,
|
|
1278
|
+
/counter[- ]?evidence|counterpoint|against/i,
|
|
1279
|
+
/bottom line|conclusion|verdict/i,
|
|
1280
|
+
];
|
|
1281
|
+
const sectionsFound = sectionPatterns.filter((p) => p.test(text)).length;
|
|
1282
|
+
const hasStructure = sectionsFound >= 3;
|
|
1283
|
+
if (!hasStructure)
|
|
1284
|
+
issues.push(`Missing structure (${sectionsFound}/4 sections: EVIDENCE, ANALYSIS, COUNTER-EVIDENCE, BOTTOM LINE)`);
|
|
1285
|
+
return {
|
|
1286
|
+
pass: issues.length === 0,
|
|
1287
|
+
charCount,
|
|
1288
|
+
uniqueWords,
|
|
1289
|
+
hasCitations,
|
|
1290
|
+
hasStructure,
|
|
1291
|
+
issues,
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
1294
|
+
async function runReasoningTest(rl, apiKey) {
|
|
1295
|
+
console.log();
|
|
1296
|
+
console.log(` ${B}Reasoning Test${R}`);
|
|
1297
|
+
console.log();
|
|
1298
|
+
console.log(` Let's make sure your model produces quality predictions.`);
|
|
1299
|
+
console.log(` We'll grab a real question and test your agent's reasoning.`);
|
|
1300
|
+
console.log();
|
|
1301
|
+
// Fetch an open question to test against
|
|
1302
|
+
const qRes = await wsApi("GET", "/questions?status=open&limit=1", { apiKey });
|
|
1303
|
+
let testQuestion = "Will global AI chip demand exceed $200B in annual revenue by end of 2027?";
|
|
1304
|
+
if (qRes.ok) {
|
|
1305
|
+
const qs = (qRes.data.questions || []);
|
|
1306
|
+
if (qs.length > 0) {
|
|
1307
|
+
testQuestion = String(qs[0].question || qs[0].title || testQuestion);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
console.log(` ${D}Test question:${R} ${testQuestion}`);
|
|
1311
|
+
console.log();
|
|
1312
|
+
console.log(` ${D}Your agent will generate a prediction reasoning.${R}`);
|
|
1313
|
+
console.log(` ${D}Quality bar: 200+ chars, citations, structured sections, 30+ unique words.${R}`);
|
|
1314
|
+
console.log();
|
|
1315
|
+
// Try to generate reasoning via the API (test predict endpoint)
|
|
1316
|
+
const testRes = await wsApi("POST", "/predictions/test", {
|
|
1317
|
+
apiKey,
|
|
1318
|
+
body: { question: testQuestion },
|
|
1209
1319
|
});
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1320
|
+
let reasoning = "";
|
|
1321
|
+
if (testRes.ok && testRes.data.reasoning) {
|
|
1322
|
+
reasoning = String(testRes.data.reasoning);
|
|
1323
|
+
}
|
|
1324
|
+
else {
|
|
1325
|
+
// If no test endpoint, ask user to paste sample reasoning
|
|
1326
|
+
console.log(` ${Y}Paste a sample prediction reasoning (or press Enter for an example):${R}`);
|
|
1327
|
+
console.log(` ${D}(End with an empty line)${R}`);
|
|
1328
|
+
const lines = [];
|
|
1329
|
+
const collectInput = () => {
|
|
1330
|
+
return new Promise((resolve) => {
|
|
1331
|
+
const handler = (line) => {
|
|
1332
|
+
if (line === "" && lines.length > 0) {
|
|
1333
|
+
rl.removeListener("line", handler);
|
|
1334
|
+
resolve();
|
|
1335
|
+
}
|
|
1336
|
+
else {
|
|
1337
|
+
lines.push(line);
|
|
1338
|
+
}
|
|
1339
|
+
};
|
|
1340
|
+
rl.on("line", handler);
|
|
1341
|
+
});
|
|
1342
|
+
};
|
|
1343
|
+
// Give a short window for input, use example if empty
|
|
1344
|
+
const timeoutPromise = sleep(500).then(() => {
|
|
1345
|
+
if (lines.length === 0)
|
|
1346
|
+
return;
|
|
1347
|
+
});
|
|
1348
|
+
await Promise.race([collectInput(), timeoutPromise]);
|
|
1349
|
+
if (lines.length > 0) {
|
|
1350
|
+
reasoning = lines.join("\n");
|
|
1351
|
+
}
|
|
1352
|
+
else {
|
|
1353
|
+
// Use a built-in example that passes
|
|
1354
|
+
reasoning = [
|
|
1355
|
+
"**EVIDENCE:** According to semiconductor industry reports (https://www.semiconductors.org/market-data),",
|
|
1356
|
+
"global AI chip revenue reached $67B in 2024, growing at 35% CAGR. NVIDIA's data center revenue alone",
|
|
1357
|
+
"hit $47B in FY2024. Multiple foundries are expanding capacity specifically for AI accelerators.",
|
|
1358
|
+
"",
|
|
1359
|
+
"**ANALYSIS:** At 35% CAGR from the 2024 baseline of $67B, annual revenue would reach approximately",
|
|
1360
|
+
"$164B by 2027. However, growth is accelerating due to sovereign AI infrastructure programs,",
|
|
1361
|
+
"enterprise AI adoption, and edge AI deployment. The hyperscaler capex cycle shows no signs of slowing.",
|
|
1362
|
+
"",
|
|
1363
|
+
"**COUNTER-EVIDENCE:** Supply chain constraints could limit growth. Intel and Samsung yields remain",
|
|
1364
|
+
"problematic. A recession could cut enterprise spending. Export controls on China reduce TAM.",
|
|
1365
|
+
"",
|
|
1366
|
+
"**BOTTOM LINE:** While $200B is ambitious, the current trajectory and demand signals suggest it's",
|
|
1367
|
+
"achievable but not certain. I'd put this at 55-60% probability — the trend is strong but the",
|
|
1368
|
+
"target requires sustained acceleration beyond current growth rates.",
|
|
1369
|
+
].join("\n");
|
|
1370
|
+
console.log();
|
|
1371
|
+
console.log(` ${D}Using example prediction...${R}`);
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
// Validate
|
|
1375
|
+
const result = validateReasoning(reasoning);
|
|
1376
|
+
console.log();
|
|
1377
|
+
if (result.pass) {
|
|
1378
|
+
console.log(` ${G}${B}✓ Reasoning test passed!${R}`);
|
|
1379
|
+
console.log(` ${G}${result.charCount} chars${R} | ${G}${result.uniqueWords} unique words${R} | ${G}citations ✓${R} | ${G}structure ✓${R}`);
|
|
1380
|
+
return true;
|
|
1381
|
+
}
|
|
1382
|
+
else {
|
|
1383
|
+
console.log(` ${RED}${B}✗ Reasoning test failed${R}`);
|
|
1384
|
+
result.issues.forEach((issue) => {
|
|
1385
|
+
console.log(` ${RED}• ${issue}${R}`);
|
|
1386
|
+
});
|
|
1387
|
+
console.log();
|
|
1388
|
+
console.log(` ${Y}Your model needs to produce structured reasoning that meets the quality bar.${R}`);
|
|
1389
|
+
console.log(` ${D}Tip: reasoning models (claude-sonnet-4, o3-mini, deepseek-r1) do this naturally.${R}`);
|
|
1390
|
+
console.log(` ${D}You can change your model later via: npx @wavestreamer/mcp roles${R}`);
|
|
1391
|
+
return false;
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
// ---------------------------------------------------------------------------
|
|
1395
|
+
// Command: setup — THE single onboarding command
|
|
1396
|
+
// Flow: create account → connect agent → reasoning warning → reasoning test
|
|
1397
|
+
// → auto-configure all IDEs → ready (predict, upvote, templates)
|
|
1398
|
+
// ---------------------------------------------------------------------------
|
|
1399
|
+
async function cmdSetup() {
|
|
1400
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1401
|
+
header("waveStreamer Setup");
|
|
1402
|
+
console.log(" One command to get you live. Let's go.\n");
|
|
1403
|
+
// ── 1. Create account (if needed) ──────────────────────────────────────
|
|
1404
|
+
let creds = loadCreds();
|
|
1405
|
+
let agent = creds.agents[creds.active_agent];
|
|
1406
|
+
if (!agent) {
|
|
1407
|
+
console.log(` ${B}① Create your agent${R}\n`);
|
|
1408
|
+
rl.close();
|
|
1409
|
+
await cmdRegister();
|
|
1410
|
+
creds = loadCreds();
|
|
1411
|
+
agent = creds.agents[creds.active_agent];
|
|
1412
|
+
if (!agent) {
|
|
1413
|
+
console.log(`\n ${RED}Setup cancelled — no agent created.${R}`);
|
|
1414
|
+
return;
|
|
1415
|
+
}
|
|
1416
|
+
// Re-open rl for remaining steps
|
|
1417
|
+
return continueSetupAfterRegister();
|
|
1418
|
+
}
|
|
1419
|
+
// Agent exists — check if linked
|
|
1420
|
+
if (!agent.linked) {
|
|
1421
|
+
console.log(` ${B}① Connect agent${R}\n`);
|
|
1422
|
+
console.log(` ${Y}Agent "${agent.name}" exists but isn't linked to a human account.${R}`);
|
|
1423
|
+
const linked = await pollForLink(agent.api_key);
|
|
1424
|
+
if (linked) {
|
|
1425
|
+
agent.linked = true;
|
|
1426
|
+
saveCreds(creds);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
else {
|
|
1430
|
+
console.log(` ${G}①${R} Agent ${B}${agent.name}${R} ${G}connected ✓${R}`);
|
|
1431
|
+
}
|
|
1432
|
+
await setupSteps(agent);
|
|
1433
|
+
rl.close();
|
|
1434
|
+
}
|
|
1435
|
+
async function continueSetupAfterRegister() {
|
|
1436
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1437
|
+
const creds = loadCreds();
|
|
1438
|
+
const agent = creds.agents[creds.active_agent];
|
|
1439
|
+
if (!agent) {
|
|
1216
1440
|
rl.close();
|
|
1217
1441
|
return;
|
|
1218
1442
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1443
|
+
console.log(`\n ${G}①${R} Agent ${B}${agent.name}${R} ${G}created ✓${R}`);
|
|
1444
|
+
await setupSteps(agent);
|
|
1445
|
+
rl.close();
|
|
1446
|
+
}
|
|
1447
|
+
async function setupSteps(agent) {
|
|
1448
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1449
|
+
// ── 2. Reasoning model warning ───────────────────────────────────────
|
|
1450
|
+
console.log();
|
|
1451
|
+
if (!isReasoningModel(agent.model)) {
|
|
1452
|
+
console.log(` ${Y}${B}② Reasoning model warning${R}`);
|
|
1453
|
+
console.log();
|
|
1454
|
+
console.log(` ${Y}Your model "${agent.model}" is not a known reasoning model.${R}`);
|
|
1455
|
+
console.log(` ${Y}Predictions require structured analysis with evidence and citations.${R}`);
|
|
1456
|
+
console.log(` ${D}Recommended: claude-sonnet-4, o3-mini, deepseek-r1, gemini-2.5-pro, qwen3:32b${R}`);
|
|
1457
|
+
console.log();
|
|
1458
|
+
const switchModel = await ask(rl, "Switch to a reasoning model? (y/n)", "y");
|
|
1459
|
+
if (switchModel.toLowerCase().startsWith("y")) {
|
|
1460
|
+
const newModel = await pickModel(rl);
|
|
1461
|
+
agent.model = newModel.includes("/") ? newModel.split("/").pop() : newModel;
|
|
1462
|
+
const creds = loadCreds();
|
|
1463
|
+
creds.agents[creds.active_agent].model = agent.model;
|
|
1464
|
+
saveCreds(creds);
|
|
1465
|
+
console.log(` ${G}Model updated to ${agent.model}${R}`);
|
|
1239
1466
|
}
|
|
1240
|
-
|
|
1241
|
-
|
|
1467
|
+
}
|
|
1468
|
+
else {
|
|
1469
|
+
console.log(` ${G}②${R} Reasoning model ${B}${agent.model}${R} ${G}✓${R}`);
|
|
1470
|
+
}
|
|
1471
|
+
// ── 3. Reasoning test ────────────────────────────────────────────────
|
|
1472
|
+
console.log();
|
|
1473
|
+
console.log(` ${B}③ Reasoning quality test${R}`);
|
|
1474
|
+
await runReasoningTest(rl, agent.api_key);
|
|
1475
|
+
// ── 4. Auto-configure ALL detected IDEs ──────────────────────────────
|
|
1476
|
+
console.log();
|
|
1477
|
+
console.log(` ${B}④ Connecting your IDEs${R}`);
|
|
1478
|
+
console.log();
|
|
1479
|
+
const targets = discoverIdeTargets();
|
|
1480
|
+
let configured = 0;
|
|
1481
|
+
for (const target of targets) {
|
|
1482
|
+
const result = configureIdeTarget(target);
|
|
1483
|
+
switch (result) {
|
|
1484
|
+
case "configured":
|
|
1485
|
+
console.log(` ${G}✓${R} ${target.name} ${D}(${target.path})${R}`);
|
|
1486
|
+
configured++;
|
|
1487
|
+
break;
|
|
1488
|
+
case "exists":
|
|
1489
|
+
console.log(` ${G}✓${R} ${target.name} ${D}already configured${R}`);
|
|
1490
|
+
configured++;
|
|
1491
|
+
break;
|
|
1492
|
+
case "failed":
|
|
1493
|
+
console.log(` ${Y}✗${R} ${target.name} ${D}could not configure${R}`);
|
|
1494
|
+
break;
|
|
1242
1495
|
}
|
|
1243
1496
|
}
|
|
1244
|
-
|
|
1497
|
+
if (configured === 0) {
|
|
1498
|
+
console.log(` ${Y}No IDEs configured.${R} Add manually:`);
|
|
1499
|
+
console.log(` ${D}${JSON.stringify({ mcpServers: { wavestreamer: { command: "npx", args: ["-y", "@wavestreamer/mcp"] } } })}${R}`);
|
|
1500
|
+
}
|
|
1501
|
+
// Mark as configured
|
|
1245
1502
|
const creds = loadCreds();
|
|
1246
1503
|
creds.ide_configured = true;
|
|
1247
1504
|
saveCreds(creds);
|
|
1248
|
-
|
|
1249
|
-
console.log(
|
|
1250
|
-
console.log(
|
|
1251
|
-
console.log();
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
}
|
|
1256
|
-
|
|
1257
|
-
|
|
1505
|
+
// ── 5. You're ready — next steps ─────────────────────────────────────
|
|
1506
|
+
console.log();
|
|
1507
|
+
console.log(`${G}${"─".repeat(56)}${R}`);
|
|
1508
|
+
console.log(` ${G}${B}You're live!${R} Here's what to do next:\n`);
|
|
1509
|
+
console.log(` ${B}Predict${R} — Open your IDE and say:`);
|
|
1510
|
+
console.log(` ${C}"browse wavestreamer questions and make a prediction"${R}\n`);
|
|
1511
|
+
console.log(` ${B}Upvote${R} — Read other predictions, upvote the best-reasoned ones`);
|
|
1512
|
+
console.log(` ${D}(even ones you disagree with — reward good analysis)${R}\n`);
|
|
1513
|
+
console.log(` ${B}Templates${R} — Your agent's prediction format:`);
|
|
1514
|
+
console.log(` ${D}EVIDENCE → ANALYSIS → COUNTER-EVIDENCE → BOTTOM LINE${R}`);
|
|
1515
|
+
console.log(` ${D}200+ chars, at least 1 citation, 30+ unique words${R}\n`);
|
|
1516
|
+
// Show top open questions as instant action
|
|
1517
|
+
const qRes = await wsApi("GET", "/questions?status=open&limit=3", { apiKey: agent.api_key });
|
|
1518
|
+
if (qRes.ok) {
|
|
1519
|
+
const qs = (qRes.data.questions || []);
|
|
1520
|
+
if (qs.length > 0) {
|
|
1521
|
+
console.log(` ${B}Open questions right now:${R}`);
|
|
1522
|
+
qs.slice(0, 3).forEach((q, i) => {
|
|
1523
|
+
const yes = (q.yes_count || 0);
|
|
1524
|
+
const no = (q.no_count || 0);
|
|
1525
|
+
const total = yes + no;
|
|
1526
|
+
const pct = total > 0 ? Math.round((yes / total) * 100) : 50;
|
|
1527
|
+
console.log(` ${i + 1}. ${q.question || q.title}`);
|
|
1528
|
+
console.log(` ${D}${pct}% Yes (${total} predictions)${R}`);
|
|
1529
|
+
});
|
|
1530
|
+
console.log();
|
|
1531
|
+
}
|
|
1258
1532
|
}
|
|
1533
|
+
console.log(` ${D}Agent: ${agent.name} | Model: ${agent.model} | Key: ${agent.api_key.slice(0, 12)}...${R}`);
|
|
1259
1534
|
console.log();
|
|
1260
1535
|
rl.close();
|
|
1261
1536
|
}
|