Skip to content
Merged
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
2 changes: 1 addition & 1 deletion ENVIRONMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ This document lists all environment variables used in the Kilo Code cloud monore
- `SENTRY_ORG` - Sentry organization slug for source map uploads; used in `apps/web/next.config.mjs`. `[SECRET]`
- `SENTRY_PROJECT` - Sentry project slug for source map uploads; used in `apps/web/next.config.mjs`. `[SECRET]`
- `SENTRY_AUTH_TOKEN` - Sentry auth token for source map uploads; used in `apps/web/next.config.mjs`. `[SECRET]`
- `NEXT_PUBLIC_SENTRY_DSN` - Sentry DSN for client-side error reporting; used in `apps/web/instrumentation-client.ts`, `sentry.edge.config.ts`, `sentry.server.config.ts`. `[PUBLIC]`
- `NEXT_PUBLIC_SENTRY_DSN` - Sentry DSN for server and Edge runtime error reporting; used in `apps/web/sentry.edge.config.ts` and `apps/web/sentry.server.config.ts`. `[PUBLIC]`

### Marketing Tags

Expand Down
7 changes: 0 additions & 7 deletions apps/web/.env
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,6 @@ NEXT_PUBLIC_POSTHOG_KEY=phc_GK2Pxl0HPj5ZPfwhLRjXrtdz8eD7e9MKnXiFrOqnB6z
POSTGRES_CONNECT_TIMEOUT=10000
POSTGRES_MAX_QUERY_TIME=20000

SENTRY_SUPPRESS_GLOBAL_ERROR_HANDLER_FILE_WARNING=1

# Sentry
SENTRY_ORG="kilo-code"
SENTRY_PROJECT="kilocode-web"
NEXT_PUBLIC_SENTRY_DSN="https://27ef80847dcd5e044283c8f88d95ffc9@o4509356317474816.ingest.us.sentry.io/4509565130637312"

# Google Waitlist stuff
GOOGLE_SHEETS_SPREADSHEET_ID=1FheQ3Yk_NlT8rn010KSLK8NUk6nxYAE_At2ebCv5O8o
GOOGLE_SERVICE_ACCOUNT_EMAIL=kilocode-waitlist-service@kilo-code-cli-waitlist.iam.gserviceaccount.com
Expand Down
18 changes: 0 additions & 18 deletions apps/web/instrumentation-client.ts

This file was deleted.

