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 .github/actions/setup-project/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ runs:
bun-version-file: ${{ inputs.bun-version-file }}

- name: Cache dependencies
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: |
node_modules
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/freebuff-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ jobs:
run: sudo apt-get update && sudo apt-get install -y tmux

- name: Download Freebuff binary
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: freebuff-binary
path: cli/bin/
Expand Down
18 changes: 9 additions & 9 deletions .github/workflows/freebuff-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
outputs:
new_version: ${{ steps.bump_version.outputs.new_version }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}

Expand Down Expand Up @@ -71,7 +71,7 @@ jobs:
git push origin "freebuff-v${{ steps.bump_version.outputs.new_version }}"

- name: Upload updated package
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: freebuff-updated-package
path: freebuff/cli/release/
Expand All @@ -96,21 +96,21 @@ jobs:
needs: [prepare-and-commit, build-binaries, e2e-tests]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Download all binary artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
path: binaries/

- name: Download updated package
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: freebuff-updated-package
path: freebuff/cli/release/

- name: Create GitHub Release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
tag_name: freebuff-v${{ needs.prepare-and-commit.outputs.new_version }}
name: Freebuff v${{ needs.prepare-and-commit.outputs.new_version }}
Expand Down Expand Up @@ -143,16 +143,16 @@ jobs:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Download updated package
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: freebuff-updated-package
path: freebuff/cli/release/

