-
Notifications
You must be signed in to change notification settings - Fork 162
feature/web ui #173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature/web ui #173
Changes from all commits
8faf177
afe0bba
ad9dbc8
14afb9a
8fddd19
2043d11
58ececb
05bfa8a
4473493
b41f068
771319c
6ffe9a6
65d8cc5
96c6eb2
5e975a6
151aef4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| name: "web-build" | ||
| description: "Builds the Vite SPA into packages/web/dist for inclusion in the rogue-ai wheel" | ||
| runs: | ||
| using: "composite" | ||
| steps: | ||
| - name: Setup pnpm | ||
| uses: pnpm/action-setup@v4 | ||
| with: | ||
| version: 10 | ||
| - name: Setup Node | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: "20" | ||
| cache: "pnpm" | ||
| cache-dependency-path: packages/web/pnpm-lock.yaml | ||
| - name: Install dependencies | ||
| shell: bash | ||
| run: cd packages/web && pnpm install --frozen-lockfile | ||
| - name: Build SPA | ||
| shell: bash | ||
| run: cd packages/web && pnpm build | ||
| - name: Verify dist exists | ||
| shell: bash | ||
| run: test -f packages/web/dist/index.html |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| name: "web-codestyle" | ||
| description: "Runs prettier --check, eslint, and tsc --noEmit on packages/web" | ||
| runs: | ||
| using: "composite" | ||
| steps: | ||
| - name: Setup pnpm | ||
| uses: pnpm/action-setup@v4 | ||
| with: | ||
| version: 10 | ||
| - name: Setup Node | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: "20" | ||
| cache: "pnpm" | ||
| cache-dependency-path: packages/web/pnpm-lock.yaml | ||
| - name: Install dependencies | ||
| shell: bash | ||
| run: cd packages/web && pnpm install --frozen-lockfile | ||
| - name: Prettier | ||
| shell: bash | ||
| run: cd packages/web && pnpm exec prettier --check . | ||
| - name: ESLint | ||
| shell: bash | ||
| run: cd packages/web && pnpm exec eslint . | ||
| - name: TypeScript | ||
| shell: bash | ||
| # `pnpm typecheck` is `pnpm routes && tsc --noEmit`. The route-tree | ||
| # generator (`tsr generate`) is required because src/routeTree.gen.ts | ||
| # is gitignored — without it tsc can't resolve `./routeTree.gen` and | ||
| # every `createFileRoute(...)` call collapses to `(arg: undefined)`. | ||
| run: cd packages/web && pnpm typecheck |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,2 @@ | ||
| from . import shirtify_langgraph_agent, shirtify_langgraph_agent_executor | ||
| from .shirtify_langgraph_agent import root_agent | ||
| from . import shirtify_langgraph_agent | ||
| from . import shirtify_langgraph_agent_executor |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| """Hatch build hook that ensures the web SPA is built before the wheel ships. | ||
|
|
||
| The hook runs ``pnpm install --frozen-lockfile && pnpm build`` inside | ||
| ``packages/web`` only when the dist is missing or stale. If pnpm is not | ||
| installed, the hook degrades gracefully: it warns and continues, so the wheel | ||
| build still succeeds for contributors who don't need the web UI. CI is | ||
| expected to run ``pnpm --filter web build`` explicitly before ``uv build`` so | ||
| the published wheel always carries ``dist/``. | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import os | ||
| import shutil | ||
| import subprocess # noqa: S404 | ||
| import sys | ||
| from pathlib import Path | ||
| from typing import Any | ||
|
|
||
| from hatchling.builders.hooks.plugin.interface import BuildHookInterface | ||
|
|
||
|
|
||
| class WebBuildHook(BuildHookInterface): | ||
| PLUGIN_NAME = "custom" | ||
|
|
||
| def initialize(self, version: str, build_data: dict[str, Any]) -> None: | ||
| repo_root = Path(self.root) | ||
| web_dir = repo_root / "packages" / "web" | ||
| dist_dir = web_dir / "dist" | ||
| dist_index = dist_dir / "index.html" | ||
| src_dir = web_dir / "src" | ||
|
|
||
| skip_build = bool(os.environ.get("ROGUE_SKIP_WEB_BUILD")) | ||
| if skip_build: | ||
| self.app.display_info("ROGUE_SKIP_WEB_BUILD set; skipping web build.") | ||
|
|
||
| if not skip_build and web_dir.is_dir(): | ||
| needs_build = not dist_index.is_file() or _is_stale(dist_index, src_dir) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Broaden the staleness check before reusing Right now a wheel can reuse stale web assets when files outside Suggested fix- src_dir = web_dir / "src"
+ build_inputs = (
+ web_dir / "src",
+ web_dir / "public",
+ web_dir / "index.html",
+ web_dir / "package.json",
+ web_dir / "pnpm-lock.yaml",
+ web_dir / "tsconfig.json",
+ web_dir / "vite.config.ts",
+ )
skip_build = bool(os.environ.get("ROGUE_SKIP_WEB_BUILD"))
if skip_build:
self.app.display_info("ROGUE_SKIP_WEB_BUILD set; skipping web build.")
if not skip_build and web_dir.is_dir():
- needs_build = not dist_index.is_file() or _is_stale(dist_index, src_dir)
+ needs_build = not dist_index.is_file() or _is_stale(
+ dist_index, build_inputs
+ )-def _is_stale(dist_index: Path, src_dir: Path) -> bool:
- if not src_dir.is_dir():
- return False
+def _is_stale(dist_index: Path, inputs: tuple[Path, ...]) -> bool:
dist_mtime = dist_index.stat().st_mtime
- for path in src_dir.rglob("*"):
- if path.is_file() and path.stat().st_mtime > dist_mtime:
- return True
+ for root in inputs:
+ if root.is_file() and root.stat().st_mtime > dist_mtime:
+ return True
+ if root.is_dir():
+ for path in root.rglob("*"):
+ if path.is_file() and path.stat().st_mtime > dist_mtime:
+ return True
return FalseAlso applies to: 87-94 🤖 Prompt for AI Agents |
||
| if needs_build: | ||
| pnpm = shutil.which("pnpm") | ||
| if pnpm is None: | ||
| if dist_index.is_file(): | ||
| self.app.display_warning( | ||
| "pnpm not found; reusing existing packages/web/dist " | ||
| "(may be stale).", | ||
| ) | ||
| else: | ||
| self.app.display_warning( | ||
| "pnpm not found and packages/web/dist is missing. " | ||
| "The wheel will not include the web UI. " | ||
| "Install Node + pnpm and rebuild, or run " | ||
| "`cd packages/web && pnpm install && pnpm build` manually.", | ||
| ) | ||
| else: | ||
| self.app.display_info("Building web SPA via pnpm...") | ||
| try: | ||
| subprocess.run( # noqa: S603 | ||
| [pnpm, "install", "--frozen-lockfile"], | ||
| cwd=str(web_dir), | ||
| check=True, | ||
| ) | ||
| subprocess.run( # noqa: S603 | ||
| [pnpm, "run", "build"], | ||
| cwd=str(web_dir), | ||
| check=True, | ||
| ) | ||
| except subprocess.CalledProcessError as e: | ||
| self.app.display_error(f"pnpm build failed: {e}") | ||
| sys.exit(1) | ||
|
|
||
| # Force-include the web dist only when it actually exists, so installs | ||
| # in environments without pnpm (and without a prebuilt dist) don't fail | ||
| # on a missing forced-include path. This replaces the static | ||
| # `[tool.hatch.build.targets.*.force-include]` tables in pyproject.toml. | ||
| if dist_dir.is_dir(): | ||
| target = self.target_name | ||
| if target == "wheel": | ||
| build_data.setdefault("force_include", {})[str(dist_dir)] = ( | ||
| "rogue/web_dist" | ||
| ) | ||
| elif target == "sdist": | ||
| build_data.setdefault("force_include", {})[str(dist_dir)] = ( | ||
| "packages/web/dist" | ||
| ) | ||
|
|
||
|
|
||
| def _is_stale(dist_index: Path, src_dir: Path) -> bool: | ||
| if not src_dir.is_dir(): | ||
| return False | ||
| dist_mtime = dist_index.stat().st_mtime | ||
| for path in src_dir.rglob("*"): | ||
| if path.is_file() and path.stat().st_mtime > dist_mtime: | ||
| return True | ||
| return False | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parse
ROGUE_SKIP_WEB_BUILDexplicitly instead of usingbool(...).bool(os.environ.get(...))treats"0"and"false"asTrue, so a caller can accidentally skip the web build and omit the UI.Suggested fix
🤖 Prompt for AI Agents