Commit graph

4 commits

Author SHA1 Message Date
Parfii-bot
dc196dc325 feat(wave21): Live2D renderer ported from AIRI — Haru model bundled
Some checks failed
Release / Build aarch64-apple-darwin (push) Has been cancelled
Release / Build x86_64-apple-darwin (push) Has been cancelled
Release / Build aarch64-unknown-linux-gnu (push) Has been cancelled
Release / Build x86_64-unknown-linux-gnu (push) Has been cancelled
Release / Build mcp-server darwin-arm64 (push) Has been cancelled
Release / Build mcp-server linux-arm64 (push) Has been cancelled
Release / Build mcp-server darwin-x64 (push) Has been cancelled
Release / Build mcp-server linux-x64 (push) Has been cancelled
Release / Build mcp-server windows-x64 (push) Has been cancelled
Release / Publish GitHub Release (push) Has been cancelled
Release / Publish npm packages (optional) (push) Has been cancelled
cortex-ui gains a Live2D anime-character renderer alongside existing
32px pixel sprites. User chooses via Setup; switch stored in localStorage
(pet.toml `meta.renderer` field will be wired to daemon in Wave 22).

## Ports from AIRI (MIT, attribution in each file header)

- `src/lib/live2d/emotions.ts` (72 LOC) — 9-value Emotion enum + motion
  name + VRM expression maps. Copy-verbatim + CortexMood→Emotion adapter.
- `src/lib/live2d/motion-manager.ts` (194 LOC) — motion state machine
  (Vue composable → Svelte 5 factory). Named-group preference, fallback
  on throw, replay, reset.
- `src/lib/live2d/expression-controller.ts` (180 LOC) — expression blend
  math + transition reset.
- `src/lib/live2d/beat-sync.ts` (63 LOC) — audio-reactive STUB; full
  port deferred to Wave 22.
- `src/lib/live2d/types.ts` (62 LOC) — shared interfaces.

## New component

- `src/components/Live2DPet.svelte` (169 LOC) — wraps pixi-live2d-display.
  Props `{ modelPath, mood, width, height }`. Fallback message in jsdom
  (no WebGL) — tests mount without throwing.

## PetEditor + Setup integration

- `PetEditor.svelte` reads `pet.toml` `meta.renderer` → localStorage
  fallback → defaults `sprite32`. Toggle button swaps renderer mid-session.
- `Setup.svelte` adds Renderer radio (sprite32 / live2d), persists to
  localStorage.

## Model bundled

Haru (`haru_greeter_t03`), Live2D Cubism official sample, free sample
data license with attribution. 3.4 MB on disk (384 KB moc3 + 2.7 MB
textures + 8 expressions + 5 motions). Served at
`./live2d-models/haru/haru_greeter_t03.model3.json`.

## Deps

- Added `pixi.js ^7.4.0` + `pixi-live2d-display ^0.4.0` to
  _ts_packages/packages/cortex-ui/package.json
- AIRI's `pixi-live2d-display.patch` copied to patches/ with README
  (manual apply, not needed for default model path)
- **Known risk**: pixi 7 vs library peer-dep 6 mismatch — silent at
  install time, untested at runtime. Fallback path: downgrade to pixi ^6
  OR swap to `pixi-live2d-display-lipsyncpatch`. Will validate during
  live browser test; fix in Wave 22 if breaks.

## Tests

30 pass / 0 fail (was 10):
- live2d-emotions.test.ts (6 new)
- live2d-motion-manager.test.ts (6 new)
- live2d-expression-controller.test.ts (5 new)
- live2d-pet-mount.test.ts (3 new)
- pre-existing api + config tests unchanged (10)

## Bundle size

- Main JS: 56 KB (22 KB gzip) — SPA shell unchanged
- pixi.js: 428 KB (129 KB gzip) — code-split, lazy-loaded on `live2d` pick
- pixi-live2d-display + Cubism4: 308 KB (82 KB gzip) — code-split too
- Haru model assets: 3.4 MB public/, served on-demand
- dist total: 7.5 MB with sourcemaps

## Constructor Pattern

All source files ≤194 LOC (motion-manager largest). All leaf fns ≤18
LOC. Factory-composer pattern avoids Vue's Composition API wrapping
(no mixins, no DI).

## Svelte 5 config touch

- `vite.config.ts` adds `resolve.conditions: ['browser']` +
  `server.deps.inline` for vitest — Svelte 5 runes resolve to client
  entry under jsdom correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 04:05:47 +08:00
