mirror of https://github.com/kortix-ai/suna.git
modify dockerfile for web dev agent
This commit is contained in:
parent
93a21ea351
commit
5339f51206
|
@ -113,10 +113,11 @@ You have the abilixwty to execute operations using both Python and CLI tools:
|
|||
|
||||
**MANDATORY WORKFLOW for Web Projects:**
|
||||
1. **RESPECT USER'S TECH STACK** - If user specifies technologies (e.g., "use Supabase", "use Prisma", "use tRPC"), those take priority
|
||||
2. For Next.js projects - Install shadcn IMMEDIATELY after project creation:
|
||||
- `npx create-next-app@14 my-app --ts --eslint --tailwind --app --src-dir --import-alias "@/*" --use-npm` (Use Next.js 14 for shadcn compatibility)
|
||||
- `cd my-app && npx shadcn@latest init` (use defaults)
|
||||
- `cd my-app && npx shadcn@latest add button card form input dialog dropdown-menu sheet tabs badge alert`
|
||||
2. For Next.js projects - **shadcn/ui comes PRE-INSTALLED with ALL components** in the optimized template:
|
||||
- Use `create_web_project` to scaffold new projects instantly with everything ready
|
||||
- **Next.js 15 + TypeScript + Tailwind CSS + shadcn/ui + ALL components included**
|
||||
- **NO MANUAL SETUP NEEDED** - everything is pre-configured and ready to use
|
||||
- All shadcn components (button, card, form, input, dialog, dropdown-menu, sheet, tabs, badge, alert, etc.) are immediately available
|
||||
3. **MANDATORY: After ANY project creation, ALWAYS run `get_project_structure` to show the created structure**
|
||||
4. Install user-specified packages BEFORE generic ones
|
||||
5. **BUILD BEFORE EXPOSING (CRITICAL FOR PERFORMANCE):**
|
||||
|
@ -126,7 +127,7 @@ You have the abilixwty to execute operations using both Python and CLI tools:
|
|||
- **WHY**: Development servers are slow and resource-intensive. Production builds are optimized and fast.
|
||||
- **THEN**: Use `expose_port` on the production server port for best user experience
|
||||
|
||||
* Use the 'create_web_project' tool to scaffold new projects with TypeScript, Tailwind CSS, and ESLint
|
||||
* Use the 'create_web_project' tool to scaffold new projects with Next.js 15, TypeScript, Tailwind CSS, shadcn/ui, and ALL components pre-installed
|
||||
* Use the 'install_dependencies' tool to add npm packages to your projects
|
||||
* Use the 'start_dev_server' tool to run development servers (automatically manages tmux sessions)
|
||||
* Use the 'build_project' tool to create production builds
|
||||
|
@ -146,7 +147,7 @@ You have the abilixwty to execute operations using both Python and CLI tools:
|
|||
**MANDATORY UI/UX REQUIREMENTS for Web Projects:**
|
||||
- **NO BASIC DESIGNS ALLOWED** - Every interface must be elegant, polished, and professional
|
||||
- **ALWAYS use shadcn/ui components** - Never write custom HTML/CSS when shadcn has a component
|
||||
- Import shadcn components
|
||||
- Import shadcn components (ALL components are pre-installed and available immediately)
|
||||
- Use the cn() utility for conditional classes and animations
|
||||
- Implement smooth transitions and micro-interactions
|
||||
- Use modern design patterns: glass morphism, subtle gradients, proper spacing
|
||||
|
@ -164,19 +165,19 @@ You have the abilixwty to execute operations using both Python and CLI tools:
|
|||
- Feedback: Use Toast, Alert, Progress, or Skeleton components
|
||||
|
||||
* Example workflow for ELEGANT Next.js app:
|
||||
1. Create project: `npx create-next-app@14 my-app --ts --eslint --tailwind --app --src-dir --import-alias "@/*" --use-npm` with TypeScript & Tailwind (v14 for shadcn compatibility)
|
||||
2. Install shadcn: `cd my-app && npx shadcn@latest init`
|
||||
3. Add CORE components first: `cd my-app && npx shadcn@latest add button card form input dialog dropdown-menu` (add others on demand)
|
||||
4. Install user-specified tech stack packages
|
||||
1. Create project: `create_web_project my-app` - **INSTANTLY gets Next.js 15 + shadcn/ui + ALL components**
|
||||
2. **SKIP shadcn setup** - Everything is pre-configured and ready to use!
|
||||
3. **SKIP component installation** - ALL shadcn components are already available
|
||||
4. Install user-specified tech stack packages only
|
||||
5. **MANDATORY: Use `get_project_structure` to display the created structure**
|
||||
6. Create beautiful layouts with shadcn components
|
||||
7. Implement dark mode toggle using shadcn's theme system
|
||||
6. Start building with pre-installed shadcn components immediately
|
||||
7. Implement dark mode toggle using shadcn's pre-configured theme system
|
||||
8. Add animations with Framer Motion or shadcn's built-in transitions
|
||||
9. Use proper loading states and error boundaries
|
||||
10. Deploy with Vercel or user-specified platform
|
||||
* Prefer pnpm and template-first scaffolding for speed when available.
|
||||
* Prefer these specialized tools over manual npm/npx commands for web projects.
|
||||
* The web dev tools handle all the complex setup automatically (npm install, configuration, etc.)
|
||||
* Prefer pnpm and the optimized template for fastest scaffolding
|
||||
* The web dev tools handle all setup automatically - shadcn/ui comes fully configured with ALL components
|
||||
* No manual setup required - everything is production-ready from the start
|
||||
|
||||
### 2.3.8 IMAGE GENERATION & EDITING
|
||||
- Use the 'image_edit_or_generate' tool to generate new images from a prompt or to edit an existing image file (no mask support).
|
||||
|
@ -336,7 +337,7 @@ You have the abilixwty to execute operations using both Python and CLI tools:
|
|||
* Write Python code for complex mathematical calculations and analysis
|
||||
* Use search tools to find solutions when encountering unfamiliar problems
|
||||
* For index.html, use deployment tools directly, or package everything into a zip file and provide it as a message attachment
|
||||
* When creating Next.js/React interfaces, ALWAYS use shadcn/ui components - install with `npx shadcn@latest init` and add components as needed
|
||||
* When creating Next.js/React interfaces, ALWAYS use shadcn/ui components - ALL components are pre-installed and ready to use
|
||||
* For images, use real image URLs from sources like unsplash.com, pexels.com, pixabay.com, giphy.com, or wikimedia.org instead of creating placeholder images; use placeholder.com only as a last resort
|
||||
|
||||
- WEBSITE DEPLOYMENT:
|
||||
|
@ -932,8 +933,8 @@ For large outputs and complex content, use files instead of long responses:
|
|||
- **For ALL Next.js/React web projects:**
|
||||
* **MANDATORY**: Use shadcn/ui as the primary component library
|
||||
* **NEVER** create custom HTML/CSS components when shadcn equivalents exist
|
||||
* **ALWAYS** install shadcn immediately: `npx shadcn@latest init`
|
||||
* **ALWAYS** add essential components: `npx shadcn@latest add button card dialog form input select dropdown-menu tabs sheet`
|
||||
* **ALL shadcn components are pre-installed** - button, card, dialog, form, input, select, dropdown-menu, tabs, sheet, etc.
|
||||
* **NO SETUP REQUIRED** - shadcn/ui comes fully configured in the optimized template
|
||||
|
||||
- **UI Excellence Requirements:**
|
||||
* Use sophisticated color schemes with proper contrast ratios
|
||||
|
|
|
@ -137,8 +137,8 @@ class ToolManager:
|
|||
self.thread_manager.add_tool(SandboxImageEditTool, project_id=self.project_id, thread_id=self.thread_id, thread_manager=self.thread_manager)
|
||||
if safe_tool_check('sb_sheets_tool'):
|
||||
self.thread_manager.add_tool(SandboxSheetsTool, project_id=self.project_id, thread_manager=self.thread_manager)
|
||||
# if safe_tool_check('sb_web_dev_tool'):
|
||||
# self.thread_manager.add_tool(SandboxWebDevTool, project_id=self.project_id, thread_id=self.thread_id, thread_manager=self.thread_manager)
|
||||
if safe_tool_check('sb_web_dev_tool'):
|
||||
self.thread_manager.add_tool(SandboxWebDevTool, project_id=self.project_id, thread_id=self.thread_id, thread_manager=self.thread_manager)
|
||||
if config.RAPID_API_KEY and safe_tool_check('data_providers_tool'):
|
||||
self.thread_manager.add_tool(DataProvidersTool)
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ class SunaConfig:
|
|||
|
||||
DEFAULT_TOOLS = {
|
||||
"sb_shell_tool": True,
|
||||
"sb_files_tool": True,
|
||||
"sb_web_dev_tool": True,
|
||||
"browser_tool": True,
|
||||
"sb_deploy_tool": True,
|
||||
"sb_expose_tool": True,
|
||||
|
|
|
@ -13,33 +13,11 @@ from utils.logger import logger
|
|||
|
||||
class SandboxWebDevTool(SandboxToolsBase):
|
||||
WORKSPACE_PATH = "/workspace"
|
||||
TEMPLATE_DIR = "/opt/templates/next14-shadcn"
|
||||
TEMPLATE_DIR = "/opt/templates/next-app"
|
||||
DEFAULT_TIMEOUT = 60
|
||||
BUILD_TIMEOUT = 1800
|
||||
INSTALL_TIMEOUT = 900
|
||||
DEFAULT_PORT = 3000
|
||||
|
||||
SHADCN_CONFIG_TEMPLATE = {
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": True,
|
||||
"tsx": True,
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "src/app/globals.css",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": True,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"iconLibrary": "lucide"
|
||||
}
|
||||
|
||||
def __init__(self, project_id: str, thread_id: str, thread_manager: ThreadManager):
|
||||
super().__init__(project_id, thread_manager)
|
||||
|
@ -128,6 +106,82 @@ class SandboxWebDevTool(SandboxToolsBase):
|
|||
}
|
||||
return commands.get(package_manager, commands["npm"]).get(command_type, "")
|
||||
|
||||
async def _has_optimized_template(self) -> bool:
|
||||
dir_check = await self._exec_sh(f"test -d {self.TEMPLATE_DIR} && echo EXISTS || echo MISSING")
|
||||
if "MISSING" in dir_check.get("output", ""):
|
||||
logger.info(f"Template directory {self.TEMPLATE_DIR} does not exist")
|
||||
return False
|
||||
|
||||
checks = [
|
||||
(f"test -f {self.TEMPLATE_DIR}/package.json", "package.json"),
|
||||
(f"test -f {self.TEMPLATE_DIR}/components.json", "components.json"),
|
||||
(f"test -f {self.TEMPLATE_DIR}/tailwind.config.ts", "tailwind.config.ts"),
|
||||
(f"test -d {self.TEMPLATE_DIR}/src/components/ui", "src/components/ui directory")
|
||||
]
|
||||
|
||||
missing_files = []
|
||||
for check_cmd, file_desc in checks:
|
||||
result = await self._exec_sh(check_cmd)
|
||||
if result.get("exit_code") != 0:
|
||||
missing_files.append(file_desc)
|
||||
|
||||
if missing_files:
|
||||
logger.info(f"Template missing files: {', '.join(missing_files)}")
|
||||
# Let's also check what files ARE available for debugging
|
||||
ls_result = await self._exec_sh(f"ls -la {self.TEMPLATE_DIR}")
|
||||
logger.info(f"Template directory contents: {ls_result.get('output', 'Could not list')}")
|
||||
return False
|
||||
|
||||
logger.info("Optimized template found and validated")
|
||||
return True
|
||||
|
||||
@openapi_schema({
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "debug_template_status",
|
||||
"description": "Debug helper to check the current state of the optimized template",
|
||||
"parameters": {"type": "object", "properties": {}, "required": []}
|
||||
}
|
||||
})
|
||||
async def debug_template_status(self) -> ToolResult:
|
||||
try:
|
||||
await self._ensure_sandbox()
|
||||
|
||||
debug_info = []
|
||||
|
||||
dir_check = await self._exec_sh(f"test -d {self.TEMPLATE_DIR} && echo EXISTS || echo MISSING")
|
||||
debug_info.append(f"Template directory ({self.TEMPLATE_DIR}): {dir_check.get('output', 'Unknown')}")
|
||||
|
||||
if "EXISTS" in dir_check.get("output", ""):
|
||||
ls_result = await self._exec_sh(f"ls -la {self.TEMPLATE_DIR}")
|
||||
debug_info.append(f"Directory contents:\n{ls_result.get('output', 'Could not list')}")
|
||||
|
||||
files_to_check = [
|
||||
"package.json",
|
||||
"components.json",
|
||||
"tailwind.config.ts",
|
||||
"src/components/ui"
|
||||
]
|
||||
|
||||
for file_path in files_to_check:
|
||||
full_path = f"{self.TEMPLATE_DIR}/{file_path}"
|
||||
if file_path.endswith("/ui"):
|
||||
check_cmd = f"test -d {full_path} && echo DIR_EXISTS || echo DIR_MISSING"
|
||||
else:
|
||||
check_cmd = f"test -f {full_path} && echo FILE_EXISTS || echo FILE_MISSING"
|
||||
|
||||
result = await self._exec_sh(check_cmd)
|
||||
debug_info.append(f"{file_path}: {result.get('output', 'Unknown')}")
|
||||
|
||||
has_template = await self._has_optimized_template()
|
||||
debug_info.append(f"Template detection result: {'✅ PASS' if has_template else '❌ FAIL'}")
|
||||
|
||||
return self.success_response("\n".join(debug_info))
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error debugging template: {e}", exc_info=True)
|
||||
return self.fail_response(f"Error debugging template: {e}")
|
||||
|
||||
@openapi_schema({
|
||||
"type": "function",
|
||||
"function": {
|
||||
|
@ -163,8 +217,8 @@ class SandboxWebDevTool(SandboxToolsBase):
|
|||
return self.success_response("""
|
||||
📁 No projects found in workspace.
|
||||
|
||||
To create a new project, use create_web_project or execute_command:
|
||||
- Next.js: npx create-next-app@latest my-next-app --ts --eslint --tailwind --app --src-dir --import-alias "@/*" --use-npm
|
||||
To create a new project, use create_web_project:
|
||||
- Next.js with shadcn/ui: All components pre-installed and ready to use!
|
||||
- React: npx create-react-app my-app --template typescript
|
||||
- Vite: npm create vite@latest my-app -- --template react-ts
|
||||
""")
|
||||
|
@ -182,7 +236,7 @@ To create a new project, use create_web_project or execute_command:
|
|||
project_type = "Node.js project"
|
||||
output_lower = cat_result.get("output", "").lower()
|
||||
if "next" in output_lower:
|
||||
project_type = "Next.js project"
|
||||
project_type = "Next.js project (with shadcn/ui)"
|
||||
elif "react" in output_lower:
|
||||
project_type = "React project"
|
||||
elif "vite" in output_lower:
|
||||
|
@ -279,263 +333,7 @@ To run this project:
|
|||
"type": "function",
|
||||
"function": {
|
||||
"name": "create_web_project",
|
||||
"description": "Scaffold a new web project with optional shadcn/ui auto-initialization. Supports Next.js (default). Uses cached templates when available for speed.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"project_name": {"type": "string", "description": "Project directory name to create"},
|
||||
"template": {"type": "string", "description": "Template key (e.g., 'next14-shadcn' or 'next')", "default": "next14-shadcn"},
|
||||
"package_manager": {"type": "string", "description": "Package manager: pnpm|npm", "default": "pnpm"},
|
||||
"init_shadcn": {"type": "boolean", "description": "Automatically initialize shadcn/ui (default: true for Next.js projects)", "default": True}
|
||||
},
|
||||
"required": ["project_name"]
|
||||
}
|
||||
}
|
||||
})
|
||||
@usage_example('''
|
||||
<!-- Create a new Next.js project with automatic shadcn/ui initialization -->
|
||||
<function_calls>
|
||||
<invoke name="create_web_project">
|
||||
<parameter name="project_name">my-portfolio</parameter>
|
||||
<parameter name="template">next14-shadcn</parameter>
|
||||
<parameter name="package_manager">pnpm</parameter>
|
||||
<parameter name="init_shadcn">true</parameter>
|
||||
</invoke>
|
||||
</function_calls>
|
||||
|
||||
<!-- Create a plain Next.js project without shadcn/ui -->
|
||||
<function_calls>
|
||||
<invoke name="create_web_project">
|
||||
<parameter name="project_name">simple-app</parameter>
|
||||
<parameter name="template">next</parameter>
|
||||
<parameter name="init_shadcn">false</parameter>
|
||||
</invoke>
|
||||
</function_calls>
|
||||
''')
|
||||
async def create_web_project(self, project_name: str, template: str = "next14-shadcn", package_manager: str = "pnpm", init_shadcn: bool = True) -> ToolResult:
|
||||
try:
|
||||
await self._ensure_sandbox()
|
||||
|
||||
use_template = template.lower() in ["next14-shadcn", "next"]
|
||||
exists_check = await self._exec_sh(f"test -d {self.TEMPLATE_DIR} && echo __TEMPLATE__ || echo __NO_TEMPLATE__")
|
||||
has_template = "__TEMPLATE__" in exists_check.get("output", "")
|
||||
|
||||
proj_dir = self._get_project_path(project_name)
|
||||
already = await self._exec_sh(f"test -e {proj_dir} && echo __EXISTS__ || echo __NEW__")
|
||||
if "__EXISTS__" in already.get("output", ""):
|
||||
return self.fail_response(f"Path '{project_name}' already exists")
|
||||
|
||||
if use_template and has_template:
|
||||
copy = await self._exec_sh(f"cp -R {self.TEMPLATE_DIR} {proj_dir}")
|
||||
if copy["exit_code"] != 0:
|
||||
return self.fail_response(f"Failed to copy template: {copy['output']}")
|
||||
else:
|
||||
if package_manager == "pnpm":
|
||||
scaffold_cmd = (
|
||||
f"cd {self.workspace_path} && "
|
||||
f"pnpm dlx create-next-app@14 {project_name} --ts --eslint --tailwind --app --src-dir --import-alias '@/*' --use-pnpm"
|
||||
)
|
||||
else:
|
||||
scaffold_cmd = (
|
||||
f"cd {self.workspace_path} && "
|
||||
f"npx create-next-app@14 {project_name} --ts --eslint --tailwind --app --src-dir --import-alias '@/*' --use-npm"
|
||||
)
|
||||
|
||||
res = await self._exec_sh(scaffold_cmd, timeout=self.INSTALL_TIMEOUT)
|
||||
if res["exit_code"] != 0:
|
||||
return self.fail_response(f"Scaffold failed: {res['output']}")
|
||||
|
||||
install_cmd = self._get_package_manager_command(package_manager, "install")
|
||||
install = await self._exec_sh(f"cd {proj_dir} && {install_cmd}", timeout=self.INSTALL_TIMEOUT)
|
||||
|
||||
if install["exit_code"] != 0:
|
||||
return self.fail_response(f"Dependency install failed: {install['output']}")
|
||||
|
||||
# Auto-initialize shadcn/ui for Next.js projects
|
||||
success_message = f"Project '{project_name}' created successfully."
|
||||
if init_shadcn and template.lower() in ["next14-shadcn", "next"]:
|
||||
try:
|
||||
# Check if components.json already exists (from template)
|
||||
components_check = await self._exec_sh(f"test -f {proj_dir}/components.json && echo EXISTS || echo MISSING")
|
||||
|
||||
if "MISSING" in components_check.get("output", ""):
|
||||
# Initialize shadcn/ui
|
||||
has_src = await self._has_src_directory(proj_dir)
|
||||
css_path = "src/app/globals.css" if has_src else "app/globals.css"
|
||||
|
||||
config = self.SHADCN_CONFIG_TEMPLATE.copy()
|
||||
config["tailwind"]["css"] = css_path
|
||||
|
||||
config_json = json.dumps(config, indent=2)
|
||||
write_cmd = f"cd {proj_dir} && cat > components.json << 'EOF'\n{config_json}\nEOF"
|
||||
write_result = await self._exec_sh(write_cmd)
|
||||
|
||||
if write_result.get("exit_code", 1) == 0:
|
||||
success_message += " shadcn/ui initialized automatically."
|
||||
else:
|
||||
logger.warning(f"Failed to auto-initialize shadcn: {write_result.get('output','')}")
|
||||
else:
|
||||
success_message += " shadcn/ui already configured."
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to auto-initialize shadcn: {e}")
|
||||
# Don't fail the entire project creation for shadcn issues
|
||||
|
||||
return self.success_response({
|
||||
"message": success_message,
|
||||
"project": project_name
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating web project: {e}", exc_info=True)
|
||||
return self.fail_response(f"Error creating web project: {e}")
|
||||
|
||||
@openapi_schema({
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "init_shadcn",
|
||||
"description": "Initialize shadcn/ui in a Next.js project (non-interactive).",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"project_name": {"type": "string", "description": "Project directory name"}
|
||||
},
|
||||
"required": ["project_name"]
|
||||
}
|
||||
}
|
||||
})
|
||||
@usage_example('''
|
||||
<!-- Initialize shadcn/ui in an existing Next.js project -->
|
||||
<function_calls>
|
||||
<invoke name="init_shadcn">
|
||||
<parameter name="project_name">my-existing-app</parameter>
|
||||
</invoke>
|
||||
</function_calls>
|
||||
''')
|
||||
async def init_shadcn(self, project_name: str) -> ToolResult:
|
||||
try:
|
||||
await self._ensure_sandbox()
|
||||
|
||||
if not await self._project_exists(project_name):
|
||||
return self.fail_response(f"Project '{project_name}' not found")
|
||||
|
||||
proj_dir = self._get_project_path(project_name)
|
||||
|
||||
has_src = await self._has_src_directory(proj_dir)
|
||||
css_path = "src/app/globals.css" if has_src else "app/globals.css"
|
||||
|
||||
config = self.SHADCN_CONFIG_TEMPLATE.copy()
|
||||
config["tailwind"]["css"] = css_path
|
||||
|
||||
config_json = json.dumps(config, indent=2)
|
||||
write_cmd = f"cd {proj_dir} && cat > components.json << 'EOF'\n{config_json}\nEOF"
|
||||
write_result = await self._exec_sh(write_cmd)
|
||||
|
||||
if write_result.get("exit_code", 1) != 0:
|
||||
return self.fail_response(f"Failed to write components.json: {write_result.get('output','')}")
|
||||
|
||||
verify = await self._exec_sh(f"test -f {proj_dir}/components.json && echo OK || echo MISS")
|
||||
if "OK" in verify.get("output", ""):
|
||||
return self.success_response(f"shadcn/ui configured successfully in '{project_name}'.")
|
||||
|
||||
return self.fail_response("components.json was not created as expected")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error initializing shadcn: {e}", exc_info=True)
|
||||
return self.fail_response(f"Error initializing shadcn: {e}")
|
||||
|
||||
@openapi_schema({
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "add_shadcn_components",
|
||||
"description": "Add shadcn/ui components to a Next.js project.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"project_name": {"type": "string"},
|
||||
"components": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Component names, e.g., button, card, form, input, dialog, dropdown-menu"
|
||||
}
|
||||
},
|
||||
"required": ["project_name", "components"]
|
||||
}
|
||||
}
|
||||
})
|
||||
@usage_example('''
|
||||
<!-- Add common shadcn/ui components to a project -->
|
||||
<function_calls>
|
||||
<invoke name="add_shadcn_components">
|
||||
<parameter name="project_name">my-app</parameter>
|
||||
<parameter name="components">["button", "card", "input", "form", "dialog"]</parameter>
|
||||
</invoke>
|
||||
</function_calls>
|
||||
''')
|
||||
async def add_shadcn_components(self, project_name: str, components: List[str]) -> ToolResult:
|
||||
try:
|
||||
await self._ensure_sandbox()
|
||||
|
||||
if not await self._project_exists(project_name):
|
||||
return self.fail_response(f"Project '{project_name}' not found")
|
||||
|
||||
proj_dir = self._get_project_path(project_name)
|
||||
|
||||
verify = await self._exec_sh(f"test -f {proj_dir}/components.json && echo OK || echo MISS")
|
||||
if "MISS" in verify.get("output", ""):
|
||||
init_res = await self.init_shadcn(project_name)
|
||||
if not init_res.success:
|
||||
return init_res
|
||||
|
||||
comps = " ".join(components)
|
||||
attempts = [
|
||||
f"cd {proj_dir} && pnpm dlx shadcn@latest add {comps}",
|
||||
f"cd {proj_dir} && npx shadcn@latest add {comps}"
|
||||
]
|
||||
|
||||
for cmd in attempts:
|
||||
res = await self._exec_sh(cmd, timeout=self.INSTALL_TIMEOUT)
|
||||
if res["exit_code"] == 0:
|
||||
return self.success_response(f"Added shadcn components to '{project_name}': {', '.join(components)}")
|
||||
|
||||
return self.fail_response(f"Failed to add components: {res.get('output','') if 'res' in locals() else 'Unknown error'}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error adding shadcn components: {e}", exc_info=True)
|
||||
return self.fail_response(f"Error adding shadcn components: {e}")
|
||||
|
||||
@openapi_schema({
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "add_common_shadcn_components",
|
||||
"description": "Add commonly used shadcn/ui components to a Next.js project in one go.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"project_name": {"type": "string", "description": "Project directory name"}
|
||||
},
|
||||
"required": ["project_name"]
|
||||
}
|
||||
}
|
||||
})
|
||||
@usage_example('''
|
||||
<!-- Add all commonly used shadcn/ui components at once -->
|
||||
<function_calls>
|
||||
<invoke name="add_common_shadcn_components">
|
||||
<parameter name="project_name">my-app</parameter>
|
||||
</invoke>
|
||||
</function_calls>
|
||||
''')
|
||||
async def add_common_shadcn_components(self, project_name: str) -> ToolResult:
|
||||
"""Add commonly used shadcn/ui components: button, card, input, form, dialog, dropdown-menu, badge, avatar."""
|
||||
common_components = ["button", "card", "input", "form", "dialog", "dropdown-menu", "badge", "avatar"]
|
||||
return await self.add_shadcn_components(project_name, common_components)
|
||||
|
||||
@openapi_schema({
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "create_full_stack_project",
|
||||
"description": "Create a complete Next.js project with shadcn/ui initialized and common components already added. One-stop setup for rapid development.",
|
||||
"description": "Create a new Next.js project with shadcn/ui and ALL components pre-installed from optimized template. Fast scaffolding with everything ready to use!",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -547,48 +345,72 @@ To run this project:
|
|||
}
|
||||
})
|
||||
@usage_example('''
|
||||
<!-- Create a complete Next.js project with shadcn/ui and common components -->
|
||||
<!-- Create a new Next.js project with shadcn/ui pre-configured -->
|
||||
<function_calls>
|
||||
<invoke name="create_full_stack_project">
|
||||
<parameter name="project_name">my-complete-app</parameter>
|
||||
<invoke name="create_web_project">
|
||||
<parameter name="project_name">my-portfolio</parameter>
|
||||
<parameter name="package_manager">pnpm</parameter>
|
||||
</invoke>
|
||||
</function_calls>
|
||||
''')
|
||||
async def create_full_stack_project(self, project_name: str, package_manager: str = "pnpm") -> ToolResult:
|
||||
"""Create a Next.js project with shadcn/ui and common components pre-installed."""
|
||||
async def create_web_project(self, project_name: str, package_manager: str = "pnpm") -> ToolResult:
|
||||
try:
|
||||
# First create the project with shadcn initialized
|
||||
create_result = await self.create_web_project(
|
||||
project_name=project_name,
|
||||
template="next14-shadcn",
|
||||
package_manager=package_manager,
|
||||
init_shadcn=True
|
||||
)
|
||||
await self._ensure_sandbox()
|
||||
|
||||
if not create_result.success:
|
||||
return create_result
|
||||
proj_dir = self._get_project_path(project_name)
|
||||
already = await self._exec_sh(f"test -e {proj_dir} && echo __EXISTS__ || echo __NEW__")
|
||||
if "__EXISTS__" in already.get("output", ""):
|
||||
return self.fail_response(f"Path '{project_name}' already exists")
|
||||
|
||||
has_template = await self._has_optimized_template()
|
||||
|
||||
# Add common components
|
||||
components_result = await self.add_common_shadcn_components(project_name)
|
||||
|
||||
if components_result.success:
|
||||
if has_template:
|
||||
copy = await self._exec_sh(f"cp -R {self.TEMPLATE_DIR} {proj_dir}")
|
||||
if copy["exit_code"] != 0:
|
||||
return self.fail_response(f"Failed to copy template: {copy['output']}")
|
||||
|
||||
install_cmd = self._get_package_manager_command(package_manager, "install")
|
||||
install = await self._exec_sh(f"cd {proj_dir} && {install_cmd}", timeout=self.INSTALL_TIMEOUT)
|
||||
|
||||
if install["exit_code"] != 0:
|
||||
return self.fail_response(f"Dependency install failed: {install['output']}")
|
||||
|
||||
return self.success_response({
|
||||
"message": f"Complete project '{project_name}' created with shadcn/ui and common components ready to use!",
|
||||
"message": f"Project '{project_name}' created successfully with Next.js 15 + shadcn/ui pre-configured and ALL components ready to use!",
|
||||
"project": project_name,
|
||||
"components_added": ["button", "card", "input", "form", "dialog", "dropdown-menu", "badge", "avatar"]
|
||||
"features": [
|
||||
"✅ Next.js 15 with TypeScript",
|
||||
"✅ Tailwind CSS configured",
|
||||
"✅ shadcn/ui initialized",
|
||||
"✅ ALL shadcn components pre-installed",
|
||||
"✅ App Router with src/ directory",
|
||||
"✅ ESLint configured"
|
||||
]
|
||||
})
|
||||
else:
|
||||
# Project created successfully, but components failed
|
||||
return self.success_response({
|
||||
"message": f"Project '{project_name}' created successfully, but failed to add components. You can add them manually with add_common_shadcn_components.",
|
||||
"project": project_name,
|
||||
"warning": components_result.result
|
||||
})
|
||||
if package_manager == "pnpm":
|
||||
scaffold_cmd = (
|
||||
f"cd {self.workspace_path} && "
|
||||
f"pnpm dlx create-next-app@15 {project_name} --ts --eslint --tailwind --app --src-dir --import-alias '@/*' --use-pnpm"
|
||||
)
|
||||
else:
|
||||
scaffold_cmd = (
|
||||
f"cd {self.workspace_path} && "
|
||||
f"npx create-next-app@15 {project_name} --ts --eslint --tailwind --app --src-dir --import-alias '@/*' --use-npm"
|
||||
)
|
||||
|
||||
res = await self._exec_sh(scaffold_cmd, timeout=self.INSTALL_TIMEOUT)
|
||||
if res["exit_code"] != 0:
|
||||
return self.fail_response(f"Scaffold failed: {res['output']}")
|
||||
|
||||
return self.success_response({
|
||||
"message": f"Project '{project_name}' created successfully. Note: Optimized template not available - used manual creation.",
|
||||
"project": project_name
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating full-stack project: {e}", exc_info=True)
|
||||
return self.fail_response(f"Error creating full-stack project: {e}")
|
||||
logger.error(f"Error creating web project: {e}", exc_info=True)
|
||||
return self.fail_response(f"Error creating web project: {e}")
|
||||
|
||||
@openapi_schema({
|
||||
"type": "function",
|
||||
|
|
|
@ -111,15 +111,12 @@ RUN npx playwright install chromium
|
|||
# Verify installation
|
||||
RUN node -e "import('playwright').then(() => console.log('Playwright installation verified')).catch(e => { console.error('Playwright verification failed:', e); process.exit(1); })"
|
||||
|
||||
# Prewarm a Next 14 + shadcn template for fast scaffolding
|
||||
WORKDIR /opt/templates
|
||||
RUN mkdir -p /opt/templates && \
|
||||
pnpm dlx create-next-app@14 next14-shadcn --ts --eslint --tailwind --app --src-dir --import-alias '@/*' --use-npm && \
|
||||
cd /opt/templates/next14-shadcn && \
|
||||
pnpm install --prefer-offline && \
|
||||
npx shadcn@latest init -y || (printf '\n' | npx shadcn@latest init) && \
|
||||
npx shadcn@latest add button card form input dropdown-menu dialog tabs sheet badge alert && \
|
||||
pnpm install --prefer-offline
|
||||
|
||||
WORKDIR /opt/templates/next-app
|
||||
|
||||
RUN npx --yes create-next-app@15.3.3 . --yes --typescript --tailwind --eslint --app --src-dir --import-alias "@/*" --use-pnpm
|
||||
RUN npx --yes shadcn@2.6.3 init --yes -d --force
|
||||
RUN npx --yes shadcn@2.6.3 add --all --yes
|
||||
|
||||
# Copy server script
|
||||
COPY . /app
|
||||
|
|
|
@ -6,7 +6,7 @@ services:
|
|||
dockerfile: ${DOCKERFILE:-Dockerfile}
|
||||
args:
|
||||
TARGETPLATFORM: ${TARGETPLATFORM:-linux/amd64}
|
||||
image: kortix/suna:0.1.3.1
|
||||
image: kortix/suna:0.1.3.2
|
||||
ports:
|
||||
- "6080:6080" # noVNC web interface
|
||||
- "5901:5901" # VNC port
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
export const AGENTPRESS_TOOL_DEFINITIONS: Record<string, { enabled: boolean; description: string; icon: string; color: string }> = {
|
||||
'sb_shell_tool': { enabled: true, description: 'Execute shell commands in tmux sessions for terminal operations, CLI tools, and system management', icon: '💻', color: 'bg-slate-100 dark:bg-slate-800' },
|
||||
'sb_files_tool': { enabled: true, description: 'Create, read, update, and delete files in the workspace with comprehensive file management', icon: '📁', color: 'bg-blue-100 dark:bg-blue-800/50' },
|
||||
'sb_web_dev_tool': { enabled: true, description: 'Create Next.js projects with shadcn/ui pre-installed, manage dependencies, build and deploy modern web applications', icon: '⚛️', color: 'bg-cyan-100 dark:bg-cyan-800/50' },
|
||||
'browser_tool': { enabled: true, description: 'Browser automation for web navigation, clicking, form filling, and page interaction', icon: '🌐', color: 'bg-indigo-100 dark:bg-indigo-800/50' },
|
||||
'sb_deploy_tool': { enabled: true, description: 'Deploy applications and services with automated deployment capabilities', icon: '🚀', color: 'bg-green-100 dark:bg-green-800/50' },
|
||||
'sb_expose_tool': { enabled: true, description: 'Expose services and manage ports for application accessibility', icon: '🔌', color: 'bg-orange-100 dark:bg-orange-800/20' },
|
||||
|
@ -22,6 +23,7 @@ export const getToolDisplayName = (toolName: string): string => {
|
|||
const displayNames: Record<string, string> = {
|
||||
'sb_shell_tool': 'Terminal',
|
||||
'sb_files_tool': 'File Manager',
|
||||
'sb_web_dev_tool': 'Web Development',
|
||||
'browser_tool': 'Browser Automation',
|
||||
'sb_deploy_tool': 'Deploy Tool',
|
||||
'sb_expose_tool': 'Port Exposure',
|
||||
|
|
|
@ -32,6 +32,7 @@ class MCPTools:
|
|||
_AgentPressTools_descriptions = {
|
||||
"sb_files_tool": "Read, write, and edit files",
|
||||
"sb_shell_tool": "Execute shell commands",
|
||||
"sb_web_dev_tool": "Create and manage modern web applications with Next.js and shadcn/ui",
|
||||
"sb_deploy_tool": "Deploy web applications",
|
||||
"sb_expose_tool": "Expose local services to the internet",
|
||||
"sb_vision_tool": "Analyze and understand images",
|
||||
|
@ -45,6 +46,7 @@ _AgentPressTools_descriptions = {
|
|||
class AgentPressTools(str, Enum):
|
||||
SB_FILES_TOOL = "sb_files_tool"
|
||||
SB_SHELL_TOOL = "sb_shell_tool"
|
||||
SB_WEB_DEV_TOOL = "sb_web_dev_tool"
|
||||
SB_DEPLOY_TOOL = "sb_deploy_tool"
|
||||
SB_EXPOSE_TOOL = "sb_expose_tool"
|
||||
SB_VISION_TOOL = "sb_vision_tool"
|
||||
|
|
Loading…
Reference in New Issue