From 9e9ca0286dc0be3bca1a786eb4be645e3b0dd728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=E1=BB=B3nh=20Th=C6=B0=C6=A1ng?= <252359928+Huynhthuongg@users.noreply.github.com> Date: Wed, 3 Jun 2026 09:51:26 +0700 Subject: [PATCH 1/3] Add Vercel-ready project landing page --- .github/workflows/ci.yml | 3 +- README.md | 25 +++++++- public/app.js | 15 +++++ public/badges/fastapi.svg | 5 ++ public/badges/termux.svg | 5 ++ public/badges/vercel.svg | 5 ++ public/index.html | 99 ++++++++++++++++++++++++++++ public/styles.css | 132 ++++++++++++++++++++++++++++++++++++++ pyproject.toml | 9 ++- scripts/check.sh | 21 ++++++ vercel.json | 14 ++++ 11 files changed, 328 insertions(+), 5 deletions(-) create mode 100644 public/app.js create mode 100644 public/badges/fastapi.svg create mode 100644 public/badges/termux.svg create mode 100644 public/badges/vercel.svg create mode 100644 public/index.html create mode 100644 public/styles.css create mode 100644 vercel.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e150f07..57e9458 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,5 +18,4 @@ jobs: python-version: ${{ matrix.python-version }} - run: python -m pip install --upgrade pip - run: python -m pip install -e '.[dev]' - - run: ruff check . - - run: pytest -q + - run: ./scripts/check.sh diff --git a/README.md b/README.md index dd1dadf..9a6ee72 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,16 @@ # Universal Project Compiler Agent +

+ Termux ready + FastAPI powered + Vercel ready +

+ +

+ Android-first compiler agent for turning requirements into secure, runnable project scaffolds.
+ Preview the landing page · Deploy on Vercel +

