Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions apps/api/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Server
PORT=4000
SUPERCODE_JSON_BODY_LIMIT=10mb

# Auth (Better-Auth)
BETTER_AUTH_URL=http://localhost:4000
CLIENT_URL=http://localhost:3000

# Database (terminal DB)
DATABASE_URL=postgresql://user:password@localhost:5432/supercode_terminal

# GitHub OAuth
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=

# Provider API Keys
GOOGLE_GENERATIVE_AI_API_KEY=
OPENROUTER_API_KEY=
OPENROUTER_MODEL=openai/gpt-oss-120b:free
MINIMAX_API_KEY=
MINIMAX_MAX_TOKENS=4096
NVIDIA_API_KEY=
NVIDIA_BASE_URL=https://integrate.api.nvidia.com/v1
NVIDIA_MODEL=minimaxai/minimax-m3
NVIDIA_MAX_TOKENS=8192
NVIDIA_TEMPERATURE=1
NVIDIA_TOP_P=0.95
MERGE_DEV_API_KEY=
ORCAROUTER_API_KEY=
CONCENTRATEAI_API_KEY=
24 changes: 21 additions & 3 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,28 @@
"name": "api",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "echo 'api app scaffold pending'",
"build": "echo 'api build scaffold pending'",
"dev": "bun --watch src/index.ts",
"build": "bun build --target bun --outdir dist src/index.ts",
"start": "bun src/index.ts",
Comment on lines +8 to +9

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Run the artifact produced by build.

build emits dist/index.js, but start runs src/index.ts. This means production does not use the built artifact and deployments containing only dist cannot start.

Suggested fix
-    "start": "bun src/index.ts",
+    "start": "bun dist/index.js",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"build": "bun build --target bun --outdir dist src/index.ts",
"start": "bun src/index.ts",
"build": "bun build --target bun --outdir dist src/index.ts",
"start": "bun dist/index.js",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/package.json` around lines 8 - 9, Update the package.json start
script to execute the dist/index.js artifact generated by the build script,
instead of launching src/index.ts. Keep the existing build command unchanged so
production starts from the compiled output.

"lint": "echo 'api lint scaffold pending'",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Replace the no-op lint script.

bun run lint currently succeeds without checking any source files, so the PR’s lint validation provides no protection against lint regressions. Wire an actual linter or fail until one is configured.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/package.json` at line 10, Replace the no-op "lint" script in
package.json with a command that runs the project's configured linter against
the API source files, or make the script exit nonzero until linting is
configured. Ensure bun run lint cannot succeed without performing real
validation.

"typecheck": "echo 'api typecheck scaffold pending'"
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@ai-sdk/google": "^3.0.80",
"@ai-sdk/openai-compatible": "^2.0.48",
"@hono/zod-validator": "^0.5.0",
"@openrouter/ai-sdk-provider": "^2.9.0",
"@super/db-terminal": "workspace:*",
"ai": "^7.0.37",
"better-auth": "^1.6.23",
"hono": "^4.7.0",
"vercel-minimax-ai-provider": "^0.0.2",
"zod": "^3.25.2"
},
"devDependencies": {
"@types/bun": "^1.3.14",
"typescript": "^5.7.0"
}
}
29 changes: 29 additions & 0 deletions apps/api/src/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Hono } from "hono"
import { cors } from "hono/cors"
import { logger } from "hono/logger"
import { bodyLimit } from "hono/body-limit"
import { healthRoute } from "./routes/health"
import { authRoute } from "./routes/auth"
import { aiRoute } from "./routes/ai"
import type { AppEnv } from "./types"

