Skip to content

Instantly share code, notes, and snippets.

@CypherpunkSamurai
Forked from SaseQ/config.json
Created August 25, 2025 12:40
Show Gist options
  • Save CypherpunkSamurai/b7143f05c5e129188b4557c7f6e66c54 to your computer and use it in GitHub Desktop.
Save CypherpunkSamurai/b7143f05c5e129188b4557c7f6e66c54 to your computer and use it in GitHub Desktop.
Atlassian Rovo Dev CLI transformer for Claude Code Router
{
"transformers": [
{
"path": "$HOME/.claude-code-router/plugins/rovo-cli.js",
"options": {
"email": "ROVO_DEV_EMAIL",
"api_token": "ROVO_DEV_API_TOKEN"
}
}
],
"Providers": [
{
"name": "rovo-cli",
"api_base_url": "https://api.atlassian.com/rovodev/v2/proxy/ai/v1/openai/v1/chat/completions",
"api_key": "sk-xxx",
"models": ["gpt-5-2025-08-07"],
"transformer": {
"use": ["rovo-cli"]
}
}
],
"Router": {
"default": "rovo-cli,gpt-5-2025-08-07"
}
}
const os = require("os");
const path = require("path");
const fs = require("fs/promises");
class RovoCLITransformer {
name = "rovo-cli";
constructor(options) {
this.options = options;
}
async transformRequestIn(request, provider) {
const body = typeof request === "string" ? JSON.parse(request) : { ...request };
if (Object.prototype.hasOwnProperty.call(body, "max_tokens")) {
if (!Object.prototype.hasOwnProperty.call(body, "max_completion_tokens")) {
body.max_completion_tokens = body.max_tokens;
}
delete body.max_tokens;
}
if (body.params && typeof body.params === "object") {
if (Object.prototype.hasOwnProperty.call(body.params, "max_tokens")) {
if (!Object.prototype.hasOwnProperty.call(body.params, "max_completion_tokens")) {
body.params.max_completion_tokens = body.params.max_tokens;
}
delete body.params.max_tokens;
}
}
const toolsToAdd = await this.getDefaultRovoTools();
const existingTools = Array.isArray(body.tools) ? body.tools : [];
const byName = new Map();
for (const t of existingTools) {
const key = t?.function?.name || JSON.stringify(t);
byName.set(key, t);
}
for (const t of toolsToAdd) {
const key = t?.function?.name || JSON.stringify(t);
if (!byName.has(key)) byName.set(key, t);
}
body.tools = Array.from(byName.values());
const email = this.options?.email;
const api_token = this.options?.api_token;
const basicToken = Buffer.from(`${email}:${api_token}`, "utf-8").toString("base64");
return {
body,
config: {
headers: {
Authorization: `Basic ${basicToken}`,
},
},
};
}
getDefaultRovoTools() {
return [
{
"type": "function",
"function": {
"name": "open_files_legacy",
"description": "IGNORE THE TOOL. Kept for legacy. Open one or more files in the workspace. Supports text, image, and PDF documents.\n",
"parameters": {
"type": "object",
"properties": {
"file_paths": {
"type": "array",
"items": {"type": "string"},
"description": "A list of file paths to open."
}
},
"required": ["file_paths"]
}
}
},
{
"type": "function",
"function": {
"name": "create_file_legacy",
"description": "IGNORE THE TOOL. Kept for legacy. Create a file in the workspace.\n",
"parameters": {
"type": "object",
"properties": {
"file_path": {"type": "string"}
},
"required": ["file_path"]
}
}
},
{
"type": "function",
"function": {
"name": "expand_code_chunks_legacy",
"description": "IGNORE THE TOOL. Kept for legacy. Expand line ranges or code chunks within a file and return the expanded content.\n\nCode can be expanded by specifying line ranges or by searching for code symbols in the code, separating levels of\nhierarchy with slashes.\n\nExample patterns:\n- \"MyClass\": Selects the class definition and any references to MyClass.\n- \"my_function\": Selects the function definition and any uses of my_function.\n- \"def my_function\": Selects only the function definition for my_function.\n- \"MyClass/my_method\": Selects the method my_method within MyClass using slash separator.",
"parameters": {
"type": "object",
"properties": {
"file_path": {"type": "string"}
},
"required": ["file_path"]
}
}
}
];
}
}
module.exports = RovoCLITransformer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment