@kevlns/v-cli 0.2.0-beta.1 → 0.2.0-beta.2
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/AGENTS.md +3 -1
- package/README.md +28 -3
- package/dist/cli.mjs +442 -24
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -7,10 +7,12 @@
|
|
|
7
7
|
|
|
8
8
|
## 核心约定(v-cli 本体)
|
|
9
9
|
|
|
10
|
-
- 环境要求 Node.js >= 20;v-cli 版本 @kevlns/v-cli@0.2.0-beta.
|
|
10
|
+
- 环境要求 Node.js >= 20;v-cli 版本 @kevlns/v-cli@0.2.0-beta.2
|
|
11
11
|
- 命令分三类:builtin(内置)、local(~/.v-cli/commands/ 下的本地插件)、official(官方插件白名单);
|
|
12
12
|
**最新、live 的命令集合以实际发现为准**:先运行 `v-cli agent index --json` 获取全部命令与 agent 元数据
|
|
13
13
|
- 单个命令的完整元数据用 `v-cli agent describe <命令名> --json` 查看
|
|
14
|
+
- AI Agent 引导文档:`v-cli agent docs` 输出本文件原文(`--json` 含 sha256/content);
|
|
15
|
+
`v-cli agent init .` 把它写入工作区(已存在默认拒绝,`--force` 覆盖,`--dry-run` 预览;符号链接目标 fail-closed)
|
|
14
16
|
- 官方插件命令(`v-cli xlmerge …`、`v-cli unity …`)在子进程中运行(stdio 继承):v-cli 只做路由,
|
|
15
17
|
不解析、不改写插件的 stdout/stderr;插件 `--help`/`--json` 等参数由插件自己消费
|
|
16
18
|
- 插件对 worktree 的写入/提交行为以插件清单 v-cli.plugin.json 的 `agent.safety` 为准:
|
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ v-cli 让你**用一个命令沉淀所有个人小工具**,而不用为每个
|
|
|
26
26
|
- **官方插件白名单** - `@kevlns/xlmerge`(`xlmerge`)与 `@kevlns/u-cli-mod`(`unity`)是唯一被路由的官方插件,安装后在子进程中运行
|
|
27
27
|
- **容错加载** - 单个插件语法错误、契约不符或注册异常只会被跳过并报告,绝不阻断其他命令
|
|
28
28
|
- **双通道输出** - 结果走 stdout(可管道、可脚本化),诊断走 stderr
|
|
29
|
-
- **agent 友好** - `agent index/describe` 输出统一索引与完整元数据;仓库内 AGENTS.md 自动生成并有漂移检查
|
|
29
|
+
- **agent 友好** - `agent docs`/`agent init` 让 AI Agent 自举读取引导文档;`agent index/describe` 输出统一索引与完整元数据;仓库内 AGENTS.md 自动生成并有漂移检查
|
|
30
30
|
- **TypeScript-first** - 严格类型编写,tsup 将核心逻辑打包为单文件 ESM,仅保留 `commander` 运行依赖
|
|
31
31
|
|
|
32
32
|
## Getting started
|
|
@@ -51,10 +51,33 @@ npm install -g git+https://github.com/kevlns/v-cli.git
|
|
|
51
51
|
v-cli doctor # 环境体检:node/版本、主目录、配置、官方/本地插件状态
|
|
52
52
|
v-cli plugin list # 列出内置命令、本地插件与官方插件状态
|
|
53
53
|
v-cli ts 1710000000 # 时间戳互转
|
|
54
|
+
v-cli agent docs # 输出当前安装包内置 AGENTS.md 原文(AI Agent 引导文档)
|
|
54
55
|
v-cli agent index # 命令 + agent 元数据索引(--json 输出机器可读)
|
|
55
56
|
v-cli agent describe xlmerge --json
|
|
57
|
+
v-cli agent init . # (可选)把 AGENTS.md 初始化到当前目录
|
|
56
58
|
```
|
|
57
59
|
|
|
60
|
+
### AI Agent 快速开始
|
|
61
|
+
|
|
62
|
+
v-cli 内置 AGENTS.md 随包发布,AI Agent 可自行发现并读取引导文档,无需人工粘贴:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
v-cli agent docs # 读当前包内置 AGENTS.md 原文(--json 拿 package/version/sha256/content)
|
|
66
|
+
v-cli agent index --json # 枚举全部命令 + 元数据(builtin/local/official,live 发现)
|
|
67
|
+
v-cli agent describe <name> --json # 单命令:用法/参数/选项/输出/退出码/安全标签
|
|
68
|
+
v-cli agent init . # (可选)把 AGENTS.md 写入工作区,AI Agent 自动读取
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`agent docs` 文本模式逐字节输出内置 AGENTS.md,`--json` 输出稳定对象
|
|
72
|
+
`{ package, version, sha256, content }`。
|
|
73
|
+
|
|
74
|
+
`agent init [directory]`(默认当前目录;目录必须已存在且为目录):
|
|
75
|
+
|
|
76
|
+
- 已存在 AGENTS.md 时**默认拒绝并退出 1,绝不改动现有文件**(`--force` 才原子覆盖);
|
|
77
|
+
- `--dry-run` 只报告目标与将执行的动作,不写入任何文件;
|
|
78
|
+
- 符号链接目标一律 fail-closed 拒绝(不跟随、不覆盖链接目标);
|
|
79
|
+
- `--json` 输出稳定结果(`ok/dryRun/action/directory/target/sha256/bytes/…`)。
|
|
80
|
+
|
|
58
81
|
### 控制器命令(官方插件)
|
|
59
82
|
|
|
60
83
|
```bash
|
|
@@ -106,7 +129,7 @@ v-cli --json ts 1710000000 | jq .seconds # 前置全局 --json 同样生效
|
|
|
106
129
|
## `--json` 语义(v-cli 0.2)
|
|
107
130
|
|
|
108
131
|
- **前置全局**:`v-cli --json <cmd> …` —— `--json` 出现在首个命令词之前时被 v-cli 消费,`ctx.json` 为真
|
|
109
|
-
- **命令自有**:`<cmd> --json …` —— 属于该命令:内置命令(`ts`、`doctor`、`plugin list`、`agent index`、`agent describe`)各自声明 `--json` 并消费;官方插件命令则**原样转发**给插件
|
|
132
|
+
- **命令自有**:`<cmd> --json …` —— 属于该命令:内置命令(`ts`、`doctor`、`plugin list`、`agent index`、`agent describe`、`agent docs`、`agent init`)各自声明 `--json` 并消费;官方插件命令则**原样转发**给插件
|
|
110
133
|
- 其他中间位置(如 `v-cli plugin --json list`)不承诺 JSON 输出
|
|
111
134
|
- 插件转发示例:`v-cli xlmerge detect --json` 会把 `--json` 转给 xlmerge;`v-cli --json xlmerge detect` 则消费掉全局 `--json`、只转发 `detect`
|
|
112
135
|
|
|
@@ -122,6 +145,8 @@ v-cli --json ts 1710000000 | jq .seconds # 前置全局 --json 同样生效
|
|
|
122
145
|
| `v-cli ts [value]` | 无参=当前时间;数字(秒/毫秒自动识别)=转可读时间;日期串=转时间戳 |
|
|
123
146
|
| `v-cli agent index [--json]` | 全部命令的 agent 索引(builtin/local/official,含元数据状态) |
|
|
124
147
|
| `v-cli agent describe <name> [--json]` | 单个命令的完整记录;未找到时 stderr 报错并退出 1 |
|
|
148
|
+
| `v-cli agent docs [--json]` | 输出当前包内置 AGENTS.md 原文;`--json` 输出 `{ package, version, sha256, content }`;缺失时退出 1 |
|
|
149
|
+
| `v-cli agent init [directory] [--force] [--dry-run] [--json]` | 把内置 AGENTS.md 写入目录(默认 cwd);已存在默认拒绝退出 1,`--force` 原子覆盖,`--dry-run` 只报告 |
|
|
125
150
|
|
|
126
151
|
### 插件契约 `CliCommand`(apiVersion 1)
|
|
127
152
|
|
|
@@ -191,7 +216,7 @@ kevlns 工具家族共享同一套发布约定(tag 驱动、CI 护栏、MIT)
|
|
|
191
216
|
|
|
192
217
|
| Package | Purpose | Status |
|
|
193
218
|
| --- | --- | --- |
|
|
194
|
-
| [`v-cli`](https://github.com/kevlns/v-cli) | 个人工具箱 CLI(本仓库) | v0.2.0-beta.
|
|
219
|
+
| [`v-cli`](https://github.com/kevlns/v-cli) | 个人工具箱 CLI(本仓库) | v0.2.0-beta.2 |
|
|
195
220
|
| [`xlmerge`](https://github.com/kevlns/xlmerge) | Git 中 .xlsx/.xlsm 冲突可视化解决工具 | v1.2.1-beta.2 |
|
|
196
221
|
| [`u-cli-mod`](https://github.com/kevlns/u-cli-mod) | Unity 精确版本路由 + CLI + pipeline 包(Windows-first) | v0.1.0-beta.2 |
|
|
197
222
|
|
package/dist/cli.mjs
CHANGED
|
@@ -75,8 +75,8 @@ function defaultHomeDir() {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
// src/core/loader.ts
|
|
78
|
-
import
|
|
79
|
-
import
|
|
78
|
+
import fs5 from "fs";
|
|
79
|
+
import path7 from "path";
|
|
80
80
|
import { pathToFileURL } from "url";
|
|
81
81
|
|
|
82
82
|
// src/core/official.ts
|
|
@@ -554,6 +554,27 @@ function validateAgentMeta(agent2, errors) {
|
|
|
554
554
|
if (c.usage !== void 0 && typeof c.usage !== "string") {
|
|
555
555
|
errors.push(`${at}.usage \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);
|
|
556
556
|
}
|
|
557
|
+
if (c.arguments !== void 0) {
|
|
558
|
+
const bad = !Array.isArray(c.arguments) || c.arguments.some(
|
|
559
|
+
(a) => !isPlainObject3(a) || typeof a.name !== "string" || typeof a.required !== "boolean" || typeof a.description !== "string"
|
|
560
|
+
);
|
|
561
|
+
if (bad) errors.push(`${at}.arguments \u5FC5\u987B\u662F { name: string; required: boolean; description: string }[]`);
|
|
562
|
+
}
|
|
563
|
+
if (c.options !== void 0) {
|
|
564
|
+
const bad = !Array.isArray(c.options) || c.options.some((o) => !isPlainObject3(o) || typeof o.flags !== "string" || typeof o.description !== "string");
|
|
565
|
+
if (bad) errors.push(`${at}.options \u5FC5\u987B\u662F { flags: string; description: string }[]`);
|
|
566
|
+
}
|
|
567
|
+
if (c.output !== void 0) {
|
|
568
|
+
const bad = !isPlainObject3(c.output) || typeof c.output.format !== "string" || typeof c.output.description !== "string";
|
|
569
|
+
if (bad) errors.push(`${at}.output \u5FC5\u987B\u662F { format: string; description: string }`);
|
|
570
|
+
}
|
|
571
|
+
if (c.exitCodes !== void 0) {
|
|
572
|
+
const bad = !isPlainObject3(c.exitCodes) || Object.entries(c.exitCodes).some(([code, desc]) => typeof code !== "string" || typeof desc !== "string");
|
|
573
|
+
if (bad) errors.push(`${at}.exitCodes \u5FC5\u987B\u662F { [\u9000\u51FA\u7801: string]: string }`);
|
|
574
|
+
}
|
|
575
|
+
if (c.safety !== void 0 && !isStringArray2(c.safety)) {
|
|
576
|
+
errors.push(`${at}.safety \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4`);
|
|
577
|
+
}
|
|
557
578
|
});
|
|
558
579
|
}
|
|
559
580
|
}
|
|
@@ -596,6 +617,193 @@ function validateLocalCommand(candidate, options = {}) {
|
|
|
596
617
|
return { ok: true, command: candidate, errors: [] };
|
|
597
618
|
}
|
|
598
619
|
|
|
620
|
+
// src/commands/agent.ts
|
|
621
|
+
import path5 from "path";
|
|
622
|
+
|
|
623
|
+
// src/core/agent-docs.ts
|
|
624
|
+
import fs3 from "fs";
|
|
625
|
+
import path4 from "path";
|
|
626
|
+
import { createHash, randomBytes } from "crypto";
|
|
627
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
628
|
+
|
|
629
|
+
// src/version.ts
|
|
630
|
+
var VERSION = "0.2.0-beta.2";
|
|
631
|
+
|
|
632
|
+
// src/core/agent-docs.ts
|
|
633
|
+
var BUNDLED_DOCS_FILE = "AGENTS.md";
|
|
634
|
+
var BUNDLED_DOCS_PACKAGE = "@kevlns/v-cli";
|
|
635
|
+
function bundledCandidatePaths(moduleFile) {
|
|
636
|
+
const candidates = [];
|
|
637
|
+
const push = (p) => {
|
|
638
|
+
if (!candidates.includes(p)) candidates.push(p);
|
|
639
|
+
};
|
|
640
|
+
if (path4.basename(path4.dirname(moduleFile)) === "dist") {
|
|
641
|
+
push(path4.join(path4.dirname(path4.dirname(moduleFile)), BUNDLED_DOCS_FILE));
|
|
642
|
+
}
|
|
643
|
+
let dir = path4.dirname(moduleFile);
|
|
644
|
+
for (; ; ) {
|
|
645
|
+
if (pkgName(path4.join(dir, "package.json")) === BUNDLED_DOCS_PACKAGE) {
|
|
646
|
+
push(path4.join(dir, BUNDLED_DOCS_FILE));
|
|
647
|
+
break;
|
|
648
|
+
}
|
|
649
|
+
const nestedPkg = path4.join(dir, "node_modules", "@kevlns", "v-cli", "package.json");
|
|
650
|
+
if (pkgName(nestedPkg) === BUNDLED_DOCS_PACKAGE) {
|
|
651
|
+
push(path4.join(dir, "node_modules", "@kevlns", "v-cli", BUNDLED_DOCS_FILE));
|
|
652
|
+
break;
|
|
653
|
+
}
|
|
654
|
+
const parent = path4.dirname(dir);
|
|
655
|
+
if (parent === dir) break;
|
|
656
|
+
dir = parent;
|
|
657
|
+
}
|
|
658
|
+
return candidates;
|
|
659
|
+
}
|
|
660
|
+
function pkgName(pkgJsonPath) {
|
|
661
|
+
try {
|
|
662
|
+
const pkg = JSON.parse(fs3.readFileSync(pkgJsonPath, "utf-8"));
|
|
663
|
+
return typeof pkg.name === "string" ? pkg.name : void 0;
|
|
664
|
+
} catch {
|
|
665
|
+
return void 0;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
function resolveBundledAgentsMd(opts = {}) {
|
|
669
|
+
const moduleFile = opts.base ?? fileURLToPath2(import.meta.url);
|
|
670
|
+
for (const candidate of bundledCandidatePaths(moduleFile)) {
|
|
671
|
+
try {
|
|
672
|
+
if (fs3.lstatSync(candidate).isFile()) return candidate;
|
|
673
|
+
} catch {
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
return void 0;
|
|
677
|
+
}
|
|
678
|
+
function readBundledAgentsMd(opts = {}) {
|
|
679
|
+
const file = resolveBundledAgentsMd(opts);
|
|
680
|
+
if (!file) {
|
|
681
|
+
const tried = bundledCandidatePaths(opts.base ?? fileURLToPath2(import.meta.url));
|
|
682
|
+
const lastTried = tried.length > 0 ? tried[tried.length - 1] : "\uFF08\u65E0\u5019\u9009\u4F4D\u7F6E\uFF09";
|
|
683
|
+
throw new Error(
|
|
684
|
+
`\u65E0\u6CD5\u5B9A\u4F4D ${BUNDLED_DOCS_PACKAGE} \u5185\u7F6E ${BUNDLED_DOCS_FILE}\uFF1A\u5DF2\u68C0\u67E5 ${tried.length} \u4E2A\u5019\u9009\u4F4D\u7F6E\u5747\u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u8BFB\uFF08\u6700\u540E\u68C0\u67E5: ${lastTried}\uFF09\u3002\u8BF7\u786E\u8BA4\u5B89\u88C5\u7684\u5305\u5185\u5305\u542B AGENTS.md\uFF08\u91CD\u65B0\u5B89\u88C5 @kevlns/v-cli \u540E\u91CD\u8BD5\uFF09\u3002`
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
let content;
|
|
688
|
+
try {
|
|
689
|
+
content = fs3.readFileSync(file, "utf-8");
|
|
690
|
+
} catch (err) {
|
|
691
|
+
throw new Error(
|
|
692
|
+
`\u65E0\u6CD5\u8BFB\u53D6 ${BUNDLED_DOCS_PACKAGE} \u5185\u7F6E ${BUNDLED_DOCS_FILE}\uFF08${file}\uFF09: ${err instanceof Error ? err.message : String(err)}`
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
return {
|
|
696
|
+
file,
|
|
697
|
+
content,
|
|
698
|
+
sha256: sha256Hex(content),
|
|
699
|
+
bytes: Buffer.byteLength(content, "utf-8")
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
function sha256Hex(content) {
|
|
703
|
+
return createHash("sha256").update(content, "utf-8").digest("hex");
|
|
704
|
+
}
|
|
705
|
+
function performAgentInit(opts) {
|
|
706
|
+
const { directory, docs, force = false, dryRun = false, explicitDirectory = false } = opts;
|
|
707
|
+
const target = path4.join(directory, BUNDLED_DOCS_FILE);
|
|
708
|
+
const base = {
|
|
709
|
+
ok: false,
|
|
710
|
+
dryRun,
|
|
711
|
+
action: "refused",
|
|
712
|
+
directory,
|
|
713
|
+
target,
|
|
714
|
+
package: BUNDLED_DOCS_PACKAGE,
|
|
715
|
+
version: VERSION,
|
|
716
|
+
sha256: docs.sha256,
|
|
717
|
+
bytes: docs.bytes
|
|
718
|
+
};
|
|
719
|
+
const refuse = (reason) => ({ ...base, ok: false, action: "refused", reason });
|
|
720
|
+
let dirStat;
|
|
721
|
+
try {
|
|
722
|
+
dirStat = fs3.statSync(directory);
|
|
723
|
+
} catch {
|
|
724
|
+
return refuse(`\u76EE\u6807\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u8BBF\u95EE: ${directory}`);
|
|
725
|
+
}
|
|
726
|
+
if (!dirStat.isDirectory()) {
|
|
727
|
+
return refuse(`\u76EE\u6807\u4E0D\u662F\u76EE\u5F55: ${directory}`);
|
|
728
|
+
}
|
|
729
|
+
if (explicitDirectory) {
|
|
730
|
+
let dirLstat;
|
|
731
|
+
try {
|
|
732
|
+
dirLstat = fs3.lstatSync(directory);
|
|
733
|
+
} catch {
|
|
734
|
+
}
|
|
735
|
+
if (dirLstat && dirLstat.isSymbolicLink()) {
|
|
736
|
+
return refuse(
|
|
737
|
+
`\u62D2\u7EDD\u5199\u5165\uFF1A\u76EE\u6807\u76EE\u5F55 ${directory} \u662F\u7B26\u53F7\u94FE\u63A5/\u8054\u63A5\u76EE\u5F55\uFF08fail-closed\uFF0C\u4E0D\u8DDF\u968F\uFF09\u3002\u8BF7\u4F20\u5165\u771F\u5B9E\u76EE\u5F55\u8DEF\u5F84\uFF0C\u6216\u7701\u7565\u53C2\u6570\u8BA9 v-cli \u4F7F\u7528\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55`
|
|
738
|
+
);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
let targetStat;
|
|
742
|
+
try {
|
|
743
|
+
targetStat = fs3.lstatSync(target);
|
|
744
|
+
} catch {
|
|
745
|
+
targetStat = void 0;
|
|
746
|
+
}
|
|
747
|
+
if (targetStat) {
|
|
748
|
+
if (targetStat.isSymbolicLink()) {
|
|
749
|
+
return refuse(
|
|
750
|
+
`\u62D2\u7EDD\u5199\u5165 ${target}\uFF1A\u76EE\u6807\u662F\u7B26\u53F7\u94FE\u63A5\uFF08fail-closed\uFF0C\u4E0D\u8DDF\u968F\u3001\u4E0D\u8986\u76D6\u94FE\u63A5\u76EE\u6807\uFF09\u3002\u8BF7\u5148\u79FB\u9664\u94FE\u63A5\u6216\u9009\u62E9\u5176\u4ED6\u76EE\u5F55`
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
if (targetStat.isDirectory()) {
|
|
754
|
+
return refuse(`\u62D2\u7EDD\u5199\u5165 ${target}\uFF1A\u76EE\u6807\u662F\u4E00\u4E2A\u76EE\u5F55\uFF08\u65E0\u6CD5\u4EE5\u6587\u4EF6\u8986\u76D6\uFF09`);
|
|
755
|
+
}
|
|
756
|
+
if (!force) {
|
|
757
|
+
return refuse(
|
|
758
|
+
`${target} \u5DF2\u5B58\u5728\uFF0C\u9ED8\u8BA4\u62D2\u7EDD\u8986\u76D6\uFF08\u4E0D\u505A\u4EFB\u4F55\u6539\u52A8\uFF09\u3002\u5982\u9700\u8986\u76D6\u8BF7\u4F7F\u7528 --force\uFF1B\u5982\u9700\u9884\u89C8\u8BF7\u4F7F\u7528 --dry-run\uFF1B\u5982\u9700\u5148\u67E5\u770B\u5185\u5BB9\u8BF7\u8FD0\u884C v-cli agent docs`
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
const existed = targetStat !== void 0;
|
|
763
|
+
const action = existed ? dryRun ? "overwrite" : "overwritten" : dryRun ? "write" : "written";
|
|
764
|
+
if (dryRun) {
|
|
765
|
+
return { ...base, ok: true, action };
|
|
766
|
+
}
|
|
767
|
+
try {
|
|
768
|
+
atomicWrite(target, docs.content);
|
|
769
|
+
} catch (err) {
|
|
770
|
+
return refuse(`\u5199\u5165\u5931\u8D25 ${target}: ${err instanceof Error ? err.message : String(err)}`);
|
|
771
|
+
}
|
|
772
|
+
return { ...base, ok: true, action };
|
|
773
|
+
}
|
|
774
|
+
function isEexist(err) {
|
|
775
|
+
return typeof err === "object" && err !== null && err.code === "EEXIST";
|
|
776
|
+
}
|
|
777
|
+
var MAX_TMP_RETRIES = 5;
|
|
778
|
+
function atomicWrite(target, content) {
|
|
779
|
+
let lastError;
|
|
780
|
+
for (let attempt = 0; attempt < MAX_TMP_RETRIES; attempt++) {
|
|
781
|
+
const tmp = path4.join(
|
|
782
|
+
path4.dirname(target),
|
|
783
|
+
`.${BUNDLED_DOCS_FILE}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`
|
|
784
|
+
);
|
|
785
|
+
let created = false;
|
|
786
|
+
try {
|
|
787
|
+
fs3.writeFileSync(tmp, content, { encoding: "utf-8", flag: "wx", mode: 420 });
|
|
788
|
+
created = true;
|
|
789
|
+
fs3.renameSync(tmp, target);
|
|
790
|
+
return;
|
|
791
|
+
} catch (err) {
|
|
792
|
+
lastError = err;
|
|
793
|
+
if (created) {
|
|
794
|
+
try {
|
|
795
|
+
fs3.rmSync(tmp, { force: true });
|
|
796
|
+
} catch {
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
if (isEexist(err)) continue;
|
|
800
|
+
throw err;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
const detail = lastError instanceof Error ? lastError.message : String(lastError ?? "\u672A\u77E5\u9519\u8BEF");
|
|
804
|
+
throw new Error(`\u539F\u5B50\u5199\u5165\u5931\u8D25\uFF08\u4E34\u65F6\u6587\u4EF6\u547D\u540D\u78B0\u649E\u91CD\u8BD5 ${MAX_TMP_RETRIES} \u6B21\u672A\u679C\uFF09: ${detail}`);
|
|
805
|
+
}
|
|
806
|
+
|
|
599
807
|
// src/commands/agent.ts
|
|
600
808
|
function buildAgentIndex(builtin, local, official) {
|
|
601
809
|
const rows = [];
|
|
@@ -659,10 +867,153 @@ function rowToText(row) {
|
|
|
659
867
|
const meta = row.metadataStatus === "full" ? "\u5B8C\u6574\u5143\u6570\u636E" : "\u6700\u5C0F\u5143\u6570\u636E";
|
|
660
868
|
return `[${row.type}] ${row.name}${status}: ${row.description} (${meta})`;
|
|
661
869
|
}
|
|
870
|
+
function describeCommandLine(c) {
|
|
871
|
+
const pathText = Array.isArray(c.path) ? c.path.join(" ") : "";
|
|
872
|
+
const argText = Array.isArray(c.arguments) && c.arguments.length > 0 ? ` \u53C2\u6570: ${c.arguments.map((a) => `${a.required ? `<${a.name}>` : `[${a.name}]`}`).join(", ")}` : "";
|
|
873
|
+
const optText = Array.isArray(c.options) && c.options.length > 0 ? ` \u9009\u9879: ${c.options.map((o) => o.flags).join(", ")}` : "";
|
|
874
|
+
const outputText = c.output && typeof c.output === "object" && typeof c.output.format === "string" ? ` \u8F93\u51FA: ${c.output.format}${c.output.description ? `\uFF08${c.output.description}\uFF09` : ""}` : "";
|
|
875
|
+
const exitText = c.exitCodes && typeof c.exitCodes === "object" && Object.keys(c.exitCodes).length > 0 ? ` \u9000\u51FA\u7801: ${Object.entries(c.exitCodes).map(([code, desc]) => `${code}=${desc}`).join(", ")}` : "";
|
|
876
|
+
const safeText = Array.isArray(c.safety) && c.safety.length > 0 ? ` \u5B89\u5168: ${c.safety.join("\uFF1B")}` : "";
|
|
877
|
+
return ` ${pathText} \u2014 ${c.description}${c.usage ? ` (\u7528\u6CD5: ${c.usage})` : ""}${argText}${optText}${outputText}${exitText}${safeText}`;
|
|
878
|
+
}
|
|
879
|
+
var AGENT_HELP_TEXT = [
|
|
880
|
+
"agent \u5B50\u547D\u4EE4\u4E00\u89C8\uFF1A",
|
|
881
|
+
" index \u5217\u51FA\u5168\u90E8\u547D\u4EE4\uFF08builtin/local/official\uFF09\u4E0E agent \u5143\u6570\u636E\uFF1B--json \u8F93\u51FA\u7A33\u5B9A JSON \u6570\u7EC4",
|
|
882
|
+
" describe \u67E5\u770B\u5355\u4E2A\u547D\u4EE4\u7684\u5B8C\u6574\u8BB0\u5F55\uFF08\u7528\u6CD5/\u53C2\u6570/\u9009\u9879/\u8F93\u51FA/\u9000\u51FA\u7801/\u5B89\u5168\u6807\u7B7E\uFF09\uFF1B--json \u8F93\u51FA\u5355\u6761\u8BB0\u5F55",
|
|
883
|
+
" docs \u8F93\u51FA\u5F53\u524D @kevlns/v-cli \u5305\u5185\u7F6E AGENTS.md \u539F\u6587\uFF1B--json \u8F93\u51FA { package, version, sha256, content }",
|
|
884
|
+
" init \u628A\u5185\u7F6E AGENTS.md \u5199\u5165\u5DE5\u4F5C\u533A\uFF08\u9ED8\u8BA4\u5F53\u524D\u76EE\u5F55\uFF09\uFF1B\u5DF2\u5B58\u5728\u9ED8\u8BA4\u62D2\u7EDD\uFF0C--force \u8986\u76D6\uFF0C--dry-run \u9884\u89C8",
|
|
885
|
+
"",
|
|
886
|
+
"JSON\uFF1A\u6240\u6709\u5B50\u547D\u4EE4\u652F\u6301 --json\uFF08\u6216\u524D\u7F6E\u5168\u5C40 --json\uFF0C\u5982 v-cli --json agent index\uFF09",
|
|
887
|
+
"",
|
|
888
|
+
"AI Agent \u5FEB\u901F\u5F00\u59CB\uFF08\u63A8\u8350\u987A\u5E8F\uFF09\uFF1A",
|
|
889
|
+
" 1. v-cli agent docs",
|
|
890
|
+
" 2. v-cli agent index --json",
|
|
891
|
+
" 3. v-cli agent describe <name> --json",
|
|
892
|
+
" 4. v-cli agent init . \uFF08\u53EF\u9009\uFF1A\u5199\u5165\u5DE5\u4F5C\u533A AGENTS.md\uFF0CAI Agent \u81EA\u52A8\u8BFB\u53D6\uFF09",
|
|
893
|
+
"",
|
|
894
|
+
"\u793A\u4F8B\uFF1A",
|
|
895
|
+
" v-cli agent index --json # \u5168\u91CF\u547D\u4EE4\u7D22\u5F15",
|
|
896
|
+
" v-cli agent describe ts --json # \u5355\u547D\u4EE4\u8BE6\u60C5",
|
|
897
|
+
" v-cli agent docs # \u5185\u7F6E\u5F15\u5BFC\u6587\u6863\u539F\u6587",
|
|
898
|
+
" v-cli agent init . --dry-run # \u9884\u89C8\u521D\u59CB\u5316\u76EE\u6807"
|
|
899
|
+
].join("\n");
|
|
900
|
+
var DOCS_HELP_TEXT = [
|
|
901
|
+
"\u8F93\u51FA\u5F53\u524D\u5B89\u88C5\u7684 @kevlns/v-cli \u5305\u5185\u7F6E AGENTS.md \u539F\u6587\uFF08AI Agent \u5F15\u5BFC\u6587\u6863\uFF09\uFF0C\u9010\u5B57\u8282\u539F\u6837\u8F93\u51FA\u3001\u4E0D\u8FFD\u52A0\u6362\u884C\u3002",
|
|
902
|
+
"",
|
|
903
|
+
"JSON \u884C\u4E3A\uFF08--json \u6216\u524D\u7F6E\u5168\u5C40 --json\uFF09\uFF1A",
|
|
904
|
+
" \u6210\u529F\uFF1Astdout \u8F93\u51FA\u7A33\u5B9A\u5BF9\u8C61 { package, version, sha256, content }",
|
|
905
|
+
" package \u5305\u540D @kevlns/v-cli",
|
|
906
|
+
" version \u5F53\u524D\u5305\u7248\u672C",
|
|
907
|
+
" sha256 content \u7684 SHA-256\uFF08hex\uFF09\uFF0C\u53EF\u6821\u9A8C\u5F15\u5BFC\u6587\u6863\u672A\u88AB\u7BE1\u6539",
|
|
908
|
+
" content AGENTS.md \u539F\u6587",
|
|
909
|
+
" \u5931\u8D25\uFF1Astdout \u8F93\u51FA\u7A00\u758F\u5BF9\u8C61 { ok: false, error }\uFF0Cstderr \u518D\u8F93\u51FA\u540C\u4E00 error\uFF0C\u9000\u51FA\u7801 1",
|
|
910
|
+
"",
|
|
911
|
+
"\u9000\u51FA\u7801\uFF1A0 \u6210\u529F\uFF1B1 \u5185\u7F6E AGENTS.md \u7F3A\u5931/\u4E0D\u53EF\u8BFB",
|
|
912
|
+
"",
|
|
913
|
+
"\u793A\u4F8B\uFF1A",
|
|
914
|
+
" v-cli agent docs",
|
|
915
|
+
" v-cli agent docs --json"
|
|
916
|
+
].join("\n");
|
|
917
|
+
var INIT_HELP_TEXT = [
|
|
918
|
+
"\u628A\u5F53\u524D @kevlns/v-cli \u5305\u5185\u7F6E AGENTS.md \u539F\u6837\u5199\u5165 <\u76EE\u5F55>/AGENTS.md\uFF0CAI Agent \u4F1A\u81EA\u52A8\u8BFB\u53D6\u5DE5\u4F5C\u533A\u6587\u6863\u3002",
|
|
919
|
+
"",
|
|
920
|
+
"\u53C2\u6570\uFF1A",
|
|
921
|
+
" [directory] \u76EE\u6807\u76EE\u5F55\uFF0C\u9ED8\u8BA4\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF1B\u5FC5\u987B\u5DF2\u5B58\u5728\u4E14\u4E3A\u76EE\u5F55",
|
|
922
|
+
"",
|
|
923
|
+
"\u9ED8\u8BA4\u884C\u4E3A\uFF08\u65E0 --force\uFF09\uFF1A\u76EE\u6807\u5DF2\u5B58\u5728 AGENTS.md \u65F6\u62D2\u7EDD\u5E76\u9000\u51FA 1\uFF0C\u7EDD\u4E0D\u6539\u52A8\u73B0\u6709\u6587\u4EF6\u3002",
|
|
924
|
+
" --force \u8986\u76D6\u5DF2\u5B58\u5728\u7684 AGENTS.md\uFF08\u539F\u5B50\u5199\u5165\uFF1A\u540C\u76EE\u5F55\u4E34\u65F6\u6587\u4EF6 + rename\uFF09",
|
|
925
|
+
" --dry-run \u53EA\u62A5\u544A\u76EE\u6807\u4E0E\u5C06\u6267\u884C\u7684\u52A8\u4F5C\uFF0C\u4E0D\u5199\u5165\u4EFB\u4F55\u6587\u4EF6",
|
|
926
|
+
" --json \u6210\u529F/\u5E72\u8DD1\u8F93\u51FA\u7A33\u5B9A JSON { ok, dryRun, action, directory, target, package, version, sha256, bytes }\uFF1B",
|
|
927
|
+
' \u62D2\u7EDD\uFF08\u5982\u5DF2\u5B58\u5728\u672A\u52A0 --force\uFF09\u8F93\u51FA { ok: false, action: "refused", reason, \u2026 } \u4E14\u9000\u51FA 1\uFF1B',
|
|
928
|
+
" \u5185\u7F6E\u6587\u6863\u7F3A\u5931\u65F6\u8F93\u51FA\u7A00\u758F { ok: false, error } \u4E14\u9000\u51FA 1",
|
|
929
|
+
" \u7B26\u53F7\u94FE\u63A5\u89C4\u5219\uFF1A\u76EE\u6807 AGENTS.md \u662F\u7B26\u53F7\u94FE\u63A5\u4E00\u5F8B\u62D2\u7EDD\uFF08fail-closed\uFF1A\u4E0D\u8DDF\u968F\u3001\u4E0D\u8986\u76D6\u94FE\u63A5\u76EE\u6807\uFF09\uFF1B",
|
|
930
|
+
" \u663E\u5F0F\u4F20\u5165\u7684\u76EE\u5F55\u672C\u8EAB\u662F\u7B26\u53F7\u94FE\u63A5/\u8054\u63A5\u76EE\u5F55\uFF08junction\uFF09\u4E5F\u62D2\u7EDD\uFF1B\u7701\u7565\u76EE\u5F55\u53C2\u6570\uFF08\u9ED8\u8BA4\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF09\u4E0D\u53D7\u6B64\u9650\u5236",
|
|
931
|
+
"",
|
|
932
|
+
"\u9000\u51FA\u7801\uFF1A0 \u6210\u529F\u6216\u5E72\u8DD1\uFF1B1 \u76EE\u5F55\u65E0\u6548 / \u5DF2\u5B58\u5728\u672A\u52A0 --force / \u7B26\u53F7\u94FE\u63A5\u6216\u8054\u63A5\u76EE\u6807 / \u5185\u7F6E\u6587\u6863\u7F3A\u5931 / \u5199\u5165\u5931\u8D25",
|
|
933
|
+
"",
|
|
934
|
+
"\u793A\u4F8B\uFF1A",
|
|
935
|
+
" v-cli agent init",
|
|
936
|
+
" v-cli agent init ./myproj",
|
|
937
|
+
" v-cli agent init --dry-run",
|
|
938
|
+
" v-cli agent init --force",
|
|
939
|
+
" v-cli agent init --json"
|
|
940
|
+
].join("\n");
|
|
662
941
|
var agent = {
|
|
663
942
|
name: "agent",
|
|
664
|
-
description: "agent
|
|
943
|
+
description: "agent\uFF1Aindex \u547D\u4EE4\u7D22\u5F15\uFF0Cdescribe \u8BE6\u60C5\uFF0Cdocs \u5185\u7F6E AGENTS.md\uFF0Cinit \u5DE5\u4F5C\u533A\u5F15\u5BFC",
|
|
665
944
|
apiVersion: 1,
|
|
945
|
+
agent: {
|
|
946
|
+
whenToUse: "\u5F53\u7528\u6237\u9700\u8981 AGENTS \u5F15\u5BFC\u6587\u6863\u3001\u547D\u4EE4\u53D1\u73B0\u6216\u4E3A AI Agent \u521D\u59CB\u5316\u5DE5\u4F5C\u533A\u65F6\uFF1A\u5148 `docs` \u8BFB\u5185\u7F6E AGENTS.md\uFF0C\u518D `index --json` \u679A\u4E3E\u5168\u90E8\u547D\u4EE4\u4E0E\u5143\u6570\u636E\uFF0C\u7528 `describe <name> --json` \u770B\u5355\u547D\u4EE4\u8BE6\u60C5\uFF0C\u6700\u540E\u53EF `init` \u628A AGENTS.md \u5199\u5165\u5DE5\u4F5C\u533A",
|
|
947
|
+
globalOptions: [
|
|
948
|
+
{ flags: "-h, --help", description: "\u663E\u793A\u547D\u4EE4\u5E2E\u52A9" }
|
|
949
|
+
],
|
|
950
|
+
commands: [
|
|
951
|
+
{
|
|
952
|
+
path: ["index"],
|
|
953
|
+
usage: "v-cli agent index [--json]",
|
|
954
|
+
description: "\u5217\u51FA\u5168\u90E8\u547D\u4EE4\uFF08builtin/local/official\uFF09\u4E0E agent \u5143\u6570\u636E",
|
|
955
|
+
arguments: [],
|
|
956
|
+
options: [{ flags: "--json", description: "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB JSON" }],
|
|
957
|
+
output: {
|
|
958
|
+
format: "stdout",
|
|
959
|
+
description: "\u6B63\u6587\u8F93\u51FA\u5230 stdout\uFF1B--json \u65F6\u8F93\u51FA\u7A33\u5B9A JSON \u6570\u7EC4\uFF08name/type/description/metadataStatus/commands/\u2026\uFF09"
|
|
960
|
+
},
|
|
961
|
+
exitCodes: { "0": "\u6210\u529F" },
|
|
962
|
+
safety: ["read-only", "no-network"]
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
path: ["describe"],
|
|
966
|
+
usage: "v-cli agent describe <name> [--json]",
|
|
967
|
+
description: "\u67E5\u770B\u5355\u4E2A\u547D\u4EE4\u7684\u5B8C\u6574\u8BB0\u5F55",
|
|
968
|
+
arguments: [{ name: "name", required: true, description: "\u547D\u4EE4\u540D\uFF08builtin/local/official\uFF09" }],
|
|
969
|
+
options: [{ flags: "--json", description: "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB JSON" }],
|
|
970
|
+
output: { format: "stdout", description: "\u6B63\u6587\u8F93\u51FA\u5230 stdout\uFF1B--json \u65F6\u8F93\u51FA\u5355\u6761\u7A33\u5B9A JSON \u5BF9\u8C61" },
|
|
971
|
+
exitCodes: { "0": "\u6210\u529F", "1": "\u672A\u627E\u5230\u547D\u4EE4\uFF08stderr \u8BF4\u660E\uFF09" },
|
|
972
|
+
safety: ["read-only"]
|
|
973
|
+
},
|
|
974
|
+
{
|
|
975
|
+
path: ["docs"],
|
|
976
|
+
usage: "v-cli agent docs [--json]",
|
|
977
|
+
description: "\u8F93\u51FA\u5F53\u524D @kevlns/v-cli \u5305\u5185\u7F6E AGENTS.md \u539F\u6587",
|
|
978
|
+
arguments: [],
|
|
979
|
+
options: [{ flags: "--json", description: "\u8F93\u51FA { package, version, sha256, content }" }],
|
|
980
|
+
output: {
|
|
981
|
+
format: "stdout",
|
|
982
|
+
description: "AGENTS.md \u539F\u6587\u9010\u5B57\u8282\u8F93\u51FA\u5230 stdout\uFF1B--json \u65F6\u8F93\u51FA\u542B sha256/content \u7684\u7A33\u5B9A JSON"
|
|
983
|
+
},
|
|
984
|
+
exitCodes: { "0": "\u6210\u529F", "1": "\u5185\u7F6E AGENTS.md \u7F3A\u5931/\u4E0D\u53EF\u8BFB" },
|
|
985
|
+
safety: ["read-only", "no-network"]
|
|
986
|
+
},
|
|
987
|
+
{
|
|
988
|
+
path: ["init"],
|
|
989
|
+
usage: "v-cli agent init [directory] [--force] [--dry-run] [--json]",
|
|
990
|
+
description: "\u628A\u5185\u7F6E AGENTS.md \u5199\u5165 <\u76EE\u5F55>/AGENTS.md\uFF1B\u9ED8\u8BA4\u5F53\u524D\u76EE\u5F55\uFF1B\u5DF2\u5B58\u5728\u9ED8\u8BA4\u62D2\u7EDD",
|
|
991
|
+
arguments: [
|
|
992
|
+
{ name: "directory", required: false, description: "\u76EE\u6807\u76EE\u5F55\uFF08\u9ED8\u8BA4\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF1B\u987B\u5DF2\u5B58\u5728\u4E14\u4E3A\u76EE\u5F55\uFF09" }
|
|
993
|
+
],
|
|
994
|
+
options: [
|
|
995
|
+
{ flags: "--force", description: "\u8986\u76D6\u5DF2\u5B58\u5728 AGENTS.md\uFF08\u539F\u5B50\u5199\u5165\uFF09" },
|
|
996
|
+
{ flags: "--dry-run", description: "\u53EA\u62A5\u544A\u76EE\u6807\u4E0E\u52A8\u4F5C\uFF0C\u4E0D\u5199\u5165" },
|
|
997
|
+
{ flags: "--json", description: "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB\u7ED3\u679C" }
|
|
998
|
+
],
|
|
999
|
+
output: {
|
|
1000
|
+
format: "stdout",
|
|
1001
|
+
description: "\u7ED3\u679C\u6587\u672C\u8F93\u51FA\u5230 stdout\uFF1B--json \u65F6\u8F93\u51FA\u7A33\u5B9A JSON\uFF08ok/dryRun/action/directory/target/package/version/sha256/bytes\uFF09"
|
|
1002
|
+
},
|
|
1003
|
+
exitCodes: {
|
|
1004
|
+
"0": "\u6210\u529F\u6216\u5E72\u8DD1",
|
|
1005
|
+
"1": "\u76EE\u5F55\u65E0\u6548 / \u5DF2\u5B58\u5728\u672A\u8986\u76D6 / \u7B26\u53F7\u94FE\u63A5\u6216\u8054\u63A5\u76EE\u6807 / \u6587\u6863\u7F3A\u5931 / \u5199\u5165\u5931\u8D25"
|
|
1006
|
+
},
|
|
1007
|
+
safety: [
|
|
1008
|
+
"writes-target-atomic",
|
|
1009
|
+
"refuses-existing",
|
|
1010
|
+
"fail-closed-symlink",
|
|
1011
|
+
"dry-run-supported",
|
|
1012
|
+
"no-commit"
|
|
1013
|
+
]
|
|
1014
|
+
}
|
|
1015
|
+
]
|
|
1016
|
+
},
|
|
666
1017
|
register(program, ctx) {
|
|
667
1018
|
program.command("index").description("\u5217\u51FA\u5168\u90E8\u547D\u4EE4\uFF08builtin/local/official\uFF09\u4E0E agent \u5143\u6570\u636E").option("--json", "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB JSON").action(async (opts) => {
|
|
668
1019
|
const json = ctx.json || opts.json;
|
|
@@ -704,27 +1055,82 @@ var agent = {
|
|
|
704
1055
|
}
|
|
705
1056
|
if (row.commands && row.commands.length > 0) {
|
|
706
1057
|
lines.push("\u5B50\u547D\u4EE4:");
|
|
707
|
-
for (const c of row.commands)
|
|
708
|
-
const pathText = Array.isArray(c.path) ? c.path.join(" ") : "";
|
|
709
|
-
const optText = Array.isArray(c.options) && c.options.length > 0 ? ` \u9009\u9879: ${c.options.map((o) => o.flags).join(", ")}` : "";
|
|
710
|
-
const safeText = Array.isArray(c.safety) && c.safety.length > 0 ? ` \u5B89\u5168: ${c.safety.join("\uFF1B")}` : "";
|
|
711
|
-
lines.push(
|
|
712
|
-
` ${pathText} \u2014 ${c.description}${c.usage ? ` (\u7528\u6CD5: ${c.usage})` : ""}${optText}${safeText}`
|
|
713
|
-
);
|
|
714
|
-
}
|
|
1058
|
+
for (const c of row.commands) lines.push(describeCommandLine(c));
|
|
715
1059
|
}
|
|
716
1060
|
ctx.log.result(lines.join("\n"));
|
|
717
1061
|
});
|
|
1062
|
+
program.command("docs").description("\u8F93\u51FA\u5F53\u524D @kevlns/v-cli \u5305\u5185\u7F6E AGENTS.md \u539F\u6587\uFF08AI Agent \u5F15\u5BFC\u6587\u6863\uFF09").option("--json", "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB JSON\uFF08\u542B sha256/content\uFF09").addHelpText("after", DOCS_HELP_TEXT).action((opts) => {
|
|
1063
|
+
const json = ctx.json || opts.json;
|
|
1064
|
+
let docs;
|
|
1065
|
+
try {
|
|
1066
|
+
docs = readBundledAgentsMd();
|
|
1067
|
+
} catch (err) {
|
|
1068
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1069
|
+
if (json) ctx.log.result({ ok: false, error: message });
|
|
1070
|
+
ctx.log.error(message);
|
|
1071
|
+
process.exitCode = 1;
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
if (json) {
|
|
1075
|
+
ctx.log.result({
|
|
1076
|
+
package: BUNDLED_DOCS_PACKAGE,
|
|
1077
|
+
version: VERSION,
|
|
1078
|
+
sha256: docs.sha256,
|
|
1079
|
+
content: docs.content
|
|
1080
|
+
});
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
process.stdout.write(docs.content);
|
|
1084
|
+
});
|
|
1085
|
+
program.command("init").description("\u521D\u59CB\u5316 <\u76EE\u5F55>/AGENTS.md\uFF08\u9ED8\u8BA4\u5F53\u524D\u76EE\u5F55\uFF09\uFF1B\u5DF2\u5B58\u5728\u9ED8\u8BA4\u62D2\u7EDD\uFF0C--force \u8986\u76D6\uFF0C--dry-run \u9884\u89C8").argument("[directory]", "\u76EE\u6807\u76EE\u5F55\uFF08\u9ED8\u8BA4\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF1B\u5FC5\u987B\u5DF2\u5B58\u5728\u4E14\u4E3A\u76EE\u5F55\uFF09").option("--force", "\u8986\u76D6\u5DF2\u5B58\u5728\u7684 AGENTS.md\uFF08\u539F\u5B50\u5199\u5165\uFF09").option("--dry-run", "\u53EA\u62A5\u544A\u76EE\u6807\u4E0E\u52A8\u4F5C\uFF0C\u4E0D\u5199\u5165\u4EFB\u4F55\u6587\u4EF6").option("--json", "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB\u7ED3\u679C").addHelpText("after", INIT_HELP_TEXT).action(
|
|
1086
|
+
(directory, opts) => {
|
|
1087
|
+
const json = ctx.json || opts.json;
|
|
1088
|
+
let docs;
|
|
1089
|
+
try {
|
|
1090
|
+
docs = readBundledAgentsMd();
|
|
1091
|
+
} catch (err) {
|
|
1092
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1093
|
+
if (json) ctx.log.result({ ok: false, error: message });
|
|
1094
|
+
ctx.log.error(message);
|
|
1095
|
+
process.exitCode = 1;
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
const result = performAgentInit({
|
|
1099
|
+
directory: path5.resolve(directory ?? process.cwd()),
|
|
1100
|
+
docs,
|
|
1101
|
+
force: opts.force,
|
|
1102
|
+
dryRun: opts.dryRun,
|
|
1103
|
+
// 显式传入目录才做目录符号链接/联接 fail-closed;默认 cwd 不受限
|
|
1104
|
+
explicitDirectory: directory !== void 0
|
|
1105
|
+
});
|
|
1106
|
+
if (json) {
|
|
1107
|
+
ctx.log.result(result);
|
|
1108
|
+
if (!result.ok && result.reason) ctx.log.error(result.reason);
|
|
1109
|
+
if (!result.ok) process.exitCode = 1;
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
if (!result.ok) {
|
|
1113
|
+
if (result.reason) ctx.log.error(result.reason);
|
|
1114
|
+
process.exitCode = 1;
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
if (result.dryRun) {
|
|
1118
|
+
ctx.log.result(
|
|
1119
|
+
`[dry-run] \u5C06${result.action === "overwrite" ? "\u8986\u76D6" : "\u5199\u5165"} ${result.target}\uFF08${result.bytes} \u5B57\u8282\uFF09`
|
|
1120
|
+
);
|
|
1121
|
+
} else {
|
|
1122
|
+
ctx.log.result(
|
|
1123
|
+
`\u5DF2${result.action === "overwritten" ? "\u8986\u76D6" : "\u5199\u5165"} ${result.target}\uFF08${result.bytes} \u5B57\u8282\uFF0CSHA-256 ${result.sha256.slice(0, 12)}\u2026\uFF09`
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
);
|
|
1128
|
+
program.addHelpText("after", AGENT_HELP_TEXT);
|
|
718
1129
|
}
|
|
719
1130
|
};
|
|
720
1131
|
|
|
721
1132
|
// src/commands/doctor.ts
|
|
722
|
-
import
|
|
723
|
-
|
|
724
|
-
// src/version.ts
|
|
725
|
-
var VERSION = "0.2.0-beta.1";
|
|
726
|
-
|
|
727
|
-
// src/commands/doctor.ts
|
|
1133
|
+
import fs4 from "fs";
|
|
728
1134
|
var doctor = {
|
|
729
1135
|
name: "doctor",
|
|
730
1136
|
description: "\u4F53\u68C0\uFF1Anode/v-cli \u7248\u672C\u3001homeDir\u3001config\u3001\u63D2\u4EF6\u72B6\u6001",
|
|
@@ -733,7 +1139,7 @@ var doctor = {
|
|
|
733
1139
|
program.option("--json", "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB JSON").action(async (opts) => {
|
|
734
1140
|
const json = ctx.json || opts.json;
|
|
735
1141
|
const homeDir = ctx.homeDir;
|
|
736
|
-
const exists =
|
|
1142
|
+
const exists = fs4.existsSync(homeDir);
|
|
737
1143
|
let configWritable = false;
|
|
738
1144
|
try {
|
|
739
1145
|
ctx.config.set((cfg) => cfg);
|
|
@@ -787,7 +1193,7 @@ var doctor = {
|
|
|
787
1193
|
};
|
|
788
1194
|
|
|
789
1195
|
// src/commands/plugin.ts
|
|
790
|
-
import
|
|
1196
|
+
import path6 from "path";
|
|
791
1197
|
var plugin = {
|
|
792
1198
|
name: "plugin",
|
|
793
1199
|
description: "\u63D2\u4EF6\u7BA1\u7406\uFF1Alist \u5217\u51FA\u547D\u4EE4\uFF0Cpath \u663E\u793A\u672C\u5730\u63D2\u4EF6\u76EE\u5F55",
|
|
@@ -826,7 +1232,7 @@ var plugin = {
|
|
|
826
1232
|
}
|
|
827
1233
|
});
|
|
828
1234
|
program.command("path").description("\u6253\u5370\u672C\u5730\u63D2\u4EF6\u76EE\u5F55\uFF08\u653E\u5165 .mjs \u6587\u4EF6\u5373\u751F\u6548\uFF09").option("--json", "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB JSON").action((opts) => {
|
|
829
|
-
const dir =
|
|
1235
|
+
const dir = path6.join(ctx.homeDir, "commands");
|
|
830
1236
|
if (ctx.json || opts.json) {
|
|
831
1237
|
ctx.log.result({ dir });
|
|
832
1238
|
} else {
|
|
@@ -894,12 +1300,12 @@ async function loadBuiltinCommands() {
|
|
|
894
1300
|
return builtinCommands.map((command) => ({ command, source: "builtin" }));
|
|
895
1301
|
}
|
|
896
1302
|
async function loadLocalPlugins(ctx) {
|
|
897
|
-
const dir =
|
|
1303
|
+
const dir = path7.join(ctx.homeDir, "commands");
|
|
898
1304
|
const loaded = [];
|
|
899
|
-
if (!
|
|
900
|
-
const files =
|
|
1305
|
+
if (!fs5.existsSync(dir)) return loaded;
|
|
1306
|
+
const files = fs5.readdirSync(dir).filter((f) => f.endsWith(".mjs")).sort();
|
|
901
1307
|
for (const file of files) {
|
|
902
|
-
const abs =
|
|
1308
|
+
const abs = path7.join(dir, file);
|
|
903
1309
|
try {
|
|
904
1310
|
const mod = await import(
|
|
905
1311
|
/* @vite-ignore */
|
|
@@ -1041,6 +1447,18 @@ async function main() {
|
|
|
1041
1447
|
if (intercepted !== void 0) return intercepted;
|
|
1042
1448
|
const program = new Command();
|
|
1043
1449
|
program.name("v-cli").description("kevlns \u7684\u4E2A\u4EBA\u5DE5\u5177\u7BB1").version(VERSION).showHelpAfterError();
|
|
1450
|
+
program.addHelpText(
|
|
1451
|
+
"after",
|
|
1452
|
+
[
|
|
1453
|
+
"AI Agent \u5FEB\u901F\u5F00\u59CB\uFF08\u63A8\u8350\u987A\u5E8F\uFF09\uFF1A",
|
|
1454
|
+
" 1. v-cli agent docs",
|
|
1455
|
+
" 2. v-cli agent index --json",
|
|
1456
|
+
" 3. v-cli agent describe <name> --json",
|
|
1457
|
+
" 4. v-cli agent init . \uFF08\u53EF\u9009\uFF1A\u5199\u5165\u5DE5\u4F5C\u533A AGENTS.md\uFF0CAI Agent \u81EA\u52A8\u8BFB\u53D6\uFF09",
|
|
1458
|
+
"",
|
|
1459
|
+
"\u8BE6\u60C5\u89C1 `v-cli agent --help`\uFF1B\u5355\u547D\u4EE4\u8BF4\u660E\u4E66\uFF1A`v-cli agent docs --help` / `v-cli agent init --help`\u3002"
|
|
1460
|
+
].join("\n")
|
|
1461
|
+
);
|
|
1044
1462
|
const loaded = await loadAllCommands(ctx);
|
|
1045
1463
|
for (const item of loaded) {
|
|
1046
1464
|
if (!item.command) {
|