@kevlns/v-cli 0.2.6 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -7,13 +7,14 @@
7
7
 
8
8
  ## 核心约定(v-cli 本体)
9
9
 
10
- - 环境要求 Node.js >= 20;v-cli 版本 @kevlns/v-cli@0.2.6
10
+ - 环境要求 Node.js >= 20;v-cli 版本 @kevlns/v-cli@0.2.8
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
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),无匹配则跳过
16
+ 同时把随包发布的 v-cli skill(skills/v-cli)装配到 <目录> 下匹配的 agent 技能目录(如 .claude/skills、.agent/skill、AgentHome/skills 等,清单见 src/core/agent-dirs.ts),无匹配则跳过;
17
+ 已有 skill 且其 SKILL.md 与随包版本不同(项目侧已按实时命令面回补)时默认保留本地版本,只有 `--force` 才会用随包版本替换
17
18
  - **首次调用规范**:首次调用任何 official 插件命令前,必须先运行 `v-cli agent docs <命令名>`,
18
19
  掌握该插件包内 `AGENTS.md`;使用规范、快速流程与禁止事项以插件 AGENTS.md 为准。
19
20
  - 官方插件命令(`v-cli xlmerge …`、`v-cli unity …`)在子进程中运行(stdio 继承):v-cli 只做路由,
@@ -23,7 +24,7 @@
23
24
 
24
25
  ## @kevlns/u-cli-mod — 命令 `v-cli unity …`
25
26
 
26
- **版本**:0.1.4
27
+ **版本**:0.2.0
27
28
  **描述**: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).
28
29
  **平台**:win32(仅 Windows 主机可用;非 Windows 上 v-cli 会拒绝路由)
29
30
 
package/README.md CHANGED
@@ -84,7 +84,7 @@ v-cli xlmerge --repo <repo> detect # 路由到 xlmerge 子进程
84
84
  v-cli xlmerge --repo <repo> resolve
85
85
 
86
86
  # Unity 工具链(仅 Windows 主机可用;其他平台 v-cli 会拒绝路由并说明原因)
87
- npm install -g @kevlns/u-cli-mod@0.1.4
87
+ npm install -g @kevlns/u-cli-mod@0.2.0
88
88
  v-cli unity doctor <project>
89
89
  ```
90
90
 
@@ -202,7 +202,7 @@ npm run test:package # 发布后安装冒烟:npm pack → 隔离 prefix
202
202
  npm run check # build + typecheck + test + check:agents + pack:guard
203
203
  ```
204
204
 
205
- > `@kevlns/xlmerge@2.0.0` / `@kevlns/u-cli-mod@0.1.4` 已发布并由 `npm install`
205
+ > `@kevlns/xlmerge@2.0.0` / `@kevlns/u-cli-mod@0.2.0` 已发布并由 `npm install`
206
206
  > 装入仓库 node_modules:`generate:agents`/`check:agents` 的默认(installed-deps)检查即为
207
207
  > 最终形态,`npm run check` 因此才能全绿,CI 的 `check:agents` 步骤也随之总是生效
