Skip to content

opt.: new website#1138

Merged
lollipopkit merged 11 commits into
mainfrom
lollipopkit/issue1137
Apr 25, 2026
Merged

opt.: new website#1138
lollipopkit merged 11 commits into
mainfrom
lollipopkit/issue1137

Conversation

@lollipopkit
Copy link
Copy Markdown
Owner

@lollipopkit lollipopkit commented Apr 24, 2026

Fixes #1137

Summary by CodeRabbit

  • New Features

    • Launched a new localized website (8 languages) with locale selection and polished UI.
    • Added Homebrew Cask support with an automated cask sync step for macOS releases.
    • Added alternative distribution sources (CDN, OpenAPK) to downloads.
  • Documentation

    • Updated README and installation guides with platform-specific install commands.
    • Replaced SSH key field name with pubKeyId across docs; clarified testing and codegen guidance.
  • Chores

    • Simplified macOS DMG naming and release packaging.

lollipopkit and others added 3 commits April 25, 2026 03:19
Co-authored-by: Copilot <copilot@github.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 24, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Adds a new Svelte/Vite/Tailwind website with full i18n support (en, es, fr, it, ja, kr, zh-CN) and associated build/config files (vite, svelte, tsconfig, package.json, CSS, entrypoints, scripts). Introduces Homebrew Cask sync tooling and Makefile integration (new sync-homebrew-cask target and DMG_PATH/TAP_REPO_PATH variables), updates macOS release scripts (DMG basename change, CocoaPods sync, spctl changes, optional cask sync), adds a Cloudflare Pages build script, and applies widespread documentation updates (installation sources, bulk-import field rename to pubKeyId, codegen/testing guidance) across localized docs.

Possibly related PRs

  • new: docs website #1033: Modifies website/docs configuration files (including docs/astro.config.mjs) and other repository documentation—overlaps site config changes.
  • opt.: docs l10n #1036: Updates documentation and localization content across multiple localized pages—overlaps i18n and localized docs additions.
🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes scope changes beyond the website: Makefile updates, release scripts (DMG, Homebrew cask), documentation updates across multiple languages, and changelog adjustments unrelated to website implementation. Move release script changes, Makefile modifications, and documentation updates to separate PRs focused on their specific domains. Keep website-related changes in this PR.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive Linked issue #1137 provides no specific coding requirements or objectives to validate against. The PR introduces a complete website implementation, but without detailed issue requirements, full compliance assessment is not possible. Provide detailed requirements in issue #1137 (features, components, configuration specifications) to validate PR implementation against stated objectives.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'opt.: new website' is concise and relates to the changeset, which introduces a complete new website package with components, configuration, and localization.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lollipopkit/issue1137

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 2 potential issues.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment thread website/src/App.svelte
Comment on lines +381 to +386
if [[ "${SYNC_HOMEBREW_CASK:-1}" == "1" ]]; then
APP_PATH="$APP_PATH" \
DMG_PATH="$DMG_PATH" \
TAP_REPO_PATH="${TAP_REPO_PATH:-$HOME/proj/homebrew-taps}" \
bash "$SCRIPT_DIR/sync-homebrew-cask.sh"
fi
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚩 SYNC_HOMEBREW_CASK defaults to enabled, which is a breaking change for existing release script users

In scripts/release/release-macos-dmg.sh:381, SYNC_HOMEBREW_CASK defaults to "1" (enabled). This means anyone who previously used the release script will now need either (a) a cloned tap repo at $HOME/proj/homebrew-taps, or (b) to explicitly set SYNC_HOMEBREW_CASK=0 to skip it. If the tap directory doesn't exist, the sync script fails at scripts/release/sync-homebrew-cask.sh:82-84. This is a deliberate design choice with a clear opt-out, but it could surprise existing users of the release pipeline.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (3)
Makefile (2)

11-13: Declare DMG_PATH variable for consistency.

DMG_PATH is referenced in the sync-homebrew-cask target (lines 153, 155, 157) but isn't declared at the top like APP_PATH and XCARCHIVE_PATH. While undefined Make variables expand to empty strings (which the script handles), declaring it improves clarity.

🛠️ Suggested fix
 XCARCHIVE_PATH ?=
 APP_PATH ?=
 TAP_REPO_PATH ?=
+DMG_PATH ?=
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Makefile` around lines 11 - 13, Add a top-level declaration for the DMG_PATH
variable to mirror the style of APP_PATH and XCARCHIVE_PATH; update the Makefile
by declaring "DMG_PATH ?=" alongside "XCARCHIVE_PATH ?=" and "APP_PATH ?=" so
the variable is defined for use in the sync-homebrew-cask target (referencing
DMG_PATH in that target) and improves clarity.

54-57: Example DMG filename uses old naming convention.

The example ServerBox-1.0.1365.dmg includes a build number, but the DMG naming was changed in package-dmg-from-xcarchive.sh and release-macos-dmg.sh to use only the version (e.g., ServerBox-1.0.1.dmg). Consider updating the example to match the new convention.

📝 Suggested fix
-		'                     Example: make sync-homebrew-cask DMG_PATH=build/artifacts/ServerBox-1.0.1365.dmg'
+		'                     Example: make sync-homebrew-cask DMG_PATH=build/artifacts/ServerBox-1.0.1.dmg'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Makefile` around lines 54 - 57, Update the example DMG filename in the
Makefile help text for the sync-homebrew-cask target to match the new naming
convention used by package-dmg-from-xcarchive.sh and release-macos-dmg.sh
(version-only, e.g., change "ServerBox-1.0.1365.dmg" to "ServerBox-1.0.1.dmg");
locate the quoted help string near the sync-homebrew-cask mention and replace
the old build-number example with a version-only DMG example so the
documentation matches the actual produced artifact name.
website/src/lib/utils.js (1)

8-8: Remove stale lint suppression comment on Line 8.

This appears unused and unrelated to the current JS file content.

Suggested cleanup
-// eslint-disable-next-line `@typescript-eslint/no-explicit-any`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/lib/utils.js` at line 8, Remove the stale ESLint suppression
comment ("// eslint-disable-next-line `@typescript-eslint/no-explicit-any`")
present in website/src/lib/utils.js (it is unused in this plain JS file); delete
that line and verify there are no other unnecessary eslint-disable comments in
the file, then run the linter to ensure no real warnings remain.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@website/jsconfig.json`:
- Line 37: Update the jsconfig.json "include" array to also match TypeScript
source files so editors and type tooling pick up .ts sources; modify the include
pattern (the existing entry "src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte")
to add "src/**/*.ts" (or a combined "src/**/*.{ts,js,svelte,d.ts}") so files
under src/i18n/*.ts and other .ts files are included in project diagnostics and
type checking.

In `@website/package.json`:
- Line 9: The "build" npm script currently invokes Bun ("bun run typesafe-i18n
&& vite build"), which is unnecessary; update the "build" script to call the
existing local script instead (e.g., "npm run typesafe-i18n && vite build" or
directly "typesafe-i18n --no-watch && vite build") so it uses the package.json
"typesafe-i18n" script and removes the Bun dependency; edit the "build" entry
accordingly.

In `@website/src/app.css`:
- Line 1: Replace the remote `@import` in website/src/app.css that loads
"cabinet-grotesk" from Fontshare with a self-hosted font bundle: remove the
`@import` line, add `@font-face` rules referencing locally checked-in font files
(e.g., cabinet-grotesk-400.woff2, 500.woff2, 700.woff2, 800.woff2) using
font-family "Cabinet Grotesk" and font-display: swap (or optional), and update
any usages of that family in your CSS to the same name; ensure you generate or
obtain appropriate WOFF2/WOFF files, place them in the repo (e.g.,
static/fonts), and reference those file paths in the `@font-face` src so the page
no longer depends on the Fontshare CDN.

In `@website/src/App.svelte`:
- Around line 16-24: The capability and feature label arrays (capabilities and
features in App.svelte) are hard-coded English strings; replace them with
translation keys and call the typesafe-i18n translation function where these
labels are rendered (e.g., swap each entry like 'Status chart' or
feature.icon/title for a key such as 'capability.statusChart' or
'feature.charts' and use the translator when building the UI). Update the
features array to store keys (e.g., key: 'feature.charts') and the capabilities
array to store keys (e.g., 'capability.statusChart'), add corresponding keys to
the i18n translation schema for all locales (including zh-CN), and ensure the
component imports/uses the typesafe-i18n translator (the same function used
elsewhere) to resolve strings before display.
- Around line 91-108: Remove the artificial "isMounted" render gate: delete the
isMounted state and its assignments (the let isMounted = $state(false)
declaration and the isMounted = true in onMount), and update any template
conditional that checks "{`#if` locale && isMounted}" to just "{`#if` locale}" so
the page renders as soon as locale is available; keep applyLocale, onMount,
loadLocale, setLocale, syncLocaleToUrl and the localStorage write intact (use
getInitialLocale/initialLocale as before) so locale initialization and URL sync
still run on mount.
- Around line 146-155: The copyCommand function currently swallows failures from
navigator.clipboard.writeText and never surfaces the command; update the catch
path in copyCommand (and the duplicate handler at the other location) to show a
fallback UI: set copiedCommand = command so the command is rendered inline for
the user, and also trigger a visible fallback copy prompt (e.g., open a small
modal or call window.prompt with the command text) so users can manually copy;
ensure the UI code that displays copiedCommand handles this fallback case.

---

Nitpick comments:
In `@Makefile`:
- Around line 11-13: Add a top-level declaration for the DMG_PATH variable to
mirror the style of APP_PATH and XCARCHIVE_PATH; update the Makefile by
declaring "DMG_PATH ?=" alongside "XCARCHIVE_PATH ?=" and "APP_PATH ?=" so the
variable is defined for use in the sync-homebrew-cask target (referencing
DMG_PATH in that target) and improves clarity.
- Around line 54-57: Update the example DMG filename in the Makefile help text
for the sync-homebrew-cask target to match the new naming convention used by
package-dmg-from-xcarchive.sh and release-macos-dmg.sh (version-only, e.g.,
change "ServerBox-1.0.1365.dmg" to "ServerBox-1.0.1.dmg"); locate the quoted
help string near the sync-homebrew-cask mention and replace the old build-number
example with a version-only DMG example so the documentation matches the actual
produced artifact name.

