Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ types.ts → Core shared interfaces and types

9. **Voice Full Support:** Gated behind `featureFlags.enableVoiceSupport` + `settings.voice.enabled`. Abstract engine pattern in `services/voice/voiceTypes.ts` (SttEngine, TtsEngine, VadEngine, WakeWordEngine, IntentEngine). `VoiceCommandService` singleton manages state machine (idle → listening → processing → speaking). Web Speech API fallbacks require zero downloads. Hooks: `useVoice`, `usePushToTalk` (Ctrl+Shift+V), `useVoiceDictation`.

10. **Feature Flags:** **23 flags** in `features/featureFlags/featureFlagsSlice.ts`. New installs get the **full feature set** — all default **on** except five opt-in flags that default **off**: `enableRtlLayout`, `enableVoiceSupport`, `enableVoiceWasm`, `enableGlobalCopilot`, `enableLocalFirstSync`. (`enableCodexAutoTracking` + `enableCrossProjectSearch` were promoted to permanent core; `enablePlotBoardV2` + `enableCloudSync` were retired — none remain in the slice.) See `docs/FEATURE-PARITY.md`. Do not use scattered `if (true)` hacks — all experimental features must go through a flag.
10. **Feature Flags:** **22 flags** in `features/featureFlags/featureFlagsSlice.ts`. New installs get the **full feature set** — all default **on** except six opt-in flags that default **off**: `enableRtlLayout`, `enableVoiceSupport`, `enableProForge`, `enableVoiceWasm`, `enableGlobalCopilot`, `enableLocalFirstSync`. (`enableCodexAutoTracking` + `enableCrossProjectSearch` were promoted to permanent core; `enablePlotBoardV2` + `enableCloudSync` were retired — none remain in the slice.) See `docs/FEATURE-PARITY.md`. Do not use scattered `if (true)` hacks — all experimental features must go through a flag.

11. **Global AI Copilot (v2):** `enableGlobalCopilot` flag. `CopilotPanel` (dialog/sidebar mode), `CopilotMessageList` (markdown rendering via DOMPurify), `InlineAnnotationLayer` (badge in ManuscriptEditor). Heuristic rules: `services/copilot/heuristicEngine.ts` (8 rules). Apply-to-chapter: `services/copilot/actionApplier.ts` (offset-safe edit, redux-undo, ≥70% length gate). ProForge integration: Ask-Copilot chip on each `ReviewItemCard`. Docs: `docs/COPILOT.md`, `docs/HEURISTIC-RULES.md`.

Expand Down
20 changes: 18 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,24 @@ jobs:
fetch-depth: 0
- uses: ./.github/actions/setup

- name: pnpm audit (high + critical)
run: pnpm audit --audit-level=high
# QNBS-v3: pnpm's audit client cannot decode force-gzipped responses from some npm CDN edge
# nodes (ERR_PNPM_AUDIT_BAD_RESPONSE, deterministic per edge — retries are useless). The
# enforced vulnerability gate in this job is the OSV scan below (covers BOTH pnpm-lock.yaml
# and Cargo.lock with a superset DB); this step is advisory-only until pnpm fixes decoding.
- name: pnpm audit (high + critical, advisory)
continue-on-error: true
run: |
if pnpm audit --audit-level=high; then
echo "pnpm audit: clean"
else
echo "::warning::pnpm audit failed (registry gzip-decoding bug or findings) — OSV scan below is the enforced gate"
exit 1
fi

# QNBS-v3 (#60): vendored y-webrtc fork invariant guard (PBKDF2 600k, non-extractable keys,
# DataChannel encryption, no dangling upstream dep) — fails the build on fork drift.
- name: Vendor fork invariant guard
run: pnpm run verify:vendor

# QNBS-v3: osv-scanner.toml (in src-tauri/) suppresses accepted RUSTSEC advisories for Cargo.lock;
# scan both lockfiles so npm + Rust advisories are caught on every push
Expand Down
12 changes: 6 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
- **Version:** `1.23.0`
- **License:** MIT

