Skip to content

Commit 37fe177

Browse files
Merge pull request #96 from firecrawl/cli-implementation
feat:`firecrawl create agent` command
2 parents 959e570 + fa0b300 commit 37fe177

3 files changed

Lines changed: 156 additions & 1 deletion

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "firecrawl-cli",
3-
"version": "1.14.9",
3+
"version": "1.15.0",
44
"description": "Command-line interface for Firecrawl. Scrape, crawl, and extract data from any website directly from your terminal.",
55
"main": "dist/index.js",
66
"bin": {

src/commands/create.ts

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/**
2+
* `firecrawl create` command — scaffolds Firecrawl starter projects.
3+
*
4+
* Hidden from --help until `firecrawl-agent-cli` is published to npm.
5+
* Once visible, the command tree will grow to include additional kinds
6+
* (scrape, browser, ai, app). For now, `agent` is the only kind.
7+
*
8+
* Implementation is a thin delegator: `firecrawl create agent ...` execs
9+
* `npx -y firecrawl-agent-cli create ...` and passes all flags through.
10+
* This avoids vendoring the scaffold code in the root CLI; the agent repo
11+
* remains the single source of truth for templates and the manifest.
12+
*/
13+
14+
import { Command } from 'commander';
15+
import { spawn } from 'child_process';
16+
17+
/** npm package name of the Firecrawl Agent CLI (bin: `firecrawl-agent`). */
18+
const AGENT_CLI_PACKAGE = 'firecrawl-agent-cli';
19+
20+
/**
21+
* Execute `npx -y <AGENT_CLI_PACKAGE> create ...` with inherited stdio so
22+
* the agent CLI's interactive prompts render in the user's terminal.
23+
* Resolves with the child exit code; callers forward it to `process.exit`.
24+
*/
25+
function runAgentCli(args: string[]): Promise<number> {
26+
const npx = process.platform === 'win32' ? 'npx.cmd' : 'npx';
27+
return new Promise((resolve) => {
28+
const child = spawn(npx, ['-y', AGENT_CLI_PACKAGE, 'create', ...args], {
29+
stdio: 'inherit',
30+
env: process.env,
31+
});
32+
child.on('exit', (code) => resolve(code ?? 1));
33+
child.on('error', (err) => {
34+
console.error(
35+
`\nFailed to launch ${AGENT_CLI_PACKAGE} via npx:`,
36+
err.message
37+
);
38+
console.error(
39+
`\n Install it directly and retry: npm install -g ${AGENT_CLI_PACKAGE}\n`
40+
);
41+
resolve(1);
42+
});
43+
});
44+
}
45+
46+
function collect(val: string, acc: string[]): string[] {
47+
acc.push(val);
48+
return acc;
49+
}
50+
51+
/**
52+
* Build the `agent` subcommand. Flag surface mirrors `firecrawl-agent create`
53+
* exactly — anything the downstream CLI accepts is passed through verbatim.
54+
*/
55+
function createAgentSubcommand(): Command {
56+
return new Command('agent')
57+
.description(
58+
'Scaffold a Firecrawl Agent project (defaults to the Next.js template)'
59+
)
60+
.argument('[project-name]', 'Project directory name')
61+
.option(
62+
'-t, --template <id>',
63+
'Template variant (next, express, library)',
64+
'next'
65+
)
66+
.option(
67+
'--provider <id>',
68+
'Orchestrator model provider (anthropic, openai, google, gateway, custom-openai)'
69+
)
70+
.option('--model <id>', 'Orchestrator model ID')
71+
.option(
72+
'--sub-agent-provider <id>',
73+
'Sub-agent model provider (defaults to orchestrator)'
74+
)
75+
.option(
76+
'--sub-agent-model <id>',
77+
'Sub-agent model ID (defaults to orchestrator)'
78+
)
79+
.option(
80+
'--from <source>',
81+
'External repo (user/repo) or local path with agent-manifest.json'
82+
)
83+
.option('--api-key <key>', 'Firecrawl API key')
84+
.option(
85+
'--key <provider=key>',
86+
'Provider API key (repeatable, e.g. --key anthropic=sk-...)',
87+
collect,
88+
[]
89+
)
90+
.option('--skip-install', 'Skip npm install')
91+
.allowUnknownOption() // Forward future flags without requiring a CLI update
92+
.action(
93+
async (
94+
projectName: string | undefined,
95+
options: Record<string, unknown>,
96+
cmd: Command
97+
) => {
98+
const args: string[] = [];
99+
if (projectName) args.push(projectName);
100+
101+
// Pass through known options. Commander camelCases hyphenated flags,
102+
// so we map back to the CLI-facing kebab-case form.
103+
const flagMap: Array<[string, string]> = [
104+
['template', '-t'],
105+
['provider', '--provider'],
106+
['model', '--model'],
107+
['subAgentProvider', '--sub-agent-provider'],
108+
['subAgentModel', '--sub-agent-model'],
109+
['from', '--from'],
110+
['apiKey', '--api-key'],
111+
];
112+
for (const [optKey, flag] of flagMap) {
113+
const val = options[optKey];
114+
if (typeof val === 'string' && val.length > 0) args.push(flag, val);
115+
}
116+
117+
// --key is repeatable
118+
const keys = options.key;
119+
if (Array.isArray(keys)) {
120+
for (const k of keys) {
121+
if (typeof k === 'string' && k.length > 0) args.push('--key', k);
122+
}
123+
}
124+
125+
if (options.skipInstall) args.push('--skip-install');
126+
127+
// Forward any unknown/forward-compatible options verbatim.
128+
const passthrough = cmd.args.slice(projectName ? 1 : 0);
129+
for (const extra of passthrough) args.push(extra);
130+
131+
const code = await runAgentCli(args);
132+
if (code !== 0) process.exit(code);
133+
}
134+
);
135+
}
136+
137+
/**
138+
* Top-level `firecrawl create` command. For now it only wires the `agent`
139+
* subcommand; future kinds (scrape, browser, ai, app) register here.
140+
*/
141+
export function createCreateCommand(): Command {
142+
const cmd = new Command('create').description(
143+
'Scaffold a Firecrawl starter project'
144+
);
145+
146+
cmd.addCommand(createAgentSubcommand());
147+
148+
return cmd;
149+
}

src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import {
5050
createCodexCommand,
5151
createOpenCodeCommand,
5252
} from './commands/experimental';
53+
import { createCreateCommand } from './commands/create';
5354

5455
// Initialize global configuration from environment variables
5556
initializeConfig();
@@ -1191,6 +1192,11 @@ program.addCommand(createInteractCommand());
11911192
// Hidden: deprecated browser command (still works, just not in --help)
11921193
program.addCommand(createBrowserCommand(), { hidden: true });
11931194

1195+
// Hidden: `firecrawl create <kind>` — scaffolds Firecrawl starter projects.
1196+
// Undocumented until `firecrawl-agent-cli` is published to npm; flip to
1197+
// visible by removing `{ hidden: true }`.
1198+
program.addCommand(createCreateCommand(), { hidden: true });
1199+
11941200
// Experimental: download, AI workflow commands
11951201
const experimental = new Command('experimental')
11961202
.description('Experimental commands (download, AI workflows)')

0 commit comments

Comments
 (0)