@kevlns/v-cli 0.2.8 → 0.2.10

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,14 +7,14 @@
7
7
 
8
8
  ## 核心约定(v-cli 本体)
9
9
 
10
- - 环境要求 Node.js >= 20;v-cli 版本 @kevlns/v-cli@0.2.8
10
+ - 环境要求 Node.js >= 20;v-cli 版本 @kevlns/v-cli@0.2.10
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
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
+ 随包版本是规范唯一权威:同名 SKILL.md 一律按随包版本刷新(本地修改会被覆盖并提示);随包没有的文件(项目扩展,如 PROJECT.md)默认保留,`--force` 时完全同步
18
18
  - **首次调用规范**:首次调用任何 official 插件命令前,必须先运行 `v-cli agent docs <命令名>`,
19
19
  掌握该插件包内 `AGENTS.md`;使用规范、快速流程与禁止事项以插件 AGENTS.md 为准。
20
20
  - 官方插件命令(`v-cli xlmerge …`、`v-cli unity …`)在子进程中运行(stdio 继承):v-cli 只做路由,
package/README.md CHANGED
@@ -214,7 +214,7 @@ 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.8 |
217
+ | [`v-cli`](https://github.com/kevlns/v-cli) | 个人工具箱 CLI(本仓库) | v0.2.10 |
218
218
  | [`xlmerge`](https://github.com/kevlns/xlmerge) | Git 中 .xlsx/.xlsm 冲突可视化解决工具 | v2.0.0 |
219
219
  | [`u-cli-mod`](https://github.com/kevlns/u-cli-mod) | Unity 精确版本路由 + CLI + pipeline 包(Windows-first) | v0.2.0 |
220
220
 
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.8";
630
+ var VERSION = "0.2.10";
631
631
 
632
632
  // src/core/agent-docs.ts
633
633
  var BUNDLED_DOCS_FILE = "AGENTS.md";
@@ -926,9 +926,13 @@ function collectAgentSkillDirs(directory) {
926
926
  }
927
927
  return hits;
928
928
  }
929
- function copySkillDir(srcRoot, destDir) {
930
- fs4.rmSync(destDir, { recursive: true, force: true });
931
- fs4.cpSync(srcRoot, destDir, { recursive: true });
929
+ function syncSkillDir(srcRoot, destDir, opts = {}) {
930
+ if (opts.purgeExtras) {
931
+ fs4.rmSync(destDir, { recursive: true, force: true });
932
+ } else {
933
+ fs4.mkdirSync(destDir, { recursive: true });
934
+ }
935
+ fs4.cpSync(srcRoot, destDir, { recursive: true, force: true });
932
936
  }
933
937
  function readSkillFileAt(targetDir) {
934
938
  try {
@@ -962,15 +966,12 @@ function performAgentSkillAssembly(opts) {
962
966
  const target = path5.join(dir, SKILL_NAME);
963
967
  const existing = readSkillFileAt(target);
964
968
  const exists = existing !== void 0;
965
- if (exists && existing !== source.content && !force) {
966
- base.assembled.push({ dir, target, action: "kept", overwrite: false });
967
- continue;
968
- }
969
+ const localModified = exists && existing !== source.content;
969
970
  const action = dryRun ? "assemble" : "assembled";
970
971
  if (!dryRun) {
971
- copySkillDir(source.root, target);
972
+ syncSkillDir(source.root, target, { purgeExtras: force });
972
973
  }
973
- base.assembled.push({ dir, target, action, overwrite: exists });
974
+ base.assembled.push({ dir, target, action, overwrite: exists, localModified });
974
975
  }
975
976
  return base;
976
977
  }
@@ -981,11 +982,9 @@ function skillOutcomeText(outcome, dryRun) {
981
982
  switch (outcome.status) {
982
983
  case "assembled": {
983
984
  const dirs = outcome.assembled.map((t) => t.dir).join(", ");
984
- return `[skill v-cli] ${verb} ${outcome.assembled.length} \u4E2A agent \u76EE\u5F55\uFF1A${dirs}`;
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`;
985
+ const refreshed = outcome.assembled.filter((t) => t.localModified).map((t) => t.dir);
986
+ const note = refreshed.length > 0 ? `\uFF1B\u5176\u4E2D ${refreshed.length} \u4E2A\u672C\u5730\u5DF2\u4FEE\u6539\u7684 SKILL.md \u5DF2\u6309\u968F\u5305\u7248\u672C\u5237\u65B0\uFF08\u540C\u76EE\u5F55\u6269\u5C55\u6587\u4EF6\u4FDD\u7559\uFF09\uFF1A${refreshed.join(", ")}` : "";
987
+ return `[skill v-cli] ${verb} ${outcome.assembled.length} \u4E2A agent \u76EE\u5F55\uFF1A${dirs}${note}`;
989
988
  }
990
989
  case "skipped-none":
991
990
  return "[skill v-cli] \u672A\u68C0\u6D4B\u5230\u5339\u914D\u7684 agent \u6280\u80FD\u76EE\u5F55\uFF0C\u8DF3\u8FC7\u88C5\u914D";
@@ -1116,9 +1115,9 @@ var INIT_HELP_TEXT = [
1116
1115
  " [directory] \u76EE\u6807\u76EE\u5F55\uFF0C\u9ED8\u8BA4\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF1B\u5FC5\u987B\u5DF2\u5B58\u5728\u4E14\u4E3A\u76EE\u5F55",
1117
1116
  "",
1118
1117
  "\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",
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",
1118
+ " --force \u8986\u76D6\u5DF2\u5B58\u5728\u7684 AGENTS.md\uFF1Bskill \u76EE\u5F55\u505A\u5B8C\u5168\u540C\u6B65\uFF08\u6E05\u6389\u6269\u5C55\u6587\u4EF6\uFF09\uFF08\u539F\u5B50\u5199\u5165\uFF1A\u540C\u76EE\u5F55\u4E34\u65F6\u6587\u4EF6 + rename\uFF09",
1119
+ " skill \u540C\u6B65 \u968F\u5305\u7248\u672C\u662F\u89C4\u8303\u552F\u4E00\u6743\u5A01\uFF1A\u540C\u540D SKILL.md \u4E00\u5F8B\u6309\u968F\u5305\u7248\u672C\u5237\u65B0\uFF08\u672C\u5730\u4FEE\u6539\u4F1A\u88AB\u8986\u76D6\u5E76\u63D0\u793A\uFF09\uFF1B",
1120
+ " \u76EE\u6807\u76EE\u5F55\u4E2D\u968F\u5305\u6CA1\u6709\u7684\u6587\u4EF6\uFF08\u9879\u76EE\u6269\u5C55\uFF0C\u5982 PROJECT.md\uFF09\u9ED8\u8BA4\u4FDD\u7559\uFF0C--force \u65F6\u5B8C\u5168\u540C\u6B65\u3002",
1122
1121
  " --dry-run \u53EA\u62A5\u544A\u76EE\u6807\u4E0E\u5C06\u6267\u884C\u7684\u52A8\u4F5C\uFF0C\u4E0D\u5199\u5165\u4EFB\u4F55\u6587\u4EF6",
1123
1122
  " --json \u6210\u529F/\u5E72\u8DD1\u8F93\u51FA\u7A33\u5B9A JSON { ok, dryRun, action, directory, target, package, version, sha256, bytes }\uFF1B",
1124
1123
  ' \u62D2\u7EDD\uFF08\u5982\u5DF2\u5B58\u5728\u672A\u52A0 --force\uFF09\u8F93\u51FA { ok: false, action: "refused", reason, \u2026 } \u4E14\u9000\u51FA 1\uFF1B',
@@ -1189,7 +1188,7 @@ var agent = {
1189
1188
  { 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" }
1190
1189
  ],
1191
1190
  options: [
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" },
1191
+ { flags: "--force", description: "\u8986\u76D6\u5DF2\u5B58\u5728\u7684 AGENTS.md\uFF1Bskill \u76EE\u5F55\u505A\u5B8C\u5168\u540C\u6B65\uFF08\u6E05\u6389\u6269\u5C55\u6587\u4EF6\uFF09" },
1193
1192
  { flags: "--dry-run", description: "\u53EA\u62A5\u544A\u76EE\u6807\u4E0E\u52A8\u4F5C\uFF0C\u4E0D\u5199\u5165" },
1194
1193
  { flags: "--json", description: "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB\u7ED3\u679C" }
1195
1194
  ],
@@ -1289,7 +1288,7 @@ var agent = {
1289
1288
  }
1290
1289
  process.stdout.write(docs.content);
1291
1290
  });
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(
1291
+ 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\uFF1Bskill \u76EE\u5F55\u505A\u5B8C\u5168\u540C\u6B65\uFF08\u6E05\u6389\u6269\u5C55\u6587\u4EF6\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(
1293
1292
  (directory, opts) => {
1294
1293
  const json = ctx.json || opts.json;
1295
1294
  let docs;
@@ -1321,9 +1320,8 @@ var agent = {
1321
1320
  dryRun: opts.dryRun,
1322
1321
  force: opts.force
1323
1322
  });
1324
- const keptOnly = skill.assembled.length > 0 && skill.assembled.every((t) => t.action === "kept");
1325
1323
  skillOutcome = skill.assembled.length > 0 ? {
1326
- status: keptOnly ? "kept" : "assembled",
1324
+ status: "assembled",
1327
1325
  assembled: skill.assembled,
1328
1326
  name: skill.skill.name,
1329
1327
  sha256: skill.skill.sha256,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kevlns/v-cli",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "description": "kevlns 的个人工具箱 CLI(插件化架构,内置 + 本地插件)+ doctor/plugin/ts 命令",
5
5
  "type": "module",
6
6
  "bin": {
@@ -41,7 +41,7 @@ description: >
41
41
  - 产物与归属:
42
42
  - 根 `AGENTS.md` 为**工具生成物**(建议纳入 `.gitignore`),禁止手改;需要更新内容时升级 v-cli 后重跑 init。
43
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 而降级。
44
+ - **skill 同步**:**随包版本是规范的唯一权威**——命中目录下已有 `v-cli/SKILL.md` 时一律按随包版本刷新(本地修改会被覆盖,工具在 `localModified=true` 时给出提示);目标目录中随包**没有**的文件默认保留,供项目放扩展说明(如 `PROJECT.md`);`--force` 时做完全同步(连扩展文件一起清掉,目录与随包逐文件一致)。因此项目**不要**直接改 `SKILL.md`,项目专属内容写进扩展文件或项目规则文档。
45
45
  - 先 `--dry-run --json` 预览目标与动作(含 `skill.assembled[].action` 与 `overwrite`),再实际写入。
46
46
 
47
47
  ## 官方插件一:xlmerge(跨平台)
@@ -107,12 +107,11 @@ receipt 属工程本地生成物:新克隆 / 清理 Library 后即使 `Package
107
107
 
108
108
  ### 长任务命令:启动即让出,用状态命令轮询
109
109
 
110
- - u-cli-mod **0.2.0 起接管等待预算**:`run_tests` 这类同步长任务默认只等 **5 秒**,到点后任务仍在 Editor 内继续执行,工具打印输出日志路径(`<工程>/Library/editor-pipeline-cli/exec-logs/*.log`)并立即返回(退出码 0),不再有 30s 白等。
110
+ - `run_tests` 这类同步长任务默认只等 **5 秒**:到点后任务仍在 Editor 内继续执行,工具打印输出日志路径(`<工程>/Library/editor-pipeline-cli/exec-logs/*.log`)并立即返回(退出码 0)。
111
111
  - 让出后**不要重复发起同一命令**,改用状态命令轮询:测试 `-- command test_status`(直到读到 `summary`),烘焙 `-- command <xxx>_bake_status`。
112
112
  - 需要同步拿到完整 `Summary` 时用 `--wait <秒>` 扩大等待(写在 `--` 之前,u-cli-mod 自行剥离,不会透传给 Unity CLI);`--wait 0` = 立即返回。
113
113
  - **优先缩小范围**(最省事):`run_tests --mode EditMode --filter <命名空间或测试类>` 通常数秒内就同步返回完整 `Summary`,无需轮询。
114
114
  - 让出后任务仍在跑,不要重复发起;如需取消用 `-- command cancel_tests`(运行中可能被拒,稍后重试)。
115
- - 若仍见到 `Pipeline command 'run_tests' timed out after 30000ms`,说明本机 v-cli/u-cli-mod 尚未升级到 0.2.0;升级后该提示消失。
116
115
 
117
116
  ## 典型流程
118
117
 
@@ -129,4 +128,4 @@ v-cli unity exec <project> -- command read_console --types error,warning --count
129
128
  v-cli unity exec <project> -- command run_tests --mode EditMode --filter <类名> # 8. 测试(小范围同步返回)
130
129
  v-cli xlmerge --repo . detect # 配置表:只读检测
131
130
  v-cli xlmerge --repo . launch # 有冲突时启动本地 UI,把 url 交给用户
132
- ```
131
+ ```