From 48bbc1f8b873294044661bae0bb6f50d7f9b56b2 Mon Sep 17 00:00:00 2001 From: chenos Date: Fri, 26 Jun 2026 10:11:00 +0800 Subject: [PATCH] fix(cli): support pnpm and yarn global self update (#9912) * fix(cli): support pnpm and yarn global self update * fix(cli): detect pnpm global installs in self check * fix(cli): detect hashed pnpm global installs * test(cli): cover custom pnpm global roots --- docs/docs/cn/api/cli/config/delete.md | 1 + docs/docs/cn/api/cli/config/index.md | 8 +- docs/docs/cn/api/cli/config/set.md | 1 + docs/docs/cn/api/cli/self/check.md | 21 +- docs/docs/cn/api/cli/self/index.md | 2 +- docs/docs/cn/api/cli/self/update.md | 20 +- docs/docs/cn/nocobase-cli/installation/cli.md | 2 + docs/docs/de/api/cli/config/delete.md | 1 + docs/docs/de/api/cli/config/index.md | 5 +- docs/docs/de/api/cli/config/set.md | 1 + docs/docs/de/api/cli/self/check.md | 19 +- docs/docs/de/api/cli/self/index.md | 2 +- docs/docs/de/api/cli/self/update.md | 20 +- docs/docs/de/nocobase-cli/installation/cli.md | 2 + docs/docs/en/api/cli/config/delete.md | 1 + docs/docs/en/api/cli/config/index.md | 5 +- docs/docs/en/api/cli/config/set.md | 1 + docs/docs/en/api/cli/self/check.md | 21 +- docs/docs/en/api/cli/self/index.md | 2 +- docs/docs/en/api/cli/self/update.md | 20 +- docs/docs/en/nocobase-cli/installation/cli.md | 2 + docs/docs/es/api/cli/config/delete.md | 1 + docs/docs/es/api/cli/config/index.md | 5 +- docs/docs/es/api/cli/config/set.md | 1 + docs/docs/es/api/cli/self/check.md | 19 +- docs/docs/es/api/cli/self/index.md | 2 +- docs/docs/es/api/cli/self/update.md | 20 +- docs/docs/es/nocobase-cli/installation/cli.md | 2 + docs/docs/fr/api/cli/config/delete.md | 1 + docs/docs/fr/api/cli/config/index.md | 5 +- docs/docs/fr/api/cli/config/set.md | 1 + docs/docs/fr/api/cli/self/check.md | 19 +- docs/docs/fr/api/cli/self/index.md | 2 +- docs/docs/fr/api/cli/self/update.md | 20 +- docs/docs/fr/nocobase-cli/installation/cli.md | 2 + docs/docs/id/api/cli/config/delete.md | 1 + docs/docs/id/api/cli/config/index.md | 5 +- docs/docs/id/api/cli/config/set.md | 1 + docs/docs/id/api/cli/self/check.md | 19 +- docs/docs/id/api/cli/self/index.md | 2 +- docs/docs/id/api/cli/self/update.md | 20 +- docs/docs/id/nocobase-cli/installation/cli.md | 2 + docs/docs/ja/api/cli/config/delete.md | 1 + docs/docs/ja/api/cli/config/index.md | 5 +- docs/docs/ja/api/cli/config/set.md | 1 + docs/docs/ja/api/cli/self/check.md | 19 +- docs/docs/ja/api/cli/self/index.md | 2 +- docs/docs/ja/api/cli/self/update.md | 20 +- docs/docs/ja/nocobase-cli/installation/cli.md | 2 + docs/docs/pt/api/cli/config/delete.md | 1 + docs/docs/pt/api/cli/config/index.md | 5 +- docs/docs/pt/api/cli/config/set.md | 1 + docs/docs/pt/api/cli/self/check.md | 19 +- docs/docs/pt/api/cli/self/index.md | 2 +- docs/docs/pt/api/cli/self/update.md | 20 +- docs/docs/pt/nocobase-cli/installation/cli.md | 2 + docs/docs/ru/api/cli/config/delete.md | 1 + docs/docs/ru/api/cli/config/index.md | 5 +- docs/docs/ru/api/cli/config/set.md | 1 + docs/docs/ru/api/cli/self/check.md | 19 +- docs/docs/ru/api/cli/self/index.md | 2 +- docs/docs/ru/api/cli/self/update.md | 20 +- docs/docs/ru/nocobase-cli/installation/cli.md | 2 + docs/docs/vi/api/cli/config/delete.md | 1 + docs/docs/vi/api/cli/config/index.md | 5 +- docs/docs/vi/api/cli/config/set.md | 1 + docs/docs/vi/api/cli/self/check.md | 19 +- docs/docs/vi/api/cli/self/index.md | 2 +- docs/docs/vi/api/cli/self/update.md | 20 +- docs/docs/vi/nocobase-cli/installation/cli.md | 2 + .../src/__tests__/self-command-logs.test.ts | 56 +++ .../cli/src/__tests__/self-manager.test.ts | 412 +++++++++++++++--- .../cli/src/__tests__/startup-update.test.ts | 20 + packages/core/cli/src/commands/self/update.ts | 4 +- packages/core/cli/src/lib/auth-store.ts | 23 +- packages/core/cli/src/lib/cli-config.ts | 19 + packages/core/cli/src/lib/run-npm.ts | 4 + packages/core/cli/src/lib/self-manager.ts | 390 ++++++++++++++--- packages/core/cli/src/lib/startup-update.ts | 2 +- 79 files changed, 1257 insertions(+), 180 deletions(-) diff --git a/docs/docs/cn/api/cli/config/delete.md b/docs/docs/cn/api/cli/config/delete.md index b62ffe2ed70..77c10fc6ae9 100644 --- a/docs/docs/cn/api/cli/config/delete.md +++ b/docs/docs/cn/api/cli/config/delete.md @@ -31,6 +31,7 @@ nb config delete proxy.nb-cli-root nb config delete proxy.upstream-host nb config delete bin.nginx nb config delete bin.git +nb config delete bin.pnpm ``` ## 相关命令 diff --git a/docs/docs/cn/api/cli/config/index.md b/docs/docs/cn/api/cli/config/index.md index 419c46e5b3b..b2cd741709a 100644 --- a/docs/docs/cn/api/cli/config/index.md +++ b/docs/docs/cn/api/cli/config/index.md @@ -10,7 +10,7 @@ keywords: "nb config,NocoBase CLI,配置,默认配置" - CLI 自身:`locale`、`update.policy`、`license.pkg-url` - Docker 运行:`docker.network`、`docker.container-prefix` -- 外部可执行文件:`bin.docker`、`bin.caddy`、`bin.git`、`bin.nginx`、`bin.yarn` +- 外部可执行文件:`bin.docker`、`bin.caddy`、`bin.git`、`bin.nginx`、`bin.pnpm`、`bin.yarn` - 代理生成:`proxy.nb-cli-root`、`proxy.upstream-host`、`proxy.nginx-driver`、`proxy.caddy-driver` ## 常用配置项 @@ -26,6 +26,7 @@ keywords: "nb config,NocoBase CLI,配置,默认配置" | `bin.caddy` | `caddy` | 覆盖 Caddy 可执行文件路径 | | `bin.git` | `git` | 覆盖 Git 可执行文件路径 | | `bin.nginx` | `nginx` | 覆盖 Nginx 可执行文件路径 | +| `bin.pnpm` | `pnpm` | 覆盖 pnpm 可执行文件路径 | | `bin.yarn` | `yarn` | 覆盖 Yarn 可执行文件路径 | | `proxy.nb-cli-root` | CLI root(通常是当前用户 Home 目录) | 把 `.nocobase` 路径映射到代理进程实际看到的根目录 | | `proxy.upstream-host` | `127.0.0.1` | 代理回源到 NocoBase 应用时使用的主机地址 | @@ -62,9 +63,14 @@ nb config get docker.network nb config set docker.network nocobase nb config set bin.nginx /usr/sbin/nginx nb config set bin.git /usr/bin/git +nb config set bin.pnpm /usr/local/bin/pnpm nb config delete docker.container-prefix ``` +## 说明 + +`bin.pnpm` 会在命令需要直接运行 pnpm 时使用,比如 `nb self update` 更新由 pnpm 管理的全局 CLI 安装。 + ## 相关命令 - [`nb init`](../init.md) diff --git a/docs/docs/cn/api/cli/config/set.md b/docs/docs/cn/api/cli/config/set.md index 77cc19d25f4..e229b473403 100644 --- a/docs/docs/cn/api/cli/config/set.md +++ b/docs/docs/cn/api/cli/config/set.md @@ -33,6 +33,7 @@ nb config set bin.docker /usr/local/bin/docker nb config set bin.caddy /opt/homebrew/bin/caddy nb config set bin.git /usr/bin/git nb config set bin.nginx /usr/sbin/nginx +nb config set bin.pnpm /usr/local/bin/pnpm nb config set proxy.nb-cli-root /workspace nb config set proxy.upstream-host host.docker.internal nb config set bin.yarn yarn diff --git a/docs/docs/cn/api/cli/self/check.md b/docs/docs/cn/api/cli/self/check.md index 39c4819a716..721ee2ef8bd 100644 --- a/docs/docs/cn/api/cli/self/check.md +++ b/docs/docs/cn/api/cli/self/check.md @@ -6,7 +6,7 @@ keywords: "nb self check,NocoBase CLI,版本检查" # nb self check -检查当前 NocoBase CLI 安装,解析所选 channel 的最新版本,并报告是否支持自动自更新。 +检查当前 NocoBase CLI 安装,解析所选 channel 的最新版本,并报告是否支持自更新。 ## 用法 @@ -18,9 +18,26 @@ nb self check [flags] | 参数 | 类型 | 说明 | | --- | --- | --- | -| `--channel` | string | 对比的发布 channel,默认 `auto`;可选 `auto`、`latest`、`beta`、`alpha` | +| `--channel` | string | 对比的发布 channel,默认 `auto`;可选 `auto`、`latest`、`test`、`beta`、`alpha` | | `--json` | boolean | 输出 JSON | +## 安装方式 + +`nb self check` 会在运行时检测当前安装方式,不会使用历史的 `self-install-methods.json` 缓存结果。 + +命令可能输出以下安装方式: + +| 安装方式 | 含义 | +| --- | --- | +| `npm-global` | CLI 安装在当前 `npm prefix -g` 目录下 | +| `pnpm-global` | CLI 安装在 pnpm 全局 `node_modules` 目录下 | +| `yarn-global` | CLI 从 `yarn global bin` 启动,或安装在 `yarn global dir` 目录下 | +| `package-local` | CLI 安装在某个本地项目的依赖树里 | +| `source` | CLI 正在从源码仓库运行 | +| `unknown` | 无法匹配到受支持的安装方式 | + +`npm-global`、`pnpm-global` 和 `yarn-global` 支持自更新。如果是 `package-local` 或 `source`,则需要更新对应的父项目依赖或源码仓库。 + ## 示例 ```bash diff --git a/docs/docs/cn/api/cli/self/index.md b/docs/docs/cn/api/cli/self/index.md index 1a79a9c3a84..e87356c774e 100644 --- a/docs/docs/cn/api/cli/self/index.md +++ b/docs/docs/cn/api/cli/self/index.md @@ -19,7 +19,7 @@ nb self | 命令 | 说明 | | --- | --- | | [`nb self check`](./check.md) | 检查当前 CLI 版本和自更新支持情况 | -| [`nb self update`](./update.md) | 更新全局 npm 安装的 NocoBase CLI | +| [`nb self update`](./update.md) | 更新全局 npm、pnpm 或 yarn 安装的 NocoBase CLI | ## 示例 diff --git a/docs/docs/cn/api/cli/self/update.md b/docs/docs/cn/api/cli/self/update.md index 50f47e5f782..b71b706084e 100644 --- a/docs/docs/cn/api/cli/self/update.md +++ b/docs/docs/cn/api/cli/self/update.md @@ -1,12 +1,12 @@ --- title: "nb self update" -description: "nb self update 命令参考:更新全局 npm 安装的 NocoBase CLI。" +description: "nb self update 命令参考:更新全局 npm、pnpm 或 yarn 安装的 NocoBase CLI。" keywords: "nb self update,NocoBase CLI,更新,自更新" --- # nb self update -当当前 CLI 由标准全局 npm 安装管理时,更新已安装的 NocoBase CLI。 +当当前 CLI 由标准全局 npm、pnpm 或 yarn 安装管理时,更新已安装的 NocoBase CLI。 ## 用法 @@ -18,12 +18,26 @@ nb self update [flags] | 参数 | 类型 | 说明 | | --- | --- | --- | -| `--channel` | string | 更新到的发布 channel,默认 `auto`;可选 `auto`、`latest`、`beta`、`alpha` | +| `--channel` | string | 更新到的发布 channel,默认 `auto`;可选 `auto`、`latest`、`test`、`beta`、`alpha` | | `--yes`, `-y` | boolean | 跳过更新确认 | | `--json` | boolean | 输出 JSON | | `--skills` | boolean | 同时刷新全局安装的 NocoBase AI coding skills | | `--verbose` | boolean | 显示详细更新输出 | +## 更新行为 + +`nb self update` 会先在运行时检测当前安装方式,不会使用历史的 `self-install-methods.json` 缓存结果。 + +如果有新版本,命令会使用当前全局 CLI 安装对应的包管理器更新: + +| 安装方式 | 更新命令 | +| --- | --- | +| `npm-global` | `npm install -g @nocobase/cli@` | +| `pnpm-global` | `pnpm add -g @nocobase/cli@` | +| `yarn-global` | `yarn global add @nocobase/cli@` | + +交互式确认默认选择 yes。脚本里可以使用 `--yes` 跳过确认。 + ## 示例 ```bash diff --git a/docs/docs/cn/nocobase-cli/installation/cli.md b/docs/docs/cn/nocobase-cli/installation/cli.md index 30e6f3196e8..c26beb147b9 100644 --- a/docs/docs/cn/nocobase-cli/installation/cli.md +++ b/docs/docs/cn/nocobase-cli/installation/cli.md @@ -41,6 +41,8 @@ nb config set update.policy auto nb config set update.policy off ``` +自更新只支持由标准全局 npm、pnpm 或 yarn 安装管理的 CLI。如果你是从源码仓库运行,或者从本地项目依赖树运行,可以用 [`nb self check`](../../api/cli/self/check.md) 查看当前检测到的安装方式,然后更新对应的父项目。 + 如果你准备把 NocoBase 部署到服务器上,并且希望从远程浏览器打开 `nb init --ui` 向导,建议先把 CLI 的默认 host 改成当前服务器 IP: ```bash diff --git a/docs/docs/de/api/cli/config/delete.md b/docs/docs/de/api/cli/config/delete.md index f326dae5f76..044e8def8da 100644 --- a/docs/docs/de/api/cli/config/delete.md +++ b/docs/docs/de/api/cli/config/delete.md @@ -31,6 +31,7 @@ nb config delete proxy.nb-cli-root nb config delete proxy.upstream-host nb config delete bin.nginx nb config delete bin.git +nb config delete bin.pnpm ``` ## Verwandte Befehle diff --git a/docs/docs/de/api/cli/config/index.md b/docs/docs/de/api/cli/config/index.md index 3c6ca6e91d8..1da48292ba3 100644 --- a/docs/docs/de/api/cli/config/index.md +++ b/docs/docs/de/api/cli/config/index.md @@ -10,7 +10,7 @@ Verwaltet die Standard-Konfigurationswerte der CLI. Die aktuell unterstützten S - CLI selbst: `locale`, `update.policy`, `license.pkg-url` - Docker-Runtime: `docker.network`, `docker.container-prefix` -- Externe ausführbare Dateien: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.yarn` +- Externe ausführbare Dateien: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.pnpm`, `bin.yarn` - Proxy-Erzeugung: `proxy.nb-cli-root`, `proxy.upstream-host`, `proxy.nginx-driver`, `proxy.caddy-driver` Die meisten Projekte brauchen nur wenige dieser Schlüssel. In der Praxis werden am häufigsten diese verwendet: @@ -34,6 +34,7 @@ Die meisten Projekte brauchen nur wenige dieser Schlüssel. In der Praxis werden | `bin.caddy` | `caddy` | Überschreibt den Pfad zur Caddy-Binärdatei | | `bin.git` | `git` | Überschreibt den Pfad zur Git-Binärdatei | | `bin.nginx` | `nginx` | Überschreibt den Pfad zur Nginx-Binärdatei | +| `bin.pnpm` | `pnpm` | Überschreibt den Pfad zur pnpm-Binärdatei | | `bin.yarn` | `yarn` | Überschreibt den Pfad zur Yarn-Binärdatei | | `proxy.nb-cli-root` | CLI-Root, normalerweise das Home-Verzeichnis des aktuellen Benutzers | Ordnet den `.nocobase`-Pfad auf den Root-Pfad ab, den der Proxy-Prozess tatsächlich sieht | | `proxy.upstream-host` | `127.0.0.1` | Überschreibt die Host-Adresse, die der Proxy für die Rückleitung zur NocoBase-Anwendung verwendet | @@ -70,12 +71,14 @@ nb config get docker.network nb config set docker.network nocobase nb config set bin.nginx /usr/sbin/nginx nb config set bin.git /usr/bin/git +nb config set bin.pnpm /usr/local/bin/pnpm nb config delete docker.container-prefix ``` ## Hinweise - `bin.nginx` und `bin.caddy` wirken sich nur auf den `local`-Driver von `nb proxy nginx` und `nb proxy caddy` aus +- `bin.pnpm` wird verwendet, wenn Befehle pnpm direkt ausführen müssen, etwa beim Aktualisieren einer von pnpm verwalteten globalen CLI-Installation mit `nb self update` - `proxy.nginx-driver` und `proxy.caddy-driver` speichern den Standard-Driver des jeweiligen Providers - `proxy.nb-cli-root` und `proxy.upstream-host` sind erweiterte Proxy-Overrides. Für die meisten CLI-verwalteten `local`- oder `docker`-Envs reichen die Standardwerte aus - Wenn du nur den aktiven Proxy-Driver umschalten möchtest, ist `nb proxy nginx use` oder `nb proxy caddy use` in der Regel klarer als das manuelle Setzen des Konfigurationsschlüssels diff --git a/docs/docs/de/api/cli/config/set.md b/docs/docs/de/api/cli/config/set.md index b4c387b4fc4..6c739cfa8b1 100644 --- a/docs/docs/de/api/cli/config/set.md +++ b/docs/docs/de/api/cli/config/set.md @@ -33,6 +33,7 @@ nb config set bin.docker /usr/local/bin/docker nb config set bin.caddy /opt/homebrew/bin/caddy nb config set bin.git /usr/bin/git nb config set bin.nginx /usr/sbin/nginx +nb config set bin.pnpm /usr/local/bin/pnpm nb config set proxy.nb-cli-root /workspace nb config set proxy.upstream-host host.docker.internal nb config set bin.yarn yarn diff --git a/docs/docs/de/api/cli/self/check.md b/docs/docs/de/api/cli/self/check.md index 71b676fdf01..0a43fef3a1d 100644 --- a/docs/docs/de/api/cli/self/check.md +++ b/docs/docs/de/api/cli/self/check.md @@ -18,9 +18,26 @@ nb self check [flags] | Parameter | Typ | Beschreibung | | --- | --- | --- | -| `--channel` | string | Release-Channel zum Vergleich, Standard `auto`; mögliche Werte: `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Release-Channel zum Vergleich, Standard `auto`; mögliche Werte: `auto`, `latest`, `test`, `beta`, `alpha` | | `--json` | boolean | Ausgabe als JSON | +## Installationsmethode + +`nb self check` erkennt die aktuelle Installationsmethode zur Laufzeit. Der historische Cache `self-install-methods.json` wird nicht verwendet. + +Der Befehl kann diese Installationsmethoden ausgeben: + +| Installationsmethode | Bedeutung | +| --- | --- | +| `npm-global` | Die CLI ist unter dem aktuellen `npm prefix -g` installiert. | +| `pnpm-global` | Die CLI ist in einem globalen `node_modules`-Baum von pnpm installiert. | +| `yarn-global` | Die CLI wird aus `yarn global bin` gestartet oder ist unter `yarn global dir` installiert. | +| `package-local` | Die CLI ist in einem lokalen Projekt-Dependency-Baum installiert. | +| `source` | Die CLI läuft aus einem Repository-Checkout. | +| `unknown` | Die CLI-Installation konnte keiner unterstützten Installationsmethode zugeordnet werden. | + +Selbstaktualisierung wird für `npm-global`, `pnpm-global` und `yarn-global` unterstützt. Bei `package-local` oder `source` aktualisierst du stattdessen das übergeordnete Projekt oder den Repository-Checkout. + ## Beispiele ```bash diff --git a/docs/docs/de/api/cli/self/index.md b/docs/docs/de/api/cli/self/index.md index 990d9461dce..2424892c68b 100644 --- a/docs/docs/de/api/cli/self/index.md +++ b/docs/docs/de/api/cli/self/index.md @@ -19,7 +19,7 @@ nb self | Befehl | Beschreibung | | --- | --- | | [`nb self check`](./check.md) | Prüft die aktuelle CLI-Version und die Unterstützung für Selbstaktualisierung | -| [`nb self update`](./update.md) | Aktualisiert die global per npm installierte NocoBase CLI | +| [`nb self update`](./update.md) | Aktualisiert die global per npm, pnpm oder yarn installierte NocoBase CLI | ## Beispiele diff --git a/docs/docs/de/api/cli/self/update.md b/docs/docs/de/api/cli/self/update.md index 9313217772e..ae697dce1df 100644 --- a/docs/docs/de/api/cli/self/update.md +++ b/docs/docs/de/api/cli/self/update.md @@ -1,12 +1,12 @@ --- title: "nb self update" -description: "nb self update Befehlsreferenz: Aktualisiert die global per npm installierte NocoBase CLI." +description: "nb self update Befehlsreferenz: Aktualisiert die global per npm, pnpm oder yarn installierte NocoBase CLI." keywords: "nb self update,NocoBase CLI,Aktualisierung,Selbstaktualisierung" --- # nb self update -Aktualisiert die installierte NocoBase CLI, sofern die aktuelle CLI durch eine standardmäßige globale npm-Installation verwaltet wird. +Aktualisiert die installierte NocoBase CLI, sofern die aktuelle CLI durch eine standardmäßige globale npm-, pnpm- oder yarn-Installation verwaltet wird. ## Verwendung @@ -18,12 +18,26 @@ nb self update [flags] | Parameter | Typ | Beschreibung | | --- | --- | --- | -| `--channel` | string | Release-Channel, auf den aktualisiert werden soll, Standard `auto`; mögliche Werte: `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Release-Channel, auf den aktualisiert werden soll, Standard `auto`; mögliche Werte: `auto`, `latest`, `test`, `beta`, `alpha` | | `--yes`, `-y` | boolean | Bestätigung der Aktualisierung überspringen | | `--json` | boolean | Ausgabe als JSON | | `--skills` | boolean | Die global installierten NocoBase AI coding skills ebenfalls aktualisieren | | `--verbose` | boolean | Ausführliche Ausgabe der Aktualisierung anzeigen | +## Aktualisierungsverhalten + +`nb self update` erkennt zuerst die aktuelle Installationsmethode zur Laufzeit. Der historische Cache `self-install-methods.json` wird nicht verwendet. + +Wenn ein Update verfügbar ist, verwendet der Befehl denselben Package Manager, der die aktuelle globale CLI-Installation verwaltet: + +| Installationsmethode | Update-Befehl | +| --- | --- | +| `npm-global` | `npm install -g @nocobase/cli@` | +| `pnpm-global` | `pnpm add -g @nocobase/cli@` | +| `yarn-global` | `yarn global add @nocobase/cli@` | + +Die interaktive Bestätigung ist standardmäßig yes. Verwende `--yes`, um die Abfrage in Scripts zu überspringen. + ## Beispiele ```bash diff --git a/docs/docs/de/nocobase-cli/installation/cli.md b/docs/docs/de/nocobase-cli/installation/cli.md index 49e8940d4ec..6e82238f8a1 100644 --- a/docs/docs/de/nocobase-cli/installation/cli.md +++ b/docs/docs/de/nocobase-cli/installation/cli.md @@ -35,6 +35,8 @@ nb config set update.policy auto nb config set update.policy off ``` +Selbstaktualisierung wird nur unterstützt, wenn die CLI durch eine standardmäßige globale npm-, pnpm- oder yarn-Installation verwaltet wird. Wenn sie aus dem Quellcode oder aus einem lokalen Projekt-Dependency-Baum läuft, verwenden Sie [`nb self check`](../../api/cli/self/check.md), um die erkannte Installationsmethode zu prüfen, und aktualisieren Sie stattdessen dieses übergeordnete Projekt. + Wenn Sie NocoBase auf dem Server bereitstellen und den `nb init --ui`-Assistenten über einen Remote-Browser öffnen möchten, wird empfohlen, zunächst den Standardhost der CLI auf die aktuelle Server-IP zu ändern: ```bash diff --git a/docs/docs/en/api/cli/config/delete.md b/docs/docs/en/api/cli/config/delete.md index 4deaa1c494e..a4c6f6fc302 100644 --- a/docs/docs/en/api/cli/config/delete.md +++ b/docs/docs/en/api/cli/config/delete.md @@ -33,6 +33,7 @@ nb config delete proxy.nginx-driver nb config delete proxy.caddy-driver nb config delete bin.nginx nb config delete bin.git +nb config delete bin.pnpm ``` ## Related commands diff --git a/docs/docs/en/api/cli/config/index.md b/docs/docs/en/api/cli/config/index.md index 6f1f4d415c5..a2f86efb0bf 100644 --- a/docs/docs/en/api/cli/config/index.md +++ b/docs/docs/en/api/cli/config/index.md @@ -10,7 +10,7 @@ Manage default CLI configuration values. The currently supported keys are mainly - CLI itself: `locale`, `update.policy`, `license.pkg-url` - Docker runtime: `docker.network`, `docker.container-prefix` -- External executables: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.yarn` +- External executables: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.pnpm`, `bin.yarn` - Proxy generation: `proxy.nb-cli-root`, `proxy.upstream-host`, `proxy.nginx-driver`, `proxy.caddy-driver` Most projects only need a few of these keys. In practice, the most common ones are: @@ -34,6 +34,7 @@ Most projects only need a few of these keys. In practice, the most common ones a | `bin.caddy` | `caddy` | Override the Caddy executable path | | `bin.git` | `git` | Override the Git executable path | | `bin.nginx` | `nginx` | Override the Nginx executable path | +| `bin.pnpm` | `pnpm` | Override the pnpm executable path | | `bin.yarn` | `yarn` | Override the Yarn executable path | | `proxy.nb-cli-root` | CLI root, usually the current user's home directory | Override the root path visible to the generated proxy config when the proxy process and CLI do not see the same filesystem root | | `proxy.upstream-host` | `127.0.0.1` | Override the host used when the proxy forwards traffic back to the NocoBase app | @@ -70,12 +71,14 @@ nb config get docker.network nb config set docker.network nocobase nb config set bin.nginx /usr/sbin/nginx nb config set bin.git /usr/bin/git +nb config set bin.pnpm /usr/local/bin/pnpm nb config delete docker.container-prefix ``` ## Notes - `bin.nginx` and `bin.caddy` only affect the `local` driver for `nb proxy nginx` and `nb proxy caddy` +- `bin.pnpm` is used when commands need to run pnpm directly, such as updating a pnpm-managed global CLI install with `nb self update` - `proxy.nginx-driver` and `proxy.caddy-driver` store the default driver used by each provider - `proxy.nb-cli-root` and `proxy.upstream-host` are advanced proxy overrides. Most CLI-managed `local` or `docker` envs can use the defaults directly - If you only want to switch the active proxy driver, using `nb proxy nginx use` or `nb proxy caddy use` is usually clearer than setting the config key manually diff --git a/docs/docs/en/api/cli/config/set.md b/docs/docs/en/api/cli/config/set.md index b406366e693..d3cbe334bb5 100644 --- a/docs/docs/en/api/cli/config/set.md +++ b/docs/docs/en/api/cli/config/set.md @@ -33,6 +33,7 @@ nb config set bin.docker /usr/local/bin/docker nb config set bin.caddy /opt/homebrew/bin/caddy nb config set bin.git /usr/bin/git nb config set bin.nginx /usr/sbin/nginx +nb config set bin.pnpm /usr/local/bin/pnpm nb config set proxy.nb-cli-root /workspace nb config set proxy.upstream-host host.docker.internal nb config set proxy.nginx-driver docker diff --git a/docs/docs/en/api/cli/self/check.md b/docs/docs/en/api/cli/self/check.md index e00746a495f..217297bfa05 100644 --- a/docs/docs/en/api/cli/self/check.md +++ b/docs/docs/en/api/cli/self/check.md @@ -6,7 +6,7 @@ keywords: "nb self check,NocoBase CLI,version check" # nb self check -Check the current NocoBase CLI installation, resolve the latest version for the selected channel, and report whether automatic self-update is supported. +Check the current NocoBase CLI installation, resolve the latest version for the selected channel, and report whether self-update is supported. ## Usage @@ -18,9 +18,26 @@ nb self check [flags] | Parameter | Type | Description | | --- | --- | --- | -| `--channel` | string | Release channel to compare with, default `auto`; options: `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Release channel to compare with, default `auto`; options: `auto`, `latest`, `test`, `beta`, `alpha` | | `--json` | boolean | Output JSON | +## Install Method + +`nb self check` detects the current install method at runtime. It does not use the historical `self-install-methods.json` cache. + +The command can report these install methods: + +| Install method | Meaning | +| --- | --- | +| `npm-global` | The CLI is installed under the current `npm prefix -g`. | +| `pnpm-global` | The CLI is installed under a pnpm global `node_modules` tree. | +| `yarn-global` | The CLI is launched from `yarn global bin` or installed under `yarn global dir`. | +| `package-local` | The CLI is installed in a local project dependency tree. | +| `source` | The CLI is running from a repository checkout. | +| `unknown` | The CLI install could not be matched to a supported install method. | + +Self-update is supported for `npm-global`, `pnpm-global`, and `yarn-global`. For `package-local` or `source`, update the parent project or repository checkout instead. + ## Examples ```bash diff --git a/docs/docs/en/api/cli/self/index.md b/docs/docs/en/api/cli/self/index.md index 7fe21bbb559..e29538172eb 100644 --- a/docs/docs/en/api/cli/self/index.md +++ b/docs/docs/en/api/cli/self/index.md @@ -19,7 +19,7 @@ nb self | Command | Description | | --- | --- | | [`nb self check`](./check.md) | Check current CLI version and self-update support | -| [`nb self update`](./update.md) | Update the globally npm-installed NocoBase CLI | +| [`nb self update`](./update.md) | Update the globally npm-, pnpm-, or yarn-installed NocoBase CLI | ## Examples diff --git a/docs/docs/en/api/cli/self/update.md b/docs/docs/en/api/cli/self/update.md index 16d53304cbd..63b3d73898b 100644 --- a/docs/docs/en/api/cli/self/update.md +++ b/docs/docs/en/api/cli/self/update.md @@ -1,12 +1,12 @@ --- title: "nb self update" -description: "nb self update command reference: update the globally npm-installed NocoBase CLI." +description: "nb self update command reference: update the globally npm-, pnpm-, or yarn-installed NocoBase CLI." keywords: "nb self update,NocoBase CLI,update,self update" --- # nb self update -Update the installed NocoBase CLI when the current CLI is managed by a standard global npm installation. +Update the installed NocoBase CLI when the current CLI is managed by a standard global npm, pnpm, or yarn installation. ## Usage @@ -18,12 +18,26 @@ nb self update [flags] | Parameter | Type | Description | | --- | --- | --- | -| `--channel` | string | Release channel to update to, default `auto`; options: `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Release channel to update to, default `auto`; options: `auto`, `latest`, `test`, `beta`, `alpha` | | `--yes`, `-y` | boolean | Skip update confirmation | | `--json` | boolean | Output JSON | | `--skills` | boolean | Also refresh the globally installed NocoBase AI coding skills | | `--verbose` | boolean | Show detailed update output | +## Update Behavior + +`nb self update` first detects the current install method at runtime. It does not use the historical `self-install-methods.json` cache. + +When an update is available, the command uses the same package manager that manages the current global CLI install: + +| Install method | Update command | +| --- | --- | +| `npm-global` | `npm install -g @nocobase/cli@` | +| `pnpm-global` | `pnpm add -g @nocobase/cli@` | +| `yarn-global` | `yarn global add @nocobase/cli@` | + +Interactive confirmation defaults to yes. Use `--yes` to skip the prompt in scripts. + ## Examples ```bash diff --git a/docs/docs/en/nocobase-cli/installation/cli.md b/docs/docs/en/nocobase-cli/installation/cli.md index 558e9adbecc..bdc2bb4d68c 100644 --- a/docs/docs/en/nocobase-cli/installation/cli.md +++ b/docs/docs/en/nocobase-cli/installation/cli.md @@ -35,6 +35,8 @@ nb config set update.policy auto nb config set update.policy off ``` +Self-update is only supported when the CLI is managed by a standard global npm, pnpm, or yarn install. If you are running from source or from a local project dependency tree, use [`nb self check`](../../api/cli/self/check.md) to see the detected install method and update that parent project instead. + If you are going to deploy NocoBase to the server and want to open the `nb init --ui` wizard from a remote browser, it is recommended to first change the CLI's default host to the current server IP: ```bash diff --git a/docs/docs/es/api/cli/config/delete.md b/docs/docs/es/api/cli/config/delete.md index 6d4d5de7832..a61be5e1e7a 100644 --- a/docs/docs/es/api/cli/config/delete.md +++ b/docs/docs/es/api/cli/config/delete.md @@ -31,6 +31,7 @@ nb config delete proxy.nb-cli-root nb config delete proxy.upstream-host nb config delete bin.nginx nb config delete bin.git +nb config delete bin.pnpm ``` ## Comandos relacionados diff --git a/docs/docs/es/api/cli/config/index.md b/docs/docs/es/api/cli/config/index.md index 3170f308114..953c020b430 100644 --- a/docs/docs/es/api/cli/config/index.md +++ b/docs/docs/es/api/cli/config/index.md @@ -10,7 +10,7 @@ Gestiona los valores de configuración predeterminados de la CLI. Las claves com - La propia CLI: `locale`, `update.policy`, `license.pkg-url` - Runtime de Docker: `docker.network`, `docker.container-prefix` -- Ejecutables externos: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.yarn` +- Ejecutables externos: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.pnpm`, `bin.yarn` - Generación de proxy: `proxy.nb-cli-root`, `proxy.upstream-host`, `proxy.nginx-driver`, `proxy.caddy-driver` La mayoría de los proyectos solo necesitan unas pocas de estas claves. En la práctica, las más habituales son: @@ -34,6 +34,7 @@ La mayoría de los proyectos solo necesitan unas pocas de estas claves. En la pr | `bin.caddy` | `caddy` | Sobrescribe la ruta del ejecutable de Caddy | | `bin.git` | `git` | Sobrescribe la ruta del ejecutable de Git | | `bin.nginx` | `nginx` | Sobrescribe la ruta del ejecutable de Nginx | +| `bin.pnpm` | `pnpm` | Sobrescribe la ruta del ejecutable de pnpm | | `bin.yarn` | `yarn` | Sobrescribe la ruta del ejecutable de Yarn | | `proxy.nb-cli-root` | raíz de la CLI, normalmente el directorio home del usuario actual | Sobrescribe la ruta raíz visible para la configuración de proxy generada cuando el proceso del proxy y la CLI no ven la misma raíz del sistema de archivos | | `proxy.upstream-host` | `127.0.0.1` | Sobrescribe el host usado por el proxy para reenviar tráfico a la aplicación NocoBase | @@ -70,12 +71,14 @@ nb config get docker.network nb config set docker.network nocobase nb config set bin.nginx /usr/sbin/nginx nb config set bin.git /usr/bin/git +nb config set bin.pnpm /usr/local/bin/pnpm nb config delete docker.container-prefix ``` ## Notas - `bin.nginx` y `bin.caddy` solo afectan al driver `local` de `nb proxy nginx` y `nb proxy caddy` +- `bin.pnpm` se usa cuando los comandos necesitan ejecutar pnpm directamente, como al actualizar una instalación global de la CLI gestionada por pnpm con `nb self update` - `proxy.nginx-driver` y `proxy.caddy-driver` almacenan el driver predeterminado usado por cada proveedor - `proxy.nb-cli-root` y `proxy.upstream-host` son overrides avanzados del proxy. La mayoría de los entornos `local` o `docker` gestionados por la CLI pueden usar directamente los valores predeterminados - Si solo quieres cambiar el driver activo del proxy, normalmente es más claro usar `nb proxy nginx use` o `nb proxy caddy use` que establecer la clave manualmente diff --git a/docs/docs/es/api/cli/config/set.md b/docs/docs/es/api/cli/config/set.md index 7f4549dbc55..1a73b355434 100644 --- a/docs/docs/es/api/cli/config/set.md +++ b/docs/docs/es/api/cli/config/set.md @@ -33,6 +33,7 @@ nb config set bin.docker /usr/local/bin/docker nb config set bin.caddy /opt/homebrew/bin/caddy nb config set bin.git /usr/bin/git nb config set bin.nginx /usr/sbin/nginx +nb config set bin.pnpm /usr/local/bin/pnpm nb config set proxy.nb-cli-root /workspace nb config set proxy.upstream-host host.docker.internal nb config set bin.yarn yarn diff --git a/docs/docs/es/api/cli/self/check.md b/docs/docs/es/api/cli/self/check.md index 06842b8c25c..63fad2e3585 100644 --- a/docs/docs/es/api/cli/self/check.md +++ b/docs/docs/es/api/cli/self/check.md @@ -18,9 +18,26 @@ nb self check [flags] | Parámetro | Tipo | Descripción | | --- | --- | --- | -| `--channel` | string | Channel de publicación con el que comparar; valor por defecto `auto`; opciones: `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Channel de publicación con el que comparar; valor por defecto `auto`; opciones: `auto`, `latest`, `test`, `beta`, `alpha` | | `--json` | boolean | Genera la salida en JSON | +## Método de instalación + +`nb self check` detecta el método de instalación actual en tiempo de ejecución. No usa el caché histórico `self-install-methods.json`. + +El comando puede informar estos métodos de instalación: + +| Método de instalación | Significado | +| --- | --- | +| `npm-global` | La CLI está instalada bajo el `npm prefix -g` actual. | +| `pnpm-global` | La CLI está instalada en un árbol global `node_modules` de pnpm. | +| `yarn-global` | La CLI se inicia desde `yarn global bin` o está instalada bajo `yarn global dir`. | +| `package-local` | La CLI está instalada en el árbol de dependencias de un proyecto local. | +| `source` | La CLI se ejecuta desde un checkout del repositorio. | +| `unknown` | La instalación de la CLI no se pudo asociar con un método de instalación compatible. | + +La actualización automática es compatible con `npm-global`, `pnpm-global` y `yarn-global`. Para `package-local` o `source`, actualiza el proyecto padre o el checkout del repositorio. + ## Ejemplos ```bash diff --git a/docs/docs/es/api/cli/self/index.md b/docs/docs/es/api/cli/self/index.md index 40631b361d9..fe49c5c9cfb 100644 --- a/docs/docs/es/api/cli/self/index.md +++ b/docs/docs/es/api/cli/self/index.md @@ -19,7 +19,7 @@ nb self | Comando | Descripción | | --- | --- | | [`nb self check`](./check.md) | Comprueba la versión actual de la CLI y el soporte de actualización automática | -| [`nb self update`](./update.md) | Actualiza la NocoBase CLI instalada globalmente con npm | +| [`nb self update`](./update.md) | Actualiza la NocoBase CLI instalada globalmente con npm, pnpm o yarn | ## Ejemplos diff --git a/docs/docs/es/api/cli/self/update.md b/docs/docs/es/api/cli/self/update.md index 647cd152a31..4cb291293e0 100644 --- a/docs/docs/es/api/cli/self/update.md +++ b/docs/docs/es/api/cli/self/update.md @@ -1,12 +1,12 @@ --- title: "nb self update" -description: "Referencia del comando nb self update: actualiza la NocoBase CLI instalada globalmente con npm." +description: "Referencia del comando nb self update: actualiza la NocoBase CLI instalada globalmente con npm, pnpm o yarn." keywords: "nb self update,NocoBase CLI,actualizar,actualización automática" --- # nb self update -Actualiza la NocoBase CLI instalada cuando esta es gestionada por una instalación global estándar de npm. +Actualiza la NocoBase CLI instalada cuando esta es gestionada por una instalación global estándar de npm, pnpm o yarn. ## Uso @@ -18,12 +18,26 @@ nb self update [flags] | Parámetro | Tipo | Descripción | | --- | --- | --- | -| `--channel` | string | Channel de publicación al que actualizar; valor por defecto `auto`; opciones: `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Channel de publicación al que actualizar; valor por defecto `auto`; opciones: `auto`, `latest`, `test`, `beta`, `alpha` | | `--yes`, `-y` | boolean | Omite la confirmación de la actualización | | `--json` | boolean | Genera la salida en JSON | | `--skills` | boolean | También actualiza las NocoBase AI coding skills instaladas globalmente | | `--verbose` | boolean | Muestra la salida detallada de la actualización | +## Comportamiento de actualización + +`nb self update` primero detecta el método de instalación actual en tiempo de ejecución. No usa el caché histórico `self-install-methods.json`. + +Cuando hay una actualización disponible, el comando usa el mismo package manager que gestiona la instalación global actual de la CLI: + +| Método de instalación | Comando de actualización | +| --- | --- | +| `npm-global` | `npm install -g @nocobase/cli@` | +| `pnpm-global` | `pnpm add -g @nocobase/cli@` | +| `yarn-global` | `yarn global add @nocobase/cli@` | + +La confirmación interactiva tiene yes como valor predeterminado. Usa `--yes` para omitir el prompt en scripts. + ## Ejemplos ```bash diff --git a/docs/docs/es/nocobase-cli/installation/cli.md b/docs/docs/es/nocobase-cli/installation/cli.md index 359345e1afe..8e006cc4b47 100644 --- a/docs/docs/es/nocobase-cli/installation/cli.md +++ b/docs/docs/es/nocobase-cli/installation/cli.md @@ -35,6 +35,8 @@ nb config set update.policy auto nb config set update.policy off ``` +La actualización automática solo se admite cuando la CLI está gestionada por una instalación global estándar de npm, pnpm o yarn. Si se ejecuta desde el código fuente o desde el árbol de dependencias de un proyecto local, usa [`nb self check`](../../api/cli/self/check.md) para ver el método de instalación detectado y actualiza ese proyecto padre. + Si va a implementar NocoBase en el servidor y desea abrir el asistente `nb init --ui` desde un navegador remoto, se recomienda cambiar primero el host predeterminado de la CLI a la IP actual del servidor: ```bash diff --git a/docs/docs/fr/api/cli/config/delete.md b/docs/docs/fr/api/cli/config/delete.md index 7f9b6bf4038..51395d53e60 100644 --- a/docs/docs/fr/api/cli/config/delete.md +++ b/docs/docs/fr/api/cli/config/delete.md @@ -31,6 +31,7 @@ nb config delete proxy.nb-cli-root nb config delete proxy.upstream-host nb config delete bin.nginx nb config delete bin.git +nb config delete bin.pnpm ``` ## Commandes associées diff --git a/docs/docs/fr/api/cli/config/index.md b/docs/docs/fr/api/cli/config/index.md index 4e8bd51694b..010cc5d6025 100644 --- a/docs/docs/fr/api/cli/config/index.md +++ b/docs/docs/fr/api/cli/config/index.md @@ -10,7 +10,7 @@ Gère les valeurs de configuration par défaut de la CLI. Les clés actuellement - La CLI elle-même : `locale`, `update.policy`, `license.pkg-url` - Runtime Docker : `docker.network`, `docker.container-prefix` -- Exécutables externes : `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.yarn` +- Exécutables externes : `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.pnpm`, `bin.yarn` - Génération de proxy : `proxy.nb-cli-root`, `proxy.upstream-host`, `proxy.nginx-driver`, `proxy.caddy-driver` La plupart des projets n'ont besoin que de quelques-unes de ces clés. En pratique, les plus courantes sont : @@ -34,6 +34,7 @@ La plupart des projets n'ont besoin que de quelques-unes de ces clés. En pratiq | `bin.caddy` | `caddy` | Remplace le chemin de l'exécutable Caddy | | `bin.git` | `git` | Remplace le chemin de l'exécutable Git | | `bin.nginx` | `nginx` | Remplace le chemin de l'exécutable Nginx | +| `bin.pnpm` | `pnpm` | Remplace le chemin de l'exécutable pnpm | | `bin.yarn` | `yarn` | Remplace le chemin de l'exécutable Yarn | | `proxy.nb-cli-root` | racine de la CLI, généralement le répertoire personnel de l'utilisateur courant | Remplace la racine visible par la configuration proxy générée lorsque le processus proxy et la CLI ne voient pas la même racine du système de fichiers | | `proxy.upstream-host` | `127.0.0.1` | Remplace l'hôte utilisé par le proxy pour renvoyer le trafic vers l'application NocoBase | @@ -70,12 +71,14 @@ nb config get docker.network nb config set docker.network nocobase nb config set bin.nginx /usr/sbin/nginx nb config set bin.git /usr/bin/git +nb config set bin.pnpm /usr/local/bin/pnpm nb config delete docker.container-prefix ``` ## Notes - `bin.nginx` et `bin.caddy` n'affectent que le driver `local` de `nb proxy nginx` et `nb proxy caddy` +- `bin.pnpm` est utilisé lorsque des commandes doivent exécuter pnpm directement, par exemple pour mettre à jour une installation globale de la CLI gérée par pnpm avec `nb self update` - `proxy.nginx-driver` et `proxy.caddy-driver` stockent le driver par défaut utilisé par chaque provider - `proxy.nb-cli-root` et `proxy.upstream-host` sont des surcharges proxy avancées. Pour la plupart des environnements `local` ou `docker` gérés par la CLI, les valeurs par défaut suffisent - Si tu veux simplement changer le driver proxy actif, `nb proxy nginx use` ou `nb proxy caddy use` est généralement plus clair que de modifier la clé de configuration manuellement diff --git a/docs/docs/fr/api/cli/config/set.md b/docs/docs/fr/api/cli/config/set.md index b1fd77ed513..d1afeb04a91 100644 --- a/docs/docs/fr/api/cli/config/set.md +++ b/docs/docs/fr/api/cli/config/set.md @@ -33,6 +33,7 @@ nb config set bin.docker /usr/local/bin/docker nb config set bin.caddy /opt/homebrew/bin/caddy nb config set bin.git /usr/bin/git nb config set bin.nginx /usr/sbin/nginx +nb config set bin.pnpm /usr/local/bin/pnpm nb config set proxy.nb-cli-root /workspace nb config set proxy.upstream-host host.docker.internal nb config set bin.yarn yarn diff --git a/docs/docs/fr/api/cli/self/check.md b/docs/docs/fr/api/cli/self/check.md index 78e53ded947..4b493b94436 100644 --- a/docs/docs/fr/api/cli/self/check.md +++ b/docs/docs/fr/api/cli/self/check.md @@ -18,9 +18,26 @@ nb self check [flags] | Paramètre | Type | Description | | --- | --- | --- | -| `--channel` | string | Channel de release à comparer, par défaut `auto` ; valeurs possibles : `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Channel de release à comparer, par défaut `auto` ; valeurs possibles : `auto`, `latest`, `test`, `beta`, `alpha` | | `--json` | boolean | Sortie au format JSON | +## Méthode d'installation + +`nb self check` détecte la méthode d'installation courante au moment de l'exécution. Il n'utilise pas l'ancien cache `self-install-methods.json`. + +La commande peut afficher ces méthodes d'installation : + +| Méthode d'installation | Signification | +| --- | --- | +| `npm-global` | La CLI est installée sous le `npm prefix -g` courant. | +| `pnpm-global` | La CLI est installée dans un arbre global `node_modules` de pnpm. | +| `yarn-global` | La CLI est lancée depuis `yarn global bin` ou installée sous `yarn global dir`. | +| `package-local` | La CLI est installée dans l'arbre de dépendances d'un projet local. | +| `source` | La CLI s'exécute depuis un checkout du dépôt. | +| `unknown` | L'installation de la CLI n'a pas pu être associée à une méthode d'installation prise en charge. | + +La mise à jour automatique est prise en charge pour `npm-global`, `pnpm-global` et `yarn-global`. Pour `package-local` ou `source`, mets plutôt à jour le projet parent ou le checkout du dépôt. + ## Exemples ```bash diff --git a/docs/docs/fr/api/cli/self/index.md b/docs/docs/fr/api/cli/self/index.md index 7b50eeeeba8..540df5bf7db 100644 --- a/docs/docs/fr/api/cli/self/index.md +++ b/docs/docs/fr/api/cli/self/index.md @@ -19,7 +19,7 @@ nb self | Commande | Description | | --- | --- | | [`nb self check`](./check.md) | Vérifier la version courante du CLI et la prise en charge de la mise à jour automatique | -| [`nb self update`](./update.md) | Mettre à jour le NocoBase CLI installé globalement via npm | +| [`nb self update`](./update.md) | Mettre à jour le NocoBase CLI installé globalement via npm, pnpm ou yarn | ## Exemples diff --git a/docs/docs/fr/api/cli/self/update.md b/docs/docs/fr/api/cli/self/update.md index 91473c95e2c..b019c960413 100644 --- a/docs/docs/fr/api/cli/self/update.md +++ b/docs/docs/fr/api/cli/self/update.md @@ -1,12 +1,12 @@ --- title: "nb self update" -description: "Référence de la commande nb self update : mettre à jour le NocoBase CLI installé globalement via npm." +description: "Référence de la commande nb self update : mettre à jour le NocoBase CLI installé globalement via npm, pnpm ou yarn." keywords: "nb self update,NocoBase CLI,mise à jour,mise à jour automatique" --- # nb self update -Mettre à jour le NocoBase CLI installé lorsque l'installation est gérée par une installation globale npm standard. +Mettre à jour le NocoBase CLI installé lorsque l'installation est gérée par une installation globale standard npm, pnpm ou yarn. ## Utilisation @@ -18,12 +18,26 @@ nb self update [flags] | Paramètre | Type | Description | | --- | --- | --- | -| `--channel` | string | Channel de release pour la mise à jour, par défaut `auto` ; valeurs possibles : `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Channel de release pour la mise à jour, par défaut `auto` ; valeurs possibles : `auto`, `latest`, `test`, `beta`, `alpha` | | `--yes`, `-y` | boolean | Ignorer la confirmation de mise à jour | | `--json` | boolean | Sortie au format JSON | | `--skills` | boolean | Mettre aussi à jour les NocoBase AI coding skills installées globalement | | `--verbose` | boolean | Afficher la sortie détaillée de la mise à jour | +## Comportement de mise à jour + +`nb self update` commence par détecter la méthode d'installation courante au moment de l'exécution. Il n'utilise pas l'ancien cache `self-install-methods.json`. + +Lorsqu'une mise à jour est disponible, la commande utilise le même package manager que celui qui gère l'installation globale courante de la CLI : + +| Méthode d'installation | Commande de mise à jour | +| --- | --- | +| `npm-global` | `npm install -g @nocobase/cli@` | +| `pnpm-global` | `pnpm add -g @nocobase/cli@` | +| `yarn-global` | `yarn global add @nocobase/cli@` | + +La confirmation interactive est yes par défaut. Utilise `--yes` pour ignorer le prompt dans les scripts. + ## Exemples ```bash diff --git a/docs/docs/fr/nocobase-cli/installation/cli.md b/docs/docs/fr/nocobase-cli/installation/cli.md index b783e77a297..2cf4452cd2b 100644 --- a/docs/docs/fr/nocobase-cli/installation/cli.md +++ b/docs/docs/fr/nocobase-cli/installation/cli.md @@ -35,6 +35,8 @@ nb config set update.policy auto nb config set update.policy off ``` +La mise à jour automatique n'est prise en charge que lorsque la CLI est gérée par une installation globale standard npm, pnpm ou yarn. Si elle s'exécute depuis les sources ou depuis l'arbre de dépendances d'un projet local, utilise [`nb self check`](../../api/cli/self/check.md) pour voir la méthode d'installation détectée, puis mets plutôt à jour ce projet parent. + Si vous envisagez de déployer NocoBase sur le serveur et souhaitez ouvrir l'assistant `nb init --ui` à partir d'un navigateur distant, il est recommandé de d'abord remplacer l'hôte par défaut de la CLI par l'adresse IP actuelle du serveur : ```bash diff --git a/docs/docs/id/api/cli/config/delete.md b/docs/docs/id/api/cli/config/delete.md index 06456bfd688..ce7d4d9bc2f 100644 --- a/docs/docs/id/api/cli/config/delete.md +++ b/docs/docs/id/api/cli/config/delete.md @@ -31,6 +31,7 @@ nb config delete proxy.nb-cli-root nb config delete proxy.upstream-host nb config delete bin.nginx nb config delete bin.git +nb config delete bin.pnpm ``` ## Perintah terkait diff --git a/docs/docs/id/api/cli/config/index.md b/docs/docs/id/api/cli/config/index.md index d2f6a402ea1..e1cdb20a379 100644 --- a/docs/docs/id/api/cli/config/index.md +++ b/docs/docs/id/api/cli/config/index.md @@ -10,7 +10,7 @@ Mengelola nilai konfigurasi default CLI. Kunci yang saat ini didukung secara umu - CLI itu sendiri: `locale`, `update.policy`, `license.pkg-url` - Runtime Docker: `docker.network`, `docker.container-prefix` -- Executable eksternal: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.yarn` +- Executable eksternal: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.pnpm`, `bin.yarn` - Pembuatan proxy: `proxy.nb-cli-root`, `proxy.upstream-host`, `proxy.nginx-driver`, `proxy.caddy-driver` Sebagian besar proyek hanya membutuhkan beberapa kunci saja. Dalam praktiknya, yang paling umum adalah: @@ -34,6 +34,7 @@ Sebagian besar proyek hanya membutuhkan beberapa kunci saja. Dalam praktiknya, y | `bin.caddy` | `caddy` | Menimpa path executable Caddy | | `bin.git` | `git` | Menimpa path executable Git | | `bin.nginx` | `nginx` | Menimpa path executable Nginx | +| `bin.pnpm` | `pnpm` | Menimpa path executable pnpm | | `bin.yarn` | `yarn` | Menimpa path executable Yarn | | `proxy.nb-cli-root` | root CLI, biasanya direktori home pengguna saat ini | Menimpa root path yang terlihat oleh konfigurasi proxy yang dihasilkan ketika proses proxy dan CLI tidak melihat root filesystem yang sama | | `proxy.upstream-host` | `127.0.0.1` | Menimpa host yang digunakan proxy untuk meneruskan trafik kembali ke aplikasi NocoBase | @@ -70,12 +71,14 @@ nb config get docker.network nb config set docker.network nocobase nb config set bin.nginx /usr/sbin/nginx nb config set bin.git /usr/bin/git +nb config set bin.pnpm /usr/local/bin/pnpm nb config delete docker.container-prefix ``` ## Catatan - `bin.nginx` dan `bin.caddy` hanya memengaruhi driver `local` untuk `nb proxy nginx` dan `nb proxy caddy` +- `bin.pnpm` digunakan saat perintah perlu menjalankan pnpm secara langsung, misalnya saat memperbarui instalasi CLI global yang dikelola pnpm dengan `nb self update` - `proxy.nginx-driver` dan `proxy.caddy-driver` menyimpan driver default yang digunakan oleh masing-masing provider - `proxy.nb-cli-root` dan `proxy.upstream-host` adalah override proxy tingkat lanjut. Untuk sebagian besar env `local` atau `docker` yang dikelola CLI, nilai default sudah cukup - Jika kamu hanya ingin mengganti driver proxy aktif, menggunakan `nb proxy nginx use` atau `nb proxy caddy use` biasanya lebih jelas daripada mengatur kunci konfigurasi secara manual diff --git a/docs/docs/id/api/cli/config/set.md b/docs/docs/id/api/cli/config/set.md index 36f2edbd94f..76b0703a6bd 100644 --- a/docs/docs/id/api/cli/config/set.md +++ b/docs/docs/id/api/cli/config/set.md @@ -33,6 +33,7 @@ nb config set bin.docker /usr/local/bin/docker nb config set bin.caddy /opt/homebrew/bin/caddy nb config set bin.git /usr/bin/git nb config set bin.nginx /usr/sbin/nginx +nb config set bin.pnpm /usr/local/bin/pnpm nb config set proxy.nb-cli-root /workspace nb config set proxy.upstream-host host.docker.internal nb config set bin.yarn yarn diff --git a/docs/docs/id/api/cli/self/check.md b/docs/docs/id/api/cli/self/check.md index 80db1b1bc6e..f90d93917f8 100644 --- a/docs/docs/id/api/cli/self/check.md +++ b/docs/docs/id/api/cli/self/check.md @@ -18,9 +18,26 @@ nb self check [flags] | Parameter | Tipe | Penjelasan | | --- | --- | --- | -| `--channel` | string | Channel rilis untuk dibandingkan, default `auto`; opsi: `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Channel rilis untuk dibandingkan, default `auto`; opsi: `auto`, `latest`, `test`, `beta`, `alpha` | | `--json` | boolean | Output JSON | +## Metode Instalasi + +`nb self check` mendeteksi metode instalasi saat ini saat runtime. Cache historis `self-install-methods.json` tidak digunakan. + +Perintah ini dapat melaporkan metode instalasi berikut: + +| Metode instalasi | Arti | +| --- | --- | +| `npm-global` | CLI terinstal di bawah `npm prefix -g` saat ini. | +| `pnpm-global` | CLI terinstal di pohon `node_modules` global pnpm. | +| `yarn-global` | CLI dijalankan dari `yarn global bin` atau terinstal di bawah `yarn global dir`. | +| `package-local` | CLI terinstal di pohon dependency proyek lokal. | +| `source` | CLI berjalan dari checkout repository. | +| `unknown` | Instalasi CLI tidak dapat dicocokkan dengan metode instalasi yang didukung. | + +Pembaruan mandiri didukung untuk `npm-global`, `pnpm-global`, dan `yarn-global`. Untuk `package-local` atau `source`, perbarui proyek induk atau checkout repository tersebut. + ## Contoh ```bash diff --git a/docs/docs/id/api/cli/self/index.md b/docs/docs/id/api/cli/self/index.md index 653d6504c82..aa9e1f3a9fc 100644 --- a/docs/docs/id/api/cli/self/index.md +++ b/docs/docs/id/api/cli/self/index.md @@ -19,7 +19,7 @@ nb self | Perintah | Penjelasan | | --- | --- | | [`nb self check`](./check.md) | Memeriksa versi CLI saat ini dan dukungan pembaruan mandiri | -| [`nb self update`](./update.md) | Memperbarui NocoBase CLI yang terinstal global melalui npm | +| [`nb self update`](./update.md) | Memperbarui NocoBase CLI yang terinstal global melalui npm, pnpm, atau yarn | ## Contoh diff --git a/docs/docs/id/api/cli/self/update.md b/docs/docs/id/api/cli/self/update.md index c1c17c14dd8..daaa1404933 100644 --- a/docs/docs/id/api/cli/self/update.md +++ b/docs/docs/id/api/cli/self/update.md @@ -1,12 +1,12 @@ --- title: "nb self update" -description: "Referensi perintah nb self update: memperbarui NocoBase CLI yang terinstal global melalui npm." +description: "Referensi perintah nb self update: memperbarui NocoBase CLI yang terinstal global melalui npm, pnpm, atau yarn." keywords: "nb self update,NocoBase CLI,update,pembaruan mandiri" --- # nb self update -Memperbarui NocoBase CLI yang terinstal saat CLI saat ini dikelola oleh instalasi npm global standar. +Memperbarui NocoBase CLI yang terinstal saat CLI saat ini dikelola oleh instalasi global npm, pnpm, atau yarn standar. ## Penggunaan @@ -18,12 +18,26 @@ nb self update [flags] | Parameter | Tipe | Penjelasan | | --- | --- | --- | -| `--channel` | string | Channel rilis untuk diupdate, default `auto`; opsi: `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Channel rilis untuk diupdate, default `auto`; opsi: `auto`, `latest`, `test`, `beta`, `alpha` | | `--yes`, `-y` | boolean | Lewati konfirmasi update | | `--json` | boolean | Output JSON | | `--skills` | boolean | Sekaligus memperbarui NocoBase AI coding skills yang terinstal secara global | | `--verbose` | boolean | Menampilkan output update detail | +## Perilaku Update + +`nb self update` terlebih dahulu mendeteksi metode instalasi saat ini saat runtime. Cache historis `self-install-methods.json` tidak digunakan. + +Saat update tersedia, perintah ini menggunakan package manager yang sama dengan yang mengelola instalasi CLI global saat ini: + +| Metode instalasi | Perintah update | +| --- | --- | +| `npm-global` | `npm install -g @nocobase/cli@` | +| `pnpm-global` | `pnpm add -g @nocobase/cli@` | +| `yarn-global` | `yarn global add @nocobase/cli@` | + +Konfirmasi interaktif secara default bernilai yes. Gunakan `--yes` untuk melewati prompt di script. + ## Contoh ```bash diff --git a/docs/docs/id/nocobase-cli/installation/cli.md b/docs/docs/id/nocobase-cli/installation/cli.md index 17428621565..c62d8037c8e 100644 --- a/docs/docs/id/nocobase-cli/installation/cli.md +++ b/docs/docs/id/nocobase-cli/installation/cli.md @@ -35,6 +35,8 @@ nb config set update.policy auto nb config set update.policy off ``` +Pembaruan mandiri hanya didukung saat CLI dikelola oleh instalasi global npm, pnpm, atau yarn standar. Jika dijalankan dari source atau dari pohon dependency proyek lokal, gunakan [`nb self check`](../../api/cli/self/check.md) untuk melihat metode instalasi yang terdeteksi, lalu perbarui proyek induk tersebut. + Jika Anda akan menyebarkan NocoBase ke server dan ingin membuka wizard `nb init --ui` dari browser jarak jauh, disarankan untuk terlebih dahulu mengubah host default CLI ke IP server saat ini: ```bash diff --git a/docs/docs/ja/api/cli/config/delete.md b/docs/docs/ja/api/cli/config/delete.md index 1de73a050e4..3293636ffad 100644 --- a/docs/docs/ja/api/cli/config/delete.md +++ b/docs/docs/ja/api/cli/config/delete.md @@ -31,6 +31,7 @@ nb config delete proxy.nb-cli-root nb config delete proxy.upstream-host nb config delete bin.nginx nb config delete bin.git +nb config delete bin.pnpm ``` ## 関連コマンド diff --git a/docs/docs/ja/api/cli/config/index.md b/docs/docs/ja/api/cli/config/index.md index fdac1b0e1b0..267ba5f9591 100644 --- a/docs/docs/ja/api/cli/config/index.md +++ b/docs/docs/ja/api/cli/config/index.md @@ -10,7 +10,7 @@ CLI のデフォルト設定値を管理します。現在サポートされて - CLI 自体: `locale`, `update.policy`, `license.pkg-url` - Docker ランタイム: `docker.network`, `docker.container-prefix` -- 外部実行ファイル: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.yarn` +- 外部実行ファイル: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.pnpm`, `bin.yarn` - プロキシ生成: `proxy.nb-cli-root`, `proxy.upstream-host`, `proxy.nginx-driver`, `proxy.caddy-driver` ほとんどのプロジェクトで必要になるのは、その一部だけです。実際によく使うのは次のキーです。 @@ -34,6 +34,7 @@ CLI のデフォルト設定値を管理します。現在サポートされて | `bin.caddy` | `caddy` | Caddy 実行ファイルのパスを上書きします | | `bin.git` | `git` | Git 実行ファイルのパスを上書きします | | `bin.nginx` | `nginx` | Nginx 実行ファイルのパスを上書きします | +| `bin.pnpm` | `pnpm` | pnpm 実行ファイルのパスを上書きします | | `bin.yarn` | `yarn` | Yarn 実行ファイルのパスを上書きします | | `proxy.nb-cli-root` | CLI ルート。通常は現在のユーザーのホームディレクトリ | プロキシプロセスと CLI が同じファイルシステムルートを見ていない場合に、生成されるプロキシ設定から見えるルートパスを上書きします | | `proxy.upstream-host` | `127.0.0.1` | プロキシが NocoBase アプリへトラフィックを転送する際に使うホストを上書きします | @@ -70,12 +71,14 @@ nb config get docker.network nb config set docker.network nocobase nb config set bin.nginx /usr/sbin/nginx nb config set bin.git /usr/bin/git +nb config set bin.pnpm /usr/local/bin/pnpm nb config delete docker.container-prefix ``` ## 注意 - `bin.nginx` と `bin.caddy` は、`nb proxy nginx` および `nb proxy caddy` の `local` ドライバにのみ影響します +- `bin.pnpm` は、pnpm を直接実行する必要があるコマンドで使われます。たとえば pnpm 管理のグローバル CLI インストールを `nb self update` で更新する場合です - `proxy.nginx-driver` と `proxy.caddy-driver` は、それぞれの provider が使用するデフォルトドライバを保存します - `proxy.nb-cli-root` と `proxy.upstream-host` は高度なプロキシ上書き設定です。ほとんどの CLI 管理 `local` / `docker` env ではデフォルト値のままで十分です - アクティブなプロキシドライバを切り替えたいだけなら、設定キーを直接書き換えるより `nb proxy nginx use` や `nb proxy caddy use` を使う方が通常は分かりやすいです diff --git a/docs/docs/ja/api/cli/config/set.md b/docs/docs/ja/api/cli/config/set.md index 1fd5b22ef0a..2cf0eb0eb6c 100644 --- a/docs/docs/ja/api/cli/config/set.md +++ b/docs/docs/ja/api/cli/config/set.md @@ -33,6 +33,7 @@ nb config set bin.docker /usr/local/bin/docker nb config set bin.caddy /opt/homebrew/bin/caddy nb config set bin.git /usr/bin/git nb config set bin.nginx /usr/sbin/nginx +nb config set bin.pnpm /usr/local/bin/pnpm nb config set proxy.nb-cli-root /workspace nb config set proxy.upstream-host host.docker.internal nb config set bin.yarn yarn diff --git a/docs/docs/ja/api/cli/self/check.md b/docs/docs/ja/api/cli/self/check.md index 20013bc4dee..786d1608a9e 100644 --- a/docs/docs/ja/api/cli/self/check.md +++ b/docs/docs/ja/api/cli/self/check.md @@ -18,9 +18,26 @@ nb self check [flags] | パラメータ | 型 | 説明 | | --- | --- | --- | -| `--channel` | string | 比較対象のリリース channel。デフォルトは `auto`。選択肢:`auto`、`latest`、`beta`、`alpha` | +| `--channel` | string | 比較対象のリリース channel。デフォルトは `auto`。選択肢:`auto`、`latest`、`test`、`beta`、`alpha` | | `--json` | boolean | JSON で出力します | +## インストール方法 + +`nb self check` は現在のインストール方法を実行時に検出します。以前の `self-install-methods.json` キャッシュは使用しません。 + +このコマンドは、次のインストール方法を表示できます。 + +| インストール方法 | 意味 | +| --- | --- | +| `npm-global` | CLI が現在の `npm prefix -g` 配下にインストールされています。 | +| `pnpm-global` | CLI が pnpm のグローバル `node_modules` ツリー配下にインストールされています。 | +| `yarn-global` | CLI が `yarn global bin` から起動されているか、`yarn global dir` 配下にインストールされています。 | +| `package-local` | CLI がローカルプロジェクトの依存関係ツリーにインストールされています。 | +| `source` | CLI がリポジトリの checkout から実行されています。 | +| `unknown` | CLI のインストールをサポート対象のインストール方法に一致させられませんでした。 | + +セルフアップデートは `npm-global`、`pnpm-global`、`yarn-global` でサポートされます。`package-local` または `source` の場合は、親プロジェクトまたはリポジトリ checkout を更新してください。 + ## 使用例 ```bash diff --git a/docs/docs/ja/api/cli/self/index.md b/docs/docs/ja/api/cli/self/index.md index 77c5bf7bfb4..fdef8f4214b 100644 --- a/docs/docs/ja/api/cli/self/index.md +++ b/docs/docs/ja/api/cli/self/index.md @@ -19,7 +19,7 @@ nb self | コマンド | 説明 | | --- | --- | | [`nb self check`](./check.md) | 現在の CLI バージョンとセルフアップデートの対応状況を確認します | -| [`nb self update`](./update.md) | グローバル npm インストールの NocoBase CLI をアップデートします | +| [`nb self update`](./update.md) | npm、pnpm、yarn のグローバルインストールで管理されている NocoBase CLI をアップデートします | ## 使用例 diff --git a/docs/docs/ja/api/cli/self/update.md b/docs/docs/ja/api/cli/self/update.md index 34771969180..615282685e5 100644 --- a/docs/docs/ja/api/cli/self/update.md +++ b/docs/docs/ja/api/cli/self/update.md @@ -1,12 +1,12 @@ --- title: "nb self update" -description: "nb self update コマンドリファレンス:グローバル npm インストールの NocoBase CLI をアップデートします。" +description: "nb self update コマンドリファレンス:npm、pnpm、yarn のグローバルインストールで管理されている NocoBase CLI をアップデートします。" keywords: "nb self update,NocoBase CLI,アップデート,セルフアップデート" --- # nb self update -現在の CLI が標準的なグローバル npm インストールで管理されている場合に、インストール済みの NocoBase CLI をアップデートします。 +現在の CLI が標準的なグローバル npm、pnpm、または yarn インストールで管理されている場合に、インストール済みの NocoBase CLI をアップデートします。 ## 使い方 @@ -18,12 +18,26 @@ nb self update [flags] | パラメータ | 型 | 説明 | | --- | --- | --- | -| `--channel` | string | アップデート先のリリース channel。デフォルトは `auto`。選択肢:`auto`、`latest`、`beta`、`alpha` | +| `--channel` | string | アップデート先のリリース channel。デフォルトは `auto`。選択肢:`auto`、`latest`、`test`、`beta`、`alpha` | | `--yes`, `-y` | boolean | アップデートの確認をスキップします | | `--json` | boolean | JSON で出力します | | `--skills` | boolean | グローバルにインストールされた NocoBase AI coding skills もあわせて更新します | | `--verbose` | boolean | 詳細なアップデート出力を表示します | +## アップデート動作 + +`nb self update` は、まず現在のインストール方法を実行時に検出します。以前の `self-install-methods.json` キャッシュは使用しません。 + +アップデートがある場合、このコマンドは現在のグローバル CLI インストールを管理しているものと同じ package manager を使います。 + +| インストール方法 | アップデートコマンド | +| --- | --- | +| `npm-global` | `npm install -g @nocobase/cli@` | +| `pnpm-global` | `pnpm add -g @nocobase/cli@` | +| `yarn-global` | `yarn global add @nocobase/cli@` | + +対話式確認のデフォルトは yes です。script で prompt をスキップするには `--yes` を使います。 + ## 使用例 ```bash diff --git a/docs/docs/ja/nocobase-cli/installation/cli.md b/docs/docs/ja/nocobase-cli/installation/cli.md index 70eeefca6a1..f2f68aa8ff2 100644 --- a/docs/docs/ja/nocobase-cli/installation/cli.md +++ b/docs/docs/ja/nocobase-cli/installation/cli.md @@ -35,6 +35,8 @@ nb config set update.policy auto nb config set update.policy off ``` +セルフアップデートは、CLI が標準的なグローバル npm、pnpm、または yarn インストールで管理されている場合にのみサポートされます。source またはローカルプロジェクトの依存関係ツリーから実行している場合は、[`nb self check`](../../api/cli/self/check.md) で検出されたインストール方法を確認し、その親プロジェクトを更新してください。 + NocoBase をサーバーにデプロイし、リモート ブラウザから `nb init --ui` ウィザードを開きたい場合は、最初に CLI のデフォルト ホストを現在のサーバー IP に変更することをお勧めします。 ```bash diff --git a/docs/docs/pt/api/cli/config/delete.md b/docs/docs/pt/api/cli/config/delete.md index 95c08a4efd5..9c47e81befe 100644 --- a/docs/docs/pt/api/cli/config/delete.md +++ b/docs/docs/pt/api/cli/config/delete.md @@ -31,6 +31,7 @@ nb config delete proxy.nb-cli-root nb config delete proxy.upstream-host nb config delete bin.nginx nb config delete bin.git +nb config delete bin.pnpm ``` ## Comandos relacionados diff --git a/docs/docs/pt/api/cli/config/index.md b/docs/docs/pt/api/cli/config/index.md index af0ddd36163..27bab7ad46e 100644 --- a/docs/docs/pt/api/cli/config/index.md +++ b/docs/docs/pt/api/cli/config/index.md @@ -10,7 +10,7 @@ Gerencia os valores de configuração padrão da CLI. As chaves atualmente supor - A própria CLI: `locale`, `update.policy`, `license.pkg-url` - Runtime do Docker: `docker.network`, `docker.container-prefix` -- Executáveis externos: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.yarn` +- Executáveis externos: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.pnpm`, `bin.yarn` - Geração de proxy: `proxy.nb-cli-root`, `proxy.upstream-host`, `proxy.nginx-driver`, `proxy.caddy-driver` A maioria dos projetos só precisa de algumas dessas chaves. Na prática, as mais comuns são: @@ -34,6 +34,7 @@ A maioria dos projetos só precisa de algumas dessas chaves. Na prática, as mai | `bin.caddy` | `caddy` | Sobrescreve o caminho do executável do Caddy | | `bin.git` | `git` | Sobrescreve o caminho do executável do Git | | `bin.nginx` | `nginx` | Sobrescreve o caminho do executável do Nginx | +| `bin.pnpm` | `pnpm` | Sobrescreve o caminho do executável do pnpm | | `bin.yarn` | `yarn` | Sobrescreve o caminho do executável do Yarn | | `proxy.nb-cli-root` | raiz da CLI, normalmente o diretório home do usuário atual | Sobrescreve o caminho raiz visível para a configuração de proxy gerada quando o processo do proxy e a CLI não enxergam a mesma raiz do sistema de arquivos | | `proxy.upstream-host` | `127.0.0.1` | Sobrescreve o host usado pelo proxy para encaminhar tráfego de volta para a aplicação NocoBase | @@ -70,12 +71,14 @@ nb config get docker.network nb config set docker.network nocobase nb config set bin.nginx /usr/sbin/nginx nb config set bin.git /usr/bin/git +nb config set bin.pnpm /usr/local/bin/pnpm nb config delete docker.container-prefix ``` ## Notas - `bin.nginx` e `bin.caddy` afetam apenas o driver `local` de `nb proxy nginx` e `nb proxy caddy` +- `bin.pnpm` é usado quando comandos precisam executar pnpm diretamente, por exemplo ao atualizar uma instalação global da CLI gerenciada por pnpm com `nb self update` - `proxy.nginx-driver` e `proxy.caddy-driver` armazenam o driver padrão usado por cada provider - `proxy.nb-cli-root` e `proxy.upstream-host` são overrides avançados de proxy. Para a maioria dos envs `local` ou `docker` gerenciados pela CLI, os valores padrão já são suficientes - Se você só quer trocar o driver ativo do proxy, normalmente é mais claro usar `nb proxy nginx use` ou `nb proxy caddy use` do que definir a chave manualmente diff --git a/docs/docs/pt/api/cli/config/set.md b/docs/docs/pt/api/cli/config/set.md index e841e48cb08..66430f4fc27 100644 --- a/docs/docs/pt/api/cli/config/set.md +++ b/docs/docs/pt/api/cli/config/set.md @@ -33,6 +33,7 @@ nb config set bin.docker /usr/local/bin/docker nb config set bin.caddy /opt/homebrew/bin/caddy nb config set bin.git /usr/bin/git nb config set bin.nginx /usr/sbin/nginx +nb config set bin.pnpm /usr/local/bin/pnpm nb config set proxy.nb-cli-root /workspace nb config set proxy.upstream-host host.docker.internal nb config set bin.yarn yarn diff --git a/docs/docs/pt/api/cli/self/check.md b/docs/docs/pt/api/cli/self/check.md index 662291963aa..d36e140c2e7 100644 --- a/docs/docs/pt/api/cli/self/check.md +++ b/docs/docs/pt/api/cli/self/check.md @@ -18,9 +18,26 @@ nb self check [flags] | Parâmetro | Tipo | Descrição | | --- | --- | --- | -| `--channel` | string | Channel de release a ser comparado, padrão `auto`; opções: `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Channel de release a ser comparado, padrão `auto`; opções: `auto`, `latest`, `test`, `beta`, `alpha` | | `--json` | boolean | Saída em JSON | +## Método de instalação + +`nb self check` detecta o método de instalação atual em runtime. Ele não usa o cache histórico `self-install-methods.json`. + +O comando pode informar estes métodos de instalação: + +| Método de instalação | Significado | +| --- | --- | +| `npm-global` | A CLI está instalada sob o `npm prefix -g` atual. | +| `pnpm-global` | A CLI está instalada em uma árvore global `node_modules` do pnpm. | +| `yarn-global` | A CLI é iniciada a partir de `yarn global bin` ou instalada sob `yarn global dir`. | +| `package-local` | A CLI está instalada na árvore de dependências de um projeto local. | +| `source` | A CLI está rodando a partir de um checkout do repositório. | +| `unknown` | A instalação da CLI não pôde ser associada a um método de instalação suportado. | + +A auto-atualização é suportada para `npm-global`, `pnpm-global` e `yarn-global`. Para `package-local` ou `source`, atualize o projeto pai ou o checkout do repositório. + ## Exemplos ```bash diff --git a/docs/docs/pt/api/cli/self/index.md b/docs/docs/pt/api/cli/self/index.md index 2fef2f3001a..0483881942e 100644 --- a/docs/docs/pt/api/cli/self/index.md +++ b/docs/docs/pt/api/cli/self/index.md @@ -19,7 +19,7 @@ nb self | Comando | Descrição | | --- | --- | | [`nb self check`](./check.md) | Verifica a versão atual do CLI e o suporte a auto-atualização | -| [`nb self update`](./update.md) | Atualiza o NocoBase CLI instalado globalmente via npm | +| [`nb self update`](./update.md) | Atualiza o NocoBase CLI instalado globalmente via npm, pnpm ou yarn | ## Exemplos diff --git a/docs/docs/pt/api/cli/self/update.md b/docs/docs/pt/api/cli/self/update.md index 4f1a45df9ec..62a0c7a7787 100644 --- a/docs/docs/pt/api/cli/self/update.md +++ b/docs/docs/pt/api/cli/self/update.md @@ -1,12 +1,12 @@ --- title: "nb self update" -description: "Referência do comando nb self update: atualiza o NocoBase CLI instalado globalmente via npm." +description: "Referência do comando nb self update: atualiza o NocoBase CLI instalado globalmente via npm, pnpm ou yarn." keywords: "nb self update,NocoBase CLI,atualizar,auto-atualização" --- # nb self update -Atualiza o NocoBase CLI instalado quando o CLI atual é gerenciado pela instalação global padrão do npm. +Atualiza o NocoBase CLI instalado quando o CLI atual é gerenciado por uma instalação global padrão de npm, pnpm ou yarn. ## Uso @@ -18,12 +18,26 @@ nb self update [flags] | Parâmetro | Tipo | Descrição | | --- | --- | --- | -| `--channel` | string | Channel de release para o qual atualizar, padrão `auto`; opções: `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Channel de release para o qual atualizar, padrão `auto`; opções: `auto`, `latest`, `test`, `beta`, `alpha` | | `--yes`, `-y` | boolean | Pula a confirmação de atualização | | `--json` | boolean | Saída em JSON | | `--skills` | boolean | Também atualiza as NocoBase AI coding skills instaladas globalmente | | `--verbose` | boolean | Exibe a saída detalhada da atualização | +## Comportamento da atualização + +`nb self update` primeiro detecta o método de instalação atual em runtime. Ele não usa o cache histórico `self-install-methods.json`. + +Quando há uma atualização disponível, o comando usa o mesmo package manager que gerencia a instalação global atual da CLI: + +| Método de instalação | Comando de atualização | +| --- | --- | +| `npm-global` | `npm install -g @nocobase/cli@` | +| `pnpm-global` | `pnpm add -g @nocobase/cli@` | +| `yarn-global` | `yarn global add @nocobase/cli@` | + +A confirmação interativa usa yes como padrão. Use `--yes` para pular o prompt em scripts. + ## Exemplos ```bash diff --git a/docs/docs/pt/nocobase-cli/installation/cli.md b/docs/docs/pt/nocobase-cli/installation/cli.md index f7fc03cfc9b..e4ab128d929 100644 --- a/docs/docs/pt/nocobase-cli/installation/cli.md +++ b/docs/docs/pt/nocobase-cli/installation/cli.md @@ -35,6 +35,8 @@ nb config set update.policy auto nb config set update.policy off ``` +A auto-atualização só é suportada quando a CLI é gerenciada por uma instalação global padrão de npm, pnpm ou yarn. Se estiver rodando a partir do source ou da árvore de dependências de um projeto local, use [`nb self check`](../../api/cli/self/check.md) para ver o método de instalação detectado e atualize esse projeto pai. + Se você for implementar o NocoBase no servidor e quiser abrir o assistente `nb init --ui` a partir de um navegador remoto, é recomendado primeiro alterar o host padrão da CLI para o IP do servidor atual: ```bash diff --git a/docs/docs/ru/api/cli/config/delete.md b/docs/docs/ru/api/cli/config/delete.md index 23571ea0ef0..f8704a99289 100644 --- a/docs/docs/ru/api/cli/config/delete.md +++ b/docs/docs/ru/api/cli/config/delete.md @@ -31,6 +31,7 @@ nb config delete proxy.nb-cli-root nb config delete proxy.upstream-host nb config delete bin.nginx nb config delete bin.git +nb config delete bin.pnpm ``` ## Связанные команды diff --git a/docs/docs/ru/api/cli/config/index.md b/docs/docs/ru/api/cli/config/index.md index b8999983d25..56a69a0b4af 100644 --- a/docs/docs/ru/api/cli/config/index.md +++ b/docs/docs/ru/api/cli/config/index.md @@ -10,7 +10,7 @@ keywords: "nb config,NocoBase CLI,configuration,default configuration" - Сама CLI: `locale`, `update.policy`, `license.pkg-url` - Docker runtime: `docker.network`, `docker.container-prefix` -- Внешние исполняемые файлы: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.yarn` +- Внешние исполняемые файлы: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.pnpm`, `bin.yarn` - Генерация proxy: `proxy.nb-cli-root`, `proxy.upstream-host`, `proxy.nginx-driver`, `proxy.caddy-driver` Большинству проектов нужна только часть этих ключей. На практике чаще всего используются: @@ -34,6 +34,7 @@ keywords: "nb config,NocoBase CLI,configuration,default configuration" | `bin.caddy` | `caddy` | Переопределяет путь к исполняемому файлу Caddy | | `bin.git` | `git` | Переопределяет путь к исполняемому файлу Git | | `bin.nginx` | `nginx` | Переопределяет путь к исполняемому файлу Nginx | +| `bin.pnpm` | `pnpm` | Переопределяет путь к исполняемому файлу pnpm | | `bin.yarn` | `yarn` | Переопределяет путь к исполняемому файлу Yarn | | `proxy.nb-cli-root` | корень CLI, обычно домашний каталог текущего пользователя | Переопределяет корневой путь, который видит сгенерированная proxy-конфигурация, когда proxy-процесс и CLI не видят один и тот же корень файловой системы | | `proxy.upstream-host` | `127.0.0.1` | Переопределяет хост, который proxy использует для пересылки трафика обратно в приложение NocoBase | @@ -70,12 +71,14 @@ nb config get docker.network nb config set docker.network nocobase nb config set bin.nginx /usr/sbin/nginx nb config set bin.git /usr/bin/git +nb config set bin.pnpm /usr/local/bin/pnpm nb config delete docker.container-prefix ``` ## Примечания - `bin.nginx` и `bin.caddy` влияют только на драйвер `local` для `nb proxy nginx` и `nb proxy caddy` +- `bin.pnpm` используется, когда командам нужно запускать pnpm напрямую, например при обновлении глобальной установки CLI, управляемой pnpm, через `nb self update` - `proxy.nginx-driver` и `proxy.caddy-driver` хранят драйвер по умолчанию для каждого provider - `proxy.nb-cli-root` и `proxy.upstream-host` — это расширенные proxy-override-настройки. Для большинства CLI-managed env типов `local` и `docker` достаточно значений по умолчанию - Если вам нужно только переключить активный proxy-драйвер, обычно понятнее использовать `nb proxy nginx use` или `nb proxy caddy use`, чем вручную менять ключ конфигурации diff --git a/docs/docs/ru/api/cli/config/set.md b/docs/docs/ru/api/cli/config/set.md index 9eb88ec0b25..4f6ccce8ee3 100644 --- a/docs/docs/ru/api/cli/config/set.md +++ b/docs/docs/ru/api/cli/config/set.md @@ -33,6 +33,7 @@ nb config set bin.docker /usr/local/bin/docker nb config set bin.caddy /opt/homebrew/bin/caddy nb config set bin.git /usr/bin/git nb config set bin.nginx /usr/sbin/nginx +nb config set bin.pnpm /usr/local/bin/pnpm nb config set proxy.nb-cli-root /workspace nb config set proxy.upstream-host host.docker.internal nb config set bin.yarn yarn diff --git a/docs/docs/ru/api/cli/self/check.md b/docs/docs/ru/api/cli/self/check.md index fc3d5041c8d..5bafd0ffb30 100644 --- a/docs/docs/ru/api/cli/self/check.md +++ b/docs/docs/ru/api/cli/self/check.md @@ -18,9 +18,26 @@ nb self check [flags] | Параметр | Тип | Описание | | --- | --- | --- | -| `--channel` | string | Channel релиза для сравнения, по умолчанию `auto`; возможные значения: `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Channel релиза для сравнения, по умолчанию `auto`; возможные значения: `auto`, `latest`, `test`, `beta`, `alpha` | | `--json` | boolean | Вывести в формате JSON | +## Метод установки + +`nb self check` определяет текущий метод установки во время выполнения. Исторический cache `self-install-methods.json` не используется. + +Команда может вывести такие методы установки: + +| Метод установки | Значение | +| --- | --- | +| `npm-global` | CLI установлен в текущем `npm prefix -g`. | +| `pnpm-global` | CLI установлен в глобальном дереве `node_modules` pnpm. | +| `yarn-global` | CLI запускается из `yarn global bin` или установлен в `yarn global dir`. | +| `package-local` | CLI установлен в дереве зависимостей локального проекта. | +| `source` | CLI запущен из checkout репозитория. | +| `unknown` | Установку CLI не удалось сопоставить с поддерживаемым методом установки. | + +Самообновление поддерживается для `npm-global`, `pnpm-global` и `yarn-global`. Для `package-local` или `source` обновляйте родительский проект или checkout репозитория. + ## Примеры ```bash diff --git a/docs/docs/ru/api/cli/self/index.md b/docs/docs/ru/api/cli/self/index.md index 8fa5f1dd6d8..e12ae7aa7a9 100644 --- a/docs/docs/ru/api/cli/self/index.md +++ b/docs/docs/ru/api/cli/self/index.md @@ -19,7 +19,7 @@ nb self | Команда | Описание | | --- | --- | | [`nb self check`](./check.md) | Проверяет текущую версию CLI и поддержку автообновления | -| [`nb self update`](./update.md) | Обновляет глобально установленный через npm NocoBase CLI | +| [`nb self update`](./update.md) | Обновляет NocoBase CLI, глобально установленный через npm, pnpm или yarn | ## Примеры diff --git a/docs/docs/ru/api/cli/self/update.md b/docs/docs/ru/api/cli/self/update.md index 21b78a278ce..53a3593c974 100644 --- a/docs/docs/ru/api/cli/self/update.md +++ b/docs/docs/ru/api/cli/self/update.md @@ -1,12 +1,12 @@ --- title: "nb self update" -description: "Справочник по команде nb self update: обновление глобально установленного через npm NocoBase CLI." +description: "Справочник по команде nb self update: обновление NocoBase CLI, глобально установленного через npm, pnpm или yarn." keywords: "nb self update,NocoBase CLI,обновление,автообновление" --- # nb self update -Обновляет установленный NocoBase CLI, если текущий CLI управляется стандартной глобальной установкой npm. +Обновляет установленный NocoBase CLI, если текущий CLI управляется стандартной глобальной установкой npm, pnpm или yarn. ## Использование @@ -18,12 +18,26 @@ nb self update [flags] | Параметр | Тип | Описание | | --- | --- | --- | -| `--channel` | string | Channel релиза для обновления, по умолчанию `auto`; возможные значения: `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Channel релиза для обновления, по умолчанию `auto`; возможные значения: `auto`, `latest`, `test`, `beta`, `alpha` | | `--yes`, `-y` | boolean | Пропустить подтверждение обновления | | `--json` | boolean | Вывести в формате JSON | | `--skills` | boolean | Также обновить глобально установленные NocoBase AI coding skills | | `--verbose` | boolean | Показать подробный вывод процесса обновления | +## Поведение обновления + +`nb self update` сначала определяет текущий метод установки во время выполнения. Исторический cache `self-install-methods.json` не используется. + +Когда доступно обновление, команда использует тот же package manager, который управляет текущей глобальной установкой CLI: + +| Метод установки | Команда обновления | +| --- | --- | +| `npm-global` | `npm install -g @nocobase/cli@` | +| `pnpm-global` | `pnpm add -g @nocobase/cli@` | +| `yarn-global` | `yarn global add @nocobase/cli@` | + +Интерактивное подтверждение по умолчанию выбирает yes. Используйте `--yes`, чтобы пропустить prompt в scripts. + ## Примеры ```bash diff --git a/docs/docs/ru/nocobase-cli/installation/cli.md b/docs/docs/ru/nocobase-cli/installation/cli.md index 2fdaa66bca2..4a206d199ce 100644 --- a/docs/docs/ru/nocobase-cli/installation/cli.md +++ b/docs/docs/ru/nocobase-cli/installation/cli.md @@ -35,6 +35,8 @@ nb config set update.policy auto nb config set update.policy off ``` +Самообновление поддерживается только тогда, когда CLI управляется стандартной глобальной установкой npm, pnpm или yarn. Если он запускается из source или из дерева зависимостей локального проекта, используйте [`nb self check`](../../api/cli/self/check.md), чтобы посмотреть определенный метод установки, и обновляйте этот родительский проект. + Если вы собираетесь развернуть NocoBase на сервере и хотите открыть мастер `nb init --ui` из удаленного браузера, рекомендуется сначала изменить хост CLI по умолчанию на текущий IP-адрес сервера: ```bash diff --git a/docs/docs/vi/api/cli/config/delete.md b/docs/docs/vi/api/cli/config/delete.md index 4f7ea78a012..37c37897a32 100644 --- a/docs/docs/vi/api/cli/config/delete.md +++ b/docs/docs/vi/api/cli/config/delete.md @@ -31,6 +31,7 @@ nb config delete proxy.nb-cli-root nb config delete proxy.upstream-host nb config delete bin.nginx nb config delete bin.git +nb config delete bin.pnpm ``` ## Lệnh liên quan diff --git a/docs/docs/vi/api/cli/config/index.md b/docs/docs/vi/api/cli/config/index.md index 615eee5831e..846517b09a4 100644 --- a/docs/docs/vi/api/cli/config/index.md +++ b/docs/docs/vi/api/cli/config/index.md @@ -10,7 +10,7 @@ Quản lý các giá trị cấu hình mặc định của CLI. Các khóa hiệ - Bản thân CLI: `locale`, `update.policy`, `license.pkg-url` - Runtime Docker: `docker.network`, `docker.container-prefix` -- Tệp thực thi bên ngoài: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.yarn` +- Tệp thực thi bên ngoài: `bin.docker`, `bin.caddy`, `bin.git`, `bin.nginx`, `bin.pnpm`, `bin.yarn` - Sinh proxy: `proxy.nb-cli-root`, `proxy.upstream-host`, `proxy.nginx-driver`, `proxy.caddy-driver` Phần lớn dự án chỉ cần một vài khóa trong số này. Trên thực tế, các khóa được dùng nhiều nhất là: @@ -34,6 +34,7 @@ Phần lớn dự án chỉ cần một vài khóa trong số này. Trên thực | `bin.caddy` | `caddy` | Ghi đè đường dẫn thực thi Caddy | | `bin.git` | `git` | Ghi đè đường dẫn thực thi Git | | `bin.nginx` | `nginx` | Ghi đè đường dẫn thực thi Nginx | +| `bin.pnpm` | `pnpm` | Ghi đè đường dẫn thực thi pnpm | | `bin.yarn` | `yarn` | Ghi đè đường dẫn thực thi Yarn | | `proxy.nb-cli-root` | root của CLI, thường là thư mục home của người dùng hiện tại | Ghi đè root path mà cấu hình proxy được sinh ra nhìn thấy khi tiến trình proxy và CLI không nhìn cùng một root filesystem | | `proxy.upstream-host` | `127.0.0.1` | Ghi đè host mà proxy dùng để chuyển tiếp lưu lượng trở lại ứng dụng NocoBase | @@ -70,12 +71,14 @@ nb config get docker.network nb config set docker.network nocobase nb config set bin.nginx /usr/sbin/nginx nb config set bin.git /usr/bin/git +nb config set bin.pnpm /usr/local/bin/pnpm nb config delete docker.container-prefix ``` ## Ghi chú - `bin.nginx` và `bin.caddy` chỉ ảnh hưởng tới driver `local` của `nb proxy nginx` và `nb proxy caddy` +- `bin.pnpm` được dùng khi lệnh cần chạy pnpm trực tiếp, chẳng hạn cập nhật cài đặt CLI global do pnpm quản lý bằng `nb self update` - `proxy.nginx-driver` và `proxy.caddy-driver` lưu driver mặc định mà từng provider sử dụng - `proxy.nb-cli-root` và `proxy.upstream-host` là các thiết lập override proxy nâng cao. Với hầu hết env `local` hoặc `docker` do CLI quản lý, giá trị mặc định là đủ - Nếu bạn chỉ muốn đổi driver proxy đang hoạt động, dùng `nb proxy nginx use` hoặc `nb proxy caddy use` thường rõ ràng hơn là tự đặt khóa cấu hình diff --git a/docs/docs/vi/api/cli/config/set.md b/docs/docs/vi/api/cli/config/set.md index 02738797fc2..d889f10c0c8 100644 --- a/docs/docs/vi/api/cli/config/set.md +++ b/docs/docs/vi/api/cli/config/set.md @@ -33,6 +33,7 @@ nb config set bin.docker /usr/local/bin/docker nb config set bin.caddy /opt/homebrew/bin/caddy nb config set bin.git /usr/bin/git nb config set bin.nginx /usr/sbin/nginx +nb config set bin.pnpm /usr/local/bin/pnpm nb config set proxy.nb-cli-root /workspace nb config set proxy.upstream-host host.docker.internal nb config set bin.yarn yarn diff --git a/docs/docs/vi/api/cli/self/check.md b/docs/docs/vi/api/cli/self/check.md index e852df2a968..24202e0e7a0 100644 --- a/docs/docs/vi/api/cli/self/check.md +++ b/docs/docs/vi/api/cli/self/check.md @@ -18,9 +18,26 @@ nb self check [flags] | Tham số | Kiểu | Mô tả | | --- | --- | --- | -| `--channel` | string | Channel phát hành để so sánh, mặc định `auto`; có thể chọn `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Channel phát hành để so sánh, mặc định `auto`; có thể chọn `auto`, `latest`, `test`, `beta`, `alpha` | | `--json` | boolean | Đầu ra dạng JSON | +## Phương thức cài đặt + +`nb self check` phát hiện phương thức cài đặt hiện tại khi chạy. Lệnh này không dùng cache lịch sử `self-install-methods.json`. + +Lệnh có thể báo cáo các phương thức cài đặt sau: + +| Phương thức cài đặt | Ý nghĩa | +| --- | --- | +| `npm-global` | CLI được cài dưới `npm prefix -g` hiện tại. | +| `pnpm-global` | CLI được cài trong cây `node_modules` global của pnpm. | +| `yarn-global` | CLI được khởi chạy từ `yarn global bin` hoặc được cài dưới `yarn global dir`. | +| `package-local` | CLI được cài trong cây dependency của một dự án cục bộ. | +| `source` | CLI đang chạy từ checkout repository. | +| `unknown` | Không thể khớp cài đặt CLI với một phương thức cài đặt được hỗ trợ. | + +Tự cập nhật được hỗ trợ cho `npm-global`, `pnpm-global` và `yarn-global`. Với `package-local` hoặc `source`, hãy cập nhật dự án cha hoặc checkout repository tương ứng. + ## Ví dụ ```bash diff --git a/docs/docs/vi/api/cli/self/index.md b/docs/docs/vi/api/cli/self/index.md index 091b70fe1bc..156837217be 100644 --- a/docs/docs/vi/api/cli/self/index.md +++ b/docs/docs/vi/api/cli/self/index.md @@ -19,7 +19,7 @@ nb self | Lệnh | Mô tả | | --- | --- | | [`nb self check`](./check.md) | Kiểm tra phiên bản CLI hiện tại và khả năng tự cập nhật | -| [`nb self update`](./update.md) | Cập nhật NocoBase CLI cài qua npm global | +| [`nb self update`](./update.md) | Cập nhật NocoBase CLI cài global qua npm, pnpm hoặc yarn | ## Ví dụ diff --git a/docs/docs/vi/api/cli/self/update.md b/docs/docs/vi/api/cli/self/update.md index a0ce36e6034..1d211580dee 100644 --- a/docs/docs/vi/api/cli/self/update.md +++ b/docs/docs/vi/api/cli/self/update.md @@ -1,12 +1,12 @@ --- title: "nb self update" -description: "Tham khảo lệnh nb self update: cập nhật NocoBase CLI được cài qua npm global." +description: "Tham khảo lệnh nb self update: cập nhật NocoBase CLI được cài global qua npm, pnpm hoặc yarn." keywords: "nb self update,NocoBase CLI,cập nhật,tự cập nhật" --- # nb self update -Khi CLI hiện tại được quản lý bởi cài đặt npm global tiêu chuẩn, lệnh này cập nhật NocoBase CLI đã cài. +Khi CLI hiện tại được quản lý bởi cài đặt global tiêu chuẩn của npm, pnpm hoặc yarn, lệnh này cập nhật NocoBase CLI đã cài. ## Cách dùng @@ -18,12 +18,26 @@ nb self update [flags] | Tham số | Kiểu | Mô tả | | --- | --- | --- | -| `--channel` | string | Channel phát hành để cập nhật, mặc định `auto`; có thể chọn `auto`, `latest`, `beta`, `alpha` | +| `--channel` | string | Channel phát hành để cập nhật, mặc định `auto`; có thể chọn `auto`, `latest`, `test`, `beta`, `alpha` | | `--yes`, `-y` | boolean | Bỏ qua xác nhận cập nhật | | `--json` | boolean | Đầu ra dạng JSON | | `--skills` | boolean | Đồng thời cập nhật các NocoBase AI coding skills được cài đặt toàn cục | | `--verbose` | boolean | Hiển thị thông tin cập nhật chi tiết | +## Hành vi cập nhật + +`nb self update` trước tiên phát hiện phương thức cài đặt hiện tại khi chạy. Lệnh này không dùng cache lịch sử `self-install-methods.json`. + +Khi có bản cập nhật, lệnh sử dụng cùng package manager đang quản lý cài đặt CLI global hiện tại: + +| Phương thức cài đặt | Lệnh cập nhật | +| --- | --- | +| `npm-global` | `npm install -g @nocobase/cli@` | +| `pnpm-global` | `pnpm add -g @nocobase/cli@` | +| `yarn-global` | `yarn global add @nocobase/cli@` | + +Xác nhận tương tác mặc định là yes. Dùng `--yes` để bỏ qua prompt trong script. + ## Ví dụ ```bash diff --git a/docs/docs/vi/nocobase-cli/installation/cli.md b/docs/docs/vi/nocobase-cli/installation/cli.md index eb1848a8c51..57d151e615e 100644 --- a/docs/docs/vi/nocobase-cli/installation/cli.md +++ b/docs/docs/vi/nocobase-cli/installation/cli.md @@ -35,6 +35,8 @@ nb config set update.policy auto nb config set update.policy off ``` +Tự cập nhật chỉ được hỗ trợ khi CLI được quản lý bởi cài đặt global tiêu chuẩn của npm, pnpm hoặc yarn. Nếu đang chạy từ source hoặc từ cây dependency của một dự án cục bộ, hãy dùng [`nb self check`](../../api/cli/self/check.md) để xem phương thức cài đặt được phát hiện rồi cập nhật dự án cha đó. + Nếu bạn định triển khai NocoBase cho máy chủ và muốn mở trình hướng dẫn `nb init --ui` từ trình duyệt từ xa, trước tiên bạn nên thay đổi máy chủ mặc định của CLI thành IP máy chủ hiện tại: ```bash diff --git a/packages/core/cli/src/__tests__/self-command-logs.test.ts b/packages/core/cli/src/__tests__/self-command-logs.test.ts index 4405458daef..2df9d60e6c3 100644 --- a/packages/core/cli/src/__tests__/self-command-logs.test.ts +++ b/packages/core/cli/src/__tests__/self-command-logs.test.ts @@ -10,6 +10,7 @@ import { beforeEach, expect, test, vi } from 'vitest'; const mocks = vi.hoisted(() => ({ + confirm: vi.fn(), inspectSelfStatus: vi.fn(), updateSelf: vi.fn(), printInfo: vi.fn(), @@ -28,6 +29,10 @@ vi.mock('../lib/self-manager.js', () => ({ updateSelf: mocks.updateSelf, })); +vi.mock('../lib/inquirer.ts', () => ({ + confirm: mocks.confirm, +})); + vi.mock('../lib/skills-manager.js', () => ({ installNocoBaseSkills: mocks.installNocoBaseSkills, removeNocoBaseSkills: mocks.removeNocoBaseSkills, @@ -153,6 +158,57 @@ test('self update logs detailed messages in verbose mode', async () => { ); }); +test('self update confirmation defaults to yes', async () => { + const { default: SelfUpdate } = await import('../commands/self/update.js'); + + const command = Object.assign(Object.create(SelfUpdate.prototype), { + parse: vi.fn(async () => ({ + flags: { + channel: 'auto', + yes: false, + json: false, + skills: false, + verbose: false, + }, + })), + log: vi.fn(), + error: (message: string) => { + throw new Error(message); + }, + }); + + mocks.inspectSelfStatus.mockResolvedValue({ + packageName: '@nocobase/cli', + packageRoot: '/usr/local/lib/node_modules/@nocobase/cli', + currentVersion: '2.1.0-beta.23', + latestVersion: '2.1.0-beta.25', + channel: 'beta', + updateAvailable: true, + installMethod: 'npm-global', + updatable: true, + }); + mocks.confirm.mockResolvedValue(true); + mocks.updateSelf.mockResolvedValue({ + action: 'updated', + status: { + currentVersion: '2.1.0-beta.23', + channel: 'beta', + }, + targetVersion: '2.1.0-beta.25', + }); + + await SelfUpdate.prototype.run.call(command); + + expect(mocks.confirm).toHaveBeenCalledWith({ + message: 'Update @nocobase/cli from 2.1.0-beta.23 to 2.1.0-beta.25?', + default: true, + }); + expect(mocks.updateSelf).toHaveBeenCalledWith({ + channel: 'auto', + verbose: false, + }); +}); + test('self update optionally refreshes skills and logs both results', async () => { const { default: SelfUpdate } = await import('../commands/self/update.js'); diff --git a/packages/core/cli/src/__tests__/self-manager.test.ts b/packages/core/cli/src/__tests__/self-manager.test.ts index 1dfa67e2506..7e8fc7de84f 100644 --- a/packages/core/cli/src/__tests__/self-manager.test.ts +++ b/packages/core/cli/src/__tests__/self-manager.test.ts @@ -23,6 +23,61 @@ import { } from '../lib/self-manager.js'; const originalCliRoot = process.env.NB_CLI_ROOT; +const MOCK_PNPM_GLOBAL_HOME = path.join(path.sep, 'mock-home', 'Library', 'pnpm'); +const MOCK_PNPM_GLOBAL_BIN = path.join(MOCK_PNPM_GLOBAL_HOME, 'bin'); +const MOCK_PNPM_GLOBAL_ROOT = path.join(MOCK_PNPM_GLOBAL_HOME, 'global', 'v11'); +const MOCK_YARN_GLOBAL_DIR = path.join(path.sep, 'mock-home', '.config', 'yarn', 'global'); +const MOCK_YARN_GLOBAL_BIN = path.join(path.sep, 'mock-home', '.yarn', 'bin'); +const MOCK_YARN_PACKAGE_ROOT = path.join(MOCK_YARN_GLOBAL_DIR, 'node_modules', '@nocobase', 'cli'); +const MOCK_PNPM_PACKAGE_ROOT = path.join( + MOCK_PNPM_GLOBAL_HOME, + 'global', + 'v11', + 'mock-install', + 'node_modules', + '@nocobase', + 'cli', +); + +function createCommandOutputFn( + options: { + distTags?: Record; + globalPrefix?: string; + pnpmGlobalBin?: string; + pnpmGlobalRoot?: string; + } = {}, +) { + const { + distTags, + globalPrefix = '/usr/local', + pnpmGlobalBin = MOCK_PNPM_GLOBAL_BIN, + pnpmGlobalRoot = MOCK_PNPM_GLOBAL_ROOT, + } = options; + + return vi.fn(async (name: string, args: string[]) => { + const command = args.join(' '); + if (name === 'npm' && command === 'prefix -g') { + return globalPrefix; + } + if (name === 'pnpm' && command === 'bin -g') { + return pnpmGlobalBin; + } + if (name === 'pnpm' && command === 'root -g') { + return pnpmGlobalRoot; + } + if (name === 'yarn' && command === 'global dir') { + return MOCK_YARN_GLOBAL_DIR; + } + if (name === 'yarn' && command === 'global bin') { + return MOCK_YARN_GLOBAL_BIN; + } + if (distTags && name === 'npm' && command === 'view @nocobase/cli dist-tags --json') { + return JSON.stringify(distTags); + } + + throw new Error(`unexpected command: ${name} ${command}`); + }); +} beforeEach(async () => { const temp = await fsp.mkdtemp(path.join(os.tmpdir(), 'nocobase-cli-self-home-')); @@ -49,14 +104,8 @@ test('compareVersions handles prerelease ordering', () => { }); test('inspectSelfStatus resolves latest version and install support for npm-global installs', async () => { - const commandOutputFn = vi.fn(async (name: string, args: string[]) => { - if (name === 'npm' && args.join(' ') === 'prefix -g') { - return '/usr/local'; - } - if (name === 'npm' && args.join(' ') === 'view @nocobase/cli dist-tags --json') { - return JSON.stringify({ latest: '2.1.0', beta: '2.1.0-beta.18', alpha: '2.1.0-alpha.3' }); - } - throw new Error(`unexpected command: ${name} ${args.join(' ')}`); + const commandOutputFn = createCommandOutputFn({ + distTags: { latest: '2.1.0', beta: '2.1.0-beta.18', alpha: '2.1.0-alpha.3' }, }); const status = await inspectSelfStatus({ @@ -73,15 +122,69 @@ test('inspectSelfStatus resolves latest version and install support for npm-glob expect(status.updateBlockedReason).toBeUndefined(); }); +test('inspectSelfStatus recognizes pnpm-global installs', async () => { + const commandOutputFn = createCommandOutputFn({ + distTags: { latest: '2.1.0', beta: '2.1.0-beta.18' }, + }); + + const status = await inspectSelfStatus({ + packageRoot: MOCK_PNPM_PACKAGE_ROOT, + currentVersion: '2.1.0-beta.17', + channel: 'auto', + commandOutputFn: commandOutputFn as any, + }); + + expect(status.installMethod).toBe('pnpm-global'); + expect(status.latestVersion).toBe('2.1.0-beta.18'); + expect(status.updateAvailable).toBe(true); + expect(status.updatable).toBe(true); + expect(status.updateBlockedReason).toBeUndefined(); +}); + +test('inspectSelfStatus recognizes pnpm-global installs from custom global roots', async () => { + const customPnpmGlobalRoot = path.join(path.sep, 'opt', 'custom-pnpm-root'); + const commandOutputFn = createCommandOutputFn({ + distTags: { latest: '2.1.0', beta: '2.1.0-beta.18' }, + pnpmGlobalBin: path.join(path.sep, 'opt', 'custom-pnpm-bin'), + pnpmGlobalRoot: customPnpmGlobalRoot, + }); + + const status = await inspectSelfStatus({ + packageRoot: path.join(customPnpmGlobalRoot, 'node_modules', '@nocobase', 'cli'), + currentVersion: '2.1.0-beta.17', + channel: 'auto', + commandOutputFn, + }); + + expect(status.installMethod).toBe('pnpm-global'); + expect(status.latestVersion).toBe('2.1.0-beta.18'); + expect(status.updateAvailable).toBe(true); + expect(status.updatable).toBe(true); + expect(status.updateBlockedReason).toBeUndefined(); +}); + +test('inspectSelfStatus recognizes yarn-global installs', async () => { + const commandOutputFn = createCommandOutputFn({ + distTags: { latest: '2.1.0', beta: '2.1.0-beta.18' }, + }); + + const status = await inspectSelfStatus({ + packageRoot: MOCK_YARN_PACKAGE_ROOT, + currentVersion: '2.1.0-beta.17', + channel: 'auto', + commandOutputFn: commandOutputFn as any, + }); + + expect(status.installMethod).toBe('yarn-global'); + expect(status.latestVersion).toBe('2.1.0-beta.18'); + expect(status.updateAvailable).toBe(true); + expect(status.updatable).toBe(true); + expect(status.updateBlockedReason).toBeUndefined(); +}); + test('inspectSelfStatus detects test prerelease versions as test channel', async () => { - const commandOutputFn = vi.fn(async (name: string, args: string[]) => { - if (name === 'npm' && args.join(' ') === 'prefix -g') { - return '/usr/local'; - } - if (name === 'npm' && args.join(' ') === 'view @nocobase/cli dist-tags --json') { - return JSON.stringify({ latest: '2.1.4', test: '2.1.4-test.10' }); - } - throw new Error(`unexpected command: ${name} ${args.join(' ')}`); + const commandOutputFn = createCommandOutputFn({ + distTags: { latest: '2.1.4', test: '2.1.4-test.10' }, }); const status = await inspectSelfStatus({ @@ -96,15 +199,10 @@ test('inspectSelfStatus detects test prerelease versions as test channel', async expect(status.updateAvailable).toBe(true); }); -test('inspectSelfStatus caches install method by bin path', async () => { - const commandOutputFn = vi.fn(async (name: string, args: string[]) => { - if (name === 'npm' && args.join(' ') === 'prefix -g') { - return '/opt/global'; - } - if (name === 'npm' && args.join(' ') === 'view @nocobase/cli dist-tags --json') { - return JSON.stringify({ latest: '2.1.0' }); - } - throw new Error(`unexpected command: ${name} ${args.join(' ')}`); +test('inspectSelfStatus detects install method on every call', async () => { + const commandOutputFn = createCommandOutputFn({ + distTags: { latest: '2.1.0' }, + globalPrefix: '/opt/global', }); const packageRoot = path.join('/opt', 'apps', 'demo', 'node_modules', '@nocobase', 'cli'); @@ -119,6 +217,9 @@ test('inspectSelfStatus caches install method by bin path', async () => { const prefixCallsAfterFirst = commandOutputFn.mock.calls.filter( ([name, args]) => name === 'npm' && Array.isArray(args) && args.join(' ') === 'prefix -g', ).length; + const yarnCallsAfterFirst = commandOutputFn.mock.calls.filter( + ([name, args]) => name === 'yarn' && Array.isArray(args) && args.join(' ') === 'global dir', + ).length; const second = await inspectSelfStatus({ packageRoot, @@ -130,19 +231,21 @@ test('inspectSelfStatus caches install method by bin path', async () => { const prefixCallsAfterSecond = commandOutputFn.mock.calls.filter( ([name, args]) => name === 'npm' && Array.isArray(args) && args.join(' ') === 'prefix -g', ).length; + const yarnCallsAfterSecond = commandOutputFn.mock.calls.filter( + ([name, args]) => name === 'yarn' && Array.isArray(args) && args.join(' ') === 'global dir', + ).length; expect(first.installMethod).toBe('package-local'); expect(second.installMethod).toBe('package-local'); expect(prefixCallsAfterFirst).toBe(1); - expect(prefixCallsAfterSecond).toBe(1); + expect(prefixCallsAfterSecond).toBe(2); + expect(yarnCallsAfterFirst).toBe(1); + expect(yarnCallsAfterSecond).toBe(2); }); test('inspectSelfInstall only performs install-method detection', async () => { - const commandOutputFn = vi.fn(async (name: string, args: string[]) => { - if (name === 'npm' && args.join(' ') === 'prefix -g') { - return '/opt/global'; - } - throw new Error(`unexpected command: ${name} ${args.join(' ')}`); + const commandOutputFn = createCommandOutputFn({ + globalPrefix: '/opt/global', }); const install = await inspectSelfInstall({ @@ -151,12 +254,181 @@ test('inspectSelfInstall only performs install-method detection', async () => { }); expect(install.installMethod).toBe('package-local'); - expect(commandOutputFn).toHaveBeenCalledTimes(1); + expect(commandOutputFn).toHaveBeenCalledTimes(5); expect(commandOutputFn).toHaveBeenCalledWith( 'npm', ['prefix', '-g'], - expect.objectContaining({ errorName: 'npm prefix' }), + expect.objectContaining({ cwd: os.homedir(), errorName: 'npm prefix' }), ); + expect(commandOutputFn).toHaveBeenCalledWith( + 'pnpm', + ['bin', '-g'], + expect.objectContaining({ cwd: os.homedir(), errorName: 'pnpm bin' }), + ); + expect(commandOutputFn).toHaveBeenCalledWith( + 'pnpm', + ['root', '-g'], + expect.objectContaining({ cwd: os.homedir(), errorName: 'pnpm root' }), + ); + expect(commandOutputFn).toHaveBeenCalledWith( + 'yarn', + ['global', 'dir'], + expect.objectContaining({ cwd: os.homedir(), errorName: 'yarn global dir' }), + ); + expect(commandOutputFn).toHaveBeenCalledWith( + 'yarn', + ['global', 'bin'], + expect.objectContaining({ cwd: os.homedir(), errorName: 'yarn global bin' }), + ); +}); + +test('inspectSelfInstall recognizes yarn-global from the invoked bin path', async () => { + const commandOutputFn = createCommandOutputFn({ + globalPrefix: '/opt/global', + }); + + const install = await inspectSelfInstall({ + packageRoot: path.join('/tmp/cache/node_modules/@nocobase/cli'), + currentBinPath: path.join(MOCK_YARN_GLOBAL_BIN, 'nb'), + commandOutputFn: commandOutputFn as any, + }); + + expect(install.installMethod).toBe('yarn-global'); +}); + +test('inspectSelfInstall recognizes pnpm-global installs when the package resolves from the pnpm link store', async () => { + const dir = await fsp.mkdtemp(path.join(os.tmpdir(), 'nocobase-cli-self-pnpm-link-store-')); + const pnpmHome = path.join(dir, '.local', 'share', 'pnpm'); + const pnpmGlobalBin = path.join(pnpmHome, 'bin'); + const pnpmGlobalRoot = path.join(pnpmHome, 'global', 'v11'); + const pnpmGlobalNodeModules = path.join(pnpmGlobalRoot, 'node_modules'); + const packageRoot = path.join( + pnpmHome, + 'store', + 'v11', + 'links', + '@nocobase', + 'cli', + '2.1.0-beta.17', + 'mock-hash', + 'node_modules', + '@nocobase', + 'cli', + ); + const globalPackageLink = path.join(pnpmGlobalNodeModules, '@nocobase', 'cli'); + + try { + await fsp.mkdir(path.dirname(globalPackageLink), { recursive: true }); + await fsp.mkdir(packageRoot, { recursive: true }); + await fsp.symlink(packageRoot, globalPackageLink, process.platform === 'win32' ? 'junction' : 'dir'); + + const commandOutputFn = createCommandOutputFn({ + pnpmGlobalBin, + pnpmGlobalRoot, + }); + + const install = await inspectSelfInstall({ + packageRoot, + commandOutputFn: commandOutputFn as any, + }); + + expect(install.installMethod).toBe('pnpm-global'); + } finally { + await fsp.rm(dir, { recursive: true, force: true }); + } +}); + +test('inspectSelfInstall recognizes pnpm-global installs from hashed global project roots when pnpm bin is unavailable', async () => { + const dir = await fsp.mkdtemp(path.join(os.tmpdir(), 'nocobase-cli-self-pnpm-global-project-')); + const pnpmHome = path.join(dir, '.local', 'share', 'pnpm'); + const pnpmGlobalRoot = path.join(pnpmHome, 'global', 'v11'); + const pnpmGlobalProjectRoot = path.join(pnpmGlobalRoot, '42d4-19f0115472f'); + const packageRoot = path.join( + pnpmHome, + 'store', + 'v11', + 'links', + '@nocobase', + 'cli', + '2.1.11-test.10', + 'mock-hash', + 'node_modules', + '@nocobase', + 'cli', + ); + const globalPackageLink = path.join(pnpmGlobalProjectRoot, 'node_modules', '@nocobase', 'cli'); + + try { + await fsp.mkdir(path.dirname(globalPackageLink), { recursive: true }); + await fsp.mkdir(packageRoot, { recursive: true }); + await fsp.symlink(packageRoot, globalPackageLink, process.platform === 'win32' ? 'junction' : 'dir'); + + const commandOutputFn = vi.fn(async (name: string, args: string[]) => { + const command = args.join(' '); + if (name === 'npm' && command === 'prefix -g') { + return '/usr/local'; + } + if (name === 'pnpm' && command === 'bin -g') { + throw new Error('pnpm bin exited with code 1'); + } + if (name === 'pnpm' && command === 'root -g') { + return pnpmGlobalRoot; + } + if (name === 'yarn' && command === 'global dir') { + return MOCK_YARN_GLOBAL_DIR; + } + if (name === 'yarn' && command === 'global bin') { + return MOCK_YARN_GLOBAL_BIN; + } + + throw new Error(`unexpected command: ${name} ${command}`); + }); + + const install = await inspectSelfInstall({ + packageRoot, + commandOutputFn: commandOutputFn as any, + }); + + expect(install.installMethod).toBe('pnpm-global'); + } finally { + await fsp.rm(dir, { recursive: true, force: true }); + } +}); + +test('inspectSelfInstall ignores stale install-method cache files', async () => { + if (!process.env.NB_CLI_ROOT) { + throw new Error('NB_CLI_ROOT is not set'); + } + + const packageRoot = path.join('/tmp/cache/node_modules/@nocobase/cli'); + const currentBinPath = path.join(MOCK_YARN_GLOBAL_BIN, 'nb'); + const cacheDir = path.join(process.env.NB_CLI_ROOT, '.nocobase'); + await fsp.mkdir(cacheDir, { recursive: true }); + await fsp.writeFile( + path.join(cacheDir, 'self-install-methods.json'), + JSON.stringify({ + entries: { + [path.join(packageRoot, 'bin', 'run.js')]: { + installMethod: 'package-local', + currentBinPath, + yarnGlobalBin: MOCK_YARN_GLOBAL_BIN, + yarnGlobalDir: MOCK_YARN_GLOBAL_DIR, + }, + }, + }), + ); + + const commandOutputFn = createCommandOutputFn({ + globalPrefix: '/opt/global', + }); + + const install = await inspectSelfInstall({ + packageRoot, + currentBinPath, + commandOutputFn: commandOutputFn as any, + }); + + expect(install.installMethod).toBe('yarn-global'); }); test('updateSelf rejects unsupported install methods', async () => { @@ -181,14 +453,8 @@ test('updateSelf rejects unsupported install methods', async () => { test('updateSelf runs npm install -g when a newer version exists', async () => { const runFn = vi.fn(async () => undefined); - const commandOutputFn = vi.fn(async (name: string, args: string[]) => { - if (name === 'npm' && args.join(' ') === 'prefix -g') { - return '/usr/local'; - } - if (name === 'npm' && args.join(' ') === 'view @nocobase/cli dist-tags --json') { - return JSON.stringify({ beta: '2.1.0-beta.18' }); - } - throw new Error(`unexpected command: ${name} ${args.join(' ')}`); + const commandOutputFn = createCommandOutputFn({ + distTags: { beta: '2.1.0-beta.18' }, }); const result = await updateSelf({ @@ -211,16 +477,62 @@ test('updateSelf runs npm install -g when a newer version exists', async () => { ); }); +test('updateSelf runs pnpm add -g for pnpm-global installs', async () => { + const runFn = vi.fn(async () => undefined); + const commandOutputFn = createCommandOutputFn({ + distTags: { beta: '2.1.0-beta.18' }, + }); + + const result = await updateSelf({ + packageRoot: MOCK_PNPM_PACKAGE_ROOT, + currentVersion: '2.1.0-beta.17', + channel: 'beta', + commandOutputFn: commandOutputFn as any, + runFn: runFn as any, + }); + + expect(result.action).toBe('updated'); + expect(result.packageSpec).toBe('@nocobase/cli@beta'); + expect(runFn).toHaveBeenCalledWith( + 'pnpm', + ['add', '-g', '@nocobase/cli@beta'], + expect.objectContaining({ + errorName: 'pnpm add', + stdio: 'ignore', + }), + ); +}); + +test('updateSelf runs yarn global add for yarn-global installs', async () => { + const runFn = vi.fn(async () => undefined); + const commandOutputFn = createCommandOutputFn({ + distTags: { beta: '2.1.0-beta.18' }, + }); + + const result = await updateSelf({ + packageRoot: MOCK_YARN_PACKAGE_ROOT, + currentVersion: '2.1.0-beta.17', + channel: 'beta', + commandOutputFn: commandOutputFn as any, + runFn: runFn as any, + }); + + expect(result.action).toBe('updated'); + expect(result.packageSpec).toBe('@nocobase/cli@beta'); + expect(runFn).toHaveBeenCalledWith( + 'yarn', + ['global', 'add', '@nocobase/cli@beta'], + expect.objectContaining({ + errorName: 'yarn global add', + stdio: 'ignore', + }), + ); +}); + test('updateSelf forwards raw install output in verbose mode', async () => { const runFn = vi.fn(async () => undefined); - const commandOutputFn = vi.fn(async (name: string, args: string[]) => { - if (name === 'npm' && args.join(' ') === 'prefix -g') { - return '/usr/local'; - } - if (name === 'npm' && args.join(' ') === 'view @nocobase/cli dist-tags --json') { - return JSON.stringify({ beta: '2.1.0-beta.18' }); - } - throw new Error(`unexpected command: ${name} ${args.join(' ')}`); + const commandOutputFn = createCommandOutputFn({ + distTags: { beta: '2.1.0-beta.18' }, }); await updateSelf({ @@ -254,7 +566,7 @@ test('formatUnsupportedSelfUpdateMessage explains source installs clearly', () = installMethod: 'source', updatable: false, updateBlockedReason: - 'This CLI is running from source in a repository checkout. Automatic self-update is only supported for standard global npm installs. Upgrade this checkout through your repo workflow instead.', + 'This CLI is running from source in a repository checkout. Automatic self-update is only supported for standard global npm, pnpm, or yarn installs. Upgrade this checkout through your repo workflow instead.', }), ).toContain('running from source'); }); diff --git a/packages/core/cli/src/__tests__/startup-update.test.ts b/packages/core/cli/src/__tests__/startup-update.test.ts index f7bc5656a6d..6c6abf99e67 100644 --- a/packages/core/cli/src/__tests__/startup-update.test.ts +++ b/packages/core/cli/src/__tests__/startup-update.test.ts @@ -106,6 +106,26 @@ describe('startup update prompt', () => { expect(await shouldRunStartupUpdateCheck(['env', 'list'])).toBe(false); }); + test('pnpm-global installs participate in startup update checks', async () => { + const { shouldRunStartupUpdateCheck } = await import('../lib/startup-update.js'); + mocks.inspectSelfInstall.mockResolvedValue({ + installMethod: 'pnpm-global', + packageRoot: '/tmp/cli', + }); + + expect(await shouldRunStartupUpdateCheck(['env', 'list'])).toBe(true); + }); + + test('yarn-global installs participate in startup update checks', async () => { + const { shouldRunStartupUpdateCheck } = await import('../lib/startup-update.js'); + mocks.inspectSelfInstall.mockResolvedValue({ + installMethod: 'yarn-global', + packageRoot: '/tmp/cli', + }); + + expect(await shouldRunStartupUpdateCheck(['env', 'list'])).toBe(true); + }); + test('startup update check still runs in non-interactive sessions', async () => { const { shouldRunStartupUpdateCheck } = await import('../lib/startup-update.js'); mocks.isInteractiveTerminal.mockReturnValue(false); diff --git a/packages/core/cli/src/commands/self/update.ts b/packages/core/cli/src/commands/self/update.ts index 538b96121ff..b4a86060673 100644 --- a/packages/core/cli/src/commands/self/update.ts +++ b/packages/core/cli/src/commands/self/update.ts @@ -40,7 +40,7 @@ function formatSkillsUpdateMessage(result: SkillsUpdateResult, verbose: boolean) export default class SelfUpdate extends Command { static override summary = 'Update the globally installed NocoBase CLI'; static override description = - 'Update the current NocoBase CLI install when it is managed by a standard global npm install.'; + 'Update the current NocoBase CLI install when it is managed by a standard global npm, pnpm, or yarn install.'; static override examples = [ '<%= config.bin %> <%= command.id %>', '<%= config.bin %> <%= command.id %> --yes', @@ -97,7 +97,7 @@ export default class SelfUpdate extends Command { message: flags.skills ? `Update ${status.packageName} from ${status.currentVersion} to ${status.latestVersion} and refresh the globally installed NocoBase AI coding skills?` : `Update ${status.packageName} from ${status.currentVersion} to ${status.latestVersion}?`, - default: false, + default: true, }); } catch { return; diff --git a/packages/core/cli/src/lib/auth-store.ts b/packages/core/cli/src/lib/auth-store.ts index c067adf3be5..47365a3aefc 100644 --- a/packages/core/cli/src/lib/auth-store.ts +++ b/packages/core/cli/src/lib/auth-store.ts @@ -145,6 +145,7 @@ export interface AuthConfig { caddy?: string; git?: string; nginx?: string; + pnpm?: string; yarn?: string; }; proxy?: { @@ -287,6 +288,19 @@ function normalizeAuthConfig(config: AuthConfig & { dockerResourcePrefix?: strin ? settings.log.retentionDays : undefined; const logEnabled = typeof settings.log?.enabled === 'boolean' ? settings.log.enabled : undefined; + const hasBinSettings = + settings.bin?.docker || + settings.bin?.caddy || + settings.bin?.git || + settings.bin?.nginx || + settings.bin?.pnpm || + settings.bin?.yarn; + const hasProxySettings = + settings.proxy?.nbCliRoot || + settings.proxy?.caddyDriver || + settings.proxy?.nginxDriver || + settings.proxy?.upstreamHost || + (settings.proxy as { host?: unknown } | undefined)?.host; return { name: config.name || config.dockerResourcePrefix, settings: { @@ -311,22 +325,19 @@ function normalizeAuthConfig(config: AuthConfig & { dockerResourcePrefix?: strin }, } : {}), - ...(settings.bin?.docker || settings.bin?.caddy || settings.bin?.git || settings.bin?.nginx || settings.bin?.yarn + ...(hasBinSettings ? { bin: { ...(settings.bin?.docker ? { docker: normalizeOptionalString(settings.bin.docker) } : {}), ...(settings.bin?.caddy ? { caddy: normalizeOptionalString(settings.bin.caddy) } : {}), ...(settings.bin?.git ? { git: normalizeOptionalString(settings.bin.git) } : {}), ...(settings.bin?.nginx ? { nginx: normalizeOptionalString(settings.bin.nginx) } : {}), + ...(settings.bin?.pnpm ? { pnpm: normalizeOptionalString(settings.bin.pnpm) } : {}), ...(settings.bin?.yarn ? { yarn: normalizeOptionalString(settings.bin.yarn) } : {}), }, } : {}), - ...(settings.proxy?.nbCliRoot || - settings.proxy?.caddyDriver || - settings.proxy?.nginxDriver || - settings.proxy?.upstreamHost || - (settings.proxy as { host?: unknown } | undefined)?.host + ...(hasProxySettings ? { proxy: { ...(settings.proxy?.nbCliRoot ? { nbCliRoot: normalizeOptionalString(settings.proxy.nbCliRoot) } : {}), diff --git a/packages/core/cli/src/lib/cli-config.ts b/packages/core/cli/src/lib/cli-config.ts index 83ffd39f928..a7f2879ec8e 100644 --- a/packages/core/cli/src/lib/cli-config.ts +++ b/packages/core/cli/src/lib/cli-config.ts @@ -19,6 +19,7 @@ export const DEFAULT_DOCKER_BIN = 'docker'; export const DEFAULT_CADDY_BIN = 'caddy'; export const DEFAULT_GIT_BIN = 'git'; export const DEFAULT_NGINX_BIN = 'nginx'; +export const DEFAULT_PNPM_BIN = 'pnpm'; export const PROXY_PROVIDER_OPTIONS = ['nginx', 'caddy'] as const; export type ProxyProvider = (typeof PROXY_PROVIDER_OPTIONS)[number]; export const DEFAULT_PROXY_PROVIDER: ProxyProvider = 'nginx'; @@ -48,6 +49,7 @@ export const SUPPORTED_CLI_CONFIG_KEYS = [ 'bin.caddy', 'bin.git', 'bin.nginx', + 'bin.pnpm', 'proxy.nb-cli-root', 'proxy.caddy-driver', 'proxy.nginx-driver', @@ -168,6 +170,7 @@ function pruneSettings(config: AuthConfig): void { !trimValue(bin.caddy) && !trimValue(bin.git) && !trimValue(bin.nginx) && + !trimValue(bin.pnpm) && !trimValue(bin.yarn) ) { delete config.settings?.bin; @@ -228,6 +231,8 @@ export function getExplicitCliConfigValue(config: AuthConfig, key: SupportedCliC return trimValue(config.settings?.bin?.git); case 'bin.nginx': return trimValue(config.settings?.bin?.nginx); + case 'bin.pnpm': + return trimValue(config.settings?.bin?.pnpm); case 'proxy.nb-cli-root': return trimValue(config.settings?.proxy?.nbCliRoot); case 'proxy.caddy-driver': @@ -276,6 +281,8 @@ export function getEffectiveCliConfigValue(config: AuthConfig, key: SupportedCli return DEFAULT_GIT_BIN; case 'bin.nginx': return DEFAULT_NGINX_BIN; + case 'bin.pnpm': + return DEFAULT_PNPM_BIN; case 'proxy.nb-cli-root': return explicit ?? resolveCliHomeRoot(); case 'proxy.caddy-driver': @@ -458,6 +465,12 @@ export async function setCliConfigValue( nginx: normalized, }; break; + case 'bin.pnpm': + config.settings.bin = { + ...(config.settings.bin ?? {}), + pnpm: normalized, + }; + break; case 'proxy.nb-cli-root': config.settings.proxy = { ...(config.settings.proxy ?? {}), @@ -574,6 +587,11 @@ export async function deleteCliConfigValue( delete config.settings.bin.nginx; } break; + case 'bin.pnpm': + if (config.settings.bin) { + delete config.settings.bin.pnpm; + } + break; case 'proxy.nb-cli-root': if (config.settings.proxy) { delete config.settings.proxy.nbCliRoot; @@ -641,6 +659,7 @@ const CONFIGURABLE_COMMAND_KEYS = { caddy: 'bin.caddy', git: 'bin.git', nginx: 'bin.nginx', + pnpm: 'bin.pnpm', yarn: 'bin.yarn', } as const; diff --git a/packages/core/cli/src/lib/run-npm.ts b/packages/core/cli/src/lib/run-npm.ts index f93cceedb36..97587397b0e 100644 --- a/packages/core/cli/src/lib/run-npm.ts +++ b/packages/core/cli/src/lib/run-npm.ts @@ -48,6 +48,10 @@ const MISSING_COMMAND_SPECS = { displayName: 'Yarn', configKey: 'bin.yarn', }, + pnpm: { + displayName: 'pnpm', + configKey: 'bin.pnpm', + }, } as const; const DOCKER_DAEMON_UNAVAILABLE_PATTERNS = [ /cannot connect to the docker daemon/i, diff --git a/packages/core/cli/src/lib/self-manager.ts b/packages/core/cli/src/lib/self-manager.ts index 93ff4d0b0bd..755c985e81c 100644 --- a/packages/core/cli/src/lib/self-manager.ts +++ b/packages/core/cli/src/lib/self-manager.ts @@ -8,18 +8,16 @@ */ import fs from 'node:fs'; -import fsp from 'node:fs/promises'; +import os from 'node:os'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; -import { resolveCliHomeDir } from './cli-home.js'; import { commandOutput, run } from './run-npm.js'; const DEFAULT_PACKAGE_NAME = '@nocobase/cli'; const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..'); -const INSTALL_METHOD_CACHE_FILE = 'self-install-methods.json'; export type SelfChannel = 'latest' | 'test' | 'beta' | 'alpha'; -export type SelfInstallMethod = 'npm-global' | 'package-local' | 'source' | 'unknown'; +export type SelfInstallMethod = 'npm-global' | 'pnpm-global' | 'yarn-global' | 'package-local' | 'source' | 'unknown'; export type SelfStatus = { packageName: string; @@ -45,6 +43,7 @@ type SelfManagerOptions = { channel?: SelfChannel | 'auto'; commandOutputFn?: typeof commandOutput; currentVersion?: string; + currentBinPath?: string; packageName?: string; packageRoot?: string; }; @@ -62,15 +61,6 @@ type ParsedVersion = { prerelease: string[]; }; -type InstallMethodCacheEntry = { - installMethod: SelfInstallMethod; - globalPrefix?: string; -}; - -type InstallMethodCacheState = { - entries?: Record; -}; - function normalizePath(value: string): string { return path.resolve(value); } @@ -191,7 +181,16 @@ function readCurrentVersion(packageRoot: string): string { return String(pkg.version ?? '').trim(); } -function detectInstallMethod(packageRoot: string, globalPrefix?: string): SelfInstallMethod { +function detectInstallMethod( + packageRoot: string, + options: { + globalPrefix?: string; + packageName?: string; + pnpmGlobalBin?: string; + pnpmGlobalRoot?: string; + yarnGlobalDir?: string; + } = {}, +): SelfInstallMethod { if ( fs.existsSync(path.join(packageRoot, 'src')) && fs.existsSync(path.join(packageRoot, 'tsconfig.json')) @@ -199,10 +198,30 @@ function detectInstallMethod(packageRoot: string, globalPrefix?: string): SelfIn return 'source'; } - if (globalPrefix && isSubPath(globalPrefix, packageRoot)) { + if (options.globalPrefix && isSubPath(options.globalPrefix, packageRoot)) { return 'npm-global'; } + if (options.yarnGlobalDir && isSubPath(options.yarnGlobalDir, packageRoot)) { + return 'yarn-global'; + } + + if ( + isPnpmGlobalInstallPath({ + packageName: options.packageName ?? DEFAULT_PACKAGE_NAME, + packageRoot, + pnpmGlobalBin: options.pnpmGlobalBin, + pnpmGlobalRoot: options.pnpmGlobalRoot, + }) + ) { + return 'pnpm-global'; + } + + // Best-effort fallback for environments where pnpm probes are unavailable. + if (isPnpmGlobalPath(packageRoot)) { + return 'pnpm-global'; + } + if (packageRoot.includes(`${path.sep}node_modules${path.sep}`)) { return 'package-local'; } @@ -210,48 +229,231 @@ function detectInstallMethod(packageRoot: string, globalPrefix?: string): SelfIn return 'unknown'; } -function getInstallMethodCacheFile(): string { - return path.join(resolveCliHomeDir('global'), INSTALL_METHOD_CACHE_FILE); +function isPnpmGlobalPath(packageRoot: string): boolean { + const normalized = normalizePath(packageRoot); + const segments = normalized.split(path.sep).filter(Boolean); + const globalIndex = segments.findIndex((segment, index) => segment === 'global' && segments[index - 1] === 'pnpm'); + if (globalIndex === -1) { + return false; + } + + return segments.slice(globalIndex + 2).includes('node_modules'); } -function getInstallMethodCacheKey(packageRoot: string): string { - return normalizePath(path.join(packageRoot, 'bin', 'run.js')); +function normalizePnpmGlobalNodeModulesRoot(pnpmGlobalRoot: string): string { + const normalizedGlobalRoot = normalizePath(pnpmGlobalRoot); + return path.basename(normalizedGlobalRoot) === 'node_modules' + ? normalizedGlobalRoot + : path.join(normalizedGlobalRoot, 'node_modules'); } -async function readInstallMethodCache(): Promise { +function readSiblingPnpmGlobalNodeModulesRoots(pnpmGlobalRoot: string): string[] { + const globalNodeModulesDir = normalizePnpmGlobalNodeModulesRoot(pnpmGlobalRoot); + const globalProjectDir = path.dirname(globalNodeModulesDir); + let entries: string[]; + try { - const raw = await fsp.readFile(getInstallMethodCacheFile(), 'utf8'); - return JSON.parse(raw) as InstallMethodCacheState; + entries = fs.readdirSync(globalProjectDir); } catch { - return {}; + return []; + } + + return entries + .filter((entry) => { + if (entry === path.basename(globalNodeModulesDir)) { + return false; + } + + try { + return fs.statSync(path.join(globalProjectDir, entry)).isDirectory(); + } catch { + return false; + } + }) + .map((entry) => path.join(globalProjectDir, entry, 'node_modules')); +} + +function readPnpmGlobalNodeModulesRoots(pnpmGlobalRoot: string): string[] { + return [normalizePnpmGlobalNodeModulesRoot(pnpmGlobalRoot), ...readSiblingPnpmGlobalNodeModulesRoots(pnpmGlobalRoot)]; +} + +function packageNameToPath(packageName: string): string[] { + return packageName.split('/').filter(Boolean); +} + +function isSameRealPath(left: string, right: string): boolean { + try { + return normalizePath(fs.realpathSync(left)) === normalizePath(fs.realpathSync(right)); + } catch { + return false; } } -async function writeInstallMethodCache(state: InstallMethodCacheState): Promise { - const filePath = getInstallMethodCacheFile(); - await fsp.mkdir(path.dirname(filePath), { recursive: true }); - await fsp.writeFile(filePath, JSON.stringify(state, null, 2)); +function isPnpmGlobalRootPath(pnpmGlobalRoot: string, packageRoot: string): boolean { + if (isSubPath(pnpmGlobalRoot, packageRoot)) { + return true; + } + + const globalNodeModulesDir = normalizePnpmGlobalNodeModulesRoot(pnpmGlobalRoot); + const globalProjectDir = path.dirname(globalNodeModulesDir); + if (!isSubPath(globalProjectDir, packageRoot)) { + return false; + } + + const segments = normalizePath(packageRoot).split(path.sep).filter(Boolean); + const pnpmStoreIndex = segments.indexOf('.pnpm'); + if (pnpmStoreIndex === -1) { + return false; + } + + return segments.slice(pnpmStoreIndex + 1).includes('node_modules'); } -async function readCachedInstallMethod(packageRoot: string): Promise { - const state = await readInstallMethodCache(); - return state.entries?.[getInstallMethodCacheKey(packageRoot)]; +function isPnpmGlobalPackagePath(pnpmGlobalRoot: string, packageRoot: string, packageName: string): boolean { + return readPnpmGlobalNodeModulesRoots(pnpmGlobalRoot).some((pnpmGlobalNodeModulesRoot) => + isSameRealPath(path.join(pnpmGlobalNodeModulesRoot, ...packageNameToPath(packageName)), packageRoot), + ); } -async function writeCachedInstallMethod(packageRoot: string, entry: InstallMethodCacheEntry): Promise { - const state = await readInstallMethodCache(); - const entries = { - ...(state.entries ?? {}), - [getInstallMethodCacheKey(packageRoot)]: entry, - }; - await writeInstallMethodCache({ entries }); +function isPnpmGlobalBinProjectPath(pnpmGlobalBin: string, packageRoot: string, packageName: string): boolean { + const pnpmHome = path.dirname(normalizePath(pnpmGlobalBin)); + const globalDir = path.join(pnpmHome, 'global'); + if (isSubPath(globalDir, packageRoot)) { + return true; + } + + let entries: string[]; + try { + entries = fs.readdirSync(globalDir); + } catch { + return false; + } + + return entries.some((entry) => { + const pnpmGlobalRoot = path.join(globalDir, entry); + return ( + isPnpmGlobalRootPath(pnpmGlobalRoot, packageRoot) + || isPnpmGlobalPackagePath(pnpmGlobalRoot, packageRoot, packageName) + ); + }); +} + +function isPnpmGlobalInstallPath(options: { + packageName: string; + packageRoot: string; + pnpmGlobalBin?: string; + pnpmGlobalRoot?: string; +}): boolean { + if (options.pnpmGlobalRoot) { + const matchedRoot = + isPnpmGlobalRootPath(options.pnpmGlobalRoot, options.packageRoot) + || isPnpmGlobalPackagePath(options.pnpmGlobalRoot, options.packageRoot, options.packageName); + if (matchedRoot) { + return true; + } + } + + if (options.pnpmGlobalBin) { + return isPnpmGlobalBinProjectPath(options.pnpmGlobalBin, options.packageRoot, options.packageName); + } + + return false; +} + +function readCurrentBinPath(currentBinPath?: string): string | undefined { + const candidate = String(currentBinPath ?? process.argv[1] ?? '').trim(); + if (!candidate) { + return undefined; + } + + return normalizePath(candidate); +} + +function cleanCommandPath(value: string): string | undefined { + const trimmed = value.trim(); + return trimmed ? trimmed : undefined; +} + +function resolvePackageManagerProbeCwd(): string | undefined { + const candidates = [os.homedir(), os.tmpdir(), path.parse(process.cwd()).root]; + + for (const candidate of candidates) { + if (!candidate) { + continue; + } + + try { + if (fs.statSync(candidate).isDirectory()) { + return candidate; + } + } catch { + // Ignore invalid probe cwd candidates and continue to the next one. + } + } + + return undefined; } async function readGlobalPrefix(commandOutputFn: typeof commandOutput): Promise { try { - return (await commandOutputFn('npm', ['prefix', '-g'], { - errorName: 'npm prefix', - })).trim(); + return cleanCommandPath( + await commandOutputFn('npm', ['prefix', '-g'], { + cwd: resolvePackageManagerProbeCwd(), + errorName: 'npm prefix', + }), + ); + } catch { + return undefined; + } +} + +async function readPnpmGlobalBin(commandOutputFn: typeof commandOutput): Promise { + try { + return cleanCommandPath( + await commandOutputFn('pnpm', ['bin', '-g'], { + cwd: resolvePackageManagerProbeCwd(), + errorName: 'pnpm bin', + }), + ); + } catch { + return undefined; + } +} + +async function readPnpmGlobalRoot(commandOutputFn: typeof commandOutput): Promise { + try { + return cleanCommandPath( + await commandOutputFn('pnpm', ['root', '-g'], { + cwd: resolvePackageManagerProbeCwd(), + errorName: 'pnpm root', + }), + ); + } catch { + return undefined; + } +} + +async function readYarnGlobalDir(commandOutputFn: typeof commandOutput): Promise { + try { + return cleanCommandPath( + await commandOutputFn('yarn', ['global', 'dir'], { + cwd: resolvePackageManagerProbeCwd(), + errorName: 'yarn global dir', + }), + ); + } catch { + return undefined; + } +} + +async function readYarnGlobalBin(commandOutputFn: typeof commandOutput): Promise { + try { + return cleanCommandPath( + await commandOutputFn('yarn', ['global', 'bin'], { + cwd: resolvePackageManagerProbeCwd(), + errorName: 'yarn global bin', + }), + ); } catch { return undefined; } @@ -272,7 +474,7 @@ function getUnsupportedSelfUpdateReason(installMethod: SelfInstallMethod): strin if (installMethod === 'source') { return [ 'This CLI is running from source in a repository checkout.', - 'Automatic self-update is only supported for standard global npm installs.', + 'Automatic self-update is only supported for standard global npm, pnpm, or yarn installs.', 'Upgrade this checkout through your repo workflow instead.', ].join(' '); } @@ -280,15 +482,15 @@ function getUnsupportedSelfUpdateReason(installMethod: SelfInstallMethod): strin if (installMethod === 'package-local') { return [ 'This CLI is installed from a local project dependency tree.', - 'Automatic self-update is only supported for standard global npm installs.', + 'Automatic self-update is only supported for standard global npm, pnpm, or yarn installs.', 'Upgrade the parent project dependency that provides this CLI instead.', ].join(' '); } if (installMethod === 'unknown') { return [ - 'This CLI install could not be recognized as a standard global npm install.', - 'Automatic self-update is only supported for standard global npm installs.', + 'This CLI install could not be recognized as a standard global npm, pnpm, or yarn install.', + 'Automatic self-update is only supported for standard global npm, pnpm, or yarn installs.', ].join(' '); } @@ -322,19 +524,28 @@ export function getSelfUpdatePackageSpec(status: Pick = {}): Promise { +export async function inspectSelfInstall( + options: Pick = {}, +): Promise { const packageRoot = options.packageRoot ? normalizePath(options.packageRoot) : PACKAGE_ROOT; + const packageName = options.packageName ?? DEFAULT_PACKAGE_NAME; const commandOutputFn = options.commandOutputFn ?? commandOutput; - const cachedInstallMethod = await readCachedInstallMethod(packageRoot); - const globalPrefix = cachedInstallMethod?.globalPrefix ?? await readGlobalPrefix(commandOutputFn); - const installMethod = cachedInstallMethod?.installMethod ?? detectInstallMethod(packageRoot, globalPrefix); - - if (!cachedInstallMethod) { - await writeCachedInstallMethod(packageRoot, { - installMethod, - globalPrefix, - }); - } + const currentBinPath = readCurrentBinPath(options.currentBinPath); + const globalPrefix = await readGlobalPrefix(commandOutputFn); + const pnpmGlobalBin = await readPnpmGlobalBin(commandOutputFn); + const pnpmGlobalRoot = await readPnpmGlobalRoot(commandOutputFn); + const yarnGlobalDir = await readYarnGlobalDir(commandOutputFn); + const yarnGlobalBin = await readYarnGlobalBin(commandOutputFn); + const installMethod = detectInstallMethodFromSignals({ + packageRoot, + currentBinPath, + globalPrefix, + packageName, + pnpmGlobalBin, + pnpmGlobalRoot, + yarnGlobalBin, + yarnGlobalDir, + }); return { packageRoot, @@ -343,6 +554,33 @@ export async function inspectSelfInstall(options: Pick { const packageRoot = options.packageRoot ? normalizePath(options.packageRoot) : PACKAGE_ROOT; const packageName = options.packageName ?? DEFAULT_PACKAGE_NAME; @@ -350,6 +588,8 @@ export async function inspectSelfStatus(options: SelfManagerOptions = {}): Promi const channel = options.channel && options.channel !== 'auto' ? options.channel : detectChannel(currentVersion); const commandOutputFn = options.commandOutputFn ?? commandOutput; const { installMethod, globalPrefix } = await inspectSelfInstall({ + currentBinPath: options.currentBinPath, + packageName, packageRoot, commandOutputFn, }); @@ -374,7 +614,7 @@ export async function inspectSelfStatus(options: SelfManagerOptions = {}): Promi latestVersion, updateAvailable, installMethod, - updatable: installMethod === 'npm-global', + updatable: installMethod === 'npm-global' || installMethod === 'pnpm-global' || installMethod === 'yarn-global', updateBlockedReason: getUnsupportedSelfUpdateReason(installMethod), globalPrefix, registryError, @@ -384,10 +624,41 @@ export async function inspectSelfStatus(options: SelfManagerOptions = {}): Promi export function formatUnsupportedSelfUpdateMessage(status: SelfStatus): string { return status.updateBlockedReason ?? [ - 'Automatic self-update is only supported for standard global npm installs.', + 'Automatic self-update is only supported for standard global npm, pnpm, or yarn installs.', ].join('\n'); } +function resolveSelfUpdateInstallCommand( + installMethod: SelfInstallMethod, + packageSpec: string, +): { + command: 'npm' | 'pnpm' | 'yarn'; + args: string[]; + errorName: string; +} { + if (installMethod === 'pnpm-global') { + return { + command: 'pnpm', + args: ['add', '-g', packageSpec], + errorName: 'pnpm add', + }; + } + + if (installMethod === 'yarn-global') { + return { + command: 'yarn', + args: ['global', 'add', packageSpec], + errorName: 'yarn global add', + }; + } + + return { + command: 'npm', + args: ['install', '-g', packageSpec], + errorName: 'npm install', + }; +} + export async function updateSelf(options: SelfUpdateOptions = {}): Promise<{ action: 'noop' | 'updated'; status: SelfStatus; @@ -414,9 +685,10 @@ export async function updateSelf(options: SelfUpdateOptions = {}): Promise<{ } const packageSpec = getSelfUpdatePackageSpec(status); - await (options.runFn ?? run)('npm', ['install', '-g', packageSpec], { + const installCommand = resolveSelfUpdateInstallCommand(status.installMethod, packageSpec); + await (options.runFn ?? run)(installCommand.command, installCommand.args, { stdio: options.verbose ? 'inherit' : 'ignore', - errorName: 'npm install', + errorName: installCommand.errorName, }); return { diff --git a/packages/core/cli/src/lib/startup-update.ts b/packages/core/cli/src/lib/startup-update.ts index 3ed80eb71ba..98e989d676f 100644 --- a/packages/core/cli/src/lib/startup-update.ts +++ b/packages/core/cli/src/lib/startup-update.ts @@ -207,7 +207,7 @@ export async function shouldRunStartupUpdateCheck(argv: string[], now = new Date } export function shouldEnableStartupUpdateForInstallMethod(installMethod: SelfInstallMethod) { - return installMethod === 'npm-global'; + return installMethod === 'npm-global' || installMethod === 'pnpm-global' || installMethod === 'yarn-global'; } function hasPendingUpdates(selfStatus: SelfStatus, skillsStatus: Awaited>) {