Bump to v0.22.0 (no man's land, #16 P3) + AGENTS.md/CHANGELOG
CI / build + unit + e2e (pull_request) Successful in 1m33s
CI / build + unit + e2e (pull_request) Successful in 1m33s
This commit is contained in:
@@ -52,7 +52,7 @@ history/
|
||||
├── eslint.config.js # flat config (ESLint 9)
|
||||
├── tsconfig.json # strict; aliases @/ → src/, @shared/ → shared/
|
||||
├── vite.config.ts # dev server + proxy /api,/sse → :4321; @ / @shared aliases
|
||||
├── vitest.config.ts # unit tests (server/**/*.test.ts + scripts/**/*.test.ts; 105 tests)
|
||||
├── vitest.config.ts # unit tests (server/**/*.test.ts + scripts/**/*.test.ts; 127 tests)
|
||||
├── playwright.config.ts # deterministic e2e (webServer runs npm run dev, LLM_STUB=1)
|
||||
├── index.html
|
||||
├── presets/ # 5 scenario JSON files + index.json (manifest)
|
||||
@@ -67,10 +67,10 @@ history/
|
||||
│ └── *.test.ts # turf-free vitest tests pinning the dataset + both manifests
|
||||
├── shared/ # NO runtime deps — the single source of truth
|
||||
│ ├── types.ts # domain types (Nation, GameState, RoundItem, Preset, …)
|
||||
│ └── protocol.ts # LLM TurnResult schema + AddAction/AddDiplomacy/RemoveQueueItem/Jump request types + pure helpers
|
||||
│ └── protocol.ts # LLM TurnResult schema (incl. `unowned`, v0.22 #16 P3) + AddAction/AddDiplomacy/RemoveQueueItem/Jump request types + pure helpers (incl. the no-man's-land map-presentation contract)
|
||||
├── server/
|
||||
│ ├── index.ts # Express: /api/* (health|action|diplomacy|queue/remove|jump|advisor|games|map|presets), /sse/:id; reads PORT/LLM_*/DATA_DIR
|
||||
│ ├── engine.ts # pure: prompts / parse+validate / applyTurnResult (sole-ownership) / runTurn (tool path + plain fallback) / getNeighbours tool + executor / playerFrontier / queue ops / advisor
|
||||
│ ├── engine.ts # pure: prompts / parse+validate / applyTurnResult (sole-ownership + no-man's-land releases, v0.22 #16 P3) / runTurn (tool path + plain fallback) / getNeighbours tool + executor / playerFrontier / queue ops / advisor
|
||||
│ ├── llm.ts # LlmClient: chat() + chatWithTools() (bounded function-calling loop), injectable transport, retry+backoff, logging + env config
|
||||
│ ├── regions.ts # turf-free region-key data access: load manifest/geo/adjacency (public/ then dist/), country→keys expansion, reference table, neighboursOf/hasAdjacency
|
||||
│ ├── stub.ts # deterministic LLM transport (tests/e2e): one frontier conquest per turn + ADVISOR_MARKER
|
||||
@@ -105,7 +105,7 @@ history/
|
||||
| `npm run dev` | Express on :4321 (tsx watch) + Vite on :5173 (proxies `/api`,`/sse`) concurrently |
|
||||
| `npm run build` | `vite build` (client → `dist/`) then `tsup server/index.ts` → `server/dist/index.js` |
|
||||
| `npm start` | run the compiled server (`node server/dist/index.js`) on :4321 |
|
||||
| `npm test` | vitest unit tests (`server/` + `scripts/`; 105 tests) |
|
||||
| `npm test` | vitest unit tests (`server/` + `scripts/`; 127 tests) |
|
||||
| `npm run typecheck` | `tsc --noEmit` (strict) across src/server/shared/e2e/configs |
|
||||
| `npm run lint` | ESLint flat config |
|
||||
| `npm run e2e` | Playwright, fully deterministic (`LLM_STUB=1`); **runs in CI on every PR** (see below) |
|
||||
@@ -171,7 +171,19 @@ history/
|
||||
transfer; the user payload carries the player's `frontier` (the sorted other-nation keys bordering
|
||||
the player's territory, via `playerFrontier`). The tool path degrades gracefully: without the
|
||||
adjacency manifest (or with a client lacking `chatWithTools`), a turn runs the legacy plain
|
||||
`chat()` path and the tool/frontier simply switch off.
|
||||
`chat()` path and the tool/frontier simply switch off. Since v0.22 (#16 P3) a key may also end
|
||||
a turn **unowned** — "no man's land": `TurnResult.unowned` lists keys released this turn;
|
||||
`applyTurnResult` applies releases FIRST (a key leaves its sole owner — only a key with exactly
|
||||
one current owner can be released; a never-assigned or corrupt key is a no-op), then claims
|
||||
against the post-release snapshot, so a `gain` on an ownerless key is a **re-claim** (granted to
|
||||
the sole gainer and removed from the cumulative `GameState.unowned` list). The user payload
|
||||
carries the current `GameState.unowned` as `unowned`, and the jump route's `regions` reference
|
||||
table includes those keys so the model can name them when re-claiming. The map renders a
|
||||
released key in the distinct visible grey (`NO_MANS_LAND_FILL` in `shared/protocol.ts`, with a
|
||||
"No man's land" tooltip sub-line) while a preset-unassigned key keeps the faint look ("No owner")
|
||||
— the distinction is decided by the client from `GameState.unowned` (via `regionFillStyle` /
|
||||
`unownedTooltipLabel`), never by the `RegionMap`, which only knows "owned" vs "absent". A fresh
|
||||
game always starts with `unowned: []` (legacy SQLite rows load with it defaulted).
|
||||
- **Map click → dossier target (owner resolved from the RegionMap, by region key).**
|
||||
Clicking a sub-region does NOT open a popup — it switches the dossier to that sub-region's
|
||||
owning nation (`focusNation(ownerId, {name})` in `App.tsx`, which also records which region was
|
||||
@@ -194,9 +206,12 @@ history/
|
||||
date advances 2 days. Since v0.21 the stub also makes **one contiguous conquest per turn**: the
|
||||
player gains `frontier[0]` (the first of the sorted `frontier` list from the prompt payload —
|
||||
stable) and that region's owner loses it; an empty frontier (no controllable border, e.g. the UK
|
||||
in `wwii-1939`) transfers nothing. The stub answers plain `content` (never tool calls), so it
|
||||
naturally bypasses the tool loop in a single round. Unit + e2e assertions rely on these exact
|
||||
values, so keep the stub deterministic.
|
||||
in `wwii-1939`) transfers nothing. Since v0.22 (#16 P3) the stub **never releases** a region to
|
||||
no man's land (it always returns `unowned: []` and ignores the payload's `unowned` field) — its
|
||||
one-conquest behavior is what the e2e assertions rely on, so the release/re-claim path is
|
||||
covered by unit tests only (`server/engine.test.ts`, `server/map.test.ts`). The stub answers
|
||||
plain `content` (never tool calls), so it naturally bypasses the tool loop in a single round.
|
||||
Unit + e2e assertions rely on these exact values, so keep the stub deterministic.
|
||||
- **HUD layout.** The game screen is a full-viewport map (z-0) with `FloatingWindow` overlays. The
|
||||
top bar is **pinned** — a fixed, non-movable bar centered at the top a few px down (it re-centers
|
||||
on resize and always floats above the other windows). The **dossier / event-feed / action**
|
||||
|
||||
Reference in New Issue
Block a user