The app supports a multi-provider AI stack (Gemini, OpenAI, Claude, Grok, OpenRouter, Ollama, WebLLM, ONNX Runtime Web, Transformers.js), four AI execution modes (Hybrid / Cloud / Local / Eco), real-time collaboration with E2E encryption, a Plot Board v2 with swimlane/canvas/timeline modes, character/world management, manuscript export, voice dictation, and an 11-locale i18n layer.
The app supports a multi-provider AI stack (Gemini, OpenAI, Claude, Grok, OpenRouter, Ollama, WebLLM, ONNX Runtime Web, Transformers.js), four AI execution modes (Hybrid / Cloud / Local / Eco), real-time collaboration with E2E encryption, a Plot Board v2 with swimlane/canvas/timeline modes, character/world management, manuscript export, voice dictation, and a 19-locale i18n layer.

---

Expand Down Expand Up @@ -84,7 +84,7 @@ WorldScript-Studio/
│ ├── status/ # App-wide status / loading flags
│ ├── writer/ # Writer view state
│ ├── versionControl/ # Snapshots and branches
│ ├── featureFlags/ # 23 flags — full set on by default; 5 opt-in (default-off)
│ ├── featureFlags/ # 22 flags — full set on by default; 6 opt-in (default-off)
│ ├── plotBoard/ # Ephemeral viewport/draw state (NOT undo-able; localStorage)
│ ├── progressTracker/ # Writing sessions, streaks, goals
│ ├── sceneComments/ # Per-scene comments (EntityAdapter)
Expand Down Expand Up @@ -114,7 +114,7 @@ WorldScript-Studio/
│ ├── collab-transport/ # Vendor fork of y-webrtc 10.3.0 with E2E encryption patch
│ ├── ui/ # Tailwind preset + design tokens
│ └── worker-bus/ # Typed worker pool, circuit breakers, dead-letter queue
├── locales/ # i18n source JSON modules (11 locales)
├── locales/ # i18n source JSON modules (19 locales)
├── public/ # Static assets; runtime i18n bundles `public/locales/<lang>/bundle.json`
├── tests/
│ ├── unit/ # Vitest tests (co-located naming convention)
Expand Down Expand Up @@ -387,7 +387,7 @@ Edge builds run `scripts/build-edge.mjs` which sets `DEPLOY_TARGET=edge` and pat

### Feature Flags

- `features/featureFlags/featureFlagsSlice.ts` gates **23 flags**. New installs get the **full feature set**: all default **on** except five opt-in flags that default **off** — `enableRtlLayout`, `enableVoiceSupport`, `enableVoiceWasm`, `enableGlobalCopilot`, `enableLocalFirstSync`. (`enableCodexAutoTracking` + `enableCrossProjectSearch` were promoted to permanent core; `enablePlotBoardV2` + `enableCloudSync` were retired — none remain in the slice.) See `docs/FEATURE-PARITY.md` for the per-flag matrix.
- `features/featureFlags/featureFlagsSlice.ts` gates **22 flags**. New installs get the **full feature set**: all default **on** except six opt-in flags that default **off** — `enableRtlLayout`, `enableVoiceSupport`, `enableProForge`, `enableVoiceWasm`, `enableGlobalCopilot`, `enableLocalFirstSync`. (`enableCodexAutoTracking` + `enableCrossProjectSearch` were promoted to permanent core; `enablePlotBoardV2` + `enableCloudSync` were retired — none remain in the slice.) See `docs/FEATURE-PARITY.md` for the per-flag matrix.
- UI: Settings → Experimental flags.
- Do not use scattered `if (true)` hacks.

Expand Down Expand Up @@ -486,10 +486,10 @@ Central orchestration layer for all background worker tasks. Messages use short
## Internationalization (i18n)