export function createApp() {
const app = new Hono<AppEnv>().basePath("/api")

app.use("*", logger())
app.use("*", cors())
app.use("*", bodyLimit({
maxSize: 10 * 1024 * 1024,
}))
Comment on lines +15 to +17

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Connect the documented body-limit configuration to runtime behavior.

The environment variable is declared but ignored by the application’s hardcoded limit.

  • apps/api/src/app.ts#L15-L17: parse and apply SUPERCODE_JSON_BODY_LIMIT.
  • apps/api/.env.example#L3-L3: keep the variable only if the application actually consumes it.
📍 Affects 2 files
  • apps/api/src/app.ts#L15-L17 (this comment)
  • apps/api/.env.example#L3-L3
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/app.ts` around lines 15 - 17, Update the bodyLimit configuration
in apps/api/src/app.ts lines 15-17 to read and parse SUPERCODE_JSON_BODY_LIMIT,
using the parsed value as maxSize instead of the hardcoded limit. Keep
SUPERCODE_JSON_BODY_LIMIT in apps/api/.env.example line 3 because the runtime
configuration will consume it.


app.onError((err, c) => {
console.error("[API Error]", err)
return c.json({ error: "Internal server error" }, 500)
})

app.route("/", healthRoute)
app.route("/", authRoute)
app.route("/", aiRoute)
Comment on lines +24 to +26

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- files ---\n'
git ls-files | rg '(^|/)(app|auth).*\.(ts|tsx|js)$|auth' || true

printf '\n--- app.ts outline ---\n'
ast-grep outline apps/api/src/app.ts --view expanded || true

printf '\n--- app.ts ---\n'
cat -n apps/api/src/app.ts

printf '\n--- auth.ts outline ---\n'
ast-grep outline apps/api/src/lib/auth.ts --view expanded || true

printf '\n--- auth.ts ---\n'
cat -n apps/api/src/lib/auth.ts

printf '\n--- route files matching auth/health/ai ---\n'
git ls-files apps/api/src | rg '(^|/)(routes|lib|index|auth|health|ai)\.(ts|js)$' || true

printf '\n--- route usages ---\n'
rg -n "healthRoute|authRoute|aiRoute|basePath|betterAuth|auth/me|sign-out|callback/github|`@auth`|/api/auth|toAuth" apps/api/src -S || true

Repository: yashdev9274/supercli

Length of output: 249


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- files ---'
git ls-files | rg '(^|/)(app|auth).*\.(ts|tsx|js)$|auth' || true

printf '%s\n' '\n--- app.ts outline ---'
ast-grep outline apps/api/src/app.ts --view expanded || true

printf '%s\n' '\n--- app.ts ---'
cat -n apps/api/src/app.ts

printf '%s\n' '\n--- auth.ts outline ---'
ast-grep outline apps/api/src/lib/auth.ts --view expanded || true

printf '%s\n' '\n--- auth.ts ---'
cat -n apps/api/src/lib/auth.ts

printf '%s\n' '\n--- route files matching auth/health/ai ---'
git ls-files apps/api/src | rg '(^|/)(routes|lib|index|auth|health|ai)\.(ts|js)$' || true

printf '%s\n' '\n--- route usages ---'
rg -n "healthRoute|authRoute|aiRoute|basePath|betterAuth|auth/me|sign-out|callback/github|`@auth`|/api/auth|toAuth" apps/api/src -S || true

Repository: yashdev9274/supercli

Length of output: 22917


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- apps/api/src/routes/auth.ts ---'
cat -n apps/api/src/routes/auth.ts

printf '%s\n' '\n--- apps/api/src/middleware/auth.ts ---'
cat -n apps/api/src/middleware/auth.ts

printf '%s\n' '\n--- apps/api package.json/auth deps ---'
if [ -f apps/api/package.json ]; then cat -n apps/api/package.json | sed -n '1,220p'; fi

printf '%s\n' '\n--- root/package lock snippets for hono/better-auth ---'
if [ -f package.json ]; then rg -n '"hono"|"better-auth"' package.json apps packages -S || true; fi

Repository: yashdev9274/supercli

Length of output: 10194


🌐 Web query:

better-auth Node.js Hono getHandler postHandler basePath toAuth

💡 Result:

In Better Auth, the handler function acts as the unified endpoint for all authentication-related requests (GET and POST) [1][2]. When integrating with Hono, you mount this handler to a specific path using Hono's.on method [3][4]. Mounting the Handler The standard approach is to use a wildcard path to ensure all authentication sub-routes are captured [2][4]. It is recommended to use the single asterisk () wildcard rather than double, as the latter can cause routing conflicts in some Hono configurations [5]. Example implementation: const app = new Hono; app.on(["POST", "GET"], "/api/auth/", (c) => { return auth.handler(c.req.raw); }); Configuration and basePath The path you provide in app.on must align with the basePath defined in your Better Auth configuration [6]. By default, Better Auth uses /api/auth as its base path [6]. If you change the basePath in your auth options, you must update the mounting path in your Hono application to match [6]. Key Considerations 1. CORS Middleware: If your frontend is on a different domain, register the Hono CORS middleware before the auth route to ensure preflight requests (OPTIONS) are handled correctly [2][4]. 2. Session Middleware: You can define a global Hono middleware that calls auth.api.getSession to populate the Hono context (c.set) with user and session data, making it available to other routes [2][4]. 3. Client Configuration: When using the Hono RPC client (@hono/client) from a different domain, you must set credentials: "include" in the client's configuration to ensure cookies are sent with requests [2][4]. Note: The terms getHandler, postHandler, and toAuth are not standard, primary methods for Better Auth/Hono integration; the unified auth.handler method is the designated, authoritative way to process requests [1][2]. For frameworks like Next.js or generic Node.js pages, different utilities such as toNextJsHandler or toNodeHandler are used instead [7].

Citations:


Mount the Better Auth handler.

apps/api/src/lib/auth.ts configures Better Auth with basePath: "/api/auth", but apps/api/src/app.ts only mounts the custom /auth/me and /auth/sign-out routes. GitHub sign-in and /api/auth/callback/github need the Better Auth GET/POST handler mounted as a wildcard under the same base paths before the custom auth handlers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/app.ts` around lines 24 - 26, Update the app route registration
in the app initialization flow to mount the Better Auth GET/POST wildcard
handler from the auth configuration before authRoute, using the configured
/api/auth base path so GitHub sign-in and callback requests are handled while
preserving the existing custom auth routes.


return app
}
14 changes: 14 additions & 0 deletions apps/api/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { serve } from "bun"
import { createApp } from "./app"

