skvlt 0.9.9

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Xi Xu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,199 @@
1
+ # Skills Vault
2
+
3
+ **_[汉语](./README.zh.md)_**
4
+
5
+ [![npm version](https://img.shields.io/npm/v/skvlt)](https://www.npmjs.com/package/skvlt)
6
+ [![CI](https://img.shields.io/github/actions/workflow/status/xixu-me/skills-vault/ci.yml?branch=main&label=ci)](https://github.com/xixu-me/skills-vault/actions/workflows/ci.yml)
7
+ [![Bun](https://img.shields.io/badge/Bun-%3E%3D1.3.11-f9f1e1)](https://bun.sh/)
8
+ [![License](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)
9
+
10
+ Skills Vault is a CLI for backing up and restoring [Agent Skills](https://agentskills.io).
11
+
12
+ It is built for the common round-trip:
13
+
14
+ 1. snapshot what is installed today
15
+ 2. commit or move the manifest
16
+ 3. restore the same set of skill sources on another machine
17
+
18
+ > [!IMPORTANT]
19
+ > Bun-only runtime. Skills Vault is designed to be installed and run with [Bun](https://bun.com).
20
+
21
+ ## Why Skills Vault
22
+
23
+ Skills Vault exists to fill the gap described in [vercel-labs/skills#729](https://github.com/vercel-labs/skills/issues/729): a declarative manifest for portable, reproducible skill setups across machines and teams.
24
+
25
+ - Back up installed skills into a deterministic `skvlt.yaml` file.
26
+ - Restore from that manifest by source, by agent, or all at once.
27
+ - Preview installs before making changes with `--dry-run`.
28
+ - Check local setup quickly with `doctor`.
29
+ - Generate completion scripts for `bash`, `zsh`, and `powershell`.
30
+
31
+ ## Quick Start
32
+
33
+ Back up your current skills:
34
+
35
+ ```bash
36
+ bunx skvlt backup
37
+ ```
38
+
39
+ Preview what a restore would run:
40
+
41
+ ```bash
42
+ bunx skvlt restore --dry-run
43
+ ```
44
+
45
+ Restore everything recorded in the manifest:
46
+
47
+ ```bash
48
+ bunx skvlt restore --all
49
+ ```
50
+
51
+ If you want a curated, ready-to-use manifest, see [xixu-me/skvlt](https://github.com/xixu-me/skvlt), a maintained collection of `skvlt.yaml` snapshots.
52
+
53
+ The default manifest is `./skvlt.yaml`. A typical file looks like this:
54
+
55
+ ```yaml
56
+ total_sources: 2
57
+ total_skills: 3
58
+ scope: "global"
59
+
60
+ sources:
61
+ "alpha/source":
62
+ count: 1
63
+ skills:
64
+ - "beta"
65
+
66
+ "beta/source":
67
+ count: 2
68
+ skills:
69
+ - "alpha"
70
+ - "zulu"
71
+ ```
72
+
73
+ ## Commands
74
+
75
+ ### `backup`
76
+
77
+ Snapshot installed skills into `skvlt.yaml`.
78
+
79
+ ```bash
80
+ bunx skvlt backup
81
+ bunx skvlt backup --dry-run
82
+ bunx skvlt backup --output ./skvlt.yaml
83
+ bunx skvlt backup --project-scope --lock-file ./skills-lock.json
84
+ ```
85
+
86
+ `backup` reads installed skill names, joins them with lock-file metadata, and writes a grouped manifest keyed by source.
87
+
88
+ > [!NOTE]
89
+ > Global backup reads from `~/.agents/.skill-lock.json` by default. Project-scope backup currently requires `--lock-file`.
90
+
91
+ ### `restore`
92
+
93
+ Install skills from a manifest.
94
+
95
+ ```bash
96
+ bunx skvlt restore --all
97
+ bunx skvlt restore --only-source xixu-me/skills
98
+ bunx skvlt restore --project-scope
99
+ bunx skvlt restore --dry-run
100
+ ```
101
+
102
+ By default, restore respects the scope recorded in the manifest. Use `--project-scope` to force a project install even when the manifest was created from global state.
103
+
104
+ `--dry-run` prints the derived `bunx skills add ...` commands without running them. Live installs run in lock-safe mode and are serialized to avoid global lock-file races.
105
+
106
+ For a curated manifest source, you can start from [xixu-me/skvlt](https://github.com/xixu-me/skvlt) and restore from the `skvlt.yaml` maintained there.
107
+
108
+ ### `doctor`
109
+
110
+ Inspect the local Skills Vault environment and global skill state.
111
+
112
+ ```bash
113
+ bunx skvlt doctor
114
+ bunx skvlt doctor --manifest ./skvlt.yaml
115
+ ```
116
+
117
+ `doctor` checks:
118
+
119
+ - the Bun runtime
120
+ - `bunx skills --help`
121
+ - whether the manifest exists
122
+ - whether the global lock file and skills directory are present
123
+ - whether tracked and installed global skills still match
124
+
125
+ ### `completion`
126
+
127
+ Print shell completion scripts.
128
+
129
+ ```bash
130
+ bunx skvlt completion bash
131
+ bunx skvlt completion zsh
132
+ bunx skvlt completion powershell
133
+ ```
134
+
135
+ ## JSON Output
136
+
137
+ All top-level commands support `--json` for structured output:
138
+
139
+ ```bash
140
+ bunx skvlt --json doctor
141
+ bunx skvlt --json backup --dry-run
142
+ ```
143
+
144
+ Successful responses include `ok`, `command`, and `data`. Failures include `ok`, `command`, and a stable `error.code` plus message.
145
+
146
+ ## Local Development
147
+
148
+ Install dependencies:
149
+
150
+ ```bash
151
+ bun install --frozen-lockfile
152
+ ```
153
+
154
+ Useful commands:
155
+
156
+ ```bash
157
+ bun run ./src/cli.ts --help
158
+ bun run ./src/cli.ts doctor
159
+ bun run backup
160
+ bun run restore
161
+ bun run test
162
+ bun run check
163
+ ```
164
+
165
+ `bun run check` is the main verification gate. It runs formatting checks, the Bun test suite, and `npm pack --dry-run --json`.
166
+
167
+ If you change workflow files, also run:
168
+
169
+ ```bash
170
+ bunx prettier --check ".github/**/*.yml"
171
+ ```
172
+
173
+ ## Package And Release Notes
174
+
175
+ The npm package publishes the `skvlt` bin from `src/cli.ts` and intentionally ships the `src` directory as its runtime payload.
176
+
177
+ Before publishing, verify the tarball contents locally:
178
+
179
+ ```bash
180
+ npm pack --dry-run --json
181
+ ```
182
+
183
+ The release workflow uses trusted publishing. The publish step is:
184
+
185
+ ```bash
186
+ npm publish --access public
187
+ ```
188
+
189
+ ## Troubleshooting
190
+
191
+ - If restore reports a global state mismatch, inspect `~/.agents/.skill-lock.json` and `~/.agents/skills`.
192
+ - If environment checks fail, start with `bunx skvlt doctor`.
193
+ - If packaging checks fail, run `bun run check` and review the tarball output from `npm pack --dry-run --json`.
194
+
195
+ For contribution, support, and security policy details, see [`CONTRIBUTING.md`](./CONTRIBUTING.md), [`SUPPORT.md`](./SUPPORT.md), and [`SECURITY.md`](./SECURITY.md).
196
+
197
+ ## License
198
+
199
+ Licensed under MIT. See [`LICENSE`](./LICENSE).
package/README.zh.md ADDED
@@ -0,0 +1,199 @@
1
+ # Skills Vault
2
+
3
+ **_[English](./README.md)_**
4
+
5
+ [![npm version](https://img.shields.io/npm/v/skvlt)](https://www.npmjs.com/package/skvlt)
6
+ [![CI](https://img.shields.io/github/actions/workflow/status/xixu-me/skills-vault/ci.yml?branch=main&label=ci)](https://github.com/xixu-me/skills-vault/actions/workflows/ci.yml)
7
+ [![Bun](https://img.shields.io/badge/Bun-%3E%3D1.3.11-f9f1e1)](https://bun.sh/)
8
+ [![License](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)
9
+
10
+ Skills Vault 是一个用于备份和恢复 [Agent Skills](https://agentskills.io) 的 CLI。
11
+
12
+ 它主要服务于这样一个常见流程:
13
+
14
+ 1. 把当前机器上已安装的 skills 快照出来
15
+ 2. 提交或移动这个 manifest
16
+ 3. 在另一台机器上恢复同一组 skill source
17
+
18
+ > [!IMPORTANT]
19
+ > 仅支持 Bun 运行时。Skills Vault 设计上就是通过 [Bun](https://bun.com) 安装和运行的。
20
+
21
+ ## 为什么需要 Skills Vault
22
+
23
+ Skills Vault 的存在,是为了补上 [vercel-labs/skills#729](https://github.com/vercel-labs/skills/issues/729) 里提到的缺口:缺少一种声明式 manifest,来支持可移植、可复现的 skills 配置。
24
+
25
+ - 把已安装的 skills 备份为确定性的 `skvlt.yaml`
26
+ - 按 source、按 agent,或者一次性从 manifest 恢复
27
+ - 通过 `--dry-run` 在真正改动前先预览
28
+ - 用 `doctor` 快速检查本地环境
29
+ - 为 `bash`、`zsh` 和 `powershell` 生成补全脚本
30
+
31
+ ## 快速开始
32
+
33
+ 备份当前已安装的 skills:
34
+
35
+ ```bash
36
+ bunx skvlt backup
37
+ ```
38
+
39
+ 预览一次 restore 将会执行什么:
40
+
41
+ ```bash
42
+ bunx skvlt restore --dry-run
43
+ ```
44
+
45
+ 恢复 manifest 中记录的全部内容:
46
+
47
+ ```bash
48
+ bunx skvlt restore --all
49
+ ```
50
+
51
+ 如果你想直接使用一个精选好的 manifest,可以查看 [xixu-me/skvlt](https://github.com/xixu-me/skvlt),这是一个持续维护的 `skvlt.yaml` 集合。
52
+
53
+ 默认 manifest 路径是 `./skvlt.yaml`。一个典型文件如下:
54
+
55
+ ```yaml
56
+ total_sources: 2
57
+ total_skills: 3
58
+ scope: "global"
59
+
60
+ sources:
61
+ "alpha/source":
62
+ count: 1
63
+ skills:
64
+ - "beta"
65
+
66
+ "beta/source":
67
+ count: 2
68
+ skills:
69
+ - "alpha"
70
+ - "zulu"
71
+ ```
72
+
73
+ ## 命令
74
+
75
+ ### `backup`
76
+
77
+ 把已安装的 skills 快照到 `skvlt.yaml`。
78
+
79
+ ```bash
80
+ bunx skvlt backup
81
+ bunx skvlt backup --dry-run
82
+ bunx skvlt backup --output ./skvlt.yaml
83
+ bunx skvlt backup --project-scope --lock-file ./skills-lock.json
84
+ ```
85
+
86
+ `backup` 会先读取已安装的 skill 名称,再结合 lock file 元数据,最终按 source 分组写出 manifest。
87
+
88
+ > [!NOTE]
89
+ > 全局备份默认读取 `~/.agents/.skill-lock.json`。项目级备份目前仍然需要显式传入 `--lock-file`。
90
+
91
+ ### `restore`
92
+
93
+ 从 manifest 安装 skills。
94
+
95
+ ```bash
96
+ bunx skvlt restore --all
97
+ bunx skvlt restore --only-source xixu-me/skills
98
+ bunx skvlt restore --project-scope
99
+ bunx skvlt restore --dry-run
100
+ ```
101
+
102
+ 默认情况下,`restore` 会遵循 manifest 中记录的 scope。如果希望即使 manifest 来自全局状态,也强制恢复到项目作用域,可以使用 `--project-scope`。
103
+
104
+ `--dry-run` 会打印推导出的 `bunx skills add ...` 命令,但不会真正执行。实际安装时会采用 lock-safe 模式串行执行,以避免全局 lock file 竞争。
105
+
106
+ 如果你想从一个精选 manifest 起步,也可以直接使用 [xixu-me/skvlt](https://github.com/xixu-me/skvlt) 中维护的 `skvlt.yaml`。
107
+
108
+ ### `doctor`
109
+
110
+ 检查本地 Skills Vault 环境和全局 skill 状态。
111
+
112
+ ```bash
113
+ bunx skvlt doctor
114
+ bunx skvlt doctor --manifest ./skvlt.yaml
115
+ ```
116
+
117
+ `doctor` 会检查:
118
+
119
+ - Bun 运行时
120
+ - `bunx skills --help`
121
+ - manifest 是否存在
122
+ - 全局 lock file 和 skills 目录是否存在
123
+ - lock file 中追踪的技能与实际安装状态是否一致
124
+
125
+ ### `completion`
126
+
127
+ 输出 shell 补全脚本。
128
+
129
+ ```bash
130
+ bunx skvlt completion bash
131
+ bunx skvlt completion zsh
132
+ bunx skvlt completion powershell
133
+ ```
134
+
135
+ ## JSON 输出
136
+
137
+ 所有顶层命令都支持 `--json` 结构化输出:
138
+
139
+ ```bash
140
+ bunx skvlt --json doctor
141
+ bunx skvlt --json backup --dry-run
142
+ ```
143
+
144
+ 成功时会返回 `ok`、`command` 和 `data`。失败时会返回 `ok`、`command`,以及稳定的 `error.code` 和错误消息。
145
+
146
+ ## 本地开发
147
+
148
+ 安装依赖:
149
+
150
+ ```bash
151
+ bun install --frozen-lockfile
152
+ ```
153
+
154
+ 常用命令:
155
+
156
+ ```bash
157
+ bun run ./src/cli.ts --help
158
+ bun run ./src/cli.ts doctor
159
+ bun run backup
160
+ bun run restore
161
+ bun run test
162
+ bun run check
163
+ ```
164
+
165
+ `bun run check` 是主要的发布前校验入口。它会运行格式检查、完整的 Bun 测试,以及 `npm pack --dry-run --json`。
166
+
167
+ 如果你修改了 workflow 文件,也请额外运行:
168
+
169
+ ```bash
170
+ bunx prettier --check ".github/**/*.yml"
171
+ ```
172
+
173
+ ## 打包与发布说明
174
+
175
+ npm 包会把 `src/cli.ts` 作为 `skvlt` 可执行入口,并且有意只将 `src` 目录作为运行时载荷发布。
176
+
177
+ 发布前,可以先在本地检查 tarball 内容:
178
+
179
+ ```bash
180
+ npm pack --dry-run --json
181
+ ```
182
+
183
+ Release workflow 使用 trusted publishing。实际发布步骤为:
184
+
185
+ ```bash
186
+ npm publish --access public
187
+ ```
188
+
189
+ ## 故障排查
190
+
191
+ - 如果 restore 报告全局状态不一致,请检查 `~/.agents/.skill-lock.json` 和 `~/.agents/skills`
192
+ - 如果环境检查失败,先运行 `bunx skvlt doctor`
193
+ - 如果打包检查失败,运行 `bun run check`,并检查 `npm pack --dry-run --json` 的输出
194
+
195
+ 关于贡献、支持和安全策略,请参阅 [`CONTRIBUTING.md`](./CONTRIBUTING.md)、[`SUPPORT.md`](./SUPPORT.md) 和 [`SECURITY.md`](./SECURITY.md)。
196
+
197
+ ## 许可证
198
+
199
+ 基于 MIT 许可证发布。详见 [`LICENSE`](./LICENSE)。
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "skvlt",
3
+ "version": "0.9.9",
4
+ "description": "The CLI for backing up and restoring Agent Skills",
5
+ "author": "Xi Xu",
6
+ "bin": {
7
+ "skvlt": "src/cli.ts"
8
+ },
9
+ "license": "MIT",
10
+ "keywords": [
11
+ "cli",
12
+ "skills",
13
+ "agents",
14
+ "backup",
15
+ "restore",
16
+ "bun"
17
+ ],
18
+ "homepage": "https://github.com/xixu-me/skills-vault#readme",
19
+ "bugs": {
20
+ "url": "https://github.com/xixu-me/skills-vault/issues"
21
+ },
22
+ "funding": {
23
+ "url": "https://xi-xu.me/#sponsorships"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/xixu-me/skills-vault.git"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "engines": {
33
+ "bun": ">=1.3.11"
34
+ },
35
+ "packageManager": "bun@1.3.11",
36
+ "private": false,
37
+ "files": [
38
+ "src"
39
+ ],
40
+ "scripts": {
41
+ "backup": "bun run ./src/cli.ts backup",
42
+ "backup:dry-run": "bun run ./src/cli.ts backup --dry-run",
43
+ "check": "bun run format:check && bun test && npm pack --dry-run --json",
44
+ "format": "prettier --write \"package.json\" \"src/**/*.ts\" \"test/**/*.ts\"",
45
+ "format:check": "prettier --check \"package.json\" \"src/**/*.ts\" \"test/**/*.ts\"",
46
+ "publish:check": "bun run check",
47
+ "prepublishOnly": "bun run publish:check",
48
+ "restore": "bun run ./src/cli.ts restore",
49
+ "restore:dry-run": "bun run ./src/cli.ts restore --dry-run",
50
+ "test": "bun test"
51
+ },
52
+ "devDependencies": {
53
+ "prettier": "^3.8.1"
54
+ }
55
+ }
package/src/cli.ts ADDED
@@ -0,0 +1,211 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import packageJson from "../package.json" with { type: "json" };
4
+ import { runBackup } from "./commands/backup";
5
+ import { runCompletion } from "./commands/completion";
6
+ import { runDoctor } from "./commands/doctor";
7
+ import { runRestore } from "./commands/restore";
8
+ import {
9
+ bold,
10
+ dimGray,
11
+ textGray,
12
+ helpFooter,
13
+ helpExample,
14
+ helpHeading,
15
+ page,
16
+ stripAnsi,
17
+ } from "./internal/cli/theme";
18
+
19
+ type CliResult = {
20
+ exitCode: number;
21
+ stdout: string;
22
+ stderr: string;
23
+ errorCode?: string;
24
+ payload?: unknown;
25
+ };
26
+
27
+ type RunCliOptions = {
28
+ reportProgress?: (chunk: string) => void;
29
+ streamOutput?: boolean;
30
+ };
31
+
32
+ function printHelp(): string {
33
+ return `\n${[
34
+ "The CLI for backing up and restoring Agent Skills",
35
+ "",
36
+ helpHeading("Usage"),
37
+ " bunx skvlt <command> [options]",
38
+ "",
39
+ helpHeading("Commands"),
40
+ " backup Backup installed skills into a manifest",
41
+ " completion Print shell completion scripts",
42
+ " doctor Inspect the local environment and skill state",
43
+ " restore Restore skills from a manifest",
44
+ "",
45
+ helpHeading("Global Options"),
46
+ " -h, --help Show top-level help",
47
+ " -j, --json Print structured JSON output",
48
+ " -v, --version Print the installed package version",
49
+ "",
50
+ helpHeading("Examples"),
51
+ helpExample("bunx skvlt backup --output ./skvlt.yaml"),
52
+ helpExample("bunx skvlt completion bash"),
53
+ helpExample("bunx skvlt doctor"),
54
+ helpExample("bunx skvlt restore --all"),
55
+ helpExample("bunx skvlt restore --only-source xixu-me/skills"),
56
+ helpFooter("https://github.com/xixu-me/skills-vault"),
57
+ ].join("\n")}`;
58
+ }
59
+
60
+ function landingCommand(command: string, description: string): string {
61
+ return ` ${dimGray("$")} ${textGray(command.padEnd(28))} ${dimGray(description)}`;
62
+ }
63
+
64
+ function printLanding(): string {
65
+ return `\n${[
66
+ dimGray("The CLI for backing up and restoring Agent Skills"),
67
+ "",
68
+ landingCommand("bunx skvlt backup", "Backup installed skills"),
69
+ landingCommand("bunx skvlt restore", "Restore from skvlt.yaml"),
70
+ landingCommand("bunx skvlt doctor", "Inspect local setup"),
71
+ landingCommand("bunx skvlt completion", "Print shell completions"),
72
+ "",
73
+ `${dimGray("Explore the open-source repo at")} ${textGray("https://github.com/xixu-me/skills-vault")}\n`,
74
+ ].join("\n")}`;
75
+ }
76
+
77
+ function extractGlobalFlags(argv: string[]) {
78
+ const positional: string[] = [];
79
+ let json = false;
80
+
81
+ for (const arg of argv) {
82
+ if (arg === "--json" || arg === "-j") {
83
+ json = true;
84
+ continue;
85
+ }
86
+
87
+ positional.push(arg);
88
+ }
89
+
90
+ return { argv: positional, json };
91
+ }
92
+
93
+ function toJsonResult(
94
+ command: string,
95
+ result: CliResult,
96
+ fallbackData?: unknown,
97
+ ): CliResult {
98
+ const body =
99
+ result.exitCode === 0
100
+ ? {
101
+ ok: true,
102
+ command,
103
+ data: result.payload ?? fallbackData ?? null,
104
+ }
105
+ : {
106
+ ok: false,
107
+ command,
108
+ error: {
109
+ code: result.errorCode ?? "CLI_ERROR",
110
+ message: stripAnsi(result.stderr || result.stdout).trim(),
111
+ },
112
+ };
113
+
114
+ return {
115
+ ...result,
116
+ stdout: `${JSON.stringify(body, null, 2)}\n`,
117
+ stderr: "",
118
+ };
119
+ }
120
+
121
+ /**
122
+ * Dispatches the top-level CLI command and normalizes text or JSON output.
123
+ */
124
+ export async function runCli(
125
+ argv: string[],
126
+ options: RunCliOptions = {},
127
+ ): Promise<CliResult> {
128
+ const extracted = extractGlobalFlags(argv);
129
+ const [command] = extracted.argv;
130
+ if (!command) {
131
+ const result: CliResult = {
132
+ exitCode: 0,
133
+ stdout: `${printLanding()}\n`,
134
+ stderr: "",
135
+ payload: { text: stripAnsi(printLanding()) },
136
+ };
137
+ return extracted.json ? toJsonResult("landing", result) : result;
138
+ }
139
+ if (command === "--help" || command === "-h") {
140
+ const result: CliResult = { exitCode: 0, stdout: printHelp(), stderr: "" };
141
+ return extracted.json
142
+ ? toJsonResult("help", result, { text: printHelp().trimEnd() })
143
+ : result;
144
+ }
145
+ if (command === "--version" || command === "-v") {
146
+ const result: CliResult = {
147
+ exitCode: 0,
148
+ stdout: `${packageJson.version}\n`,
149
+ stderr: "",
150
+ payload: { version: packageJson.version },
151
+ };
152
+ return extracted.json ? toJsonResult("version", result) : result;
153
+ }
154
+ if (command === "backup") {
155
+ const result = await runBackup(extracted.argv.slice(1), {
156
+ reportProgress: extracted.json ? undefined : options.reportProgress,
157
+ streamOutput: extracted.json ? false : options.streamOutput,
158
+ });
159
+ return extracted.json ? toJsonResult("backup", result) : result;
160
+ }
161
+ if (command === "doctor") {
162
+ const result = await runDoctor(extracted.argv.slice(1));
163
+ return extracted.json ? toJsonResult("doctor", result) : result;
164
+ }
165
+ if (command === "completion") {
166
+ const result = await runCompletion(extracted.argv.slice(1));
167
+ return extracted.json ? toJsonResult("completion", result) : result;
168
+ }
169
+ if (command === "restore") {
170
+ const result = await runRestore(extracted.argv.slice(1), {
171
+ reportProgress: extracted.json ? undefined : options.reportProgress,
172
+ streamOutput: extracted.json ? false : options.streamOutput,
173
+ });
174
+ return extracted.json ? toJsonResult("restore", result) : result;
175
+ }
176
+ const result: CliResult = {
177
+ exitCode: 1,
178
+ stdout: "",
179
+ stderr: page(
180
+ `Unknown command: ${command}\nRun ${bold("bunx skvlt --help")} for usage.`,
181
+ ),
182
+ errorCode: "UNKNOWN_COMMAND",
183
+ };
184
+ return extracted.json ? toJsonResult(command, result) : result;
185
+ }
186
+
187
+ /**
188
+ * Executes the CLI entrypoint and writes buffered output to the process streams.
189
+ */
190
+ export async function main(
191
+ argv: string[] = process.argv.slice(2),
192
+ ): Promise<number> {
193
+ const result = await runCli(argv, {
194
+ reportProgress: (chunk) => {
195
+ process.stdout.write(chunk);
196
+ },
197
+ streamOutput: true,
198
+ });
199
+ if (result.stdout) {
200
+ process.stdout.write(result.stdout);
201
+ }
202
+ if (result.stderr) {
203
+ console.error(result.stderr.trimEnd());
204
+ }
205
+ return result.exitCode;
206
+ }
207
+
208
+ if (import.meta.main) {
209
+ const exitCode = await main();
210
+ process.exit(exitCode);
211
+ }