Restructure: move Vite project into app/, deploy build output to repo root

The webserver serves the repo checkout directly as static files, so
index.html at the repo root must be the production build (pointing at
hashed /assets/*.js) rather than the dev template (/src/main.tsx),
which was being served with an unrecognized application/octet-stream
MIME type and blocked by the browser.

- Move src/, public/, scripts/, server/, package.json, vite.config.ts,
  tsconfig.json, .env(.example), and the dev index.html into app/.
- Add app/scripts/deploy.mjs: copies app/dist/* into the repo root
  after every `vite build`, cleaning up stale hashed filenames.
- Wire it into `npm run build` (app/package.json).
- Update run.sh to operate from app/, and .gitignore for the new layout.
- Commit the current build output (index.html, assets/, manifest,
  sw.js, workbox-*.js, favicon.svg, icons/, LICENSE) to the repo root.
- Update README with the new project layout and deployment model.
This commit is contained in:
oliver committed 2026-11-04 14:05:46 -03:00
1 parent 5245c0a856
commit c7b653ff6a
54 files changed
+224 -34

No files matched your search

+59 -20
View File
@@ -107,13 +107,46 @@ Then on the config screen enter your **API server URL** and **API key**.
```bash
./run.sh # dev server (http://localhost:5173)
./run.sh build # production build into dist/
./run.sh build # production build, deployed straight into the repo root
./run.sh serve # build if needed, then host + proxy /api/*, /v1/* (needs HERMES_TARGET)
./run.sh preview # build, then serve the build with vite preview
./run.sh icons # regenerate the PWA icon set
./run.sh typecheck # type-check without emitting
```
### Deployment model: the repo root *is* the web root
The Vite project lives in `app/`. Running a build (`./run.sh build` or
`cd app && npm run build`) compiles it and then copies the output
(`index.html`, `assets/`, `manifest.webmanifest`, `sw.js`, `workbox-*.js`,
`favicon.svg`, `icons/`, `LICENSE`) directly into the **repository root** —
see `app/scripts/deploy.mjs`. Those deployed files are committed to git.
This means a webserver that simply serves the raw repository checkout as
static files (no build step, no custom MIME types, no reverse-proxy config)
works out of the box: `index.html` in the repo root already references
hashed, plain `.js`/`.css` assets — nothing points at `/src/*.tsx` in
production, so there's no "unauthorized MIME type" issue.
To publish a new version:
```bash
cd app
npm run build # builds app/dist, then syncs it into the repo root
cd ..
git add -A
git commit -m "Deploy: <description>"
git push # or however the server pulls the repo
```
> Note: `app/` (source, dev config, `node_modules`) is still present in the
> checkout, so if the webserver serves the whole repo folder, the raw
> TypeScript source under `app/src` is technically reachable as plain text.
> It is never *executed* as a module by the deployed app (the deployed
> `index.html` only references the built `assets/*.js`), so this is not a
> functional issue — just something to be aware of if source privacy
> matters to you.
| Variable | Used by | Meaning |
| --- | --- | --- |
| `HERMES_TARGET` | `serve` | API server base URL to proxy to |
@@ -154,29 +187,35 @@ Then on the config screen enter your **API server URL** and **API key**.
- **Response shapes.** The Sessions REST API's exact JSON envelope isn't fully
documented, so the client normalises several shapes (`sessions`/`data`/`items`,
`id`/`session_id`, string/array content). If a field looks off on your version,
it's a one-line tweak in `src/api/client.ts`.
it's a one-line tweak in `app/src/api/client.ts`.
## Project layout
```
src/
api/
client.ts # HermesClient: bearer auth, sessions REST, SSE chat
types.ts # API server types + normalised UI types
hooks/
useSpeechRecognition.ts # browser dictation
useTts.ts # browser speech synthesis
lib/
config.ts # saved connections (localStorage)
format.ts # time / token formatting
markdown.tsx # tiny safe markdown renderer
state/
store.ts # zustand store: connections, sessions, streaming
components/ # ConfigScreen, ConnectionForm, Sidebar, ChatView, Composer, …
server/
proxy.mjs # optional static host + /api,/v1 reverse proxy (no deps)
scripts/
gen-icons.mjs # dependency-free PNG icon generator
index.html, assets/, manifest.webmanifest, # repo root = deployed build
sw.js, workbox-*.js, favicon.svg, icons/, # output (see Deployment model above)
LICENSE
app/ # Vite project (source, dev config)
index.html # dev entry (-> /src/main.tsx); NOT served in production
src/
api/
client.ts # HermesClient: bearer auth, sessions REST, SSE chat
types.ts # API server types + normalised UI types
hooks/
useSpeechRecognition.ts # browser dictation
useTts.ts # browser speech synthesis
lib/
config.ts # saved connections (localStorage)
format.ts # time / token formatting
markdown.tsx # tiny safe markdown renderer
state/
store.ts # zustand store: connections, sessions, streaming
components/ # ConfigScreen, ConnectionForm, Sidebar, ChatView, Composer, …
scripts/
gen-icons.mjs # dependency-free PNG icon generator
deploy.mjs # copies app/dist/* into the repo root after `vite build`
server/
proxy.mjs # optional static host + /api,/v1 reverse proxy (no deps)
```
## License