Skip to content

chore(tauri): auto-sync version from package.json to Cargo.toml + tauri.conf.json#65

Merged
qnbs merged 9 commits into
mainfrom
chore/tauri-version-sync
May 30, 2026
Merged

chore(tauri): auto-sync version from package.json to Cargo.toml + tauri.conf.json#65
qnbs merged 9 commits into
mainfrom
chore/tauri-version-sync

Conversation

@qnbs

@qnbs qnbs commented May 30, 2026

Copy link
Copy Markdown
Owner

User description

Summary

Eliminates the recurring version drift between web () and desktop (, ).

Changes

  • Adds [sync-tauri-version] Already in sync. (idempotent, Node-native, no deps)
  • Wires it into and alongside the existing

Verification

  • Run [sync-tauri-version] Already in sync. manually → should print when versions match
  • Change version → rerun → both Tauri files updated

Refs: P2-4


CodeAnt-AI Description

Prevent settings crashes, sync desktop version automatically, and tighten local/dev defaults

What Changed

  • Settings pages no longer crash when older saved data is missing advancedEditor, accessibility, or themeCustomization; the pages now open and keep working with default values.
  • The desktop app version now stays aligned with package.json automatically, and the Tauri config is updated to the new release version.
  • The local dev server now listens on 127.0.0.1 by default instead of all network interfaces, with an opt-in env var for shared dev setups.
  • Desktop app security rules were tightened by removing broad WebSocket wildcard access and blocking site embedding.
  • Added regression tests for the missing-settings crash cases and coverage for log sanitizing and log formatting behavior.

Impact

✅ Fewer settings-page crashes from older saved data
✅ No web/desktop version drift
✅ Safer local development and tighter desktop app loading rules

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

qnbs added 9 commits May 30, 2026 22:57
…y, Appearance

Prevents crashes when persisted settings from older app versions lack
advancedEditor, accessibility, or themeCustomization objects.
Each section now reads from a defaults-merged local object so missing
nested fields can never crash the page.

Refs: P0-2, PR #62 alternative
Adds crash-prevention tests for AdvancedEditor, Accessibility, and
Appearance sections when their respective nested settings objects are
undefined (pre-v1.8 persisted state).

Refs: P0-2
…stomization, add missing normalizeAccessibilitySettings import
…odule extraction

Adds tests for the branch-coverage gaps identified in the audit:
- GDPR redaction vs preservation branches
- Log level branches (debug/info/warn/error)
- withContext merging and nesting
- Error formatting in args
- Module extraction with/without [Prefix]
- Cache limit, formatting, and clear

Refs: P1-2
…ri.conf.json

Adds scripts/sync-tauri-version.mjs and wires it into predev/prebuild
so the desktop version can never drift from the web version again.

Refs: P2-4
@codeant-ai

codeant-ai Bot commented May 30, 2026

Copy link
Copy Markdown

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@vercel

vercel Bot commented May 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
storycraft-studio Ready Ready Preview, Comment May 30, 2026 10:04pm

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
storycraft-studio b2e6aea May 30 2026, 10:05 PM

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label May 30, 2026

