Commit Graph
31 Commits
Author SHA1 Message Date
parththakkar106andClaude Opus 4.8 4dac445f90 Add Phase 12: native RPG world state
Structured world/player/NPC stats, two-way flags, and sticky milestones
per scenario (stat_schema). The AI proposes a per-turn delta; a Python
engine referees it (clamp to min/max, per-turn cap, cooldown, counters).
Band word-labels plus a fixed stat guide (descriptions + full ranges)
keep the model grounded. World State drawer + Insights delta report;
undo/retry roll it back via the Phase 11 snapshot pattern.

- migrations 26-28 (scenarios.stat_schema, adventures.world_state,
  actions.world_state_before); all nullable, additive, safe on existing rows
- migration 29 raises the default context budget 4096 -> 16384
  (custom values preserved)
- seeded demo scenario 04-rpg-world-state.json (Bandit Camp)
- 19 new tests (33 total pass)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 14:47:29 +05:30
parththakkar106andClaude Opus 4.8 64356414b1 Add requirements-dev.txt (pytest) for the test suite
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 03:00:38 +05:30
parththakkar106andClaude Opus 4.8 dab1807118 Roll back script_state on undo/retry; fix retry double-apply
The shared per-adventure script_state ("scoreboard" scripts write to) was
never reverted by undo, and retry re-ran the output hook on top of the already-
mutated state, double-applying its changes (e.g. "+10 gold" became +20).

Each action now snapshots script_state as it was immediately before its own
hooks ran (new Action.state_before column, migration 25):
- undo restores the turn's first-action snapshot, prunes memories that
  summarized the removed actions, and takes the turn lock against races.
- retry restores the AI action's snapshot before regenerating.

Story-card mutations are not reverted (documented limit). Adds the project's
first test suite: unit + full HTTP integration through the real scripting
engine (14 tests). See plan/11-state-revert-and-retry-fix.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 02:58:38 +05:30
parththakkar106andClaude Opus 4.8 92044a53c4 Make the action input auto-grow up to ~4 lines
Swap the single-line action <input> for a <textarea> that grows with its
content (capped at ~4 lines, then scrolls) and shrinks back after send.
Enter still sends; Shift+Enter inserts a newline. Buttons stay bottom-aligned
as it grows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-21 01:41:00 +05:30
parththakkar106andClaude Opus 4.8 8a1650c0d4 Collapse nested state trees by default, keep top level expanded
Only depth 0 opens automatically; deeper objects/arrays start collapsed
and expand on click, so deep state stays readable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-21 01:23:59 +05:30
parththakkar106andClaude Opus 4.8 e74566c5d4 Render script state as a nested tree, not a flat JSON blob
The State drawer stringified non-string values with JSON.stringify, so
nested objects/arrays showed as raw JSON. Add a recursive StateValue /
StateTree renderer: primitives are typed and coloured, objects/arrays are
collapsible and indented so deep state shows its structure.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-21 01:22:33 +05:30
parththakkar106andClaude Opus 4.8 2953cd70ed Show a friendly message on 429 instead of raw JSON
Map HTTP 429 in _friendly_http_error: OpenRouter's free-models-per-day cap
gets a "daily limit, resets 00:00 UTC" message; other rate limits get a
generic "too many requests, try again" note. Avoids leaking the raw error
JSON (incl. user_id) to players.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-21 01:01:29 +05:30
parththakkar106andClaude Opus 4.8 328ae8942d Add per-adventure "Sync from library" for scripts
Adventure scripts are frozen snapshots taken at creation. Add an opt-in
way to pull the latest library code into a live adventure:

- AdventureScript.source_script_id links a copy to its library Script
  (migration 24; set at adventure creation)
- list endpoint flags out_of_date by diffing copy vs library
- POST /adventures/{id}/scripts/{sid}/sync overwrites the copy's code,
  preserving enabled/position/script_state