const PORT = Number(process.env.PORT) || 4000

serve({
fetch: createApp().fetch,
port: PORT,
development: {
hmr: true,
},
})

console.log(`[API] Server running on http://localhost:${PORT}`)
21 changes: 21 additions & 0 deletions apps/api/src/lib/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { betterAuth } from "better-auth"
import { prismaAdapter } from "better-auth/adapters/prisma"
import prisma from "./prisma"

const serverUrl = process.env.BETTER_AUTH_URL || "http://localhost:4000"
const clientUrl = process.env.CLIENT_URL || "http://localhost:3000"
const isProduction = serverUrl.startsWith("https://")

export const auth = betterAuth({
database: prismaAdapter(prisma, { provider: "postgresql" }),
baseURL: serverUrl,
basePath: "/api/auth",
trustedOrigins: [clientUrl, serverUrl],
socialProviders: {
github: {
clientId: process.env.GITHUB_CLIENT_ID as string,
clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
Comment on lines +16 to +17

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)(auth\.ts|\.env\.example|package\.json|pnpm-lock\.yaml)$' || true

echo "== auth outline =="
if [ -f apps/api/src/lib/auth.ts ]; then
  ast-grep outline apps/api/src/lib/auth.ts || true
  wc -l apps/api/src/lib/auth.ts
  sed -n '1,220p' apps/api/src/lib/auth.ts | cat -n
fi

echo "== env references =="
rg -n "GITHUB_CLIENT_ID|GITHUB_CLIENT_SECRET|github|GITHUB|CLIENT_URL|SERVER_URL|better-auth" apps/api .env.example .env* -S 2>/dev/null || true

Repository: yashdev9274/supercli

Length of output: 2899


🌐 Web query:

Better Auth OAuth github redirectURI baseURL SERVER_URL CLIENT_URL environment

💡 Result:

In Better Auth, managing OAuth redirect URIs involves correctly configuring your environment and authentication settings to bridge the gap between your server (where the auth logic runs) and your client (where the user interacts with your application) [1]. Key Configuration Concepts baseURL: This is the root URL of your authentication server [2]. You should always set this explicitly in your Better Auth configuration or via the environment variable BETTER_AUTH_URL [3]. Relying on automatic request inference is not recommended for production environments [3]. redirectURI: By default, Better Auth constructs the redirect URI using the baseURL and a standard callback path (e.g., /api/auth/callback/github) [4][5]. You can override this by providing a specific redirectURI in the provider configuration [2][3], but it must match exactly what you have registered in your GitHub OAuth App settings. Handling Client vs. Server URLs A common issue occurs when your server runs on one port (e.g., 8787) and your client on another (e.g., 3000) [1]. Better Auth might default to the server's URL, leading to redirect mismatches [1]. To resolve this: 1. Trusted Origins: Add your client's URL to the trustedOrigins array in your auth configuration to allow cross-origin communication [1]. export const auth = betterAuth({ baseURL: "http://your-server-url", trustedOrigins: ["http://localhost:3000"], }); 2. Callback URL Parameter: When initiating the sign-in process on the client, pass the callbackURL parameter to specify where the user should be sent after the OAuth flow completes [1]. await authClient.signIn.social({ provider: "github", callbackURL: "http://localhost:3000/dashboard", }); 3. OAuth Proxy Plugin: For complex deployments (e.g., preview environments or multi-host setups), use the OAuth Proxy plugin [6]. This allows you to register only your production callback URL with GitHub while the plugin handles routing requests from other environments through your production server [6]. Always ensure that the redirect URL registered in your GitHub Developer Settings matches the callback endpoint constructed by Better Auth [7][6]. If you are using the Generic OAuth plugin, remember that the redirectURI must include the:providerId placeholder [5][8].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== root env example =="
if [ -f .env.example ]; then
  cat -n .env.example | sed -n '1,180p'
fi

echo "== apps/api env example =="
if [ -f apps/api/.env.example ]; then
  cat -n apps/api/.env.example | sed -n '1,180p'
fi

echo "== runtime probe process.env assertion behavior =="
node - <<'JS'
const env = { GITHUB_CLIENT_ID: undefined, GITHUB_CLIENT_SECRET: undefined }

function register(input) {
  return {
    clientId: input.GITHUB_CLIENT_ID,
    clientSecret: input.GITHUB_CLIENT_SECRET,
    authEnvIsNull: input.GITHUB_CLIENT_ID === null,
    authEnvIsUndefined: input.GITHUB_CLIENT_ID === undefined,
    authEnvEmptyString: input.GITHUB_CLIENT_ID === "",
  }
}
console.log(JSON.stringify(register(env), null, 2))
JS

echo "== better-auth package metadata/source availability =="
python3 - <<'PY'
import json
from pathlib import Path
root = Path("apps/api")
for p in ["package.json", "pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lockb"]:
    path = root / p
    print(f"{path}: exists={path.exists()}")
PY

Repository: yashdev9274/supercli

Length of output: 1958


Validate GitHub credentials before registering the provider.

as string only suppresses TypeScript errors; it does not convert missing environment variables into strings. With apps/api/.env.example, GitHub is configured with undefined credentials, so the provider can register with no clientId/clientSecret. Omit the provider when GitHub is optional, or fail fast with a clear configuration error when it is required.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/lib/auth.ts` around lines 16 - 17, Validate GITHUB_CLIENT_ID and
GITHUB_CLIENT_SECRET before registering the GitHub provider instead of relying
on type assertions. When GitHub is optional, omit the provider if either value
is missing; when required, fail fast with a clear configuration error, ensuring
no provider is registered with undefined credentials.

...(isProduction ? { redirectURI: `${clientUrl}/api/auth/callback/github` } : {}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== candidate files =="
git ls-files | rg '(^|/)apps/api/src/lib/auth\.ts$|auth|better-auth|callback|route|routes|middleware' || true

echo "== auth.ts =="
if [ -f apps/api/src/lib/auth.ts ]; then
  cat -n apps/api/src/lib/auth.ts
fi

echo "== surrounding auth references =="
rg -n "CLIENT_URL|clientUrl|baseURL|basePath|redirectURI|redirectUrl|github|callbacks|better-auth|originPath|handler|auth" apps -S || true

Repository: yashdev9274/supercli

Length of output: 50376


🌐 Web query:

Better Auth socialProvider github redirectURI documentation

💡 Result:

In Better Auth, the redirectURI option within the socialProviders configuration is an optional parameter used to specify a custom callback URL for the OAuth flow [1][2][3]. By default, Better Auth automatically constructs the callback URL using the format: {baseURL}/api/auth/callback/{providerName} [4][5][2] ### How to Configure To override this default behavior, you can explicitly define the redirectURI in your betterAuth configuration object [1][3]. ts import { betterAuth } from "better-auth"; export const auth = betterAuth({ baseURL: "https://your-app.com", // Ensure this is set correctly socialProviders: { github: { clientId: process.env.GITHUB_CLIENT_ID!, clientSecret: process.env.GITHUB_CLIENT_SECRET!, // Optional: Custom redirect URI redirectURI: "https://your-app.com/api/auth/callback/github", }, }, }); ### Important Considerations 1. Ensure the redirectURI you provide in the configuration matches the one registered in your GitHub Developer Settings exactly [6]. 2. The baseURL (or BETTER_AUTH_URL environment variable) is critical [6]. Better Auth uses this to build the callback URL, and incorrect settings often result in redirect_uri_mismatch errors from the provider [6]. 3. For local development, ensure your baseURL is set to your local address (e.g., http://localhost:3000), and register this same URL in your GitHub OAuth App settings [6]. For further details, refer to the Better Auth OAuth documentation or the configuration reference [4][3].

Citations:


🌐 Web query:

Better Auth GitHub OAuth callback path redirectURI callback URL

💡 Result:

In Better Auth, the callback URL (or redirect URI) must follow a specific pattern for the library to correctly identify and handle the OAuth provider. The standard pattern for the callback URL is: {baseURL}/api/auth/callback/github [1][2] Key Configuration Details: 1. Requirement for Provider Identification: Better Auth internally registers callback routes using the pattern /callback/:id [3]. If the callback URL does not include the provider name (e.g., /callback/github), Better Auth will be unable to identify which provider is handling the request, typically resulting in a 404 error [3]. 2. Setting the baseURL: It is recommended to configure the baseURL in your Better Auth instance [3][1]. When set correctly, Better Auth will automatically construct the appropriate callback URL for each provider, avoiding common redirect_uri_mismatch errors [1]. 3. GitHub App Configuration: You must register this exact URL in your GitHub Developer Portal settings [4][1]. - For local development: http://localhost:3000/api/auth/callback/github [4] - For production: Replace with your actual domain, such as https://example.com/api/auth/callback/github [4][1] 4. Custom redirectURI: While you can manually specify a redirectURI in the socialProviders configuration, it must still match the path expected by Better Auth (/callback/github) [3][5][6]. The redirectURI option is used by the provider for the redirect after authorization, but it does not change Better Auth's internal routing requirements [3]. Example Configuration: export const auth = betterAuth({ baseURL: process.env.BETTER_AUTH_URL, // e.g., "https://example.com/api/auth" [3][1] socialProviders: { github: { clientId: process.env.GITHUB_CLIENT_ID as string, clientSecret: process.env.GITHUB_CLIENT_SECRET as string, }, }, }); In summary, ensure the URL registered in your GitHub app settings matches {baseURL}/api/auth/callback/github exactly [3][1].

Citations:


Use the API callback URL for GitHub OAuth.

redirectURI should point at the Better-Auth server, not the client URL. With baseURL set in production values to the API host, this should be something like ${serverUrl}/api/auth/callback/github, so GitHub redirects to the route the backend actually handles.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/lib/auth.ts` at line 18, Update the GitHub OAuth configuration
in the auth setup so the production redirectURI uses serverUrl, matching the
Better-Auth baseURL, rather than clientUrl; preserve the existing callback path
and non-production behavior.

},
},
})
37 changes: 37 additions & 0 deletions apps/api/src/lib/pricing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export interface ModelPricing {
input: number
output: number
cacheRead: number
cacheWrite: number
}