5 changes: 0 additions & 5 deletions apps/web/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,6 @@ const nextConfig = {

// This is required to support PostHog trailing slash API requests
skipTrailingSlashRedirect: true,
// Maximize chance of decent client-side stack traces
productionBrowserSourceMaps: true,
// Configure `pageExtensions` to include markdown and MDX files
pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'],

Expand Down Expand Up @@ -248,9 +246,6 @@ const sentryConfig = {
// Only print logs for uploading source maps in CI
silent: !process.env.CI,

// Upload a larger set of source maps for prettier stack traces (increases build time)
widenClientFileUpload: true,

// Tree-shake Sentry debug statements to reduce bundle size
bundleSizeOptimizations: {
excludeDebugStatements: true,
Expand Down
9 changes: 1 addition & 8 deletions apps/web/src/app/global-error.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
'use client';

import { captureException } from '@sentry/nextjs';
import { useEffect } from 'react';

export default function GlobalError({ error }: { error: Error & { digest?: string } }) {
useEffect(() => {
captureException(error);
}, [error]);

export default function GlobalError() {
return (
<html lang="en">
<body>
Expand Down
9 changes: 0 additions & 9 deletions apps/web/src/app/payments/topup/success/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { redirect } from 'next/navigation';
import { useEffect, useState } from 'react';
import { fetchCreditTransactionIdForStripeSession, getPaymentReturnUrl } from './actions';
import BigLoader from '@/components/BigLoader';
import { captureMessage } from '@sentry/nextjs';
import { fromMicrodollars } from '@/lib/utils';
import { TOPUP_AMOUNT_QUERY_STRING_KEY } from '@/lib/organizations/constants';
import { PageContainer } from '@/components/layouts/PageContainer';
Expand Down Expand Up @@ -38,14 +37,6 @@ export default function TopUpSuccessPage() {
// we intententionally listen to tries because we want to set a timeout after each try
if (tries > 14) {
setHasExceededMaxTries(true);
void (async function () {
captureMessage('Exceeded max tries to fetch credit transaction ID', {
extra: {
sessionId: sessionId,
},
});
})();

return;
}

Expand Down
9 changes: 0 additions & 9 deletions apps/web/src/components/auth/FakeLoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { useState, useEffect, useCallback, useRef } from 'react';
import { signIn } from 'next-auth/react';
import { Button } from '../Button';
import getSignInCallbackUrl from '@/lib/getSignInCallbackUrl';
import { captureException } from '@sentry/nextjs';

export type FakeSignInButtonProps = {
searchParams: NextAppSearchParams;
Expand Down Expand Up @@ -46,14 +45,6 @@ export function FakeLoginForm({ searchParams }: FakeSignInButtonProps) {
});
} catch (error) {
console.error('Fake login error:', error);
captureException(error, {
tags: { source: 'fake_login' },
extra: {
email: submissionEmail,
callbackUrl,
},
level: 'warning',
});
} finally {
setIsLoading(false);
}
Expand Down
3 changes: 1 addition & 2 deletions apps/web/src/components/auth/StytchClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import Script from 'next/script';
import { useEffect, useState } from 'react';
import { captureException } from '@sentry/nextjs';

const telemetryJsUri =
process.env.NEXT_PUBLIC_STYTCH_PROJECT_ENV === 'test'
Expand Down Expand Up @@ -41,7 +40,7 @@ export const StytchClient = ({ children }: React.PropsWithChildren) => {
submitURL: 'https://auth.kilo.ai/submit',
})
.then(setFreshTelemetryId)
.catch(err => captureException(err));
.catch(error => console.error('Failed to get Stytch telemetry ID:', error));
}}
/>
{children}
Expand Down
13 changes: 0 additions & 13 deletions apps/web/src/hooks/useSignInFlow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import { useState, useCallback, useMemo, useEffect, useRef } from 'react';
import { signIn } from 'next-auth/react';
import getSignInCallbackUrl from '@/lib/getSignInCallbackUrl';
import { captureException } from '@sentry/nextjs';
import type { AuthProviderId } from '@/lib/auth/provider-metadata';
import { ProdNonSSOAuthProviders } from '@/lib/auth/provider-metadata';
import { useSignInHint, type SignInHint } from '@/hooks/useSignInHint';
Expand Down Expand Up @@ -307,9 +306,6 @@ export function useSignInFlow({
setShowTurnstile(false);
} catch (error) {
console.error('[SignInForm] Error during email check:', error);
captureException(error, {
tags: { source: 'email_lookup' },
});
setIsVerifying(false);
setShowTurnstile(false);
setError('An error occurred. Please try again.');
Expand Down Expand Up @@ -389,9 +385,6 @@ export function useSignInFlow({
}
} catch (error) {
console.error('[SignInForm] Magic link request failed:', error);
captureException(error, {
tags: { source: 'magic_link_request' },
});
setError('Failed to send magic link. Please try again.');
}
}, [email, params, saveHint]);
Expand Down Expand Up @@ -477,9 +470,6 @@ export function useSignInFlow({
setFlowState('landing');
} catch (error) {
console.error('[SignInForm] Error during sign-in flow:', error);
captureException(error, {
tags: { source: 'turnstile_verification' },
});
setError('An error occurred. Please try again.');
setShowTurnstile(false);
setFlowState('landing');
Expand Down Expand Up @@ -539,9 +529,6 @@ export function useSignInFlow({
await signIn(provider, { callbackUrl });
} catch (error) {
console.error('[SignInForm] OAuth sign-in failed:', error);
captureException(error, {
tags: { source: 'oauth_signin' },
});
setError('Failed to sign in. Please try again.');
setFlowState('provider-select');
}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/lib/ai-gateway/auto-model/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from '@/lib/ai-gateway/providers/anthropic.constants';
import type { OpenRouterReasoningConfig } from '@/lib/ai-gateway/providers/openrouter/types';
import type { OpenCodeSettings, Verbosity } from '@kilocode/db/schema-types';
import { QWEN37_PLUS_MODEL_ID } from '@/lib/ai-gateway/custom-pricing';
import { QWEN37_PLUS_MODEL_ID } from '@/lib/ai-gateway/providers/qwen';
import { NVIDIA_TRIAL_TOS } from '@/lib/ai-gateway/providers/nvidia';

type AutoModel = {
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/lib/ai-gateway/custom-pricing.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { captureMessage } from '@sentry/nextjs';
import type { OpenRouterModel } from '@/lib/organizations/organization-types';
import type { JustTheCostsUsageStats } from '@/lib/ai-gateway/processUsage.types';
import { QWEN37_MAX_MODEL_ID, QWEN37_PLUS_MODEL_ID } from '@/lib/ai-gateway/providers/qwen';
import {
calculateCost_mUsd,
type Pricing,
type PricingTiers,
} from '@/lib/ai-gateway/providers/kilo-exclusive-model';

export const QWEN37_MAX_MODEL_ID = 'qwen/qwen3.7-max';
export const QWEN37_PLUS_MODEL_ID = 'qwen/qwen3.7-plus';
export { QWEN37_MAX_MODEL_ID, QWEN37_PLUS_MODEL_ID };

// Qwen long-context pricing starts at exactly 256 Ki tokens (262,144 tokens).
const TOKENS_256K = 256 * 1024;
Expand Down
3 changes: 1 addition & 2 deletions apps/web/src/lib/ai-gateway/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ import {
GEMINI_PRO_CURRENT_MODEL_ID,
gemma_4_26b_a4b_it_free_model,
} from '@/lib/ai-gateway/providers/google';
import { qwen36_plus_stealth_model } from '@/lib/ai-gateway/providers/qwen';
import { QWEN37_PLUS_MODEL_ID } from '@/lib/ai-gateway/custom-pricing';
import { QWEN37_PLUS_MODEL_ID, qwen36_plus_stealth_model } from '@/lib/ai-gateway/providers/qwen';
import { stepfun_37_flash_free_model } from '@/lib/ai-gateway/providers/stepfun';
import { isGrokModel } from '@/lib/ai-gateway/providers/xai';
import { isClaudeModel } from '@/lib/ai-gateway/providers/anthropic.constants';
Expand Down
3 changes: 3 additions & 0 deletions apps/web/src/lib/ai-gateway/providers/qwen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ function makeTieredPricing(

const TOKENS_256K = 256 * 1024;

export const QWEN37_MAX_MODEL_ID = 'qwen/qwen3.7-max';
export const QWEN37_PLUS_MODEL_ID = 'qwen/qwen3.7-plus';

export const qwen36_plus_stealth_model: KiloExclusiveModel = {
public_id: 'stealth/qwen3.6-plus',
display_name: 'Stealth: Qwen3.6 Plus (50% off)',
Expand Down
3 changes: 0 additions & 3 deletions apps/web/src/lib/auth/send-magic-link.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { captureException } from '@sentry/nextjs';

export type SendMagicLinkResult = { success: true } | { success: false; error: string };

/**
Expand Down Expand Up @@ -33,7 +31,6 @@ export async function sendMagicLink(
};
} catch (error) {
console.error('Magic link request error:', error);
captureException(error, { tags: { source: 'magic_link_request' } });
return {
success: false,
error: 'Failed to send magic link. Please try again.',
Expand Down
55 changes: 0 additions & 55 deletions apps/web/src/lib/security-headers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import {
getConfiguredConnectSrcOrigins,
getContentSecurityPolicyHeaderName,
getContentSecurityPolicyMode,
getSecurityPolicyReportingHeaders,
getSentrySecurityReportUri,
} from '@/lib/security-headers';

function getPolicyDirective(policy: string, directive: string): string {
Expand Down Expand Up @@ -82,8 +80,6 @@ describe('security headers', () => {
NEXT_PUBLIC_CLOUD_AGENT_NEXT_WS_URL: 'wss://next-agent.example.com/path',
NEXT_PUBLIC_SESSION_INGEST_WS_URL: 'wss://ingest.example.com/path',
NEXT_PUBLIC_GASTOWN_URL: 'https://gastown.example.com/api',
NEXT_PUBLIC_SENTRY_DSN:
'https://27ef80847dcd5e044283c8f88d95ffc9@o4509356317474816.ingest.us.sentry.io/4509565130637312',
};

expect(getConfiguredConnectSrcOrigins(env)).toEqual([
Expand All @@ -92,7 +88,6 @@ describe('security headers', () => {
'wss://ingest.example.com',
'https://gastown.example.com',
'wss://gastown.example.com',
'https://o4509356317474816.ingest.us.sentry.io',
]);
});

Expand All @@ -104,56 +99,6 @@ describe('security headers', () => {
).toEqual(['http://localhost:8787', 'ws://localhost:8787']);
});

it('adds Sentry security policy reporting directives when DSN is configured', () => {
const policy = buildContentSecurityPolicy({
env: {
NEXT_PUBLIC_SENTRY_DSN:
'https://27ef80847dcd5e044283c8f88d95ffc9@o4509356317474816.ingest.us.sentry.io/4509565130637312',
SENTRY_ENVIRONMENT: 'production',
SENTRY_RELEASE: 'web-2026-04-24',
},
});

const reportUri =
'https://o4509356317474816.ingest.us.sentry.io/api/4509565130637312/security/?sentry_key=27ef80847dcd5e044283c8f88d95ffc9&sentry_environment=production&sentry_release=web-2026-04-24';

expect(policy).toContain(`report-uri ${reportUri}`);
expect(policy).toContain('report-to csp-endpoint');
expect(policy).toContain('https://o4509356317474816.ingest.us.sentry.io');
});

it('builds Sentry security policy reporting headers', () => {
const reportUri = getSentrySecurityReportUri({
NEXT_PUBLIC_SENTRY_DSN:
'https://27ef80847dcd5e044283c8f88d95ffc9@o4509356317474816.ingest.us.sentry.io/4509565130637312',
VERCEL_ENV: 'preview',
});

expect(reportUri).toBe(
'https://o4509356317474816.ingest.us.sentry.io/api/4509565130637312/security/?sentry_key=27ef80847dcd5e044283c8f88d95ffc9&sentry_environment=preview'
);

const headers = getSecurityPolicyReportingHeaders({
NEXT_PUBLIC_SENTRY_DSN:
'https://27ef80847dcd5e044283c8f88d95ffc9@o4509356317474816.ingest.us.sentry.io/4509565130637312',
VERCEL_ENV: 'preview',
});

expect(headers['Reporting-Endpoints']).toBe(`csp-endpoint="${reportUri}"`);
expect(JSON.parse(headers['Report-To'] ?? '')).toEqual({
group: 'csp-endpoint',
max_age: 10886400,
endpoints: [{ url: reportUri }],
include_subdomains: true,
});
});

it('omits Sentry security policy reporting when DSN is missing', () => {
expect(getSentrySecurityReportUri({})).toBeNull();
expect(getSecurityPolicyReportingHeaders({})).toEqual({});
expect(buildContentSecurityPolicy({ env: {} })).not.toContain('report-uri');
});

it('supports enforcement, report-only, and off modes', () => {
expect(getContentSecurityPolicyMode({})).toBe('report-only');
expect(getContentSecurityPolicyHeaderName('report-only')).toBe(
Expand Down
Loading
Loading