- legacy copies with no link fall back to a name match, then adopt the link
- Play page shows a Sync button only when a copy differs from its library

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-21 00:56:01 +05:30
parththakkar106andClaude Opus 4.8 94db6e055b Add power-user email allowlist to bypass demo turn cap
Trusted testers listed in AIDND_POWER_USERS get unmetered turns on the
shared demo key: demo_turns_left reports the full cap and count_demo_turn
skips them. Registered accounts only, matched case-insensitively.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-21 00:21:30 +05:30
parththakkar106andClaude Opus 4.8 36413acd3e Add Download button to in-play Scripts panel
Each script in the panel can now be downloaded as an import-compatible
JSON bundle (matching the /scripts export format), so demo/server-owned
scripts can be forked into a user's own library via the Scripts page's
Import.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-20 19:30:13 +05:30
parththakkar106andClaude Opus 4.8 73f43efbe7 Let the in-play Scripts panel show each script's code
The panel only showed a name + on/off toggle, so demo (server-owned)
scripts — which never appear on the personal Scripts page — had no
in-app way to inspect their code. AdventureScriptOut already ships the
hook sources, so add a "View code" expander that renders the non-empty
hooks (library / onInput / onModelContext / onOutput) read-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-20 19:11:39 +05:30
parththakkar106andClaude Opus 4.8 2fc167327d Fix HP demo: emit tag on first line; seeder reconciles demos in place
The reasoning model truncated replies before the end-of-reply [HP-N]
tag, so damage was never reported and HP stuck at 100. Move the tag to
the FIRST line of the reply so it survives truncation, and clarify the
wording (concrete example numbers instead of the literal "[HP-N]" that
confused the model).

Also make the seeder the source of truth for demo content: it now
reconciles an existing seeded scenario in place when a seed file
changes (keeping the scenario row and its adventure FKs), instead of
only inserting when missing — otherwise fixes to already-seeded demos
never reach production. No-op when content already matches, so it stays
cheap on every boot.

Verified end-to-end through the quickjs engine, including a truncated
reply still applying damage, and the in-place update path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-20 19:02:41 +05:30
parththakkar106andClaude Opus 4.8 ff09254878 Seed HP-system demo scenario (AI-driven, script-tracked health)
Adds "[Demo] The Goblin Ambush (HP script)": a combat scene whose script
tells the AI the current HP and to tag damage/healing as [HP-N]/[HP+N];
the AI decides the amounts, the onOutput hook applies them to state.hp
(clamped 0..100), hides the tags, and flags death at 0. Showcases the
new left State drawer with live variables. Verified through the real
quickjs engine: a simulated attack drops HP, a potion heals (clamped),
a fatal blow sets state.dead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-20 18:07:10 +05:30
parththakkar106andClaude Opus 4.8 f067ddb766 Add collapsible left "Script State" drawer on the play screen
Exposes the scripting `state` object (every variable scripts read/write
via state.x, persisted per-adventure) in a collapsible left rail that
refreshes after each turn. New owner-scoped GET
/api/adventures/{id}/script-state endpoint; the drawer only fetches
while open and shows an empty-state hint until a script sets a variable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-20 17:59:16 +05:30
parththakkar106andClaude Opus 4.8 fdb13a2c19 Bulk import/export of story cards (AI Dungeon world-info format)
Add GET /api/story-cards/export and POST /api/story-cards/import for a
scenario or adventure, using the AI Dungeon world-info array shape
(keys/value/type/title/description/useForCharacterCreation) mapped to our
columns. Import accepts a bare array or {cards|storyCards|worldInfo:[...]},
enforces the per-owner cap (existing + incoming) and import rate limit.
Export/Import buttons added to the scenario editor and the in-play Plot
panel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-20 17:25:00 +05:30
parththakkar106andClaude Opus 4.8 82fb6c8535 Reasoning-model UX: better empty-response error, higher default budget, live link
- When a model streams reasoning but no story text, return a specific,
  actionable error (raise Max output tokens / set a reasoning cap / use a
  non-reasoning model) instead of the opaque "empty response".
- Bump default max_output_tokens 400 -> 800: 400 truncated scenes and
  left reasoning models with no room after thinking. Affects new settings
  rows; existing users keep their value.
- README: add a "Try it live" link to the Render deployment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-20 17:05:29 +05:30
parththakkar106andClaude Opus 4.8 8188ed3999 Play screen UX: sticky header + fix streaming autoscroll
- Pin the play header (Plot/Memory/Scripts/Insights toggles) just below
  the top nav so they stay reachable without scrolling back up to the
  first message.