const MODEL_PRICING: Record<string, ModelPricing> = {
"gemini-3-flash-preview": { input: 1, output: 4, cacheRead: 0.25, cacheWrite: 1 },
"gemini-3-pro-preview": { input: 1.25, output: 10, cacheRead: 0.315, cacheWrite: 1.25 },
"minimax-m3": { input: 0.15, output: 0.85, cacheRead: 0.015, cacheWrite: 0.15 },
"nvidia/minimax-m3": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
}

export function lookupPricing(model: string): ModelPricing {
return (
MODEL_PRICING[model] ?? {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
}
)
}

export function computeCost(
model: string,
inputTokens: number,
outputTokens: number,
cachedInputTokens: number
): number {
const p = lookupPricing(model)
const regularInput = inputTokens - cachedInputTokens
const cost =
(regularInput * p.input + cachedInputTokens * p.cacheRead + outputTokens * p.output) / 1_000_000
return Math.round(cost * 1_000_000) / 1_000_000
}
Comment on lines +1 to +37

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n "from \"\.\./lib/pricing\"|from \"\./pricing\"|lib/pricing" --type=ts

Repository: yashdev9274/supercli

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -u

echo "Repository files matching pricing.ts/index.ts:"
git ls-files | rg '(^|/)pricing\.ts$|(^|/)index\.ts$' || true

