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
75 changes: 43 additions & 32 deletions hatch_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ def initialize(self, version, build_data):
self.app.display_info("Skipping frontend build (SKIP_FRONTEND_BUILD set)")
return

# Editable installs do not need packaged frontend assets; the dedicated
# frontend CI job already validates the client bundle separately.
if version == "editable":
self.app.display_info("Skipping frontend build for editable install")
return

# Only build for wheel target
if self.target_name != "wheel":
return
Expand All @@ -44,40 +50,45 @@ def initialize(self, version, build_data):
dist_dir = client_dir / "dist"
if dist_dir.exists() and (dist_dir / "index.html").exists():
self.app.display_info("Frontend already built - skipping build")
return
else:
# Check if npm is available
if not shutil.which("npm"):
self.app.display_info("npm not found - skipping frontend build")
return

# Check if npm is available
if not shutil.which("npm"):
self.app.display_info("npm not found - skipping frontend build")
return
self.app.display_info("Building frontend client...")

# Prefer the lockfile for reproducible CI/frontend packaging.
install_cmd = (
["npm", "ci"] if (client_dir / "package-lock.json").exists() else ["npm", "install"]
)

# Install dependencies
self.app.display_info("Installing npm dependencies...")
result = subprocess.run(
install_cmd,
cwd=client_dir,
capture_output=True,
text=True,
)
if result.returncode != 0:
cmd_name = " ".join(install_cmd)
self.app.display_error(f"{cmd_name} failed: {result.stderr}")
raise RuntimeError(f"{cmd_name} failed: {result.stderr}")

# Build the frontend
self.app.display_info("Running npm build...")
result = subprocess.run(
["npm", "run", "build"],
cwd=client_dir,
capture_output=True,
text=True,
)
if result.returncode != 0:
self.app.display_error(f"npm build failed: {result.stderr}")
raise RuntimeError(f"npm build failed: {result.stderr}")

self.app.display_info("Building frontend client...")

# Install dependencies
self.app.display_info("Installing npm dependencies...")
result = subprocess.run(
["npm", "install"],
cwd=client_dir,
capture_output=True,
text=True,
)
if result.returncode != 0:
self.app.display_error(f"npm install failed: {result.stderr}")
raise RuntimeError(f"npm install failed: {result.stderr}")

# Build the frontend
self.app.display_info("Running npm build...")
result = subprocess.run(
["npm", "run", "build"],
cwd=client_dir,
capture_output=True,
text=True,
)
if result.returncode != 0:
self.app.display_error(f"npm build failed: {result.stderr}")
raise RuntimeError(f"npm build failed: {result.stderr}")

# Verify build output exists
# Non-editable wheel builds should leave the built assets in-package.
dist_dir = client_dir / "dist"
if not dist_dir.exists() or not (dist_dir / "index.html").exists():
raise RuntimeError(f"Build output not found at {dist_dir}")
Expand Down
3 changes: 0 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,6 @@ packages = ["src/kurt", "eval"]
[tool.hatch.build.targets.wheel.hooks.custom]
path = "hatch_build.py"

[tool.hatch.build.targets.wheel.force-include]
"src/kurt/web/client/dist" = "kurt/web/client/dist"

[tool.ruff]
line-length = 100
target-version = "py310"
Expand Down
3 changes: 2 additions & 1 deletion src/kurt/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ def get_command(self, ctx, name):
"help": ("kurt.cli.show", "show_group"),
# Agent workflows
"agents": ("kurt.workflows.agents.cli", "agents_group"),
"media": ("kurt.workflows.media.cli", "media_group"),
# Skill management
"skill": ("kurt.cli.skill", "skill"),
},
Expand Down Expand Up @@ -209,7 +210,7 @@ def main(ctx, json_output: bool, quiet: bool):

# Skip auto-migrate for commands that don't need DB or use Dolt CLI directly
# doctor/repair use Dolt CLI commands which conflict with the auto-started server
if ctx.invoked_subcommand in ["init", "help", "doctor", "repair"]:
if ctx.invoked_subcommand in ["init", "help", "doctor", "repair", "media"]:
return

# Skip if no project initialized
Expand Down
6 changes: 6 additions & 0 deletions src/kurt/services/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""Kurt services - external API integrations and utilities."""

from kurt.services.ai_generation import AIGenerationService
from kurt.services.media_edit import MediaEditService

__all__ = ["AIGenerationService", "MediaEditService"]
Loading
Loading