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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ freebuff

Then describe what you want. Freebuff finds the relevant files, makes changes, and runs the checks that matter for your project.

You can also pass the first prompt on the command line:

```bash
freebuff "add a dark mode toggle"
```

## Models

Freebuff includes a curated model catalog. The regular picker currently offers:
Expand Down
45 changes: 45 additions & 0 deletions cli/src/__tests__/cli-args.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,51 @@ describe('Freebuff CLI Argument Parsing', () => {
expect(result.initialPrompt).toBeNull()
})

test('accepts an initial prompt and joins its words', () => {
const result = parseArgs({
argv: ['node', 'freebuff', 'add', 'a', 'dark', 'mode', 'toggle'],
isFreebuff: true,
version: '1.0.0',
})

expect(result.initialPrompt).toBe('add a dark mode toggle')
expect(result.command).toBeUndefined()
expect(result.initialMode).toBe('LITE')
})

test('accepts an initial prompt alongside --cwd and --continue', () => {
// `--continue [id]` takes an optional value, so a prompt that follows it
// would be read as the conversation id (as in codebuff); keep it last.
const result = parseArgs({
argv: [
'node',
'freebuff',
'--cwd',
'/tmp',
'fix the tests',
'--continue',
],
isFreebuff: true,
version: '1.0.0',
})

expect(result.cwd).toBe('/tmp')
expect(result.continue).toBe(true)
expect(result.continueId).toBeNull()
expect(result.initialPrompt).toBe('fix the tests')
})

test('treats a prompt that starts with a codebuff command word as a prompt', () => {
const result = parseArgs({
argv: ['node', 'freebuff', 'publish', 'the', 'release', 'notes'],
isFreebuff: true,
version: '1.0.0',
})

expect(result.command).toBeUndefined()
expect(result.initialPrompt).toBe('publish the release notes')
})

test('parses --trust-agents and defaults it to false', () => {
expect(
parseArgs({
Expand Down
26 changes: 20 additions & 6 deletions cli/src/cli-args.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createRequire } from 'module'

import { Argument, Command } from 'commander'
import { Command } from 'commander'

import { IS_FREEBUFF, type AgentMode } from './utils/constants'
import { getCliEnv } from './utils/env'
Expand Down Expand Up @@ -50,7 +50,10 @@ export function parseArgs({
const program = new Command()

if (isFreebuff) {
// Freebuff: simplified CLI - no prompt args, no agent override, no clear-logs
// Freebuff: simplified CLI - no agent override, no clear-logs, no mode
// flags. The initial prompt is accepted like codebuff's so launchers can
// hand a task straight to the TUI; it is sent through the normal chat
// path, so session admission, the landing screen and ads are unchanged.
program
.name('freebuff')
.description('Freebuff - Free AI coding assistant')
Expand All @@ -67,10 +70,12 @@ export function parseArgs({
'--trust-agents',
"Load this repository's .agents files and mcp.json without asking (for CI)",
)
.addArgument(
new Argument('[command]', 'Command to run').choices(['login']),
.addHelpText(
'after',
'\nCommands:\n login Log in to your account',
)
.helpOption('-h, --help', 'Show this help message')
.argument('[prompt...]', 'Initial prompt to send to the agent')
} else {
// Codebuff: full CLI with all options
program
Expand Down Expand Up @@ -115,6 +120,14 @@ export function parseArgs({
const options = program.opts()
const args = program.args

// Freebuff has one command, `login`; any other first word is the start of
// a prompt. Codebuff keeps its wider command set (login, publish).
const command = isFreebuff
? args[0] === 'login'
? 'login'
: undefined
: args[0]

const continueFlag = options.continue

// Determine initial mode from flags (last flag wins if multiple specified)
Expand All @@ -129,8 +142,9 @@ export function parseArgs({
}

return {
initialPrompt: !isFreebuff && args.length > 0 ? args.join(' ') : null,
command: args[0],
initialPrompt:
args.length > 0 && command !== 'login' ? args.join(' ') : null,
command,
agent: options.agent,
clearLogs: options.clearLogs || false,
continue: Boolean(continueFlag),
Expand Down
Loading