In `@website/src/lib/utils.js`:
- Line 8: Remove the stale ESLint suppression comment ("//
eslint-disable-next-line `@typescript-eslint/no-explicit-any`") present in
website/src/lib/utils.js (it is unused in this plain JS file); delete that line
and verify there are no other unnecessary eslint-disable comments in the file,
then run the linter to ensure no real warnings remain.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d8967f5f-7941-42b0-a03f-931016205065

📥 Commits

Reviewing files that changed from the base of the PR and between c1ccc09 and 7bf3894.

⛔ Files ignored due to path filters (4)
  • website/bun.lock is excluded by !**/*.lock
  • website/public/app_icon.png is excluded by !**/*.png
  • website/public/icons.svg is excluded by !**/*.svg
  • website/src/assets/serverbox/app_icon.png is excluded by !**/*.png
📒 Files selected for processing (27)
  • Makefile
  • scripts/release/package-dmg-from-xcarchive.sh
  • scripts/release/release-macos-dmg.sh
  • scripts/release/sync-homebrew-cask.sh
  • website/.gitignore
  • website/.typesafe-i18n.json
  • website/.vscode/extensions.json
  • website/components.json
  • website/index.html
  • website/jsconfig.json
  • website/package.json
  • website/src/App.svelte
  • website/src/app.css
  • website/src/i18n/en/index.ts
  • website/src/i18n/formatters.ts
  • website/src/i18n/i18n-svelte.ts
  • website/src/i18n/i18n-types.ts
  • website/src/i18n/i18n-util.async.ts
  • website/src/i18n/i18n-util.sync.ts
  • website/src/i18n/i18n-util.ts
  • website/src/i18n/zh-CN/index.ts
  • website/src/lib/Counter.svelte
  • website/src/lib/i18n.js
  • website/src/lib/utils.js
  • website/src/main.js
  • website/svelte.config.js
  • website/vite.config.js

Comment thread website/jsconfig.json Outdated
Comment thread website/package.json
"scripts": {
"dev": "vite",
"typesafe-i18n": "typesafe-i18n --no-watch",
"build": "bun run typesafe-i18n && vite build",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Detected JS lockfiles:"
fd -a '^(bun.lockb|bun.lock|package-lock.json|pnpm-lock.yaml|yarn.lock)$' . || true

echo
echo "References to Bun/build tooling:"
rg -n "setup-bun|bun run|npm run build|pnpm run build|yarn build" website/package.json README.md .github/workflows 2>/dev/null || true

Repository: lollipopkit/flutter_server_box

Length of output: 275


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Checking GitHub Workflows for Bun setup ==="
find .github/workflows -name "*.yml" -o -name "*.yaml" 2>/dev/null | head -20

echo
echo "=== Searching workflow files for Bun/Node setup ==="
rg -l "." .github/workflows 2>/dev/null | head -10

Repository: lollipopkit/flutter_server_box

Length of output: 297


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Checking README for build instructions ==="
head -100 README.md 2>/dev/null || echo "No README.md at root"

echo
echo "=== Checking website/README if exists ==="
head -50 website/README.md 2>/dev/null || echo "No website/README.md"

echo
echo "=== Checking docs directory for build instructions ==="
find docs -name "README*" -o -name "*.md" 2>/dev/null | head -5

Repository: lollipopkit/flutter_server_box

Length of output: 6219


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Checking if typesafe-i18n can be run directly ==="
rg "typesafe-i18n" website/package.json -A 2 -B 2

echo
echo "=== Checking website package.json dependencies ==="
grep -A 30 '"dependencies"' website/package.json || echo "No dependencies section found"

Repository: lollipopkit/flutter_server_box

Length of output: 513


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Content of .github/workflows/release.yml ==="
cat .github/workflows/release.yml

echo
echo "=== Content of .github/workflows/analysis.yml ==="
cat .github/workflows/analysis.yml

Repository: lollipopkit/flutter_server_box

Length of output: 7976


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== docs/README.md content ==="
cat docs/README.md 2>/dev/null | head -80

echo
echo "=== Checking for website/docs deployment mentions ==="
rg "website|docs" .github/workflows 2>/dev/null || echo "No website/docs deployment found in workflows"

echo
echo "=== Checking if typesafe-i18n CLI can be called directly ==="
rg "typesafe-i18n" website/ -B 2 -A 2

Repository: lollipopkit/flutter_server_box

Length of output: 6026


Build script unnecessarily requires Bun when direct CLI call is available.

The build command uses bun run typesafe-i18n, but the npm script "typesafe-i18n": "typesafe-i18n --no-watch" already exists in the same package.json. The CLI can be invoked directly without Bun, improving portability for developers who use npm/pnpm only.

Suggested fix
-    "build": "bun run typesafe-i18n && vite build",
+    "build": "typesafe-i18n --no-watch && vite build",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"build": "bun run typesafe-i18n && vite build",
"build": "typesafe-i18n --no-watch && vite build",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/package.json` at line 9, The "build" npm script currently invokes Bun
("bun run typesafe-i18n && vite build"), which is unnecessary; update the
"build" script to call the existing local script instead (e.g., "npm run
typesafe-i18n && vite build" or directly "typesafe-i18n --no-watch && vite
build") so it uses the package.json "typesafe-i18n" script and removes the Bun
dependency; edit the "build" entry accordingly.

Comment thread website/src/app.css Outdated
@@ -0,0 +1,712 @@
@import 'https://api.fontshare.com/v2/css?f[]=cabinet-grotesk@400,500,700,800&display=swap';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Self-host the display font instead of importing it from Fontshare at runtime.

This makes every visit depend on a third-party CSS request, which leaks visitor metadata and can delay text rendering if that service is slow or blocked. For a public marketing page, bundle the font locally or fall back to system fonts.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/app.css` at line 1, Replace the remote `@import` in
website/src/app.css that loads "cabinet-grotesk" from Fontshare with a
self-hosted font bundle: remove the `@import` line, add `@font-face` rules
referencing locally checked-in font files (e.g., cabinet-grotesk-400.woff2,
500.woff2, 700.woff2, 800.woff2) using font-family "Cabinet Grotesk" and
font-display: swap (or optional), and update any usages of that family in your
CSS to the same name; ensure you generate or obtain appropriate WOFF2/WOFF
files, place them in the repo (e.g., static/fonts), and reference those file
paths in the `@font-face` src so the page no longer depends on the Fontshare CDN.

Comment thread website/src/App.svelte
Comment on lines +16 to +24
const capabilities = ['Status chart', 'SSH Terminal', 'SFTP', 'Docker', 'Process', 'Systemd', 'S.M.A.R.T', 'GPU', 'Sensors', 'Push', 'Home Widget', 'watchOS']

const features = [
{ key: 'charts', icon: '⬡', wide: false },
{ key: 'workspace', icon: '⬡', wide: true },
{ key: 'terminal', icon: '⬡', wide: false },
{ key: 'native', icon: '⬡', wide: false },
{ key: 'platforms', icon: '⬡', wide: false },
]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

These capability labels are not localizable.

They bypass typesafe-i18n, so the zh-CN page will still render this section in English. The current translation schema also has no keys for these items, so they cannot be translated without a schema change.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/App.svelte` around lines 16 - 24, The capability and feature
label arrays (capabilities and features in App.svelte) are hard-coded English
strings; replace them with translation keys and call the typesafe-i18n
translation function where these labels are rendered (e.g., swap each entry like
'Status chart' or feature.icon/title for a key such as 'capability.statusChart'
or 'feature.charts' and use the translator when building the UI). Update the
features array to store keys (e.g., key: 'feature.charts') and the capabilities
array to store keys (e.g., 'capability.statusChart'), add corresponding keys to
the i18n translation schema for all locales (including zh-CN), and ensure the
component imports/uses the typesafe-i18n translator (the same function used
elsewhere) to resolve strings before display.

Comment thread website/src/App.svelte
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 25, 2026

Deploying serverbox with  Cloudflare Pages  Cloudflare Pages

Latest commit: 4a0001e
Status: ✅  Deploy successful!
Preview URL: https://5912ecd1.serverbox.pages.dev
Branch Preview URL: https://lollipopkit-issue1137.serverbox.pages.dev

View logs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
website/src/app.css (1)

1-1: ⚠️ Potential issue | 🟠 Major

Replace runtime font CDN import with self-hosted @font-face (also fixes current Stylelint error).

Line 1 adds a render-blocking third-party font request and leaks visitor metadata to an external service. It also triggers the reported import-notation lint error. Please self-host font files and switch to local @font-face declarations.

Suggested patch
-@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;700;800&display=swap');
+@font-face {
+  font-family: 'Plus Jakarta Sans';
+  src: url('/fonts/PlusJakartaSans-Regular.woff2') format('woff2');
+  font-weight: 400;
+  font-style: normal;
+  font-display: swap;
+}
+
+@font-face {
+  font-family: 'Plus Jakarta Sans';
+  src: url('/fonts/PlusJakartaSans-Medium.woff2') format('woff2');
+  font-weight: 500;
+  font-style: normal;
+  font-display: swap;
+}
+
+@font-face {
+  font-family: 'Plus Jakarta Sans';
+  src: url('/fonts/PlusJakartaSans-Bold.woff2') format('woff2');
+  font-weight: 700;
+  font-style: normal;
+  font-display: swap;
+}
+
+@font-face {
+  font-family: 'Plus Jakarta Sans';
+  src: url('/fonts/PlusJakartaSans-ExtraBold.woff2') format('woff2');
+  font-weight: 800;
+  font-style: normal;
+  font-display: swap;
+}

Verification (read-only):

#!/bin/bash
set -euo pipefail

echo "1) Ensure no runtime `@import` remains:"
rg -n '^\s*@import' website/src/app.css || true

echo
echo "2) Ensure local `@font-face` blocks exist:"
rg -n '@font-face|Plus Jakarta Sans' website/src/app.css

echo
echo "3) Ensure font assets exist in repo:"
fd -i 'plus.*jakarta.*\.(woff2|woff)$' || true

Expected:

  • Step 1 returns no @import in website/src/app.css.
  • Step 2 shows @font-face entries.
  • Step 3 lists checked-in font files.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/app.css` at line 1, Remove the runtime `@import` from
website/src/app.css and replace it with self-hosted `@font-face` declarations for
"Plus Jakarta Sans" (regular/500/700/800) referencing checked-in WOFF/WOFF2
asset files (e.g., plus-jakarta-sans-400.woff2, -500.woff2, -700.woff2,
-800.woff2); ensure the CSS uses local font-family names and correct font-weight
mappings, add font-style: normal and font-display (swap) to each `@font-face`, and
commit the corresponding font files so the import-notation Stylelint error is
resolved and no external CDN call occurs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/release/sync-homebrew-cask.sh`:
- Around line 70-72: The DMG basename (DMG_BASENAME) can diverge from the actual
artifact name because it's currently derived from APP_VERSION; change the script
to derive DMG_BASENAME from DMG_PATH when DMG_PATH is set and use that unified
basename everywhere (the cask URL, the hash computation, and the filename
referenced later) so the cask hash is always computed from the same file
referenced by DMG_PATH; update the DMG_BASENAME assignment and any later uses
(e.g., where the cask URL and the shasum are produced) to reference this
DMG_BASENAME derived from DMG_PATH to ensure consistency between the artifact
used for hashing and the cask URL.

---

Duplicate comments:
In `@website/src/app.css`:
- Line 1: Remove the runtime `@import` from website/src/app.css and replace it
with self-hosted `@font-face` declarations for "Plus Jakarta Sans"
(regular/500/700/800) referencing checked-in WOFF/WOFF2 asset files (e.g.,
plus-jakarta-sans-400.woff2, -500.woff2, -700.woff2, -800.woff2); ensure the CSS
uses local font-family names and correct font-weight mappings, add font-style:
normal and font-display (swap) to each `@font-face`, and commit the corresponding
font files so the import-notation Stylelint error is resolved and no external
CDN call occurs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: fc7de71d-fca8-4ce6-b161-e6949eb6931d

📥 Commits

Reviewing files that changed from the base of the PR and between 7bf3894 and acada65.

📒 Files selected for processing (11)
  • Makefile
  • docs/astro.config.mjs
  • scripts/build-cloudflare-pages.sh
  • scripts/release/release-macos-dmg.sh
  • scripts/release/sync-homebrew-cask.sh
  • website/jsconfig.json
  • website/src/App.svelte
  • website/src/app.css
  • website/src/i18n/en/index.ts
  • website/src/i18n/i18n-types.ts
  • website/src/i18n/zh-CN/index.ts
✅ Files skipped from review due to trivial changes (3)
  • website/jsconfig.json
  • website/src/i18n/i18n-types.ts
  • website/src/i18n/en/index.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • website/src/i18n/zh-CN/index.ts
  • website/src/App.svelte
  • scripts/release/release-macos-dmg.sh

Comment on lines +70 to +72
RELEASE_TAG="${RELEASE_TAG:-v${APP_VERSION}}"
DMG_BASENAME="${DMG_BASENAME:-ServerBox-${APP_VERSION}}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use DMG_PATH as the source of truth for cask URL basename.

Line 71 can generate a basename that differs from the actual artifact at Line 87. When that happens, the cask hash is computed from one DMG but Line 95 points to a different filename, breaking install/update.

💡 Proposed fix
 RELEASE_TAG="${RELEASE_TAG:-v${APP_VERSION}}"
-DMG_BASENAME="${DMG_BASENAME:-ServerBox-${APP_VERSION}}"
+if [[ -z "${DMG_BASENAME:-}" ]]; then
+  if [[ -n "${DMG_PATH:-}" ]]; then
+    DMG_BASENAME="$(basename "$DMG_PATH" .dmg)"
+  else
+    DMG_BASENAME="ServerBox-${APP_VERSION}"
+  fi
+fi

Also applies to: 95-95

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/release/sync-homebrew-cask.sh` around lines 70 - 72, The DMG basename
(DMG_BASENAME) can diverge from the actual artifact name because it's currently
derived from APP_VERSION; change the script to derive DMG_BASENAME from DMG_PATH
when DMG_PATH is set and use that unified basename everywhere (the cask URL, the
hash computation, and the filename referenced later) so the cask hash is always
computed from the same file referenced by DMG_PATH; update the DMG_BASENAME
assignment and any later uses (e.g., where the cask URL and the shasum are
produced) to reference this DMG_BASENAME derived from DMG_PATH to ensure
consistency between the artifact used for hashing and the cask URL.

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 2 new potential issues.

View 4 additional findings in Devin Review.

Open in Devin Review

bun run build

cd "$ROOT_DIR/docs"
bun install
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Missing --frozen-lockfile for docs bun install in CI build script

In scripts/build-cloudflare-pages.sh, the website build uses bun install --frozen-lockfile (line 7) for reproducible installs, but the docs build on line 11 uses bare bun install. The docs directory has a bun.lock file, so this is inconsistent. Without --frozen-lockfile, bun install may resolve newer dependency versions within semver ranges and silently modify the lockfile, leading to non-reproducible Cloudflare Pages builds or unexpected breakage when a transitive dependency publishes a bad release.

Suggested change
bun install
bun install --frozen-lockfile
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread website/src/App.svelte
label: 'iOS / macOS',
sources: [
{ label: 'App Store', href: 'https://apps.apple.com/app/id1586449703' },
{ label: 'Homebrew Cask', command: 'brew install --cask server-box' },
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚩 Homebrew cask install command may require prior brew tap step

The website at App.svelte:39 shows brew install --cask server-box as the install command. However, sync-homebrew-cask.sh generates the cask to a custom tap at $HOME/proj/homebrew-taps, not the official homebrew/homebrew-cask repo. For this command to work, users would need to first run something like brew tap lollipopkit/taps (assuming the repo is published at github.com/lollipopkit/homebrew-taps). The command as shown would fail for users who haven't tapped the repo. This may be intentional if the cask is planned for submission to the official homebrew-cask repo.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 2 new potential issues.

View 6 additional findings in Devin Review.

Open in Devin Review

Komplette Benutzerabläufe testen (in `integration_test/`):

```dart
Im aktuellen Repository gibt es keine `integration_test/`-Suite. Fügen Sie Integrationstests nur hinzu, wenn eine Funktion End-to-End-Geräte- oder App-Flow-Abdeckung benötigt.dart
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Missing code fence opener in localized testing docs renders Dart code as plain paragraph text

In the German (and identically in es, fr, ja, zh) testing docs, the ```dart code fence opening was accidentally concatenated to the preceding paragraph text. Line 70 reads ...benötigt.dart where .dart is actually the language hint from a code fence that lost its triple-backtick delimiter. The closing ``` remains orphaned on line 82. This causes the Dart code example (lines 71–81) to render as raw inline text instead of a formatted code block.

Same bug in other locale files
  • docs/src/content/docs/es/development/testing.md:70
  • docs/src/content/docs/fr/development/testing.md:70
  • docs/src/content/docs/ja/development/testing.md:70
  • docs/src/content/docs/zh/development/testing.md:70

The English version (docs/src/content/docs/development/testing.md) correctly removed the code block entirely, so it's unaffected.

Prompt for agents
In five localized testing docs (de, es, fr, ja, zh), the code-fence opening triple-backtick-dart got concatenated to the end of the preceding paragraph line. For example, in docs/src/content/docs/de/development/testing.md line 70, the text ends with 'benötigt.dart' instead of 'benötigt.' followed by a blank line and then a proper code fence. The same pattern appears on line 70 of es, fr, ja, and zh equivalents. Either add a proper code fence opening (blank line then triple-backtick-dart) before the testWidgets code, or remove the orphaned code block entirely to match the English version which just says there is no integration_test suite.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

## Aus dem Quellcode bauen

Um Server Box aus dem Quellcode zu bauen, lesen Sie den Abschnitt [Bauen](/de/development/building/) in der Entwicklungsdokumentation.
Um Server Box aus dem Quellcode zu bauen, lesen Sie den Abschnitt [Bauen](/docs/development/building/) in der Entwicklungsdokumentation.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Localized installation pages link to English building page instead of locale-specific page

When adding the /docs base path prefix, the locale segment was dropped from the "Build from Source" link in 4 localized installation pages. For example, the German page (docs/src/content/docs/de/installation.mdx:55) links to /docs/development/building/ instead of /docs/de/development/building/. This navigates users to the English building page. The Chinese version at docs/src/content/docs/zh/installation.mdx:55 correctly uses /docs/zh/development/building/.

Same bug in other locale files
  • docs/src/content/docs/es/installation.mdx:55 — links to /docs/development/building/ instead of /docs/es/development/building/
  • docs/src/content/docs/fr/installation.mdx:55 — links to /docs/development/building/ instead of /docs/fr/development/building/
  • docs/src/content/docs/ja/installation.mdx:55 — links to /docs/development/building/ instead of /docs/ja/development/building/
Suggested change
Um Server Box aus dem Quellcode zu bauen, lesen Sie den Abschnitt [Bauen](/docs/development/building/) in der Entwicklungsdokumentation.
Um Server Box aus dem Quellcode zu bauen, lesen Sie den Abschnitt [Bauen](/docs/de/development/building/) in der Entwicklungsdokumentation.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
docs/src/content/docs/ja/advanced/bulk-import.md (1)

34-45: ⚠️ Potential issue | 🟡 Minor

Missing documentation for the optional id field.

The French version of this document (line 46 in docs/src/content/docs/fr/advanced/bulk-import.md) documents an optional id field, but this Japanese version does not include it. According to the code (lib/data/model/server/server_private_info.dart lines 57, 71-75), the id field is a valid optional field that auto-generates when missing or empty during import.

Consider adding a row to the fields table:

 | `pubKeyId` | いいえ | 秘密鍵レコードの ID(「非公開鍵」から取得 - 推奨) |
 | `tags` | いいえ | 整理用タグ |
 | `autoConnect` | いいえ | 起動時に自動接続 |
+| `id` | いいえ | 安定したサーバー識別子。省略または空の場合はインポート時に生成されます |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/content/docs/ja/advanced/bulk-import.md` around lines 34 - 45, The
table is missing the optional "id" field which the import code
(ServerPrivateInfo model in server_private_info.dart) accepts and which is
auto-generated when omitted or empty; update the fields table to add a row for
`id` marked as optional with a brief description like
"レコードの一意識別子(省略または空の場合はインポート時に自動生成)" so readers know they can supply an explicit
id or let the system generate one.
docs/src/content/docs/es/development/testing.md (1)

70-82: ⚠️ Potential issue | 🟠 Major

Fix malformed integration-test example block.

Line 70 contains stray app.dart, and the snippet at Lines 71-82 is missing an opening code fence. This breaks section rendering in Markdown/MDX.

🛠️ Proposed fix
-El repositorio actual no contiene una suite `integration_test/`. Añade pruebas de integración solo cuando una función necesite cobertura end-to-end de dispositivo o flujo completo de la app.dart
+El repositorio actual no contiene una suite `integration_test/`. Añade pruebas de integración solo cuando una función necesite cobertura end-to-end de dispositivo o flujo completo de la app.
+
+```dart
 testWidgets('flujo de agregar servidor', (tester) async {
   await tester.pumpWidget(MyApp());
@@
   await tester.enterText(find.byKey(Key('name')), 'Test Server');
   // ...
 });
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @docs/src/content/docs/es/development/testing.md around lines 70 - 82, Remove
the stray "app.dart" word and fix the malformed code fence for the integration
test example: add a proper opening triple-backtick with language identifier
(```dart) immediately before the testWidgets block and keep the existing closing
triple-backtick, so the example containing testWidgets('flujo de agregar
servidor', (tester) async { ... }), MyApp(), await tester.tap(...), and await
tester.enterText(find.byKey(Key('name')), 'Test Server'); is a single
well-formed fenced code block.


</details>

</blockquote></details>
<details>
<summary>docs/src/content/docs/de/development/testing.md (1)</summary><blockquote>

`70-82`: _⚠️ Potential issue_ | _🟠 Major_

**Repair the Integration Tests code-block delimiter.**

At Line 70, `dart` is appended to prose instead of opening a fenced block. With the closing fence at Line 82, markdown structure becomes invalid.


<details>
<summary>🛠️ Proposed fix</summary>

```diff
-Im aktuellen Repository gibt es keine `integration_test/`-Suite. Fügen Sie Integrationstests nur hinzu, wenn eine Funktion End-to-End-Geräte- oder App-Flow-Abdeckung benötigt.dart
+Im aktuellen Repository gibt es keine `integration_test/`-Suite. Fügen Sie Integrationstests nur hinzu, wenn eine Funktion End-to-End-Geräte- oder App-Flow-Abdeckung benötigt.
+```dart
 testWidgets('Server hinzufügen Ablauf', (tester) async {
   await tester.pumpWidget(MyApp());
@@
 });
 ```
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @docs/src/content/docs/de/development/testing.md around lines 70 - 82, The
markdown has "dart" appended to prose instead of an opening fenced code block,
breaking structure; fix by replacing that stray "dart" text with an opening code
fence "dart" before the testWidgets block so the example (starting with testWidgets('Server hinzufügen Ablauf', (tester) async { ... }), including references to MyApp, Icons.add and Key('name'), is properly fenced and closed by the existing closing "".


</details>

</blockquote></details>
<details>
<summary>docs/src/content/docs/zh/development/testing.md (1)</summary><blockquote>

`70-82`: _⚠️ Potential issue_ | _🟠 Major_

**Fix broken markdown code fence in the Integration Tests section.**

Line 70 appends `dart` as plain text but does not open a fenced block, while Line 82 closes one. This can break rendering of the remainder of the page.


<details>
<summary>🛠️ Proposed fix</summary>

```diff
-当前仓库没有 `integration_test/` 测试套件。只有当功能需要端到端设备或完整应用流程覆盖时,再新增集成测试。dart
+当前仓库没有 `integration_test/` 测试套件。只有当功能需要端到端设备或完整应用流程覆盖时,再新增集成测试。
+```dart
 testWidgets('添加服务器流程', (tester) async {
   await tester.pumpWidget(MyApp());
@@
 });
 ```
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @docs/src/content/docs/zh/development/testing.md around lines 70 - 82, The
markdown in the Integration Tests section has a broken code fence — the language
token "dart" is plain text instead of starting a fenced block, which breaks
rendering; update the snippet so the fenced block begins with dart before the testWidgets example and keep the closing after the test body (the code using
testWidgets, MyApp(), tester.tap/find.byIcon, enterText with Key('name'), etc.),
ensuring the code fence encloses the entire Dart snippet.


</details>

</blockquote></details>
<details>
<summary>docs/src/content/docs/fr/development/testing.md (1)</summary><blockquote>

`70-82`: _⚠️ Potential issue_ | _🟠 Major_

**Correct the malformed code-block opening in Integration Tests.**

At Line 70, `dart` is concatenated to the sentence instead of opening a fenced block. With only the closing fence at Line 82, rendering is broken.


<details>
<summary>🛠️ Proposed fix</summary>

```diff
-Le dépôt actuel ne contient pas de suite `integration_test/`. Ajoutez des tests d’intégration seulement lorsqu’une fonctionnalité nécessite une couverture end-to-end sur appareil ou flux applicatif complet.dart
+Le dépôt actuel ne contient pas de suite `integration_test/`. Ajoutez des tests d’intégration seulement lorsqu’une fonctionnalité nécessite une couverture end-to-end sur appareil ou flux applicatif complet.
+```dart
 testWidgets('flux d\'ajout de serveur', (tester) async {
   await tester.pumpWidget(MyApp());
@@
 });
 ```
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @docs/src/content/docs/fr/development/testing.md around lines 70 - 82, The
markdown has a malformed code block where the word "dart" is appended to the
preceding sentence instead of opening a fenced block; fix by inserting a proper
code-fence opener (dart) immediately before the test snippet so the block that contains testWidgets('flux d\'ajout de serveur', (tester) async { ... }), await tester.pumpWidget(MyApp()), await tester.tap(find.byIcon(Icons.add)), await tester.enterText(find.byKey(Key('name')), 'Test Server') and the closing render correctly; ensure only one opening ```dart is added and no stray text
remains on the same line as the paragraph.


</details>

</blockquote></details>
<details>
<summary>docs/src/content/docs/ja/development/testing.md (1)</summary><blockquote>

`70-82`: _⚠️ Potential issue_ | _🟠 Major_

**Integration section has an unbalanced markdown fence.**

Line 70 includes `dart` as text, but no opening ```dart fence exists before the snippet. The closing fence at Line 82 then mis-structures the document.


<details>
<summary>🛠️ Proposed fix</summary>

```diff
-現在のリポジトリには `integration_test/` スイートはありません。デバイス上の end-to-end やアプリ全体のフロー確認が必要な機能でのみ追加してください。dart
+現在のリポジトリには `integration_test/` スイートはありません。デバイス上の end-to-end やアプリ全体のフロー確認が必要な機能でのみ追加してください。
+```dart
 testWidgets('サーバー追加フロー', (tester) async {
   await tester.pumpWidget(MyApp());
@@
 });
 ```
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @docs/src/content/docs/ja/development/testing.md around lines 70 - 82, The
Markdown code block in the integration section is missing the opening dart fence which leaves the closing at the end unbalanced; add an opening fenced
code block (dart) immediately before the snippet that starts with testWidgets('サーバー追加フロー', (tester) async { and keep the existing closing
after the final }); so the entire testWidgets example (including await
tester.pumpWidget(MyApp());, await tester.tap(...), await tester.enterText(...),
etc.) is enclosed in a proper dart ... fenced block.


</details>

</blockquote></details>

</blockquote></details>
♻️ Duplicate comments (1)
website/src/App.svelte (1)

16-17: ⚠️ Potential issue | 🟡 Minor

Hard-coded English labels bypass locale switching.

Line 16 capability labels are rendered directly at Line 254, and Line 175 hard-codes Docs, so these stay English on non-English locales.

Also applies to: 175-175, 253-255

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/App.svelte` around lines 16 - 17, The capabilities array is
hard-coded in English (const capabilities) and the 'Docs' label is also inlined,
so both bypass locale switching; replace each literal in the capabilities array
with translated keys (e.g., use your i18n/translate function like
t('capabilities.statusChart'), t('capabilities.sshTerminal'), etc.) and change
the hard-coded 'Docs' string to use the same translate function (e.g.,
t('docs')). Ensure the component uses the translation function where
capabilities is consumed (the list rendering) so labels come from the locale
bundle, and add corresponding keys to your locale resource files.
🧹 Nitpick comments (2)
docs/src/content/docs/fr/advanced/bulk-import.md (1)

13-13: Optional: Minor French typographical improvements.

Static analysis flagged two minor French typography issues:

  • Line 13: Non-standard apostrophe character after "elles sont plus sûres"
  • Line 43: Spacing around the dash in "clés privées - recommandé"

These are minor stylistic issues and do not affect functionality.

Also applies to: 43-43

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/content/docs/fr/advanced/bulk-import.md` at line 13, Replace the
non‑standard apostrophe and fix dash spacing in the French copy: in the string
"Préférer les clés SSH (`pubKeyId`) au lieu de `pwd` - elles sont plus sûres"
replace the curly/non‑standard apostrophe with a standard straight/apostrophe
where needed and ensure the spacing around the hyphen in "clés privées -
recommandé" follows French typographic rules (use space‑hyphen‑space or an
en‑dash with thin spaces as your style guide requires) so both lines use
consistent, standard French punctuation.
docs/src/content/docs/zh/development/codegen.md (1)

24-28: Clarify the clean/rebuild flow to avoid redundant execution.

Current order runs build before clean, then runs build again. Consider presenting this as either a normal build flow or a separate “clean rebuild” flow.

📘 Proposed doc adjustment
-# 生成所有代码
-dart run build_runner build --delete-conflicting-outputs
-
 # 清理生成缓存
 dart run build_runner clean
 
-# 然后重新生成
+# 重新生成所有代码
 dart run build_runner build --delete-conflicting-outputs
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/content/docs/zh/development/codegen.md` around lines 24 - 28, Split
the current snippet into two clear flows: a "Normal build" section showing the
regular build command (dart run build_runner build --delete-conflicting-outputs)
and a separate "Clean rebuild" section that first runs dart run build_runner
clean and then dart run build_runner build --delete-conflicting-outputs; ensure
the clean/rebuild example explicitly orders clean before build and add short
headings or notes to avoid implying build is run twice.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/src/content/docs/zh/installation.mdx`:
- Line 55: The localized installation pages for German, Spanish, French, and
Japanese currently link to the English build doc; update the link in each file
so the route includes its locale prefix (e.g., change
/docs/development/building/ to /docs/de/development/building/ in the German
install file, /docs/es/development/building/ to /docs/es/development/building/
in Spanish, /docs/fr/development/building/ to /docs/fr/development/building/ in
French, and /docs/ja/development/building/ to /docs/ja/development/building/ in
Japanese) to match Astro's locale routing (defaultLocale: 'root') — note the
Chinese file docs/src/content/docs/zh/installation.mdx is already correct.

In `@README.md`:
- Around line 33-36: The iOS and macOS installation rows in the README table
violate markdownlint MD055 pipe style; update those two table rows (the iOS row
with "AppStore" link and the macOS row with "AppStore / brew install --cask
server-box") to use the same pipe style as the other rows by adding the leading
and trailing pipe characters and matching column separators (e.g., change " |
iOS | [AppStore](...)" to "| iOS | [AppStore](...) |" and similarly ensure the
macOS row ends with a trailing pipe).

---

Outside diff comments:
In `@docs/src/content/docs/de/development/testing.md`:
- Around line 70-82: The markdown has "dart" appended to prose instead of an
opening fenced code block, breaking structure; fix by replacing that stray
"dart" text with an opening code fence "```dart" before the testWidgets block so
the example (starting with testWidgets('Server hinzufügen Ablauf', (tester)
async { ... }), including references to MyApp, Icons.add and Key('name'), is
properly fenced and closed by the existing closing "```".

In `@docs/src/content/docs/es/development/testing.md`:
- Around line 70-82: Remove the stray "app.dart" word and fix the malformed code
fence for the integration test example: add a proper opening triple-backtick
with language identifier (```dart) immediately before the testWidgets block and
keep the existing closing triple-backtick, so the example containing
testWidgets('flujo de agregar servidor', (tester) async { ... }), MyApp(), await
tester.tap(...), and await tester.enterText(find.byKey(Key('name')), 'Test
Server'); is a single well-formed fenced code block.

In `@docs/src/content/docs/fr/development/testing.md`:
- Around line 70-82: The markdown has a malformed code block where the word
"dart" is appended to the preceding sentence instead of opening a fenced block;
fix by inserting a proper code-fence opener (```dart) immediately before the
test snippet so the block that contains testWidgets('flux d\'ajout de serveur',
(tester) async { ... }), await tester.pumpWidget(MyApp()), await
tester.tap(find.byIcon(Icons.add)), await
tester.enterText(find.byKey(Key('name')), 'Test Server') and the closing ```
render correctly; ensure only one opening ```dart is added and no stray text
remains on the same line as the paragraph.

In `@docs/src/content/docs/ja/advanced/bulk-import.md`:
- Around line 34-45: The table is missing the optional "id" field which the
import code (ServerPrivateInfo model in server_private_info.dart) accepts and
which is auto-generated when omitted or empty; update the fields table to add a
row for `id` marked as optional with a brief description like
"レコードの一意識別子(省略または空の場合はインポート時に自動生成)" so readers know they can supply an explicit
id or let the system generate one.

In `@docs/src/content/docs/ja/development/testing.md`:
- Around line 70-82: The Markdown code block in the integration section is
missing the opening ```dart fence which leaves the closing ``` at the end
unbalanced; add an opening fenced code block (```dart) immediately before the
snippet that starts with testWidgets('サーバー追加フロー', (tester) async { and keep the
existing closing ``` after the final }); so the entire testWidgets example
(including await tester.pumpWidget(MyApp());, await tester.tap(...), await
tester.enterText(...), etc.) is enclosed in a proper ```dart ... ``` fenced
block.

In `@docs/src/content/docs/zh/development/testing.md`:
- Around line 70-82: The markdown in the Integration Tests section has a broken
code fence — the language token "dart" is plain text instead of starting a
fenced block, which breaks rendering; update the snippet so the fenced block
begins with ```dart before the testWidgets example and keep the closing ```
after the test body (the code using testWidgets, MyApp(),
tester.tap/find.byIcon, enterText with Key('name'), etc.), ensuring the code
fence encloses the entire Dart snippet.

---

Duplicate comments:
In `@website/src/App.svelte`:
- Around line 16-17: The capabilities array is hard-coded in English (const
capabilities) and the 'Docs' label is also inlined, so both bypass locale
switching; replace each literal in the capabilities array with translated keys
(e.g., use your i18n/translate function like t('capabilities.statusChart'),
t('capabilities.sshTerminal'), etc.) and change the hard-coded 'Docs' string to
use the same translate function (e.g., t('docs')). Ensure the component uses the
translation function where capabilities is consumed (the list rendering) so
labels come from the locale bundle, and add corresponding keys to your locale
resource files.

---

Nitpick comments:
In `@docs/src/content/docs/fr/advanced/bulk-import.md`:
- Line 13: Replace the non‑standard apostrophe and fix dash spacing in the
French copy: in the string "Préférer les clés SSH (`pubKeyId`) au lieu de `pwd`
- elles sont plus sûres" replace the curly/non‑standard apostrophe with a
standard straight/apostrophe where needed and ensure the spacing around the
hyphen in "clés privées - recommandé" follows French typographic rules (use
space‑hyphen‑space or an en‑dash with thin spaces as your style guide requires)
so both lines use consistent, standard French punctuation.

In `@docs/src/content/docs/zh/development/codegen.md`:
- Around line 24-28: Split the current snippet into two clear flows: a "Normal
build" section showing the regular build command (dart run build_runner build
--delete-conflicting-outputs) and a separate "Clean rebuild" section that first
runs dart run build_runner clean and then dart run build_runner build
--delete-conflicting-outputs; ensure the clean/rebuild example explicitly orders
clean before build and add short headings or notes to avoid implying build is
run twice.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 1cbfe035-49d1-429e-8a37-f15a15e9a498

📥 Commits

Reviewing files that changed from the base of the PR and between acada65 and b553f47.

📒 Files selected for processing (46)
  • README.md
  • README_zh.md
  • docs/src/content/docs/advanced/bulk-import.md
  • docs/src/content/docs/de/advanced/bulk-import.md
  • docs/src/content/docs/de/development/architecture.md
  • docs/src/content/docs/de/development/codegen.md
  • docs/src/content/docs/de/development/testing.md
  • docs/src/content/docs/de/index.mdx
  • docs/src/content/docs/de/installation.mdx
  • docs/src/content/docs/de/principles/architecture.md
  • docs/src/content/docs/development/architecture.md
  • docs/src/content/docs/development/codegen.md
  • docs/src/content/docs/development/testing.md
  • docs/src/content/docs/es/advanced/bulk-import.md
  • docs/src/content/docs/es/development/architecture.md
  • docs/src/content/docs/es/development/codegen.md
  • docs/src/content/docs/es/development/testing.md
  • docs/src/content/docs/es/index.mdx
  • docs/src/content/docs/es/installation.mdx
  • docs/src/content/docs/fr/advanced/bulk-import.md
  • docs/src/content/docs/fr/development/architecture.md
  • docs/src/content/docs/fr/development/codegen.md
  • docs/src/content/docs/fr/development/testing.md
  • docs/src/content/docs/fr/index.mdx
  • docs/src/content/docs/fr/installation.mdx
  • docs/src/content/docs/index.mdx
  • docs/src/content/docs/installation.mdx
  • docs/src/content/docs/ja/advanced/bulk-import.md
  • docs/src/content/docs/ja/development/architecture.md
  • docs/src/content/docs/ja/development/codegen.md
  • docs/src/content/docs/ja/development/testing.md
  • docs/src/content/docs/ja/index.mdx
  • docs/src/content/docs/ja/installation.mdx
  • docs/src/content/docs/ja/principles/architecture.md
  • docs/src/content/docs/principles/architecture.md
  • docs/src/content/docs/zh/advanced/bulk-import.md
  • docs/src/content/docs/zh/development/architecture.md
  • docs/src/content/docs/zh/development/codegen.md
  • docs/src/content/docs/zh/development/testing.md
  • docs/src/content/docs/zh/index.mdx
  • docs/src/content/docs/zh/installation.mdx
  • docs/src/content/docs/zh/principles/architecture.md
  • website/src/App.svelte
  • website/src/i18n/en/index.ts
  • website/src/i18n/i18n-types.ts
  • website/src/i18n/zh-CN/index.ts
✅ Files skipped from review due to trivial changes (20)
  • docs/src/content/docs/principles/architecture.md
  • docs/src/content/docs/de/principles/architecture.md
  • docs/src/content/docs/development/architecture.md
  • website/src/i18n/en/index.ts
  • docs/src/content/docs/zh/index.mdx
  • docs/src/content/docs/de/index.mdx
  • docs/src/content/docs/ja/principles/architecture.md
  • docs/src/content/docs/zh/principles/architecture.md
  • docs/src/content/docs/fr/index.mdx
  • docs/src/content/docs/ja/development/architecture.md
  • docs/src/content/docs/zh/development/architecture.md
  • docs/src/content/docs/index.mdx
  • docs/src/content/docs/es/development/architecture.md
  • docs/src/content/docs/de/development/architecture.md
  • website/src/i18n/zh-CN/index.ts
  • docs/src/content/docs/de/advanced/bulk-import.md
  • docs/src/content/docs/es/advanced/bulk-import.md
  • docs/src/content/docs/advanced/bulk-import.md
  • docs/src/content/docs/zh/advanced/bulk-import.md
  • website/src/i18n/i18n-types.ts

## 从源码构建

要从源码构建 Server Box,请参阅开发文档中的[构建](/zh/development/building)部分。
要从源码构建 Server Box,请参阅开发文档中的[构建](/docs/zh/development/building/)部分。
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify how building links are referenced across localized installation docs
rg -n 'development/building' docs/src/content/docs

# Inspect available building pages by locale/path
fd -i 'building.mdx' docs/src/content/docs

# Check docs base and i18n-related config
rg -n "base:\\s*'/docs'|base:\\s*\"/docs\"|i18n|locale|locales|defaultLocale" docs/astro.config.mjs

Repository: lollipopkit/flutter_server_box

Length of output: 1122


🏁 Script executed:

# Get full astro.config.mjs to see complete i18n/locale configuration
cat docs/astro.config.mjs

Repository: lollipopkit/flutter_server_box

Length of output: 5890


🏁 Script executed:

# Check for building.mdx files across all locales
find docs/src/content/docs -name 'building.mdx' -type f

Repository: lollipopkit/flutter_server_box

Length of output: 56


🏁 Script executed:

# Check the development directory structure
ls -la docs/src/content/docs/*/development/

Repository: lollipopkit/flutter_server_box

Length of output: 2663


The Chinese file is correct; other localized installation files have incorrect links.

With Astro's locale routing (configured as defaultLocale: 'root'), links in localized files must include their locale prefix. The Chinese file's /docs/zh/development/building/ is correct. However, the German, Spanish, French, and Japanese installation files incorrectly use /docs/development/building/ (the English route) instead of their respective locale-prefixed routes:

  • German (de): should be /docs/de/development/building/
  • Spanish (es): should be /docs/es/development/building/
  • French (fr): should be /docs/fr/development/building/
  • Japanese (ja): should be /docs/ja/development/building/
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/content/docs/zh/installation.mdx` at line 55, The localized
installation pages for German, Spanish, French, and Japanese currently link to
the English build doc; update the link in each file so the route includes its
locale prefix (e.g., change /docs/development/building/ to
/docs/de/development/building/ in the German install file,
/docs/es/development/building/ to /docs/es/development/building/ in Spanish,
/docs/fr/development/building/ to /docs/fr/development/building/ in French, and
/docs/ja/development/building/ to /docs/ja/development/building/ in Japanese) to
match Astro's locale routing (defaultLocale: 'root') — note the Chinese file
docs/src/content/docs/zh/installation.mdx is already correct.

Comment thread README.md
Comment on lines +33 to +36
| iOS | [AppStore](https://apps.apple.com/app/id1586449703) |
| macOS | [AppStore](https://apps.apple.com/app/id1586449703) / brew install --cask server-box |
| Android | [GitHub](https://github.com/lollipopkit/flutter_server_box/releases) / [CDN](https://cdn.lpkt.cn/serverbox/pkg/?sort=time&order=desc&layout=grid) / [F-Droid](https://f-droid.org/packages/tech.lolli.toolbox) / [OpenAPK](https://www.openapk.net/serverbox/tech.lolli.toolbox/) |
| Linux / Windows | [GitHub](https://github.com/lollipopkit/flutter_server_box/releases) / [CDN](https://cdn.lpkt.cn/serverbox/pkg/?sort=time&order=desc&layout=grid) |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix markdownlint MD055 table pipe style on installation rows.

Line 33 and Line 34 currently violate the configured table pipe style; this can cause lint noise/failures.

🔧 Proposed markdownlint-compliant table format
-|Platform| From|
-|--|--|
-| iOS | [AppStore](https://apps.apple.com/app/id1586449703) |
-| macOS | [AppStore](https://apps.apple.com/app/id1586449703) / brew install --cask server-box |
-| Android | [GitHub](https://github.com/lollipopkit/flutter_server_box/releases) / [CDN](https://cdn.lpkt.cn/serverbox/pkg/?sort=time&order=desc&layout=grid) / [F-Droid](https://f-droid.org/packages/tech.lolli.toolbox) / [OpenAPK](https://www.openapk.net/serverbox/tech.lolli.toolbox/) |
-| Linux / Windows | [GitHub](https://github.com/lollipopkit/flutter_server_box/releases) / [CDN](https://cdn.lpkt.cn/serverbox/pkg/?sort=time&order=desc&layout=grid) |
+Platform | From
+-- | --
+iOS | [AppStore](https://apps.apple.com/app/id1586449703)
+macOS | [AppStore](https://apps.apple.com/app/id1586449703) / brew install --cask server-box
+Android | [GitHub](https://github.com/lollipopkit/flutter_server_box/releases) / [CDN](https://cdn.lpkt.cn/serverbox/pkg/?sort=time&order=desc&layout=grid) / [F-Droid](https://f-droid.org/packages/tech.lolli.toolbox) / [OpenAPK](https://www.openapk.net/serverbox/tech.lolli.toolbox/)
+Linux / Windows | [GitHub](https://github.com/lollipopkit/flutter_server_box/releases) / [CDN](https://cdn.lpkt.cn/serverbox/pkg/?sort=time&order=desc&layout=grid)
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 33-33: Table pipe style
Expected: no_leading_or_trailing; Actual: leading_and_trailing; Unexpected leading pipe

(MD055, table-pipe-style)


[warning] 33-33: Table pipe style
Expected: no_leading_or_trailing; Actual: leading_and_trailing; Unexpected trailing pipe

(MD055, table-pipe-style)


[warning] 34-34: Table pipe style
Expected: no_leading_or_trailing; Actual: leading_and_trailing; Unexpected leading pipe

(MD055, table-pipe-style)


[warning] 34-34: Table pipe style
Expected: no_leading_or_trailing; Actual: leading_and_trailing; Unexpected trailing pipe

(MD055, table-pipe-style)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` around lines 33 - 36, The iOS and macOS installation rows in the
README table violate markdownlint MD055 pipe style; update those two table rows
(the iOS row with "AppStore" link and the macOS row with "AppStore / brew
install --cask server-box") to use the same pipe style as the other rows by
adding the leading and trailing pipe characters and matching column separators
(e.g., change " | iOS | [AppStore](...)" to "| iOS | [AppStore](...) |" and
similarly ensure the macOS row ends with a trailing pipe).

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
website/src/App.svelte (1)

16-16: ⚠️ Potential issue | 🟡 Minor

Capability badges still bypass i18n.

capabilities is still a hard-coded English array and the template renders each item verbatim, so this section stays English on every non-English locale. Store translation keys here and resolve them through $LL at render time.

Also applies to: 252-255

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/App.svelte` at line 16, The capabilities array is hard-coded in
English; change it to contain translation keys (e.g. 'capabilities.statusChart',
'capabilities.sshTerminal', etc.) instead of literal English strings in the
const capabilities declaration, and update the template that renders
capabilities to call the localization function $LL with each key (e.g. $LL(key)
or $LL(key)() depending on how $LL is used) so badges display translated text;
apply the same change to the other occurrences referenced (the similar
arrays/uses around the other capability blocks).
🧹 Nitpick comments (4)
docs/src/content/docs/fr/installation.mdx (2)

51-51: Use a more natural phrase for watchOS availability.

Line 51 reads better in French with “incluse dans l’application iOS” instead of “en tant que partie de”.

💡 Suggested diff
-Disponible sur l'**[App Store](https://apps.apple.com/app/id1586449703)** en tant que partie de l'application iOS.
+Disponible sur l'**[App Store](https://apps.apple.com/app/id1586449703)**, incluse dans l'application iOS.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/content/docs/fr/installation.mdx` at line 51, The phrase "en tant
que partie de" on Line 51 should be replaced with a more natural French phrasing
for watchOS availability; update the sentence that currently reads "Disponible
sur l'**[App Store](https://apps.apple.com/app/id1586449703)** en tant que
partie de l'application iOS." to use "incluse dans l’application iOS" instead so
the text reads "Disponible sur l'**[App
Store](https://apps.apple.com/app/id1586449703)** incluse dans l’application
iOS."

20-20: Prefer more idiomatic French wording for readability.

Line 20 is correct semantically, but the adverb placement is a bit unnatural for native reading flow.

💡 Suggested diff
-- **[F-Droid](https://f-droid.org/packages/tech.lolli.toolbox)** - Pour les utilisateurs qui préfèrent les sources exclusivement FOSS
+- **[F-Droid](https://f-droid.org/packages/tech.lolli.toolbox)** - Pour les utilisateurs qui préfèrent exclusivement les sources FOSS
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/content/docs/fr/installation.mdx` at line 20, Remplace la phrase
actuelle "**[F-Droid](https://f-droid.org/packages/tech.lolli.toolbox)** - Pour
les utilisateurs qui préfèrent les sources exclusivement FOSS" par une
formulation plus idiomatique telle que
"**[F-Droid](https://f-droid.org/packages/tech.lolli.toolbox)** - Pour les
utilisateurs préférant uniquement des sources FOSS" (ou alternativement
"préférant exclusivement des sources FOSS") pour améliorer le placement de
l'adverbe et la fluidité en français.
docs/src/content/docs/fr/advanced/bulk-import.md (1)

13-13: Optional: French typography conventions.

The static analysis tool suggests using curly apostrophes (') instead of straight apostrophes (') and em-dashes instead of hyphens in certain contexts. However, for technical Markdown documentation, straight apostrophes and hyphens are perfectly acceptable and more portable across different rendering engines.

Also applies to: 43-43

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/content/docs/fr/advanced/bulk-import.md` at line 13, The reviewer
flagged French typography (curly apostrophes and em-dashes) in the sentence
"Préférer les clés SSH (`pubKeyId`) au lieu de `pwd` - elles sont plus sûres";
leave the technical Markdown punctuation as-is for portability: keep straight
apostrophes and the hyphen (not convert to curly quotes or em-dash) and ensure
the same treatment is applied to the other instance noted (the occurrence around
the same sentence). Locate the string containing "Préférer les clés SSH", the
inline code tokens `pubKeyId` and `pwd`, and update nothing except confirming
consistency across both occurrences.
website/src/lib/i18n.ts (1)

23-26: Use the existing locale type guard instead of cast-based checks.

normalizeLocale currently relies on locale as Locales. Reusing isLocale from website/src/i18n/i18n-util.ts keeps one validation path and removes unsafe casts.

♻️ Proposed refactor
-import { baseLocale, locales as generatedLocales } from '../i18n/i18n-util'
+import { baseLocale, isLocale, locales as generatedLocales } from '../i18n/i18n-util'
...
 export function normalizeLocale(locale: string | null | undefined): Locales {
   if (!locale) return defaultLocale
-  if (generatedLocales.includes(locale as Locales)) return locale as Locales
+  if (isLocale(locale)) return locale
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/lib/i18n.ts` around lines 23 - 26, normalizeLocale uses an unsafe
cast (locale as Locales) and generatedLocales.includes; replace that with the
existing type guard isLocale from i18n-util.ts: import isLocale and use if
(isLocale(locale)) return locale; otherwise return defaultLocale; keep
references to normalizeLocale, isLocale, generatedLocales and defaultLocale to
locate and update the logic without introducing casts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@README_zh.md`:
- Around line 33-34: Two table rows ("iOS" and "macOS" entries) use
leading/trailing pipe characters while the rest of the table uses compact style,
triggering markdownlint MD055; remove the leading and trailing pipe characters
from those two rows so they match the compact table format (i.e., make the "iOS"
and "macOS" rows omit the starting and ending | characters) to satisfy the
linter.

In `@website/src/App.svelte`:
- Around line 102-107: The applyLocale function currently calls
localStorage.setItem unguarded which can throw and disrupt locale application;
modify applyLocale (referencing applyLocale, loadLocale, setLocale, and
localeStorageKey) to make persistence best-effort by wrapping the
localStorage.setItem(localeStorageKey, nextLocale) call in a try/catch and
swallow or log the error (do not rethrow) so that loadLocale and setLocale
always complete even when storage is unavailable.
- Around line 151-163: The function copyCommand currently sets copiedCommand
before awaiting navigator.clipboard.writeText, leaving copiedCommand set on
failures; move the success-state assignment so copiedCommand is set only after
the await resolves (inside the try, after writeText completes) and in the catch
block explicitly clear copiedCommand and set copyFallbackCommand before invoking
window.prompt; update references to copiedCommand and copyFallbackCommand inside
copyCommand (and the timeout that clears the success state) so the timeout is
scheduled only after the successful write.

---

Duplicate comments:
In `@website/src/App.svelte`:
- Line 16: The capabilities array is hard-coded in English; change it to contain
translation keys (e.g. 'capabilities.statusChart', 'capabilities.sshTerminal',
etc.) instead of literal English strings in the const capabilities declaration,
and update the template that renders capabilities to call the localization
function $LL with each key (e.g. $LL(key) or $LL(key)() depending on how $LL is
used) so badges display translated text; apply the same change to the other
occurrences referenced (the similar arrays/uses around the other capability
blocks).

---

Nitpick comments:
In `@docs/src/content/docs/fr/advanced/bulk-import.md`:
- Line 13: The reviewer flagged French typography (curly apostrophes and
em-dashes) in the sentence "Préférer les clés SSH (`pubKeyId`) au lieu de `pwd`
- elles sont plus sûres"; leave the technical Markdown punctuation as-is for
portability: keep straight apostrophes and the hyphen (not convert to curly
quotes or em-dash) and ensure the same treatment is applied to the other
instance noted (the occurrence around the same sentence). Locate the string
containing "Préférer les clés SSH", the inline code tokens `pubKeyId` and `pwd`,
and update nothing except confirming consistency across both occurrences.

In `@docs/src/content/docs/fr/installation.mdx`:
- Line 51: The phrase "en tant que partie de" on Line 51 should be replaced with
a more natural French phrasing for watchOS availability; update the sentence
that currently reads "Disponible sur l'**[App
Store](https://apps.apple.com/app/id1586449703)** en tant que partie de
l'application iOS." to use "incluse dans l’application iOS" instead so the text
reads "Disponible sur l'**[App Store](https://apps.apple.com/app/id1586449703)**
incluse dans l’application iOS."
- Line 20: Remplace la phrase actuelle
"**[F-Droid](https://f-droid.org/packages/tech.lolli.toolbox)** - Pour les
utilisateurs qui préfèrent les sources exclusivement FOSS" par une formulation
plus idiomatique telle que
"**[F-Droid](https://f-droid.org/packages/tech.lolli.toolbox)** - Pour les
utilisateurs préférant uniquement des sources FOSS" (ou alternativement
"préférant exclusivement des sources FOSS") pour améliorer le placement de
l'adverbe et la fluidité en français.

In `@website/src/lib/i18n.ts`:
- Around line 23-26: normalizeLocale uses an unsafe cast (locale as Locales) and
generatedLocales.includes; replace that with the existing type guard isLocale
from i18n-util.ts: import isLocale and use if (isLocale(locale)) return locale;
otherwise return defaultLocale; keep references to normalizeLocale, isLocale,
generatedLocales and defaultLocale to locate and update the logic without
introducing casts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 97ed997f-5ce1-45d8-8d66-23fa1410e56e

📥 Commits

Reviewing files that changed from the base of the PR and between b553f47 and dd059d0.

📒 Files selected for processing (27)
  • README.md
  • README_zh.md
  • docs/src/content/docs/de/installation.mdx
  • docs/src/content/docs/es/development/testing.md
  • docs/src/content/docs/es/installation.mdx
  • docs/src/content/docs/fr/advanced/bulk-import.md
  • docs/src/content/docs/fr/installation.mdx
  • docs/src/content/docs/ja/advanced/bulk-import.md
  • docs/src/content/docs/ja/installation.mdx
  • docs/src/content/docs/zh/development/codegen.md
  • website/index.html
  • website/src/App.svelte
  • website/src/i18n/en/index.ts
  • website/src/i18n/es/index.ts
  • website/src/i18n/fr/index.ts
  • website/src/i18n/i18n-types.ts
  • website/src/i18n/i18n-util.async.ts
  • website/src/i18n/i18n-util.sync.ts
  • website/src/i18n/i18n-util.ts
  • website/src/i18n/it/index.ts
  • website/src/i18n/ja/index.ts
  • website/src/i18n/kr/index.ts
  • website/src/i18n/zh-CN/index.ts
  • website/src/lib/i18n.ts
  • website/src/lib/utils.ts
  • website/src/main.ts
  • website/tsconfig.json
✅ Files skipped from review due to trivial changes (5)
  • website/src/i18n/en/index.ts
  • website/src/i18n/fr/index.ts
  • website/tsconfig.json
  • website/src/i18n/zh-CN/index.ts
  • website/src/i18n/i18n-util.sync.ts
🚧 Files skipped from review as they are similar to previous changes (8)
  • website/index.html
  • website/src/i18n/i18n-util.async.ts
  • docs/src/content/docs/ja/advanced/bulk-import.md
  • README.md
  • docs/src/content/docs/es/development/testing.md
  • website/src/i18n/i18n-util.ts
  • docs/src/content/docs/es/installation.mdx
  • docs/src/content/docs/ja/installation.mdx

Comment thread README_zh.md
Comment on lines +33 to +34
| iOS | [AppStore](https://apps.apple.com/app/id1586449703) |
| macOS | [AppStore](https://apps.apple.com/app/id1586449703) / brew install --cask server-box |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix table row pipe style to satisfy markdownlint MD055.

Line 33 and Line 34 use leading/trailing pipes, but this table is otherwise in compact style. This will keep lint warnings active.

💡 Suggested diff
-| iOS | [AppStore](https://apps.apple.com/app/id1586449703) |
-| macOS | [AppStore](https://apps.apple.com/app/id1586449703) / brew install --cask server-box |
+iOS | [AppStore](https://apps.apple.com/app/id1586449703)
+macOS | [AppStore](https://apps.apple.com/app/id1586449703) / brew install --cask server-box
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 33-33: Table pipe style
Expected: no_leading_or_trailing; Actual: leading_and_trailing; Unexpected leading pipe

(MD055, table-pipe-style)


[warning] 33-33: Table pipe style
Expected: no_leading_or_trailing; Actual: leading_and_trailing; Unexpected trailing pipe

(MD055, table-pipe-style)


[warning] 34-34: Table pipe style
Expected: no_leading_or_trailing; Actual: leading_and_trailing; Unexpected leading pipe

(MD055, table-pipe-style)


[warning] 34-34: Table pipe style
Expected: no_leading_or_trailing; Actual: leading_and_trailing; Unexpected trailing pipe

(MD055, table-pipe-style)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README_zh.md` around lines 33 - 34, Two table rows ("iOS" and "macOS"
entries) use leading/trailing pipe characters while the rest of the table uses
compact style, triggering markdownlint MD055; remove the leading and trailing
pipe characters from those two rows so they match the compact table format
(i.e., make the "iOS" and "macOS" rows omit the starting and ending |
characters) to satisfy the linter.

Comment thread website/src/App.svelte
Comment on lines +102 to +107
function applyLocale(nextLocale) {
locale = nextLocale
loadLocale(nextLocale)
setLocale(nextLocale)
localStorage.setItem(localeStorageKey, nextLocale)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, locate the App.svelte file
find . -name "App.svelte" -type f

Repository: lollipopkit/flutter_server_box

Length of output: 99


🏁 Script executed:

# Read the relevant section of App.svelte around lines 102-107
cat -n website/src/App.svelte | head -130 | tail -40

Repository: lollipopkit/flutter_server_box

Length of output: 1334


🏁 Script executed:

# Search for all occurrences of applyLocale in the codebase
rg "applyLocale" -B 2 -A 2

Repository: lollipopkit/flutter_server_box

Length of output: 847


🏁 Script executed:

# Search for localStorage usage patterns in the codebase to understand error handling
rg "localStorage" -B 1 -A 1

Repository: lollipopkit/flutter_server_box

Length of output: 423


Make locale persistence best-effort.

If localStorage.setItem() throws here, the onMount initialization and locale change handlers can fail even though loadLocale() and setLocale() already succeeded. Wrap the persistence write so locale application still works when storage is unavailable (private browsing mode, quota exceeded, or restricted contexts).

Proposed fix
  function applyLocale(nextLocale) {
    locale = nextLocale
    loadLocale(nextLocale)
    setLocale(nextLocale)
-   localStorage.setItem(localeStorageKey, nextLocale)
+   try {
+     localStorage.setItem(localeStorageKey, nextLocale)
+   } catch {
+     // Ignore storage failures; locale switching should still work.
+   }
  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function applyLocale(nextLocale) {
locale = nextLocale
loadLocale(nextLocale)
setLocale(nextLocale)
localStorage.setItem(localeStorageKey, nextLocale)
}
function applyLocale(nextLocale) {
locale = nextLocale
loadLocale(nextLocale)
setLocale(nextLocale)
try {
localStorage.setItem(localeStorageKey, nextLocale)
} catch {
// Ignore storage failures; locale switching should still work.
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/src/App.svelte` around lines 102 - 107, The applyLocale function
currently calls localStorage.setItem unguarded which can throw and disrupt
locale application; modify applyLocale (referencing applyLocale, loadLocale,
setLocale, and localeStorageKey) to make persistence best-effort by wrapping the
localStorage.setItem(localeStorageKey, nextLocale) call in a try/catch and
swallow or log the error (do not rethrow) so that loadLocale and setLocale
always complete even when storage is unavailable.

Comment thread website/src/App.svelte
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 6 additional findings in Devin Review.

Open in Devin Review

bun run build

cd "$ROOT_DIR/docs"
bun install
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚩 Cloudflare Pages build uses --frozen-lockfile for website but not for docs

In scripts/build-cloudflare-pages.sh, line 7 uses bun install --frozen-lockfile for the website, but line 11 uses bun install (without --frozen-lockfile) for the docs. Both directories have bun.lock files. Without --frozen-lockfile, the docs build could install different dependency versions than what's locked, potentially causing non-reproducible CI builds.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

coderabbitai[bot]

This comment was marked as resolved.

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 4 new potential issues.

View 7 additional findings in Devin Review.

Open in Devin Review

Comment thread website/src/App.svelte
syncLocaleToUrl,
} from './lib/i18n'

const capabilities = ['Status chart', 'SSH Terminal', 'SFTP', 'Docker', 'Process', 'Systemd', 'S.M.A.R.T', 'GPU', 'Sensors', 'Push', 'Home Widget', 'watchOS']
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Capabilities badges hardcoded in English — translations exist but are never used

The capabilities array at website/src/App.svelte:16 is a hardcoded English array (['Status chart', 'SSH Terminal', …]). The template at line 254-256 renders these strings directly. However, translated equivalents exist in every locale file (e.g., website/src/i18n/zh-CN/index.ts:67-80 has '状态图表', '推送', '桌面小组件', etc.; website/src/i18n/ja/index.ts:68-80 has '状態チャート', '通知', 'ホームウィジェット', etc.). These capabilities.items translations are never wired up, so non-English visitors always see English-only capability badges while every other section on the page is properly localized.

Prompt for agents
In website/src/App.svelte, the capabilities array on line 16 is hardcoded in English. Instead, the code should use the i18n keys from capabilities.items which have translations in all locale files.

The current code:
  const capabilities = ['Status chart', 'SSH Terminal', ...]
and the template:
  {#each capabilities as item}
    <span class="protocol-badge">{item}</span>
  {/each}

Should be changed to use the translation keys. One approach is to define an array of the item keys:
  const capabilityKeys = ['statusChart', 'sshTerminal', 'sftp', 'docker', 'process', 'systemd', 'smart', 'gpu', 'sensors', 'push', 'homeWidget', 'watchos']

And in the template use:
  {#each capabilityKeys as key}
    <span class="protocol-badge">{$LL.capabilities.items[key]()}</span>
  {/each}

This would correctly use the translations from capabilities.items in each locale file (en/index.ts, zh-CN/index.ts, ja/index.ts, fr/index.ts, es/index.ts, kr/index.ts, it/index.ts).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Tester des flux utilisateurs complets (dans `integration_test/`) :

```dart
Le dépôt actuel ne contient pas de suite `integration_test/`. Ajoutez des tests d’intégration seulement lorsqu’une fonctionnalité nécessite une couverture end-to-end sur appareil ou flux applicatif complet.dart
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Missing code fence in French testing docs — .dart merged into paragraph text

The markdown code fence ```dart was corrupted into .dart appended to the end of the paragraph at line 70. This causes the subsequent Dart code example (testWidgets(…)) to render as plain text instead of a syntax-highlighted code block. The closing ``` at line 82 is still present, so the rest of the document below the closing fence is also misrendered. The English (docs/src/content/docs/development/testing.md:70) and Spanish versions are correct (they omit the code block entirely).

Suggested change
Le dépôt actuel ne contient pas de suite `integration_test/`. Ajoutez des tests dintégration seulement lorsquune fonctionnalité nécessite une couverture end-to-end sur appareil ou flux applicatif complet.dart
Le dépôt actuel ne contient pas de suite `integration_test/`. Ajoutez des tests d'intégration seulement lorsqu'une fonctionnalité nécessite une couverture end-to-end sur appareil ou flux applicatif complet.
```dart
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

完全なユーザーフローのテスト (`integration_test/` 内):

```dart
現在のリポジトリには `integration_test/` スイートはありません。デバイス上の end-to-end やアプリ全体のフロー確認が必要な機能でのみ追加してください。dart
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Missing code fence in Japanese testing docs — .dart merged into paragraph text

Same issue: the ```dart code fence was corrupted into .dart appended to the paragraph at docs/src/content/docs/ja/development/testing.md:70. The Dart code block that follows renders as plain text.

Suggested change
現在のリポジトリには `integration_test/` スイートはありません。デバイス上の end-to-end やアプリ全体のフロー確認が必要な機能でのみ追加してください。dart
現在のリポジトリには `integration_test/` スイートはありません。デバイス上の end-to-end やアプリ全体のフロー確認が必要な機能でのみ追加してください。
```dart
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

测试完整的用户流程(位于 `integration_test/`):

```dart
当前仓库没有 `integration_test/` 测试套件。只有当功能需要端到端设备或完整应用流程覆盖时,再新增集成测试。dart
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Missing code fence in Chinese testing docs — .dart merged into paragraph text

Same issue: the ```dart code fence was corrupted into .dart appended to the paragraph at docs/src/content/docs/zh/development/testing.md:70. The Dart code block that follows renders as plain text.

Suggested change
当前仓库没有 `integration_test/` 测试套件。只有当功能需要端到端设备或完整应用流程覆盖时,再新增集成测试。dart
当前仓库没有 `integration_test/` 测试套件。只有当功能需要端到端设备或完整应用流程覆盖时,再新增集成测试。
```dart
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@lollipopkit lollipopkit merged commit f52eac6 into main Apr 25, 2026
2 of 3 checks passed
@lollipopkit lollipopkit deleted the lollipopkit/issue1137 branch April 25, 2026 12:46
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 2 new potential issues.

View 7 additional findings in Devin Review.

Open in Devin Review

Comment thread Makefile
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚩 Makefile gen-build-clean target still uses invalid --clean flag despite docs update

The PR updates documentation in multiple languages (e.g., docs/src/content/docs/development/codegen.md:24-28) to recommend dart run build_runner clean followed by dart run build_runner build --delete-conflicting-outputs as two separate commands. However, the Makefile gen-build-clean target at Makefile:94-95 still uses the old single-command form dart run build_runner build --delete-conflicting-outputs --clean. The --clean flag is not a valid option for build_runner build; the correct approach is build_runner clean as a separate subcommand. This is a pre-existing issue, but the PR's doc changes explicitly corrected the guidance without updating the Makefile target to match.

(Refers to lines 94-95)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread README_zh.md
Comment on lines +33 to +34
| iOS | [AppStore](https://apps.apple.com/app/id1586449703) |
| macOS | [AppStore](https://apps.apple.com/app/id1586449703) / brew install --cask server-box |
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 README_zh.md table rows have inconsistent pipe formatting causing broken table

The installation table in README_zh.md mixes two markdown table row styles. Lines 33–34 (iOS, macOS) use | col | col | syntax with leading/trailing pipes, but the header row (平台|下载 / --|--) and lines 35–36 (Android, Linux/Windows) omit leading pipes. This inconsistency causes the iOS and macOS rows to be parsed as having extra columns (the leading | creates an implicit empty first column), while Android/Linux rows parse correctly as 2 columns. Compare with README.md:31-36 which uses consistent | formatting throughout.

Suggested change
| iOS | [AppStore](https://apps.apple.com/app/id1586449703) |
| macOS | [AppStore](https://apps.apple.com/app/id1586449703) / brew install --cask server-box |
iOS | [AppStore](https://apps.apple.com/app/id1586449703)
macOS | [AppStore](https://apps.apple.com/app/id1586449703) / brew install --cask server-box
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

opt.: new website

1 participant