- name: Set up Node.js for npm publishing
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 24
registry-url: https://registry.npmjs.org/
Expand Down
10 changes: 5 additions & 5 deletions cli/src/components/multiline-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ export const MultilineInput = forwardRef<
const cursorRow = lineInfo
? Math.max(
0,
lineInfo.lineStarts.findLastIndex(
lineInfo.lineStartCols.findLastIndex(
(lineStart) => lineStart <= cursorPosition,
),
)
Expand Down Expand Up @@ -420,7 +420,7 @@ export const MultilineInput = forwardRef<
const scrollBox = scrollBoxRef.current
if (!scrollBox) return

const lineStarts = lineInfo?.lineStarts ?? [0]
const lineStarts = lineInfo?.lineStartCols ?? [0]

const viewport = (scrollBox as any).viewport
const viewportTop = Number(viewport?.y ?? 0)
Expand Down Expand Up @@ -616,7 +616,7 @@ export const MultilineInput = forwardRef<
if (key.ctrl && lowerKeyName === 'u' && !key.meta && !key.option) {
preventKeyDefault(key)
if (handleSelectionDeletion()) return true
const visualLineStart = lineInfo?.lineStarts?.[cursorRow] ?? lineStart
const visualLineStart = lineInfo?.lineStartCols?.[cursorRow] ?? lineStart

if (cursorPosition > visualLineStart) {
const newValue =
Expand Down Expand Up @@ -801,7 +801,7 @@ export const MultilineInput = forwardRef<

// Calculate visual line boundaries from lineInfo (accounts for word wrap)
// Fall back to logical line boundaries if visual info is unavailable
const lineStarts = currentLineInfo?.lineStarts ?? []
const lineStarts = currentLineInfo?.lineStartCols ?? []
const visualLineIndex = lineStarts.findLastIndex(
(start) => start <= cursorPosition,
)
Expand Down Expand Up @@ -1091,7 +1091,7 @@ export const MultilineInput = forwardRef<
const effectiveMinHeight = Math.max(1, Math.min(minHeight, safeMaxHeight))

const totalLines =
lineInfo === null ? 0 : lineInfo.lineStarts.length
lineInfo === null ? 0 : lineInfo.lineStartCols.length

// Add bottom gutter when cursor is on line 2 of exactly 2 lines
const gutterEnabled =
Expand Down
8 changes: 2 additions & 6 deletions cli/src/utils/__tests__/error-handling.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,8 @@ describe('error-handling', () => {
})

describe('FREE_MODE_UNAVAILABLE_MESSAGE', () => {
test('mentions free mode', () => {
expect(FREE_MODE_UNAVAILABLE_MESSAGE.toLowerCase()).toContain('free mode')
})

test('mentions paid plan', () => {
expect(FREE_MODE_UNAVAILABLE_MESSAGE.toLowerCase()).toContain('paid plan')
test('mentions unavailability in country', () => {
expect(FREE_MODE_UNAVAILABLE_MESSAGE.toLowerCase()).toContain('not available in your country')
})
})

Expand Down
7 changes: 5 additions & 2 deletions cli/src/utils/error-handling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { env } from '@codebuff/common/env'

import type { ChatMessage } from '../types/chat'

import { IS_FREEBUFF } from './constants'

const defaultAppUrl = env.NEXT_PUBLIC_CODEBUFF_APP_URL || 'https://codebuff.com'

// Normalize unknown errors to a user-facing string.
Expand Down Expand Up @@ -57,8 +59,9 @@ export const isFreeModeUnavailableError = (error: unknown): boolean => {

export const OUT_OF_CREDITS_MESSAGE = `Out of credits. Please add credits at ${defaultAppUrl}/usage`

export const FREE_MODE_UNAVAILABLE_MESSAGE =
'Free mode is not available outside of the United States and Canada. Please upgrade to a paid plan to use Codebuff outside the US and Canada.'
export const FREE_MODE_UNAVAILABLE_MESSAGE = IS_FREEBUFF
? 'Freebuff is not available in your country.'
: 'Free mode is not available in your country. You can use another mode to continue.'

export const createErrorMessage = (
error: unknown,
Expand Down
2 changes: 1 addition & 1 deletion docs/error-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Used for errors that the client needs to identify programmatically:
| Status | `error` code | Example `message` |
|--------|-------------|-------------------|
| 403 | `account_suspended` | `"Your account has been suspended due to billing issues. Please contact [email protected] to resolve this."` |
| 403 | `free_mode_unavailable` | `"Free mode is not available in your country."` |
| 403 | `free_mode_unavailable` | `"Free mode is not available in your country."` (Freebuff: `"Freebuff is not available in your country."`) |
| 429 | `rate_limit_exceeded` | `"Subscription weekly limit reached. Your limit resets in 2 hours. Enable 'Continue with credits' in the CLI to use a-la-carte credits."` |

### Catch-all server error
Expand Down
4 changes: 3 additions & 1 deletion freebuff/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ freebuff

**Simple** — No modes. No config. Just works.

**Fast** — 5–10× speed up. 3–5× tokens per second compared to Claude, plus context gathering in seconds.
**Fast** — 5–10× speed up. Faster models plus context gathering in seconds rather than minutes.

**Loaded** — Built-in web research, browser use, and more.

Expand Down Expand Up @@ -58,6 +58,8 @@ freebuff

**Are you training on my data?** No. We only use model providers that do not train on our requests. Your code stays yours.

**Which countries is Freebuff available in?** Freebuff is currently available in select countries. See [freebuff.com](https://freebuff.com) for the full list.

**What data do you store?** We don't store your codebase. We only collect minimal logs for debugging purposes.

## How It Works
Expand Down
2 changes: 1 addition & 1 deletion freebuff/cli/release/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "freebuff",
"version": "0.0.18",
"version": "0.0.20",
"description": "The world's strongest free coding agent",
"license": "MIT",
"bin": {
Expand Down
15 changes: 10 additions & 5 deletions freebuff/web/src/app/home-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,28 @@ const faqs = [
{
question: 'What models do you use?',
answer:
'MiniMax M2.5 as the main coding agent, Gemini 3.1 Flash Lite for finding files and research, and GPT-5.4 for deep thinking if you connect your ChatGPT subscription.',
'MiniMax M2.5 as the main coding agent. Gemini 3.1 Flash Lite for finding files and research.\n\nConnect your ChatGPT subscription to unlock GPT-5.4 for deep thinking.',
},
{
question: 'Which countries is Freebuff available in?',
answer:
'Freebuff is currently available in the United States, Canada, United Kingdom, Australia, Norway, Sweden, Netherlands, Denmark, Germany, Finland, Belgium, Luxembourg, Switzerland, Ireland, and Iceland.',
'Freebuff is currently available in:\n\nUnited States, Canada, United Kingdom, Australia, New Zealand, Norway, Sweden, Netherlands, Denmark, Germany, Finland, Belgium, Luxembourg, Switzerland, Ireland, and Iceland.',
},
{
question: 'Are you training on my data?',
answer:
'No. We only use model providers that do not train on our requests. Your code stays yours.',
'No. We do not share your data with third parties that would train on it or use it for another purpose.\n\nIn the future, we may use request data to train custom models to improve Freebuff — this will be opt-out, so you\'ll always have control.',
},
{
question: 'What data do you store?',
answer:
"We don't store your codebase. We only collect minimal logs for debugging purposes.",
},
{
question: 'What else is cool in Freebuff?',
answer:
'Freebuff comes with specialized subagents: file-picker finds relevant files across your codebase, code-reviewer gives critical feedback on your changes, and browser-use lets the AI control a real browser to test your app.\n\nAfter every response, it generates 3 clickable follow-up suggestions so you always know what to do next.\n\nFor big tasks, try the /interview → /plan → implement → /review workflow to go from idea to polished code.',
},
]

const setupSteps = [
Expand Down Expand Up @@ -294,7 +299,7 @@ function FAQList() {
<div className="flex gap-4 px-4 pb-5">
<span className="flex-shrink-0 w-[1.5ch]"></span>
<div className="border-l-2 border-acid-matrix/40 pl-4">
<p className="text-zinc-300 leading-relaxed text-sm">
<p className="text-zinc-300 leading-relaxed text-sm whitespace-pre-line">
{faq.answer}
</p>
</div>
Expand All @@ -312,7 +317,7 @@ function FAQList() {
const PHILOSOPHY_WORDS = [
{ word: 'SIMPLE', description: 'No modes. No config. Just works.' },
{ word: 'FAST', description: '5–10× speed up via fast models and quick context gathering.' },
{ word: 'LOADED', description: 'Built in web research, plan/review using your ChatGPT subscription, and more.' },
{ word: 'LOADED', description: 'Built in web research, browser use, plan/review using your ChatGPT subscription, and more.' },
]

function PhilosophySection() {
Expand Down
Loading
Loading