213 lines
9.0 KiB
Markdown
213 lines
9.0 KiB
Markdown
# AGENTS.md
|
|
|
|
Guidance for AI coding agents working in this repository.
|
|
|
|
## Project
|
|
|
|
Next.js frontend for a Paradox save file parser. It uploads a game save file to a
|
|
backend service, polls until parsing finishes, and displays the result in a
|
|
grid.
|
|
|
|
- **Next.js 16** (App Router, Turbopack) with **React 19**
|
|
- **TypeScript 6 and 7** side by side (see "Things that will bite you"),
|
|
**ESLint 9** (flat config), **Prettier 3**
|
|
- **ag-grid** for the data grid, **Bootstrap 5** for styling
|
|
|
|
Source files live in `src/`:
|
|
|
|
- `app/` for routes,
|
|
- `components/` for shared UI
|
|
- `services/` for backend calls
|
|
- `lib/` for helpers
|
|
- `config/` for app config
|
|
- `types/` for .d.ts type declaration files
|
|
|
|
## Architecture
|
|
|
|
The parsing backend is a **separate service in its own repository**, not part
|
|
of this project. Start it manually before running the frontend; it is expected
|
|
at `http://127.0.0.1:5226`.
|
|
|
|
The browser never calls that backend directly. Requests go through a Next route
|
|
handler that forwards them:
|
|
|
|
```
|
|
SaveParserBackendService -> /api/proxy/saveParserBackend/* -> backend
|
|
(client, fetch) (server, route handler)
|
|
```
|
|
|
|
- [src/services/SaveParserBackendService.ts](src/services/SaveParserBackendService.ts)
|
|
is the only place that talks to the backend. It exposes `uploadSave`,
|
|
`getSaveStatus` and `getParsedSave` — upload, poll until parsing finishes,
|
|
then fetch the result.
|
|
- [src/app/api/proxy/saveParserBackend/[[...path]]/route.ts](src/app/api/proxy/saveParserBackend/[[...path]]/route.ts)
|
|
forwards every method to the configured backend URL. It exists only to keep
|
|
requests same-origin, and is meant to be deleted once the backend handles
|
|
CORS itself.
|
|
- Route paths live in [src/app/api/proxy/paths.ts](src/app/api/proxy/paths.ts)
|
|
rather than as string literals, so both sides of the proxy stay in sync.
|
|
|
|
Configuration comes from [src/config/AppConfig.ts](src/config/AppConfig.ts)
|
|
(defaults) merged with `runtimeConfig.json` at the repo root, which holds the
|
|
backend URL. That file is gitignored, so a fresh clone starts without one and
|
|
falls back to the defaults.
|
|
|
|
### Current status
|
|
|
|
Much of the app is still scaffold. Do not assume a feature works because the UI
|
|
for it exists:
|
|
|
|
- **The grid is not wired up.** [src/app/browse/page.tsx](src/app/browse/page.tsx)
|
|
renders two hardcoded rows and never calls the backend. Nothing connects the
|
|
upload flow to it yet.
|
|
- **Auth does not work.** `AuthService` posts to `/api/auth/login` and
|
|
`/api/auth/register`, which do not exist as routes. The service is slated for
|
|
removal in favour of Discord OAuth.
|
|
- **`hashPassword` is a no-op** that returns the password unchanged. Treat any
|
|
current auth code as a placeholder, not as something to build on.
|
|
|
|
## Terminal
|
|
|
|
**On Windows, prefer `bash.exe`** — but only a real MSYS2, Cygwin, or
|
|
MinGW/Git Bash installation, for example `D:\msys2\usr\bin\bash.exe`.
|
|
|
|
**Never use `C:\Windows\System32\bash.exe`.** Despite its name it is not a
|
|
POSIX bash; it is the launcher stub for WSL. Do not start WSL to run ordinary
|
|
commands.
|
|
|
|
If no MSYS/Cygwin/MinGW bash is installed, **use PowerShell** as the terminal.
|
|
PowerShell is the fallback, never WSL.
|
|
|
|
If bash reports `command not found` for `node` or `npm`, that is a `PATH`
|
|
problem rather than a missing install: MSYS2 defaults `MSYS2_PATH_TYPE` to
|
|
`minimal`, which discards the Windows `PATH`. Setting it to `inherit` fixes it.
|
|
|
|
## Commands
|
|
|
|
```sh
|
|
npm run dev # dev server
|
|
npm run build # production build
|
|
npm run lint # eslint
|
|
npm run format # prettier, rewrites everything except .gitignore/.prettierignore
|
|
npx tsc --noEmit # typecheck
|
|
```
|
|
|
|
### Checking your work
|
|
|
|
**Always run `npm run lint` and `npm run build` after changing code.** They are
|
|
the primary way to find errors in this project, and they catch different
|
|
things:
|
|
|
|
- `npm run lint` reports code errors and style violations. It must finish with
|
|
zero problems — no errors and no warnings.
|
|
- `npm run build` catches type errors and build-time problems that lint cannot
|
|
see, such as Node APIs leaking into the edge runtime. It must exit cleanly
|
|
and print no warnings.
|
|
|
|
`npx tsc --noEmit` is a faster way to check types alone while iterating, but it
|
|
does not replace a full build.
|
|
|
|
Do not report a change as finished until both commands pass.
|
|
|
|
## Version control
|
|
|
|
This project is managed with **git**.
|
|
|
|
**Read-only git commands are fine to use without asking.**
|
|
`git status`, `git log`, `git diff`, `git show`, `git blame` and similar inspection commands
|
|
may be run freely.
|
|
|
|
**Never run a git command that changes the repository without the user's
|
|
explicit permission.**
|
|
This is a strict ban, and it covers everything that writes to the history, the index,
|
|
or the working tree including `add`, `commit`, `checkout`, `restore`, `reset`,
|
|
`stash`, `branch`, `merge`, `rebase`, `push`, `rm`, etc.
|
|
|
|
Ask first and wait for a clear yes before running such git command.
|
|
|
|
## Conventions
|
|
|
|
Prettier settings live in `.prettierrc` and are not negotiable: **4 spaces, no
|
|
semicolons, single quotes, 80 column width**. Run `npm run format` after
|
|
editing, or match the surrounding style exactly.
|
|
|
|
Import from within `src/` using the `@/` alias, for example
|
|
`import { getMsgFromError } from '@/lib/errors'`.
|
|
|
|
Write doc comments as JSDoc (`/** ... */`), which editors show on hover.
|
|
Plain `//` and `///` comments do not appear in tooltips.
|
|
In `.ts` files put only prose in the JSDoc and let the signature carry the types;
|
|
do not duplicate types in `{braces}`.
|
|
|
|
Catch blocks should not annotate the error. Let it be `unknown` and convert it
|
|
with the shared helper:
|
|
|
|
```ts
|
|
} catch (err) {
|
|
const errMsg = getMsgFromError(err)
|
|
...
|
|
}
|
|
```
|
|
|
|
Avoid `any`; `no-explicit-any` is enforced. Prefer `unknown` plus narrowing.
|
|
|
|
## Things that will bite you
|
|
|
|
**Both TypeScript 6 and 7 are installed on purpose, under swapped names.**
|
|
TypeScript 7 is the native Go compiler and type-checks much faster, but
|
|
typescript-eslint refuses to run under it, which would break `npm run lint`
|
|
entirely. So each tool gets the version it can use:
|
|
|
|
| package.json entry | resolves to | used by |
|
|
| -------------------- | ------------------------------------------------ | ----------------- |
|
|
| `typescript` | `@typescript/typescript6` (TS 6 API, bin `tsc6`) | typescript-eslint |
|
|
| `@typescript/native` | `typescript@7` (Go compiler) | `next build` |
|
|
|
|
The alias is deliberately reversed: typescript-eslint looks the compiler up by
|
|
the package _name_ `typescript`, so that name must stay on TS 6. Do not "fix"
|
|
this by renaming the entries.
|
|
|
|
`next.config.ts` sets `experimental.useTypeScriptCli`, which makes Next spawn a
|
|
`tsc` binary instead of using the compiler API. Next resolves that binary from
|
|
the package named `typescript` too, so it would also get TS 6. The `prebuild`
|
|
script [scripts/replace-tsc6-with-tsc7.mjs](scripts/replace-tsc6-with-tsc7.mjs)
|
|
works around this by rewriting `node_modules/typescript/bin/tsc6` into a
|
|
one-line stub that imports TS 7's `lib/tsc.js`.
|
|
|
|
Consequences to keep in mind:
|
|
|
|
- The patch lives in `node_modules`, so `npm install` undoes it. `prebuild`
|
|
reapplies it, so `npm run build` is always correct; nothing else needs doing.
|
|
- `npx tsc --noEmit` is unaffected either way. `node_modules/.bin/tsc` links
|
|
straight to `@typescript/native`, so the standalone typecheck is always TS 7.
|
|
- Do not drop the `prebuild` script while leaving `useTypeScriptCli` enabled.
|
|
Nothing breaks visibly — the build just silently goes back to type-checking
|
|
with TS 6.
|
|
|
|
**All of this is temporary.** The only reason TS 6 is still here is that
|
|
TypeScript 7.0 ships no stable programmatic JS API, so typescript-eslint cannot
|
|
run on it. That API arrives in **TypeScript 7.1, planned for 2026-11-24**. Once
|
|
it is out and typescript-eslint supports it, tear the whole arrangement down:
|
|
drop `@typescript/native` and the `@typescript/typescript6` alias for a plain
|
|
`"typescript": "^7.1"`, delete `scripts/replace-tsc6-with-tsc7.mjs` and the
|
|
`prebuild` script, and re-check whether `useTypeScriptCli` is still worth
|
|
keeping.
|
|
|
|
**Env vars in npm scripts must go through `cross-env`.** The `dev` and `build`
|
|
scripts set `NEXT_TELEMETRY_DISABLED=1`, which stops Next from collecting
|
|
anonymous usage data and saves the ~0.5s the telemetry flush adds to every
|
|
build. The `FOO=1 cmd` prefix is POSIX shell syntax, and on Windows npm runs
|
|
scripts through `cmd`, where it is a syntax error — so the prefix is written as
|
|
`cross-env NEXT_TELEMETRY_DISABLED=1 next ...` instead. Keep `cross-env` on any
|
|
new script that needs an env var.
|
|
|
|
Setting the variable from `prebuild` would not work: `prebuild` and `build` are
|
|
sibling processes, so an env var exported by one is not visible to the other.
|
|
Each script that needs it sets it itself. `prebuild` has no `cross-env` prefix
|
|
because it only rewrites the tsc bin and never talks to telemetry.
|
|
|
|
**`instrumentation.ts` is compiled for the edge runtime too and it can't be disabled.**
|
|
Anything using `fs`, `path`, or other Node APIs must be imported behind the
|
|
`process.env.NEXT_RUNTIME === 'nodejs'` guard, or the build warns and pulls
|
|
Node-only code into the edge bundle.
|