- **Custom React Context** (`contexts/I18nContext.tsx`) — not i18next.
- Source modules: `locales/<lang>/*.json` for **11 locales**: `ar`, `de`, `el`, `en`, `es`, `fr`, `he`, `it`, `ja`, `pt`, `zh`.
- Source modules: `locales/<lang>/*.json` for **19 locales**: `ar`, `de`, `el`, `en`, `es`, `eu`, `fa`, `fi`, `fr`, `he`, `hu`, `is`, `it`, `ja`, `ko`, `pt`, `ru`, `sv`, `zh`.
- Runtime bundles: `public/locales/<lang>/bundle.json` (rebuilt by `pnpm run i18n:bundle` or automatically via `predev` / `prebuild`).
- Hook: `useTranslation()` returns `t('key.path')`. **No hardcoded text** in UI.
- Key parity is enforced in CI (`pnpm run i18n:check`). Add keys to **all eleven** locale trees.
- Key parity is enforced in CI (`pnpm run i18n:check`). Add keys to **all nineteen** locale trees.
- Repair scripts: `services/i18nBootstrap.ts` and `services/i18nRepair.ts` handle missing keys / bundle corruption.
- RTL Beta: Arabic (`ar`) and Hebrew (`he`) set `html[dir="rtl"]`. Layout mirroring uses logical properties and a global `[dir="rtl"]` CSS net. Canvas/SVG boards (Plot Board, Character Graph) stay LTR to keep pointer/geometry math correct. `enableRtlLayout` flag forces RTL for testing.

Expand Down
49 changes: 47 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- **Settings hygiene.** Removed stale Experimental-category search hints (`plot board`, `codex`,
`cross project` — retired/promoted flags) in favor of current features; `ProForgeDashboard` now
uses the catalog-driven `MaturityBadge` instead of a hard-coded Experimental pill, keeping the
v1.24 maturity-label convention consistent.

