From 4eb486ef83091edc186bb0c521937ee9172f0d7e Mon Sep 17 00:00:00 2001 From: Kevin Codex Date: Thu, 30 Apr 2026 18:22:01 +0800 Subject: [PATCH] Feat/web landing refresh (#958) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(web): openclaude landing — runs anywhere, uses anything A new marketing site for openclaude under web/, plus the minimal root infrastructure to build, ignore, and gate it without affecting the published npm package. Landing page (web/) - Vite + React 19 with monospace gitlawb typography (sf mono / fira code). - Hero: pill, two-line wordmark "runs anywhere. / uses anything.", copy-to-clipboard install command, github cta. - Six feature rows in hermes-style "title — sentence" format on hairline dividers (any model, real tools, profiles per repo, streaming, gateway routing, editor + server modes). - Install block: same copyable command + three numbered steps. - One-line footer with brand, version, gitlawb link, and license. - Light theme is the default with a no-flash bootstrap script and a ☀ / ☾ toggle persisted to localStorage. - New orange terminal-face logo at 36px in the nav. - Body wash: dual orange radial gradients for warmth on both themes. Root infra - web/ excluded from npm publish via .npmignore (belt-and-suspenders alongside the existing files whitelist). - web/ excluded from docker context (.dockerignore). - web:dev / web:build / web:preview / web:typecheck scripts in package.json that delegate via --cwd web (no root deps added). - web typecheck + build added to the pr-checks workflow. - web/dist/ and web/*.tsbuildinfo ignored. Co-Authored-By: OpenClaude * added vercel in .gitignore --------- Co-authored-by: OpenClaude --- .dockerignore | 1 + .github/workflows/pr-checks.yml | 26 ++ .gitignore | 2 + .npmignore | 6 + package.json | 4 + web/.gitignore | 1 + web/bun.lock | 129 ++++++++ web/index.html | 40 +++ web/package.json | 21 ++ web/public/openclaude.png | Bin 0 -> 46557 bytes web/src/App.tsx | 196 ++++++++++++ web/src/content.ts | 35 +++ web/src/main.tsx | 9 + web/src/styles.css | 530 ++++++++++++++++++++++++++++++++ web/src/vite-env.d.ts | 1 + web/tsconfig.json | 20 ++ web/vite.config.ts | 6 + 17 files changed, 1027 insertions(+) create mode 100644 .npmignore create mode 100644 web/.gitignore create mode 100644 web/bun.lock create mode 100644 web/index.html create mode 100644 web/package.json create mode 100644 web/public/openclaude.png create mode 100644 web/src/App.tsx create mode 100644 web/src/content.ts create mode 100644 web/src/main.tsx create mode 100644 web/src/styles.css create mode 100644 web/src/vite-env.d.ts create mode 100644 web/tsconfig.json create mode 100644 web/vite.config.ts diff --git a/.dockerignore b/.dockerignore index 618de682..d50a4de5 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,6 @@ node_modules dist +web .git .gitignore .env diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 54290fc3..5379fb86 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -58,3 +58,29 @@ jobs: - name: Provider recommendation tests run: npm run test:provider-recommendation + + web: + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Set up Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: 22 + + - name: Set up Bun + uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1 + with: + bun-version: 1.3.11 + + - name: Install web dependencies + run: bun install --cwd web --frozen-lockfile + + - name: Typecheck web + run: bun run --cwd web typecheck + + - name: Build web + run: bun run --cwd web build diff --git a/.gitignore b/.gitignore index 2c5087b7..f73b8fd0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ node_modules/ dist/ *.tsbuildinfo +web/dist/ +web/*.tsbuildinfo .env .env.* !.env.example diff --git a/.npmignore b/.npmignore new file mode 100644 index 00000000..ac6657d2 --- /dev/null +++ b/.npmignore @@ -0,0 +1,6 @@ +# npm publish only ships what the `files` field in package.json allows. +# This .npmignore is a safety net: if `files` is ever removed or expanded, +# nothing in this list can be published. + +# Marketing / landing site — never ship with the CLI package. +web/ diff --git a/package.json b/package.json index f3e24d87..4f6c4038 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,10 @@ "dev:grpc": "bun run scripts/start-grpc.ts", "dev:grpc:cli": "bun run scripts/grpc-cli.ts", "start": "node dist/cli.mjs", + "web:dev": "bun run --cwd web dev", + "web:build": "bun run --cwd web build", + "web:preview": "bun run --cwd web preview", + "web:typecheck": "bun run --cwd web typecheck", "test": "bun test", "test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-dir=coverage --max-concurrency=1 && bun run scripts/render-coverage-heatmap.ts", "test:coverage:ui": "bun run scripts/render-coverage-heatmap.ts", diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 00000000..e985853e --- /dev/null +++ b/web/.gitignore @@ -0,0 +1 @@ +.vercel diff --git a/web/bun.lock b/web/bun.lock new file mode 100644 index 00000000..07a5a62c --- /dev/null +++ b/web/bun.lock @@ -0,0 +1,129 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "openclaude-web", + "dependencies": { + "@types/react": "19.2.14", + "@types/react-dom": "19.2.3", + "@vitejs/plugin-react": "6.0.1", + "react": "19.2.4", + "react-dom": "19.2.4", + "typescript": "6.0.3", + "vite": "8.0.10", + }, + }, + }, + "packages": { + "@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], + + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], + + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], + + "@oxc-project/types": ["@oxc-project/types@0.127.0", "", {}, "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ=="], + + "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.17", "", { "os": "android", "cpu": "arm64" }, "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ=="], + + "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.17", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw=="], + + "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.17", "", { "os": "darwin", "cpu": "x64" }, "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw=="], + + "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.17", "", { "os": "freebsd", "cpu": "x64" }, "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw=="], + + "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17", "", { "os": "linux", "cpu": "arm" }, "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ=="], + + "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17", "", { "os": "linux", "cpu": "arm64" }, "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q=="], + + "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.17", "", { "os": "linux", "cpu": "arm64" }, "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg=="], + + "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17", "", { "os": "linux", "cpu": "ppc64" }, "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA=="], + + "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17", "", { "os": "linux", "cpu": "s390x" }, "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA=="], + + "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.17", "", { "os": "linux", "cpu": "x64" }, "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA=="], + + "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.17", "", { "os": "linux", "cpu": "x64" }, "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw=="], + + "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.17", "", { "os": "none", "cpu": "arm64" }, "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA=="], + + "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.17", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA=="], + + "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17", "", { "os": "win32", "cpu": "arm64" }, "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA=="], + + "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.17", "", { "os": "win32", "cpu": "x64" }, "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg=="], + + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.7", "", {}, "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA=="], + + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + + "@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], + + "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], + + "@vitejs/plugin-react": ["@vitejs/plugin-react@6.0.1", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-rc.7" }, "peerDependencies": { "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", "babel-plugin-react-compiler": "^1.0.0", "vite": "^8.0.0" }, "optionalPeers": ["@rolldown/plugin-babel", "babel-plugin-react-compiler"] }, "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ=="], + + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], + + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], + + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="], + + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="], + + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="], + + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="], + + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="], + + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="], + + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="], + + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="], + + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="], + + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + + "postcss": ["postcss@8.5.12", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA=="], + + "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], + + "react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="], + + "rolldown": ["rolldown@1.0.0-rc.17", "", { "dependencies": { "@oxc-project/types": "=0.127.0", "@rolldown/pluginutils": "1.0.0-rc.17" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.17", "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", "@rolldown/binding-darwin-x64": "1.0.0-rc.17", "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA=="], + + "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + + "vite": ["vite@8.0.10", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.10", "rolldown": "1.0.0-rc.17", "tinyglobby": "^0.2.16" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw=="], + + "rolldown/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.17", "", {}, "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg=="], + } +} diff --git a/web/index.html b/web/index.html new file mode 100644 index 00000000..87ae9932 --- /dev/null +++ b/web/index.html @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + openclaude — runs anywhere, uses anything + + + + + + + +
+ + + diff --git a/web/package.json b/web/package.json new file mode 100644 index 00000000..373c1fde --- /dev/null +++ b/web/package.json @@ -0,0 +1,21 @@ +{ + "name": "openclaude-web", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc --noEmit && vite build", + "preview": "vite preview", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@types/react": "19.2.14", + "@types/react-dom": "19.2.3", + "@vitejs/plugin-react": "6.0.1", + "react": "19.2.4", + "react-dom": "19.2.4", + "typescript": "6.0.3", + "vite": "8.0.10" + } +} diff --git a/web/public/openclaude.png b/web/public/openclaude.png new file mode 100644 index 0000000000000000000000000000000000000000..17eba88a95215874c9e38e53cf6847f93f1ded88 GIT binary patch literal 46557 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 literal 0 HcmV?d00001 diff --git a/web/src/App.tsx b/web/src/App.tsx new file mode 100644 index 00000000..ce2d3d4c --- /dev/null +++ b/web/src/App.tsx @@ -0,0 +1,196 @@ +import { useEffect, useState } from 'react' +import './styles.css' +import { features, installCommand, navLinks } from './content' + +type Theme = 'light' | 'dark' + +function readInitialTheme(): Theme { + if (typeof document === 'undefined') return 'light' + const attr = document.documentElement.dataset.theme + if (attr === 'light' || attr === 'dark') return attr + return 'light' +} + +function App() { + const [theme, setTheme] = useState(readInitialTheme) + + useEffect(() => { + document.documentElement.dataset.theme = theme + document.documentElement.style.colorScheme = theme + try { + localStorage.setItem('openclaude-theme', theme) + } catch { + /* storage unavailable */ + } + }, [theme]) + + const toggleTheme = () => setTheme(t => (t === 'dark' ? 'light' : 'dark')) + + return ( +
+
+ +
+ +
+ + +
+
+

// features

+

built for agents that ship code.

+
+
    + {features.map(f => ( +
  • +

    {f.title}

    +

    — {f.body}

    +
  • + ))} +
+
+ +
+
+

// install

+

one line. then write a task.

+
+
+ +
    +
  1. + 01 +
    + install +

    requires node ≥ 20.

    +
    +
  2. +
  3. + 02 +
    + start +

    run openclaude in any repo.

    +
    +
  4. +
  5. + 03 +
    + pick a provider +

    type /provider to wire openai, ollama, gemini, or a gateway.

    +
    +
  6. +
+
+
+
+ +
+
+ + + openclaude + v0.7.0 + + | + gitlawb ↗ + | + license + · + {new Date().getFullYear()} +
+
+
+ ) +} + +function Hero() { + return ( +
+
+
+ +

+ runs anywhere.
+ uses anything. +

+ +

+ not a chatbot wrapper or another ide plugin. an open coding agent that runs in your + terminal, talks to any model, and keeps every change reviewable. +

+ + + +

+ works with openai, gemini, codex, ollama, lm studio, litellm, and 200+ models. +

+
+ ) +} + +function CopyableCommand({ + command, + variant, +}: { + command: string + variant?: 'hero' +}) { + const [copied, setCopied] = useState(false) + + const onCopy = async () => { + try { + await navigator.clipboard.writeText(command) + setCopied(true) + window.setTimeout(() => setCopied(false), 1400) + } catch { + /* clipboard unavailable */ + } + } + + return ( + + ) +} + +export default App diff --git a/web/src/content.ts b/web/src/content.ts new file mode 100644 index 00000000..a2dd4b92 --- /dev/null +++ b/web/src/content.ts @@ -0,0 +1,35 @@ +export const installCommand = 'npm install -g @gitlawb/openclaude' + +export const features = [ + { + title: 'any model, one terminal', + body: 'local ollama, openai-compatible apis, gemini, codex, github models — switch with one command, no rewrites.', + }, + { + title: 'real tools, not just chat', + body: 'bash, file edits, grep, glob, mcp servers, slash commands — wired into the agent loop, not bolted on.', + }, + { + title: 'profiles per repo', + body: 'save model, base url, auth, and runtime defaults to .openclaude-profile.json so every clone boots the same way.', + }, + { + title: 'streaming, not batch', + body: 'watch the agent think, call tools, and produce diffs live. no opaque background jobs.', + }, + { + title: 'routes through a gateway', + body: 'plug into litellm, openrouter, or an internal proxy for policy, cost control, and failover.', + }, + { + title: 'editor and server modes', + body: 'vs code extension and a grpc server so external systems can drive the same loop.', + }, +] as const + +export const navLinks = [ + { href: '#features', label: 'features' }, + { href: '#install', label: 'install' }, + { href: 'https://github.com/Gitlawb/openclaude', label: 'github' }, + { href: 'https://gitlawb.com/node/repos/z6MkqDnb/openclaude', label: 'gitlawb' }, +] as const diff --git a/web/src/main.tsx b/web/src/main.tsx new file mode 100644 index 00000000..c4c5b6df --- /dev/null +++ b/web/src/main.tsx @@ -0,0 +1,9 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/web/src/styles.css b/web/src/styles.css new file mode 100644 index 00000000..cb1daf13 --- /dev/null +++ b/web/src/styles.css @@ -0,0 +1,530 @@ +/* ── reset + tokens ───────────────────────────────────────────────────── */ + +* { box-sizing: border-box; } + +:root { + --max: 960px; + + /* shared brand */ + --accent: #ff7a1a; + --accent-2: #ffb15f; + --accent-soft: rgba(255, 122, 26, 0.14); + --accent-line: rgba(255, 122, 26, 0.40); + + font-family: 'SF Mono', 'Fira Code', 'Fira Mono', 'Roboto Mono', 'Courier New', monospace; + font-feature-settings: 'ss01', 'ss02', 'cv01', 'cv11'; + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* ── light theme (default) ────────────────────────────────────────────── */ +:root, +:root[data-theme='light'] { + color-scheme: light; + --bg: #fbfaf7; + --bg-elev: rgba(251, 250, 247, 0.88); + --bg-soft: rgba(255, 122, 26, 0.05); + --ink: #1a1208; + --ink-2: rgba(26, 18, 8, 0.88); + --muted: rgba(26, 18, 8, 0.64); + --quiet: rgba(26, 18, 8, 0.46); + --line: rgba(26, 18, 8, 0.10); + --line-strong: rgba(255, 122, 26, 0.30); + --hero-glow: rgba(255, 122, 26, 0.28); + --hero-wash: rgba(255, 122, 26, 0.18); + --hero-wash-2: rgba(255, 177, 95, 0.10); + --copy-bg: #ffffff; + --selection-fg: #ffffff; + --scroll-thumb: #d8c9bc; +} + +/* ── dark theme ───────────────────────────────────────────────────────── */ +:root[data-theme='dark'] { + color-scheme: dark; + --bg: #000000; + --bg-elev: rgba(0, 0, 0, 0.85); + --bg-soft: rgba(255, 255, 255, 0.025); + --ink: #ffffff; + --ink-2: rgba(255, 255, 255, 0.82); + --muted: rgba(255, 255, 255, 0.55); + --quiet: rgba(255, 255, 255, 0.38); + --line: rgba(255, 255, 255, 0.10); + --line-strong: rgba(255, 255, 255, 0.20); + --hero-glow: rgba(255, 122, 26, 0.22); + --hero-wash: rgba(255, 122, 26, 0.16); + --hero-wash-2: rgba(255, 122, 26, 0.06); + --copy-bg: rgba(0, 0, 0, 0.5); + --selection-fg: #120804; + --scroll-thumb: #3a2615; +} + +html { + scroll-behavior: smooth; + background: var(--bg); + transition: background-color 0.25s ease; +} + +body { + min-width: 320px; + margin: 0; + background: + radial-gradient(circle at 78% -4%, var(--hero-wash), transparent 420px), + radial-gradient(circle at 12% 18%, var(--hero-wash-2), transparent 360px), + var(--bg); + color: var(--ink); + overflow-x: hidden; + transition: background-color 0.25s ease, color 0.25s ease; +} + +::-webkit-scrollbar { width: 3px; height: 3px; } +::-webkit-scrollbar-track { background: var(--bg); } +::-webkit-scrollbar-thumb { background: var(--scroll-thumb); } +::selection { background: var(--accent); color: var(--selection-fg); } + +a { + color: inherit; + text-decoration: none; + transition: color 0.18s ease; +} +a:hover { color: var(--ink); } + +button, a { -webkit-tap-highlight-color: transparent; } + +button:focus-visible, +a:focus-visible { + outline: 1px solid var(--accent); + outline-offset: 3px; +} + +button { font: inherit; } +code, pre { font-family: inherit; } +h1, h2, h3, p { margin-top: 0; } + +/* ── shell ────────────────────────────────────────────────────────────── */ + +.site-shell { overflow: hidden; } + +.nav, +.shell-main, +.footer { + width: min(100% - 2.5rem, var(--max)); + margin: 0 auto; +} + +@media (max-width: 600px) { + .nav, .shell-main, .footer { + width: min(100% - 1.5rem, var(--max)); + } +} + +/* ── header ───────────────────────────────────────────────────────────── */ + +.site-header { + position: sticky; + top: 0; + z-index: 30; + background: var(--bg-elev); + backdrop-filter: blur(14px); + transition: background-color 0.25s ease; +} + +.nav { + display: flex; + height: 64px; + align-items: center; + justify-content: space-between; + gap: 1.5rem; +} + +.nav .brand img { + width: 36px; + height: 36px; +} + +.nav .brand { + font-size: 0.95rem; + gap: 0.6rem; +} + +@media (max-width: 600px) { + .nav .brand img { width: 30px; height: 30px; } + .nav .brand { font-size: 0.85rem; } +} + +.nav-rule { + width: min(100% - 2.5rem, var(--max)); + margin: 0 auto; + border-top: 1px dashed var(--line); +} + +.brand { + display: inline-flex; + align-items: center; + gap: 0.5rem; + color: var(--ink); + font-size: 0.85rem; + font-weight: 600; + letter-spacing: -0.01em; +} + +.brand img { + width: 22px; + height: 22px; + display: block; +} + +.brand .ver { + margin-left: 0.4rem; + color: var(--quiet); + font-size: 0.7rem; + font-weight: 400; +} + +.nav-right { + display: flex; + align-items: center; + gap: 1.4rem; +} + +.nav-links { + display: flex; + align-items: center; + gap: 1.6rem; +} + +.nav-links a { + color: var(--muted); + font-size: 0.78rem; +} +.nav-links a:hover { color: var(--ink); } + +.theme-toggle { + display: inline-flex; + align-items: center; + justify-content: center; + height: 28px; + width: 28px; + border: 1px solid var(--line); + background: var(--bg-soft); + color: var(--muted); + cursor: pointer; + font-size: 0.85rem; + line-height: 1; + transition: border-color 0.18s ease, color 0.18s ease, background-color 0.18s ease; +} +.theme-toggle:hover { + border-color: var(--accent); + color: var(--accent); +} + +@media (max-width: 600px) { + .nav-right { gap: 0.85rem; } + .nav-links { gap: 1rem; } + .nav-links a { font-size: 0.72rem; } +} + +/* ── shared atoms ─────────────────────────────────────────────────────── */ + +.eyebrow { + margin: 0 0 0.85rem; + color: var(--accent); + font-size: 0.72rem; + font-weight: 500; + letter-spacing: 0.04em; +} + +.button { + display: inline-flex; + height: 44px; + align-items: center; + justify-content: center; + gap: 0.45rem; + padding: 0 1.05rem; + border: 1px solid transparent; + font-size: 0.8rem; + font-weight: 500; + letter-spacing: 0.01em; + cursor: pointer; + transition: border-color 0.2s ease, background-color 0.2s ease, color 0.2s ease; +} + +.button-ghost { + border-color: var(--line-strong); + color: var(--ink); + background: transparent; +} +.button-ghost:hover { + border-color: var(--ink); + background: rgba(255, 255, 255, 0.04); +} + +.section-head { + max-width: 38rem; + margin: 0 auto 2.25rem; + text-align: center; +} + +.section-head h2 { + margin: 0; + color: var(--ink); + font-size: clamp(1.6rem, 3vw, 2.1rem); + font-weight: 600; + line-height: 1.15; + letter-spacing: -0.025em; +} + +/* ── hero ─────────────────────────────────────────────────────────────── */ + +.hero { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + padding: clamp(4rem, 12vh, 8rem) 0 clamp(3rem, 8vh, 5.5rem); + gap: 1.4rem; +} + +.hero-eyebrow { + display: inline-flex; + align-items: center; + gap: 0.55rem; + padding: 0.4rem 0.85rem; + border: 1px solid var(--accent-line); + background: var(--bg-soft); + color: var(--ink-2); + font-size: 0.7rem; + letter-spacing: 0.02em; +} + +.hero-eyebrow .dot { + width: 6px; + height: 6px; + border-radius: 999px; + background: var(--accent); + box-shadow: 0 0 0 3px var(--accent-soft); +} + +.hero-title { + margin: 0; + font-size: clamp(2.4rem, 6vw, 4.4rem); + font-weight: 700; + line-height: 1; + letter-spacing: -0.04em; + color: var(--ink); + text-shadow: 0 0 28px var(--hero-glow); +} + +.hero-sub { + max-width: 36rem; + margin: 0; + color: var(--muted); + font-size: clamp(0.95rem, 1.4vw, 1.05rem); + line-height: 1.65; +} + +.hero-cta { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: stretch; + gap: 0.75rem; + margin-top: 0.4rem; +} + +.hero-foot { + margin: 0.6rem 0 0; + color: var(--quiet); + font-size: 0.75rem; + letter-spacing: 0.02em; +} + +/* ── copyable command ─────────────────────────────────────────────────── */ + +.copy-cmd { + display: inline-flex; + align-items: center; + gap: 0.7rem; + height: 44px; + padding: 0 0.95rem; + border: 1px solid var(--accent-line); + background: var(--copy-bg); + color: var(--ink); + font-size: 0.82rem; + cursor: pointer; + box-shadow: 0 8px 24px -16px var(--accent-soft); + transition: border-color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease; +} +.copy-cmd:hover { + border-color: var(--accent); + box-shadow: 0 10px 28px -14px var(--accent-soft); +} + +.copy-cmd-hero { + height: 48px; + padding: 0 1.1rem; + font-size: 0.88rem; +} + +.copy-prefix { color: var(--accent); font-weight: 500; } +.copy-text { color: var(--ink-2); } +.copy-icon { + margin-left: 0.4rem; + color: var(--quiet); + font-size: 0.7rem; + letter-spacing: 0.06em; + text-transform: uppercase; +} + +/* ── features ─────────────────────────────────────────────────────────── */ + +.features { + padding: clamp(3rem, 8vh, 5rem) 0; +} + +.feature-list { + display: grid; + grid-template-columns: 1fr; + gap: 0; + margin: 0; + padding: 0; + list-style: none; + border-top: 1px solid var(--line); +} + +.feature-row { + display: grid; + grid-template-columns: minmax(180px, 0.32fr) 1fr; + gap: 1.5rem; + padding: 1.4rem 0; + border-bottom: 1px solid var(--line); +} + +.feature-row h3 { + margin: 0; + color: var(--ink); + font-size: 0.9rem; + font-weight: 600; + letter-spacing: -0.005em; +} + +.feature-row p { + margin: 0; + color: var(--muted); + font-size: 0.88rem; + line-height: 1.65; +} + +@media (max-width: 600px) { + .feature-row { + grid-template-columns: 1fr; + gap: 0.4rem; + padding: 1.1rem 0; + } + .feature-row p { font-size: 0.85rem; } +} + +/* ── install block ────────────────────────────────────────────────────── */ + +.install-block { + padding: clamp(3rem, 8vh, 5rem) 0 clamp(4rem, 10vh, 6rem); +} + +.install-grid { + display: grid; + grid-template-columns: 1fr; + gap: 2rem; + max-width: 36rem; + margin: 0 auto; +} + +.install-grid .copy-cmd { + width: 100%; + justify-content: flex-start; +} + +.install-steps { + display: grid; + gap: 0; + margin: 0; + padding: 0; + list-style: none; + border-top: 1px solid var(--line); +} + +.install-steps li { + display: grid; + grid-template-columns: 2.5rem 1fr; + gap: 1rem; + padding: 1rem 0; + border-bottom: 1px solid var(--line); +} + +.step-num { + color: var(--accent); + font-size: 0.72rem; + letter-spacing: 0.18em; + padding-top: 0.18rem; +} + +.install-steps strong { + display: block; + margin-bottom: 0.25rem; + color: var(--ink); + font-size: 0.88rem; + font-weight: 600; + letter-spacing: -0.005em; +} + +.install-steps p { + margin: 0; + color: var(--muted); + font-size: 0.85rem; + line-height: 1.6; +} + +.install-steps code { + padding: 0.05rem 0.35rem; + border: 1px solid var(--line); + background: rgba(255, 122, 26, 0.06); + color: var(--accent-2); + font-size: 0.8rem; +} + +/* ── footer ───────────────────────────────────────────────────────────── */ + +.footer { + padding: 2rem 0 2.5rem; + border-top: 1px dashed var(--line); +} + +.footer-line { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.55rem; + color: var(--quiet); + font-size: 0.74rem; +} + +.footer-line .brand { + font-size: 0.78rem; +} + +.footer-line .sep { + color: var(--line-strong); +} + +.footer-line a { + color: var(--muted); +} +.footer-line a:hover { color: var(--ink); } + +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + scroll-behavior: auto !important; + animation-duration: 0.001ms !important; + animation-iteration-count: 1 !important; + } +} diff --git a/web/src/vite-env.d.ts b/web/src/vite-env.d.ts new file mode 100644 index 00000000..5894ae0b --- /dev/null +++ b/web/src/vite-env.d.ts @@ -0,0 +1 @@ +declare module '*.css' diff --git a/web/tsconfig.json b/web/tsconfig.json new file mode 100644 index 00000000..72854962 --- /dev/null +++ b/web/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2023", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ES2023"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": ["src", "vite.config.ts"] +} diff --git a/web/vite.config.ts b/web/vite.config.ts new file mode 100644 index 00000000..9ffcc675 --- /dev/null +++ b/web/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], +})