@qilitt-mickey/vue3-temp-skill 1.2.8 → 1.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bin/cli.js +29 -7
  2. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -39,6 +39,13 @@ export function createInstaller({ home = os.homedir(), skillDir = PACKAGE_DIR, c
39
39
  try { return fs.lstatSync(file); } catch (err) { if (err.code === "ENOENT") return null; throw err; }
40
40
  };
41
41
  const conflict = (file) => { throw new Error(`未管理或类型不符的路径冲突,保留原内容: ${file}`); };
42
+ // 迁移受阻一次报全:逐个文件中止会让用户反复重试才知道还有冲突。
43
+ function unclaimed(list, dir) {
44
+ const unique = [...new Set(list)];
45
+ const shown = unique.slice(0, 20);
46
+ const rest = unique.length - shown.length;
47
+ throw new Error(`旧资源冲突:${unique.length} 个路径无法与本包核对,原内容全部保留:\n${shown.map((file) => ` ${file}`).join("\n")}${rest ? `\n …另有 ${rest} 个` : ""}\n人工迁移:把 ${dir} 改名备份(如 ${dir}.bak)后重新执行 ${SKILL_NAME} install <target>;或只删除以上路径后重试 --force。`);
48
+ }
42
49
  function safePath(file) {
43
50
  for (let current = path.resolve(file); ; current = path.dirname(current)) {
44
51
  const info = stat(current);
@@ -115,22 +122,26 @@ export function createInstaller({ home = os.homedir(), skillDir = PACKAGE_DIR, c
115
122
  }
116
123
  return { files: data.files, exists: true };
117
124
  }
118
- if (!force) throw new Error(`未管理的旧目录冲突: ${dir};仅可用 --force 尝试识别自有资源后迁移`);
125
+ if (!force) throw new Error(`未管理的旧目录冲突: ${dir};用 --force 仅迁移可识别的自有资源,或把 ${dir} 改名备份后重新执行 ${SKILL_NAME} install <target>`);
119
126
  source ||= runtimeFiles();
127
+ const keys = [...source.keys()];
120
128
  const files = [];
129
+ const offenders = [];
121
130
  function inspect(relative = "") {
122
131
  for (const entry of fs.readdirSync(path.join(dir, relative), { withFileTypes: true })) {
123
132
  const file = relative ? `${relative}/${entry.name}` : entry.name;
124
133
  const full = path.join(dir, file);
125
- if (entry.isSymbolicLink()) conflict(full);
134
+ if (entry.isSymbolicLink()) { offenders.push(full); continue; }
126
135
  if (entry.isDirectory()) {
127
- if (![...source.keys()].some((key) => key.startsWith(`${file}/`))) conflict(full);
136
+ // 整目录不可核对时只报目录本身,不把它里面的文件逐个铺开。
137
+ if (!keys.some((key) => key.startsWith(`${file}/`))) { offenders.push(full); continue; }
128
138
  inspect(file);
129
139
  } else if (entry.isFile() && source.has(file) && fs.readFileSync(full).equals(source.get(file))) files.push(file);
130
- else conflict(full);
140
+ else offenders.push(full);
131
141
  }
132
142
  }
133
143
  inspect();
144
+ if (offenders.length) unclaimed(offenders, dir);
134
145
  if (!files.includes("SKILL.md")) conflict(dir);
135
146
  return { files, exists: true, legacy: true };
136
147
  }
@@ -163,17 +174,19 @@ export function createInstaller({ home = os.homedir(), skillDir = PACKAGE_DIR, c
163
174
  safePath(dest);
164
175
  if (!stat(dest)) return { text: "", range: null };
165
176
  if (stat(dest).isDirectory()) {
166
- if (!force) throw new Error(`旧目录占用了索引文件: ${dest};需要 --force 并识别自有资源后迁移`);
177
+ if (!force) throw new Error(`旧目录占用了索引文件: ${dest};把 ${dest} 改名备份后重新执行 ${SKILL_NAME} install <target>,或用 --force 仅迁移可识别的自有资源`);
167
178
  const directory = ownership(dest, force, source);
168
179
  // 索引目录必须可完整移走;不能先删除受管文件再发现其中还留有用户文件。
180
+ const offenders = [];
169
181
  function check(relative = "") {
170
182
  for (const entry of fs.readdirSync(path.join(dest, relative), { withFileTypes: true })) {
171
183
  const file = relative ? `${relative}/${entry.name}` : entry.name;
172
184
  if (entry.isDirectory() && directory.files.some((owned) => owned.startsWith(`${file}/`))) check(file);
173
- else if (!entry.isFile() || (!directory.files.includes(file) && (directory.legacy || file !== MANIFEST))) conflict(path.join(dest, file));
185
+ else if (!entry.isFile() || (!directory.files.includes(file) && (directory.legacy || file !== MANIFEST))) offenders.push(path.join(dest, file));
174
186
  }
175
187
  }
176
188
  check();
189
+ if (offenders.length) unclaimed(offenders, dest);
177
190
  return { text: "", range: null, directory };
178
191
  }
179
192
  if (!stat(dest).isFile()) conflict(dest);
@@ -182,7 +195,7 @@ export function createInstaller({ home = os.homedir(), skillDir = PACKAGE_DIR, c
182
195
  if (cfg.type === "rules" && !range) {
183
196
  const legacyBody = path.join(path.dirname(path.dirname(dest)), "skills", SKILL_NAME);
184
197
  if (!force || text !== legacyRulesText(legacyBody)) {
185
- throw new Error(`未管理的规则文件冲突: ${dest};旧版本需 --force 且可识别,否则请人工迁移`);
198
+ throw new Error(`未管理的规则文件冲突: ${dest};内容与本包旧版本逐字一致时可用 --force 迁移,否则把 ${dest} 改名备份后重新执行 ${SKILL_NAME} install <target>`);
186
199
  }
187
200
  return { text: "", range: null, legacyBody, legacyOwnership: ownership(legacyBody, force, source) };
188
201
  }
@@ -321,6 +334,15 @@ export function createInstaller({ home = os.homedir(), skillDir = PACKAGE_DIR, c
321
334
  jobs = track.filter((entry) => !target || target === "all" || entry.target === target);
322
335
  if (opts.project !== undefined) jobs = jobs.map((entry) => ({ ...entry, project: opts.project }));
323
336
  if (target && target !== "all" && (opts.project !== undefined || jobs.length === 0)) jobs = [{ target, project: opts.project || null }];
337
+ // 批量任务沿用 install 的规则:无 --project 的项目专属目标跳过并说明,不让一条历史记录中止整批。
338
+ if (!target || target === "all") {
339
+ const batch = [];
340
+ for (const job of jobs) {
341
+ if (targets[job.target].projectOnly && !job.project) { log(`${job.target} 仅支持项目安装,未指定 --project,已跳过`); continue; }
342
+ batch.push(job);
343
+ }
344
+ jobs = batch;
345
+ }
324
346
  }
325
347
  const identity = (entry) => JSON.stringify([entry.target, entry.project]);
326
348
  jobs = [...new Map(jobs.map((entry) => [identity(entry), entry])).values()];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qilitt-mickey/vue3-temp-skill",
3
- "version": "1.2.8",
3
+ "version": "1.2.9",
4
4
  "type": "module",
5
5
  "description": "vue3-web-temp 项目工程技能:按需功能开发、保留业务的设计还原与视觉及功能双重验证",
6
6
  "bin": {