diff --git a/beta-skills/firecrawl-alexandria/SKILL.md b/beta-skills/firecrawl-alexandria/SKILL.md index 4d18337550..f07c3fb647 100644 --- a/beta-skills/firecrawl-alexandria/SKILL.md +++ b/beta-skills/firecrawl-alexandria/SKILL.md @@ -5,19 +5,19 @@ description: Use for explicitly requested Firecrawl Alexandria beta tool discove # Alexandria Beta -Use the beta CLI explicitly on every invocation: `npx firecrawl-cli@alexandria --enable alexandria`. Do not replace the user's stable CLI or use a direct Exchange connection. The beta must be published before this npm tag works. +Use the beta CLI explicitly on every invocation: `npx firecrawl-cli@alexandria`. Version `1.23.4-alexandria-beta.1` or newer needs no enable flag. Do not replace the user's stable CLI or use a direct Exchange connection. -Use `FIRECRAWL_API_KEY` or existing Firecrawl login credentials. Never print credentials. The hidden flag is not authorization: the API enforces team and provider access. +Use `FIRECRAWL_API_KEY` or existing Firecrawl login credentials. Never print credentials. Installing the beta is not authorization: the API enforces team and provider access. ## Discover Before Executing ```sh -npx firecrawl-cli@alexandria --enable alexandria search "GDP" --sources alexandria --json -npx firecrawl-cli@alexandria --enable alexandria find-tools --options '{"providers":["fred"]}' --pretty -npx firecrawl-cli@alexandria --enable alexandria find-tools https://example.com --pretty +npx firecrawl-cli@alexandria search "GDP" --json +npx firecrawl-cli@alexandria find-tools --options '{"providers":["fred"]}' --pretty +npx firecrawl-cli@alexandria find-tools https://example.com --pretty ``` -For ordinary web results alongside provider tools, use `--sources web,alexandria`. For URL scraping with related tool discovery, use `scrape https://example.com --domain-tools --json` after the same beta prefix. +Search defaults to web results plus Alexandria tools and domain-tool discovery. Inspect both; discovery does not execute the returned provider tools. Use `--sources web` for web-only search or `--sources alexandria` for tool-only discovery. Search itself can consume credits. For URL scraping with related tool discovery, use `scrape https://example.com --domain-tools --json` after the same beta prefix. Read the returned `data.tools` contracts before choosing a provider/capability. Use their exact input schema, pricing and access requirements; never invent options or assume a provider is free. Follow returned Find Tools requests with `find-tools --request ''`. This accepts only the `firecrawl/find-tools` discovery call, not arbitrary provider execution. @@ -28,7 +28,7 @@ Obtain approval before paid execution unless the user has already authorized the Once the discovered contract confirms the capability and options: ```sh -npx firecrawl-cli@alexandria --enable alexandria scrape --alexandria fred/series/observations --options '{"series_id":"GDP"}' --request-id gdp-beta-1 --json +npx firecrawl-cli@alexandria scrape --alexandria fred/series/observations --options '{"series_id":"GDP"}' --request-id gdp-beta-1 --json ``` Choose a new unique request ID for each new logical execution; the ID above is only an example. Preserve the ID printed on stderr and reuse it only for identical retries, including options and call order. For batches, repeat `--alexandria` and pair each call with a positional `--options` object (maximum 10 calls). diff --git a/package.json b/package.json index bbe7dd9bec..f989aaab7d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firecrawl-cli", - "version": "1.23.4-alexandria-beta.0", + "version": "1.23.4-alexandria-beta.1", "publishConfig": { "tag": "alexandria" }, diff --git a/src/__tests__/alexandria-beta.test.ts b/src/__tests__/alexandria-beta.test.ts index aa70334474..5bd27e47b5 100644 --- a/src/__tests__/alexandria-beta.test.ts +++ b/src/__tests__/alexandria-beta.test.ts @@ -71,7 +71,7 @@ async function cli(args: string[], key = 'fc-test') { } } -it('keeps beta options out of normal help and refuses use without opt-in', async () => { +it('keeps beta options out of normal help and respects explicit web-only search', async () => { for (const args of [['--help'], ['search', '--help'], ['scrape', '--help']]) { const result = await cli(args); expect(result.code).toBe(0); @@ -79,13 +79,19 @@ it('keeps beta options out of normal help and refuses use without opt-in', async /alexandria|find-tools|domain-tools|--enable/i ); } - const result = await cli(['search', 'gdp', '--sources', 'alexandria']); - expect(result.code).toBe(1); - expect(result.stderr).toContain('--enable alexandria'); - const setup = await cli(['setup', 'alexandria', '--yes']); - expect(setup.code).toBe(1); - expect(setup.stderr).toContain('--enable alexandria'); - expect(requests).toHaveLength(0); + response = { success: true, data: { web: [] } }; + const result = await cli([ + 'search', + 'pizza hut', + '--sources', + 'web', + '--json', + ]); + expect(result.code).toBe(0); + expect(requests[0].body).toMatchObject({ + sources: [{ type: 'web' }], + domainTools: false, + }); }); it('preserves mixed search results, tools and billing metadata', async () => { @@ -98,16 +104,7 @@ it('preserves mixed search results, tools and billing metadata', async () => { tools: [{ provider: 'fred', capability: 'series/observations' }], }, }; - const result = await cli([ - '--enable', - 'alexandria', - 'search', - 'gdp', - '--sources', - 'web,alexandria', - '--domain-tools', - '--json', - ]); + const result = await cli(['search', 'pizza hut', '--json']); expect(result.code).toBe(0); expect(JSON.parse(result.stdout)).toEqual(response); expect(requests[0]).toMatchObject({ @@ -118,12 +115,13 @@ it('preserves mixed search results, tools and billing metadata', async () => { domainTools: true, }, }); + const readable = await cli(['search', 'pizza hut']); + expect(readable.stdout).toContain('=== Tools ==='); + expect(readable.stdout).toContain('series/observations'); }); it('sends provider calls to Scrape with a stable retry ID and preserves the receipt', async () => { const args = [ - '--enable', - 'alexandria', 'scrape', '--alexandria', 'fred/series/observations', @@ -167,8 +165,6 @@ it('relays terms refusals and keeps the request ID on failure', async () => { requiresAction: { url: 'https://firecrawl.dev/terms/provider' }, }; const result = await cli([ - '--enable', - 'alexandria', 'scrape', '--alexandria', 'provider/lookup', @@ -182,13 +178,7 @@ it('relays terms refusals and keeps the request ID on failure', async () => { }); it('executes Find Tools through the same API and refuses keyless access', async () => { - const args = [ - '--enable', - 'alexandria', - 'find-tools', - '--options', - '{"providers":["fred"]}', - ]; + const args = ['find-tools', '--options', '{"providers":["fred"]}']; expect((await cli(args, '')).code).toBe(1); expect(requests).toHaveLength(0); expect((await cli(args)).code).toBe(0); @@ -211,13 +201,7 @@ it('keeps URL scrape tool contracts in the output', async () => { success: true, data: { markdown: 'Example', tools: [{ provider: 'fred' }] }, }; - const result = await cli([ - 'scrape', - 'https://example.com', - '--enable', - 'alexandria', - '--domain-tools', - ]); + const result = await cli(['scrape', 'https://example.com', '--domain-tools']); expect(result.code).toBe(0); expect(JSON.parse(result.stdout)).toEqual(response.data); expect(requests[0]).toMatchObject({ diff --git a/src/index.ts b/src/index.ts index 5556762183..9132719df9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -326,23 +326,6 @@ program // Update global config if API key or URL is provided via global option const globalOptions = thisCommand.opts(); const commandOptions = actionCommand.opts(); - const usesAlexandria = - actionCommand.name() === 'find-tools' || - (actionCommand.name() === 'setup' && - actionCommand.args[0] === 'alexandria') || - commandOptions.domainTools || - (actionCommand.name() === 'scrape' && - (commandOptions.alexandria || - commandOptions.options || - commandOptions.requestId)) || - (actionCommand.name() === 'search' && - commandOptions.sources - ?.split(',') - .some( - (source: string) => source.trim().toLowerCase() === 'alexandria' - )); - if (usesAlexandria && globalOptions.enable !== 'alexandria') - throw new Error('This beta feature requires --enable alexandria.'); if (globalOptions.apiKey) { updateConfig({ apiKey: globalOptions.apiKey }); } @@ -1017,19 +1000,14 @@ function createSearchCommand(): Command { .option('--json', 'Output as compact JSON', false) .action(async (query, options) => { // Parse sources - let sources: SearchSource[] | undefined; + let sources: SearchSource[] = ['web', 'alexandria']; if (options.sources) { sources = options.sources .split(',') .map((s: string) => s.trim().toLowerCase()) as SearchSource[]; // Validate sources - const validSources = [ - 'web', - 'images', - 'news', - ...(program.opts().enable === 'alexandria' ? ['alexandria'] : []), - ]; + const validSources = ['web', 'images', 'news', 'alexandria']; for (const source of sources) { if (!validSources.includes(source)) { console.error( @@ -1069,7 +1047,7 @@ function createSearchCommand(): Command { const searchOptions = { query, - domainTools: options.domainTools, + domainTools: options.domainTools ?? sources.includes('alexandria'), limit: options.limit, sources, categories,