@ziniao-open/cli 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -2
- package/package.json +6 -2
- package/scripts/install.js +31 -8
- package/scripts/remove-ziniao-cli-shims.ps1 +43 -0
- package/scripts/remove-ziniao-cli-shims.sh +82 -0
- package/scripts/setup-ziniao-cli.ps1 +179 -0
- package/scripts/setup-ziniao-cli.sh +232 -0
package/README.md
CHANGED
|
@@ -10,6 +10,43 @@
|
|
|
10
10
|
npm install -g @ziniao-open/cli
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
紫鸟客户端自带的 `ziniao` CLI 需要同步到 AppCache 并加入 PATH。执行 `npm install -g @ziniao-open/cli` 时会自动尝试同步;安装紫鸟客户端后,也可以手动执行以下命令:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
source "$(npm root -g)/@ziniao-open/cli/scripts/setup-ziniao-cli.sh"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Windows PowerShell 执行:
|
|
20
|
+
|
|
21
|
+
```powershell
|
|
22
|
+
. "$(npm root -g)\@ziniao-open\cli\scripts\setup-ziniao-cli.ps1"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
也可以在安装后手动修复:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
ziniao-cli doctor fix-path
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
遍历当前 PATH 清理旧的 `ziniao` shim,并清理 Unix 端的 `ziniaobrowser/cli` 缓存目录(默认只预览):
|
|
32
|
+
|
|
33
|
+
```powershell
|
|
34
|
+
& "$(npm root -g)\@ziniao-open\cli\scripts\remove-ziniao-cli-shims.ps1"
|
|
35
|
+
& "$(npm root -g)\@ziniao-open\cli\scripts\remove-ziniao-cli-shims.ps1" -Apply
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
macOS/Linux:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
"$(npm root -g)/@ziniao-open/cli/scripts/remove-ziniao-cli-shims.sh"
|
|
42
|
+
"$(npm root -g)/@ziniao-open/cli/scripts/remove-ziniao-cli-shims.sh" --apply
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
脚本只探测 `ziniao.app` / `ziniao` 的安装目录;Windows 会优先查询卸载注册表中 `DisplayIcon` 包含 `ziniao.exe` 的条目,再从本体目录的 `resources/app.asar.unpacked/envkit/cli` 查找 CLI。Windows 使用 `%APPDATA%\ziniaobrowser\cli`,macOS 使用 `~/Library/Application Support/ziniaobrowser/cli`,Linux 使用 `${XDG_CONFIG_HOME:-~/.config}/ziniaobrowser/cli`,在目标目录缺少 CLI 或文件内容发生变化时同步最新文件,并注册当前用户 PATH。找不到源文件时只提示并继续,不阻断 PATH 配置。若安装目录无法自动探测,可设置 `ZINIAO_INSTALL_DIR`;若目标位置不同,可设置 `ZINIAO_APP_CACHE_DIR`。
|
|
46
|
+
Windows 同时会把找到的紫鸟本体绝对路径写入 `%APPDATA%\ziniaobrowser\gui-path`,供 CLI 定位桌面客户端。
|
|
47
|
+
macOS/Linux 也会在找到桌面本体时写入对应的 `gui-path`(macOS 为 `~/Library/Application Support/ziniaobrowser/gui-path`,Linux 为 `${XDG_CONFIG_HOME:-~/.config}/ziniaobrowser/gui-path`)。
|
|
48
|
+
macOS/Linux 还会在 `~/.local/bin/ziniao` 创建固定 shim,避免向随机 PATH 目录写入文件。
|
|
49
|
+
|
|
13
50
|
安装时会自动下载当前平台对应的预编译二进制(支持 macOS / Linux / Windows × amd64 / arm64),并做 SHA-256 校验。
|
|
14
51
|
|
|
15
52
|
## 快速开始
|
|
@@ -46,14 +83,49 @@ ziniao-cli --help
|
|
|
46
83
|
|
|
47
84
|
完整列表见 `ziniao-cli --help`。
|
|
48
85
|
|
|
86
|
+
## 本地 dev/prod 打包与切换
|
|
87
|
+
|
|
88
|
+
在仓库根目录执行以下命令,可分别生成本地测试环境包和本地正式环境包:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
make package-dev
|
|
92
|
+
make package-prod
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
两个命令都会生成本地多平台 snapshot 包。版本基于最近的发布 tag,并使用本机递增计数器:最近 tag 为 `v1.0.7` 时,依次生成 `1.0.7-dev-1`、`1.0.7-dev-2`、`1.0.7-dev-3`。
|
|
96
|
+
|
|
97
|
+
计数器保存在 `~/.ziniao-cli/dev-build-counter`;当最近 tag 变化时计数从 `1` 重新开始。可通过 `ZINIAO_CLI_DEV_COUNTER_FILE` 指定其他计数器路径,便于 CI 或测试隔离。产物写入 `dist/`,该命令只打包,不发布。
|
|
98
|
+
|
|
99
|
+
`package-dev` 内置测试环境 `https://test-sbappstoreapi.ziniao.com` 与 `https://test-open.ziniao.com`,默认使用独立配置目录 `~/.ziniao-cli-dev/`,本地二进制写入 `~/.ziniao-cli-dev/bin/ziniao-cli`。
|
|
100
|
+
|
|
101
|
+
`package-prod` 内置正式环境 `https://sbappstoreapi.ziniao.com` 与 `https://open.ziniao.com`,默认使用独立配置目录 `~/.ziniao-cli-prod/`,本地二进制写入 `~/.ziniao-cli-prod/bin/ziniao-cli`。
|
|
102
|
+
|
|
103
|
+
仓库内的 `scripts/ziniao-cli-use` 提供统一切换入口;如果你已将该脚本加入 PATH,可直接执行:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
ziniao-cli-use dev
|
|
107
|
+
ziniao-cli-use prod
|
|
108
|
+
ziniao-cli-use online
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
- `ziniao-cli-use dev`:切换到 `~/.ziniao-cli-dev/bin/ziniao-cli`
|
|
112
|
+
- `ziniao-cli-use prod`:切换到 `~/.ziniao-cli-prod/bin/ziniao-cli`
|
|
113
|
+
- `ziniao-cli-use online`:切换回 npm 安装的线上版 `ziniao-cli`,继续使用默认线上配置目录 `~/.ziniao-cli/`
|
|
114
|
+
|
|
115
|
+
`make package-dev` 与 `make package-prod` 只会更新各自隔离的本地输出路径,不会改写仓库根目录的 `./ziniao-cli`。如果你需要仓库根目录的开发测试二进制,继续使用 `make build`。
|
|
116
|
+
|
|
117
|
+
dev、本地 prod、online 三套 CLI 默认分别使用 `~/.ziniao-cli-dev/`、`~/.ziniao-cli-prod/`、`~/.ziniao-cli/`,API Key 和配置互不读取。首次运行某个本地环境前,执行 `ziniao-cli config init` 即可在对应目录完成初始化。
|
|
118
|
+
|
|
49
119
|
## AI Agent Skills
|
|
50
120
|
|
|
51
|
-
仓库提供
|
|
121
|
+
仓库提供 12 个开箱即用的 AI Agent Skill:访问策略、账号、部门、设备、OpenAPI 探索、页面、角色、共享基础、Skill 创建、员工、店铺和批量账号授权。
|
|
52
122
|
|
|
53
123
|
安装 Skill:
|
|
54
124
|
|
|
55
125
|
```bash
|
|
56
|
-
|
|
126
|
+
ziniao-cli skills install
|
|
57
127
|
```
|
|
58
128
|
|
|
129
|
+
备选:`npx skills add ziniao-open/skills -y -g`
|
|
130
|
+
|
|
59
131
|
详见 [ziniao-skills](https://github.com/ziniao-open/skills)。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziniao-open/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "紫鸟开放平台命令行工具,为开发者和 AI Agent 提供统一的接口调用入口。",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"bin": {
|
|
@@ -12,7 +12,11 @@
|
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"scripts/install.js",
|
|
15
|
-
"scripts/run.js"
|
|
15
|
+
"scripts/run.js",
|
|
16
|
+
"scripts/setup-ziniao-cli.sh",
|
|
17
|
+
"scripts/setup-ziniao-cli.ps1",
|
|
18
|
+
"scripts/remove-ziniao-cli-shims.ps1",
|
|
19
|
+
"scripts/remove-ziniao-cli-shims.sh"
|
|
16
20
|
],
|
|
17
21
|
"engines": {
|
|
18
22
|
"node": ">=18"
|
package/scripts/install.js
CHANGED
|
@@ -197,6 +197,31 @@ function findBinaryIn(dir, name) {
|
|
|
197
197
|
return null;
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
+
function runDesktopCliSetup() {
|
|
201
|
+
const scriptName = IS_WIN ? "setup-ziniao-cli.ps1" : "setup-ziniao-cli.sh";
|
|
202
|
+
const scriptPath = join(__dirname, scriptName);
|
|
203
|
+
if (!existsSync(scriptPath)) {
|
|
204
|
+
warn(`desktop CLI PATH setup script is missing: ${scriptPath}`);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const result = IS_WIN
|
|
209
|
+
? spawnSync("powershell.exe", [
|
|
210
|
+
"-NoProfile",
|
|
211
|
+
"-NonInteractive",
|
|
212
|
+
"-ExecutionPolicy",
|
|
213
|
+
"Bypass",
|
|
214
|
+
"-File",
|
|
215
|
+
scriptPath,
|
|
216
|
+
], { stdio: "inherit" })
|
|
217
|
+
: spawnSync("sh", [scriptPath], { stdio: "inherit" });
|
|
218
|
+
if (result.error) {
|
|
219
|
+
warn(`desktop CLI PATH setup skipped: ${result.error.message}`);
|
|
220
|
+
} else if (result.status !== 0) {
|
|
221
|
+
warn(`desktop CLI PATH setup exited with code ${result.status}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
200
225
|
async function downloadAndInstall() {
|
|
201
226
|
const version = PKG.version;
|
|
202
227
|
if (!DOWNLOAD_BASE) {
|
|
@@ -266,18 +291,16 @@ async function main() {
|
|
|
266
291
|
if (PKG.version === "0.0.0") {
|
|
267
292
|
warn("package.json version is 0.0.0; skipping binary install (developer mode).");
|
|
268
293
|
warn("Set ZINIAO_CLI_BINARY=/path/to/binary or run `make build` to use a local build.");
|
|
269
|
-
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
if (existsSync(TARGET_PATH)) {
|
|
294
|
+
} else if (existsSync(TARGET_PATH)) {
|
|
273
295
|
makeExecutable(TARGET_PATH);
|
|
274
296
|
log(`binary already present at ${TARGET_PATH}, skipping download`);
|
|
275
|
-
|
|
297
|
+
} else if (copyFromEnv()) {
|
|
298
|
+
// Local binary installed.
|
|
299
|
+
} else {
|
|
300
|
+
await downloadAndInstall();
|
|
276
301
|
}
|
|
277
302
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
await downloadAndInstall();
|
|
303
|
+
runDesktopCliSetup();
|
|
281
304
|
}
|
|
282
305
|
|
|
283
306
|
main().catch((err) => fail(err.stack || err.message || String(err)));
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Find and optionally remove ziniao.exe shims created in PATH directories.
|
|
2
|
+
# Run without -Apply first to preview the files that would be removed.
|
|
3
|
+
|
|
4
|
+
[CmdletBinding(SupportsShouldProcess)]
|
|
5
|
+
param(
|
|
6
|
+
[switch]$Apply
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
$ErrorActionPreference = "Stop"
|
|
10
|
+
|
|
11
|
+
function Write-Log([string]$Message) {
|
|
12
|
+
Write-Output "[ziniao-cli-shims] $Message"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
$targetDir = Join-Path $env:APPDATA "ziniaobrowser\cli"
|
|
16
|
+
$candidates = @()
|
|
17
|
+
foreach ($pathEntry in @($env:Path -split ";" | Where-Object { $_ })) {
|
|
18
|
+
$directory = $pathEntry.TrimEnd('\')
|
|
19
|
+
if (-not $directory -or $directory -ieq $targetDir.TrimEnd('\')) { continue }
|
|
20
|
+
$shimPath = Join-Path $directory "ziniao.exe"
|
|
21
|
+
if (-not (Test-Path -LiteralPath $shimPath -PathType Leaf)) { continue }
|
|
22
|
+
$candidates += $shimPath
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (-not $candidates) {
|
|
26
|
+
Write-Log "No ziniao.exe shims found in PATH directories."
|
|
27
|
+
exit 0
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
foreach ($candidate in ($candidates | Select-Object -Unique)) {
|
|
31
|
+
if (-not $Apply) {
|
|
32
|
+
Write-Log "Would remove: $candidate"
|
|
33
|
+
continue
|
|
34
|
+
}
|
|
35
|
+
if ($PSCmdlet.ShouldProcess($candidate, "Remove CLI shim")) {
|
|
36
|
+
Remove-Item -LiteralPath $candidate -Force
|
|
37
|
+
Write-Log "Removed: $candidate"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (-not $Apply) {
|
|
42
|
+
Write-Log "Preview only. Re-run with -Apply to remove these files."
|
|
43
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Find and optionally remove ziniao shims created in PATH directories.
|
|
3
|
+
# Run without --apply first to preview the files that would be removed.
|
|
4
|
+
|
|
5
|
+
apply=0
|
|
6
|
+
if [ "${1:-}" = "--apply" ]; then
|
|
7
|
+
apply=1
|
|
8
|
+
elif [ -n "${1:-}" ]; then
|
|
9
|
+
printf '%s\n' "[ziniao-cli-shims] ERROR: unsupported option: $1" >&2
|
|
10
|
+
exit 2
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
log() { printf '%s\n' "[ziniao-cli-shims] $*"; }
|
|
14
|
+
|
|
15
|
+
home_dir="${HOME:?HOME is not set}"
|
|
16
|
+
platform="$(uname -s 2>/dev/null || printf 'unknown')"
|
|
17
|
+
case "$platform" in
|
|
18
|
+
Darwin) default_dir="$home_dir/Library/Application Support/ziniaobrowser/cli" ;;
|
|
19
|
+
Linux) default_dir="${XDG_CONFIG_HOME:-$home_dir/.config}/ziniaobrowser/cli" ;;
|
|
20
|
+
*)
|
|
21
|
+
log "ERROR: unsupported operating system: $platform"
|
|
22
|
+
exit 1
|
|
23
|
+
;;
|
|
24
|
+
esac
|
|
25
|
+
|
|
26
|
+
target_dir="${ZINIAO_APP_CACHE_DIR:-${default_dir%/cli}}/cli"
|
|
27
|
+
found=0
|
|
28
|
+
old_ifs="$IFS"
|
|
29
|
+
IFS=:
|
|
30
|
+
for path_entry in ${PATH:-}; do
|
|
31
|
+
IFS="$old_ifs"
|
|
32
|
+
directory="${path_entry%/}"
|
|
33
|
+
[ -n "$directory" ] || continue
|
|
34
|
+
[ "$directory" = "${target_dir%/}" ] && continue
|
|
35
|
+
shim_path="$directory/ziniao"
|
|
36
|
+
[ -e "$shim_path" ] || [ -L "$shim_path" ] || continue
|
|
37
|
+
found=1
|
|
38
|
+
if [ "$apply" -eq 1 ]; then
|
|
39
|
+
rm -f -- "$shim_path"
|
|
40
|
+
log "Removed: $shim_path"
|
|
41
|
+
else
|
|
42
|
+
log "Would remove: $shim_path"
|
|
43
|
+
fi
|
|
44
|
+
IFS=:
|
|
45
|
+
done
|
|
46
|
+
IFS="$old_ifs"
|
|
47
|
+
|
|
48
|
+
stable_shim="$home_dir/.local/bin/ziniao"
|
|
49
|
+
if [ -e "$stable_shim" ] || [ -L "$stable_shim" ]; then
|
|
50
|
+
if [ "$stable_shim" != "$target_dir/ziniao" ]; then
|
|
51
|
+
found=1
|
|
52
|
+
if [ "$apply" -eq 1 ]; then
|
|
53
|
+
rm -f -- "$stable_shim"
|
|
54
|
+
log "Removed: $stable_shim"
|
|
55
|
+
else
|
|
56
|
+
log "Would remove: $stable_shim"
|
|
57
|
+
fi
|
|
58
|
+
fi
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
cache_found=0
|
|
62
|
+
if [ -d "$target_dir" ]; then
|
|
63
|
+
cache_found=1
|
|
64
|
+
if [ "$apply" -eq 1 ]; then
|
|
65
|
+
if [ -f "$target_dir/ziniao" ] || [ -L "$target_dir/ziniao" ]; then
|
|
66
|
+
rm -f -- "$target_dir/ziniao"
|
|
67
|
+
fi
|
|
68
|
+
if rmdir "$target_dir" 2>/dev/null; then
|
|
69
|
+
log "Removed CLI cache directory: $target_dir"
|
|
70
|
+
else
|
|
71
|
+
log "WARN: CLI cache directory is not empty; keeping it: $target_dir"
|
|
72
|
+
fi
|
|
73
|
+
else
|
|
74
|
+
log "Would remove CLI cache directory: $target_dir"
|
|
75
|
+
fi
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
if [ "$found" -eq 0 ] && [ "$cache_found" -eq 0 ]; then
|
|
79
|
+
log "No ziniao shims found in PATH directories."
|
|
80
|
+
elif [ "$apply" -eq 0 ]; then
|
|
81
|
+
log "Preview only. Re-run with --apply to remove these files."
|
|
82
|
+
fi
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Synchronize the Ziniao desktop CLI into the per-user AppCache and register
|
|
2
|
+
# that directory in the current user's PATH.
|
|
3
|
+
#
|
|
4
|
+
# Use `. .\scripts\setup-ziniao-cli.ps1` to refresh the current PowerShell.
|
|
5
|
+
# A normal invocation persists PATH but cannot modify its parent PowerShell.
|
|
6
|
+
|
|
7
|
+
$ErrorActionPreference = "Stop"
|
|
8
|
+
$isDotSourced = $MyInvocation.InvocationName -eq "."
|
|
9
|
+
|
|
10
|
+
function Write-Log([string]$Message) {
|
|
11
|
+
Write-Output "[ziniao-cli-path] $Message"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
$arch = if ([Environment]::Is64BitOperatingSystem) {
|
|
15
|
+
if ($env:PROCESSOR_ARCHITEW6432) { $env:PROCESSOR_ARCHITEW6432 } else { $env:PROCESSOR_ARCHITECTURE }
|
|
16
|
+
} else { $env:PROCESSOR_ARCHITECTURE }
|
|
17
|
+
switch ($arch.ToLowerInvariant()) {
|
|
18
|
+
"amd64" { $archDir = "x64" }
|
|
19
|
+
"x86_64" { $archDir = "x64" }
|
|
20
|
+
"arm64" { $archDir = "arm64" }
|
|
21
|
+
default { throw "Unsupported CPU architecture: $arch" }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
$sourceName = "ziniao.exe"
|
|
25
|
+
$sourceRelative = Join-Path "envkit\cli\win32\$archDir" $sourceName
|
|
26
|
+
$resourceRoot = "resources\app.asar.unpacked"
|
|
27
|
+
|
|
28
|
+
$sourcePath = $null
|
|
29
|
+
$guiExecutablePath = $null
|
|
30
|
+
$checkedSourcePaths = @()
|
|
31
|
+
if ($env:ZINIAO_CLI_SOURCE -and (Test-Path -LiteralPath $env:ZINIAO_CLI_SOURCE -PathType Leaf)) {
|
|
32
|
+
$sourcePath = $env:ZINIAO_CLI_SOURCE
|
|
33
|
+
}
|
|
34
|
+
if (-not $sourcePath -and $env:ZINIAO_INSTALL_DIR) {
|
|
35
|
+
$candidate = Join-Path $env:ZINIAO_INSTALL_DIR "$resourceRoot\$sourceRelative"
|
|
36
|
+
$checkedSourcePaths += $candidate
|
|
37
|
+
if (Test-Path -LiteralPath $candidate -PathType Leaf) {
|
|
38
|
+
$sourcePath = $candidate
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (-not $sourcePath) {
|
|
42
|
+
$uninstallKeys = @(
|
|
43
|
+
"HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*",
|
|
44
|
+
"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*",
|
|
45
|
+
"HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
|
|
46
|
+
)
|
|
47
|
+
$uninstallEntries = Get-ItemProperty $uninstallKeys -ErrorAction SilentlyContinue |
|
|
48
|
+
Where-Object { $_.DisplayIcon -and $_.DisplayIcon -match "ziniao\.exe" }
|
|
49
|
+
foreach ($entry in $uninstallEntries) {
|
|
50
|
+
$displayIcon = ([string]$entry.DisplayIcon).Trim()
|
|
51
|
+
if ($displayIcon -match '^\s*"([^"]+\.exe)"') {
|
|
52
|
+
$executablePath = $matches[1]
|
|
53
|
+
} elseif ($displayIcon -match '^\s*(.*?\.exe)(?:,\d+)?(?:\s|$)') {
|
|
54
|
+
$executablePath = $matches[1]
|
|
55
|
+
} else {
|
|
56
|
+
continue
|
|
57
|
+
}
|
|
58
|
+
if (-not (Test-Path -LiteralPath $executablePath -PathType Leaf)) { continue }
|
|
59
|
+
$guiExecutablePath = $executablePath
|
|
60
|
+
$installDir = Split-Path -Parent $executablePath
|
|
61
|
+
$candidate = Join-Path $installDir "$resourceRoot\$sourceRelative"
|
|
62
|
+
$checkedSourcePaths += $candidate
|
|
63
|
+
if (Test-Path -LiteralPath $candidate -PathType Leaf) {
|
|
64
|
+
$sourcePath = $candidate
|
|
65
|
+
Write-Log "Found the Ziniao installation from the uninstall registry: $installDir"
|
|
66
|
+
break
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if ($env:ZINIAO_APP_CACHE_DIR) {
|
|
71
|
+
$appCacheDir = $env:ZINIAO_APP_CACHE_DIR
|
|
72
|
+
} else {
|
|
73
|
+
# The Windows GUI installs its CLI under %APPDATA%\ziniaobrowser\cli.
|
|
74
|
+
$appCacheDir = Join-Path $env:APPDATA "ziniaobrowser"
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
$targetDir = Join-Path $appCacheDir "cli"
|
|
78
|
+
$targetPath = Join-Path $targetDir $sourceName
|
|
79
|
+
New-Item -ItemType Directory -Path $targetDir -Force | Out-Null
|
|
80
|
+
|
|
81
|
+
if ($guiExecutablePath) {
|
|
82
|
+
$guiPathFile = Join-Path $env:APPDATA "ziniaobrowser\gui-path"
|
|
83
|
+
try {
|
|
84
|
+
New-Item -ItemType Directory -Path (Split-Path -Parent $guiPathFile) -Force | Out-Null
|
|
85
|
+
[System.IO.File]::WriteAllText(
|
|
86
|
+
$guiPathFile,
|
|
87
|
+
"$guiExecutablePath$([Environment]::NewLine)",
|
|
88
|
+
[System.Text.Encoding]::ASCII
|
|
89
|
+
)
|
|
90
|
+
Write-Log "Wrote GUI path hint: $guiPathFile"
|
|
91
|
+
} catch {
|
|
92
|
+
Write-Log "WARN: Could not write GUI path hint: $($_.Exception.Message)"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function Get-FileSha256([string]$Path) {
|
|
97
|
+
$sha256 = [System.Security.Cryptography.SHA256]::Create()
|
|
98
|
+
$stream = [System.IO.File]::OpenRead($Path)
|
|
99
|
+
try {
|
|
100
|
+
return ([BitConverter]::ToString($sha256.ComputeHash($stream))).Replace("-", "")
|
|
101
|
+
} finally {
|
|
102
|
+
$stream.Dispose()
|
|
103
|
+
$sha256.Dispose()
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (-not $sourcePath) {
|
|
108
|
+
foreach ($checkedPath in ($checkedSourcePaths | Select-Object -Unique)) {
|
|
109
|
+
Write-Log "Checked CLI source path: $checkedPath"
|
|
110
|
+
}
|
|
111
|
+
if (Test-Path -LiteralPath $targetPath -PathType Leaf) {
|
|
112
|
+
Write-Log "CLI source was not found in the install directory; keeping the existing AppCache CLI: $targetPath"
|
|
113
|
+
} else {
|
|
114
|
+
Write-Log "WARN: ${sourceName} was not found in the install directory; skipping copy. Set `$env:ZINIAO_INSTALL_DIR or `$env:ZINIAO_CLI_SOURCE to override."
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
$needsCopy = -not (Test-Path -LiteralPath $targetPath -PathType Leaf)
|
|
118
|
+
if (-not $needsCopy) {
|
|
119
|
+
$needsCopy = (Get-FileSha256 $sourcePath) -ne (Get-FileSha256 $targetPath)
|
|
120
|
+
}
|
|
121
|
+
if ($needsCopy) {
|
|
122
|
+
Copy-Item -LiteralPath $sourcePath -Destination $targetPath -Force
|
|
123
|
+
Write-Log "Synced CLI: $sourcePath -> $targetPath"
|
|
124
|
+
} else {
|
|
125
|
+
Write-Log "AppCache CLI is up to date: $targetPath"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function Install-PathShim {
|
|
130
|
+
if (-not (Test-Path -LiteralPath $targetPath -PathType Leaf)) { return }
|
|
131
|
+
$windowsAppsDir = Join-Path $env:LOCALAPPDATA "Microsoft\WindowsApps"
|
|
132
|
+
foreach ($pathEntry in @($env:Path -split ";" | Where-Object { $_ })) {
|
|
133
|
+
$normalizedPath = $pathEntry.TrimEnd('\')
|
|
134
|
+
if ($normalizedPath -ieq $windowsAppsDir.TrimEnd('\') -and (Test-Path -LiteralPath $windowsAppsDir -PathType Container)) {
|
|
135
|
+
$shimPath = Join-Path $windowsAppsDir $sourceName
|
|
136
|
+
if (-not (Test-Path -LiteralPath $shimPath)) {
|
|
137
|
+
try {
|
|
138
|
+
Copy-Item -LiteralPath $targetPath -Destination $shimPath -ErrorAction Stop
|
|
139
|
+
$script:shimInstalled = $true
|
|
140
|
+
Write-Log "Created the CLI shim in WindowsApps: $shimPath"
|
|
141
|
+
} catch {
|
|
142
|
+
Write-Log "WARN: Could not create the CLI shim in WindowsApps: $($_.Exception.Message)"
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
Write-Log "WindowsApps already contains a file named $sourceName; leaving it unchanged"
|
|
146
|
+
}
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
if ($normalizedPath -ieq $targetDir.TrimEnd('\')) {
|
|
150
|
+
$script:shimInstalled = $true
|
|
151
|
+
Write-Log "The current PATH already contains the AppCache CLI directory: $targetDir"
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
Write-Log "The AppCache CLI directory is not on the current PATH; no shim was created in another directory."
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
$shimInstalled = $false
|
|
159
|
+
Install-PathShim
|
|
160
|
+
|
|
161
|
+
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
|
|
162
|
+
$entries = @($userPath -split ";" | Where-Object { $_ })
|
|
163
|
+
if (-not ($entries | Where-Object { $_.TrimEnd('\') -ieq $targetDir.TrimEnd('\') })) {
|
|
164
|
+
[Environment]::SetEnvironmentVariable("Path", (($entries + $targetDir) -join ";"), "User")
|
|
165
|
+
Write-Log "Added to the user PATH: $targetDir"
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
$currentEntries = @($env:Path -split ";" | Where-Object { $_ })
|
|
169
|
+
if (-not ($currentEntries | Where-Object { $_.TrimEnd('\') -ieq $targetDir.TrimEnd('\') })) {
|
|
170
|
+
$env:Path = "$targetDir;$env:Path"
|
|
171
|
+
}
|
|
172
|
+
if ($shimInstalled) {
|
|
173
|
+
Write-Log "The CLI is already available on the current PATH; this PowerShell session needs no PATH refresh"
|
|
174
|
+
} elseif ($isDotSourced) {
|
|
175
|
+
Write-Log "The current PowerShell PATH was refreshed"
|
|
176
|
+
} else {
|
|
177
|
+
Write-Log "The current process PATH was refreshed; dot-source this script in the parent PowerShell or reopen the terminal"
|
|
178
|
+
}
|
|
179
|
+
Write-Log "Verification command: Get-Command ziniao"
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Synchronize the Ziniao desktop CLI into the per-user AppCache and register
|
|
3
|
+
# that directory in the current user's shell PATH.
|
|
4
|
+
#
|
|
5
|
+
# Use `source scripts/setup-ziniao-cli.sh` when the current shell should be
|
|
6
|
+
# refreshed immediately. A normal execution can persist PATH but cannot modify
|
|
7
|
+
# its parent shell.
|
|
8
|
+
|
|
9
|
+
log() { printf '%s\n' "[ziniao-cli-path] $*"; }
|
|
10
|
+
fail() { printf '%s\n' "[ziniao-cli-path] ERROR: $*" >&2; return 1 2>/dev/null || exit 1; }
|
|
11
|
+
|
|
12
|
+
is_sourced=0
|
|
13
|
+
if [ -n "${BASH_VERSION:-}" ]; then
|
|
14
|
+
[ "${BASH_SOURCE[0]:-$0}" != "$0" ] && is_sourced=1
|
|
15
|
+
elif [ -n "${ZSH_EVAL_CONTEXT:-}" ]; then
|
|
16
|
+
case "$ZSH_EVAL_CONTEXT" in
|
|
17
|
+
*:file) is_sourced=1 ;;
|
|
18
|
+
esac
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
if [ "$is_sourced" -eq 0 ]; then
|
|
22
|
+
set -eu
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
platform="$(uname -s 2>/dev/null || printf 'unknown')"
|
|
26
|
+
machine="$(uname -m 2>/dev/null || printf 'unknown')"
|
|
27
|
+
|
|
28
|
+
case "$platform" in
|
|
29
|
+
Darwin) platform_dir="darwin"; source_name="ziniao"; ;;
|
|
30
|
+
Linux) platform_dir="linux"; source_name="ziniao"; ;;
|
|
31
|
+
MINGW*|MSYS*|CYGWIN*)
|
|
32
|
+
fail "Windows shell detected; use PowerShell: scripts/setup-ziniao-cli.ps1"
|
|
33
|
+
return 1 2>/dev/null || exit 1
|
|
34
|
+
;;
|
|
35
|
+
*) fail "Unsupported operating system: $platform"; return 1 2>/dev/null || exit 1 ;;
|
|
36
|
+
esac
|
|
37
|
+
|
|
38
|
+
case "$machine" in
|
|
39
|
+
arm64|aarch64) arch_dir="arm64" ;;
|
|
40
|
+
x86_64|amd64) arch_dir="x64" ;;
|
|
41
|
+
*) fail "Unsupported CPU architecture: $machine"; return 1 2>/dev/null || exit 1 ;;
|
|
42
|
+
esac
|
|
43
|
+
|
|
44
|
+
home_dir="${HOME:?HOME is not set}"
|
|
45
|
+
|
|
46
|
+
find_source() {
|
|
47
|
+
if [ -n "${ZINIAO_CLI_SOURCE:-}" ] && [ -f "$ZINIAO_CLI_SOURCE" ]; then
|
|
48
|
+
printf '%s\n' "$ZINIAO_CLI_SOURCE"
|
|
49
|
+
return 0
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
for candidate_arch in "$arch_dir" x64 arm64; do
|
|
53
|
+
source_rel="envkit/cli/$platform_dir/$candidate_arch/$source_name"
|
|
54
|
+
if [ -n "${ZINIAO_INSTALL_DIR:-}" ]; then
|
|
55
|
+
candidate="$ZINIAO_INSTALL_DIR/$source_rel"
|
|
56
|
+
if [ -f "$candidate" ]; then
|
|
57
|
+
printf '%s\n' "$candidate"
|
|
58
|
+
return 0
|
|
59
|
+
fi
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
for install_root in \
|
|
63
|
+
"/Applications/ziniao.app/Contents/Resources/app.asar.unpacked" \
|
|
64
|
+
"$home_dir/Applications/ziniao.app/Contents/Resources/app.asar.unpacked" \
|
|
65
|
+
"$home_dir/Library/Application Support/ziniaobrowser/app.asar.unpacked" \
|
|
66
|
+
"/opt/ziniao/resources/app.asar.unpacked"; do
|
|
67
|
+
candidate="$install_root/$source_rel"
|
|
68
|
+
if [ -f "$candidate" ]; then
|
|
69
|
+
printf '%s\n' "$candidate"
|
|
70
|
+
return 0
|
|
71
|
+
fi
|
|
72
|
+
done
|
|
73
|
+
done
|
|
74
|
+
return 1
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
log_source_candidates() {
|
|
78
|
+
[ -n "${ZINIAO_CLI_SOURCE:-}" ] && log "Checked CLI source path: $ZINIAO_CLI_SOURCE"
|
|
79
|
+
for candidate_arch in "$arch_dir" x64 arm64; do
|
|
80
|
+
source_rel="envkit/cli/$platform_dir/$candidate_arch/$source_name"
|
|
81
|
+
[ -n "${ZINIAO_INSTALL_DIR:-}" ] && log "Checked CLI source path: $ZINIAO_INSTALL_DIR/$source_rel"
|
|
82
|
+
for install_root in \
|
|
83
|
+
"/Applications/ziniao.app/Contents/Resources/app.asar.unpacked" \
|
|
84
|
+
"$home_dir/Applications/ziniao.app/Contents/Resources/app.asar.unpacked" \
|
|
85
|
+
"$home_dir/Library/Application Support/ziniaobrowser/app.asar.unpacked" \
|
|
86
|
+
"/opt/ziniao/resources/app.asar.unpacked"; do
|
|
87
|
+
log "Checked CLI source path: $install_root/$source_rel"
|
|
88
|
+
done
|
|
89
|
+
done
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
find_gui_executable() {
|
|
93
|
+
case "$platform_dir" in
|
|
94
|
+
darwin)
|
|
95
|
+
for candidate in \
|
|
96
|
+
"/Applications/ziniao.app/Contents/MacOS/ziniaobrowser" \
|
|
97
|
+
"/Applications/ziniao.app/Contents/MacOS/ziniao" \
|
|
98
|
+
"$home_dir/Applications/ziniao.app/Contents/MacOS/ziniaobrowser" \
|
|
99
|
+
"$home_dir/Applications/ziniao.app/Contents/MacOS/ziniao"; do
|
|
100
|
+
[ -f "$candidate" ] && { printf '%s\n' "$candidate"; return 0; }
|
|
101
|
+
done
|
|
102
|
+
;;
|
|
103
|
+
linux)
|
|
104
|
+
for candidate in \
|
|
105
|
+
"/opt/ziniao/ziniaobrowser" \
|
|
106
|
+
"/opt/ziniao/ziniao" \
|
|
107
|
+
"/usr/lib/ziniaobrowser/ziniaobrowser" \
|
|
108
|
+
"/usr/lib/ziniaobrowser/ziniao"; do
|
|
109
|
+
[ -f "$candidate" ] && { printf '%s\n' "$candidate"; return 0; }
|
|
110
|
+
done
|
|
111
|
+
;;
|
|
112
|
+
esac
|
|
113
|
+
return 1
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if [ -n "${ZINIAO_APP_CACHE_DIR:-}" ]; then
|
|
117
|
+
target_dir="$ZINIAO_APP_CACHE_DIR/cli"
|
|
118
|
+
else
|
|
119
|
+
case "$platform_dir" in
|
|
120
|
+
darwin) target_dir="$home_dir/Library/Application Support/ziniaobrowser/cli" ;;
|
|
121
|
+
*) target_dir="${XDG_CONFIG_HOME:-$home_dir/.config}/ziniaobrowser/cli" ;;
|
|
122
|
+
esac
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
source_path="$(find_source || true)"
|
|
126
|
+
gui_executable_path="$(find_gui_executable || true)"
|
|
127
|
+
target_path="$target_dir/$source_name"
|
|
128
|
+
mkdir -p "$target_dir"
|
|
129
|
+
|
|
130
|
+
if [ -n "$source_path" ]; then
|
|
131
|
+
log "CLI source path: $source_path"
|
|
132
|
+
else
|
|
133
|
+
log_source_candidates
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
if [ -n "$gui_executable_path" ]; then
|
|
137
|
+
case "$platform_dir" in
|
|
138
|
+
darwin) gui_path_file="$home_dir/Library/Application Support/ziniaobrowser/gui-path" ;;
|
|
139
|
+
*)
|
|
140
|
+
xdg_config_home="${XDG_CONFIG_HOME:-$home_dir/.config}"
|
|
141
|
+
gui_path_file="$xdg_config_home/ziniaobrowser/gui-path"
|
|
142
|
+
;;
|
|
143
|
+
esac
|
|
144
|
+
if mkdir -p "$(dirname "$gui_path_file")" && printf '%s\n' "$gui_executable_path" > "$gui_path_file"; then
|
|
145
|
+
log "Wrote GUI path hint: $gui_path_file"
|
|
146
|
+
else
|
|
147
|
+
log "WARN: Could not write GUI path hint: $gui_path_file"
|
|
148
|
+
fi
|
|
149
|
+
fi
|
|
150
|
+
if [ -z "$source_path" ]; then
|
|
151
|
+
if [ -f "$target_path" ]; then
|
|
152
|
+
log "CLI source was not found in the install directory; keeping the existing AppCache CLI: $target_path"
|
|
153
|
+
else
|
|
154
|
+
log "WARN: ${source_name} was not found in the install directory; skipping copy. Set ZINIAO_INSTALL_DIR or ZINIAO_CLI_SOURCE to override."
|
|
155
|
+
fi
|
|
156
|
+
elif [ ! -f "$target_path" ] || ! cmp -s "$source_path" "$target_path"; then
|
|
157
|
+
cp "$source_path" "$target_path"
|
|
158
|
+
chmod 755 "$target_path"
|
|
159
|
+
log "Synced CLI: $source_path -> $target_path"
|
|
160
|
+
else
|
|
161
|
+
log "AppCache CLI is up to date: $target_path"
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
shim_installed=0
|
|
165
|
+
install_path_shim() {
|
|
166
|
+
[ -f "$target_path" ] || return 0
|
|
167
|
+
shim_dir="$home_dir/.local/bin"
|
|
168
|
+
shim_path="$shim_dir/$source_name"
|
|
169
|
+
mkdir -p "$shim_dir"
|
|
170
|
+
if [ -L "$shim_path" ] && [ "$(readlink "$shim_path" 2>/dev/null || true)" = "$target_path" ]; then
|
|
171
|
+
shim_installed=1
|
|
172
|
+
log "The CLI shim already points to the AppCache CLI: $shim_path"
|
|
173
|
+
elif [ ! -e "$shim_path" ]; then
|
|
174
|
+
if ln -s "$target_path" "$shim_path" 2>/dev/null; then
|
|
175
|
+
shim_installed=1
|
|
176
|
+
log "Created the CLI shim: $shim_path"
|
|
177
|
+
else
|
|
178
|
+
log "WARN: Could not create the CLI shim: $shim_path"
|
|
179
|
+
fi
|
|
180
|
+
else
|
|
181
|
+
log "A file already exists at the CLI shim path; leaving it unchanged: $shim_path"
|
|
182
|
+
fi
|
|
183
|
+
case ":${PATH:-}:" in
|
|
184
|
+
*:"$target_dir":*)
|
|
185
|
+
shim_installed=1
|
|
186
|
+
log "The current PATH already contains the AppCache CLI directory: $target_dir"
|
|
187
|
+
;;
|
|
188
|
+
*:"$shim_dir":*)
|
|
189
|
+
[ "$shim_installed" -eq 1 ] && log "The current PATH contains the CLI shim directory: $shim_dir"
|
|
190
|
+
;;
|
|
191
|
+
*)
|
|
192
|
+
log "The AppCache CLI directory is not on the current PATH; no shim will be created elsewhere: $target_dir"
|
|
193
|
+
;;
|
|
194
|
+
esac
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
install_path_shim
|
|
198
|
+
|
|
199
|
+
shim_dir="$home_dir/.local/bin"
|
|
200
|
+
export PATH="$target_dir:$shim_dir${PATH:+:$PATH}"
|
|
201
|
+
|
|
202
|
+
profile=""
|
|
203
|
+
case "${SHELL:-}" in
|
|
204
|
+
*/zsh) profile="$home_dir/.zshrc" ;;
|
|
205
|
+
*/bash) profile="$home_dir/.bashrc" ;;
|
|
206
|
+
esac
|
|
207
|
+
if [ -z "$profile" ]; then
|
|
208
|
+
case "$platform_dir" in
|
|
209
|
+
darwin) profile="$home_dir/.zshrc" ;;
|
|
210
|
+
*) profile="$home_dir/.profile" ;;
|
|
211
|
+
esac
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
marker="# ziniao-cli: AppCache CLI PATH"
|
|
215
|
+
path_line="export PATH=\"$target_dir:$shim_dir:\$PATH\""
|
|
216
|
+
if ! grep -Fqx "$marker" "$profile" 2>/dev/null; then
|
|
217
|
+
mkdir -p "$(dirname "$profile")"
|
|
218
|
+
printf '\n%s\n' "$marker" >> "$profile"
|
|
219
|
+
log "Added to shell profile: $profile"
|
|
220
|
+
fi
|
|
221
|
+
if ! grep -Fqx "$path_line" "$profile" 2>/dev/null; then
|
|
222
|
+
printf '%s\n' "$path_line" >> "$profile"
|
|
223
|
+
fi
|
|
224
|
+
|
|
225
|
+
if [ "$shim_installed" -eq 1 ]; then
|
|
226
|
+
log "The CLI is already on the current PATH; this terminal needs no PATH refresh"
|
|
227
|
+
elif [ "$is_sourced" -eq 1 ]; then
|
|
228
|
+
log "The current shell PATH was refreshed"
|
|
229
|
+
else
|
|
230
|
+
log "The current process PATH was refreshed; source \"$profile\" in the parent terminal"
|
|
231
|
+
fi
|
|
232
|
+
log "Verification command: command -v $source_name"
|