- Fix streaming autoscroll: snap to the real document bottom instantly
  instead of smooth-scrolling to storyEndRef. That ref sits above the
  sticky composer, so block:'end' stopped short — hiding the latest line
  behind the input bar and yanking the reader back up when they scrolled
  down. Smooth behavior also never settled at per-token speed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-20 16:57:16 +05:30
parththakkar106andClaude Opus 4.8 0971d3feda Fix adventures list 500 on Postgres (GROUP BY)
list_adventures selected Scenario.title while grouping only by
Adventure.id. SQLite tolerates selecting an ungrouped column, so it
worked locally, but Postgres (Neon) rejects it — the adventures list
endpoint 500'd on the live deploy, so saved adventures could not be
listed or resumed. Add Scenario.title to the GROUP BY.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-20 16:41:51 +05:30
parththakkar106andClaude Opus 4.8 c96b8cdf2f Seed public demo scenarios on startup
Idempotent seeder inserts public, unowned demo scenarios from
backend/app/seed_data/*.json if a public scenario with the same title
is missing, so a fresh Neon database (and any clone) gets demo content
guests can play immediately. Ships two scenarios: the Sunken Crypt of
Vharos (all four script hooks) and Signal from the Derelict (sci-fi,
context-engine focused).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEpWMjnfPqzZ13nPMoGhs5
2026-07-20 16:17:57 +05:30
parththakkar106andClaude Opus 4.8 68c165585c Phase 10: Render deploy blueprint
- render.yaml: single Docker web service (SPA + API same-origin), free tier,
  Neon Postgres via AIDND_DATABASE_URL, generated AIDND_SECRET_KEY,
  /api/health check, us-east region, auto-deploy on main.
- README: "Deploy (Render)" section.
- Record verified Postgres path (real Neon, PG 18.4) and Phase 10 decisions
  (Neon, free tier, cloud Docker build) in plan/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017e6tQuojBLYPetUfmhit4X
2026-07-07 14:07:08 +05:30
parththakkar106andClaude Opus 4.8 4772171b6c Phase 9: production hardening
Config via env, abuse/resource limits, and production serving so the app
is safe to expose publicly:

- Fail-fast on missing SECRET_KEY when MULTI_USER=true
- quickjs per-execution time/memory limits (while(true) can't hang server)
- Per-user/per-IP rate limiting on turn/script/auth endpoints
- Request body size limit + per-user row caps
- Security headers (CSP, X-Frame-Options, nosniff, referrer-policy) incl. SSE
- Debug router 403 and /docs disabled in multi-user mode
- DATABASE_URL support (defaults to Neon Postgres) alongside SQLite
- Documented all env vars in backend/.env.example

Verified locally via uvicorn (MULTI_USER=1, SQLite); see plan/09-phase-hardening.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017e6tQuojBLYPetUfmhit4X
2026-07-07 12:30:06 +05:30
parththakkar106andClaude Fable 5 de4db373f2 Phase 8: optional accounts, per-user data, shared demo key
Guest-first multi-user mode behind AIDND_MULTI_USER (local installs
unchanged): signed-cookie guest sessions bootstrapped by /api/auth/me,
register upgrades the guest in place, login/logout, per-IP rate limits.
Every router scoped by user_id; Settings become per-user with the API
key Fernet-encrypted at rest and write-only through the API. Users
without a key get a server-funded demo key (OpenRouter free models,
20 turns/day, memory bank disabled on demo turns). Public read-only
demo scenarios (seed_demo.py); debug log restricted to local mode.
Frontend: auth modal + guest nudge, 401 re-establish/retry, demo
banner and key management in Settings.

Migrations 13-23 adopt existing data under a local user and encrypt
stored keys. Verified: migration on a copy of real data.db, two-session
isolation + register/login via curl and Chrome, demo cap 429, live
OpenRouter turn through the encrypted-key path, vite build + oxlint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFsGHju9szibJJa2YJcdbg
2026-07-06 23:04:03 +05:30
parththakkar106andClaude Fable 5 253b533d3b Fix remaining code-review findings (15 bugs; #11 skipped as AID-compatible)
Backend:
- provider: fall back to parsing a plain JSON body when a server ignores
  stream=true (was: silent empty turn); error if response has no text (#5)
- memorybank: clamp cursors after undo/retry shrinks the action list, and
  translate summary_cursor (list position) to an Action.index boundary
  before comparing with Memory.source_end (#7)
- memorybank: pinned memories now count toward the top_k budget (#8)
- memorybank: cosine() returns 0.0 on dimension mismatch; changing the
  embedding model clears stored vectors so they re-embed (#9)
- scripting: MAX_STORY_CARDS cap now counts cards inserted during the
  hook, so a script can't add unbounded cards in one turn (#10)
- settings: /test tolerates non-dict JSON from /models (#13)
- scenarios: import accepts worldInformation as a story-card source (#14)

Frontend:
- per-key debounce timers in PlotPanel and ScenarioEditor — editing two
  things within 600ms no longer drops the first save (#15, #16)
- Continue button no longer discards typed input (#17)
- failed retry resyncs actions from the server instead of leaving the
  removed action missing (#18)
- Settings save/test surface errors instead of hanging on Testing… (#19)
- InsightsPanel ignores stale responses from superseded requests (#20)
- placeholder scan includes story-card trigger keys (#21)

addStoryCard returning the 0-based index (falsy for the first card) matches
real AI Dungeon per the scripting guidebook — kept, documented (#11).
Statuses updated in CODE_REVIEW_FINDINGS.md; stale entries for previously
fixed items (#1-4, #6, #12) corrected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFsGHju9szibJJa2YJcdbg
2026-07-06 17:23:12 +05:30
parththakkar106andClaude Fable 5 3ee653a631 Plan: record successful Docker test (WSL2)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFsGHju9szibJJa2YJcdbg
2026-07-06 17:06:49 +05:30
parththakkar106andClaude Fable 5 3fb2fe1a9e Regenerate package-lock.json with npm 11.18
npm 11.6 failed to record top-level entries for @emnapi/core and
@emnapi/runtime (optional deps of @napi-rs/wasm-runtime), which made
'npm ci' fail on any other machine.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFsGHju9szibJJa2YJcdbg
2026-07-06 17:03:42 +05:30
parththakkar106andClaude Fable 5 b711b573b5 Dockerfile: node 24 to match the npm 11 lockfile
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFsGHju9szibJJa2YJcdbg
2026-07-06 17:00:43 +05:30
parththakkar106andClaude Fable 5 855cc899ed Mark start.sh executable
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFsGHju9szibJJa2YJcdbg
2026-07-06 16:58:13 +05:30
parththakkar106andClaude Fable 5 526f502eb6 Add .gitattributes: keep shell scripts LF on Windows checkouts
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFsGHju9szibJJa2YJcdbg
2026-07-06 16:52:13 +05:30
parththakkar106andClaude Fable 5 22630c8411 Phase 7: MIT license, portfolio README, Docker, cross-platform start
- LICENSE: MIT
- README: rewritten as portfolio-grade docs (features with code pointers,
  architecture, Docker/Windows/macOS quick starts, BYO-model table)
- Dockerfile (3-stage: SPA build, pip wheels, slim runtime) + compose with
  a /data volume; .dockerignore keeps secrets and local data out
- database.py: AIDND_DB_PATH env override so deployments can relocate the
  SQLite file; documented in backend/.env.example
- start.sh: macOS/Linux dev script with first-run setup

Verified locally: production SPA build served by the backend (deep links
OK), DB created at the override path. Docker image itself untested here
(Docker not installed); flagged in plan/07.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFsGHju9szibJJa2YJcdbg
2026-07-06 16:51:48 +05:30
parththakkar106andClaude Fable 5 466d7bc0e4 Add public-release plan (phases 7-10)
Phases: public repo & Docker (7), guest-first optional accounts (8),
production hardening (9), Render deploy (10). Confirmed decisions and
per-phase open questions recorded in each file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFsGHju9szibJJa2YJcdbg
2026-07-06 16:48:13 +05:30
parththakkar106andClaude Fable 5 db9f904222 Initial commit: AI Dungeon clone (FastAPI backend + React frontend)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFsGHju9szibJJa2YJcdbg
2026-07-06 16:08:19 +05:30