@rvry/mcp 0.12.1 → 0.13.0
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/README.md +29 -40
- package/dist/index.d.ts +1 -1
- package/dist/index.js +316 -23
- package/dist/local-writer.d.ts +102 -16
- package/dist/local-writer.js +351 -56
- package/dist/setup.js +152 -234
- package/package.json +1 -1
package/dist/setup.js
CHANGED
|
@@ -218,132 +218,6 @@ function registerClaudeCode(token) {
|
|
|
218
218
|
return 'error';
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
|
-
/**
|
|
222
|
-
* Write RVRY server entry into a generic MCP JSON config file.
|
|
223
|
-
* Used by clients that follow the Desktop-style config format (Codex, Gemini, etc.)
|
|
224
|
-
*/
|
|
225
|
-
function configureJsonMcp(configPath, token) {
|
|
226
|
-
try {
|
|
227
|
-
let config = {};
|
|
228
|
-
if (existsSync(configPath)) {
|
|
229
|
-
const raw = readFileSync(configPath, 'utf-8');
|
|
230
|
-
try {
|
|
231
|
-
config = JSON.parse(raw);
|
|
232
|
-
}
|
|
233
|
-
catch {
|
|
234
|
-
writeFileSync(configPath + '.backup', raw, 'utf-8');
|
|
235
|
-
config = {};
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
if (!config.mcpServers || typeof config.mcpServers !== 'object') {
|
|
239
|
-
config.mcpServers = {};
|
|
240
|
-
}
|
|
241
|
-
const servers = config.mcpServers;
|
|
242
|
-
const existing = servers.RVRY;
|
|
243
|
-
if (existing) {
|
|
244
|
-
const existingEnv = existing.env;
|
|
245
|
-
if (existingEnv?.RVRY_TOKEN === token)
|
|
246
|
-
return 'unchanged';
|
|
247
|
-
}
|
|
248
|
-
const wasNew = !existing;
|
|
249
|
-
servers.RVRY = RVRY_SERVER_ENTRY(token);
|
|
250
|
-
const dir = dirname(configPath);
|
|
251
|
-
if (!existsSync(dir))
|
|
252
|
-
mkdirSync(dir, { recursive: true });
|
|
253
|
-
writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
254
|
-
return wasNew ? 'ok' : 'updated';
|
|
255
|
-
}
|
|
256
|
-
catch (err) {
|
|
257
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
258
|
-
console.log(` Error writing config: ${msg}`);
|
|
259
|
-
return 'error';
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Write RVRY server entry into a TOML config file (e.g. ~/.codex/config.toml).
|
|
264
|
-
* Uses string/regex manipulation — no TOML parser dependency.
|
|
265
|
-
*/
|
|
266
|
-
function configureTomlMcp(configPath, token) {
|
|
267
|
-
const block = [
|
|
268
|
-
'[mcp_servers.rvry]',
|
|
269
|
-
'command = "npx"',
|
|
270
|
-
'args = ["--yes", "--package", "@rvry/mcp@latest", "rvry-mcp"]',
|
|
271
|
-
'',
|
|
272
|
-
'[mcp_servers.rvry.env]',
|
|
273
|
-
`RVRY_TOKEN = "${token}"`,
|
|
274
|
-
].join('\n');
|
|
275
|
-
try {
|
|
276
|
-
let content = '';
|
|
277
|
-
if (existsSync(configPath)) {
|
|
278
|
-
content = readFileSync(configPath, 'utf-8');
|
|
279
|
-
}
|
|
280
|
-
const sectionRegex = /^\[mcp_servers\.rvry\]/m;
|
|
281
|
-
if (sectionRegex.test(content)) {
|
|
282
|
-
// Section exists — check if token is the same
|
|
283
|
-
const tokenMatch = content.match(/^\[mcp_servers\.rvry\.env\]\s*\nRVRY_TOKEN\s*=\s*"([^"]*)"/m);
|
|
284
|
-
if (tokenMatch && tokenMatch[1] === token) {
|
|
285
|
-
return 'unchanged';
|
|
286
|
-
}
|
|
287
|
-
// Replace entire section: from [mcp_servers.rvry] to next top-level section or EOF
|
|
288
|
-
// Match from [mcp_servers.rvry] up to (but not including) the next section header
|
|
289
|
-
// that is NOT a sub-section of mcp_servers.rvry
|
|
290
|
-
const replaceRegex = /\[mcp_servers\.rvry\][\s\S]*?(?=\n\[(?!mcp_servers\.rvry[.\]])|$)/;
|
|
291
|
-
content = content.replace(replaceRegex, block);
|
|
292
|
-
writeFileSync(configPath, content, 'utf-8');
|
|
293
|
-
return 'updated';
|
|
294
|
-
}
|
|
295
|
-
// Section doesn't exist — append
|
|
296
|
-
const separator = content.length > 0 && !content.endsWith('\n') ? '\n\n' : content.length > 0 ? '\n' : '';
|
|
297
|
-
const dir = dirname(configPath);
|
|
298
|
-
if (!existsSync(dir))
|
|
299
|
-
mkdirSync(dir, { recursive: true });
|
|
300
|
-
writeFileSync(configPath, content + separator + block + '\n', 'utf-8');
|
|
301
|
-
return 'ok';
|
|
302
|
-
}
|
|
303
|
-
catch (err) {
|
|
304
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
305
|
-
console.log(` Error writing TOML config: ${msg}`);
|
|
306
|
-
return 'error';
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
function isGeminiCLIAvailable() {
|
|
310
|
-
try {
|
|
311
|
-
const cmd = platform() === 'win32' ? 'where gemini' : 'which gemini';
|
|
312
|
-
execSync(cmd, { stdio: 'pipe' });
|
|
313
|
-
return true;
|
|
314
|
-
}
|
|
315
|
-
catch { /* not on PATH */ }
|
|
316
|
-
if (existsSync(join(homedir(), '.gemini', 'settings.json')))
|
|
317
|
-
return true;
|
|
318
|
-
return false;
|
|
319
|
-
}
|
|
320
|
-
function registerGeminiCLI(token) {
|
|
321
|
-
try {
|
|
322
|
-
// Remove existing entry first (silent fail if not registered)
|
|
323
|
-
try {
|
|
324
|
-
execSync('gemini mcp remove rvry', { stdio: 'pipe' });
|
|
325
|
-
}
|
|
326
|
-
catch { /* not registered */ }
|
|
327
|
-
execSync(`gemini mcp add rvry -e RVRY_TOKEN="${token}" --scope user npx --yes --package @rvry/mcp@latest rvry-mcp`, { stdio: 'inherit' });
|
|
328
|
-
return 'ok';
|
|
329
|
-
}
|
|
330
|
-
catch {
|
|
331
|
-
// Fallback: write settings.json directly
|
|
332
|
-
return configureJsonMcp(join(homedir(), '.gemini', 'settings.json'), token);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
function isCodexAvailable() {
|
|
336
|
-
try {
|
|
337
|
-
const cmd = platform() === 'win32' ? 'where codex' : 'which codex';
|
|
338
|
-
execSync(cmd, { stdio: 'pipe' });
|
|
339
|
-
return true;
|
|
340
|
-
}
|
|
341
|
-
catch { /* not on PATH */ }
|
|
342
|
-
// Fallback: check if config directory exists (covers aliased installs)
|
|
343
|
-
if (existsSync(join(homedir(), '.codex', 'config.toml')))
|
|
344
|
-
return true;
|
|
345
|
-
return false;
|
|
346
|
-
}
|
|
347
221
|
/** All supported clients. Add new clients here. */
|
|
348
222
|
const CLIENT_REGISTRY = [
|
|
349
223
|
{
|
|
@@ -360,70 +234,6 @@ const CLIENT_REGISTRY = [
|
|
|
360
234
|
configure: (token) => configureDesktop(token),
|
|
361
235
|
notInstalledHint: 'Not installed',
|
|
362
236
|
},
|
|
363
|
-
{
|
|
364
|
-
name: 'Anti-Gravity',
|
|
365
|
-
id: 'antigravity',
|
|
366
|
-
defaultSelected: false,
|
|
367
|
-
detect: () => {
|
|
368
|
-
// OR-logic: binary (agy or antigravity), config dir, or macOS app bundle
|
|
369
|
-
try {
|
|
370
|
-
const cmd = platform() === 'win32' ? 'where agy' : 'which agy';
|
|
371
|
-
execSync(cmd, { stdio: 'pipe' });
|
|
372
|
-
return true;
|
|
373
|
-
}
|
|
374
|
-
catch { /* not on PATH */ }
|
|
375
|
-
if (platform() !== 'win32') {
|
|
376
|
-
try {
|
|
377
|
-
execSync('which antigravity', { stdio: 'pipe' });
|
|
378
|
-
return true;
|
|
379
|
-
}
|
|
380
|
-
catch { /* not on PATH */ }
|
|
381
|
-
}
|
|
382
|
-
if (existsSync(join(homedir(), '.gemini', 'antigravity')))
|
|
383
|
-
return true;
|
|
384
|
-
if (platform() === 'darwin' && existsSync('/Applications/Google Antigravity.app'))
|
|
385
|
-
return true;
|
|
386
|
-
return false;
|
|
387
|
-
},
|
|
388
|
-
configure: (token) => configureJsonMcp(join(homedir(), '.gemini', 'antigravity', 'mcp_config.json'), token),
|
|
389
|
-
notInstalledHint: 'Not installed (https://antigravity.google)',
|
|
390
|
-
},
|
|
391
|
-
{
|
|
392
|
-
name: 'Cursor',
|
|
393
|
-
id: 'cursor',
|
|
394
|
-
defaultSelected: false,
|
|
395
|
-
detect: () => {
|
|
396
|
-
if (platform() === 'darwin' && existsSync('/Applications/Cursor.app'))
|
|
397
|
-
return true;
|
|
398
|
-
if (existsSync(join(homedir(), '.cursor', 'mcp.json')))
|
|
399
|
-
return true;
|
|
400
|
-
try {
|
|
401
|
-
const cmd = platform() === 'win32' ? 'where cursor' : 'which cursor';
|
|
402
|
-
execSync(cmd, { stdio: 'pipe' });
|
|
403
|
-
return true;
|
|
404
|
-
}
|
|
405
|
-
catch { /* not on PATH */ }
|
|
406
|
-
return false;
|
|
407
|
-
},
|
|
408
|
-
configure: (token) => configureJsonMcp(join(homedir(), '.cursor', 'mcp.json'), token),
|
|
409
|
-
notInstalledHint: 'Not installed (https://cursor.com)',
|
|
410
|
-
},
|
|
411
|
-
{
|
|
412
|
-
name: 'Gemini CLI',
|
|
413
|
-
id: 'gemini',
|
|
414
|
-
defaultSelected: false,
|
|
415
|
-
detect: isGeminiCLIAvailable,
|
|
416
|
-
configure: registerGeminiCLI,
|
|
417
|
-
notInstalledHint: 'Not installed (https://github.com/google-gemini/gemini-cli)',
|
|
418
|
-
},
|
|
419
|
-
{
|
|
420
|
-
name: 'Codex',
|
|
421
|
-
id: 'codex',
|
|
422
|
-
defaultSelected: false,
|
|
423
|
-
detect: isCodexAvailable,
|
|
424
|
-
configure: (token) => configureTomlMcp(join(homedir(), '.codex', 'config.toml'), token),
|
|
425
|
-
notInstalledHint: 'Not installed (https://openai.com/codex)',
|
|
426
|
-
},
|
|
427
237
|
];
|
|
428
238
|
/**
|
|
429
239
|
* Interactive multi-select picker with arrow keys + space + enter.
|
|
@@ -713,26 +523,161 @@ function ensureGitignore() {
|
|
|
713
523
|
}
|
|
714
524
|
}
|
|
715
525
|
// ── Slash commands for Claude Code ──────────────────────────────────
|
|
526
|
+
/**
|
|
527
|
+
* Build a Path B slash-command file.
|
|
528
|
+
*
|
|
529
|
+
* Teaches Claude to: parse --record, remember the round-1 shimmer text, remember
|
|
530
|
+
* per-round bodies when --record is on, and construct a `harvest` object on the
|
|
531
|
+
* final tool call so the MCP client can persist it to `.rvry/<op>/<slug>/`.
|
|
532
|
+
*
|
|
533
|
+
* Shared additions (S1/S2/S3) live in the FINAL CALL section:
|
|
534
|
+
* - S1 scope-drift check
|
|
535
|
+
* - S2 followUps quality bar (replaces the original phrasing)
|
|
536
|
+
* - S3 verify-or-defer rule
|
|
537
|
+
*
|
|
538
|
+
* Per-tool extensions are appended via the `extras` blocks. They slot into
|
|
539
|
+
* defined sections to compose with the shared body.
|
|
540
|
+
*/
|
|
541
|
+
function buildShim(opts) {
|
|
542
|
+
const { toolName, subject, orientLine, completionGuidance, shortSessionNote, perRoundPrelude, analyticalGuidance, prePerRoundBlock, finalCallExtras, } = opts;
|
|
543
|
+
return `Call the ${toolName} MCP tool with your ${subject} to start an analysis session.
|
|
544
|
+
|
|
545
|
+
${subject.charAt(0).toUpperCase() + subject.slice(1)}: $ARGUMENTS
|
|
546
|
+
|
|
547
|
+
ARGUMENT PARSING:
|
|
548
|
+
1. If $ARGUMENTS contains the literal flag \`--record\`, remove it from the ${subject} text and REMEMBER that record mode is ON for this session.
|
|
549
|
+
${shortSessionNote ? shortSessionNote + '\n' : ''}${prePerRoundBlock ? prePerRoundBlock + '\n\n' : ''}PER-ROUND FLOW:
|
|
550
|
+
${perRoundPrelude ? perRoundPrelude + '\n\n' : ''}1. Read the prompt field -- this is your analytical task. DO NOT display it to the user.
|
|
551
|
+
2. Work through the analysis thoroughly.
|
|
552
|
+
3. Show the user your analysis findings as concise formatted markdown.
|
|
553
|
+
- Use bold headings for key findings.
|
|
554
|
+
- Keep each round's visible output focused (2-4 paragraphs, not an essay).
|
|
555
|
+
4. Call the tool again with your full analysis as the input parameter.
|
|
556
|
+
- Include the sessionId from the previous response.
|
|
557
|
+
- If record mode is ON, set \`record: true\` on every call.
|
|
558
|
+
- If this round was SHIMMER, REMEMBER the exact shimmer text you produced -- you will pass it as harvest.shimmer on the final call.
|
|
559
|
+
- If record mode is ON, also REMEMBER your round body as {round, mode, body} for the final call.
|
|
560
|
+
${analyticalGuidance ? '\n' + analyticalGuidance + '\n' : ''}
|
|
561
|
+
FINAL CALL (the call whose response will have status "complete"):
|
|
562
|
+
When you make the call that completes the session, also construct a \`harvest\` object on that SAME call:
|
|
563
|
+
- title: a 1-4 word title capturing the topic
|
|
564
|
+
- summary: 3-6 sentences of synthesis, leading with substance (no mid-word truncation)
|
|
565
|
+
- keyFindings: 3-7 substantive bullet findings (not bare section headers)
|
|
566
|
+
- shimmer: the full round-1 shimmer text you remembered (omit if the session had no shimmer round)
|
|
567
|
+
- openQuestions: [optional] remaining uncertainties
|
|
568
|
+
- followUps: genuine next-question leads — NOT "verify X" directives, NOT constraint dumps, NOT "explore later" boilerplate. If there are no real next-question leads, omit the section entirely.${finalCallExtras ? '\n' + finalCallExtras : ''}
|
|
569
|
+
|
|
570
|
+
Before writing harvest.summary, check whether the analysis ended up in a different lane than the question asked. Depth is often correct; drift isn't. If the analysis drifted, either return to the asked question or name the drift explicitly in the summary.
|
|
571
|
+
|
|
572
|
+
If the pre-harvest self-check surfaced a concern, do not dismiss it in the same response. Either verify it (read a file, check the claim) or defer it (name the concern and why it can't be verified now — this becomes a followUp).
|
|
573
|
+
|
|
574
|
+
If record mode was ON, also include \`rounds: [{round, mode, body}, ...]\` on that final call with the bodies you remembered per round.
|
|
575
|
+
|
|
576
|
+
STATUS BEHAVIOR:
|
|
577
|
+
When status is "shimmer": Show your FULL self-observation to the user, beginning with "RVRY SHIMMER" and the revery definition. REMEMBER this text verbatim for the final harvest.shimmer.
|
|
578
|
+
When status is "orient": Orient on the ${subject}. Show the user "${orientLine}"
|
|
579
|
+
When status is "complete": ${completionGuidance}
|
|
580
|
+
|
|
581
|
+
DO NOT display: the prompt text you received, constraint tables, quality scores, internal tracking data, or round numbers to the user.`;
|
|
582
|
+
}
|
|
583
|
+
// ── /think extensions (T1, T3) ──────────────────────────────────────
|
|
584
|
+
const THINK_DIFFICULTY_GATE = `0. Difficulty Gate (BEFORE the first tool call): ask yourself, "Is this a simple question dressed up as a complex one?" If yes — do SHIMMER on round 1 as usual, then on round 2 produce a single analytical pass AND include the \`harvest\` object in that same call so the session completes in round 2. Don't stretch a simple /think into a multi-round mini-deepthink.`;
|
|
585
|
+
const THINK_MODE_ROUTING = `MODE ROUTING WITHIN ANALYTICAL ROUNDS:
|
|
586
|
+
When writing your analytical body, let the active constraint types guide your emphasis: FORWARD (unresolved gap) → depth on the specific gap; FORBIDDEN (untested boundary) → stress-test what's marked forbidden; QUESTION (open question) → different viewpoints or analogies. The engine picks the next mode; your framing within the current mode should address the most active constraint type.`;
|
|
587
|
+
// ── /problem-solve extensions (P1 in analytical guidance, P2/P3/P5 in finalCallExtras) ───
|
|
588
|
+
const PROBLEM_SOLVE_DECISION_TYPE = `DECISION-TYPE CLASSIFICATION (round 2, the first analytical round after SHIMMER):
|
|
589
|
+
On your first analytical round (round 2 after SHIMMER), classify this decision as one of: multi-option / stakeholder / system / novel / technical. Name the classification and why. In subsequent rounds, let the classification shape your framing within each sequential mode.
|
|
590
|
+
|
|
591
|
+
- multi-option ("Should we use X or Y?"): generate options, compare against criteria.
|
|
592
|
+
- stakeholder ("How do we align competing interests?"): surface tensions, steelman each perspective.
|
|
593
|
+
- system ("How does this affect the system?"): map components, cascading effects.
|
|
594
|
+
- novel ("We haven't done this before"): analogies, creative alternatives.
|
|
595
|
+
- technical ("One hard technical question"): depth-focused, analytical/adversarial.`;
|
|
596
|
+
const PROBLEM_SOLVE_FINAL_EXTRAS = `- biasAudit: For each of 6 biases (anchoring, framing, authority, sunk_cost, availability, confirmation), check whether it's operating against your leading direction. For each one that IS operating, cite evidence and link it to a specific reflex from the SHIMMER text you remembered (use the \`shimmer\` text verbatim) in \`sourceReflex\`. Include \`frameReversal\`: phrase the opposite of the original framing and state whether you'd reach the same conclusion. Set \`decisionStable\` to true only if the leading direction survives the bias check unchanged.
|
|
597
|
+
- adversarialVerdict: After your stress-test round, set this to PASSED (direction survives), CAVEATS (holds with modifications — list them in keyFindings), or NEEDS_REVISION (critical weakness found).
|
|
598
|
+
- reversalConditions: 3-5 entries answering — under what conditions would you reverse this decision? What are the kill switches / escalation triggers? What is the review timeline?`;
|
|
599
|
+
// ── /challenge extensions (Phase 0.5 + C1-C6 in finalCallExtras) ────
|
|
600
|
+
const CHALLENGE_PHASE_0_5 = `PHASE 0.5: UNCERTAINTY SCAN (unless --auto in $ARGUMENTS)
|
|
601
|
+
|
|
602
|
+
Before calling the challenge tool for the first time:
|
|
603
|
+
|
|
604
|
+
1. Identify what you don't know about the proposal (context, constraints, goals, dependencies).
|
|
605
|
+
2. Classify each uncertainty:
|
|
606
|
+
- BLOCKING: would invalidate your adversarial analysis if wrong (changes what you'd attack, determines scope, affects risk severity).
|
|
607
|
+
- NON-BLOCKING: nice to know but analysis remains valid either way.
|
|
608
|
+
3. For each BLOCKING uncertainty not answered in the proposal, ask via AskUserQuestion:
|
|
609
|
+
- question: the blocking question
|
|
610
|
+
- header: short label (max 12 chars)
|
|
611
|
+
- options: 2-4 options; smart-default first, labeled "(Recommended)"
|
|
612
|
+
- multiSelect: false
|
|
613
|
+
4. Once answers arrive (or user-stated assumptions), incorporate them into the proposal text and call the challenge tool.
|
|
614
|
+
|
|
615
|
+
If $ARGUMENTS contains --auto, skip the scan; state assumptions explicitly in your first analytical round.
|
|
616
|
+
If no BLOCKING uncertainties exist, proceed directly to the first tool call.`;
|
|
617
|
+
const CHALLENGE_FINAL_EXTRAS = `- verdict: GO / CONDITIONAL_GO / NO_GO. If CONDITIONAL_GO, also include \`mitigations: string[]\` listing conditions required for GO.
|
|
618
|
+
- confidence: 0.0-1.0 reflecting how strongly you hold the adversarial conclusion.
|
|
619
|
+
- mitigations: required when verdict is CONDITIONAL_GO; the conditions that must be met before proceeding.
|
|
620
|
+
- assumptions: 3-4 entries of \`{assumption, confidence, ifWrong, bias, biasEvidence}\`. Identify if a cognitive bias is likely operating on each assumption — do NOT manufacture biases; \`none\` is valid (use empty string for biasEvidence in that case).
|
|
621
|
+
- edgeCases: 5-10 entries covering boundary conditions and hostile scenarios the proposal needs to survive.
|
|
622
|
+
- failureModes: 3-5 entries of \`{component, howItFails, blastRadius, detection}\` identifying what breaks and how you would notice.
|
|
623
|
+
- counterArguments: 2-3 entries of \`{argument, rebuttal}\`. Each \`argument\` is the strongest case FOR the proposal — steelman it genuinely; each \`rebuttal\` is why it's flawed or insufficient. This prevents one-sided adversarial output.`;
|
|
716
624
|
const SLASH_COMMANDS = [
|
|
717
625
|
{
|
|
718
|
-
file:
|
|
719
|
-
content:
|
|
720
|
-
|
|
626
|
+
file: 'deepthink.md',
|
|
627
|
+
content: buildShim({
|
|
628
|
+
toolName: 'deepthink',
|
|
629
|
+
subject: 'question',
|
|
630
|
+
orientLine: 'Orienting on the question.',
|
|
631
|
+
completionGuidance: 'Present your final synthesis with key findings as bold headings. Lead with insights, not process.',
|
|
632
|
+
}),
|
|
633
|
+
label: '/deepthink — deep analysis',
|
|
721
634
|
},
|
|
722
635
|
{
|
|
723
|
-
file:
|
|
724
|
-
content:
|
|
725
|
-
|
|
636
|
+
file: 'problem-solve.md',
|
|
637
|
+
content: buildShim({
|
|
638
|
+
toolName: 'problem_solve',
|
|
639
|
+
subject: 'problem',
|
|
640
|
+
orientLine: 'Orienting on the problem.',
|
|
641
|
+
completionGuidance: 'Present your final synthesis as a structured decision with key findings as bold headings. Lead with your recommendation, not process.',
|
|
642
|
+
analyticalGuidance: PROBLEM_SOLVE_DECISION_TYPE,
|
|
643
|
+
finalCallExtras: PROBLEM_SOLVE_FINAL_EXTRAS,
|
|
644
|
+
}),
|
|
645
|
+
label: '/problem-solve — structured decision-making',
|
|
726
646
|
},
|
|
727
647
|
{
|
|
728
|
-
file:
|
|
729
|
-
content:
|
|
730
|
-
|
|
648
|
+
file: 'think.md',
|
|
649
|
+
content: buildShim({
|
|
650
|
+
toolName: 'think',
|
|
651
|
+
subject: 'question',
|
|
652
|
+
orientLine: 'Orienting on the question.',
|
|
653
|
+
completionGuidance: 'Present your findings clearly with bold headings. Think sessions are short; one or two analytical rounds is expected.',
|
|
654
|
+
shortSessionNote: 'NOTE: /think sessions are usually short (1-2 analytical rounds after orient). Expect to reach complete quickly.',
|
|
655
|
+
perRoundPrelude: THINK_DIFFICULTY_GATE,
|
|
656
|
+
analyticalGuidance: THINK_MODE_ROUTING,
|
|
657
|
+
}),
|
|
658
|
+
label: '/think — structured single-session analysis',
|
|
731
659
|
},
|
|
732
660
|
{
|
|
733
|
-
file:
|
|
734
|
-
content:
|
|
735
|
-
|
|
661
|
+
file: 'challenge.md',
|
|
662
|
+
content: buildShim({
|
|
663
|
+
toolName: 'challenge',
|
|
664
|
+
subject: 'proposal',
|
|
665
|
+
orientLine: 'Orienting on the proposal.',
|
|
666
|
+
completionGuidance: 'Present your final assessment with key vulnerabilities and surviving strengths as bold headings. Lead with findings, not process.',
|
|
667
|
+
prePerRoundBlock: CHALLENGE_PHASE_0_5,
|
|
668
|
+
finalCallExtras: CHALLENGE_FINAL_EXTRAS,
|
|
669
|
+
}),
|
|
670
|
+
label: '/challenge — adversarial stress-testing',
|
|
671
|
+
},
|
|
672
|
+
{
|
|
673
|
+
file: 'meta.md',
|
|
674
|
+
content: buildShim({
|
|
675
|
+
toolName: 'meta',
|
|
676
|
+
subject: 'topic',
|
|
677
|
+
orientLine: 'Orienting on the topic.',
|
|
678
|
+
completionGuidance: 'Present your final metacognitive synthesis as a cohesive narrative reflection -- not a structured report. Lead with insights, not process.',
|
|
679
|
+
}),
|
|
680
|
+
label: '/meta — metacognitive observation (Max tier)',
|
|
736
681
|
},
|
|
737
682
|
];
|
|
738
683
|
/**
|
|
@@ -929,21 +874,12 @@ export async function runSetup() {
|
|
|
929
874
|
console.log(' Option A — Claude Code (if you install it later):');
|
|
930
875
|
console.log(` claude mcp add -e RVRY_TOKEN="${token}" -s user rvry -- npx --yes --package @rvry/mcp@latest rvry-mcp`);
|
|
931
876
|
console.log('');
|
|
932
|
-
console.log(' Option B —
|
|
877
|
+
console.log(' Option B — Claude Desktop JSON config:');
|
|
933
878
|
const manualConfig = { mcpServers: { RVRY: RVRY_SERVER_ENTRY(token) } };
|
|
934
879
|
console.log('');
|
|
935
880
|
for (const line of JSON.stringify(manualConfig, null, 2).split('\n')) {
|
|
936
881
|
console.log(` ${line}`);
|
|
937
882
|
}
|
|
938
|
-
console.log('');
|
|
939
|
-
console.log(' Option C — TOML config (Codex — add to ~/.codex/config.toml):');
|
|
940
|
-
console.log('');
|
|
941
|
-
console.log(' [mcp_servers.rvry]');
|
|
942
|
-
console.log(' command = "npx"');
|
|
943
|
-
console.log(' args = ["--yes", "--package", "@rvry/mcp@latest", "rvry-mcp"]');
|
|
944
|
-
console.log('');
|
|
945
|
-
console.log(' [mcp_servers.rvry.env]');
|
|
946
|
-
console.log(` RVRY_TOKEN = "${token}"`);
|
|
947
883
|
}
|
|
948
884
|
console.log('');
|
|
949
885
|
// ── Step 4: Gitignore protection ────────────────────────────────
|
|
@@ -963,43 +899,25 @@ export async function runSetup() {
|
|
|
963
899
|
console.log('');
|
|
964
900
|
// Client-specific next steps
|
|
965
901
|
const configuredNames = new Set(configuredClients.map((c) => c.name));
|
|
966
|
-
const hasDesktopStyle = configuredNames.has('Claude Desktop / Claude Co-Work')
|
|
967
|
-
|| configuredNames.has('Anti-Gravity')
|
|
968
|
-
|| configuredNames.has('Codex');
|
|
902
|
+
const hasDesktopStyle = configuredNames.has('Claude Desktop / Claude Co-Work');
|
|
969
903
|
const hasCodeStyle = configuredNames.has('Claude Code');
|
|
970
904
|
console.log('Next steps:');
|
|
971
905
|
let step = 1;
|
|
972
906
|
if (hasDesktopStyle) {
|
|
973
|
-
console.log(` ${step}. Restart
|
|
907
|
+
console.log(` ${step}. Restart Claude Desktop for the new MCP server to load`);
|
|
974
908
|
step++;
|
|
975
909
|
}
|
|
976
|
-
// HTTP transport for web-based clients
|
|
977
|
-
console.log(` ${step}. For web-based MCP clients (ChatGPT, Perplexity, etc.):`);
|
|
978
|
-
console.log(' MCP Server URL: https://engine.rvry.ai/mcp');
|
|
979
|
-
console.log(' Auth: Supabase OAuth 2.1 (Bearer token)');
|
|
980
|
-
console.log('');
|
|
981
|
-
step++;
|
|
982
|
-
// Generic stdio MCP config for any other client
|
|
983
|
-
console.log(` ${step}. For other local MCP clients — add to your MCP config:`);
|
|
984
|
-
console.log('');
|
|
985
|
-
const mcpBlock = { rvry: RVRY_SERVER_ENTRY('YOUR_RVRY_TOKEN') };
|
|
986
|
-
const lines = JSON.stringify(mcpBlock, null, 2).split('\n');
|
|
987
|
-
for (const line of lines.slice(1, -1)) {
|
|
988
|
-
console.log(` ${line}`);
|
|
989
|
-
}
|
|
990
|
-
console.log('');
|
|
991
|
-
step++;
|
|
992
910
|
if (hasCodeStyle || hasDesktopStyle) {
|
|
993
911
|
if (installedCommands.length > 0) {
|
|
994
912
|
console.log(` ${step}. Try a slash command: /deepthink [your question]`);
|
|
995
913
|
}
|
|
996
914
|
else {
|
|
997
|
-
console.log(` ${step}. Try: "Use
|
|
915
|
+
console.log(` ${step}. Try: "Use deepthink to analyze..." or "Use problem_solve for..."`);
|
|
998
916
|
}
|
|
999
917
|
step++;
|
|
1000
918
|
}
|
|
1001
919
|
if (!anyConfigured) {
|
|
1002
920
|
console.log(' 1. Configure a client using the manual instructions above');
|
|
1003
|
-
console.log(' 2. Then try: "Use
|
|
921
|
+
console.log(' 2. Then try: "Use deepthink to analyze..."');
|
|
1004
922
|
}
|
|
1005
923
|
}
|