echo
echo "Pricing module exports/import/usages:"
rg -n "lookupPricing|computeCost|ModelPricing|MODEL_PRICING|from \"\.\./lib/pricing\"|from \"\./pricing\"|lib/pricing" --type=ts .

echo
echo "apps/api/src/lib/pricing.ts:"
cat -n apps/api/src/lib/pricing.ts | sed -n '1,120p'

echo
echo "apps/api/src/providers/index.ts (provider pricing area):"
if [ -f apps/api/src/providers/index.ts ]; then
  wc -l apps/api/src/providers/index.ts
  sed -n '1,130p' apps/api/src/providers/index.ts | cat -n
fi

Repository: yashdev9274/supercli

Length of output: 15336


Fix the nvidia pricing lookup in providers/index.ts.

routeToProvider() maps NVIDIA to aiModel: "minimaxai/minimax-m3", but the local pricing table only has minimax-m3. That lookup falls back to 0 costs, so NVIDIA requests are reported without pricing. Use a shared pricing module or update this lookup to match the routed model key.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/lib/pricing.ts` around lines 1 - 37, The NVIDIA routed model key
is “minimaxai/minimax-m3”, but MODEL_PRICING only recognizes “minimax-m3”,
causing zero-cost lookups. Update the pricing lookup or shared pricing
definitions used by routeToProvider so the routed NVIDIA key resolves to the
Minimax pricing values, while preserving existing model pricing behavior.

2 changes: 2 additions & 0 deletions apps/api/src/lib/prisma.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import prisma from "@super/db-terminal"
export default prisma
47 changes: 47 additions & 0 deletions apps/api/src/lib/token-budget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import prisma from "./prisma"

const DAILY_TOKEN_LIMIT = 128_000
const DAILY_QUERY_LIMIT = 20

export async function checkDailyTokenBudget(userId: string): Promise<{
allowed: boolean
used: number
limit: number
remaining: number
queriesUsed: number
queriesRemaining: number
}> {
const today = new Date()
today.setHours(0, 0, 0, 0)
const tomorrow = new Date(today)
tomorrow.setDate(tomorrow.getDate() + 1)

const events = await prisma.usageEvent.findMany({
where: {
createdAt: { gte: today, lt: tomorrow },
},
select: {
inputTokens: true,
outputTokens: true,
cachedInputTokens: true,
},
})
Comment on lines +6 to +28

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n "checkDailyTokenBudget" --type=ts
rg -n "model UsageEvent" -A 15 --type-add 'prisma:*.prisma' --type prisma

Repository: yashdev9274/supercli

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -u

printf 'tracked files matching token-budget/checkDailyTokenBudget/UsageEvent:\n'
git ls-files | rg -i 'token-budget|checkDailyToken|usage|prisma|schema' || true

printf '\nAll occurrences of checkDailyTokenBudget / UsageEvent in repo:\n'
rg -n "checkDailyTokenBudget|UsageEvent|usageEvent" . || true

printf '\nCandidate file snippets:\n'
fd -a 'token-budget\.(ts|tsx|js|jsx)$|schema\.prisma$' . | while read -r f; do
  printf '\n--- %s ---\n' "$f"
  wc -l "$f"
  sed -n '1,220p' "$f" | cat -n
done

Repository: yashdev9274/supercli

Length of output: 29096


Scope this daily budget check to the passed userId.

checkDailyTokenBudget(userId) returns usage from all UsageEvent rows because the where clause only filters by date. Use the provided userId where usage is per-user; if the optional value is intentional, make that documented/null behavior explicit.

🐛 Proposed fix
   const events = await prisma.usageEvent.findMany({
     where: {
+      userId,
       createdAt: { gte: today, lt: tomorrow },
     },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function checkDailyTokenBudget(userId: string): Promise<{
allowed: boolean
used: number
limit: number
remaining: number
queriesUsed: number
queriesRemaining: number
}> {
const today = new Date()
today.setHours(0, 0, 0, 0)
const tomorrow = new Date(today)
tomorrow.setDate(tomorrow.getDate() + 1)
const events = await prisma.usageEvent.findMany({
where: {
createdAt: { gte: today, lt: tomorrow },
},
select: {
inputTokens: true,
outputTokens: true,
cachedInputTokens: true,
},
})
export async function checkDailyTokenBudget(userId: string): Promise<{
allowed: boolean
used: number
limit: number
remaining: number
queriesUsed: number
queriesRemaining: number
}> {
const today = new Date()
today.setHours(0, 0, 0, 0)
const tomorrow = new Date(today)
tomorrow.setDate(tomorrow.getDate() + 1)
const events = await prisma.usageEvent.findMany({
where: {
userId,
createdAt: { gte: today, lt: tomorrow },
},
select: {
inputTokens: true,
outputTokens: true,
cachedInputTokens: true,
},
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/lib/token-budget.ts` around lines 6 - 28, Update the UsageEvent
query in checkDailyTokenBudget to filter by the provided userId in addition to
the current-day createdAt range, so all returned totals are scoped to that user.
Preserve the existing date boundaries and token field selection.