+ Android-first, Termux-first development agent that transforms documents, specifications, repositories, OCR text, Markdown, or natural language requests into complete, runnable, maintainable software project scaffolds. The original product specification is preserved in [docs/SPECIFICATION.md](docs/SPECIFICATION.md). @@ -58,6 +69,18 @@ tests/ Unit tests .github/workflows/ CI checks ``` + +## Vercel landing page + +A polished static introduction page is included in `public/` with animated SVG badges and Vercel routing/security headers in `vercel.json`. + +```bash +npm i -g vercel +vercel deploy --prod +``` + +If deploying from CI, provide your Vercel token as an environment secret and run `vercel deploy --prod --token "$VERCEL_TOKEN"`. + ## Development ```bash @@ -65,7 +88,7 @@ python -m pip install -e '.[dev]' ./scripts/check.sh ``` -`./scripts/check.sh` runs Ruff and the full pytest suite so release checks match CI. +`./scripts/check.sh` verifies development dependencies, then runs Ruff, Codespell, and the full pytest suite so release checks match CI. The Vercel landing page lives in `public/` and is served as a static site. ## Current release diff --git a/public/app.js b/public/app.js new file mode 100644 index 0000000..d1bfe86 --- /dev/null +++ b/public/app.js @@ -0,0 +1,15 @@ +document.documentElement.classList.add('js'); + +const observer = new IntersectionObserver( + (entries) => { + for (const entry of entries) { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + observer.unobserve(entry.target); + } + } + }, + { threshold: 0.18 } +); + +document.querySelectorAll('.reveal').forEach((node) => observer.observe(node)); diff --git a/public/badges/fastapi.svg b/public/badges/fastapi.svg new file mode 100644 index 0000000..09196c8 --- /dev/null +++ b/public/badges/fastapi.svg @@ -0,0 +1,5 @@ + + + + FASTAPI POWERED + diff --git a/public/badges/termux.svg b/public/badges/termux.svg new file mode 100644 index 0000000..cba805d --- /dev/null +++ b/public/badges/termux.svg @@ -0,0 +1,5 @@ + + + + TERMUX READY + diff --git a/public/badges/vercel.svg b/public/badges/vercel.svg new file mode 100644 index 0000000..64d9bf7 --- /dev/null +++ b/public/badges/vercel.svg @@ -0,0 +1,5 @@ + + + + VERCEL READY + diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..efc804d --- /dev/null +++ b/public/index.html @@ -0,0 +1,99 @@ + + + + + + + + + + Universal Project Compiler Agent + + + + + + +
+
+ + +
+
+
+

Android-first • Termux-ready • Secure by default

+

Turn rough requirements into polished, runnable software scaffolds.

+

Plan, compile, and ship maintainable Python/FastAPI projects with generated docs, tests, scripts, secret redaction, and low-resource workflows built for mobile developers.

+
+ Termux ready + FastAPI powered + Vercel ready +
+ +
+ +
+ +
+
+

What ships

+

Professional scaffolds with safety rails.

+
+
+
01

Planning engine

Converts natural language into Critical/High/Medium/Low implementation tasks with impact and file scope.

+
02

Safe generation

Normalizes slugs, rejects unsafe paths, escapes Markdown, and redacts common secrets before writing files.

+
03

Dual interface

Use the local CLI for Termux workflows or the FastAPI service for browsers, automation, and future dashboards.

+
+
+ +
+
+

Workflow

+

From prompt to project in three steps.

+
+
    +
  1. DescribePaste a README, spec, OCR text, or a plain-language product idea.
  2. +
  3. ReviewInspect prioritized work items, security notes, and inferred architecture.
  4. +
  5. CompileGenerate a runnable scaffold with docs, tests, scripts, and package metadata.
  6. +
+
+ +
+
+

Vercel-ready

+

Static landing page configuration is included.

+

Deploy the polished GitHub introduction page with Vercel after connecting the repository or by running the Vercel CLI with your account token.

+
+ Open Vercel import +
+
+ + + + + diff --git a/public/styles.css b/public/styles.css new file mode 100644 index 0000000..2f44b99 --- /dev/null +++ b/public/styles.css @@ -0,0 +1,132 @@ +:root { + color-scheme: dark; + --bg: #050816; + --panel: rgba(15, 23, 42, 0.72); + --panel-strong: rgba(15, 23, 42, 0.9); + --text: #f8fafc; + --muted: #a5b4fc; + --soft: #cbd5e1; + --line: rgba(255, 255, 255, 0.14); + --accent: #8b5cf6; + --accent-two: #06b6d4; + --accent-three: #22c55e; + --shadow: 0 28px 110px rgba(0, 0, 0, 0.48); +} + +* { box-sizing: border-box; } +html { scroll-behavior: smooth; } +body { + margin: 0; + min-height: 100vh; + overflow-x: hidden; + background: + radial-gradient(circle at 12% 10%, rgba(139, 92, 246, 0.28), transparent 32rem), + radial-gradient(circle at 88% 4%, rgba(6, 182, 212, 0.22), transparent 30rem), + linear-gradient(135deg, #050816 0%, #0f172a 50%, #111827 100%); + color: var(--text); + font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; +} + +a { color: inherit; text-decoration: none; } +.shell { width: min(1120px, calc(100% - 32px)); margin: 0 auto; } +.aurora { + position: fixed; + z-index: -1; + width: 24rem; + height: 24rem; + border-radius: 999px; + filter: blur(28px); + opacity: 0.35; + animation: float 13s ease-in-out infinite alternate; +} +.aurora-one { left: -7rem; top: 18rem; background: var(--accent); } +.aurora-two { right: -8rem; top: 8rem; background: var(--accent-two); animation-delay: -4s; } + +.nav { display: flex; align-items: center; justify-content: space-between; gap: 18px; padding: 24px 0; } +.brand { display: inline-flex; align-items: center; gap: 12px; font-weight: 900; } +.brand-mark { + display: grid; + width: 42px; + height: 42px; + place-items: center; + border-radius: 14px; + background: linear-gradient(135deg, var(--accent), var(--accent-two)); + box-shadow: 0 14px 36px rgba(6, 182, 212, 0.22); +} +.nav nav { display: flex; gap: 18px; color: var(--soft); font-weight: 700; } +.nav nav a:hover { color: white; } + +.hero { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(320px, 0.9fr); gap: 36px; align-items: center; padding: 72px 0 84px; } +.eyebrow { margin: 0 0 14px; color: var(--muted); font-weight: 900; letter-spacing: 0.12em; text-transform: uppercase; } +h1, h2, h3 { margin: 0; line-height: 1; letter-spacing: -0.055em; } +h1 { max-width: 820px; font-size: clamp(48px, 8vw, 94px); } +h2 { font-size: clamp(34px, 5vw, 58px); } +h3 { font-size: 24px; } +.lede { max-width: 720px; margin: 24px 0; color: var(--soft); font-size: clamp(18px, 2vw, 22px); line-height: 1.7; } +.badge-row { display: flex; flex-wrap: wrap; gap: 10px; margin: 18px 0 30px; } +.badge-row img { height: 34px; filter: drop-shadow(0 12px 20px rgba(0, 0, 0, 0.22)); } +.actions { display: flex; flex-wrap: wrap; gap: 14px; } +.button { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 48px; + border-radius: 999px; + padding: 0 20px; + font-weight: 900; + transition: transform 0.2s ease, border-color 0.2s ease, filter 0.2s ease; +} +.button:hover { transform: translateY(-2px); filter: brightness(1.08); } +.primary { background: linear-gradient(135deg, var(--accent), var(--accent-two)); color: white; } +.ghost { border: 1px solid var(--line); background: rgba(255, 255, 255, 0.06); } + +.terminal-card { + border: 1px solid var(--line); + border-radius: 28px; + background: linear-gradient(180deg, var(--panel), rgba(2, 6, 23, 0.78)); + box-shadow: var(--shadow); + overflow: hidden; + transform: perspective(900px) rotateY(-5deg) rotateX(3deg); +} +.terminal-bar { display: flex; gap: 8px; padding: 18px; border-bottom: 1px solid var(--line); } +.terminal-bar span { width: 12px; height: 12px; border-radius: 999px; background: var(--accent-three); } +.terminal-bar span:nth-child(2) { background: #f59e0b; } +.terminal-bar span:nth-child(3) { background: #ef4444; } +pre { margin: 0; padding: 24px; overflow: auto; color: #dbeafe; font-size: 15px; line-height: 1.75; } + +.section { padding: 72px 0; } +.section-heading { max-width: 700px; margin-bottom: 28px; } +.grid { display: grid; gap: 18px; } +.cards { grid-template-columns: repeat(3, minmax(0, 1fr)); } +.card, .deploy, .steps li { + border: 1px solid var(--line); + border-radius: 26px; + background: var(--panel); + box-shadow: 0 20px 70px rgba(0, 0, 0, 0.22); +} +.card { padding: 24px; } +.card span { color: var(--accent-three); font-weight: 900; } +.card p, .steps span, .deploy p { color: var(--soft); line-height: 1.65; } +.split { display: grid; grid-template-columns: 0.8fr 1.2fr; gap: 28px; align-items: start; } +.steps { display: grid; gap: 14px; margin: 0; padding: 0; list-style: none; counter-reset: step; } +.steps li { display: grid; gap: 8px; padding: 22px; } +.steps strong { font-size: 22px; } +.deploy { display: flex; justify-content: space-between; gap: 24px; align-items: center; margin: 72px auto; padding: 30px; background: linear-gradient(135deg, rgba(139, 92, 246, 0.2), rgba(6, 182, 212, 0.14)); } +.footer { padding: 24px 0 40px; color: var(--soft); } +.reveal { opacity: 1; transform: translateY(0); } +.js .reveal { opacity: 0; transform: translateY(22px); transition: opacity 0.8s ease, transform 0.8s ease; } +.js .reveal.visible { opacity: 1; transform: translateY(0); } + +@keyframes float { + from { transform: translate3d(0, 0, 0) scale(1); } + to { transform: translate3d(3rem, -2rem, 0) scale(1.08); } +} + +@media (max-width: 860px) { + .nav { align-items: flex-start; flex-direction: column; } + .nav nav { flex-wrap: wrap; } + .hero, .split, .cards { grid-template-columns: 1fr; } + .hero { padding-top: 44px; } + .terminal-card { transform: none; } + .deploy { align-items: flex-start; flex-direction: column; } +} diff --git a/pyproject.toml b/pyproject.toml index 006121f..81b73d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,8 +20,9 @@ dependencies = [ dev = [ "pytest>=8.0,<9.0", "ruff>=0.6,<1.0", - "httpx>=0.27,<1.0", - "httpx2>=2.3,<3.0" + "httpx>=0.28,<1.0", + "httpx2>=2.3,<3.0", + "codespell>=2.3,<3.0" ] [project.scripts] @@ -47,3 +48,7 @@ select = ["E", "F", "I", "B", "UP", "SIM"] [tool.ruff.lint.per-file-ignores] "app/universal_compiler_agent/server.py" = ["E501"] "app/universal_compiler_agent/templates.py" = ["E501"] + +[tool.codespell] +skip = "*.png,.git,.pytest_cache,.ruff_cache,.venv" +ignore-words-list = "thi" diff --git a/scripts/check.sh b/scripts/check.sh index 7f5a70c..5bdfb32 100755 --- a/scripts/check.sh +++ b/scripts/check.sh @@ -1,4 +1,25 @@ #!/usr/bin/env sh set -eu + +missing="" +for command in ruff codespell; do + if ! command -v "$command" >/dev/null 2>&1; then + missing="$missing $command" + fi +done + +for module in pytest httpx2 httpx; do + if ! python -c "import ${module}" >/dev/null 2>&1; then + missing="$missing $module" + fi +done + +if [ -n "$missing" ]; then + echo "Missing development dependencies:$missing" >&2 + echo "Run: python -m pip install -e '.[dev]'" >&2 + exit 1 +fi + ruff check . +codespell README.md docs app tests pyproject.toml scripts config public vercel.json pytest -q diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..f058b70 --- /dev/null +++ b/vercel.json @@ -0,0 +1,14 @@ +{ + "cleanUrls": true, + "trailingSlash": false, + "headers": [ + { + "source": "/(.*)", + "headers": [ + { "key": "X-Content-Type-Options", "value": "nosniff" }, + { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" }, + { "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=()" } + ] + } + ] +} From f34fb5554f6f5ade9e75ab3e2f7560a6d95f11f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=E1=BB=B3nh=20Th=C6=B0=C6=A1ng?= <252359928+Huynhthuongg@users.noreply.github.com> Date: Wed, 3 Jun 2026 09:56:26 +0700 Subject: [PATCH 2/3] Reduce landing page PR merge scope --- .github/workflows/ci.yml | 3 ++- README.md | 2 +- pyproject.toml | 5 ++--- scripts/check.sh | 21 --------------------- vercel.json | 33 ++++++++++++++++++++++++++++++--- 5 files changed, 35 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 57e9458..e150f07 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,4 +18,5 @@ jobs: python-version: ${{ matrix.python-version }} - run: python -m pip install --upgrade pip - run: python -m pip install -e '.[dev]' - - run: ./scripts/check.sh + - run: ruff check . + - run: pytest -q diff --git a/README.md b/README.md index 9a6ee72..d30efb1 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ python -m pip install -e '.[dev]' ./scripts/check.sh ``` -`./scripts/check.sh` verifies development dependencies, then runs Ruff, Codespell, and the full pytest suite so release checks match CI. The Vercel landing page lives in `public/` and is served as a static site. +`./scripts/check.sh` runs Ruff and the full pytest suite so release checks match CI. The Vercel landing page lives in `public/` and is served as a static site. ## Current release diff --git a/pyproject.toml b/pyproject.toml index 81b73d2..fe9c955 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,9 +20,8 @@ dependencies = [ dev = [ "pytest>=8.0,<9.0", "ruff>=0.6,<1.0", - "httpx>=0.28,<1.0", - "httpx2>=2.3,<3.0", - "codespell>=2.3,<3.0" + "httpx>=0.27,<1.0", + "httpx2>=2.3,<3.0" ] [project.scripts] diff --git a/scripts/check.sh b/scripts/check.sh index 5bdfb32..7f5a70c 100755 --- a/scripts/check.sh +++ b/scripts/check.sh @@ -1,25 +1,4 @@ #!/usr/bin/env sh set -eu - -missing="" -for command in ruff codespell; do - if ! command -v "$command" >/dev/null 2>&1; then - missing="$missing $command" - fi -done - -for module in pytest httpx2 httpx; do - if ! python -c "import ${module}" >/dev/null 2>&1; then - missing="$missing $module" - fi -done - -if [ -n "$missing" ]; then - echo "Missing development dependencies:$missing" >&2 - echo "Run: python -m pip install -e '.[dev]'" >&2 - exit 1 -fi - ruff check . -codespell README.md docs app tests pyproject.toml scripts config public vercel.json pytest -q diff --git a/vercel.json b/vercel.json index f058b70..9e4df4a 100644 --- a/vercel.json +++ b/vercel.json @@ -5,10 +5,37 @@ { "source": "/(.*)", "headers": [ - { "key": "X-Content-Type-Options", "value": "nosniff" }, - { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" }, - { "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=()" } + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "Referrer-Policy", + "value": "strict-origin-when-cross-origin" + }, + { + "key": "Permissions-Policy", + "value": "camera=(), microphone=(), geolocation=()" + } ] } + ], + "rewrites": [ + { + "source": "/", + "destination": "/public/index.html" + }, + { + "source": "/styles.css", + "destination": "/public/styles.css" + }, + { + "source": "/app.js", + "destination": "/public/app.js" + }, + { + "source": "/badges/:path*", + "destination": "/public/badges/:path*" + } ] } From 0bff53b7c4a3a5d3a520105c816229682cabf147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=E1=BB=B3nh=20Th=C6=B0=C6=A1ng?= <252359928+Huynhthuongg@users.noreply.github.com> Date: Wed, 3 Jun 2026 18:21:16 +0700 Subject: [PATCH 3/3] Update vercel.json Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> --- vercel.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vercel.json b/vercel.json index 9e4df4a..f202d04 100644 --- a/vercel.json +++ b/vercel.json @@ -23,7 +23,7 @@ "rewrites": [ { "source": "/", - "destination": "/public/index.html" + "destination": "/index.html" }, { "source": "/styles.css",