@browserbasehq/bb9
Advanced tools
Comparing version 1.1.8 to 1.1.9
#!/usr/bin/env node | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
import { program } from "commander"; | ||
@@ -21,142 +12,137 @@ import inquirer from "inquirer"; | ||
import { minimatch } from "minimatch"; | ||
function promptForOptions() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const answers = yield inquirer.prompt([ | ||
{ | ||
type: "list", | ||
name: "modelName", | ||
message: "Select AI model to use", | ||
choices: [ | ||
{ name: "OpenAI GPT-4o", value: "gpt-4o" }, | ||
{ | ||
name: "Anthropic Claude 3.5 Sonnet", | ||
value: "claude-3-5-sonnet-20241022", | ||
}, | ||
], | ||
default: "gpt-4o", | ||
}, | ||
{ | ||
type: "input", | ||
name: "anthropicApiKey", | ||
message: "Enter your Anthropic API key", | ||
when: (answers) => answers.modelName.includes("claude") && !process.env.ANTHROPIC_API_KEY, | ||
}, | ||
{ | ||
type: "input", | ||
name: "openaiApiKey", | ||
message: "Enter your OpenAI API key", | ||
when: (answers) => answers.modelName.includes("gpt") && !process.env.OPENAI_API_KEY, | ||
}, | ||
{ | ||
type: "list", | ||
name: "env", | ||
message: "Would you like to run locally or on Browserbase (10 free sessions)?", | ||
choices: [ | ||
{ | ||
name: "Browserbase", | ||
value: "BROWSERBASE", | ||
}, | ||
{ | ||
name: "Local", | ||
value: "LOCAL", | ||
}, | ||
], | ||
default: "BROWSERBASE", | ||
}, | ||
{ | ||
type: "input", | ||
name: "projectId", | ||
message: "Go to Browserbase Settings: https://www.browserbase.com/settings\nEnter your project ID", | ||
when: (answers) => answers.env === "BROWSERBASE" && !process.env.BROWSERBASE_PROJECT_ID, | ||
}, | ||
{ | ||
type: "input", | ||
name: "apiKey", | ||
message: "Enter your Browserbase API key", | ||
when: (answers) => answers.env === "BROWSERBASE" && !process.env.BROWSERBASE_API_KEY, | ||
}, | ||
{ | ||
type: "confirm", | ||
name: "debugDom", | ||
message: "Enable DOM debugging features?", | ||
default: true, | ||
}, | ||
{ | ||
type: "confirm", | ||
name: "headless", | ||
message: "Run browser in headless mode?", | ||
default: false, | ||
when: (answers) => answers.env === "LOCAL", | ||
}, | ||
{ | ||
type: "confirm", | ||
name: "enableCaching", | ||
message: "Enable prompt caching?", | ||
default: true, | ||
}, | ||
]); | ||
return answers; | ||
}); | ||
async function promptForOptions() { | ||
const answers = await inquirer.prompt([ | ||
{ | ||
type: "list", | ||
name: "modelName", | ||
message: "Select AI model to use", | ||
choices: [ | ||
{ name: "OpenAI GPT-4o", value: "gpt-4o" }, | ||
{ | ||
name: "Anthropic Claude 3.5 Sonnet", | ||
value: "claude-3-5-sonnet-20241022", | ||
}, | ||
], | ||
default: "gpt-4o", | ||
}, | ||
{ | ||
type: "input", | ||
name: "anthropicApiKey", | ||
message: "Enter your Anthropic API key", | ||
when: (answers) => answers.modelName.includes("claude") && !process.env.ANTHROPIC_API_KEY, | ||
}, | ||
{ | ||
type: "input", | ||
name: "openaiApiKey", | ||
message: "Enter your OpenAI API key", | ||
when: (answers) => answers.modelName.includes("gpt") && !process.env.OPENAI_API_KEY, | ||
}, | ||
{ | ||
type: "list", | ||
name: "env", | ||
message: "Would you like to run locally or on Browserbase (10 free sessions)?", | ||
choices: [ | ||
{ | ||
name: "Browserbase", | ||
value: "BROWSERBASE", | ||
}, | ||
{ | ||
name: "Local", | ||
value: "LOCAL", | ||
}, | ||
], | ||
default: "BROWSERBASE", | ||
}, | ||
{ | ||
type: "input", | ||
name: "projectId", | ||
message: "Go to Browserbase Settings: https://www.browserbase.com/settings\nEnter your project ID", | ||
when: (answers) => answers.env === "BROWSERBASE" && !process.env.BROWSERBASE_PROJECT_ID, | ||
}, | ||
{ | ||
type: "input", | ||
name: "apiKey", | ||
message: "Enter your Browserbase API key", | ||
when: (answers) => answers.env === "BROWSERBASE" && !process.env.BROWSERBASE_API_KEY, | ||
}, | ||
{ | ||
type: "confirm", | ||
name: "debugDom", | ||
message: "Enable DOM debugging features?", | ||
default: true, | ||
}, | ||
{ | ||
type: "confirm", | ||
name: "headless", | ||
message: "Run browser in headless mode?", | ||
default: false, | ||
when: (answers) => answers.env === "LOCAL", | ||
}, | ||
{ | ||
type: "confirm", | ||
name: "enableCaching", | ||
message: "Enable prompt caching?", | ||
default: true, | ||
}, | ||
]); | ||
return answers; | ||
} | ||
function createProjectStructure(projectPath, projectName, options, commandOptions) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
// Create project directory | ||
yield fs.mkdir(projectPath, { recursive: true }); | ||
// Copy starter kit files | ||
const starterKitPath = path.join(dirname(fileURLToPath(import.meta.url)), "..", "examples", "starterProject"); | ||
function copyRecursively(source, destination) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const stats = yield fs.stat(source); | ||
if (stats.isDirectory()) { | ||
yield fs.mkdir(destination, { recursive: true }); | ||
const files = yield fs.readdir(source); | ||
// Check for .gitignore file | ||
let ignorePatterns = []; | ||
const gitignorePath = path.join(source, ".gitignore"); | ||
try { | ||
yield fs.access(gitignorePath); | ||
const gitignoreContent = yield fs.readFile(gitignorePath, "utf8"); | ||
ignorePatterns = gitignoreContent | ||
.split("\n") | ||
.map((line) => line.trim()) | ||
.filter((line) => line && !line.startsWith("#")); | ||
async function createProjectStructure(projectPath, projectName, options, commandOptions) { | ||
try { | ||
// Create project directory | ||
await fs.mkdir(projectPath, { recursive: true }); | ||
// Copy starter kit files | ||
const starterKitPath = path.join(dirname(fileURLToPath(import.meta.url)), "..", "examples", "starterProject"); | ||
async function copyRecursively(source, destination) { | ||
const stats = await fs.stat(source); | ||
if (stats.isDirectory()) { | ||
await fs.mkdir(destination, { recursive: true }); | ||
const files = await fs.readdir(source); | ||
// Check for .gitignore file | ||
let ignorePatterns = []; | ||
const gitignorePath = path.join(source, ".gitignore"); | ||
try { | ||
await fs.access(gitignorePath); | ||
const gitignoreContent = await fs.readFile(gitignorePath, "utf8"); | ||
ignorePatterns = gitignoreContent | ||
.split("\n") | ||
.map((line) => line.trim()) | ||
.filter((line) => line && !line.startsWith("#")); | ||
} | ||
catch { | ||
// File doesn't exist, use empty patterns array | ||
ignorePatterns = []; | ||
} | ||
for (const file of files) { | ||
// Skip files matching gitignore patterns | ||
const shouldIgnore = ignorePatterns.some((pattern) => { | ||
if (pattern.endsWith("/")) { | ||
return file.startsWith(pattern); | ||
} | ||
catch (_a) { | ||
// File doesn't exist, use empty patterns array | ||
ignorePatterns = []; | ||
} | ||
for (const file of files) { | ||
// Skip files matching gitignore patterns | ||
const shouldIgnore = ignorePatterns.some((pattern) => { | ||
if (pattern.endsWith("/")) { | ||
return file.startsWith(pattern); | ||
} | ||
return file === pattern || minimatch(file, pattern); | ||
}) || file.includes("example_"); | ||
if (!shouldIgnore || | ||
file.includes(`example_${commandOptions.template}.ts`)) { | ||
yield copyRecursively(path.join(source, file), path.join(destination, file.includes(`example_${commandOptions.template}.ts`) | ||
? "index.ts" | ||
: file)); | ||
} | ||
} | ||
return file === pattern || minimatch(file, pattern); | ||
}) || file.includes("example_"); | ||
if (!shouldIgnore || | ||
file.includes(`example_${commandOptions.template}.ts`)) { | ||
await copyRecursively(path.join(source, file), path.join(destination, file.includes(`example_${commandOptions.template}.ts`) | ||
? "index.ts" | ||
: file)); | ||
} | ||
else { | ||
// Read and process file | ||
let content = yield fs.readFile(source, "utf8"); | ||
if (path.basename(source) === "stagehand.config.ts") { | ||
content = content | ||
.replace("${apiKey}", options.openaiApiKey || options.anthropicApiKey || "") | ||
.replace("${modelName}", options.modelName || "gpt-4o"); | ||
} | ||
content = content.replace("${projectName}", projectName); | ||
yield fs.writeFile(destination, content); | ||
} | ||
}); | ||
} | ||
} | ||
try { | ||
yield copyRecursively(starterKitPath, projectPath); | ||
// Create .env file with configuration | ||
const envContent = `# Environment to run Stagehand in (LOCAL or BROWSERBASE) | ||
else { | ||
// Read and process file | ||
let content = await fs.readFile(source, "utf8"); | ||
if (path.basename(source) === "stagehand.config.ts") { | ||
content = content | ||
.replace("${apiKey}", options.openaiApiKey || options.anthropicApiKey || "") | ||
.replace("${modelName}", options.modelName || "gpt-4o"); | ||
} | ||
content = content.replace("${projectName}", projectName); | ||
await fs.writeFile(destination, content); | ||
} | ||
} | ||
try { | ||
await copyRecursively(starterKitPath, projectPath); | ||
// Create .env file with configuration | ||
const envContent = `# Environment to run Stagehand in (LOCAL or BROWSERBASE) | ||
STAGEHAND_ENV=${options.env} | ||
@@ -177,81 +163,77 @@ | ||
STAGEHAND_ENV_HEADLESS=${options.headless || false}`; | ||
yield fs.writeFile(path.join(projectPath, ".env"), envContent); | ||
} | ||
catch (err) { | ||
console.error(chalk.red(`Error copying starter kit files: ${err.message}`)); | ||
} | ||
// Initialize git if requested | ||
if (!commandOptions.ignoreGit) { | ||
execSync("git config --global init.defaultBranch main", { | ||
cwd: projectPath, | ||
}); | ||
execSync("git init", { cwd: projectPath }); | ||
execSync("git branch -M main", { cwd: projectPath }); | ||
} | ||
if (commandOptions.template !== "stagehand") { | ||
execSync("npm install --save @browserbasehq/sdk"); | ||
} | ||
await fs.writeFile(path.join(projectPath, ".env"), envContent); | ||
} | ||
catch (error) { | ||
throw new Error(`Failed to create project structure: ${error}`); | ||
catch (err) { | ||
console.error(chalk.red(`Error copying starter kit files: ${err.message}`)); | ||
} | ||
}); | ||
// Initialize git if requested | ||
if (!commandOptions.ignoreGit) { | ||
execSync("git config --global init.defaultBranch main", { | ||
cwd: projectPath, | ||
}); | ||
execSync("git init", { cwd: projectPath }); | ||
execSync("git branch -M main", { cwd: projectPath }); | ||
} | ||
if (commandOptions.template !== "stagehand") { | ||
execSync("npm install --save @browserbasehq/sdk"); | ||
} | ||
} | ||
catch (error) { | ||
throw new Error(`Failed to create project structure: ${error}`); | ||
} | ||
} | ||
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")); | ||
// Add new function for the 'add' command | ||
function addExample(exampleName) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
async function addExample(exampleName) { | ||
try { | ||
// Create browser directory if it doesn't exist | ||
const browserDir = path.join(process.cwd(), "browser"); | ||
await fs.mkdir(browserDir, { recursive: true }); | ||
// Read the example file | ||
const examplePath = path.join(dirname(fileURLToPath(import.meta.url)), "..", "examples", "starterProject", `example_${exampleName}.ts`); | ||
try { | ||
// Create browser directory if it doesn't exist | ||
const browserDir = path.join(process.cwd(), "browser"); | ||
yield fs.mkdir(browserDir, { recursive: true }); | ||
// Read the example file | ||
const examplePath = path.join(dirname(fileURLToPath(import.meta.url)), "..", "examples", "starterProject", `example_${exampleName}.ts`); | ||
try { | ||
const exampleContent = yield fs.readFile(examplePath, "utf8"); | ||
yield fs.writeFile(path.join(browserDir, `${exampleName}.ts`), exampleContent); | ||
} | ||
catch (error) { | ||
throw new Error(`Example '${exampleName}' not found`); | ||
} | ||
// Check package.json for required dependencies | ||
let packageJson; | ||
try { | ||
const packageJsonContent = yield fs.readFile(path.join(process.cwd(), "package.json"), "utf8"); | ||
packageJson = JSON.parse(packageJsonContent); | ||
} | ||
catch (error) { | ||
throw new Error("package.json not found. Are you in a Node.js project?"); | ||
} | ||
const dependencies = packageJson.dependencies || {}; | ||
const missingDeps = []; | ||
if (!dependencies["@browserbasehq/sdk"]) { | ||
missingDeps.push("@browserbasehq/sdk"); | ||
} | ||
if (!dependencies["@browserbasehq/stagehand"]) { | ||
missingDeps.push("@browserbasehq/stagehand"); | ||
} | ||
if (missingDeps.length > 0) { | ||
const { installDeps } = yield inquirer.prompt([ | ||
{ | ||
type: "confirm", | ||
name: "installDeps", | ||
message: `Would you like to install missing dependencies: ${missingDeps.join(", ")}?`, | ||
default: true, | ||
}, | ||
]); | ||
if (installDeps) { | ||
console.log(chalk.yellow("Installing dependencies...")); | ||
const packageManager = ((_a = process.env.npm_config_user_agent) === null || _a === void 0 ? void 0 : _a.split("/")[0]) || "npm"; | ||
execSync(`${packageManager} ${packageManager === "yarn" ? "add" : "install"} ${missingDeps.join(" ")}`, { stdio: "inherit" }); | ||
} | ||
} | ||
console.log(chalk.green(`Successfully added ${exampleName} to browser/${exampleName}.ts`)); | ||
const exampleContent = await fs.readFile(examplePath, "utf8"); | ||
await fs.writeFile(path.join(browserDir, `${exampleName}.ts`), exampleContent); | ||
} | ||
catch (error) { | ||
console.error(chalk.red(error.message)); | ||
process.exit(1); | ||
throw new Error(`Example '${exampleName}' not found`); | ||
} | ||
}); | ||
// Check package.json for required dependencies | ||
let packageJson; | ||
try { | ||
const packageJsonContent = await fs.readFile(path.join(process.cwd(), "package.json"), "utf8"); | ||
packageJson = JSON.parse(packageJsonContent); | ||
} | ||
catch (error) { | ||
throw new Error("package.json not found. Are you in a Node.js project?"); | ||
} | ||
const dependencies = packageJson.dependencies || {}; | ||
const missingDeps = []; | ||
if (!dependencies["@browserbasehq/sdk"]) { | ||
missingDeps.push("@browserbasehq/sdk"); | ||
} | ||
if (!dependencies["@browserbasehq/stagehand"]) { | ||
missingDeps.push("@browserbasehq/stagehand"); | ||
} | ||
if (missingDeps.length > 0) { | ||
const { installDeps } = await inquirer.prompt([ | ||
{ | ||
type: "confirm", | ||
name: "installDeps", | ||
message: `Would you like to install missing dependencies: ${missingDeps.join(", ")}?`, | ||
default: true, | ||
}, | ||
]); | ||
if (installDeps) { | ||
console.log(chalk.yellow("Installing dependencies...")); | ||
const packageManager = process.env.npm_config_user_agent?.split("/")[0] || "npm"; | ||
execSync(`${packageManager} ${packageManager === "yarn" ? "add" : "install"} ${missingDeps.join(" ")}`, { stdio: "inherit" }); | ||
} | ||
} | ||
console.log(chalk.green(`Successfully added ${exampleName} to browser/${exampleName}.ts`)); | ||
} | ||
catch (error) { | ||
console.error(chalk.red(error.message)); | ||
process.exit(1); | ||
} | ||
} | ||
@@ -270,7 +252,7 @@ // Modify the program definition to use subcommands | ||
.option("--ignore-git", "Skip git checks and initialization") | ||
.action((projectName, options) => __awaiter(void 0, void 0, void 0, function* () { | ||
.action(async (projectName, options) => { | ||
try { | ||
const projectPath = path.join(process.cwd(), projectName); | ||
const promptOptions = yield promptForOptions(); | ||
yield createProjectStructure(projectPath, projectName, promptOptions, options); | ||
const promptOptions = await promptForOptions(); | ||
await createProjectStructure(projectPath, projectName, promptOptions, options); | ||
console.log(chalk.green(`🤘 Successfully created new Stagehand project: "${projectName}"`)); | ||
@@ -284,3 +266,3 @@ console.log(chalk.yellow("🎬 Lights, Camera, act()!")); | ||
} | ||
})); | ||
}); | ||
// Add new 'add' command | ||
@@ -287,0 +269,0 @@ program |
{ | ||
"name": "@browserbasehq/bb9", | ||
"version": "1.1.8", | ||
"version": "1.1.9", | ||
"description": "", | ||
@@ -25,2 +25,3 @@ "main": "./dist/index.js", | ||
"@changesets/cli": "^2.27.10", | ||
"@tsconfig/recommended": "^1.0.8", | ||
"@types/node": "^22.10.2" | ||
@@ -27,0 +28,0 @@ }, |
45916
12
645
4