From 3dc39adc08932bb2e7f7ec18a562af3d8665d0a0 Mon Sep 17 00:00:00 2001 From: Recoup Agent Date: Thu, 19 Mar 2026 23:49:03 +0000 Subject: [PATCH 1/3] agent: @U0AJM7X8FBR How can we give Recoup the ability to use a chartmetric API --- src/sandboxes/getSandboxEnv.ts | 5 +++++ src/sandboxes/setupOpenClaw.ts | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/sandboxes/getSandboxEnv.ts b/src/sandboxes/getSandboxEnv.ts index 3906254..6cf0cbe 100644 --- a/src/sandboxes/getSandboxEnv.ts +++ b/src/sandboxes/getSandboxEnv.ts @@ -20,5 +20,10 @@ export function getSandboxEnv( env.GITHUB_TOKEN = githubToken; } + const chartmetricRefreshToken = process.env.CHARTMETRIC_REFRESH_TOKEN; + if (chartmetricRefreshToken) { + env.CHARTMETRIC_REFRESH_TOKEN = chartmetricRefreshToken; + } + return env; } diff --git a/src/sandboxes/setupOpenClaw.ts b/src/sandboxes/setupOpenClaw.ts index 7f7c480..6005c9e 100644 --- a/src/sandboxes/setupOpenClaw.ts +++ b/src/sandboxes/setupOpenClaw.ts @@ -24,11 +24,13 @@ export async function setupOpenClaw( } const githubToken = process.env.GITHUB_TOKEN; + const chartmetricRefreshToken = process.env.CHARTMETRIC_REFRESH_TOKEN; logger.log("Injecting env vars into openclaw.json", { RECOUP_API_KEY: `${process.env.RECOUP_API_KEY.slice(0, 4)}...`, RECOUP_ACCOUNT_ID: accountId, GITHUB_TOKEN: githubToken ? "present" : "missing", + CHARTMETRIC_REFRESH_TOKEN: chartmetricRefreshToken ? "present" : "missing", }); const injectEnv = await sandbox.runCommand({ @@ -43,6 +45,7 @@ export async function setupOpenClaw( c.env.RECOUP_API_KEY = '${process.env.RECOUP_API_KEY}'; c.env.RECOUP_ACCOUNT_ID = '${accountId}'; ${githubToken ? `c.env.GITHUB_TOKEN = '${githubToken}';` : ""} + ${chartmetricRefreshToken ? `c.env.CHARTMETRIC_REFRESH_TOKEN = '${chartmetricRefreshToken}';` : ""} c.tools = c.tools || {}; c.tools.profile = 'coding'; c.agents = c.agents || {}; From 4dfb58f058df6084efcbf6e895cad59ffb4d8fca Mon Sep 17 00:00:00 2001 From: Recoup Agent Date: Fri, 20 Mar 2026 00:08:37 +0000 Subject: [PATCH 2/3] feat: inject CHARTMETRIC_BASE_URL proxy instead of refresh token MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements Option A for credits: sandboxes now receive CHARTMETRIC_BASE_URL pointing to the api proxy (https://recoup-api.vercel.app/api/chartmetric) instead of the raw CHARTMETRIC_REFRESH_TOKEN. The proxy handles token exchange, credit deduction, and forwards requests to Chartmetric — keeping the key server-side only. Co-Authored-By: Claude Sonnet 4.6 --- src/sandboxes/getSandboxEnv.ts | 5 +---- src/sandboxes/setupOpenClaw.ts | 5 ++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/sandboxes/getSandboxEnv.ts b/src/sandboxes/getSandboxEnv.ts index 6cf0cbe..ee8c2e5 100644 --- a/src/sandboxes/getSandboxEnv.ts +++ b/src/sandboxes/getSandboxEnv.ts @@ -20,10 +20,7 @@ export function getSandboxEnv( env.GITHUB_TOKEN = githubToken; } - const chartmetricRefreshToken = process.env.CHARTMETRIC_REFRESH_TOKEN; - if (chartmetricRefreshToken) { - env.CHARTMETRIC_REFRESH_TOKEN = chartmetricRefreshToken; - } + env.CHARTMETRIC_BASE_URL = "https://recoup-api.vercel.app/api/chartmetric"; return env; } diff --git a/src/sandboxes/setupOpenClaw.ts b/src/sandboxes/setupOpenClaw.ts index 6005c9e..549fafd 100644 --- a/src/sandboxes/setupOpenClaw.ts +++ b/src/sandboxes/setupOpenClaw.ts @@ -24,13 +24,12 @@ export async function setupOpenClaw( } const githubToken = process.env.GITHUB_TOKEN; - const chartmetricRefreshToken = process.env.CHARTMETRIC_REFRESH_TOKEN; logger.log("Injecting env vars into openclaw.json", { RECOUP_API_KEY: `${process.env.RECOUP_API_KEY.slice(0, 4)}...`, RECOUP_ACCOUNT_ID: accountId, GITHUB_TOKEN: githubToken ? "present" : "missing", - CHARTMETRIC_REFRESH_TOKEN: chartmetricRefreshToken ? "present" : "missing", + CHARTMETRIC_BASE_URL: "https://recoup-api.vercel.app/api/chartmetric", }); const injectEnv = await sandbox.runCommand({ @@ -45,7 +44,7 @@ export async function setupOpenClaw( c.env.RECOUP_API_KEY = '${process.env.RECOUP_API_KEY}'; c.env.RECOUP_ACCOUNT_ID = '${accountId}'; ${githubToken ? `c.env.GITHUB_TOKEN = '${githubToken}';` : ""} - ${chartmetricRefreshToken ? `c.env.CHARTMETRIC_REFRESH_TOKEN = '${chartmetricRefreshToken}';` : ""} + c.env.CHARTMETRIC_BASE_URL = 'https://recoup-api.vercel.app/api/chartmetric'; c.tools = c.tools || {}; c.tools.profile = 'coding'; c.agents = c.agents || {}; From f069a08b2f6b3d18cc2387cba7e1b4f57de7a422 Mon Sep 17 00:00:00 2001 From: Recoup Agent Date: Fri, 20 Mar 2026 00:49:04 +0000 Subject: [PATCH 3/3] fix: update getSandboxEnv tests to include CHARTMETRIC_BASE_URL Tests were failing because the new CHARTMETRIC_BASE_URL env var was added to getSandboxEnv but the test assertions were not updated to expect it. Co-Authored-By: Claude Sonnet 4.6 --- src/sandboxes/__tests__/getSandboxEnv.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sandboxes/__tests__/getSandboxEnv.test.ts b/src/sandboxes/__tests__/getSandboxEnv.test.ts index 1942b29..de2d62c 100644 --- a/src/sandboxes/__tests__/getSandboxEnv.test.ts +++ b/src/sandboxes/__tests__/getSandboxEnv.test.ts @@ -13,17 +13,18 @@ describe("getSandboxEnv", () => { process.env = { ...originalEnv }; }); - it("returns RECOUP_API_KEY, RECOUP_ACCOUNT_ID, and GITHUB_TOKEN", () => { + it("returns RECOUP_API_KEY, RECOUP_ACCOUNT_ID, GITHUB_TOKEN, and CHARTMETRIC_BASE_URL", () => { const env = getSandboxEnv("acc_123"); expect(env).toEqual({ RECOUP_API_KEY: "test-api-key", RECOUP_ACCOUNT_ID: "acc_123", GITHUB_TOKEN: "test-github-token", + CHARTMETRIC_BASE_URL: "https://recoup-api.vercel.app/api/chartmetric", }); }); - it("omits GITHUB_TOKEN when not set", () => { + it("omits GITHUB_TOKEN when not set but still includes CHARTMETRIC_BASE_URL", () => { delete process.env.GITHUB_TOKEN; const env = getSandboxEnv("acc_123"); @@ -31,6 +32,7 @@ describe("getSandboxEnv", () => { expect(env).toEqual({ RECOUP_API_KEY: "test-api-key", RECOUP_ACCOUNT_ID: "acc_123", + CHARTMETRIC_BASE_URL: "https://recoup-api.vercel.app/api/chartmetric", }); expect(env).not.toHaveProperty("GITHUB_TOKEN"); });