diff --git a/CHANGELOG.md b/CHANGELOG.md index d054e580..a0b3954c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,6 +125,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [ADR 0012](docs/adr/0012-local-server-connectivity-tauri-http.md) and [`docs/LOCAL-AI.md`](docs/LOCAL-AI.md). +- **Desktop Ollama/LM Studio/vLLM discovery still broken in packaged builds after #269 (#266).** + Root cause: `vite.config.ts`'s `rollupOptions.external` unconditionally externalized every + `@tauri-apps/*` package from **every** `vite build`, including the exact build Tauri's + `beforeBuildCommand` invokes to produce the `.deb`/`.msi`. Since `services/localServerHttp.ts`'s + `@tauri-apps/plugin-http` import is dynamic, this left an unresolvable bare module specifier in + the shipped desktop bundle — every caller's catch classified the resulting load failure + identically to a genuinely-down server (no CORS noise, no discovery, even with Ollama/LM Studio + running). `tauri dev` was unaffected (Vite's dev server doesn't apply `rollupOptions`), so the + regression only surfaced in packaged builds. Fixed by extracting the existing Tauri-build + detection (`resolveViteBase.ts`'s `TAURI_ENV_PLATFORM`/`TAURI_PLATFORM` check) into a shared + `isTauriBuild()` export and making the external array conditional on it; the web/PWA build is + unaffected. `localServerHttp.ts`'s `resolveFetch()` also now classifies a plugin load failure as + a distinct `LocalServerError('plugin_unavailable')` (logged), instead of folding it into + `'unreachable'`. See the 2026-07-28 update in + [ADR 0012](docs/adr/0012-local-server-connectivity-tauri-http.md). + - **Feature-catalog / slice default drift made structurally impossible.** `features/featureCatalog.ts` now covers all **22** flags (was 16) and **derives** each entry's `defaultOn` from the slice's `defaultFeatureFlagsState` instead of hand-keying it — the class of bug where the catalog said diff --git a/CLAUDE.md b/CLAUDE.md index 22d34899..c5ba180f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,15 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ### Low-End Local Hardware (Current Environment) -**ONE Bash tool call per turn.** Concurrent shells (vitest, biome, tsc, vite, pnpm build) cause OOM and pool-worker timeouts. -- ONE Bash tool call per turn. Wait for the result. Then proceed. -- NO `run_in_background` for vitest, biome, tsc, vite, or any pnpm build command. -- NO parallel Agent tool calls that each issue shell commands. -- NO multiple Bash tool calls in the same response block. -- Chain sequential steps inside ONE Bash call using `&&` if needed. -- DevContainer / Codespaces configuration has been removed; this is a local-only development environment. - -**Plan-mode exception — parallel exploration IS allowed.** The OOM risk is from concurrent *heavy shells* (vitest/biome/tsc/vite/build), not from read-only exploration. In **plan mode** (read-only research, no builds), you SHOULD launch parallel `Explore`/`Plan` subagents to map the codebase faster — these read files and run light `grep`/`ls`, which is safe. The ONE-Bash-per-turn rule still governs the **main loop's own heavy commands** at all times, and parallel agents must not each kick off vitest/biome/tsc/vite/build. Outside plan mode (implementation), keep agent spawns sequential when they issue heavy shells. +Shell-execution rules (one Bash call per turn, no parallel heavy shells, plan-mode exception) live in the user-global `~/.claude/CLAUDE.md` and apply here. Project-specific addition: DevContainer / Codespaces configuration has been removed; this is a local-only development environment. ## Commands @@ -78,8 +70,6 @@ Conventional Commits format: `feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `ch WorldScript Studio is an offline-first PWA — a React 19 SPA with Google Gemini AI, IndexedDB persistence, and optional Tauri desktop packaging. No backend; API keys are entered in the UI and encrypted at rest. -**Stack:** React 19, TypeScript (strict), Vite 8, Tailwind CSS 4.x, Redux Toolkit 2.x, pnpm 11, Node ≥ 22. Four internal workspace packages (`@domain/ai-core`, `@domain/ui`, `collab-transport`, `@domain/worker-bus` in `packages/`) are consumed as `workspace:*` deps. - **Live:** `https://worldscript-studio.vercel.app/` (Vercel, primary) · GitHub Pages: `https://qnbs.github.io/WorldScript-Studio/` · Cloudflare Pages: `wrangler.toml` · Vercel: `vercel.json`. ### Directory map @@ -194,6 +184,8 @@ Wrap each major view root with `components/ui/ViewErrorBoundary.tsx` — provide **Prompt assembly:** `services/ragPromptAssembly.ts` — `assembleRAGPrompt(opts)`. Templates from `services/promptLibrary.ts`. +**Heuristic-fallback layer:** `services/ai/heuristicFallback/` — when every provider in the chain fails terminally (offline, quota, Eco/Heuristics-only mode), `aiProviderService` calls `applyHeuristicFallback(task, ctx)` (`seam.ts`) before falling through to the generic local stub. It looks up a per-feature generator in `registry.ts` (keyed by task id: `outline`, `character.profile`, `world.profile`, `plotBoard.beat`) and builds a `HeuristicFallbackResult` from existing project data — no network call. Returns `null` when no generator is registered for a task, so wiring a new call site is always non-breaking. Generators self-register via `registerHeuristicGenerator(task, fn)` at module load (mirrors the `services/copilot/heuristicEngine.ts` pluggable-rule pattern). `useHeuristicFallback()` + `` surface an "Assisted (offline)" badge wherever a result came from this layer; events also feed `telemetryService` as `backend: 'heuristic'`. + ### DuckDB Analytics `workers/duckdbWorker.ts` off main thread (OPFS → in-memory fallback). `duckdbClient.ts`: singleton, init retry 3× backoff. Schema: 10 tables + 5 views incl. `rag_chunks` (FLOAT[384]). Gate all paths behind `enableDuckDbAnalytics`. Dual-write via `duckdbListenerLoader.ts` (dynamically imported). `ragVectorMigration.ts`: FLOAT[64]→FLOAT[384] upgrade. `useDuckDb.ts` 30s timeout; `useAnalytics.ts` parallelizes 4 queries. @@ -248,7 +240,7 @@ Production uses **rolldown** (not esbuild/rollup); CI E2E runs `vite dev` — pr Experimental features are gated behind `features/featureFlags/featureFlagsSlice.ts` (**22 flags**). New installs get the **full feature set**: all flags default **on** except six user-opt-in flags. `enableCodexAutoTracking` + `enableCrossProjectSearch` were promoted to permanent core behaviour (v1.20 / v1.8); `enablePlotBoardV2` and `enableCloudSync` were retired — none of those four remain in the slice. UI: Settings → Experimental flags (`FeatureFlagsSection.tsx`). Do not use scattered `if (true)` hacks. -**Default on (17):** `enableStoryBibleAdvanced`, `enableBinderResearch`, `enableCompileWizard`, `enableProjectHealthScore`, `enableAppHealthPanel`, `enableDuckDbAnalytics`, `enableObjectsGroups`, `enableMindMaps`, `enableCharacterInterviews`, `enableLoraAdapters`, `enablePluginSystem`, `enableIdbAtRestEncryption` (B-1, passphrase UX complete — Settings › Privacy), `enableAdaptiveAiEngine`, `enableWebnnInference`, `enableComputeShaders`, `enableWorkerBusV2`, `enableRustCompute`. **User opt-in — default off (6):** `enableProForge` (experimental, token-heavy 8-stage agentic pipeline — flipped to opt-in in v1.24 post-release), `enableVoiceSupport` (requires browser mic permission), `enableVoiceWasm` (B-2, ~57 MB Whisper download), `enableGlobalCopilot` (ambient AI), `enableRtlLayout` (B-5, ar/he stubs only), `enableLocalFirstSync` (shadow Yjs projection, ADR-0008; Redux stays SoT). The Settings UI groups these by catalog tier; `features/featureCatalog.ts` **derives** each flag's `defaultOn` from the slice (no hand-keyed drift). Note: `enableCloudSync` was **retired** in v1.20 (no UI shipped; `CloudSyncBackend.create()` requires explicit-consent boolean instead). +**Default on (16):** `enableStoryBibleAdvanced`, `enableBinderResearch`, `enableCompileWizard`, `enableProjectHealthScore`, `enableAppHealthPanel`, `enableDuckDbAnalytics`, `enableObjectsGroups`, `enableMindMaps`, `enableCharacterInterviews`, `enableLoraAdapters`, `enablePluginSystem`, `enableIdbAtRestEncryption` (B-1, passphrase UX complete — Settings › Privacy), `enableAdaptiveAiEngine`, `enableComputeShaders`, `enableWorkerBusV2`, `enableRustCompute`. **User opt-in — default off (6):** `enableProForge` (experimental, token-heavy 8-stage agentic pipeline — flipped to opt-in in v1.24 post-release), `enableVoiceSupport` (requires browser mic permission), `enableVoiceWasm` (B-2, ~57 MB Whisper download), `enableGlobalCopilot` (ambient AI), `enableRtlLayout` (B-5, ar/he stubs only), `enableLocalFirstSync` (shadow Yjs projection, ADR-0008; Redux stays SoT). The Settings UI groups these by catalog tier; `features/featureCatalog.ts` **derives** each flag's `defaultOn` from the slice (no hand-keyed drift). Note: `enableCloudSync` was **retired** in v1.20 (no UI shipped; `CloudSyncBackend.create()` requires explicit-consent boolean instead). ### Command Center & shortcuts @@ -407,7 +399,7 @@ Reference plugins: `wordCountOverlay.plugin.ts`, `sceneAppender.plugin.ts`. Gate ### Virtual scrolling -`NavigatorPanel.tsx` uses `useVirtualizer` (`@tanstack/react-virtual`): scrollable `