describe('sanitizeLogContext', () => {
it('redacts keys matching sensitive pattern', () => {
const ctx = { apiKey: 'secret', userToken: 'tok', myPassword: 'pw' };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Replace the hardcoded sensitive-looking credential values with clearly synthetic, non-secret placeholders (or generated fixture values) so no plaintext secret/token/password literals are committed, even in tests. [custom_rule_security]

Severity Level: Critical 🚨

Why it matters? 🤔

The test hardcodes values that look like credentials or secrets (apiKey, userToken, myPassword) directly in source. Even though they are only test fixtures, the custom security guidance is to avoid committing plaintext secret-like literals, so this is a real rule violation.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** tests/unit/services/logger.test.ts
**Line:** 19:19
**Comment:**
	*Custom Rule Security: Replace the hardcoded sensitive-looking credential values with clearly synthetic, non-secret placeholders (or generated fixture values) so no plaintext secret/token/password literals are committed, even in tests.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment thread vite.config.ts
port: 3000,
host: '0.0.0.0',
// QNBS-v3: Default to loopback for security; opt-in to 0.0.0.0 via VITE_DEV_HOST for Codespaces.
host: process.env['VITE_DEV_HOST'] || '127.0.0.1',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The new default binds the dev server strictly to IPv4 loopback (127.0.0.1). On environments where localhost resolves to IPv6 first (::1), vite dev can become unreachable even on the same machine. Use localhost (or a dual-stack-safe default) instead of forcing IPv4-only binding. [api mismatch]

Severity Level: Major ⚠️
-`pnpm dev` unreachable via localhost on IPv6-first hosts.
- ⚠️ Developers must override VITE_DEV_HOST to restore access.
Steps of Reproduction ✅
1. Ensure environment variable `VITE_DEV_HOST` is unset so the default branch in
`vite.config.ts:31-35` is used (`server.host` falls back to `'127.0.0.1'`).

2. Start the dev server by running `pnpm dev` (script `dev": "vite"` in
`package.json:11-15`), which uses `vite.config.ts` and binds the dev server to host
`127.0.0.1` and port `3000` as configured at `vite.config.ts:31-35`.

3. On a machine where `localhost` resolves to the IPv6 loopback `::1` first (common on
IPv6-first configurations), open a browser and navigate to `http://localhost:3000`.

4. Observe that the browser attempts to connect to `::1:3000`, but the Vite dev server is
only listening on IPv4 `127.0.0.1:3000` (per `server.host` at `vite.config.ts:34`),
resulting in connection failure until the user explicitly sets `VITE_DEV_HOST=0.0.0.0` or
`VITE_DEV_HOST=localhost`.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** vite.config.ts
**Line:** 34:34
**Comment:**
	*Api Mismatch: The new default binds the dev server strictly to IPv4 loopback (`127.0.0.1`). On environments where `localhost` resolves to IPv6 first (`::1`), `vite dev` can become unreachable even on the same machine. Use `localhost` (or a dual-stack-safe default) instead of forcing IPv4-only binding.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment thread vite.config.ts
preview: {
port: 4173,
host: '0.0.0.0',
host: process.env['VITE_DEV_HOST'] || '127.0.0.1',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The same IPv4-only default is also applied to preview mode, so vite preview can fail to be reachable in IPv6-first localhost setups. Keep preview host aligned with a dual-stack-safe default rather than hardcoding IPv4 loopback. [api mismatch]

Severity Level: Major ⚠️
-`pnpm preview` inaccessible via localhost on IPv6-first hosts.
- ⚠️ Requires preview host override for affected developers.
Steps of Reproduction ✅
1. Ensure environment variable `VITE_DEV_HOST` is unset so the preview configuration in
`vite.config.ts:37-40` uses the default `host: '127.0.0.1'` for the `preview` block.

2. Build the app and start preview by running `pnpm build` (script `build": "vite build"`
at `package.json:33-35`) followed by `pnpm preview` (script `preview": "vite preview"` at
`package.json:37-38`), which uses the `preview.host` and `preview.port` settings at
`vite.config.ts:37-40`.

3. On a machine where `localhost` resolves to IPv6 loopback `::1` first, open a browser
and navigate to `http://localhost:4173`.

4. Observe that the browser connects to `::1:4173` while the Vite preview server is only
bound to IPv4 `127.0.0.1:4173` (per `preview.host` at `vite.config.ts:39`), causing
preview to be unreachable until `VITE_DEV_HOST` is explicitly set to a dual-stack-safe
value such as `localhost`.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** vite.config.ts
**Line:** 39:39
**Comment:**
	*Api Mismatch: The same IPv4-only default is also applied to preview mode, so `vite preview` can fail to be reachable in IPv6-first localhost setups. Keep preview host aligned with a dual-stack-safe default rather than hardcoding IPv4 loopback.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +30 to +32
const cargoRe = /^version = "[^"]+"/m;
const cargoNew = cargo.replace(cargoRe, `version = "${version}"`);
if (cargoNew !== cargo) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The Cargo update path can silently do nothing when the TOML formatting changes (for example version="x.y.z" without spaces), because it relies on a very strict regex and then treats an unchanged string as "already in sync". Add an explicit "pattern not found" check and fail with a non-zero exit so version drift is not hidden. [incomplete implementation]

Severity Level: Major ⚠️
- ❌ Tauri desktop binary ships with outdated Cargo package version.
- ⚠️ Autoupdater may misdetect installed version from Cargo manifest.
- ⚠️ Version drift undetected because sync script reports success.
Steps of Reproduction ✅
1. In `/workspace/StoryCraft-Studio/package.json` line 4, change the app version to
`"version": "1.20.0"` so the desired version is `1.20.0`.

2. In `/workspace/StoryCraft-Studio/src-tauri/Cargo.toml` line 3, change the version line
from `version = "1.19.0"` to `version="1.19.0"` (no spaces around `=`), so Cargo.toml is
now both out of date and formatted differently from the regex `^version =`.

3. Ensure `/workspace/StoryCraft-Studio/src-tauri/tauri.conf.json` line 4 has `"version":
"1.20.0",` so only Cargo.toml is out of sync with `package.json`.

4. Run `pnpm run predev` or `pnpm run prebuild`, which invoke `node
scripts/sync-tauri-version.mjs` via the `predev`/`prebuild` scripts in `package.json`
lines 13 and 16; during execution, `scripts/sync-tauri-version.mjs` reads Cargo.toml at
line 29, applies `cargoRe = /^version = "[^"]+"/m` at line 30 and `cargo.replace(...)` at
line 31, finds no match for `version="1.19.0"`, leaves `cargoNew === cargo` so the `if
(cargoNew !== cargo)` block at line 32 is skipped and `changed` stays `false`,
tauri.conf.json already matches so lines 38–46 also do not flip `changed`, and the script
prints `[sync-tauri-version] Already in sync.` at lines 48–49 even though Cargo.toml still
contains the old version.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** scripts/sync-tauri-version.mjs
**Line:** 30:32
**Comment:**
	*Incomplete Implementation: The Cargo update path can silently do nothing when the TOML formatting changes (for example `version="x.y.z"` without spaces), because it relies on a very strict regex and then treats an unchanged string as "already in sync". Add an explicit "pattern not found" check and fail with a non-zero exit so version drift is not hidden.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +40 to +42
const tauriRe = /"version":\s*"[^"]+"/;
const tauriNew = tauriConf.replace(tauriRe, `"version": "${version}"`);
if (tauriNew !== tauriConf) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The Tauri config update also assumes the version regex always matches; if the key format changes, the script will skip the update and still print "Already in sync." Add a required-match validation before replacement and exit with error if no version field is found. [incomplete implementation]

Severity Level: Major ⚠️
- ❌ Tauri config version can diverge without failing sync.
- ⚠️ Updater endpoints use tauri.conf.json version for releases.
- ⚠️ Build pipeline passes despite missing Tauri version field.
Steps of Reproduction ✅
1. In `/workspace/StoryCraft-Studio/package.json` line 4, keep the app version at
`"version": "1.20.0"` and in `/workspace/StoryCraft-Studio/src-tauri/Cargo.toml` line 3
keep `version = "1.20.0"`, so Cargo.toml and package.json are in sync.

2. In `/workspace/StoryCraft-Studio/src-tauri/tauri.conf.json`, replace the top-level
`"version": "1.19.0",` line 4 with a differently named field such as `"appVersion":
"1.19.0",` so there is no `"version":` key matching the regex
`/\"version\":\s*\"[^\"]+\"/`.

3. Run `pnpm run prebuild` (or `pnpm run predev`), which executes `node
scripts/sync-tauri-version.mjs` via the `prebuild`/`predev` scripts in `package.json`
lines 13 and 16.

4. When `scripts/sync-tauri-version.mjs` runs, it reads tauri.conf.json at line 39 and
applies `tauriRe = /"version":\s*"[^"]+"/` and `tauriConf.replace(tauriRe, ...)` at lines
40–41; because the `"version"` key is missing, `tauriNew === tauriConf` so the `if
(tauriNew !== tauriConf)` block at line 42 is skipped, Cargo was already in sync so
`changed` remains `false`, and the script logs `[sync-tauri-version] Already in sync.` at
lines 48–49 even though the effective Tauri app version field in tauri.conf.json has
diverged or is no longer enforced.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** scripts/sync-tauri-version.mjs
**Line:** 40:42
**Comment:**
	*Incomplete Implementation: The Tauri config update also assumes the version regex always matches; if the key format changes, the script will skip the update and still print "Already in sync." Add a required-match validation before replacement and exit with error if no version field is found.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines 5 to +25
@@ -18,11 +21,13 @@ const PRESET_IDS: Exclude<AccessibilityPresetId, 'custom'>[] = [

export const AccessibilitySection: FC = () => {
const { t, settings, handleSettingChange } = useSettingsViewContext();
// QNBS-v3: Defensive merge — old persisted states may lack accessibility entirely.
const accessibility = normalizeAccessibilitySettings(settings.accessibility);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: This newly added import/use of normalizeAccessibilitySettings breaks the existing unit-test module mock contract: tests/unit/settings/AccessibilitySection.test.tsx mocks accessibilitySchema but does not export normalizeAccessibilitySettings, so Vitest will throw at module load (No "normalizeAccessibilitySettings" export is defined on the mock). Update the test mock to include that export (or use a partial mock that preserves real exports). [api mismatch]

Severity Level: Critical 🚨
- ❌ AccessibilitySection unit test file fails at import time.
- ❌ CI pipeline fails whenever unit tests are executed.
Steps of Reproduction ✅
1. Open `tests/unit/settings/AccessibilitySection.test.tsx` and observe the mock at line
59 (from Grep): `vi.mock('../../../features/settings/accessibilitySchema', () => ({
accessibilityPresetDefaults: ... }))` — this mock only defines
`accessibilityPresetDefaults` on the mocked module (lines 10–20 in the BulkRead snippet).

2. Note that after the mocks, the test imports the component at line 27: `import {
AccessibilitySection } from '../../../components/settings/AccessibilitySection';`
(verified in `tests/unit/settings/AccessibilitySection.test.tsx`).

3. In `components/settings/AccessibilitySection.tsx` (lines 5–8 from BulkRead), the
component imports both `accessibilityPresetDefaults` and `normalizeAccessibilitySettings`
from `../../features/settings/accessibilitySchema`, and uses
`normalizeAccessibilitySettings(settings.accessibility)` at line 25 to compute the
`accessibility` object.

4. When you run the Vitest suite including
`tests/unit/settings/AccessibilitySection.test.tsx` (e.g., via your standard test
command), Vitest resolves the mocked `../../../features/settings/accessibilitySchema`
module; because the mock factory only returns `{ accessibilityPresetDefaults: ... }` and
omits `normalizeAccessibilitySettings`, the ESM import in `AccessibilitySection.tsx`
requests a named export that the mock does not provide, causing Vitest to throw a runtime
error during module load (before any `describe`/`it` blocks execute) about the missing
`normalizeAccessibilitySettings` export on the mock module.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** components/settings/AccessibilitySection.tsx
**Line:** 5:25
**Comment:**
	*Api Mismatch: This newly added import/use of `normalizeAccessibilitySettings` breaks the existing unit-test module mock contract: `tests/unit/settings/AccessibilitySection.test.tsx` mocks `accessibilitySchema` but does not export `normalizeAccessibilitySettings`, so Vitest will throw at module load (`No "normalizeAccessibilitySettings" export is defined on the mock`). Update the test mock to include that export (or use a partial mock that preserves real exports).

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@codeant-ai

codeant-ai Bot commented May 30, 2026

Copy link
Copy Markdown

CodeAnt AI finished reviewing your PR.

@qnbs
qnbs merged commit 3f26f36 into main May 30, 2026
15 of 18 checks passed
qnbs added a commit that referenced this pull request May 31, 2026
…tion, CLAUDE.md trim

Security — Scorecard Pinned-Dependencies:
- Dockerfile: pin node:22-alpine and nginx:1.27-alpine to SHA digests (#46,#47)
- .devcontainer/Dockerfile: pin base image SHA, graphifyy==0.8.26, download-then-sha256sum
  pattern for nodesource/rustup installers, starship v1.25.1 with verified tarball (#60-#64)

Security — Scorecard Token-Permissions:
- deploy-cloudflare-pages.yml: add top-level permissions:contents:read (#55);
  remove unnecessary deployments:write — wrangler uses API token, not GitHub token (#65)
- mutation.yml: remove unnecessary checks:write — Stryker reporters write local files only (#66)

A11y — WCAG AA contrast in CommandPalette:
- text-white/80 → text-white and text-white/70 → text-white on --sc-accent selected option
  (contrast ratios 3.79/4.31/4.02 < 4.5:1 threshold; full-opacity white ≥ 4.5:1)
- SaveStatusIndicator: text-green-400 → var(--sc-success-fg) (design token, theme-safe)
- NavigatorPanel: <li> wrapper → <div> to avoid nested <li> axe violation

E2E stabilization:
- helpers.ts + export.spec.ts: add .first() to AI Configuration button (strict mode fix)
- a11y.spec.ts: waitForSpaReady instead of domcontentloaded (avoids nav-destroyed evaluate)
- lora-wizard.spec.ts: ensureBlankProject before clickNavItem (#sidebar not rendered without project)
- playwright.config.ts: PLAYWRIGHT_REUSE_SERVER env var support for VRT job
- package.json: test:vrt uses PLAYWRIGHT_REUSE_SERVER=true

Docs:
- CLAUDE.md: trim from 41.9k to 39.9k chars (remove duplicate quality-gate blocks,
  timeout-prevention, deprecated sprint-handoff refs, minor verbose one-liners)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@qnbs
qnbs deleted the chore/tauri-version-sync branch May 31, 2026 16:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant