@kevlns/v-cli 0.2.0-beta.3 → 0.2.0
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 +11 -38
- package/dist/cli.mjs +262 -44
- package/package.json +4 -3
- package/skills/v-cli/SKILL.md +80 -0
package/AGENTS.md
CHANGED
|
@@ -7,12 +7,15 @@
|
|
|
7
7
|
|
|
8
8
|
## 核心约定(v-cli 本体)
|
|
9
9
|
|
|
10
|
-
- 环境要求 Node.js >= 20;v-cli 版本 @kevlns/v-cli@0.2.0
|
|
10
|
+
- 环境要求 Node.js >= 20;v-cli 版本 @kevlns/v-cli@0.2.0
|
|
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
14
|
- AI Agent 引导文档:`v-cli agent docs` 输出本文件原文(`--json` 含 sha256/content);
|
|
15
|
-
`v-cli agent init .` 把它写入工作区(已存在默认拒绝,`--force` 覆盖,`--dry-run` 预览;符号链接目标 fail-closed
|
|
15
|
+
`v-cli agent init .` 把它写入工作区(已存在默认拒绝,`--force` 覆盖,`--dry-run` 预览;符号链接目标 fail-closed);
|
|
16
|
+
同时把随包发布的 v-cli skill(skills/v-cli)装配到 <目录> 下匹配的 agent 技能目录(如 .claude/skills、.agent/skill、AgentHome/skills 等,清单见 src/core/agent-dirs.ts),无匹配则跳过
|
|
17
|
+
- **首次调用规范**:首次调用任何 official 插件命令前,必须先运行 `v-cli agent docs <命令名>`,
|
|
18
|
+
掌握该插件包内 `AGENTS.md`;使用规范、快速流程与禁止事项以插件 AGENTS.md 为准。
|
|
16
19
|
- 官方插件命令(`v-cli xlmerge …`、`v-cli unity …`)在子进程中运行(stdio 继承):v-cli 只做路由,
|
|
17
20
|
不解析、不改写插件的 stdout/stderr;插件 `--help`/`--json` 等参数由插件自己消费
|
|
18
21
|
- 插件对 worktree 的写入/提交行为以插件清单 v-cli.plugin.json 的 `agent.safety` 为准:
|
|
@@ -20,55 +23,25 @@
|
|
|
20
23
|
|
|
21
24
|
## @kevlns/u-cli-mod — 命令 `v-cli unity …`
|
|
22
25
|
|
|
23
|
-
**版本**:0.1.0
|
|
26
|
+
**版本**:0.1.0
|
|
24
27
|
**描述**:Pin a Unity project to its exact editor version route, download the verified Unity CLI and install the adapted com.unity.pipeline package for Unity 2022 (Windows-first, non-official Unity tooling).
|
|
25
28
|
**平台**:win32(仅 Windows 主机可用;非 Windows 上 v-cli 会拒绝路由)
|
|
26
29
|
|
|
27
30
|
**何时使用**:Use for Windows-first Unity Editor 2022 workflows that must stay pinned to an exact editor version: diagnose a project against its route, list pinned routes, download the verified Unity CLI, transactionally install the adapted com.unity.pipeline package, or run Unity Pipeline CLI commands with enforced project targeting. Never use on non-Windows hosts.
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
- `-h, --help` — display help for command
|
|
32
|
-
|
|
33
|
-
**子命令**:
|
|
34
|
-
- `doctor` — 检查工程版本、路由、CLI 与 Pipeline 状态(用法:`v-cli unity doctor <project> [options]`)
|
|
35
|
-
- 安全标签:read-only; never writes the project or the cache;fail-closed exact m_EditorVersion + m_EditorVersionWithRevision match (no wildcard, no fallback);queries running Unity.exe processes via PowerShell; a failed query is reported in the unityProcesses output, not fatal
|
|
36
|
-
- `routes` — 列出所有已配置的 Editor 精确路由(用法:`v-cli unity routes [options]`)
|
|
37
|
-
- 安全标签:read-only; no network access;uses only embedded pinned route metadata shipped in the package
|
|
38
|
-
- `cli install` — 下载并校验固定版本的 Unity CLI(SHA-256 + Authenticode)(用法:`v-cli unity cli install [options]`)
|
|
39
|
-
- 安全标签:writes only under the user cache: %LOCALAPPDATA%\editor-pipeline-cli\cache\cli;downloads from the pinned Unity official CDN HTTPS URL only;verifies fixed SHA-256 + expected size + Authenticode signer subject and certificate thumbprint before the binary is placed;unverified temp download is deleted on any failure; the final file is created by atomic rename
|
|
40
|
-
- `pipeline install` — 按工程 Editor 版本事务式安装适配后的 com.unity.pipeline(用法:`v-cli unity pipeline install <project> [options]`)
|
|
41
|
-
- 安全标签:transactional install: stage -> verify -> backup -> replace -> re-verify -> receipt; automatic rollback on any failure;fail-closed when a matching Unity Editor is running, unless --allow-running-editor;--dry-run never writes the project and never writes a receipt;source and destination trees must match the pinned expected-tree (385 files, SHA-256) before and after placement;writes only under <project>/Packages/com.unity.pipeline and <project>/Library/editor-pipeline-cli
|
|
42
|
-
- `setup` — cli install + pipeline install(用法:`v-cli unity setup <project> [options]`)
|
|
43
|
-
- 安全标签:combines the cli install and pipeline install safety contracts;fail-closed running-Editor guard unless --allow-running-editor;--dry-run never writes the project;--skip-cli avoids all CLI downloads
|
|
44
|
-
- `exec` — 调用路由 CLI 执行 Unity Pipeline 命令;--project-path 由工具统一绑定(用法:`v-cli unity exec <project> [options] -- <unity-cli-args...>`)
|
|
45
|
-
- 安全标签:re-verifies the pinned CLI SHA-256 before every invocation (fail-closed on tamper);rejects every --project-path variant (case-insensitive: --project-path, --projectPath, -projectPath, --project_path, mixed case);always appends the resolved --project-path as the final argument; the wrapper owns project targeting;no route fallback: the project must match a pinned route exactly;the documented -- separator is consumed by the wrapper and never forwarded to the Unity CLI
|
|
46
|
-
- `cache clean` — 清理下载缓存与生成的适配包(用法:`v-cli unity cache clean [options]`)
|
|
47
|
-
- 安全标签:removes only directories under the user cache root %LOCALAPPDATA%\editor-pipeline-cli;default scope: generated packages + pipeline downloads only; without --all the CLI cache and logs are preserved
|
|
32
|
+
**首次调用前必读**:`v-cli agent docs unity`(插件包内 AGENTS.md 规范正本)
|
|
33
|
+
**实时参数/命令**:`v-cli agent describe unity --json`
|
|
48
34
|
|
|
49
35
|
## @kevlns/xlmerge — 命令 `v-cli xlmerge …`
|
|
50
36
|
|
|
51
|
-
**版本**:1.2.1
|
|
37
|
+
**版本**:1.2.1
|
|
52
38
|
**描述**:Visual resolver for Git merge conflicts in .xlsx/.xlsm planning tables: three-way sheet/row/cell diff, local UI, write-back and commit.
|
|
53
39
|
**平台**:darwin, linux, win32
|
|
54
40
|
|
|
55
41
|
**何时使用**:When a user asks to resolve Git merge conflicts in .xlsx/.xlsm planning or configuration tables (策划表/配置表冲突): run detect first; when count > 0 run launch and give the returned url to the user. Do not inspect workbook cells or summarize diffs yourself; the resolver owns diff, choices, write-back and commit.
|
|
56
42
|
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
- `--runtime-dir <dir>` — Optional directory for extracted Git stage workbooks and manifest (default: system temp). Used by prepare, resolve and launch.
|
|
60
|
-
|
|
61
|
-
**子命令**:
|
|
62
|
-
- `detect` — List unresolved .xlsx/.xlsm files in the repository.(用法:`v-cli xlmerge --repo <repo> detect`)
|
|
63
|
-
- 安全标签:read-only;no-worktree-modification
|
|
64
|
-
- `prepare` — Extract base/ours/theirs stage versions from the Git index and build a sheet-aware manifest.(用法:`v-cli xlmerge --repo <repo> prepare [--path <file>]`)
|
|
65
|
-
- 安全标签:writes-runtime-dir;no-worktree-modification;no-commit
|
|
66
|
-
- `resolve` — Prepare conflicts and serve the local visual resolver in the foreground (blocking).(用法:`v-cli xlmerge --repo <repo> resolve [--path <file>] [--no-browser]`)
|
|
67
|
-
- 安全标签:blocking;binds-loopback;opens-browser-by-default;no-push;writes-runtime-dir;writes-worktree-via-ui;commits-by-default-via-ui
|
|
68
|
-
- `launch` — Prepare conflicts, start the visual resolver in the background and return its URL.(用法:`v-cli xlmerge --repo <repo> launch [--path <file>] [--no-browser]`)
|
|
69
|
-
- 安全标签:starts-background-server;binds-loopback;opens-browser-by-default;no-push;writes-runtime-dir;writes-worktree-via-ui;commits-by-default-via-ui
|
|
70
|
-
- `apply` — Write back decisions from a decisions JSON without launching the UI.(用法:`v-cli xlmerge --repo <repo> apply --manifest <manifest.json> --decisions <decisions.json> [--no-commit] [--push] [--message <text>]`)
|
|
71
|
-
- 安全标签:writes-worktree;commits-by-default;pushes-only-with-flag
|
|
43
|
+
**首次调用前必读**:`v-cli agent docs xlmerge`(插件包内 AGENTS.md 规范正本)
|
|
44
|
+
**实时参数/命令**:`v-cli agent describe xlmerge --json`
|
|
72
45
|
|
|
73
46
|
---
|
|
74
47
|
|
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 fs6 from "fs";
|
|
79
|
+
import path8 from "path";
|
|
80
80
|
import { pathToFileURL } from "url";
|
|
81
81
|
|
|
82
82
|
// src/core/official.ts
|
|
@@ -618,7 +618,7 @@ function validateLocalCommand(candidate, options = {}) {
|
|
|
618
618
|
}
|
|
619
619
|
|
|
620
620
|
// src/commands/agent.ts
|
|
621
|
-
import
|
|
621
|
+
import path6 from "path";
|
|
622
622
|
|
|
623
623
|
// src/core/agent-docs.ts
|
|
624
624
|
import fs3 from "fs";
|
|
@@ -627,7 +627,7 @@ import { createHash, randomBytes } from "crypto";
|
|
|
627
627
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
628
628
|
|
|
629
629
|
// src/version.ts
|
|
630
|
-
var VERSION = "0.2.0
|
|
630
|
+
var VERSION = "0.2.0";
|
|
631
631
|
|
|
632
632
|
// src/core/agent-docs.ts
|
|
633
633
|
var BUNDLED_DOCS_FILE = "AGENTS.md";
|
|
@@ -699,6 +699,51 @@ function readBundledAgentsMd(opts = {}) {
|
|
|
699
699
|
bytes: Buffer.byteLength(content, "utf-8")
|
|
700
700
|
};
|
|
701
701
|
}
|
|
702
|
+
function readOfficialAgentsMd(command, opts = {}) {
|
|
703
|
+
const spec = OFFICIAL_PLUGINS.find((item) => item.command === command);
|
|
704
|
+
if (!spec) {
|
|
705
|
+
throw new Error(
|
|
706
|
+
`\u672A\u627E\u5230\u5B98\u65B9\u63D2\u4EF6\u547D\u4EE4: ${command}\u3002\u8BF7\u5148\u8FD0\u884C v-cli agent index --json \u67E5\u770B\u53EF\u7528\u5B98\u65B9\u63D2\u4EF6\u3002`
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
const resolvePackage = opts.resolvePackage ?? defaultResolvePackage;
|
|
710
|
+
const pkgJsonPath = resolvePackage(spec.package);
|
|
711
|
+
if (!pkgJsonPath) {
|
|
712
|
+
throw new Error(
|
|
713
|
+
`\u672A\u5B89\u88C5\u5B98\u65B9\u63D2\u4EF6\u5305 ${spec.package}\uFF08\u547D\u4EE4 ${command}\uFF09\uFF0C\u6216\u5B83\u4E0D\u5728\u53EF\u89E3\u6790\u8DEF\u5F84\u3002\u8BF7\u5148\u5B89\u88C5\u540E\u91CD\u8BD5\u3002`
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
let pkgJson;
|
|
717
|
+
try {
|
|
718
|
+
pkgJson = JSON.parse(fs3.readFileSync(pkgJsonPath, "utf-8"));
|
|
719
|
+
} catch (err) {
|
|
720
|
+
throw new Error(
|
|
721
|
+
`\u65E0\u6CD5\u8BFB\u53D6\u5B98\u65B9\u63D2\u4EF6 ${spec.package} \u7684 package.json\uFF08${pkgJsonPath}\uFF09: ${err instanceof Error ? err.message : String(err)}`
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
if (pkgJson.name !== spec.package || typeof pkgJson.version !== "string") {
|
|
725
|
+
throw new Error(`\u5B98\u65B9\u63D2\u4EF6 package.json \u8EAB\u4EFD\u65E0\u6548: \u671F\u671B ${spec.package} \u4E14 version \u4E3A\u5B57\u7B26\u4E32\u3002`);
|
|
726
|
+
}
|
|
727
|
+
const file = path4.join(path4.dirname(pkgJsonPath), BUNDLED_DOCS_FILE);
|
|
728
|
+
let content;
|
|
729
|
+
try {
|
|
730
|
+
if (!fs3.lstatSync(file).isFile()) throw new Error("\u76EE\u6807\u4E0D\u662F\u666E\u901A\u6587\u4EF6");
|
|
731
|
+
content = fs3.readFileSync(file, "utf-8");
|
|
732
|
+
} catch (err) {
|
|
733
|
+
throw new Error(
|
|
734
|
+
`\u5B98\u65B9\u63D2\u4EF6 ${spec.package}@${pkgJson.version} \u672A\u63D0\u4F9B\u53EF\u8BFB\u7684 ${BUNDLED_DOCS_FILE}\uFF08${file}\uFF09: ${err instanceof Error ? err.message : String(err)}\u3002\u8BF7\u5347\u7EA7\u6216\u91CD\u65B0\u5B89\u88C5\u8BE5\u63D2\u4EF6\u3002`
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
return {
|
|
738
|
+
package: spec.package,
|
|
739
|
+
command,
|
|
740
|
+
version: pkgJson.version,
|
|
741
|
+
file,
|
|
742
|
+
content,
|
|
743
|
+
sha256: sha256Hex(content),
|
|
744
|
+
bytes: Buffer.byteLength(content, "utf-8")
|
|
745
|
+
};
|
|
746
|
+
}
|
|
702
747
|
function sha256Hex(content) {
|
|
703
748
|
return createHash("sha256").update(content, "utf-8").digest("hex");
|
|
704
749
|
}
|
|
@@ -804,7 +849,140 @@ function atomicWrite(target, content) {
|
|
|
804
849
|
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
850
|
}
|
|
806
851
|
|
|
852
|
+
// src/core/agent-skill.ts
|
|
853
|
+
import fs4 from "fs";
|
|
854
|
+
import path5 from "path";
|
|
855
|
+
|
|
856
|
+
// src/core/agent-dirs.ts
|
|
857
|
+
var AGENT_SKILL_DIRS = [
|
|
858
|
+
".claude/skills",
|
|
859
|
+
".claude/skill",
|
|
860
|
+
".cursor/skills",
|
|
861
|
+
".cursor/rules",
|
|
862
|
+
".github/prompts",
|
|
863
|
+
".gemini/skills",
|
|
864
|
+
".codex/skills",
|
|
865
|
+
".agents/skills",
|
|
866
|
+
".agent/skills",
|
|
867
|
+
".agent/skill",
|
|
868
|
+
"AgentHome/skills",
|
|
869
|
+
".windsurf/skills",
|
|
870
|
+
".trae/skills",
|
|
871
|
+
".kilocode/skills",
|
|
872
|
+
".roo/skills",
|
|
873
|
+
".opencode/skills",
|
|
874
|
+
".augment/skills",
|
|
875
|
+
".kiro/skills",
|
|
876
|
+
".amazonq/skills",
|
|
877
|
+
".continue/skills"
|
|
878
|
+
];
|
|
879
|
+
|
|
880
|
+
// src/core/agent-skill.ts
|
|
881
|
+
var SKILL_NAME = "v-cli";
|
|
882
|
+
var SKILL_FILE = "SKILL.md";
|
|
883
|
+
function resolveSkillSourceRoot(opts = {}) {
|
|
884
|
+
const agentsMd = resolveBundledAgentsMd(opts);
|
|
885
|
+
if (!agentsMd) return void 0;
|
|
886
|
+
const root = path5.join(path5.dirname(agentsMd), "skills", SKILL_NAME);
|
|
887
|
+
try {
|
|
888
|
+
if (fs4.statSync(root).isDirectory()) return root;
|
|
889
|
+
} catch {
|
|
890
|
+
}
|
|
891
|
+
return void 0;
|
|
892
|
+
}
|
|
893
|
+
function readSkillSource(opts = {}) {
|
|
894
|
+
const root = resolveSkillSourceRoot(opts);
|
|
895
|
+
if (!root) {
|
|
896
|
+
throw new Error(
|
|
897
|
+
`\u65E0\u6CD5\u5B9A\u4F4D ${BUNDLED_DOCS_PACKAGE} \u5185\u7F6E skill\uFF08skills/${SKILL_NAME}\uFF09\uFF1A\u8BF7\u786E\u8BA4\u5B89\u88C5\u7684\u5305\u5185\u5305\u542B skills/ \u76EE\u5F55\uFF08\u91CD\u65B0\u5B89\u88C5 @kevlns/v-cli \u540E\u91CD\u8BD5\uFF09\u3002`
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
const file = path5.join(root, SKILL_FILE);
|
|
901
|
+
let content;
|
|
902
|
+
try {
|
|
903
|
+
if (!fs4.lstatSync(file).isFile()) throw new Error("\u5165\u53E3\u4E0D\u662F\u666E\u901A\u6587\u4EF6");
|
|
904
|
+
content = fs4.readFileSync(file, "utf-8");
|
|
905
|
+
} catch (err) {
|
|
906
|
+
throw new Error(
|
|
907
|
+
`\u65E0\u6CD5\u8BFB\u53D6 ${BUNDLED_DOCS_PACKAGE} \u5185\u7F6E skill\uFF08${file}\uFF09: ${err instanceof Error ? err.message : String(err)}`
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
return {
|
|
911
|
+
root,
|
|
912
|
+
file,
|
|
913
|
+
content,
|
|
914
|
+
sha256: sha256Hex(content),
|
|
915
|
+
bytes: Buffer.byteLength(content, "utf-8")
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
function collectAgentSkillDirs(directory) {
|
|
919
|
+
const hits = [];
|
|
920
|
+
for (const rel of AGENT_SKILL_DIRS) {
|
|
921
|
+
const abs = path5.join(directory, rel);
|
|
922
|
+
try {
|
|
923
|
+
if (fs4.statSync(abs).isDirectory()) hits.push(abs);
|
|
924
|
+
} catch {
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
return hits;
|
|
928
|
+
}
|
|
929
|
+
function copySkillDir(srcRoot, destDir) {
|
|
930
|
+
fs4.rmSync(destDir, { recursive: true, force: true });
|
|
931
|
+
fs4.cpSync(srcRoot, destDir, { recursive: true });
|
|
932
|
+
}
|
|
933
|
+
function performAgentSkillAssembly(opts) {
|
|
934
|
+
const { directory, source, dryRun = false } = opts;
|
|
935
|
+
const base = {
|
|
936
|
+
ok: true,
|
|
937
|
+
dryRun,
|
|
938
|
+
directory,
|
|
939
|
+
assembled: [],
|
|
940
|
+
skill: { name: SKILL_NAME, sha256: source.sha256, bytes: source.bytes }
|
|
941
|
+
};
|
|
942
|
+
let dirStat;
|
|
943
|
+
try {
|
|
944
|
+
dirStat = fs4.statSync(directory);
|
|
945
|
+
} catch {
|
|
946
|
+
return { ...base, ok: false, reason: `\u76EE\u6807\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u8BBF\u95EE: ${directory}` };
|
|
947
|
+
}
|
|
948
|
+
if (!dirStat.isDirectory()) {
|
|
949
|
+
return { ...base, ok: false, reason: `\u76EE\u6807\u4E0D\u662F\u76EE\u5F55: ${directory}` };
|
|
950
|
+
}
|
|
951
|
+
const hits = collectAgentSkillDirs(directory);
|
|
952
|
+
for (const dir of hits) {
|
|
953
|
+
const target = path5.join(dir, SKILL_NAME);
|
|
954
|
+
let overwrite = false;
|
|
955
|
+
try {
|
|
956
|
+
fs4.lstatSync(target);
|
|
957
|
+
overwrite = true;
|
|
958
|
+
} catch {
|
|
959
|
+
overwrite = false;
|
|
960
|
+
}
|
|
961
|
+
const action = dryRun ? "assemble" : "assembled";
|
|
962
|
+
if (!dryRun) {
|
|
963
|
+
copySkillDir(source.root, target);
|
|
964
|
+
}
|
|
965
|
+
base.assembled.push({ dir, target, action, overwrite });
|
|
966
|
+
}
|
|
967
|
+
return base;
|
|
968
|
+
}
|
|
969
|
+
|
|
807
970
|
// src/commands/agent.ts
|
|
971
|
+
function skillOutcomeText(outcome, dryRun) {
|
|
972
|
+
const verb = dryRun ? "\u5C06\u88C5\u914D\u5230" : "\u5DF2\u88C5\u914D\u5230";
|
|
973
|
+
switch (outcome.status) {
|
|
974
|
+
case "assembled": {
|
|
975
|
+
const dirs = outcome.assembled.map((t) => t.dir).join(", ");
|
|
976
|
+
return `[skill v-cli] ${verb} ${outcome.assembled.length} \u4E2A agent \u76EE\u5F55\uFF1A${dirs}`;
|
|
977
|
+
}
|
|
978
|
+
case "skipped-none":
|
|
979
|
+
return "[skill v-cli] \u672A\u68C0\u6D4B\u5230\u5339\u914D\u7684 agent \u6280\u80FD\u76EE\u5F55\uFF0C\u8DF3\u8FC7\u88C5\u914D";
|
|
980
|
+
case "skipped-source-missing":
|
|
981
|
+
return `[skill v-cli] \u8DF3\u8FC7\u88C5\u914D\uFF08\u6E90\u7F3A\u5931\uFF09\uFF1A${outcome.reason}`;
|
|
982
|
+
case "skipped-init-failed":
|
|
983
|
+
return "[skill v-cli] \u8DF3\u8FC7\u88C5\u914D\uFF08AGENTS.md \u672A\u5C31\u7EEA\uFF09";
|
|
984
|
+
}
|
|
985
|
+
}
|
|
808
986
|
function buildAgentIndex(builtin, local, official) {
|
|
809
987
|
const rows = [];
|
|
810
988
|
for (const cmd of builtin) {
|
|
@@ -880,7 +1058,7 @@ var AGENT_HELP_TEXT = [
|
|
|
880
1058
|
"agent \u5B50\u547D\u4EE4\u4E00\u89C8\uFF1A",
|
|
881
1059
|
" 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
1060
|
" 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
|
|
1061
|
+
" docs \u65E0\u53C2\u8F93\u51FA v-cli AGENTS.md\uFF1B\u4F20 <command> \u8F93\u51FA\u5DF2\u5B89\u88C5\u5B98\u65B9\u63D2\u4EF6\u5305\u5185 AGENTS.md",
|
|
884
1062
|
" 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
1063
|
"",
|
|
886
1064
|
"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",
|
|
@@ -894,28 +1072,33 @@ var AGENT_HELP_TEXT = [
|
|
|
894
1072
|
"\u793A\u4F8B\uFF1A",
|
|
895
1073
|
" v-cli agent index --json # \u5168\u91CF\u547D\u4EE4\u7D22\u5F15",
|
|
896
1074
|
" v-cli agent describe ts --json # \u5355\u547D\u4EE4\u8BE6\u60C5",
|
|
897
|
-
" v-cli agent docs # \
|
|
1075
|
+
" v-cli agent docs # v-cli \u7626\u7D22\u5F15\u539F\u6587",
|
|
1076
|
+
" v-cli agent docs unity # u-cli-mod \u5305\u5185\u4F7F\u7528\u89C4\u8303",
|
|
1077
|
+
" v-cli agent docs xlmerge --json # xlmerge \u5305\u5185\u89C4\u8303\uFF08JSON\uFF09",
|
|
898
1078
|
" v-cli agent init . --dry-run # \u9884\u89C8\u521D\u59CB\u5316\u76EE\u6807"
|
|
899
1079
|
].join("\n");
|
|
900
1080
|
var DOCS_HELP_TEXT = [
|
|
901
|
-
"\u8F93\u51FA
|
|
1081
|
+
"\u8F93\u51FA AGENTS.md \u539F\u6587\uFF08\u9010\u5B57\u8282\u539F\u6837\u8F93\u51FA\u3001\u4E0D\u8FFD\u52A0\u6362\u884C\uFF09\u3002",
|
|
1082
|
+
" \u7701\u7565 [command]\uFF1A\u5F53\u524D @kevlns/v-cli \u5305\u5185\u7F6E\u7626\u7D22\u5F15\u3002",
|
|
1083
|
+
" \u4F20\u5165 [command]\uFF1A\u5DF2\u5B89\u88C5\u5B98\u65B9\u63D2\u4EF6\u5305\u6839 AGENTS.md\uFF08\u5982 unity / xlmerge\uFF09\u3002",
|
|
1084
|
+
"",
|
|
1085
|
+
"\u53C2\u6570\uFF1A",
|
|
1086
|
+
" [command] official \u63D2\u4EF6\u547D\u4EE4\u540D\uFF1B\u5148\u7528 v-cli agent index --json \u67E5\u770B",
|
|
902
1087
|
"",
|
|
903
1088
|
"JSON \u884C\u4E3A\uFF08--json \u6216\u524D\u7F6E\u5168\u5C40 --json\uFF09\uFF1A",
|
|
904
1089
|
" \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
1090
|
" \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
1091
|
"",
|
|
911
|
-
"\u9000\u51FA\u7801\uFF1A0 \u6210\u529F\uFF1B1 \
|
|
1092
|
+
"\u9000\u51FA\u7801\uFF1A0 \u6210\u529F\uFF1B1 \u547D\u4EE4\u672A\u77E5 / \u63D2\u4EF6\u672A\u5B89\u88C5 / AGENTS.md \u7F3A\u5931\u6216\u4E0D\u53EF\u8BFB",
|
|
912
1093
|
"",
|
|
913
1094
|
"\u793A\u4F8B\uFF1A",
|
|
914
1095
|
" v-cli agent docs",
|
|
915
|
-
" v-cli agent docs
|
|
1096
|
+
" v-cli agent docs unity",
|
|
1097
|
+
" v-cli agent docs xlmerge --json"
|
|
916
1098
|
].join("\n");
|
|
917
1099
|
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\
|
|
1100
|
+
"\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\uFF1B",
|
|
1101
|
+
"\u540C\u65F6\u628A\u968F\u5305\u53D1\u5E03\u7684 v-cli skill\uFF08skills/v-cli\uFF09\u88C5\u914D\u5230 <\u76EE\u5F55> \u4E0B\u5339\u914D\u7684 agent \u6280\u80FD\u76EE\u5F55\uFF08\u5982 .claude/skills\u3001.agent/skill\u3001AgentHome/skills \u7B49\uFF0C\u6E05\u5355\u89C1 src/core/agent-dirs.ts\uFF09\uFF0C\u65E0\u5339\u914D\u76EE\u5F55\u5219\u8DF3\u8FC7\u3002",
|
|
919
1102
|
"",
|
|
920
1103
|
"\u53C2\u6570\uFF1A",
|
|
921
1104
|
" [directory] \u76EE\u6807\u76EE\u5F55\uFF0C\u9ED8\u8BA4\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF1B\u5FC5\u987B\u5DF2\u5B58\u5728\u4E14\u4E3A\u76EE\u5F55",
|
|
@@ -973,21 +1156,21 @@ var agent = {
|
|
|
973
1156
|
},
|
|
974
1157
|
{
|
|
975
1158
|
path: ["docs"],
|
|
976
|
-
usage: "v-cli agent docs [--json]",
|
|
977
|
-
description: "\u8F93\u51FA
|
|
978
|
-
arguments: [],
|
|
1159
|
+
usage: "v-cli agent docs [command] [--json]",
|
|
1160
|
+
description: "\u65E0\u53C2\u8F93\u51FA v-cli AGENTS.md\uFF1B\u4F20 command \u8F93\u51FA\u5B98\u65B9\u63D2\u4EF6\u5305\u5185 AGENTS.md",
|
|
1161
|
+
arguments: [{ name: "command", required: false, description: "\u5B98\u65B9\u63D2\u4EF6\u547D\u4EE4\u540D\uFF08\u5982 unity\u3001xlmerge\uFF09" }],
|
|
979
1162
|
options: [{ flags: "--json", description: "\u8F93\u51FA { package, version, sha256, content }" }],
|
|
980
1163
|
output: {
|
|
981
1164
|
format: "stdout",
|
|
982
1165
|
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
1166
|
},
|
|
984
|
-
exitCodes: { "0": "\u6210\u529F", "1": "\
|
|
1167
|
+
exitCodes: { "0": "\u6210\u529F", "1": "\u547D\u4EE4\u672A\u77E5 / \u63D2\u4EF6\u672A\u5B89\u88C5 / AGENTS.md \u7F3A\u5931\u6216\u4E0D\u53EF\u8BFB" },
|
|
985
1168
|
safety: ["read-only", "no-network"]
|
|
986
1169
|
},
|
|
987
1170
|
{
|
|
988
1171
|
path: ["init"],
|
|
989
1172
|
usage: "v-cli agent init [directory] [--force] [--dry-run] [--json]",
|
|
990
|
-
description: "\
|
|
1173
|
+
description: "\u521D\u59CB\u5316 <\u76EE\u5F55>\uFF1A\u5199\u5165 AGENTS.md \u5E76\u88C5\u914D v-cli skill \u5230\u5339\u914D\u7684 agent \u6280\u80FD\u76EE\u5F55\uFF1B\u9ED8\u8BA4\u5F53\u524D\u76EE\u5F55\uFF1B\u5DF2\u5B58\u5728\u9ED8\u8BA4\u62D2\u7EDD",
|
|
991
1174
|
arguments: [
|
|
992
1175
|
{ 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
1176
|
],
|
|
@@ -998,7 +1181,7 @@ var agent = {
|
|
|
998
1181
|
],
|
|
999
1182
|
output: {
|
|
1000
1183
|
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"
|
|
1184
|
+
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 \u53CA skill \u88C5\u914D\u7ED3\u679C\uFF09"
|
|
1002
1185
|
},
|
|
1003
1186
|
exitCodes: {
|
|
1004
1187
|
"0": "\u6210\u529F\u6216\u5E72\u8DD1",
|
|
@@ -1009,7 +1192,8 @@ var agent = {
|
|
|
1009
1192
|
"refuses-existing",
|
|
1010
1193
|
"fail-closed-symlink",
|
|
1011
1194
|
"dry-run-supported",
|
|
1012
|
-
"no-commit"
|
|
1195
|
+
"no-commit",
|
|
1196
|
+
"assembles-skill"
|
|
1013
1197
|
]
|
|
1014
1198
|
}
|
|
1015
1199
|
]
|
|
@@ -1059,11 +1243,20 @@ var agent = {
|
|
|
1059
1243
|
}
|
|
1060
1244
|
ctx.log.result(lines.join("\n"));
|
|
1061
1245
|
});
|
|
1062
|
-
program.command("docs").description("\u8F93\u51FA
|
|
1246
|
+
program.command("docs").description("\u65E0\u53C2\u8F93\u51FA v-cli AGENTS.md\uFF1B\u4F20 command \u8F93\u51FA\u5B98\u65B9\u63D2\u4EF6\u5305\u5185 AGENTS.md").argument("[command]", "\u5B98\u65B9\u63D2\u4EF6\u547D\u4EE4\u540D\uFF08\u5982 unity\u3001xlmerge\uFF09").option("--json", "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB JSON\uFF08\u542B sha256/content\uFF09").addHelpText("after", DOCS_HELP_TEXT).action((command, opts) => {
|
|
1063
1247
|
const json = ctx.json || opts.json;
|
|
1064
1248
|
let docs;
|
|
1249
|
+
let packageName = BUNDLED_DOCS_PACKAGE;
|
|
1250
|
+
let version = VERSION;
|
|
1065
1251
|
try {
|
|
1066
|
-
|
|
1252
|
+
if (command) {
|
|
1253
|
+
const pluginDocs = readOfficialAgentsMd(command);
|
|
1254
|
+
docs = pluginDocs;
|
|
1255
|
+
packageName = pluginDocs.package;
|
|
1256
|
+
version = pluginDocs.version;
|
|
1257
|
+
} else {
|
|
1258
|
+
docs = readBundledAgentsMd();
|
|
1259
|
+
}
|
|
1067
1260
|
} catch (err) {
|
|
1068
1261
|
const message = err instanceof Error ? err.message : String(err);
|
|
1069
1262
|
if (json) ctx.log.result({ ok: false, error: message });
|
|
@@ -1073,8 +1266,8 @@ var agent = {
|
|
|
1073
1266
|
}
|
|
1074
1267
|
if (json) {
|
|
1075
1268
|
ctx.log.result({
|
|
1076
|
-
package:
|
|
1077
|
-
version
|
|
1269
|
+
package: packageName,
|
|
1270
|
+
version,
|
|
1078
1271
|
sha256: docs.sha256,
|
|
1079
1272
|
content: docs.content
|
|
1080
1273
|
});
|
|
@@ -1095,16 +1288,48 @@ var agent = {
|
|
|
1095
1288
|
process.exitCode = 1;
|
|
1096
1289
|
return;
|
|
1097
1290
|
}
|
|
1291
|
+
const resolvedDir = path6.resolve(directory ?? process.cwd());
|
|
1098
1292
|
const result = performAgentInit({
|
|
1099
|
-
directory:
|
|
1293
|
+
directory: resolvedDir,
|
|
1100
1294
|
docs,
|
|
1101
1295
|
force: opts.force,
|
|
1102
1296
|
dryRun: opts.dryRun,
|
|
1103
1297
|
// 显式传入目录才做目录符号链接/联接 fail-closed;默认 cwd 不受限
|
|
1104
1298
|
explicitDirectory: directory !== void 0
|
|
1105
1299
|
});
|
|
1300
|
+
let skillOutcome;
|
|
1301
|
+
if (result.ok) {
|
|
1302
|
+
try {
|
|
1303
|
+
const source = readSkillSource();
|
|
1304
|
+
const skill = performAgentSkillAssembly({
|
|
1305
|
+
directory: resolvedDir,
|
|
1306
|
+
source,
|
|
1307
|
+
dryRun: opts.dryRun
|
|
1308
|
+
});
|
|
1309
|
+
skillOutcome = skill.assembled.length > 0 ? {
|
|
1310
|
+
status: "assembled",
|
|
1311
|
+
assembled: skill.assembled,
|
|
1312
|
+
name: skill.skill.name,
|
|
1313
|
+
sha256: skill.skill.sha256,
|
|
1314
|
+
bytes: skill.skill.bytes
|
|
1315
|
+
} : {
|
|
1316
|
+
status: "skipped-none",
|
|
1317
|
+
assembled: [],
|
|
1318
|
+
name: skill.skill.name,
|
|
1319
|
+
sha256: skill.skill.sha256,
|
|
1320
|
+
bytes: skill.skill.bytes
|
|
1321
|
+
};
|
|
1322
|
+
} catch (err) {
|
|
1323
|
+
skillOutcome = {
|
|
1324
|
+
status: "skipped-source-missing",
|
|
1325
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
1326
|
+
};
|
|
1327
|
+
}
|
|
1328
|
+
} else {
|
|
1329
|
+
skillOutcome = { status: "skipped-init-failed" };
|
|
1330
|
+
}
|
|
1106
1331
|
if (json) {
|
|
1107
|
-
ctx.log.result(result);
|
|
1332
|
+
ctx.log.result({ ...result, skill: skillOutcome });
|
|
1108
1333
|
if (!result.ok && result.reason) ctx.log.error(result.reason);
|
|
1109
1334
|
if (!result.ok) process.exitCode = 1;
|
|
1110
1335
|
return;
|
|
@@ -1114,15 +1339,8 @@ var agent = {
|
|
|
1114
1339
|
process.exitCode = 1;
|
|
1115
1340
|
return;
|
|
1116
1341
|
}
|
|
1117
|
-
|
|
1118
|
-
|
|
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
|
-
}
|
|
1342
|
+
const head = result.dryRun ? `[dry-run] \u5C06${result.action === "overwrite" ? "\u8986\u76D6" : "\u5199\u5165"} ${result.target}\uFF08${result.bytes} \u5B57\u8282\uFF09` : `\u5DF2${result.action === "overwritten" ? "\u8986\u76D6" : "\u5199\u5165"} ${result.target}\uFF08${result.bytes} \u5B57\u8282\uFF0CSHA-256 ${result.sha256.slice(0, 12)}\u2026\uFF09`;
|
|
1343
|
+
ctx.log.result([head, skillOutcomeText(skillOutcome, result.dryRun)].join("\n"));
|
|
1126
1344
|
}
|
|
1127
1345
|
);
|
|
1128
1346
|
program.addHelpText("after", AGENT_HELP_TEXT);
|
|
@@ -1130,7 +1348,7 @@ var agent = {
|
|
|
1130
1348
|
};
|
|
1131
1349
|
|
|
1132
1350
|
// src/commands/doctor.ts
|
|
1133
|
-
import
|
|
1351
|
+
import fs5 from "fs";
|
|
1134
1352
|
var doctor = {
|
|
1135
1353
|
name: "doctor",
|
|
1136
1354
|
description: "\u4F53\u68C0\uFF1Anode/v-cli \u7248\u672C\u3001homeDir\u3001config\u3001\u63D2\u4EF6\u72B6\u6001",
|
|
@@ -1139,7 +1357,7 @@ var doctor = {
|
|
|
1139
1357
|
program.option("--json", "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB JSON").action(async (opts) => {
|
|
1140
1358
|
const json = ctx.json || opts.json;
|
|
1141
1359
|
const homeDir = ctx.homeDir;
|
|
1142
|
-
const exists =
|
|
1360
|
+
const exists = fs5.existsSync(homeDir);
|
|
1143
1361
|
let configWritable = false;
|
|
1144
1362
|
try {
|
|
1145
1363
|
ctx.config.set((cfg) => cfg);
|
|
@@ -1193,7 +1411,7 @@ var doctor = {
|
|
|
1193
1411
|
};
|
|
1194
1412
|
|
|
1195
1413
|
// src/commands/plugin.ts
|
|
1196
|
-
import
|
|
1414
|
+
import path7 from "path";
|
|
1197
1415
|
var plugin = {
|
|
1198
1416
|
name: "plugin",
|
|
1199
1417
|
description: "\u63D2\u4EF6\u7BA1\u7406\uFF1Alist \u5217\u51FA\u547D\u4EE4\uFF0Cpath \u663E\u793A\u672C\u5730\u63D2\u4EF6\u76EE\u5F55",
|
|
@@ -1232,7 +1450,7 @@ var plugin = {
|
|
|
1232
1450
|
}
|
|
1233
1451
|
});
|
|
1234
1452
|
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) => {
|
|
1235
|
-
const dir =
|
|
1453
|
+
const dir = path7.join(ctx.homeDir, "commands");
|
|
1236
1454
|
if (ctx.json || opts.json) {
|
|
1237
1455
|
ctx.log.result({ dir });
|
|
1238
1456
|
} else {
|
|
@@ -1300,12 +1518,12 @@ async function loadBuiltinCommands() {
|
|
|
1300
1518
|
return builtinCommands.map((command) => ({ command, source: "builtin" }));
|
|
1301
1519
|
}
|
|
1302
1520
|
async function loadLocalPlugins(ctx) {
|
|
1303
|
-
const dir =
|
|
1521
|
+
const dir = path8.join(ctx.homeDir, "commands");
|
|
1304
1522
|
const loaded = [];
|
|
1305
|
-
if (!
|
|
1306
|
-
const files =
|
|
1523
|
+
if (!fs6.existsSync(dir)) return loaded;
|
|
1524
|
+
const files = fs6.readdirSync(dir).filter((f) => f.endsWith(".mjs")).sort();
|
|
1307
1525
|
for (const file of files) {
|
|
1308
|
-
const abs =
|
|
1526
|
+
const abs = path8.join(dir, file);
|
|
1309
1527
|
try {
|
|
1310
1528
|
const mod = await import(
|
|
1311
1529
|
/* @vite-ignore */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kevlns/v-cli",
|
|
3
|
-
"version": "0.2.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "kevlns 的个人工具箱 CLI(插件化架构,内置 + 本地插件)+ doctor/plugin/ts 命令",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist/",
|
|
11
11
|
"schemas/",
|
|
12
|
+
"skills/",
|
|
12
13
|
"AGENTS.md"
|
|
13
14
|
],
|
|
14
15
|
"scripts": {
|
|
@@ -46,8 +47,8 @@
|
|
|
46
47
|
],
|
|
47
48
|
"dependencies": {
|
|
48
49
|
"commander": "^12.1.0",
|
|
49
|
-
"@kevlns/xlmerge": "1.2.1
|
|
50
|
-
"@kevlns/u-cli-mod": "0.1.0
|
|
50
|
+
"@kevlns/xlmerge": "1.2.1",
|
|
51
|
+
"@kevlns/u-cli-mod": "0.1.0"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
54
|
"@types/node": "^20.14.0",
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: v-cli
|
|
3
|
+
description: >
|
|
4
|
+
使用 kevlns 的个人工具箱 CLI(v-cli)处理配置表冲突与 Unity 工程精确版本工具链。当任务提到 v-cli、xlmerge、
|
|
5
|
+
unity 命令、配置表 .xlsx/.xlsm Git 冲突处理、Unity CLI 安装、Unity 工程诊断/体检(doctor)、
|
|
6
|
+
com.unity.pipeline 适配包安装时使用本 skill。
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# v-cli 使用规范
|
|
10
|
+
|
|
11
|
+
## 工具概述
|
|
12
|
+
|
|
13
|
+
- `@kevlns/v-cli` 是 npm 全局安装的个人工具箱 CLI(当前 0.2.0-beta.x),插件化架构。
|
|
14
|
+
- 命令分三类:
|
|
15
|
+
- **builtin**(内置):`doctor`(环境体检)、`plugin list/path`(插件管理)、`ts`(时间戳互转)、`agent index/describe/docs/init`(agent 引导)。
|
|
16
|
+
- **local**:`~/.v-cli/commands/` 下的本地插件(本项目未使用)。
|
|
17
|
+
- **official**(官方插件,经 v-cli 路由):`xlmerge`、`unity`。
|
|
18
|
+
- 环境要求:Node.js >= 20(仅 Windows 主机可使用 `unity` 插件,其他平台 v-cli 拒绝路由)。
|
|
19
|
+
|
|
20
|
+
## 能力发现协议(核心规则,必须遵守)
|
|
21
|
+
|
|
22
|
+
**一切能力、参数、用法以 v-cli 自己的 agent 命令输出为准,严禁无头搜索 npm 安装目录、源码或 README 猜测用法。**
|
|
23
|
+
|
|
24
|
+
- `v-cli agent docs` — 输出 v-cli 内置 AGENTS.md(宿主规范全文;`--json` 含 sha256/content)。
|
|
25
|
+
- `v-cli agent index --json` — 枚举全部命令(builtin/local/official)与 agent 元数据,获取最新命令集合。
|
|
26
|
+
- `v-cli agent describe <命令名> --json` — 单个命令的完整记录:用法、参数、选项、输出格式、退出码、安全标签。
|
|
27
|
+
- `v-cli agent docs <命令名>` — 输出官方插件包内 AGENTS.md(该插件的使用规范正本)。
|
|
28
|
+
- `v-cli agent init .` — 可选:把内置 AGENTS.md 写入工作区(已存在默认拒绝,`--force` 覆盖,`--dry-run` 预览)。
|
|
29
|
+
- live 命令集合以实际发现为准:先 `agent index --json`,再对目标命令 `agent describe <命令> --json`。
|
|
30
|
+
|
|
31
|
+
## 首调规范
|
|
32
|
+
|
|
33
|
+
**首次调用任何 official 插件命令(`v-cli xlmerge …`、`v-cli unity …`)前,必须先运行 `v-cli agent docs <命令名>` 读取该插件包内的 AGENTS.md 规范正本。** 使用规范、快速流程与禁止事项以插件自身 AGENTS.md 为准。
|
|
34
|
+
|
|
35
|
+
官方插件命令在子进程中运行(stdio 继承):v-cli 只做路由,不解析、不改写插件输出;插件 `--help`/`--json` 等参数由插件自己消费。插件对 worktree 的写入/提交行为以插件清单的安全标签为准;**未经显式 flag 不得 push**。
|
|
36
|
+
|
|
37
|
+
## 官方插件一:xlmerge(跨平台)
|
|
38
|
+
|
|
39
|
+
Git 中 `.xlsx` / `.xlsm` 策划表/配置表冲突的可视化解决工具。
|
|
40
|
+
|
|
41
|
+
- 流程:
|
|
42
|
+
1. `v-cli xlmerge --repo <仓库路径> detect` — 检测冲突。
|
|
43
|
+
2. 冲突数 > 0 时运行 `launch`,**把返回的 URL 交给用户在本地 UI 处理**。
|
|
44
|
+
- **agent 不得自行检查工作簿单元格、不得自己总结 diff**:resolver 拥有 diff、选择、写回与提交。
|
|
45
|
+
- 用户要求「解决配置表冲突」时:先 detect;count > 0 时 launch 并给出 URL。
|
|
46
|
+
|
|
47
|
+
## 官方插件二:unity(仅 win32)
|
|
48
|
+
|
|
49
|
+
Unity 2022 工程**精确版本路由**(版本号 + revision 双重匹配)+ 下载经验证的 Unity CLI(SHA-256 + Authenticode)+ 事务式安装适配版 `com.unity.pipeline` 包。
|
|
50
|
+
|
|
51
|
+
### 核心命令
|
|
52
|
+
|
|
53
|
+
| 命令 | 说明 |
|
|
54
|
+
|---|---|
|
|
55
|
+
| `v-cli unity doctor <project>` | 只读体检:路由匹配 / CLI 状态 / Pipeline 状态 / 运行中的 Unity 进程 / 支持版本列表 |
|
|
56
|
+
| `v-cli unity setup <project>` | CLI + 适配包一键就绪(**推荐首次入口**,等价 cli install + pipeline install;`--dry-run` 预览、`--skip-cli` 跳过下载) |
|
|
57
|
+
| `v-cli unity pipeline install <project>` | 事务式安装适配包(staging → 校验 → 备份 → 替换 → 再校验 → receipt,失败自动回滚;`--dry-run` 只预览不写入) |
|
|
58
|
+
| `v-cli unity cli install` | 下载并校验固定版本 Unity CLI(`--editor <版本>` 限定、`--force` 重下) |
|
|
59
|
+
| `v-cli unity exec <project> -- <unity-cli-args>` | 调用路由 CLI 执行 Unity Pipeline 命令 |
|
|
60
|
+
| `v-cli unity routes` | 列出所有已配置的 Editor 精确路由(`-e <版本>` 过滤) |
|
|
61
|
+
| `v-cli unity cache clean` | 清理下载缓存与生成的适配包(`--all` 连 CLI 缓存一起清) |
|
|
62
|
+
|
|
63
|
+
### 关键规则(违反即报错或导致损坏,必须遵守)
|
|
64
|
+
|
|
65
|
+
1. **exec 前必须 doctor 通过且适配包已安装**(setup 或 pipeline install 已完成);未就绪时先跑 setup,不要直接 exec。
|
|
66
|
+
2. **禁止在 exec 参数中传入任何 `--project-path` 变体**(`-projectPath`、`--project_path`、大小写混合、`=` 形式等):目标工程由工具统一绑定,exec 会拒绝所有变体并把解析后的 `--project-path` 作为最后一个参数附加;`--` 分隔符被包装器消费,不转发给 Unity CLI。
|
|
67
|
+
3. **运行中的 Unity Editor 是 fail-closed**:安装被阻止时引导用户先关闭目标工程的 Editor;**除非用户显式要求,不得使用 `--allow-running-editor` 绕过**。
|
|
68
|
+
4. **安装是事务式的**:不要手动清理工程内 `Packages/com.unity.pipeline` 或 `Library/editor-pipeline-cli`;失败会自动回滚,人为清理会破坏回滚与 receipt 校验。
|
|
69
|
+
5. **版本路由是精确匹配**(`m_EditorVersion` + revision 同时一致),无"就近版本"回退;工程版本不在路由表内时如实报告支持列表(`doctor` 输出的 `supportedVersions`),不得猜测、不得改写 `ProjectVersion.txt`。
|
|
70
|
+
6. **exec 每次调用前都会重新校验 CLI 哈希**(防篡改,属正常行为);校验失败按提示 `v-cli unity cli install --force` 修复即可。
|
|
71
|
+
|
|
72
|
+
## 典型流程
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
v-cli agent docs unity # 首调前必读插件规范正本
|
|
76
|
+
v-cli unity doctor <project> # 1. 体检(只读)
|
|
77
|
+
v-cli unity setup <project> --dry-run # 2.(可选)先预览
|
|
78
|
+
v-cli unity setup <project> # 3. 就绪(CLI + 适配包)
|
|
79
|
+
v-cli unity exec <project> -- command editor_status # 4. 执行 Pipeline 命令
|
|
80
|
+
```
|