const totalTokens = events.reduce(
(sum, e) => sum + e.inputTokens + e.outputTokens + (e.cachedInputTokens ?? 0),
0
)

const queriesUsed = events.length
const remaining = DAILY_TOKEN_LIMIT - totalTokens
const queriesRemaining = DAILY_QUERY_LIMIT - queriesUsed

return {
allowed: remaining > 0 && queriesRemaining > 0,
used: totalTokens,
limit: DAILY_TOKEN_LIMIT,
remaining: Math.max(0, remaining),
queriesUsed,
queriesRemaining: Math.max(0, queriesRemaining),
}
}
27 changes: 27 additions & 0 deletions apps/api/src/lib/track-usage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import prisma from "./prisma"

export async function recordUsage(opts: {
provider: string
model: string
inputTokens: number
outputTokens: number
cachedInputTokens?: number
costUsd: number
durationMs: number
}) {
Comment on lines +3 to +11

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add explicit return type.

recordUsage lacks an explicit return type annotation. As per coding guidelines, "Prefer explicit return types on library functions" for **/*.{ts,tsx} files.

-export async function recordUsage(opts: {
+export async function recordUsage(opts: {
   provider: string
   model: string
   inputTokens: number
   outputTokens: number
   cachedInputTokens?: number
   costUsd: number
   durationMs: number
-}) {
+}): Promise<void> {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function recordUsage(opts: {
provider: string
model: string
inputTokens: number
outputTokens: number
cachedInputTokens?: number
costUsd: number
durationMs: number
}) {
export async function recordUsage(opts: {
provider: string
model: string
inputTokens: number
outputTokens: number
cachedInputTokens?: number
costUsd: number
durationMs: number
}): Promise<void> {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/lib/track-usage.ts` around lines 3 - 11, Add an explicit return
type annotation to the exported recordUsage function, using the actual value it
returns (or Promise<void> if it performs side effects without returning a
value). Keep the existing parameter contract and implementation behavior
unchanged.

Source: Coding guidelines

try {
await prisma.usageEvent.create({
data: {
provider: opts.provider,
model: opts.model,
inputTokens: opts.inputTokens,
outputTokens: opts.outputTokens,
cachedInputTokens: opts.cachedInputTokens ?? 0,
costUsd: opts.costUsd,
durationMs: opts.durationMs,
},
})
} catch (e) {
console.error("[track-usage] Failed to record usage event:", e)
}
}
28 changes: 28 additions & 0 deletions apps/api/src/middleware/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { createMiddleware } from "hono/factory"
import prisma from "../lib/prisma"
import type { AppEnv } from "../types"

export const authenticate = createMiddleware<AppEnv>(async (c, next) => {
const authHeader = c.req.header("Authorization")
if (!authHeader?.startsWith("Bearer ")) {
return c.json({ error: "Unauthorized" }, 401)
}

const token = authHeader.slice(7)
try {
const session = await prisma.session.findUnique({
where: { token },
include: { user: true },
})

if (!session || session.expiresAt < new Date()) {
return c.json({ error: "Unauthorized" }, 401)
}

c.set("user", session.user)
c.set("session", session)
await next()
} catch {
return c.json({ error: "Unauthorized" }, 401)
Comment on lines +12 to +26

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Do not convert downstream failures into 401 Unauthorized.

The try/catch also encloses await next(). Any exception from a protected handler—such as auth.api.signOut() in apps/api/src/routes/auth.ts:15-19—is caught and returned as 401, masking server failures. Restrict the try/catch to findUnique() and call next() after the catch block.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/middleware/auth.ts` around lines 12 - 26, Restrict the try/catch
in the authentication middleware to the prisma.session.findUnique call so only
session lookup failures return 401. Move await next() after the catch block
while preserving the existing session validation and c.set("user", ...) /
c.set("session", ...) behavior, allowing downstream handler exceptions to
propagate.

}
})
Loading
Loading