- **Desktop settings "minimize to tray" is now a proper switch.** `DesktopSection` used the only raw
`<input type="checkbox">` left in Settings, with its hint not programmatically associated. It now
renders the design-system `ToggleSwitch` (`role="switch"`, `aria-labelledby` + `aria-describedby`
Expand All @@ -90,7 +95,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
provider is still described as an adaptive-engine backend). Refreshed in the five Production locales.
- **ProForge is now opt-in (default off).** The experimental 8-stage agentic editing pipeline
(`enableProForge`) shipped on by default; it is token-heavy and carries loop risk, so it is now a
user opt-in like Voice and the Global Copilot. New installs get **17 default-on / 6 default-off**
user opt-in like Voice and the Global Copilot. New installs get **16 default-on / 6 default-off**
flags. Existing users who enabled or relied on it are unaffected (the persisted value wins);
everyone can still turn it on under Settings → Experimental.
- **Settings → Experimental features are grouped by category** (Writing, AI, Editing Pipeline,
Expand All @@ -105,11 +110,51 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- **Ollama / LM Studio / vLLM discovery & connectivity on desktop, CORS noise in the PWA
(#266).** Root cause: all local-server traffic (`services/ollamaService.ts`,
`scanLocalOpenAiCompatibleEndpoints()`) used the WebView's `fetch`, so inside the Tauri shell the
cross-origin `localhost` requests died on CORS/PNA, and in the PWA the settings auto-effect probed
`localhost:11434` on every visit (loud CORS console errors). All local-server calls now go through
the new thin `services/localServerHttp.ts`, which routes via `@tauri-apps/plugin-http` (native,
CORS-free) on desktop and keeps browser `fetch` on the web, with shared URL normalization, timeout
composition and `unreachable`/`timeout` classification (user aborts still propagate unchanged).
The Settings → AI card no longer auto-probes localhost in the PWA — it shows a quiet "desktop app
required" banner with a download CTA instead — and the desktop scan gained per-endpoint status
badges (reachable / no response / timeout / HTTP error) plus a one-click **Use this URL** action.
All new strings localized in 19 locales. See
[ADR 0012](docs/adr/0012-local-server-connectivity-tauri-http.md) and
[`docs/LOCAL-AI.md`](docs/LOCAL-AI.md).

- **Feature-catalog / slice default drift made structurally impossible.** `features/featureCatalog.ts`
now covers all **23** flags (was 16) and **derives** each entry's `defaultOn` from the slice's
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
`false` while the slice said `true` for ~12 flags can no longer recur (guarded by the new
`tests/unit/featureCatalog.test.ts`). Added risk-level / desktop-requirement / dependency metadata.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

### Security

- **Tauri HTTP-plugin capability scope pinned (#266).** `http:default` alone grants **no** URL
scope — every plugin-http call (including AI-SDK cloud calls on desktop) was silently denied by
the plugin's allow-list check. The capability now explicitly allows loopback any-port
(`http://localhost:*/*`, `http://127.0.0.1:*/*` — Ollama/LM Studio/vLLM + custom ports) and the
cloud endpoints mirroring the Tauri CSP `connect-src` (Gemini, OpenAI, x.ai, OpenRouter, Groq).
- **y-webrtc vendor-fork audit + CI invariant guard (#60).** Full-file diff of
`packages/collab-transport` against upstream `y-webrtc@10.3.0`: no deviations beyond the three
documented SC patches (PBKDF2 600k iterations, `extractable: false`, `return promise.reject`) plus
the DataChannel E2E encryption — recorded in `packages/collab-transport/AUDIT.md`, fork bumped to
`10.3.0-sc2`. The deprecated `patches/y-webrtc@10.3.0.patch` and the dead root `y-webrtc`
dependency (zero imports) are removed, and the previously-referenced-but-missing
`scripts/verify-vendor-fork.mjs` now exists and runs in the CI security job (`verify:vendor`).
- **Advisory batch remediated (2026-07-26, CI security gate).** Cargo.lock: `quick-xml` 0.39.4 →
0.41.0 via `plist` 1.10.0 (RUSTSEC-2026-0194/0195, CVSS 7.5), `anyhow` → 1.0.104,
`crossbeam-epoch` → 0.9.20, `serde_with` → 3.21.0. pnpm overrides raised: `dompurify` → 3.4.12,
`protobufjs` → 8.7.1, `body-parser` → 1.20.6 (bounded `<2` for express-4 compat). The two stale
no-longer-matching OSV ignores (dompurify GHSA-x4vx-rjvf-j5p4, js-yaml-3.x GHSA-h67p-54hq-rp68)
were dropped from `src-tauri/osv-scanner.toml`. The `pnpm audit` CI step is now advisory
(`continue-on-error`): some npm CDN edge nodes force-gzip the bulk-advisories response which
pnpm cannot decode (`ERR_PNPM_AUDIT_BAD_RESPONSE`, deterministic per edge — retries useless);
the OSV scan of both lockfiles remains the enforced gate.

### Removed

- **Dead `enableWebnnInference` feature flag removed.** The flag shipped default-on but **no runtime
Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ Production uses **rolldown** (not esbuild/rollup); CI E2E runs `vite dev` — pr

### Feature Flags

Experimental features are gated behind `features/featureFlags/featureFlagsSlice.ts` (**23 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.
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).

Expand Down Expand Up @@ -337,7 +337,7 @@ All `.md` guides listed in **[`README.md`](README.md#-documentation-hub) § Docu

**useAppSelectorShallow with plotBoard:** Include `plotBoard: { activeMode: 'swimlane', snapToGrid: false, selectedConnectionId: null, isDrawingConnection: false, drawFromSectionId: null, activeSubplotFilter: null, zoom: 1, panX: 0, panY: 0 }` in mock state. Connections/subplots/tensionOverrides are in `project.present.data`. Add `// biome-ignore lint/suspicious/noExplicitAny: test mock` before `(selector: (s: any) => unknown)` lines.

**FeatureFlagsState mocks:** Always include ALL 23 flags (TypeScript strict rejects partial). Only **six** default **off**: `enableProForge`, `enableRtlLayout`, `enableVoiceSupport`, `enableVoiceWasm`, `enableGlobalCopilot`, `enableLocalFirstSync` — every other flag (including all edge-AI flags and `enableIdbAtRestEncryption`) defaults **on**. When a test needs a non-default flag state, set it explicitly in the mock — don't assume the default.
**FeatureFlagsState mocks:** Always include ALL 22 flags (TypeScript strict rejects partial). Only **six** default **off**: `enableProForge`, `enableRtlLayout`, `enableVoiceSupport`, `enableVoiceWasm`, `enableGlobalCopilot`, `enableLocalFirstSync` — every other flag (including all edge-AI flags and `enableIdbAtRestEncryption`) defaults **on**. When a test needs a non-default flag state, set it explicitly in the mock — don't assume the default.

**ConnectionLayer test IDs:** `data-testid="connection-group"` — query by testid, not role.

Expand Down
Loading
Loading