Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cb21379e0 | ||
|
|
7ccf8be455
|
||
|
|
23ebd67234
|
||
|
|
7f6f3d7a00
|
||
|
|
25a50486cb
|
||
|
|
56429e0449
|
||
|
|
c855a52b8c | ||
|
|
e2679393ee | ||
|
|
e072280560 | ||
|
|
34785e2abe |
No files matched your search
@@ -1,65 +0,0 @@
|
||||
name: Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Install pnpm
|
||||
run: npm install -g pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: doc-build
|
||||
path: doc_build/
|
||||
|
||||
deploy-vercel:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: doc-build
|
||||
path: doc_build/
|
||||
|
||||
- name: Deploy to Vercel
|
||||
run: npx vercel deploy --prod --yes --token ${{ secrets.VERCEL_TOKEN }}
|
||||
env:
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||
|
||||
deploy-onixbyte:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: doc-build
|
||||
path: doc_build/
|
||||
|
||||
- name: Deploy to OnixByte.cn
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/id_ed25519
|
||||
chmod 600 ~/.ssh/id_ed25519
|
||||
ssh-keyscan onixbyte.cn >> ~/.ssh/known_hosts
|
||||
rsync -avz --delete doc_build/ root@onixbyte.cn:${{ vars.DEPLOY_PATH }}
|
||||
@@ -1,38 +0,0 @@
|
||||
workflow:
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
|
||||
stages:
|
||||
- build
|
||||
- deploy
|
||||
|
||||
build:
|
||||
stage: build
|
||||
image: node:24.15-trixie-slim
|
||||
before_script:
|
||||
- corepack enable
|
||||
- corepack prepare pnpm@latest --activate
|
||||
- pnpm config set store-dir .pnpm-store
|
||||
script:
|
||||
- pnpm install --frozen-lockfile
|
||||
- pnpm build
|
||||
artifacts:
|
||||
paths:
|
||||
- doc_build/
|
||||
|
||||
deploy:
|
||||
stage: deploy
|
||||
image: alpine:latest
|
||||
needs:
|
||||
- build
|
||||
before_script:
|
||||
- apk add --no-cache openssh-client rsync
|
||||
- mkdir -p ~/.ssh
|
||||
- echo "$SSH_PRIVATE_KEY_BASE64" | base64 -d > ~/.ssh/id_ed25519
|
||||
- chmod 600 ~/.ssh/id_ed25519
|
||||
- ssh-keyscan -H onixbyte.cn >> ~/.ssh/known_hosts
|
||||
script:
|
||||
- rsync -avz --delete doc_build/ ${SSH_USER}@onixbyte.cn:${DEPLOY_PATH}
|
||||
- ssh ${SSH_USER}@onixbyte.cn "chown -R caddy:caddy ${DEPLOY_PATH} && chmod -R 755 ${DEPLOY_PATH}"
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
@@ -9,10 +9,9 @@ A static documentation site built with [Rspress](https://rspress.dev/), supporti
|
||||
## URLs
|
||||
|
||||
| Domain | Recommended For |
|
||||
|--------------------------------------------------|--------------------------------|
|
||||
| [onixbyte.cn](https://onixbyte.cn) | Users in China mainland |
|
||||
| [onixbyte.com](https://onixbyte.com) | Users outside China mainland |
|
||||
| [onixbyte.github.io](https://onixbyte.github.io) | Global (GitHub Pages fallback) |
|
||||
|------------------------------------------------------------|------------------------------|
|
||||
| [opensource.onixbyte.cn](https://opensource.onixbyte.cn) | Users in China mainland |
|
||||
| [opensource.onixbyte.com](https://opensource.onixbyte.com) | Users outside China mainland |
|
||||
|
||||
## Local Development
|
||||
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
---
|
||||
title: Git Cheatsheet
|
||||
tags:
|
||||
- git
|
||||
- tips
|
||||
author:
|
||||
name: Zihlu Wang
|
||||
email: real@zihluwang.me
|
||||
---
|
||||
|
||||
## Ignoring Local Modifications to Tracked Files: `git update-index --skip-worktree`
|
||||
|
||||
When you need to modify a Git-tracked file locally but don't want those changes to show up in `git status` or in commits (e.g. a local `application-local.yml`, `.env`, or IDE configuration), you can use `--skip-worktree` to make Git ignore local modifications to that file.
|
||||
|
||||
### Marking and Unmarking
|
||||
|
||||
```bash
|
||||
# Make Git ignore local modifications to the file
|
||||
git update-index --skip-worktree <file>
|
||||
|
||||
# Unmark the file and track it again
|
||||
git update-index --no-skip-worktree <file>
|
||||
```
|
||||
|
||||
### Listing Ignored Files
|
||||
|
||||
Marked files are shown with an `S` flag in `git ls-files -v`:
|
||||
|
||||
```bash
|
||||
git ls-files -v | grep '^S'
|
||||
```
|
||||
|
||||
### Committing Changes to a Marked File
|
||||
|
||||
To commit new changes to the file, unmark it first, commit, then mark it again:
|
||||
|
||||
```bash
|
||||
git update-index --no-skip-worktree <file>
|
||||
git add <file>
|
||||
git commit -m "chore: update config"
|
||||
git update-index --skip-worktree <file>
|
||||
```
|
||||
|
||||
### `--skip-worktree` vs `--assume-unchanged`
|
||||
|
||||
Both options stop Git from reporting modifications to tracked files, but they serve different purposes:
|
||||
|
||||
| Option | Purpose |
|
||||
| -------------------- | ----------------------------------------------------------------------------------------------------------------- |
|
||||
| `--assume-unchanged` | A performance optimisation for large files that rarely change; Git may re-track the file once it notices a change |
|
||||
| `--skip-worktree` | Deliberately ignore local changes for "keep local modifications, don't commit" scenarios; more persistent |
|
||||
|
||||
So for "ignoring local changes", use `--skip-worktree`.
|
||||
|
||||
### Caveats
|
||||
|
||||
- `--skip-worktree` only affects the working tree — it is not a permanent ignore. Operations that rewrite the file, such as `git pull`, `git checkout`, or `git stash`, may overwrite your local changes or cause a conflict. If the file is also likely to change upstream, unmark it before pulling.
|
||||
- It only applies to **tracked** files; for untracked files, use `.gitignore`.
|
||||
|
||||
## Stashing Unfinished Work: `git stash`
|
||||
|
||||
When you need to switch branches mid-task, use `git stash` to set your working-tree changes aside:
|
||||
|
||||
```bash
|
||||
git stash push -m "work in progress" # save with a message
|
||||
git stash -u # include untracked files
|
||||
git stash list # list saved stashes
|
||||
git stash pop # restore and drop the stash
|
||||
git stash apply # restore but keep the stash
|
||||
git stash drop # delete a stash
|
||||
```
|
||||
|
||||
## Amending the Latest Commit: `git commit --amend`
|
||||
|
||||
When you commit and then realise you forgot a file or want to change the message:
|
||||
|
||||
```bash
|
||||
git add <forgotten-file>
|
||||
git commit --amend # keep the same message, fold in new changes
|
||||
git commit --amend -m "new message" # also change the message
|
||||
```
|
||||
|
||||
Note: if the commit has already been pushed, prefer adding a new commit instead of rewriting shared history.
|
||||
|
||||
## Undoing Changes: `git restore` and `git reset`
|
||||
|
||||
```bash
|
||||
git restore <file> # discard unstaged working-tree changes
|
||||
git restore --staged <file> # unstage but keep the changes (like git reset HEAD <file>)
|
||||
git restore --source=HEAD <file> # restore the file to its HEAD version
|
||||
```
|
||||
|
||||
To discard all uncommitted changes (including the staging area):
|
||||
|
||||
```bash
|
||||
git reset --hard HEAD
|
||||
```
|
||||
|
||||
`--hard` also resets the working tree, so double-check that nothing you want to keep would be lost.
|
||||
|
||||
## Recovering Lost Commits: `git reflog`
|
||||
|
||||
When a commit seems to have vanished after a bad `git reset --hard` or `git rebase`, `reflog` records every place HEAD has been:
|
||||
|
||||
```bash
|
||||
git reflog
|
||||
git reset --hard HEAD@{2} # go back to an earlier recorded position
|
||||
```
|
||||
|
||||
As long as the commit still exists in the object database, reflog can get you back to it.
|
||||
|
||||
## Bisecting a Regression: `git bisect`
|
||||
|
||||
When you don't know which commit introduced a bug, `git bisect` uses binary search to locate it:
|
||||
|
||||
```bash
|
||||
git bisect start
|
||||
git bisect bad # the current commit is bad
|
||||
git bisect good <sha> # mark a known-good commit
|
||||
```
|
||||
|
||||
Git checks out a midpoint commit; you just mark each as `good` or `bad` until it narrows down the offending commit:
|
||||
|
||||
```bash
|
||||
git bisect good # or git bisect bad
|
||||
git bisect reset # finish and return to your branch
|
||||
```
|
||||
|
||||
## Friendlier History: `git log`
|
||||
|
||||
```bash
|
||||
git log --oneline --graph --decorate --all # graph view across all branches
|
||||
git log -S "some-string" --all # find commits that added/removed a string
|
||||
git blame <file> # show the last modifier of each line
|
||||
git blame -L 10,20 <file> # restrict to a line range
|
||||
```
|
||||
|
||||
## Cleaning Up Untracked Files: `git clean`
|
||||
|
||||
```bash
|
||||
git clean -n -fd # preview which files would be removed (always run this first)
|
||||
git clean -fd # delete untracked files and directories
|
||||
```
|
||||
|
||||
`-n` only shows what would be deleted without deleting it — preview before you execute.
|
||||
|
||||
## Picking Commits: `git cherry-pick`
|
||||
|
||||
Apply a specific commit from another branch onto your current branch:
|
||||
|
||||
```bash
|
||||
git cherry-pick <sha>
|
||||
```
|
||||
|
||||
## Deleting Merged Local Branches
|
||||
|
||||
```bash
|
||||
git branch --merged | grep -v '\*' | xargs -n 1 git branch -d
|
||||
```
|
||||
|
||||
This deletes all local branches merged into the current branch (except the current one). Preview with `git branch --merged` first.
|
||||
@@ -207,4 +207,75 @@ Specification<User> spec = (root, query, cb) -> {
|
||||
Page<User> page = userRepository.findAll(spec, pageable);
|
||||
```
|
||||
|
||||
## Flattening Objects or Maps into JSON with Jackson
|
||||
|
||||
When serialising to JSON, you sometimes need to "flatten" a nested object's properties into the parent JSON rather than having them appear as a nested field. Jackson provides two annotations for handling objects and `Map` flattening separately.
|
||||
|
||||
### `@JsonUnwrapped` — flattening objects with a known structure
|
||||
|
||||
`@JsonUnwrapped` expands the properties of a nested object directly into the parent JSON:
|
||||
|
||||
```java
|
||||
public class Address {
|
||||
private String street;
|
||||
private String city;
|
||||
// getters and setters
|
||||
}
|
||||
|
||||
public class User {
|
||||
private String name;
|
||||
|
||||
@JsonUnwrapped
|
||||
private Address address;
|
||||
// getters and setters
|
||||
}
|
||||
```
|
||||
|
||||
Serialised output:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "John Doe",
|
||||
"street": "Oxford Street",
|
||||
"city": "London"
|
||||
}
|
||||
```
|
||||
|
||||
Without `@JsonUnwrapped`, `address` would appear as a nested JSON object: `"address": { "street": "...", "city": "..." }`.
|
||||
|
||||
### `@JsonAnyGetter` — flattening a Map with dynamic keys
|
||||
|
||||
`@JsonAnyGetter` flattens a `Map`'s key-value pairs directly into the parent JSON, ideal for dynamic or open-ended fields:
|
||||
|
||||
```java
|
||||
public class Product {
|
||||
private String name;
|
||||
|
||||
private Map<String, Object> attributes = new HashMap<>();
|
||||
|
||||
@JsonAnyGetter
|
||||
public Map<String, Object> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
// other getters and setters
|
||||
}
|
||||
```
|
||||
|
||||
With `attributes` containing `{"colour": "red", "size": "XL"}`, the serialised output is:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Example Product",
|
||||
"colour": "red",
|
||||
"size": "XL"
|
||||
}
|
||||
```
|
||||
|
||||
Note that `@JsonAnyGetter` must be placed on the **getter method**, not the field itself. You will also need `@JsonAnySetter` to support deserialisation.
|
||||
|
||||
### How to choose
|
||||
|
||||
| Scenario | Annotation |
|
||||
|-------------------------------------------------------|--------------------|
|
||||
| Flatten nested objects with fixed fields (e.g. address, config) | `@JsonUnwrapped` |
|
||||
| Flatten dynamic key-value pairs with unknown keys | `@JsonAnyGetter` |
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
title: JetBrains IDE Prompting for the Git User's Password When Cloning over SSH
|
||||
tags:
|
||||
- jetbrains
|
||||
- git
|
||||
- ssh
|
||||
- windows
|
||||
author:
|
||||
name: Zihlu Wang
|
||||
email: real@zihluwang.me
|
||||
---
|
||||
|
||||
When you develop on Windows with a JetBrains IDE — IntelliJ IDEA, PyCharm, WebStorm, GoLand and friends — and your local Windows username contains non-ASCII characters such as Chinese, cloning a repository over SSH can behave rather oddly:
|
||||
|
||||
> The remote is configured as an SSH URL, yet you are repeatedly prompted for the Git user's password.
|
||||
|
||||
Take a repository address such as:
|
||||
|
||||
```text
|
||||
git@git.example.com:project/demo.git
|
||||
```
|
||||
|
||||
Normally Git authenticates over SSH with a key pair and should never ask for the Git user's own login password.
|
||||
|
||||
The problem may be invisible in command-line Git, but it can surface in a JetBrains IDE when you clone, pull or push.
|
||||
|
||||
## Symptoms
|
||||
|
||||
Suppose the Windows username is:
|
||||
|
||||
```text
|
||||
张三
|
||||
```
|
||||
|
||||
Its home directory will be:
|
||||
|
||||
```text
|
||||
C:\Users\张三
|
||||
```
|
||||
|
||||
In the IDE, choose:
|
||||
|
||||
```text
|
||||
Git → Clone → Repository URL
|
||||
```
|
||||
|
||||
and enter:
|
||||
|
||||
```text
|
||||
git@git.example.com:project/demo.git
|
||||
```
|
||||
|
||||
After you click Clone, you may see something like:
|
||||
|
||||
```text
|
||||
git@git.example.com's password:
|
||||
```
|
||||
|
||||
or the IDE may pop up a password dialog asking for the Git user's password. Even entering the correct password may fail to complete the clone.
|
||||
|
||||
## Why does an SSH URL ask for a password?
|
||||
|
||||
To make sense of this, you first need to understand how SSH falls back between authentication methods.
|
||||
|
||||
SSH tries authentication methods in order:
|
||||
|
||||
1. **Public key authentication** — the client presents a local private key, and the server checks whether the matching public key appears in `~/.ssh/authorized_keys` (on a Git server, among the SSH keys you have uploaded);
|
||||
2. **Password / keyboard-interactive authentication** — if public key authentication does not succeed, the server carries on and asks for a password.
|
||||
|
||||
So when `git@git.example.com's password:` appears in the IDE, **the problem is not that SSH was bypassed — it is that public key authentication failed**: the SSH client could not produce the right private key, so the server fell back to password authentication and is now asking for the password of the `git` account on the server — the `git` account, note, not your own. And because mainstream Git servers (GitLab, Gitea and the like) disable password login for `git` by default, supplying the correct password still gets you nowhere.
|
||||
|
||||
The root of the problem is that **the client cannot find the private key**.
|
||||
|
||||
On Windows with a Chinese username, this is usually down to path encoding. By default the private key lives at:
|
||||
|
||||
```text
|
||||
C:\Users\张三\.ssh\id_rsa
|
||||
```
|
||||
|
||||
The SSH client — whether it is the OpenSSH bundled with Git for Windows or the SSH implementation built into the JetBrains IDE — locates this directory through the `%USERPROFILE%` or `HOME` environment variable. When the username contains non-ASCII characters, that path is liable to be mangled as it crosses process boundaries (shuttled back and forth between UTF-8, GBK and ANSI), so the `~/.ssh` path the client resolves no longer matches the real one — neither `config` nor the private key can be read, and password authentication is all that is left.
|
||||
|
||||
A handy way to tell: **run `ssh -T git@git.example.com` in a terminal and it greets you normally, yet the IDE still demands a password when cloning.** That tells you the key itself is fine, and the fault lies purely in the IDE's path resolution.
|
||||
|
||||
## How to confirm
|
||||
|
||||
1. Check that the remote really is an SSH URL (`git@host:path` or `ssh://git@host/path`) and not an HTTP one.
|
||||
2. Run `ssh -T git@git.example.com` in a terminal:
|
||||
- Everything works → the key and the server configuration are fine, and the problem lies with the IDE;
|
||||
- It fails too → work through the usual suspects first: the private key file, `~/.ssh/config`, and whether the public key has been uploaded to the server.
|
||||
3. In the IDE, check which SSH implementation Git is using: `Settings → Version Control → Git → SSH executable`.
|
||||
4. Check that `C:\Users\张三\.ssh` really exists, and that whatever is in `config` is being read.
|
||||
|
||||
## Temporary workarounds
|
||||
|
||||
Before you rearrange your username, try one of the following to sidestep the non-ASCII path.
|
||||
|
||||
### Option 1: use the ssh.exe bundled with Git
|
||||
|
||||
A JetBrains IDE may default to its own built-in SSH implementation. Change `Settings → Version Control → Git → SSH executable` to `Native`, which makes it use the `ssh.exe` shipped with Git for Windows, then retry the clone. The two implementations resolve paths differently, and switching is often enough to sidestep the issue entirely.
|
||||
|
||||
### Option 2: move the keys to a pure-ASCII path and point at them explicitly
|
||||
|
||||
Copy the key directory from `C:\Users\张三\.ssh` to `C:\ssh`, then tell Git explicitly which private key and known_hosts file to use:
|
||||
|
||||
```shell
|
||||
git config --global core.sshCommand "ssh -i C:/ssh/id_rsa -o UserKnownHostsFile=C:/ssh/known_hosts"
|
||||
```
|
||||
|
||||
Once configured, command-line Git — and any IDE that shells out to the system Git — will use this command, and nothing depends on guessing `~/.ssh` any more.
|
||||
|
||||
### Option 3: give the IDE its own HOME
|
||||
|
||||
Create a pure-ASCII home directory (say `C:\ssh-home`), place your keys in `C:\ssh-home\.ssh\`, and set the following in the environment the IDE runs with:
|
||||
|
||||
```text
|
||||
HOME=C:\ssh-home
|
||||
```
|
||||
|
||||
SSH will then look for its configuration and private keys under `C:\ssh-home\.ssh\`, avoiding the Chinese path altogether.
|
||||
|
||||
> All three options relieve the symptom, but they are patches, not cures. As long as the username remains Chinese, other tools — Node, Python, Docker and any number of CLI utilities — can still trip over exactly the same problem. **The proper fix is to change the Windows username to English**, and the steps are in [Renaming a Windows User Account and Profile Folder to English](./rename-windows-user-profile-to-english.mdx).
|
||||
@@ -0,0 +1,185 @@
|
||||
---
|
||||
title: Renaming a Windows User Account and Profile Folder to English
|
||||
tags:
|
||||
- windows
|
||||
- user-profile
|
||||
- registry
|
||||
- troubleshooting
|
||||
author:
|
||||
name: Zihlu Wang
|
||||
email: real@zihluwang.me
|
||||
---
|
||||
|
||||
import { Kbd } from "@rspress/core/theme"
|
||||
|
||||
Windows works perfectly well with a Chinese username, but it makes life needlessly difficult for a good many developer tools — the most glaring example being [a JetBrains IDE that keeps asking for a password when cloning over SSH](./jetbrains-git-ssh-clone-password-prompt.md). The culprit is the non-ASCII characters in `C:\Users\张三`: Git, Node, Python, Docker and a host of CLI tools each read that path with their own idea of the correct encoding, and sooner or later one of them gets it wrong.
|
||||
|
||||
Renaming the account to English sorts this whole class of problem out in one go. The procedure is not complicated, but it is sensitive to the **order of the steps** and to **when you restart**, so follow along below.
|
||||
|
||||
:::warning Before you start
|
||||
|
||||
This procedure edits the **registry** and renames a **user profile folder**, so it carries real risk. Before you begin:
|
||||
|
||||
- Back up important data (the desktop, your documents, and the configuration directories of any applications you rely on);
|
||||
- Make sure the account you are using has **administrator** rights;
|
||||
- Create a system restore point first, so that you can roll back if something goes wrong midway;
|
||||
- Follow the steps below in order — do not skip any, and pay particular attention to the timing of the restarts.
|
||||
|
||||
:::
|
||||
|
||||
## The general idea
|
||||
|
||||
The word "username" on Windows actually covers two separate things:
|
||||
|
||||
1. **The account's display name** — the name shown on the sign-in screen and in the Start menu;
|
||||
2. **The user profile folder name** — the `C:\Users\<name>` folder.
|
||||
|
||||
The awkward part is that Windows will not let you rename the profile folder of a user who is signed in; and since the registry records the **absolute path** of that folder, renaming the folder without touching the registry means your profile cannot be mounted the next time you sign in.
|
||||
|
||||
So a "go-between" account is needed to do the work:
|
||||
|
||||
> Create a temporary account → sign in as it → rename the folder → edit the registry → return to your own account.
|
||||
|
||||
## 1. Find the SID of the existing account
|
||||
|
||||
Sign in as your current account (the one with the Chinese name) and open PowerShell or Command Prompt:
|
||||
|
||||
```powershell
|
||||
whoami /user
|
||||
```
|
||||
|
||||
The output looks like this:
|
||||
|
||||
```text
|
||||
User information
|
||||
----------------
|
||||
User Name SID
|
||||
================= ============================================
|
||||
desktop-abc\张三 S-1-5-21-1234567890-1234567890-1234567890-1001
|
||||
```
|
||||
|
||||
Note the string at the end, `S-1-5-21-...-1001`. That is the `{old user SID}` you will need later.
|
||||
|
||||
To list every local account and its SID in one go:
|
||||
|
||||
```powershell
|
||||
wmic useraccount get name,sid
|
||||
|
||||
# or, on more recent versions of PowerShell:
|
||||
Get-LocalUser | Select-Object Name, SID
|
||||
```
|
||||
|
||||
## 2. Create a new local Windows account
|
||||
|
||||
Open `Settings → Accounts → Other users → Add account`. When asked how the person will sign in, choose **"I don't have this person's sign-in information"**, then **"Add a user without a Microsoft account"**, and create a local account with a plain English name such as `tempadmin`.
|
||||
|
||||
When it has been created, select it in the Other users list, choose **Change account type**, and make it an **administrator**.
|
||||
|
||||
This account is purely a go-between. Its purpose is to let you work on your own profile's files and registry entries **while your own account is signed out**.
|
||||
|
||||
## 3. Sign out of your account and sign in as the new one
|
||||
|
||||
Save your work, sign out of your current account, restart the computer, and sign in with the temporary account you have just created.
|
||||
|
||||
## 4. Rename the profile folder
|
||||
|
||||
Still signed in as the temporary account, open **File Explorer**, go to `C:\Users`, and rename `张三` to the English name you want (for example `JohnDoe`):
|
||||
|
||||
```text
|
||||
C:\Users\张三 → C:\Users\JohnDoe
|
||||
```
|
||||
|
||||
If Windows complains that the folder is in use, some process belonging to your original account is still running (a background service, a sync client, a resident utility). A full restart usually clears it; alternatively, rename it from the command line:
|
||||
|
||||
```powershell
|
||||
Rename-Item -Path "C:\Users\张三" -NewName "JohnDoe"
|
||||
```
|
||||
|
||||
:::tip Naming advice
|
||||
Stick to letters and digits, and avoid spaces. `C:\Users\zhang san` does work, but the space will cause trouble with some command-line tools all the same.
|
||||
:::
|
||||
|
||||
## 5. Update ProfileImagePath in the registry
|
||||
|
||||
Press <Kbd>Win</Kbd> + <Kbd>R</Kbd>, type `regedit` and press Enter to open the Registry Editor, then navigate to:
|
||||
|
||||
```text
|
||||
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\{old user SID}
|
||||
```
|
||||
|
||||
using the SID you noted in step 1. Double-click `ProfileImagePath` in the right-hand pane and change its value from:
|
||||
|
||||
```text
|
||||
C:\Users\张三
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```text
|
||||
C:\Users\JohnDoe
|
||||
```
|
||||
|
||||
Click OK and close the Registry Editor.
|
||||
|
||||
:::warning This is the critical step
|
||||
If you rename the folder but fail to update the registry — or update it incorrectly — your next sign-in will land you in a **temporary profile**: an empty desktop, empty Documents, as though all your data had vanished. It has not; it is still sitting in `C:\Users\JohnDoe`. Go back and check that the SID and `ProfileImagePath` agree, and the profile will mount again.
|
||||
|
||||
Also, if you find two entries under `ProfileList` sharing the same SID, one of them suffixed with `.bak`, that means a profile failed to load at some point. Make sure the correct entry (the one without `.bak`) points at the new folder, then tidy away the duplicate.
|
||||
:::
|
||||
|
||||
## 6. Sign out of the temporary account and restart
|
||||
|
||||
Sign out of the temporary account once more, then restart the computer.
|
||||
|
||||
## 7. Sign back in and let Windows repair the profile
|
||||
|
||||
Sign in with **your original account** (the name on the sign-in screen may still be Chinese; that is dealt with in step 9). As it signs in, Windows detects that the profile path has changed and repairs the profile automatically. You may see messages such as "Getting Windows ready" — wait patiently until it finishes.
|
||||
|
||||
Once you are in, check two things:
|
||||
|
||||
- `C:\Users\JohnDoe` is your profile folder, and your desktop, documents and other personal files are all present;
|
||||
- Open Command Prompt or PowerShell and run `echo %USERPROFILE%`. It should print `C:\Users\JohnDoe`.
|
||||
|
||||
## 8. Fix the paths in the system environment variables
|
||||
|
||||
Right-click `This PC → Properties → Advanced system settings → Environment Variables`, then go through both the **System variables** and the **User variables**, changing every entry that hard-codes the old path from `C:\Users\张三\...` to `C:\Users\JohnDoe\...`.
|
||||
|
||||
Note the distinction:
|
||||
|
||||
- Entries written as `%USERPROFILE%\AppData\...` need **no change** — they are expanded at run time and follow the new folder automatically;
|
||||
- Only **hard-coded absolute paths** need editing, for example `C:\Users\张三\scoop\shims` or `C:\Users\张三\AppData\Local\Programs\Python\Python312`;
|
||||
- `TEMP` and `TMP` are usually of the form `%USERPROFILE%\AppData\Local\Temp` and generally need nothing done to them.
|
||||
|
||||
## 9. Change the account's display name
|
||||
|
||||
Press <Kbd>Win</Kbd> + <Kbd>R</Kbd>, type `control userpasswords2` and press Enter. Select your original account in the list, click **Properties**, change the user name to the new English one, and click OK.
|
||||
|
||||
This step only affects the sign-in screen and the name shown in the interface. It does not change the SID, and it has no bearing on the folder you have already renamed.
|
||||
|
||||
## 10. Remove the temporary account (optional)
|
||||
|
||||
Once you are satisfied that everything works, and that you can still sign in after a restart, delete the go-between account: go to `Settings → Accounts → Other users`, select it, choose **Remove**, then delete the `C:\Users\tempadmin` folder.
|
||||
|
||||
:::tip
|
||||
Restart once and confirm that everything is in order before deleting it, so that you are not left needing the temporary account after it has gone.
|
||||
:::
|
||||
|
||||
## Afterwards: some applications may need reinstalling
|
||||
|
||||
Once the username — and hence the profile folder — changes, any application that has **absolute paths written into its configuration, services, scheduled tasks or shortcuts** may fail to start, or may lose its settings. The usual suspects:
|
||||
|
||||
- **Package managers and runtimes** — Scoop, Chocolatey, Anaconda, nvm, and globally installed Node or Python packages, whose shims and configuration files tend to contain the old path;
|
||||
- **Development tools** — the JetBrains IDEs (whose configuration and cache live under the old path), Docker Desktop, WSL distributions, and Git's global configuration and credential store;
|
||||
- **Anything registered as a Windows service** — databases, web servers and the like, where the service definition pins the absolute paths of the executable and its data directory;
|
||||
- **Desktop shortcuts and the "recently used" lists** — these may all stop working;
|
||||
- **Cloud storage and sync clients** — these will need pointing at the new folder again.
|
||||
|
||||
When that happens, **uninstalling and reinstalling** is usually the least painful and most reliable remedy; a few applications can be put right by re-pointing the paths or running a repair install. It is worth opening each of your everyday development tools after the rename and checking them one by one, reinstalling whatever misbehaves.
|
||||
|
||||
## Summary
|
||||
|
||||
Renaming a Windows username — and in particular the profile folder — is a "pain once, relief for a long time" operation. The process itself is not complicated, but it is sensitive to the order of the steps and the timing of the restarts. Follow the sequence strictly — note the SID, create a temporary account, rename the folder, edit the registry, then come back to fix the environment variables and the display name — and it will go smoothly.
|
||||
|
||||
And once it is done, problems of the kind described in [JetBrains IDE Prompting for the Git User's Password When Cloning over SSH](./jetbrains-git-ssh-clone-password-prompt.md), caused by non-ASCII paths, disappear along with them.
|
||||
|
||||
> Reproduced from a video by Douyin user **@90后科技说**, originally at [https://v.douyin.com/2hqIZUsG9YM/](https://v.douyin.com/2hqIZUsG9YM/).
|
||||
@@ -2,18 +2,3 @@
|
||||
title: Notifications
|
||||
---
|
||||
|
||||
## Microsoft Email Delivery Issues (@outlook, @hotmail, @live, @msn and custom domain emails hosted on Microsoft)
|
||||
|
||||
> Updated at *19 May 2026*.
|
||||
|
||||
**Urgent Action Required for Users with Microsoft-Hosted Emails.**
|
||||
|
||||
Please be advised that our automated email service is currently experiencing severe delivery issues to all email addresses hosted by Microsoft. Due to recent aggressive filtering policies by their Exchange Online Protection (EOP), our mail delivery server has been blocked by Microsoft. As a consequence, our system is **unable to send any notifications, password resets, or activation emails** to accounts ending in **@outlook.com**, **@hotmail.com**, **@live.com**, **@msn.com**, or **indeed any custom domains hosted by Microsoft**.
|
||||
|
||||
To ensure uninterrupted service, please follow the guidance below based on your account status:
|
||||
|
||||
- For Prospective Users (Before Registration): Please **do not** use a Microsoft-hosted email address to register your account. You will not receive the essential activation link. Kindly use an alternative email service provider, such as your corporate email, Gmail, etc. to complete your registration.
|
||||
- For Existing Registered Users: If your profile is currently linked to an Outlook or Hotmail address, please log in immediately and update your primary email address. You can change this by navigating to your **[User Settings -> Preferences -> Emails](https://git.onixbyte.cn/-/profile/emails)** page. Failing to do so will result in missing critical repository updates, CI/CD pipeline failure logs, and Merge Request notifications.
|
||||
|
||||
We are actively working to appeal this block with the Microsoft Postmaster Centre. We sincerely apologise for any inconvenience caused and appreciate your prompt cooperation in updating your contact details.
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
---
|
||||
title: Git 使用小贴士
|
||||
tags:
|
||||
- git
|
||||
- tips
|
||||
author:
|
||||
name: Zihlu Wang
|
||||
email: real@zihluwang.me
|
||||
---
|
||||
|
||||
## 忽略已跟踪文件的本地改动:`git update-index --skip-worktree`
|
||||
|
||||
当你需要在本机修改某个已被 Git 跟踪的文件,但又不希望这些改动出现在 `git status` 或提交里时(比如本地的 `application-local.yml`、`.env`、IDE 配置等),可以使用 `--skip-worktree` 让 Git 忽略该文件的本地改动。
|
||||
|
||||
### 标记与取消标记
|
||||
|
||||
```bash
|
||||
# 让 Git 忽略该文件的本地改动
|
||||
git update-index --skip-worktree <file>
|
||||
|
||||
# 取消忽略,恢复对该文件的跟踪
|
||||
git update-index --no-skip-worktree <file>
|
||||
```
|
||||
|
||||
### 查看所有被忽略的文件
|
||||
|
||||
被标记的文件会在 `git ls-files -v` 的输出中以 `S` 标识:
|
||||
|
||||
```bash
|
||||
git ls-files -v | grep '^S'
|
||||
```
|
||||
|
||||
### 提交对已标记文件的改动
|
||||
|
||||
如果需要向仓库提交该文件的新改动,需要先取消标记、提交、再重新标记:
|
||||
|
||||
```bash
|
||||
git update-index --no-skip-worktree <file>
|
||||
git add <file>
|
||||
git commit -m "chore: update config"
|
||||
git update-index --skip-worktree <file>
|
||||
```
|
||||
|
||||
### `--skip-worktree` 与 `--assume-unchanged` 的区别
|
||||
|
||||
两个选项都能让 Git 不再关注已跟踪文件的改动,但用途不同:
|
||||
|
||||
| 选项 | 用途 |
|
||||
| -------------------- | ---------------------------------------------------------------------------- |
|
||||
| `--assume-unchanged` | 性能优化,适用于几乎不会改变的大型文件;Git 检测到文件变化后可能自动重新跟踪 |
|
||||
| `--skip-worktree` | 有意忽略本地改动,适用于「保持本地修改但不上传」的场景,更持久 |
|
||||
|
||||
因此,「忽略本地改动」应该使用 `--skip-worktree`。
|
||||
|
||||
### 注意事项
|
||||
|
||||
- `--skip-worktree` 只影响工作区层面,并不是一个「永久忽略」。在执行 `git pull`、`git checkout`、`git stash` 等可能改写该文件的操作时,本地改动可能会被覆盖或引发冲突。如果该文件在远端也会变化,建议在拉取前先取消标记。
|
||||
- 它只对**已跟踪**的文件生效;对于未跟踪的文件,请使用 `.gitignore`。
|
||||
|
||||
## 暂存未完成的改动:`git stash`
|
||||
|
||||
需要临时切换分支时,可以用 `git stash` 把工作区改动保存起来:
|
||||
|
||||
```bash
|
||||
git stash push -m "work in progress" # 保存并附带备注
|
||||
git stash -u # 连同未跟踪的文件一起保存
|
||||
git stash list # 查看已保存的改动
|
||||
git stash pop # 恢复并删除该条记录
|
||||
git stash apply # 恢复但保留该条记录
|
||||
git stash drop # 删除某条记录
|
||||
```
|
||||
|
||||
## 修正最近一次提交:`git commit --amend`
|
||||
|
||||
当你提交后发现忘了加入某些文件、或想修改提交信息时:
|
||||
|
||||
```bash
|
||||
git add <forgotten-file>
|
||||
git commit --amend # 保持原提交信息,合并进新改动
|
||||
git commit --amend -m "新提交信息" # 同时修改提交信息
|
||||
```
|
||||
|
||||
注意:如果该提交已经被推送到远端,请改用新增一个提交的方式,避免改写公共历史。
|
||||
|
||||
## 撤销改动:`git restore` 与 `git reset`
|
||||
|
||||
```bash
|
||||
git restore <file> # 丢弃工作区(未暂存)的改动
|
||||
git restore --staged <file> # 取消暂存,保留改动(相当于 git reset HEAD <file>)
|
||||
git restore --source=HEAD <file> # 将文件恢复到 HEAD 版本
|
||||
```
|
||||
|
||||
想彻底丢弃未提交的全部改动(包括暂存区),可以:
|
||||
|
||||
```bash
|
||||
git reset --hard HEAD
|
||||
```
|
||||
|
||||
`--hard` 会连同工作区一并重置,使用前请确认没有需要保留的改动。
|
||||
|
||||
## 找回丢失的提交:`git reflog`
|
||||
|
||||
误用了 `git reset --hard` 或 `git rebase` 导致提交「消失」时,`reflog` 记录了 HEAD 的所有历史位置:
|
||||
|
||||
```bash
|
||||
git reflog
|
||||
git reset --hard HEAD@{2} # 回到 reflog 中记录的某个位置
|
||||
```
|
||||
|
||||
只要提交还在对象库中,就能通过 reflog 找回。
|
||||
|
||||
## 二分查找回归:`git bisect`
|
||||
|
||||
当某个 bug 不知道从哪个提交引入时,`git bisect` 会通过二分法帮你定位:
|
||||
|
||||
```bash
|
||||
git bisect start
|
||||
git bisect bad # 当前提交是有问题的
|
||||
git bisect good <sha> # 标记一个已知正常的提交
|
||||
```
|
||||
|
||||
Git 会不断切换到一个中间提交,你只需要根据当前状态标记 `good` 或 `bad`,最终会定位到引入 bug 的那个提交:
|
||||
|
||||
```bash
|
||||
git bisect good # 或 git bisect bad
|
||||
git bisect reset # 结束并回到原分支
|
||||
```
|
||||
|
||||
## 更友好的历史记录:`git log`
|
||||
|
||||
```bash
|
||||
git log --oneline --graph --decorate --all # 以图形方式查看全部分支
|
||||
git log -S "some-string" --all # 查找新增或删除某字符串的提交
|
||||
git blame <file> # 查看每行代码的最后修改者
|
||||
git blame -L 10,20 <file> # 只查看指定行范围
|
||||
```
|
||||
|
||||
## 清理未跟踪文件:`git clean`
|
||||
|
||||
```bash
|
||||
git clean -n -fd # 先预览会被删除的文件(安全起见务必先跑)
|
||||
git clean -fd # 删除未跟踪的文件和目录
|
||||
```
|
||||
|
||||
`-n` 表示只展示而不实际删除,建议先预览再执行。
|
||||
|
||||
## 精挑细选:`git cherry-pick`
|
||||
|
||||
把其他分支上的某个提交应用到当前分支:
|
||||
|
||||
```bash
|
||||
git cherry-pick <sha>
|
||||
```
|
||||
|
||||
## 清理已合并的本地分支
|
||||
|
||||
```bash
|
||||
git branch --merged | grep -v '\*' | xargs -n 1 git branch -d
|
||||
```
|
||||
|
||||
该命令会删除所有已合并进当前分支的本地分支(当前分支除外)。执行前建议先用 `git branch --merged` 预览。
|
||||
@@ -201,3 +201,76 @@ Specification<User> spec = (root, query, cb) -> {
|
||||
|
||||
Page<User> page = userRepository.findAll(spec, pageable);
|
||||
```
|
||||
|
||||
## 使用 Jackson 将对象或 Map 平铺到 JSON 中
|
||||
|
||||
在序列化 JSON 时,有时需要将嵌套对象的属性"平铺"到父级 JSON 中,而不是作为一个嵌套字段出现。Jackson 提供了两个注解来分别处理对象和 `Map` 的平铺场景。
|
||||
|
||||
### `@JsonUnwrapped` — 平铺已知结构的对象
|
||||
|
||||
`@JsonUnwrapped` 会将一个嵌套对象的属性直接展开到父级 JSON 中:
|
||||
|
||||
```java
|
||||
public class Address {
|
||||
private String street;
|
||||
private String city;
|
||||
// getters and setters
|
||||
}
|
||||
|
||||
public class User {
|
||||
private String name;
|
||||
|
||||
@JsonUnwrapped
|
||||
private Address address;
|
||||
// getters and setters
|
||||
}
|
||||
```
|
||||
|
||||
序列化结果:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "陳大文",
|
||||
"street": "彌敦道",
|
||||
"city": "香港"
|
||||
}
|
||||
```
|
||||
|
||||
如果不使用 `@JsonUnwrapped`,`address` 会作为一个嵌套 JSON 对象出现:`"address": { "street": "...", "city": "..." }`。
|
||||
|
||||
### `@JsonAnyGetter` — 平铺键值不固定的 Map
|
||||
|
||||
`@JsonAnyGetter` 可以将 `Map` 中的键值对直接平铺到父级 JSON 中,适合 key 不固定或动态扩展的场景:
|
||||
|
||||
```java
|
||||
public class Product {
|
||||
private String name;
|
||||
|
||||
private Map<String, Object> attributes = new HashMap<>();
|
||||
|
||||
@JsonAnyGetter
|
||||
public Map<String, Object> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
// other getters and setters
|
||||
}
|
||||
```
|
||||
|
||||
当 `attributes` 包含 `{"colour": "red", "size": "XL"}` 时,序列化结果:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Example Product",
|
||||
"colour": "red",
|
||||
"size": "XL"
|
||||
}
|
||||
```
|
||||
|
||||
注意 `@JsonAnyGetter` 需要加在 **getter 方法**上,而不是字段上;同时需要搭配 `@JsonAnySetter` 来支持反序列化。
|
||||
|
||||
### 如何选择
|
||||
|
||||
| 场景 | 注解 |
|
||||
|----------------------------------------|--------------------|
|
||||
| 平铺字段固定的嵌套对象(如地址、配置) | `@JsonUnwrapped` |
|
||||
| 平铺 key 不固定的动态键值对 | `@JsonAnyGetter` |
|
||||
@@ -0,0 +1,123 @@
|
||||
---
|
||||
title: JetBrains IDE 使用 SSH 方式 Git Clone 时提示输入 Git 用户密码的问题
|
||||
tags:
|
||||
- jetbrains
|
||||
- git
|
||||
- ssh
|
||||
- windows
|
||||
author:
|
||||
name: Zihlu Wang
|
||||
email: real@zihluwang.me
|
||||
---
|
||||
|
||||
在 Windows 环境下使用 JetBrains 系列 IDE(例如 IntelliJ IDEA、PyCharm、WebStorm、GoLand 等)开发项目时,如果 Windows 本地用户名使用了中文,在通过 SSH 方式执行 `git clone` 时,有时会遇到一个比较奇怪的问题:
|
||||
|
||||
> 明明配置的是 Git SSH 地址,却一直提示输入 Git 用户的密码。
|
||||
|
||||
例如仓库地址:
|
||||
|
||||
```text
|
||||
git@git.example.com:project/demo.git
|
||||
```
|
||||
|
||||
正常情况下,Git 应该通过 SSH Key 进行身份认证,而不应该要求输入 Git 用户本身的登录密码。
|
||||
|
||||
这种问题在命令行 Git 中可能不明显,但在 JetBrains IDE 中执行 Clone、Pull、Push 等操作时可能出现。
|
||||
|
||||
## 问题表现
|
||||
|
||||
假设 Windows 用户名为:
|
||||
|
||||
```text
|
||||
张三
|
||||
```
|
||||
|
||||
对应的用户目录可能是:
|
||||
|
||||
```text
|
||||
C:\Users\张三
|
||||
```
|
||||
|
||||
在 JetBrains IDE 中选择:
|
||||
|
||||
```text
|
||||
Git → Clone → Repository URL
|
||||
```
|
||||
|
||||
然后填写:
|
||||
|
||||
```text
|
||||
git@git.example.com:project/demo.git
|
||||
```
|
||||
|
||||
点击 Clone 后,可能出现类似提示:
|
||||
|
||||
```text
|
||||
git@git.example.com's password:
|
||||
```
|
||||
|
||||
或者 IDE 弹出密码输入框,要求输入 Git 用户的密码。
|
||||
|
||||
但是即使输入正确的密码,也可能无法完成 Clone。
|
||||
|
||||
## 为什么 SSH 地址还会要求输入密码?
|
||||
|
||||
要理解这个问题,先要理解 SSH 的认证回退机制。
|
||||
|
||||
SSH 登录时,认证方式是按顺序尝试的:
|
||||
|
||||
1. **公钥认证(Public Key)**——客户端拿出本地私钥,服务器检查对应公钥是否在 `~/.ssh/authorized_keys`(Git 服务端则是用户上传的 SSH Key)中;
|
||||
2. **密码 / 键盘交互认证(Password / Keyboard-Interactive)**——如果公钥认证没有通过,服务器会继续询问密码。
|
||||
|
||||
因此,当 IDE 里出现 `git@git.example.com's password:` 时,**问题并不是「没有走 SSH」,而是「公钥认证失败了」**:SSH 客户端没能拿出正确的那把私钥,服务器于是退回到密码认证,向你索要 Git 服务器上 `git` 用户的密码——注意,是 `git` 这个账户的密码,而不是你自己的账号密码。而主流 Git 服务端(GitLab、Gitea 等)默认都禁用了 `git` 用户的密码登录,所以即便输入了正确的密码,Clone 依然会失败。
|
||||
|
||||
问题的根子在于:**客户端没有找到私钥。**
|
||||
|
||||
在中文用户名的 Windows 上,这通常是路径编码导致的。Windows 下私钥默认位于:
|
||||
|
||||
```text
|
||||
C:\Users\张三\.ssh\id_rsa
|
||||
```
|
||||
|
||||
SSH 客户端(无论是 Git for Windows 附带的 OpenSSH,还是 JetBrains IDE 内置的 SSH 实现)需要借助 `%USERPROFILE%` 或 `HOME` 环境变量定位这个目录。当用户名中含有中文等非 ASCII 字符时,这条路径在进程之间传递时容易出现编码不一致(UTF-8 / GBK / ANSI 之间来回转换),最终客户端解析出的 `~/.ssh` 路径与实际路径对不上——`config` 文件和私钥都读不到,也就只能退回密码认证了。
|
||||
|
||||
一个很典型的判断方法:**在系统终端里执行 `ssh -T git@git.example.com` 能正常返回欢迎信息,但在 IDE 里 Clone 却要密码。** 这说明私钥本身没问题,问题只出在 IDE 这一侧的路径解析上。
|
||||
|
||||
## 如何确认
|
||||
|
||||
1. 确认仓库地址用的确实是 SSH 协议(`git@host:path` 或 `ssh://git@host/path`),而不是 HTTP 地址。
|
||||
2. 在终端执行 `ssh -T git@git.example.com`:
|
||||
- 终端一切正常 → 私钥与服务器配置都没问题,问题在 IDE 侧;
|
||||
- 终端也报错 → 先按常规流程排查私钥文件、`~/.ssh/config`、以及公钥是否已上传到服务端。
|
||||
3. 在 IDE 中查看 Git 使用的 SSH 实现:`Settings → Version Control → Git → SSH executable`。
|
||||
4. 检查 `C:\Users\张三\.ssh` 目录是否真实存在、`config` 内容是否被正确读取。
|
||||
|
||||
## 临时绕过方案
|
||||
|
||||
在动手改用户名之前,可以先尝试下面几种绕开非 ASCII 路径的做法。
|
||||
|
||||
### 方案一:改用 Git 自带的 ssh.exe
|
||||
|
||||
JetBrains IDE 默认可能使用内置的 SSH 实现。把 `Settings → Version Control → Git → SSH executable` 改为 `Native`(即使用 Git for Windows 附带的 `ssh.exe`),然后重试 Clone。切换实现后路径解析的行为不同,往往能直接绕开这个问题。
|
||||
|
||||
### 方案二:把密钥放到纯 ASCII 路径下并显式指定
|
||||
|
||||
将密钥目录从 `C:\Users\张三\.ssh` 复制到 `C:\ssh`,再让 Git 显式使用这个目录下的私钥与 known_hosts:
|
||||
|
||||
```shell
|
||||
git config --global core.sshCommand "ssh -i C:/ssh/id_rsa -o UserKnownHostsFile=C:/ssh/known_hosts"
|
||||
```
|
||||
|
||||
配置后,命令行 Git 以及所有调用系统 Git 的 IDE 都会走这条命令,不再依赖 `~/.ssh` 的自动推导。
|
||||
|
||||
### 方案三:为 IDE 单独设置 HOME 环境变量
|
||||
|
||||
创建一个纯 ASCII 的家目录(例如 `C:\ssh-home`),把密钥放到 `C:\ssh-home\.ssh\` 下,然后在 IDE 使用的环境变量中设置:
|
||||
|
||||
```text
|
||||
HOME=C:\ssh-home
|
||||
```
|
||||
|
||||
这样 SSH 就会去 `C:\ssh-home\.ssh\` 里查找配置与私钥,完全避开中文路径。
|
||||
|
||||
> 三种方案都能缓解问题,但本质上都是「打补丁」。只要用户名还是中文,其它的软件——Node、Python、Docker、各类 CLI 工具——仍可能因为同样的原因踩坑。**根本的解决办法是把 Windows 用户名改成英文**,具体步骤见 [将 Windows 用户名修改为英文](./rename-windows-user-profile-to-english.mdx)。
|
||||
@@ -0,0 +1,185 @@
|
||||
---
|
||||
title: 将 Windows 用户名(用户目录)修改为英文的完整步骤
|
||||
tags:
|
||||
- windows
|
||||
- user-profile
|
||||
- registry
|
||||
- troubleshooting
|
||||
author:
|
||||
name: Zihlu Wang
|
||||
email: real@zihluwang.me
|
||||
---
|
||||
|
||||
import { Kbd } from "@rspress/core/theme"
|
||||
|
||||
在 Windows 上使用中文用户名,系统本身能正常工作,却会给不少开发工具添麻烦——最典型的就是 [JetBrains IDE 用 SSH 方式 Clone 时反复要求输入密码](./jetbrains-git-ssh-clone-password-prompt.md)。根源在于用户目录 `C:\Users\张三` 里的非 ASCII 字符:Git、Node、Python、Docker 以及各类 CLI 工具在读取这条路径时各用各的编码,稍有不慎就会解析失败。
|
||||
|
||||
把用户名改成英文可以一劳永逸地解决这类问题。整个过程不算复杂,但对**步骤顺序**和**重启时机**比较敏感,下面按顺序逐步说明。
|
||||
|
||||
:::warning 开始之前
|
||||
|
||||
本文的操作会修改**注册表**和**用户配置文件目录**,属于有风险的操作。动手前请务必:
|
||||
|
||||
- 备份重要数据(尤其是桌面、文档、以及各类软件的配置目录);
|
||||
- 确认当前账户拥有**管理员权限**;
|
||||
- 建议先创建一个系统还原点,以便中途出问题时回退;
|
||||
- 严格按本文的顺序执行,不要跳步,尤其是重启的时机。
|
||||
|
||||
:::
|
||||
|
||||
## 整体思路
|
||||
|
||||
Windows 里的「用户名」其实对应两样东西:
|
||||
|
||||
1. **账户显示名**——登录界面、开始菜单上看到的名字;
|
||||
2. **用户配置文件目录名**——`C:\Users\<名字>` 这一层文件夹。
|
||||
|
||||
麻烦之处在于:Windows 不允许在用户处于登录状态时重命名它的配置文件目录;同时注册表里记录了这个目录的**绝对路径**,光改文件夹名而不改注册表,会导致下次登录时挂载不到原配置文件。
|
||||
|
||||
因此需要借助一个「过渡账户」来完成:
|
||||
|
||||
> 建临时账户 → 用它登录 → 改文件夹名 → 改注册表 → 回到原账户。
|
||||
|
||||
## 一、获取现有用户的 SID
|
||||
|
||||
以当前(中文用户名的)账户登录,打开 PowerShell 或命令提示符,执行:
|
||||
|
||||
```powershell
|
||||
whoami /user
|
||||
```
|
||||
|
||||
输出类似:
|
||||
|
||||
```text
|
||||
用户信息
|
||||
------------------
|
||||
用户名 SID
|
||||
================= ============================================
|
||||
desktop-abc\张三 S-1-5-21-1234567890-1234567890-1234567890-1001
|
||||
```
|
||||
|
||||
记下结尾那串 `S-1-5-21-...-1001`,它就是后面要找的 `{旧用户 SID}`。
|
||||
|
||||
如果想一次列出所有本地账户及其 SID,可以用:
|
||||
|
||||
```powershell
|
||||
wmic useraccount get name,sid
|
||||
|
||||
# 或在较新版本的 PowerShell 中:
|
||||
Get-LocalUser | Select-Object Name, SID
|
||||
```
|
||||
|
||||
## 二、创建一个新的本地 Windows 用户
|
||||
|
||||
打开 `设置 → 账户 → 其他用户 → 添加账户`,在「如何登录?」这一步选择 **「我没有这个人的登录信息」**,接着选择 **「添加一个没有 Microsoft 帐户的用户」**,创建一个纯英文名的**本地账户**,例如 `tempadmin`。
|
||||
|
||||
创建完成后,在「其他用户」列表中选中该账户,进入「更改账户类型」,把它**提升为管理员**。
|
||||
|
||||
这个账户只是「过渡用」的,作用是让我们能在**原账户已注销**的状态下,去操作它的文件与注册表。
|
||||
|
||||
## 三、注销当前用户,登录新创建的账户
|
||||
|
||||
保存好手头的工作,注销当前账户,重启电脑,然后用刚才创建的临时账户登录。
|
||||
|
||||
## 四、重命名用户目录
|
||||
|
||||
在临时账户下打开**文件资源管理器**,进入 `C:\Users`,把 `张三` 重命名为你想要的英文名(例如 `JohnDoe`):
|
||||
|
||||
```text
|
||||
C:\Users\张三 → C:\Users\JohnDoe
|
||||
```
|
||||
|
||||
如果提示「文件夹正在使用」,说明原账户还有进程在运行(后台服务、同步网盘、常驻程序等)。可以先彻底重启再试,或者改用命令行重命名:
|
||||
|
||||
```powershell
|
||||
Rename-Item -Path "C:\Users\张三" -NewName "JohnDoe"
|
||||
```
|
||||
|
||||
:::tip 命名建议
|
||||
新名字建议只用英文字母和数字,并且不要带空格。虽然 `C:\Users\zhang san` 也能用,但空格同样会让部分命令行工具出问题。
|
||||
:::
|
||||
|
||||
## 五、修改注册表中的 ProfileImagePath
|
||||
|
||||
按 <Kbd>Win</Kbd> + <Kbd>R</Kbd>,输入 `regedit` 回车,打开注册表编辑器,定位到:
|
||||
|
||||
```text
|
||||
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\{旧用户 SID}
|
||||
```
|
||||
|
||||
也就是第一步记下的那串 SID 对应的项。双击右侧的 `ProfileImagePath`,把「数值数据」从:
|
||||
|
||||
```text
|
||||
C:\Users\张三
|
||||
```
|
||||
|
||||
改为:
|
||||
|
||||
```text
|
||||
C:\Users\JohnDoe
|
||||
```
|
||||
|
||||
确定后关闭注册表编辑器。
|
||||
|
||||
:::warning 这一步最关键
|
||||
如果目录名改了、注册表却没改(或改错),下次登录会进入一个**临时配置文件**——桌面空白、文档为空,看起来像「用户数据全丢了」。其实数据还在 `C:\Users\JohnDoe` 里,只要回头核对 SID 与 `ProfileImagePath` 是否一致就能恢复。
|
||||
|
||||
另外,如果 `ProfileList` 下出现了两个相同 SID 的项,其中一个是带 `.bak` 后缀,说明此前发生过配置文件加载失败。此时应确保正确的那一项(不带 `.bak`)的 `ProfileImagePath` 指向新目录,并把重复项清理掉。
|
||||
:::
|
||||
|
||||
## 六、注销临时账户并重启
|
||||
|
||||
再次注销临时账户,然后重启电脑。
|
||||
|
||||
## 七、登录原账户,等待 Windows 自动修复
|
||||
|
||||
用**原来的账户**登录(此时登录界面显示的名字可能还是中文,下一步再改)。登录过程中 Windows 会检测到配置文件路径的变化并自动修复,期间可能出现「正在准备 Windows」之类的提示,耐心等待它完成。
|
||||
|
||||
登录后确认两件事:
|
||||
|
||||
- `C:\Users\JohnDoe` 是你的用户目录,桌面、文档等个人文件都在;
|
||||
- 打开命令提示符或 PowerShell 执行 `echo %USERPROFILE%`,输出应为 `C:\Users\JohnDoe`。
|
||||
|
||||
## 八、修正系统环境变量中的路径
|
||||
|
||||
右键 `此电脑 → 属性 → 高级系统设置 → 环境变量`,逐条检查**系统变量**与**用户变量**,把所有硬编码了旧路径的项,从 `C:\Users\张三\...` 改为 `C:\Users\JohnDoe\...`。
|
||||
|
||||
判断时注意区分:
|
||||
|
||||
- 形如 `%USERPROFILE%\AppData\...` 的项**不用改**,它会在运行时展开,会自动指向新目录;
|
||||
- 只有**写死的绝对路径**才需要改,例如 `C:\Users\张三\scoop\shims`、`C:\Users\张三\AppData\Local\Programs\Python\Python312`;
|
||||
- 用户变量里的 `TEMP`、`TMP` 通常是 `%USERPROFILE%\AppData\Local\Temp` 形式,一般无需修改。
|
||||
|
||||
## 九、修改账户的显示名
|
||||
|
||||
按 <Kbd>Win</Kbd> + <Kbd>R</Kbd>,输入 `control userpasswords2` 回车。在弹出的用户列表中选中原账户那一行,点击 **属性**,把「用户名」改为新的英文名,确定即可。
|
||||
|
||||
这一步只影响登录界面和界面里显示的名称,不改变 SID,也不会影响前面已经改好的目录。
|
||||
|
||||
## 十、清理临时账户(可选)
|
||||
|
||||
确认一切正常、重启后仍能正常登录之后,可以把过渡用的临时账户删掉:进入 `设置 → 账户 → 其他用户`,选中它并选择「删除」,再删掉 `C:\Users\tempadmin` 目录。
|
||||
|
||||
:::tip
|
||||
删除前建议先重启一次并确认新账户一切正常,免得删完才发现还有问题需要回过头来用临时账户。
|
||||
:::
|
||||
|
||||
## 改完之后:部分软件可能需要重装
|
||||
|
||||
用户名(用户目录)变更后,凡是把**绝对路径写进配置、服务、计划任务或快捷方式**的软件,都可能因为路径失效而无法启动或丢失配置。常见需要留意的有:
|
||||
|
||||
- **包管理器与运行时**——Scoop、Chocolatey、Anaconda、nvm,以及全局安装的 Node / Python 包,它们的 shims 和配置文件里往往写着旧路径;
|
||||
- **开发工具**——JetBrains 系列 IDE(配置与缓存目录就位于旧路径下)、Docker Desktop、WSL 发行版、Git 的全局配置与凭据存储;
|
||||
- **注册为服务的程序**——数据库、Web 服务器等,Windows 服务里通常固化了可执行文件与数据目录的绝对路径;
|
||||
- **桌面快捷方式与「最近使用」列表**——可能全部失效;
|
||||
- **各类云盘 / 同步客户端**——需要重新指定本地目录。
|
||||
|
||||
遇到这类情况时,**卸载后重新安装**通常是最省事、最可靠的处理方式;少数软件也可以通过重新指定路径或「修复安装」解决。建议改完用户名后,把日常使用的开发工具逐个打开验证一遍,发现异常就重装。
|
||||
|
||||
## 小结
|
||||
|
||||
把 Windows 用户名(尤其是用户目录)改成英文,是一次「一次疼、长期省」的操作:流程本身不复杂,但对步骤顺序和重启时机比较敏感。只要严格按顺序来——记 SID、建临时账户、改目录、改注册表、回来修正环境变量与显示名——就能顺利完成。
|
||||
|
||||
改完之后,[JetBrains IDE 用 SSH Clone 时要求输入密码](./jetbrains-git-ssh-clone-password-prompt.md) 这类由非 ASCII 路径引起的问题也会一并消失。
|
||||
|
||||
> 本文转载整理自抖音用户 **@90后科技说**,原视频地址:[https://v.douyin.com/2hqIZUsG9YM/](https://v.douyin.com/2hqIZUsG9YM/)
|
||||
@@ -2,18 +2,3 @@
|
||||
title: 通知
|
||||
---
|
||||
|
||||
## Microsoft 邮件投递问题(@outlook、@hotmail、@live、@msn 以及托管在 Microsoft 的自定义域名邮箱)
|
||||
|
||||
> 更新于 *2026 年 5 月 19 日*
|
||||
|
||||
**使用 Microsoft 托管邮箱的用户需立即采取行动。**
|
||||
|
||||
特此通知,我们的自动邮件服务目前向所有由 Microsoft 托管的邮箱地址投递时遇到严重问题。由于 Microsoft Exchange Online Protection (EOP) 近期采取了激进的过滤策略,我们的邮件投递服务器已被 Microsoft 屏蔽。因此,我们的系统**无法向以下邮箱地址发送任何通知、密码重置或激活邮件**:**@outlook.com**、**@hotmail.com**、**@live.com**、**@msn.com**,以及**任何由 Microsoft 托管自定义域名的邮箱**。
|
||||
|
||||
为确保服务不受影响,请根据您的账户状态参考以下指引:
|
||||
|
||||
- **新用户(注册前)**:请**不要**使用 Microsoft 托管的邮箱地址注册账户。您将无法收到必要的激活链接。请使用其他邮件服务商,例如您的企业邮箱、QQ 邮箱或网易 163 邮箱完成注册。
|
||||
- **已注册用户**:如果您的账户当前绑定了 Outlook 或 Hotmail 邮箱地址,请立即登录并更新您的主邮箱。您可以通过 **[用户设置 -> 偏好设置 -> 邮箱](https://git.onixbyte.cn/-/profile/emails)** 页面进行更改。未能及时更新将导致您无法收到重要的仓库更新、CI/CD 流水线失败日志以及合并请求通知。
|
||||
|
||||
我们正在积极与 Microsoft Postmaster Centre 沟通,以申请解除此屏蔽。对于由此带来的任何不便,我们深表歉意,并感谢您及时配合更新联系信息。
|
||||
|
||||
+6
-1
@@ -1,10 +1,12 @@
|
||||
{
|
||||
"name": "rspress-doc-template",
|
||||
"name": "opensource.onixbyte.com",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "rspress build",
|
||||
"build:com": "rspress build --config rspress.config.ts",
|
||||
"build:cn": "rspress build --config rspress.cn.config.ts",
|
||||
"dev": "rspress dev",
|
||||
"format": "prettier --write .",
|
||||
"lint": "eslint .",
|
||||
@@ -15,6 +17,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.4",
|
||||
"@mdx-js/react": "3.1.1",
|
||||
"@rspress/plugin-sitemap": "2.0.11",
|
||||
"@tailwindcss/postcss": "^4.3.0",
|
||||
"@types/node": "^22.8.1",
|
||||
"@types/react": "^19.2.14",
|
||||
@@ -25,6 +29,7 @@
|
||||
"react": "^19.2.6",
|
||||
"react-dom": "^19.2.6",
|
||||
"tailwindcss": "^4.3.0",
|
||||
"typescript": "6.0.3",
|
||||
"typescript-eslint": "^8.58.1"
|
||||
}
|
||||
}
|
||||
Generated
+135
-113
@@ -10,11 +10,17 @@ importers:
|
||||
dependencies:
|
||||
'@rspress/core':
|
||||
specifier: ^2.0.10
|
||||
version: 2.0.11(@rspack/core@2.0.3(@swc/helpers@0.5.21))(@types/mdast@4.0.4)(@types/react@19.2.14)(micromark-util-types@2.0.2)(micromark@4.0.2)
|
||||
version: 2.0.11(@rspack/core@2.0.3(@swc/helpers@0.5.21))(@types/mdast@4.0.4)(@types/react@19.2.14)(micromark-util-types@2.0.2)(micromark@4.0.2(supports-color@7.2.0))(supports-color@7.2.0)
|
||||
devDependencies:
|
||||
'@eslint/js':
|
||||
specifier: ^9.39.4
|
||||
version: 9.39.4
|
||||
'@mdx-js/react':
|
||||
specifier: 3.1.1
|
||||
version: 3.1.1(@types/react@19.2.14)(react@19.2.6)
|
||||
'@rspress/plugin-sitemap':
|
||||
specifier: 2.0.11
|
||||
version: 2.0.11(@rspress/core@2.0.11(@rspack/core@2.0.3(@swc/helpers@0.5.21))(@types/mdast@4.0.4)(@types/react@19.2.14)(micromark-util-types@2.0.2)(micromark@4.0.2(supports-color@7.2.0))(supports-color@7.2.0))
|
||||
'@tailwindcss/postcss':
|
||||
specifier: ^4.3.0
|
||||
version: 4.3.0
|
||||
@@ -29,7 +35,7 @@ importers:
|
||||
version: 19.2.3(@types/react@19.2.14)
|
||||
eslint:
|
||||
specifier: ^9.39.4
|
||||
version: 9.39.4(jiti@2.7.0)
|
||||
version: 9.39.4(jiti@2.7.0)(supports-color@7.2.0)
|
||||
globals:
|
||||
specifier: ^17.5.0
|
||||
version: 17.6.0
|
||||
@@ -45,9 +51,12 @@ importers:
|
||||
tailwindcss:
|
||||
specifier: ^4.3.0
|
||||
version: 4.3.0
|
||||
typescript:
|
||||
specifier: 6.0.3
|
||||
version: 6.0.3
|
||||
typescript-eslint:
|
||||
specifier: ^8.58.1
|
||||
version: 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)
|
||||
version: 8.59.4(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)
|
||||
|
||||
packages:
|
||||
|
||||
@@ -253,6 +262,12 @@ packages:
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
|
||||
'@rspress/plugin-sitemap@2.0.11':
|
||||
resolution: {integrity: sha512-046LCHgbJXdaPipWB2SWMjZcAtIrOjXGZOD92xlTjhZ74D7Mk1Nod1MQdtOEoISWedcHdgpUVXMDbB1doKBpPQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
peerDependencies:
|
||||
'@rspress/core': ^2.0.10
|
||||
|
||||
'@rspress/shared@2.0.11':
|
||||
resolution: {integrity: sha512-7l5Pso4s597utJyisVEnd7n/40h053nfE8DwGQMeS8RLGtSwVgxFwNHsSrvQEGtFlLrg2aWWSITqnAVO1wfTew==}
|
||||
|
||||
@@ -668,6 +683,7 @@ packages:
|
||||
eslint@9.39.4:
|
||||
resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
jiti: '*'
|
||||
@@ -1555,17 +1571,17 @@ snapshots:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))':
|
||||
'@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))':
|
||||
dependencies:
|
||||
eslint: 9.39.4(jiti@2.7.0)
|
||||
eslint: 9.39.4(jiti@2.7.0)(supports-color@7.2.0)
|
||||
eslint-visitor-keys: 3.4.3
|
||||
|
||||
'@eslint-community/regexpp@4.12.2': {}
|
||||
|
||||
'@eslint/config-array@0.21.2':
|
||||
'@eslint/config-array@0.21.2(supports-color@7.2.0)':
|
||||
dependencies:
|
||||
'@eslint/object-schema': 2.1.7
|
||||
debug: 4.4.3
|
||||
debug: 4.4.3(supports-color@7.2.0)
|
||||
minimatch: 3.1.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -1578,10 +1594,10 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/json-schema': 7.0.15
|
||||
|
||||
'@eslint/eslintrc@3.3.5':
|
||||
'@eslint/eslintrc@3.3.5(supports-color@7.2.0)':
|
||||
dependencies:
|
||||
ajv: 6.15.0
|
||||
debug: 4.4.3
|
||||
debug: 4.4.3(supports-color@7.2.0)
|
||||
espree: 10.4.0
|
||||
globals: 14.0.0
|
||||
ignore: 5.3.2
|
||||
@@ -1636,7 +1652,7 @@ snapshots:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
'@mdx-js/mdx@3.1.1':
|
||||
'@mdx-js/mdx@3.1.1(supports-color@7.2.0)':
|
||||
dependencies:
|
||||
'@types/estree': 1.0.9
|
||||
'@types/estree-jsx': 1.0.5
|
||||
@@ -1648,14 +1664,14 @@ snapshots:
|
||||
estree-util-is-identifier-name: 3.0.0
|
||||
estree-util-scope: 1.0.0
|
||||
estree-walker: 3.0.3
|
||||
hast-util-to-jsx-runtime: 2.3.6
|
||||
hast-util-to-jsx-runtime: 2.3.6(supports-color@7.2.0)
|
||||
markdown-extensions: 2.0.0
|
||||
recma-build-jsx: 1.0.0
|
||||
recma-jsx: 1.0.1(acorn@8.16.0)
|
||||
recma-stringify: 1.0.0
|
||||
rehype-recma: 1.0.0
|
||||
remark-mdx: 3.1.1
|
||||
remark-parse: 11.0.0
|
||||
rehype-recma: 1.0.0(supports-color@7.2.0)
|
||||
remark-mdx: 3.1.1(supports-color@7.2.0)
|
||||
remark-parse: 11.0.0(supports-color@7.2.0)
|
||||
remark-rehype: 11.1.2
|
||||
source-map: 0.7.6
|
||||
unified: 11.0.5
|
||||
@@ -1754,9 +1770,9 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@rspack/core': 2.0.3(@swc/helpers@0.5.21)
|
||||
|
||||
'@rspress/core@2.0.11(@rspack/core@2.0.3(@swc/helpers@0.5.21))(@types/mdast@4.0.4)(@types/react@19.2.14)(micromark-util-types@2.0.2)(micromark@4.0.2)':
|
||||
'@rspress/core@2.0.11(@rspack/core@2.0.3(@swc/helpers@0.5.21))(@types/mdast@4.0.4)(@types/react@19.2.14)(micromark-util-types@2.0.2)(micromark@4.0.2(supports-color@7.2.0))(supports-color@7.2.0)':
|
||||
dependencies:
|
||||
'@mdx-js/mdx': 3.1.1
|
||||
'@mdx-js/mdx': 3.1.1(supports-color@7.2.0)
|
||||
'@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.6)
|
||||
'@rsbuild/core': 2.0.6
|
||||
'@rsbuild/plugin-react': 2.0.0(@rsbuild/core@2.0.6)(@rspack/core@2.0.3(@swc/helpers@0.5.21))
|
||||
@@ -1769,9 +1785,9 @@ snapshots:
|
||||
copy-to-clipboard: 3.3.3
|
||||
flexsearch: 0.8.212
|
||||
hast-util-heading-rank: 3.0.0
|
||||
hast-util-to-jsx-runtime: 2.3.6
|
||||
mdast-util-mdx: 3.0.0
|
||||
mdast-util-mdxjs-esm: 2.0.1
|
||||
hast-util-to-jsx-runtime: 2.3.6(supports-color@7.2.0)
|
||||
mdast-util-mdx: 3.0.0(supports-color@7.2.0)
|
||||
mdast-util-mdxjs-esm: 2.0.1(supports-color@7.2.0)
|
||||
medium-zoom: 1.1.0
|
||||
nprogress: 0.2.0
|
||||
react: 19.2.6
|
||||
@@ -1782,11 +1798,11 @@ snapshots:
|
||||
react-router-dom: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||
rehype-external-links: 3.0.0
|
||||
rehype-raw: 7.0.0
|
||||
remark-cjk-friendly: 2.0.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(unified@11.0.5)
|
||||
remark-cjk-friendly-gfm-strikethrough: 2.0.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(unified@11.0.5)
|
||||
remark-gfm: 4.0.1
|
||||
remark-mdx: 3.1.1
|
||||
remark-parse: 11.0.0
|
||||
remark-cjk-friendly: 2.0.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2(supports-color@7.2.0))(unified@11.0.5)
|
||||
remark-cjk-friendly-gfm-strikethrough: 2.0.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2(supports-color@7.2.0))(unified@11.0.5)
|
||||
remark-gfm: 4.0.1(supports-color@7.2.0)
|
||||
remark-mdx: 3.1.1(supports-color@7.2.0)
|
||||
remark-parse: 11.0.0(supports-color@7.2.0)
|
||||
remark-stringify: 11.0.0
|
||||
scroll-into-view-if-needed: 3.1.0
|
||||
shiki: 4.0.2
|
||||
@@ -1804,6 +1820,10 @@ snapshots:
|
||||
- micromark-util-types
|
||||
- supports-color
|
||||
|
||||
'@rspress/plugin-sitemap@2.0.11(@rspress/core@2.0.11(@rspack/core@2.0.3(@swc/helpers@0.5.21))(@types/mdast@4.0.4)(@types/react@19.2.14)(micromark-util-types@2.0.2)(micromark@4.0.2(supports-color@7.2.0))(supports-color@7.2.0))':
|
||||
dependencies:
|
||||
'@rspress/core': 2.0.11(@rspack/core@2.0.3(@swc/helpers@0.5.21))(@types/mdast@4.0.4)(@types/react@19.2.14)(micromark-util-types@2.0.2)(micromark@4.0.2(supports-color@7.2.0))(supports-color@7.2.0)
|
||||
|
||||
'@rspress/shared@2.0.11':
|
||||
dependencies:
|
||||
'@rsbuild/core': 2.0.6
|
||||
@@ -1980,15 +2000,15 @@ snapshots:
|
||||
|
||||
'@types/unist@3.0.3': {}
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.59.4(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@typescript-eslint/eslint-plugin@8.59.4(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
'@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)
|
||||
'@typescript-eslint/scope-manager': 8.59.4
|
||||
'@typescript-eslint/type-utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/type-utils': 8.59.4(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)
|
||||
'@typescript-eslint/visitor-keys': 8.59.4
|
||||
eslint: 9.39.4(jiti@2.7.0)
|
||||
eslint: 9.39.4(jiti@2.7.0)(supports-color@7.2.0)
|
||||
ignore: 7.0.5
|
||||
natural-compare: 1.4.0
|
||||
ts-api-utils: 2.5.0(typescript@6.0.3)
|
||||
@@ -1996,23 +2016,23 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 8.59.4
|
||||
'@typescript-eslint/types': 8.59.4
|
||||
'@typescript-eslint/typescript-estree': 8.59.4(typescript@6.0.3)
|
||||
'@typescript-eslint/typescript-estree': 8.59.4(supports-color@7.2.0)(typescript@6.0.3)
|
||||
'@typescript-eslint/visitor-keys': 8.59.4
|
||||
debug: 4.4.3
|
||||
eslint: 9.39.4(jiti@2.7.0)
|
||||
debug: 4.4.3(supports-color@7.2.0)
|
||||
eslint: 9.39.4(jiti@2.7.0)(supports-color@7.2.0)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/project-service@8.59.4(typescript@6.0.3)':
|
||||
'@typescript-eslint/project-service@8.59.4(supports-color@7.2.0)(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/tsconfig-utils': 8.59.4(typescript@6.0.3)
|
||||
'@typescript-eslint/types': 8.59.4
|
||||
debug: 4.4.3
|
||||
debug: 4.4.3(supports-color@7.2.0)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -2026,13 +2046,13 @@ snapshots:
|
||||
dependencies:
|
||||
typescript: 6.0.3
|
||||
|
||||
'@typescript-eslint/type-utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@typescript-eslint/type-utils@8.59.4(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.59.4
|
||||
'@typescript-eslint/typescript-estree': 8.59.4(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)
|
||||
debug: 4.4.3
|
||||
eslint: 9.39.4(jiti@2.7.0)
|
||||
'@typescript-eslint/typescript-estree': 8.59.4(supports-color@7.2.0)(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)
|
||||
debug: 4.4.3(supports-color@7.2.0)
|
||||
eslint: 9.39.4(jiti@2.7.0)(supports-color@7.2.0)
|
||||
ts-api-utils: 2.5.0(typescript@6.0.3)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
@@ -2040,13 +2060,13 @@ snapshots:
|
||||
|
||||
'@typescript-eslint/types@8.59.4': {}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.59.4(typescript@6.0.3)':
|
||||
'@typescript-eslint/typescript-estree@8.59.4(supports-color@7.2.0)(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/project-service': 8.59.4(typescript@6.0.3)
|
||||
'@typescript-eslint/project-service': 8.59.4(supports-color@7.2.0)(typescript@6.0.3)
|
||||
'@typescript-eslint/tsconfig-utils': 8.59.4(typescript@6.0.3)
|
||||
'@typescript-eslint/types': 8.59.4
|
||||
'@typescript-eslint/visitor-keys': 8.59.4
|
||||
debug: 4.4.3
|
||||
debug: 4.4.3(supports-color@7.2.0)
|
||||
minimatch: 10.2.5
|
||||
semver: 7.8.0
|
||||
tinyglobby: 0.2.16
|
||||
@@ -2055,13 +2075,13 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)':
|
||||
'@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0))
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))
|
||||
'@typescript-eslint/scope-manager': 8.59.4
|
||||
'@typescript-eslint/types': 8.59.4
|
||||
'@typescript-eslint/typescript-estree': 8.59.4(typescript@6.0.3)
|
||||
eslint: 9.39.4(jiti@2.7.0)
|
||||
'@typescript-eslint/typescript-estree': 8.59.4(supports-color@7.2.0)(typescript@6.0.3)
|
||||
eslint: 9.39.4(jiti@2.7.0)(supports-color@7.2.0)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -2163,9 +2183,11 @@ snapshots:
|
||||
|
||||
csstype@3.2.3: {}
|
||||
|
||||
debug@4.4.3:
|
||||
debug@4.4.3(supports-color@7.2.0):
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
optionalDependencies:
|
||||
supports-color: 7.2.0
|
||||
|
||||
decode-named-character-reference@1.3.0:
|
||||
dependencies:
|
||||
@@ -2217,14 +2239,14 @@ snapshots:
|
||||
|
||||
eslint-visitor-keys@5.0.1: {}
|
||||
|
||||
eslint@9.39.4(jiti@2.7.0):
|
||||
eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0))
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
'@eslint/config-array': 0.21.2
|
||||
'@eslint/config-array': 0.21.2(supports-color@7.2.0)
|
||||
'@eslint/config-helpers': 0.4.2
|
||||
'@eslint/core': 0.17.0
|
||||
'@eslint/eslintrc': 3.3.5
|
||||
'@eslint/eslintrc': 3.3.5(supports-color@7.2.0)
|
||||
'@eslint/js': 9.39.4
|
||||
'@eslint/plugin-kit': 0.4.1
|
||||
'@humanfs/node': 0.16.8
|
||||
@@ -2234,7 +2256,7 @@ snapshots:
|
||||
ajv: 6.15.0
|
||||
chalk: 4.1.2
|
||||
cross-spawn: 7.0.6
|
||||
debug: 4.4.3
|
||||
debug: 4.4.3(supports-color@7.2.0)
|
||||
escape-string-regexp: 4.0.0
|
||||
eslint-scope: 8.4.0
|
||||
eslint-visitor-keys: 4.2.1
|
||||
@@ -2392,7 +2414,7 @@ snapshots:
|
||||
web-namespaces: 2.0.1
|
||||
zwitch: 2.0.4
|
||||
|
||||
hast-util-to-estree@3.1.3:
|
||||
hast-util-to-estree@3.1.3(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/estree': 1.0.9
|
||||
'@types/estree-jsx': 1.0.5
|
||||
@@ -2402,9 +2424,9 @@ snapshots:
|
||||
estree-util-attach-comments: 3.0.0
|
||||
estree-util-is-identifier-name: 3.0.0
|
||||
hast-util-whitespace: 3.0.0
|
||||
mdast-util-mdx-expression: 2.0.1
|
||||
mdast-util-mdx-jsx: 3.2.0
|
||||
mdast-util-mdxjs-esm: 2.0.1
|
||||
mdast-util-mdx-expression: 2.0.1(supports-color@7.2.0)
|
||||
mdast-util-mdx-jsx: 3.2.0(supports-color@7.2.0)
|
||||
mdast-util-mdxjs-esm: 2.0.1(supports-color@7.2.0)
|
||||
property-information: 7.1.0
|
||||
space-separated-tokens: 2.0.2
|
||||
style-to-js: 1.1.21
|
||||
@@ -2427,7 +2449,7 @@ snapshots:
|
||||
stringify-entities: 4.0.4
|
||||
zwitch: 2.0.4
|
||||
|
||||
hast-util-to-jsx-runtime@2.3.6:
|
||||
hast-util-to-jsx-runtime@2.3.6(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/estree': 1.0.9
|
||||
'@types/hast': 3.0.4
|
||||
@@ -2436,9 +2458,9 @@ snapshots:
|
||||
devlop: 1.1.0
|
||||
estree-util-is-identifier-name: 3.0.0
|
||||
hast-util-whitespace: 3.0.0
|
||||
mdast-util-mdx-expression: 2.0.1
|
||||
mdast-util-mdx-jsx: 3.2.0
|
||||
mdast-util-mdxjs-esm: 2.0.1
|
||||
mdast-util-mdx-expression: 2.0.1(supports-color@7.2.0)
|
||||
mdast-util-mdx-jsx: 3.2.0(supports-color@7.2.0)
|
||||
mdast-util-mdxjs-esm: 2.0.1(supports-color@7.2.0)
|
||||
property-information: 7.1.0
|
||||
space-separated-tokens: 2.0.2
|
||||
style-to-js: 1.1.21
|
||||
@@ -2606,14 +2628,14 @@ snapshots:
|
||||
unist-util-is: 6.0.1
|
||||
unist-util-visit-parents: 6.0.2
|
||||
|
||||
mdast-util-from-markdown@2.0.3:
|
||||
mdast-util-from-markdown@2.0.3(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
'@types/unist': 3.0.3
|
||||
decode-named-character-reference: 1.3.0
|
||||
devlop: 1.1.0
|
||||
mdast-util-to-string: 4.0.0
|
||||
micromark: 4.0.2
|
||||
micromark: 4.0.2(supports-color@7.2.0)
|
||||
micromark-util-decode-numeric-character-reference: 2.0.2
|
||||
micromark-util-decode-string: 2.0.1
|
||||
micromark-util-normalize-identifier: 2.0.1
|
||||
@@ -2631,67 +2653,67 @@ snapshots:
|
||||
mdast-util-find-and-replace: 3.0.2
|
||||
micromark-util-character: 2.1.1
|
||||
|
||||
mdast-util-gfm-footnote@2.1.0:
|
||||
mdast-util-gfm-footnote@2.1.0(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
devlop: 1.1.0
|
||||
mdast-util-from-markdown: 2.0.3
|
||||
mdast-util-from-markdown: 2.0.3(supports-color@7.2.0)
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
micromark-util-normalize-identifier: 2.0.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mdast-util-gfm-strikethrough@2.0.0:
|
||||
mdast-util-gfm-strikethrough@2.0.0(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
mdast-util-from-markdown: 2.0.3
|
||||
mdast-util-from-markdown: 2.0.3(supports-color@7.2.0)
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mdast-util-gfm-table@2.0.0:
|
||||
mdast-util-gfm-table@2.0.0(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
devlop: 1.1.0
|
||||
markdown-table: 3.0.4
|
||||
mdast-util-from-markdown: 2.0.3
|
||||
mdast-util-from-markdown: 2.0.3(supports-color@7.2.0)
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mdast-util-gfm-task-list-item@2.0.0:
|
||||
mdast-util-gfm-task-list-item@2.0.0(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
devlop: 1.1.0
|
||||
mdast-util-from-markdown: 2.0.3
|
||||
mdast-util-from-markdown: 2.0.3(supports-color@7.2.0)
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mdast-util-gfm@3.1.0:
|
||||
mdast-util-gfm@3.1.0(supports-color@7.2.0):
|
||||
dependencies:
|
||||
mdast-util-from-markdown: 2.0.3
|
||||
mdast-util-from-markdown: 2.0.3(supports-color@7.2.0)
|
||||
mdast-util-gfm-autolink-literal: 2.0.1
|
||||
mdast-util-gfm-footnote: 2.1.0
|
||||
mdast-util-gfm-strikethrough: 2.0.0
|
||||
mdast-util-gfm-table: 2.0.0
|
||||
mdast-util-gfm-task-list-item: 2.0.0
|
||||
mdast-util-gfm-footnote: 2.1.0(supports-color@7.2.0)
|
||||
mdast-util-gfm-strikethrough: 2.0.0(supports-color@7.2.0)
|
||||
mdast-util-gfm-table: 2.0.0(supports-color@7.2.0)
|
||||
mdast-util-gfm-task-list-item: 2.0.0(supports-color@7.2.0)
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mdast-util-mdx-expression@2.0.1:
|
||||
mdast-util-mdx-expression@2.0.1(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/estree-jsx': 1.0.5
|
||||
'@types/hast': 3.0.4
|
||||
'@types/mdast': 4.0.4
|
||||
devlop: 1.1.0
|
||||
mdast-util-from-markdown: 2.0.3
|
||||
mdast-util-from-markdown: 2.0.3(supports-color@7.2.0)
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mdast-util-mdx-jsx@3.2.0:
|
||||
mdast-util-mdx-jsx@3.2.0(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/estree-jsx': 1.0.5
|
||||
'@types/hast': 3.0.4
|
||||
@@ -2699,7 +2721,7 @@ snapshots:
|
||||
'@types/unist': 3.0.3
|
||||
ccount: 2.0.1
|
||||
devlop: 1.1.0
|
||||
mdast-util-from-markdown: 2.0.3
|
||||
mdast-util-from-markdown: 2.0.3(supports-color@7.2.0)
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
parse-entities: 4.0.2
|
||||
stringify-entities: 4.0.4
|
||||
@@ -2708,23 +2730,23 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mdast-util-mdx@3.0.0:
|
||||
mdast-util-mdx@3.0.0(supports-color@7.2.0):
|
||||
dependencies:
|
||||
mdast-util-from-markdown: 2.0.3
|
||||
mdast-util-mdx-expression: 2.0.1
|
||||
mdast-util-mdx-jsx: 3.2.0
|
||||
mdast-util-mdxjs-esm: 2.0.1
|
||||
mdast-util-from-markdown: 2.0.3(supports-color@7.2.0)
|
||||
mdast-util-mdx-expression: 2.0.1(supports-color@7.2.0)
|
||||
mdast-util-mdx-jsx: 3.2.0(supports-color@7.2.0)
|
||||
mdast-util-mdxjs-esm: 2.0.1(supports-color@7.2.0)
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mdast-util-mdxjs-esm@2.0.1:
|
||||
mdast-util-mdxjs-esm@2.0.1(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/estree-jsx': 1.0.5
|
||||
'@types/hast': 3.0.4
|
||||
'@types/mdast': 4.0.4
|
||||
devlop: 1.1.0
|
||||
mdast-util-from-markdown: 2.0.3
|
||||
mdast-util-from-markdown: 2.0.3(supports-color@7.2.0)
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -2783,11 +2805,11 @@ snapshots:
|
||||
micromark-util-symbol: 2.0.1
|
||||
micromark-util-types: 2.0.2
|
||||
|
||||
micromark-extension-cjk-friendly-gfm-strikethrough@2.0.1(micromark-util-types@2.0.2)(micromark@4.0.2):
|
||||
micromark-extension-cjk-friendly-gfm-strikethrough@2.0.1(micromark-util-types@2.0.2)(micromark@4.0.2(supports-color@7.2.0)):
|
||||
dependencies:
|
||||
devlop: 1.1.0
|
||||
get-east-asian-width: 1.6.0
|
||||
micromark: 4.0.2
|
||||
micromark: 4.0.2(supports-color@7.2.0)
|
||||
micromark-extension-cjk-friendly-util: 3.0.1(micromark-util-types@2.0.2)
|
||||
micromark-util-character: 2.1.1
|
||||
micromark-util-chunked: 2.0.1
|
||||
@@ -2804,10 +2826,10 @@ snapshots:
|
||||
optionalDependencies:
|
||||
micromark-util-types: 2.0.2
|
||||
|
||||
micromark-extension-cjk-friendly@2.0.1(micromark-util-types@2.0.2)(micromark@4.0.2):
|
||||
micromark-extension-cjk-friendly@2.0.1(micromark-util-types@2.0.2)(micromark@4.0.2(supports-color@7.2.0)):
|
||||
dependencies:
|
||||
devlop: 1.1.0
|
||||
micromark: 4.0.2
|
||||
micromark: 4.0.2(supports-color@7.2.0)
|
||||
micromark-extension-cjk-friendly-util: 3.0.1(micromark-util-types@2.0.2)
|
||||
micromark-util-chunked: 2.0.1
|
||||
micromark-util-resolve-all: 2.0.1
|
||||
@@ -3038,10 +3060,10 @@ snapshots:
|
||||
|
||||
micromark-util-types@2.0.2: {}
|
||||
|
||||
micromark@4.0.2:
|
||||
micromark@4.0.2(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/debug': 4.1.13
|
||||
debug: 4.4.3
|
||||
debug: 4.4.3(supports-color@7.2.0)
|
||||
decode-named-character-reference: 1.3.0
|
||||
devlop: 1.1.0
|
||||
micromark-core-commonmark: 2.0.3
|
||||
@@ -3230,17 +3252,17 @@ snapshots:
|
||||
hast-util-raw: 9.1.0
|
||||
vfile: 6.0.3
|
||||
|
||||
rehype-recma@1.0.0:
|
||||
rehype-recma@1.0.0(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/estree': 1.0.9
|
||||
'@types/hast': 3.0.4
|
||||
hast-util-to-estree: 3.1.3
|
||||
hast-util-to-estree: 3.1.3(supports-color@7.2.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
remark-cjk-friendly-gfm-strikethrough@2.0.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(unified@11.0.5):
|
||||
remark-cjk-friendly-gfm-strikethrough@2.0.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2(supports-color@7.2.0))(unified@11.0.5):
|
||||
dependencies:
|
||||
micromark-extension-cjk-friendly-gfm-strikethrough: 2.0.1(micromark-util-types@2.0.2)(micromark@4.0.2)
|
||||
micromark-extension-cjk-friendly-gfm-strikethrough: 2.0.1(micromark-util-types@2.0.2)(micromark@4.0.2(supports-color@7.2.0))
|
||||
unified: 11.0.5
|
||||
optionalDependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
@@ -3248,9 +3270,9 @@ snapshots:
|
||||
- micromark
|
||||
- micromark-util-types
|
||||
|
||||
remark-cjk-friendly@2.0.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(unified@11.0.5):
|
||||
remark-cjk-friendly@2.0.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2(supports-color@7.2.0))(unified@11.0.5):
|
||||
dependencies:
|
||||
micromark-extension-cjk-friendly: 2.0.1(micromark-util-types@2.0.2)(micromark@4.0.2)
|
||||
micromark-extension-cjk-friendly: 2.0.1(micromark-util-types@2.0.2)(micromark@4.0.2(supports-color@7.2.0))
|
||||
unified: 11.0.5
|
||||
optionalDependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
@@ -3258,28 +3280,28 @@ snapshots:
|
||||
- micromark
|
||||
- micromark-util-types
|
||||
|
||||
remark-gfm@4.0.1:
|
||||
remark-gfm@4.0.1(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
mdast-util-gfm: 3.1.0
|
||||
mdast-util-gfm: 3.1.0(supports-color@7.2.0)
|
||||
micromark-extension-gfm: 3.0.0
|
||||
remark-parse: 11.0.0
|
||||
remark-parse: 11.0.0(supports-color@7.2.0)
|
||||
remark-stringify: 11.0.0
|
||||
unified: 11.0.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
remark-mdx@3.1.1:
|
||||
remark-mdx@3.1.1(supports-color@7.2.0):
|
||||
dependencies:
|
||||
mdast-util-mdx: 3.0.0
|
||||
mdast-util-mdx: 3.0.0(supports-color@7.2.0)
|
||||
micromark-extension-mdxjs: 3.0.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
remark-parse@11.0.0:
|
||||
remark-parse@11.0.0(supports-color@7.2.0):
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
mdast-util-from-markdown: 2.0.3
|
||||
mdast-util-from-markdown: 2.0.3(supports-color@7.2.0)
|
||||
micromark-util-types: 2.0.2
|
||||
unified: 11.0.5
|
||||
transitivePeerDependencies:
|
||||
@@ -3378,13 +3400,13 @@ snapshots:
|
||||
dependencies:
|
||||
prelude-ls: 1.2.1
|
||||
|
||||
typescript-eslint@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3):
|
||||
typescript-eslint@8.59.4(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3):
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 8.59.4(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)
|
||||
'@typescript-eslint/typescript-estree': 8.59.4(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)
|
||||
eslint: 9.39.4(jiti@2.7.0)
|
||||
'@typescript-eslint/eslint-plugin': 8.59.4(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)
|
||||
'@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)
|
||||
'@typescript-eslint/typescript-estree': 8.59.4(supports-color@7.2.0)(typescript@6.0.3)
|
||||
'@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)
|
||||
eslint: 9.39.4(jiti@2.7.0)(supports-color@7.2.0)
|
||||
typescript: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Build configuration for `onixbyte.cn`.
|
||||
*
|
||||
* Thin wrapper over the shared factory — see `rspress.config.ts` for what the
|
||||
* `cn` target changes. Invoke it with `pnpm build:cn`, which passes this file
|
||||
* via `rspress build --config`.
|
||||
*/
|
||||
import { createConfig } from "./rspress.config"
|
||||
|
||||
export default createConfig("cn")
|
||||
+235
-23
@@ -1,44 +1,256 @@
|
||||
import * as path from "node:path"
|
||||
import { writeFile } from "node:fs/promises"
|
||||
import { defineConfig } from "@rspress/core"
|
||||
import type { RspressPlugin, SocialLink, UserConfig } from "@rspress/core"
|
||||
import { pluginSitemap } from "@rspress/plugin-sitemap"
|
||||
import { DOUYIN_ICON } from "./theme/lib/social-icons"
|
||||
|
||||
export default defineConfig({
|
||||
root: path.join(__dirname, "docs"),
|
||||
/**
|
||||
* Which deployment this build targets.
|
||||
*
|
||||
* The two builds differ in more than colour: `onixbyte.cn` is hosted in
|
||||
* mainland China, so its build points every absolute URL at the `.cn` origin
|
||||
* and omits links to sites that are not reliably reachable from there.
|
||||
*
|
||||
* Build with `pnpm build:com` / `pnpm build:cn` — see `package.json`. Both
|
||||
* write to `doc_build`, so run and deploy them one at a time.
|
||||
*/
|
||||
export type SiteTarget = "com" | "cn"
|
||||
|
||||
const ORIGINS: Record<SiteTarget, string> = {
|
||||
com: "https://opensource.onixbyte.com",
|
||||
cn: "https://opensource.onixbyte.cn",
|
||||
}
|
||||
|
||||
/** Every locale the site is published in, default first for each target. */
|
||||
const LANGS = ["en-gb", "zh-hans"] as const
|
||||
|
||||
/**
|
||||
* Locale served from the unprefixed routes.
|
||||
*
|
||||
* `.com` leads with English; `.cn` leads with Chinese, so a visitor landing on
|
||||
* the bare domain gets the language that site exists for. The other locale then
|
||||
* moves to a prefix — on `.cn`, English lives at `/en-gb/`.
|
||||
*/
|
||||
const DEFAULT_LANG: Record<SiteTarget, string> = {
|
||||
com: "en-gb",
|
||||
cn: "zh-hans",
|
||||
}
|
||||
|
||||
/** hreflang and Open Graph locale codes, keyed by Rspress lang. */
|
||||
const HREFLANG: Record<string, string> = { "en-gb": "en-GB", "zh-hans": "zh-Hans" }
|
||||
const OG_LOCALE: Record<string, string> = { "en-gb": "en_GB", "zh-hans": "zh_CN" }
|
||||
|
||||
/** Language-switcher labels, keyed by Rspress lang. */
|
||||
const LOCALE_LABELS: Record<string, string> = {
|
||||
"en-gb": "English (Great Britain)",
|
||||
"zh-hans": "简体中文",
|
||||
}
|
||||
|
||||
/** Site title and description, keyed by Rspress lang. */
|
||||
const LOCALE_META: Record<string, { title: string; description: string }> = {
|
||||
"en-gb": {
|
||||
title: "OnixByte",
|
||||
icon: "/onixbyte-icon.svg",
|
||||
logo: {
|
||||
light: "/onixbyte-light-logo.svg",
|
||||
dark: "/onixbyte-dark-logo.svg",
|
||||
description:
|
||||
"OnixByte builds self-developed SaaS products and delivers custom software engineering services.",
|
||||
},
|
||||
themeConfig: {
|
||||
socialLinks: [
|
||||
"zh-hans": {
|
||||
title: "OnixByte",
|
||||
description: "曜珀科技自主研发 SaaS 产品,并提供定制化软件开发服务。",
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Social links, split by whether they are reliably reachable from mainland
|
||||
* China. The `.cn` build renders only the `domestic` set.
|
||||
*
|
||||
* To move a link between builds, move it between these two arrays — nothing
|
||||
* else needs to change.
|
||||
*/
|
||||
const SOCIAL_LINKS: Record<"domestic" | "international", SocialLink[]> = {
|
||||
domestic: [
|
||||
{
|
||||
icon: "github",
|
||||
mode: "link",
|
||||
content: "https://git.onixbyte.com/onixbyte/homepage",
|
||||
content: "https://github.com/onixbyte-opensource",
|
||||
},
|
||||
{
|
||||
// Rspress has no preset Douyin icon, so the artwork is supplied inline —
|
||||
// see `theme/lib/social-icons.ts` for the expected markup.
|
||||
icon: { svg: DOUYIN_ICON },
|
||||
mode: "link",
|
||||
content: "https://v.douyin.com/8PlxMzXors0/",
|
||||
},
|
||||
],
|
||||
international: [
|
||||
{
|
||||
icon: "x",
|
||||
mode: "link",
|
||||
content: "https://x.com/onixbyte",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-route sitemap priorities.
|
||||
*
|
||||
* `loc` is deliberately absent. The plugin builds a full entry (including `loc`)
|
||||
* and then spreads `customMaps[routePath]` over it, so `loc` is genuinely
|
||||
* optional — its own documentation shows entries without one. The published
|
||||
* type nonetheless marks `loc` as required, so the assertion at the call site
|
||||
* bridges that mismatch. `SitemapOverrides` is what keeps the priority values
|
||||
* themselves checked.
|
||||
*/
|
||||
type CustomMapsOption = NonNullable<Parameters<typeof pluginSitemap>[0]["customMaps"]>
|
||||
type SitemapOverrides = Record<string, Omit<CustomMapsOption[string], "loc">>
|
||||
|
||||
const PRIORITISED_ROUTES = [
|
||||
["/products/", "1.0"],
|
||||
["/services/", "1.0"],
|
||||
] as const
|
||||
|
||||
/**
|
||||
* Builds the override map for a target.
|
||||
*
|
||||
* The keys are full route paths, so they depend on which locale is unprefixed —
|
||||
* `/products/` means English on `.com` and Chinese on `.cn`.
|
||||
*/
|
||||
function sitemapPriorities(localePrefix: (lang: string) => string): SitemapOverrides {
|
||||
return Object.fromEntries(
|
||||
LANGS.flatMap((lang) =>
|
||||
PRIORITISED_ROUTES.map(([routePath, priority]) => [
|
||||
`${localePrefix(lang)}${routePath}`,
|
||||
{ priority },
|
||||
])
|
||||
)
|
||||
) satisfies SitemapOverrides
|
||||
}
|
||||
|
||||
/** Strips the language prefix, always returning a leading slash. */
|
||||
function bareRoutePath(localePrefix: (lang: string) => string, routePath: string, lang: string) {
|
||||
const prefix = localePrefix(lang)
|
||||
const rest = prefix && routePath.startsWith(prefix) ? routePath.slice(prefix.length) : routePath
|
||||
return rest.startsWith("/") ? rest : `/${rest}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes `robots.txt` at build time.
|
||||
*
|
||||
* It cannot live in `docs/public/`, because a single static file would have to
|
||||
* carry the wrong origin for one of the two targets.
|
||||
*
|
||||
* Rspress also runs `afterBuild` in dev, after each recompile. Dev never creates
|
||||
* the output directory, so the write would fail with `ENOENT` — hence the
|
||||
* `isProd` guard, which comes from the hook rather than `NODE_ENV`.
|
||||
*/
|
||||
function pluginRobots(origin: string): RspressPlugin {
|
||||
return {
|
||||
name: "plugin-onixbyte-robots",
|
||||
async afterBuild(config: UserConfig, isProd: boolean) {
|
||||
if (!isProd) {
|
||||
return
|
||||
}
|
||||
const outDir = path.resolve(process.cwd(), config.outDir ?? "doc_build")
|
||||
const body = ["User-agent: *", "Allow: /", "", `Sitemap: ${origin}/sitemap.xml`, ""].join(
|
||||
"\n"
|
||||
)
|
||||
await writeFile(path.join(outDir, "robots.txt"), body, "utf8")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function createConfig(target: SiteTarget): UserConfig {
|
||||
const origin = ORIGINS[target]
|
||||
const defaultLang = DEFAULT_LANG[target]
|
||||
const socialLinks = [
|
||||
...SOCIAL_LINKS.domestic,
|
||||
...(target === "cn" ? [] : SOCIAL_LINKS.international),
|
||||
]
|
||||
|
||||
/** Rspress drops the prefix from the default locale's routes. */
|
||||
const localePrefix = (lang: string) => (lang === defaultLang ? "" : `/${lang}`)
|
||||
|
||||
return defineConfig({
|
||||
root: path.join(__dirname, "docs"),
|
||||
title: LOCALE_META[defaultLang].title,
|
||||
description: LOCALE_META[defaultLang].description,
|
||||
icon: "/onixbyte-icon.svg",
|
||||
logo: {
|
||||
light: "/onixbyte-light-logo.svg",
|
||||
dark: "/onixbyte-dark-logo.svg",
|
||||
},
|
||||
/**
|
||||
* Per-route `<head>` additions.
|
||||
*
|
||||
* `og:title`, `og:description`, `description` and `og:type` are
|
||||
* deliberately absent: the theme's `HeadTags` already emits them from the
|
||||
* page title and site description, and site-level `head` entries do not
|
||||
* take part in its de-duplication — adding them here would produce
|
||||
* duplicate tags.
|
||||
*/
|
||||
head: [
|
||||
(route) => {
|
||||
const canonical = `${origin}${route.routePath}`
|
||||
const bare = bareRoutePath(localePrefix, route.routePath, route.lang)
|
||||
const otherLang = LANGS.find((lang) => lang !== route.lang) ?? route.lang
|
||||
const alternate = `${origin}${localePrefix(otherLang)}${bare === "/" ? "/" : bare}`
|
||||
const defaultUrl = `${origin}${bare === "/" ? "/" : bare}`
|
||||
|
||||
return [
|
||||
`<link rel="canonical" href="${canonical}">`,
|
||||
`<link rel="alternate" hreflang="${HREFLANG[route.lang]}" href="${canonical}">`,
|
||||
`<link rel="alternate" hreflang="${HREFLANG[otherLang]}" href="${alternate}">`,
|
||||
`<link rel="alternate" hreflang="x-default" href="${defaultUrl}">`,
|
||||
`<meta property="og:url" content="${canonical}">`,
|
||||
`<meta property="og:site_name" content="OnixByte">`,
|
||||
`<meta property="og:locale" content="${OG_LOCALE[route.lang]}">`,
|
||||
`<meta property="og:image" content="${origin}/og-image.png">`,
|
||||
`<meta name="twitter:card" content="summary_large_image">`,
|
||||
].join("")
|
||||
},
|
||||
],
|
||||
themeConfig: {
|
||||
// NOTE: `footer` is intentionally not set — the site footer is the
|
||||
// `SiteFooter` component wired through the Layout `bottom` slot. Setting
|
||||
// `footer.message` here would render the built-in `HomeFooter` on top of
|
||||
// it on the home page only.
|
||||
//
|
||||
// `nav` and `sidebar` are also intentionally not set: supplying either
|
||||
// switches off auto-generation and would make every `_nav.json` and
|
||||
// `_meta.json` inert.
|
||||
socialLinks,
|
||||
lastUpdated: true,
|
||||
},
|
||||
markdown: {
|
||||
showLineNumbers: true,
|
||||
},
|
||||
lang: "en-gb",
|
||||
locales: [
|
||||
{
|
||||
lang: "en-gb",
|
||||
label: "English (Great Britain)",
|
||||
title: "OnixByte",
|
||||
description: "OnixByte Official",
|
||||
},
|
||||
{
|
||||
lang: "zh-hans",
|
||||
label: "简体中文",
|
||||
title: "OnixByte",
|
||||
description: "OnixByte 官方站点",
|
||||
lang: defaultLang,
|
||||
// The default locale is listed first so the language switcher leads with it.
|
||||
locales: [defaultLang, ...LANGS.filter((lang) => lang !== defaultLang)].map((lang) => ({
|
||||
lang,
|
||||
label: LOCALE_LABELS[lang],
|
||||
...LOCALE_META[lang],
|
||||
})),
|
||||
// Local full-text search. This is already the Rspress v2 default; stated
|
||||
// explicitly so the intent is visible. The index is emitted per locale to
|
||||
// `static/search_index.<lang>.<hash>.json` at build time.
|
||||
search: {
|
||||
mode: "local",
|
||||
codeBlocks: true,
|
||||
},
|
||||
plugins: [
|
||||
pluginSitemap({
|
||||
siteUrl: origin,
|
||||
defaultChangeFreq: "weekly",
|
||||
defaultPriority: "0.5",
|
||||
// Double assertion rather than a plain cast: the plugin's `Sitemap` type
|
||||
// requires `loc`, so the two types do not overlap enough for a single
|
||||
// assertion. See `sitemapPriorities` above for why omitting it is right.
|
||||
customMaps: sitemapPriorities(localePrefix) as unknown as CustomMapsOption,
|
||||
}),
|
||||
pluginRobots(origin),
|
||||
],
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default createConfig("com")
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Inline SVG markup for social links that Rspress ships no preset icon for.
|
||||
*
|
||||
* Values are injected verbatim as innerHTML by the theme's `SocialLink`
|
||||
* component, so each must be a complete `<svg>` element. Match the shape
|
||||
* Rspress uses for its presets so the icons sit consistently in the nav bar:
|
||||
*
|
||||
* <svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 24 24">
|
||||
* <path fill="currentColor" d="…" />
|
||||
* </svg>
|
||||
*
|
||||
* `width="100%"` lets the nav bar size the glyph; the viewBox carries the
|
||||
* aspect ratio, so keep whatever coordinate system the source artwork uses.
|
||||
* `fill="currentColor"` is essential — the presets all set it, and without it
|
||||
* a path defaults to solid black and disappears in dark mode.
|
||||
*
|
||||
* Rspress's built-in set covers Weibo, Bilibili, Zhihu, Juejin, QQ and WeChat,
|
||||
* but not Douyin. Adding such an icon to the preset registry is not possible
|
||||
* from userland — `getSocialIcons` throws on any name it does not recognise —
|
||||
* so a literal SVG string is the supported route.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Official Douyin mark.
|
||||
*
|
||||
* The source artwork is authored on a 1024×1024 grid and fills it exactly
|
||||
* (the glyph runs from y=0 to y=1024), so the viewBox is carried through
|
||||
* unchanged. Editor attributes from the export (`t`, `class`, `version`,
|
||||
* `p-id`, the fixed pixel `width`/`height`) have been dropped; `width="100%"`
|
||||
* and `fill="currentColor"` are set here instead.
|
||||
*/
|
||||
export const DOUYIN_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 1024 1024"><path fill="currentColor" d="M937.4 423.9c-84 0-165.7-27.3-232.9-77.8v352.3c0 179.9-138.6 325.6-309.6 325.6S85.3 878.3 85.3 698.4c0-179.9 138.6-325.6 309.6-325.6 17.1 0 33.7 1.5 49.9 4.3v186.6c-15.5-6.1-32-9.2-48.6-9.2-76.3 0-138.2 65-138.2 145.3 0 80.2 61.9 145.3 138.2 145.3 76.2 0 138.1-65.1 138.1-145.3V0H707c0 134.5 103.7 243.5 231.6 243.5v180.3l-1.2 0.1"/></svg>`
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
"value": "CN"
|
||||
}
|
||||
],
|
||||
"destination": "https://onixbyte.cn/:path*",
|
||||
"destination": "https://opensource.onixbyte.cn/:path*",
|
||||
"permanent": false
|
||||
}
|
||||
]
|
||||
|
||||
Reference in new issue
Block a user