208
208
  > (不依赖 sibling 仓库检出;若未来仍需要在预发布阶段以 sibling 清单 bootstrap,
@@ -214,9 +214,9 @@ kevlns 工具家族共享同一套发布约定(tag 驱动、CI 护栏、MIT)
214
214
 
215
215
  | Package | Purpose | Status |
216
216
  | --- | --- | --- |
217
- | [`v-cli`](https://github.com/kevlns/v-cli) | 个人工具箱 CLI(本仓库) | v0.2.6 |
217
+ | [`v-cli`](https://github.com/kevlns/v-cli) | 个人工具箱 CLI(本仓库) | v0.2.8 |
218
218
  | [`xlmerge`](https://github.com/kevlns/xlmerge) | Git 中 .xlsx/.xlsm 冲突可视化解决工具 | v2.0.0 |
219
- | [`u-cli-mod`](https://github.com/kevlns/u-cli-mod) | Unity 精确版本路由 + CLI + pipeline 包(Windows-first) | v0.1.4 |
219
+ | [`u-cli-mod`](https://github.com/kevlns/u-cli-mod) | Unity 精确版本路由 + CLI + pipeline 包(Windows-first) | v0.2.0 |
220
220
 
221
221
  ## Compatibility
222
222
 
@@ -249,4 +249,4 @@ Released under the [MIT License](./LICENSE).
249
249
 
250
250
  Part of the **kevlns** tool family.
251
251
 
252
- </div>
252
+ </div>
package/dist/cli.mjs CHANGED
@@ -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.6";
630
+ var VERSION = "0.2.8";
631
631
 
632
632
  // src/core/agent-docs.ts
633
633
  var BUNDLED_DOCS_FILE = "AGENTS.md";
@@ -930,8 +930,17 @@ function copySkillDir(srcRoot, destDir) {
930
930
  fs4.rmSync(destDir, { recursive: true, force: true });
931
931
  fs4.cpSync(srcRoot, destDir, { recursive: true });
932
932
  }
933
+ function readSkillFileAt(targetDir) {
934
+ try {
935
+ const file = path5.join(targetDir, SKILL_FILE);
936
+ if (!fs4.lstatSync(file).isFile()) return void 0;
937
+ return fs4.readFileSync(file, "utf-8");
938
+ } catch {
939
+ return void 0;
940
+ }
941
+ }
933
942
  function performAgentSkillAssembly(opts) {
934
- const { directory, source, dryRun = false } = opts;
943
+ const { directory, source, dryRun = false, force = false } = opts;
935
944
  const base = {
936
945
  ok: true,
937
946
  dryRun,
@@ -951,18 +960,17 @@ function performAgentSkillAssembly(opts) {
951
960
  const hits = collectAgentSkillDirs(directory);
952
961
  for (const dir of hits) {
953
962
  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;
963
+ const existing = readSkillFileAt(target);
964
+ const exists = existing !== void 0;
965
+ if (exists && existing !== source.content && !force) {
966
+ base.assembled.push({ dir, target, action: "kept", overwrite: false });
967
+ continue;
960
968
  }
961
969
  const action = dryRun ? "assemble" : "assembled";
962
970
  if (!dryRun) {
963
971
  copySkillDir(source.root, target);
964
972
  }
965
- base.assembled.push({ dir, target, action, overwrite });
973
+ base.assembled.push({ dir, target, action, overwrite: exists });
966
974
  }
967
975
  return base;
968
976
  }
@@ -975,6 +983,10 @@ function skillOutcomeText(outcome, dryRun) {
975
983
  const dirs = outcome.assembled.map((t) => t.dir).join(", ");
976
984
  return `[skill v-cli] ${verb} ${outcome.assembled.length} \u4E2A agent \u76EE\u5F55\uFF1A${dirs}`;
977
985
  }
986
+ case "kept": {
987
+ const dirs = outcome.assembled.map((t) => t.dir).join(", ");
988
+ return `[skill v-cli] \u4FDD\u7559\u672C\u5730\u5DF2\u4FEE\u6539\u7248\u672C\uFF08\u672A\u8986\u76D6\uFF09\uFF1A${dirs}\uFF1B\u5982\u9700\u7528\u968F\u5305\u7248\u672C\u8986\u76D6\u8BF7\u52A0 --force`;
989
+ }
978
990
  case "skipped-none":
979
991
  return "[skill v-cli] \u672A\u68C0\u6D4B\u5230\u5339\u914D\u7684 agent \u6280\u80FD\u76EE\u5F55\uFF0C\u8DF3\u8FC7\u88C5\u914D";
980
992
  case "skipped-source-missing":
@@ -1104,7 +1116,9 @@ var INIT_HELP_TEXT = [
1104
1116
  " [directory] \u76EE\u6807\u76EE\u5F55\uFF0C\u9ED8\u8BA4\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF1B\u5FC5\u987B\u5DF2\u5B58\u5728\u4E14\u4E3A\u76EE\u5F55",
1105
1117
  "",
1106
1118
  "\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",
1107
- " --force \u8986\u76D6\u5DF2\u5B58\u5728\u7684 AGENTS.md\uFF08\u539F\u5B50\u5199\u5165\uFF1A\u540C\u76EE\u5F55\u4E34\u65F6\u6587\u4EF6 + rename\uFF09",
1119
+ " --force \u8986\u76D6\u5DF2\u5B58\u5728\u7684 AGENTS.md \u4E0E\u672C\u5730\u5DF2\u4FEE\u6539\u7684 skill\uFF08\u539F\u5B50\u5199\u5165\uFF1A\u540C\u76EE\u5F55\u4E34\u65F6\u6587\u4EF6 + rename\uFF09",
1120
+ " skill \u4FDD\u62A4 \u5DF2\u6709 skill \u4E14\u5185\u5BB9\u4E0E\u968F\u5305\u7248\u672C\u4E0D\u540C\uFF08\u9879\u76EE\u4FA7\u5DF2\u56DE\u8865\uFF09\u65F6\u9ED8\u8BA4\u4FDD\u7559\u4E0D\u8986\u76D6\uFF0C\u53EA\u6709 --force \u624D\u4F1A\u66FF\u6362\uFF1B",
1121
+ " \u5185\u5BB9\u4E00\u81F4\u65F6\u6B63\u5E38\u8986\u76D6\u4FDD\u6301\u4E00\u81F4\u3002",
1108
1122
  " --dry-run \u53EA\u62A5\u544A\u76EE\u6807\u4E0E\u5C06\u6267\u884C\u7684\u52A8\u4F5C\uFF0C\u4E0D\u5199\u5165\u4EFB\u4F55\u6587\u4EF6",
1109
1123
  " --json \u6210\u529F/\u5E72\u8DD1\u8F93\u51FA\u7A33\u5B9A JSON { ok, dryRun, action, directory, target, package, version, sha256, bytes }\uFF1B",
1110
1124
  ' \u62D2\u7EDD\uFF08\u5982\u5DF2\u5B58\u5728\u672A\u52A0 --force\uFF09\u8F93\u51FA { ok: false, action: "refused", reason, \u2026 } \u4E14\u9000\u51FA 1\uFF1B',
@@ -1175,7 +1189,7 @@ var agent = {
1175
1189
  { 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" }
1176
1190
  ],
1177
1191
  options: [
1178
- { flags: "--force", description: "\u8986\u76D6\u5DF2\u5B58\u5728 AGENTS.md\uFF08\u539F\u5B50\u5199\u5165\uFF09" },
1192
+ { flags: "--force", description: "\u8986\u76D6\u5DF2\u5B58\u5728\u7684 AGENTS.md \u4E0E\u672C\u5730\u5DF2\u4FEE\u6539\u7684 skill\uFF08\u539F\u5B50\u5199\u5165\uFF09" },
1179
1193
  { flags: "--dry-run", description: "\u53EA\u62A5\u544A\u76EE\u6807\u4E0E\u52A8\u4F5C\uFF0C\u4E0D\u5199\u5165" },
1180
1194
  { flags: "--json", description: "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB\u7ED3\u679C" }
1181
1195
  ],
@@ -1275,7 +1289,7 @@ var agent = {
1275
1289
  }
1276
1290
  process.stdout.write(docs.content);
1277
1291
  });
1278
- 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(
1292
+ 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 \u4E0E\u672C\u5730\u5DF2\u4FEE\u6539\u7684 skill\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(
1279
1293
  (directory, opts) => {
1280
1294
  const json = ctx.json || opts.json;
1281
1295
  let docs;
@@ -1304,10 +1318,12 @@ var agent = {
1304
1318
  const skill = performAgentSkillAssembly({
1305
1319
  directory: resolvedDir,
1306
1320
  source,
1307
- dryRun: opts.dryRun
1321
+ dryRun: opts.dryRun,
1322
+ force: opts.force
1308
1323
  });
1324
+ const keptOnly = skill.assembled.length > 0 && skill.assembled.every((t) => t.action === "kept");
1309
1325
  skillOutcome = skill.assembled.length > 0 ? {
1310
- status: "assembled",
1326
+ status: keptOnly ? "kept" : "assembled",
1311
1327
  assembled: skill.assembled,
1312
1328
  name: skill.skill.name,
1313
1329
  sha256: skill.skill.sha256,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kevlns/v-cli",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "kevlns 的个人工具箱 CLI(插件化架构,内置 + 本地插件)+ doctor/plugin/ts 命令",
5
5
  "type": "module",
6
6
  "bin": {
@@ -46,7 +46,7 @@
46
46
  "personal"
47
47
  ],
48
48
  "dependencies": {
49
- "@kevlns/u-cli-mod": "0.1.4",
49
+ "@kevlns/u-cli-mod": "0.2.0",
50
50
  "@kevlns/xlmerge": "2.0.0",
51
51
  "commander": "^12.1.0"
52
52
  },
@@ -59,4 +59,4 @@
59
59
  "allowScripts": {
60
60
  "esbuild@0.27.2": true
61
61
  }
62
- }
62
+ }
@@ -3,19 +3,19 @@ name: v-cli
3
3
  description: >
4
4
  使用 kevlns 的个人工具箱 CLI(v-cli)处理配置表冲突与 Unity 工程精确版本工具链。当任务提到 v-cli、xlmerge、
5
5
  unity 命令、配置表 .xlsx/.xlsm Git 冲突处理、Unity CLI 安装、Unity 工程诊断/体检(doctor)、
6
- com.unity.pipeline 适配包安装时使用本 skill。
6
+ com.unity.pipeline 适配包安装、v-cli agent init 工作区初始化时使用本 skill。
7
7
  ---
8
8
 
9
9
  # v-cli 使用规范
10
10
 
11
11
  ## 工具概述
12
12
 
13
- - `@kevlns/v-cli` 是 npm 全局安装的个人工具箱 CLI(当前 0.2.0-beta.x),插件化架构。
13
+ - `@kevlns/v-cli` 是 npm 全局安装的个人工具箱 CLI,插件化架构;环境要求 Node.js >= 20(`unity` 插件仅 win32,其他平台 v-cli 拒绝路由)。
14
14
  - 命令分三类:
15
15
  - **builtin**(内置):`doctor`(环境体检)、`plugin list/path`(插件管理)、`ts`(时间戳互转)、`agent index/describe/docs/init`(agent 引导)。
16
- - **local**:`~/.v-cli/commands/` 下的本地插件(本项目未使用)。
16
+ - **local**:`~/.v-cli/commands/` 下的本地插件。
17
17
  - **official**(官方插件,经 v-cli 路由):`xlmerge`、`unity`。
18
- - 环境要求:Node.js >= 20(仅 Windows 主机可使用 `unity` 插件,其他平台 v-cli 拒绝路由)。
18
+ - **本文件不写死任何版本号**:v-cli 本体与官方插件的实际版本、命令集合、参数一律以 `v-cli doctor` 与 `v-cli agent index --json` 的实时输出为准。
19
19
 
20
20
  ## 能力发现协议(核心规则,必须遵守)
21
21
 
@@ -25,7 +25,6 @@ description: >
25
25
  - `v-cli agent index --json` — 枚举全部命令(builtin/local/official)与 agent 元数据,获取最新命令集合。
26
26
  - `v-cli agent describe <命令名> --json` — 单个命令的完整记录:用法、参数、选项、输出格式、退出码、安全标签。
27
27
  - `v-cli agent docs <命令名>` — 输出官方插件包内 AGENTS.md(该插件的使用规范正本)。
28
- - `v-cli agent init .` — 可选:把内置 AGENTS.md 写入工作区(已存在默认拒绝,`--force` 覆盖,`--dry-run` 预览)。
29
28
  - live 命令集合以实际发现为准:先 `agent index --json`,再对目标命令 `agent describe <命令> --json`。
30
29
 
31
30
  ## 首调规范
@@ -34,15 +33,31 @@ description: >
34
33
 
35
34
  官方插件命令在子进程中运行(stdio 继承):v-cli 只做路由,不解析、不改写插件输出;插件 `--help`/`--json` 等参数由插件自己消费。插件对 worktree 的写入/提交行为以插件清单的安全标签为准;**未经显式 flag 不得 push**。
36
35
 
36
+ ## 工程初始化(agent init)
37
+
38
+ - `v-cli agent init [目录] [--force] [--dry-run] [--json]`:把内置 AGENTS.md 写入工作区,并把随包的 v-cli skill 装配到该目录下匹配的 agent 技能目录(如 `.claude/skills`、`.agent/skill`、`AgentHome/skills` 等,清单见 `src/core/agent-dirs.ts`);无匹配目录则跳过。
39
+ - **强制约束**:只能在本仓 Git 根目录执行,先 `git rev-parse --show-toplevel` 定位并切换到根,禁止在任何子目录执行。
40
+ - 命中以下任一场景必须执行一次:① `v-cli` 未安装(先确认 Node.js >= 20 与 npm 可用,`npm install -g @kevlns/v-cli`,用 `v-cli --version` 与 `v-cli agent index --json` 验证);② 项目内 skill(`<技能目录>/v-cli/SKILL.md`)缺失。两个场景同时命中只执行一次;命令用单数 `agent`,不得写成 `v-cli agents …`。
41
+ - 产物与归属:
42
+ - 根 `AGENTS.md` 为**工具生成物**(建议纳入 `.gitignore`),禁止手改;需要更新内容时升级 v-cli 后重跑 init。
43
+ - 分支不变式(实测):① `AGENTS.md` 不存在 → 写入它**并**装配 skill;② `AGENTS.md` 已存在且未加 `--force` → **整体拒绝**(`action=refused`、`skill.status=skipped-init-failed`),不做任何改动;`--force` 会同时覆盖两者。
44
+ - **skill 保护**:命中目录下已有 `v-cli/SKILL.md` 且内容与随包版本**不同**(项目侧已按实时命令面回补)时,默认**保留本地版本**(`action=kept`)而不覆盖;内容一致时正常覆盖;只有 `--force` 才会用随包版本替换本地版本。因此项目侧正本不会因日常 init 而降级。
45
+ - 先 `--dry-run --json` 预览目标与动作(含 `skill.assembled[].action` 与 `overwrite`),再实际写入。
46
+
37
47
  ## 官方插件一:xlmerge(跨平台)
38
48
 
39
- Git 中 `.xlsx` / `.xlsm` 策划表/配置表冲突的可视化解决工具。
49
+ Git 中 `.xlsx` / `.xlsm` 策划表/配置表冲突的公式感知可视化解决工具(三向 Sheet/行/列/Cell diff + 本地 UI + 原子写回与提交)。
40
50
 
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。
51
+ - 命令面:`detect`、`filter add`、`prepare`、`resolve`、`launch`、`apply`(参数以 `v-cli agent describe xlmerge --json` 为准)。
52
+ - 正常流程(只做命令路由,不做表格分析):
53
+ 1. `v-cli xlmerge --repo <仓库路径> detect` — 只读检测,返回 `count` / `reviewCount` / `autoTheirs` / `conflicts`。
54
+ 2. `count > 0` 时 `v-cli xlmerge --repo <仓库路径> launch`(不传 `--path`,整批处理):
55
+ - `reviewCount > 0`:把返回的 `url` 交给用户,**停止分析**,等用户在页面完成选择。
56
+ - `reviewCount == 0`:不启动 UI,按过滤项写回并提交,报告其 JSON 结果。
57
+ 3. `count == 0`:报告无未解决冲突并结束。
58
+ - 硬性边界:不检查工作簿 Cell、不自行三方 diff、不总结冲突、不替用户选 ours/theirs、不因冲突量大而进入计划模式;**禁用阻塞式 `resolve` 作为正常入口**;`launch --no-browser` + `prepare`/`apply` 的无头链路仅限自动化测试或用户明确给出决策 JSON;`apply` 默认写回并 commit,`--no-commit` 仅用于测试,`--push` 仅在用户明确要求时。
59
+ - 仅处理单个文件时用 `launch --path <仓库相对路径>`;多文件禁止按文件循环调用。
60
+ - `filter add <path>` 会把规范化相对路径写入仓库根 `.xlmerge.json` 的 `autoTheirs`(幂等、大小写不敏感),命中项不进 UI,直接逐字节采用 Git index stage 3。**仅在用户明确要求某类生成表始终取远端整表时添加**。
46
61
 
47
62
  ## 官方插件二:unity(仅 win32)
48
63
 
@@ -52,29 +67,66 @@ Unity 2022 工程**精确版本路由**(版本号 + revision 双重匹配)+
52
67
 
53
68
  | 命令 | 说明 |
54
69
  |---|---|
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` 只预览不写入) |
70
+ | `v-cli unity doctor <project>` | 只读体检:路由 / CLI 状态 / 适配包状态 / 运行中的 Unity 进程 / 支持版本列表 |
71
+ | `v-cli unity setup <project>` | CLI + 适配包一键就绪(**首次入口推荐**,等价 cli install + pipeline install;`--dry-run` 预览、`--skip-cli` 跳过下载) |
72
+ | `v-cli unity pipeline install <project>` | 事务式安装适配包(staging → 校验 → 备份 → 替换 → 再校验 → receipt,失败自动回滚;`--dry-run` 只预览、`--force` 覆盖不一致的现有包) |
58
73
  | `v-cli unity cli install` | 下载并校验固定版本 Unity CLI(`--editor <版本>` 限定、`--force` 重下) |
59
- | `v-cli unity exec <project> -- <unity-cli-args>` | 调用路由 CLI 执行 Unity Pipeline 命令 |
74
+ | `v-cli unity exec <project> [--wait <秒>] -- <unity-cli-args>` | 调用路由 CLI 执行 Unity Pipeline 命令(命令全集见 `v-cli agent docs unity`) |
60
75
  | `v-cli unity routes` | 列出所有已配置的 Editor 精确路由(`-e <版本>` 过滤) |
61
76
  | `v-cli unity cache clean` | 清理下载缓存与生成的适配包(`--all` 连 CLI 缓存一起清) |
62
77
 
78
+ ### exec 前的就绪判据(必须全部满足)
79
+
80
+ - `doctor.cli.state == "valid"`;
81
+ - `doctor.pipeline.installed == true` **且** `doctor.pipeline.state == "current"`(`installedPatchVersion == patchVersion`)。
82
+
83
+ 误判陷阱:`doctor` 退出码 0 只表示诊断完成;`pipeline.present == true` 只表示目录存在;升级 npm 包**不会**自动更新工程内适配包。未就绪一律先 `setup`,不得直接 `exec`。
84
+
85
+ 就绪后的最后一道前提:`exec` 连接的是**已打开并加载适配包的目标工程 Editor**;Editor 未启动时报 `No Pipeline instance found for project: …`,这属于"未启动 Editor",不是适配未就绪,**不得**因此重跑安装或绕过校验。
86
+
87
+ ### 状态处置
88
+
89
+ | state | 处置 |
90
+ |---|---|
91
+ | `missing` | `v-cli unity setup <project>`(或 `pipeline install`) |
92
+ | `outdated` / `invalid` | 先关闭目标工程 Editor,再 `v-cli unity pipeline install <project> --force`(自动备份,备份与 receipt 都在 `Library/editor-pipeline-cli/`,已被 gitignore) |
93
+ | `current` | 可直接 `exec` |
94
+
95
+ receipt 属工程本地生成物:新克隆 / 清理 Library 后即使 `Packages/com.unity.pipeline` 已入库且文件树完好,`state` 仍会是 `invalid`,需按上一行重装一次补齐 receipt。
96
+
63
97
  ### 关键规则(违反即报错或导致损坏,必须遵守)
64
98
 
65
- 1. **exec 前必须 doctor 通过且适配包已安装**(setup 或 pipeline install 已完成);未就绪时先跑 setup,不要直接 exec。
99
+ 1. **exec 前必须满足上述就绪判据**;未就绪时先 setup,不要直接 exec。
66
100
  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`。
101
+ 3. **运行中的 Editor 是 fail-closed 保护,判定对象是「目标工程自己的」Editor 进程**;其他工程实例在跑不阻塞安装。被阻止时引导用户先关闭目标工程 Editor,**除非用户显式要求,不得使用 `--allow-running-editor` 绕过**。
102
+ 4. **安装是事务式的**:不要手动清理工程内 `Packages/com.unity.pipeline` 或 `Library/editor-pipeline-cli`;失败会自动回滚,人为清理会破坏回滚与 receipt 校验。写入范围仅这两个目录。
103
+ 5. **版本路由是精确匹配**(`m_EditorVersion` + revision 同时一致,以 `ProjectVersion.txt` 为准),无"就近版本"回退;工程版本不在路由表内时如实报告 `doctor` 输出的 `supportedVersions`,不得猜测、不得改写 `ProjectVersion.txt`。
70
104
  6. **exec 每次调用前都会重新校验 CLI 哈希**(防篡改,属正常行为);校验失败按提示 `v-cli unity cli install --force` 修复即可。
105
+ 7. **读取 Editor 当前 Console 首选 `command read_console`**;`get_console_logs` 是兼容别名,`command console` 是回调捕获流,适合 cursor/since 跟随,不能替代原生 Console 快照。若 schema 中缺 `read_console`,先核对 `doctor` 的 `patchVersion`/`installedPatchVersion`/`state`,不要把它当成 `console` 的别名。
106
+ 8. 工程内适配包已随仓入库;工具重装写出的文件树与仓库版本一致时(行尾由 `.gitattributes` 归一)**不应产生 git diff**,若出现大面积 diff 应先判定为行尾/编码现象再复核内容,不得据此手工回滚适配包。
107
+
108
+ ### 长任务命令:启动即让出,用状态命令轮询
109
+
110
+ - u-cli-mod **0.2.0 起接管等待预算**:`run_tests` 这类同步长任务默认只等 **5 秒**,到点后任务仍在 Editor 内继续执行,工具打印输出日志路径(`<工程>/Library/editor-pipeline-cli/exec-logs/*.log`)并立即返回(退出码 0),不再有 30s 白等。
111
+ - 让出后**不要重复发起同一命令**,改用状态命令轮询:测试 `-- command test_status`(直到读到 `summary`),烘焙 `-- command <xxx>_bake_status`。
112
+ - 需要同步拿到完整 `Summary` 时用 `--wait <秒>` 扩大等待(写在 `--` 之前,u-cli-mod 自行剥离,不会透传给 Unity CLI);`--wait 0` = 立即返回。
113
+ - **优先缩小范围**(最省事):`run_tests --mode EditMode --filter <命名空间或测试类>` 通常数秒内就同步返回完整 `Summary`,无需轮询。
114
+ - 让出后任务仍在跑,不要重复发起;如需取消用 `-- command cancel_tests`(运行中可能被拒,稍后重试)。
115
+ - 若仍见到 `Pipeline command 'run_tests' timed out after 30000ms`,说明本机 v-cli/u-cli-mod 尚未升级到 0.2.0;升级后该提示消失。
71
116
 
72
117
  ## 典型流程
73
118
 
74
119
  ```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
- ```
120
+ v-cli doctor # 0. 本机环境体检(版本、插件可用性)
121
+ v-cli agent init . --dry-run --json # 1.(工程根)预览初始化动作
122
+ v-cli agent init . # 2. 写入 AGENTS.md + 装配 skill
123
+ v-cli agent docs unity # 3. 首调前必读插件规范正本
124
+ v-cli unity doctor <project> # 4. 体检(只读)判就绪
125
+ v-cli unity setup <project> --dry-run # 5.(可选)先预览
126
+ v-cli unity setup <project> # 6. 就绪(CLI + 适配包 + receipt)
127
+ v-cli unity exec <project> -- command editor_status # 7. 执行 Pipeline 命令
128
+ v-cli unity exec <project> -- command read_console --types error,warning --count 100
129
+ v-cli unity exec <project> -- command run_tests --mode EditMode --filter <类名> # 8. 测试(小范围同步返回)
130
+ v-cli xlmerge --repo . detect # 配置表:只读检测
131
+ v-cli xlmerge --repo . launch # 有冲突时启动本地 UI,把 url 交给用户
132
+ ```