Parfii-bot
a42847063f feat(cortex-ui): pet sprite render with mood switcher
Cherry-pick 7 pixel-art sprites from feat/pet-ui-v1 (PR #16) — cat
(idle/happy/think/sleep), dog-idle, owl-idle, blob-idle — into
cortex-ui public dir so the PetEditor view renders a visual pet
instead of a bare JSON dump.

## Behavior

- Species inferred from first letter of pet_name:
  - 'd*' → dog, 'o*' → owl, 'b*' → blob, else → cat (default,
    has 4 mood states)
- Mood switcher: click idle / happy / think / sleep → swaps sprite
- image-rendering: pixelated for crisp pixel-art scaling
- 32×32 native scaled to 128×128 (4x) with nearest-neighbor

## Why now

User tested the UI end-to-end, confirmed auth+CORS+whitespace fix
works, then asked for the cat. The sprite-gen commit (PR #16) is
still unmerged but sprites are sibling static assets — safe to copy
into cortex-ui without blocking on PR merge. Ownership stays with
the sprite-gen branch; cortex-ui just embeds the artefacts.

Rebuild hash: index-RLWTBoLo.js + index-BzERxlis.css.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 03:17:25 +08:00
Parfii-bot
39f95f7e04 fix(cortex-ui): strip whitespace from token; drop credentials:'include'
Live e2e test caught a paste-inserted whitespace in URL token param —
copy-paste from terminal had inserted %20%20%20 into middle of the
64-char hex token, which passed URL parsing but failed byte-level
auth::tokens_match on the daemon → 403.

Two fixes:

1. `sanitize_token()` strips ALL whitespace (spaces, tabs, newlines,
   zero-width) from token before use, applied on both URL-param and
   localStorage read paths. Defensive even against future Setup-form
   paste mishaps — Setup input itself could also be whitespace-dirty.

2. `credentials: 'include'` → `credentials: 'omit'`. Bearer auth rides
   on an explicit header; we don't need cookies. `include` triggers
   browser quirks (Safari especially) around credentialed cross-origin
   fetches that can strip or mismangle Authorization on redirects.

3. Error message now includes response body preview — `"403 Forbidden
   — {\"error\":{\"code\":\"forbidden\",\"message\":\"bearer token
   rejected\"}}"` — so the next failing setup surfaces root-cause.

Tests unchanged (10 passing). Rebuild hash: index-7ZqAoBoM.js.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 03:14:09 +08:00
Parfii-bot
6672ae48e7 feat(wave20): kei-cortex daemon + cortex-ui — local HTTP + TypeScript web UI
49 crates, 876 tests green (+17 kei-cortex + 10 cortex-ui TS, was 859).

## kei-cortex — local HTTP daemon (Rust)

Axum-based server on :9797 exposing read-only cortex state (ledger,
pet, memory) as JSON for browser UI consumption. Bearer token auth.
CORS for https://keisei.app. Binds 127.0.0.1 only.

### Endpoints

- GET  /healthz — unauthenticated liveness
- GET  /api/v1/cortex/summary — total_dnas + active_pets + recent_sessions
- GET  /api/v1/cortex/pet/:user_id — pet manifest
- POST /api/v1/cortex/pet/:user_id/interaction — log chat
- GET  /api/v1/cortex/ledger/recent?limit=N — recent agent runs
- GET  /api/v1/cortex/memory/search?user_id=X&pet_name=Y&q=... — recall

### Security

- Token at ~/.keisei/cortex.token (32-byte hex, chmod 600 atomic via
  OpenOptions mode 0o600)
- tower-http CorsLayer with configured allow_origin
- tokio::task::spawn_blocking for rusqlite reads
- All non-healthz routes protected by Bearer middleware

### Constructor Pattern

14 files, largest 137 LOC. All functions ≤30 LOC. Split: auth / config
/ error / state / routes + 5 handlers (health/summary/pet/ledger/memory).

17 tests: token roundtrip + chmod 600 (cfg unix) + 401/403/healthz +
summary shape + pet 404 + pet parse + interaction 201 + CORS preflight
+ ledger limit + empty ledger.

## cortex-ui — Svelte 5 + TypeScript + Vite

Static web app, build to dist/ (~500 KB incl sourcemaps, 64 KB minified
JS+CSS), deployable to https://keisei.app/cortex/. Connects to local
kei-cortex daemon via fetch.

### Features

- Setup wizard (first run): daemon URL + token paste, saved to
  localStorage (origin-scoped)
- Dashboard: summary cards + nav
- PetEditor: view pet.toml fields (identity/voice/edge/forbidden)
- LedgerStream: recent agent runs, auto-refresh 5s
- MemorySearch: query form + results list
- Hash-based routing (no server needed)
- Dark-mode via prefers-color-scheme
- URL-param override: ?daemon=URL&token=T for one-click setup

### Stack choice

Svelte 5 for minimal runtime (~2 KB). TypeScript strict inherits
_ts_packages/tsconfig.base.json. Vite for dev + build. vitest for unit
tests (10 passing: api header/error, config precedence/overrides).

## User flow

Non-dev:
1. Install keisei, run `kei-cortex serve`
2. Open https://keisei.app/cortex
3. Paste daemon URL + token from ~/.keisei/cortex.token
4. View dashboard, edit pet, search memory — all local data, zero cloud

Power user (self-host):
1. `cd _ts_packages/packages/cortex-ui && npm run build`
2. Serve dist/ from localhost OR deploy anywhere
3. Point to own daemon URL

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 01:50:21 +08:00