@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.
- package/bin/cli.js +29 -7
- 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}
|
|
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())
|
|
134
|
+
if (entry.isSymbolicLink()) { offenders.push(full); continue; }
|
|
126
135
|
if (entry.isDirectory()) {
|
|
127
|
-
|
|
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
|
|
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}
|
|
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)))
|
|
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}
|
|
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()];
|