@icebreakers/monorepo 3.2.13 → 3.2.15
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/dist/cli.cjs +6 -10
- package/dist/cli.mjs +6 -10
- package/dist/index.cjs +42 -29
- package/dist/index.d.cts +26 -5
- package/dist/index.d.mts +27 -6
- package/dist/index.mjs +2 -3
- package/dist/{upgrade-DiPTZW6J.mjs → upgrade-BTlzE81C.mjs} +240 -419
- package/dist/{upgrade-DjOZstRC.cjs → upgrade-a6Bh03Pw.cjs} +575 -649
- package/package.json +7 -12
|
@@ -5,119 +5,22 @@ import { findWorkspacePackages } from "@pnpm/workspace.find-packages";
|
|
|
5
5
|
import { readWorkspaceManifest } from "@pnpm/workspace.read-manifest";
|
|
6
6
|
import path from "pathe";
|
|
7
7
|
import process from "node:process";
|
|
8
|
-
import
|
|
8
|
+
import { access, cp, mkdir, mkdtemp, open, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
9
9
|
import { createConsola } from "consola";
|
|
10
10
|
import { assetsDir, checkbox, ensureTemplateAssetsPrepared, execaCommand, getAssetTargets, isGitignoreFile, scaffoldTemplate, templatesDir, toPublishGitignorePath, toWorkspaceGitignorePath } from "@icebreakers/monorepo-templates";
|
|
11
|
+
import YAML, { isSeq, parseDocument } from "yaml";
|
|
12
|
+
import crypto from "node:crypto";
|
|
11
13
|
import { loadConfig } from "c12";
|
|
12
14
|
import os from "node:os";
|
|
13
15
|
import * as path$1 from "node:path";
|
|
14
16
|
import { fileURLToPath } from "node:url";
|
|
15
17
|
import pc from "picocolors";
|
|
16
18
|
import "@pnpm/types";
|
|
17
|
-
import YAML, { isSeq, parseDocument } from "yaml";
|
|
18
|
-
import crypto from "node:crypto";
|
|
19
19
|
import { parse, stringify } from "comment-json";
|
|
20
20
|
import PQueue from "p-queue";
|
|
21
21
|
import klaw from "klaw";
|
|
22
|
-
import { Buffer
|
|
22
|
+
import { Buffer } from "node:buffer";
|
|
23
23
|
import { coerce, gte, minVersion } from "semver";
|
|
24
|
-
|
|
25
|
-
//#region \0rolldown/runtime.js
|
|
26
|
-
var __create = Object.create;
|
|
27
|
-
var __defProp$1 = Object.defineProperty;
|
|
28
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
29
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
30
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
31
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
32
|
-
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
33
|
-
var __copyProps = (to, from, except, desc) => {
|
|
34
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
35
|
-
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
36
|
-
key = keys[i];
|
|
37
|
-
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
38
|
-
__defProp$1(to, key, {
|
|
39
|
-
get: ((k) => from[k]).bind(null, key),
|
|
40
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return to;
|
|
46
|
-
};
|
|
47
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp$1(target, "default", {
|
|
48
|
-
value: mod,
|
|
49
|
-
enumerable: true
|
|
50
|
-
}) : target, mod));
|
|
51
|
-
|
|
52
|
-
//#endregion
|
|
53
|
-
//#region ../../node_modules/.pnpm/get-value@4.0.1/node_modules/get-value/dist/index.mjs
|
|
54
|
-
var __defProp = Object.defineProperty;
|
|
55
|
-
var __name = (target, value) => __defProp(target, "name", {
|
|
56
|
-
value,
|
|
57
|
-
configurable: true
|
|
58
|
-
});
|
|
59
|
-
var isObject = /* @__PURE__ */ __name((v) => v !== null && typeof v === "object", "isObject");
|
|
60
|
-
var join = /* @__PURE__ */ __name((segs, joinChar, options) => {
|
|
61
|
-
if (typeof options.join === "function") return options.join(segs);
|
|
62
|
-
return segs[0] + joinChar + segs[1];
|
|
63
|
-
}, "join");
|
|
64
|
-
var split = /* @__PURE__ */ __name((path, splitChar, options) => {
|
|
65
|
-
if (typeof options.split === "function") return options.split(path);
|
|
66
|
-
return path.split(splitChar);
|
|
67
|
-
}, "split");
|
|
68
|
-
var isValid = /* @__PURE__ */ __name((key, target = {}, options) => {
|
|
69
|
-
if (typeof options?.isValid === "function") return options.isValid(key, target);
|
|
70
|
-
return true;
|
|
71
|
-
}, "isValid");
|
|
72
|
-
var isValidObject = /* @__PURE__ */ __name((v) => {
|
|
73
|
-
return isObject(v) || typeof v === "function";
|
|
74
|
-
}, "isValidObject");
|
|
75
|
-
var index_default = /* @__PURE__ */ __name((target, path, options = {}) => {
|
|
76
|
-
if (!isObject(options)) options = { default: options };
|
|
77
|
-
if (!isValidObject(target)) return typeof options.default !== "undefined" ? options.default : target;
|
|
78
|
-
if (typeof path === "number") path = String(path);
|
|
79
|
-
const pathIsArray = Array.isArray(path);
|
|
80
|
-
const pathIsString = typeof path === "string";
|
|
81
|
-
const splitChar = options.separator || ".";
|
|
82
|
-
const joinChar = options.joinChar || (typeof splitChar === "string" ? splitChar : ".");
|
|
83
|
-
if (!pathIsString && !pathIsArray) return target;
|
|
84
|
-
if (target[path] !== void 0) return isValid(path, target, options) ? target[path] : options.default;
|
|
85
|
-
const segs = pathIsArray ? path : split(path, splitChar, options);
|
|
86
|
-
const len = segs.length;
|
|
87
|
-
let idx = 0;
|
|
88
|
-
do {
|
|
89
|
-
let prop = segs[idx];
|
|
90
|
-
if (typeof prop !== "string") prop = String(prop);
|
|
91
|
-
while (prop && prop.slice(-1) === "\\") prop = join([prop.slice(0, -1), segs[++idx] || ""], joinChar, options);
|
|
92
|
-
if (target[prop] !== void 0) {
|
|
93
|
-
if (!isValid(prop, target, options)) return options.default;
|
|
94
|
-
target = target[prop];
|
|
95
|
-
} else {
|
|
96
|
-
let hasProp = false;
|
|
97
|
-
let n = idx + 1;
|
|
98
|
-
while (n < len) {
|
|
99
|
-
prop = join([prop, segs[n++]], joinChar, options);
|
|
100
|
-
if (hasProp = target[prop] !== void 0) {
|
|
101
|
-
if (!isValid(prop, target, options)) return options.default;
|
|
102
|
-
target = target[prop];
|
|
103
|
-
idx = n - 1;
|
|
104
|
-
break;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
if (!hasProp) return options.default;
|
|
108
|
-
}
|
|
109
|
-
} while (++idx < len && isValidObject(target));
|
|
110
|
-
if (idx === len) return target;
|
|
111
|
-
return options.default;
|
|
112
|
-
}, "getValue");
|
|
113
|
-
/*!
|
|
114
|
-
* get-value <https://github.com/jonschlinkert/get-value>
|
|
115
|
-
*
|
|
116
|
-
* Copyright (c) 2014-present, Jon Schlinkert.
|
|
117
|
-
* Released under the MIT License.
|
|
118
|
-
*/
|
|
119
|
-
|
|
120
|
-
//#endregion
|
|
121
24
|
//#region src/core/git.ts
|
|
122
25
|
/**
|
|
123
26
|
* 对 simple-git 的轻量封装,集中处理配置缓存与常用查询。
|
|
@@ -152,8 +55,8 @@ var GitClient = class {
|
|
|
152
55
|
* 解析 remote.origin.url,返回 git-url-parse 的结构,便于获取仓库元信息。
|
|
153
56
|
*/
|
|
154
57
|
async getGitUrl() {
|
|
155
|
-
const x =
|
|
156
|
-
if (x) return gitUrlParse(x);
|
|
58
|
+
const x = (await this.getConfig())["remote.origin.url"];
|
|
59
|
+
if (typeof x === "string") return gitUrlParse(x);
|
|
157
60
|
}
|
|
158
61
|
/**
|
|
159
62
|
* 组合 owner/name,生成常用的仓库名表达。
|
|
@@ -168,8 +71,8 @@ var GitClient = class {
|
|
|
168
71
|
async getUser() {
|
|
169
72
|
const config = await this.getConfig();
|
|
170
73
|
return {
|
|
171
|
-
name:
|
|
172
|
-
email:
|
|
74
|
+
name: config["user.name"],
|
|
75
|
+
email: config["user.email"]
|
|
173
76
|
};
|
|
174
77
|
}
|
|
175
78
|
/**
|
|
@@ -184,7 +87,6 @@ var GitClient = class {
|
|
|
184
87
|
}
|
|
185
88
|
}
|
|
186
89
|
};
|
|
187
|
-
|
|
188
90
|
//#endregion
|
|
189
91
|
//#region ../../node_modules/.pnpm/defu@6.1.4/node_modules/defu/dist/defu.mjs
|
|
190
92
|
function isPlainObject$1(value) {
|
|
@@ -213,19 +115,18 @@ function createDefu(merger) {
|
|
|
213
115
|
return (...arguments_) => arguments_.reduce((p, c) => _defu(p, c, "", merger), {});
|
|
214
116
|
}
|
|
215
117
|
const defu = createDefu();
|
|
216
|
-
|
|
118
|
+
createDefu((object, key, currentValue) => {
|
|
217
119
|
if (object[key] !== void 0 && typeof currentValue === "function") {
|
|
218
120
|
object[key] = currentValue(object[key]);
|
|
219
121
|
return true;
|
|
220
122
|
}
|
|
221
123
|
});
|
|
222
|
-
|
|
124
|
+
createDefu((object, key, currentValue) => {
|
|
223
125
|
if (Array.isArray(object[key]) && typeof currentValue === "function") {
|
|
224
126
|
object[key] = currentValue(object[key]);
|
|
225
127
|
return true;
|
|
226
128
|
}
|
|
227
129
|
});
|
|
228
|
-
|
|
229
130
|
//#endregion
|
|
230
131
|
//#region src/core/workspace.ts
|
|
231
132
|
/**
|
|
@@ -264,14 +165,96 @@ async function getWorkspaceData(cwd, options) {
|
|
|
264
165
|
packages: await getWorkspacePackages(workspaceDir, options)
|
|
265
166
|
};
|
|
266
167
|
}
|
|
267
|
-
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region src/utils/fs.ts
|
|
170
|
+
function stringifyJson(data, options) {
|
|
171
|
+
return JSON.stringify(data, void 0, options?.spaces);
|
|
172
|
+
}
|
|
173
|
+
async function ensureParentDir(targetPath) {
|
|
174
|
+
await mkdir(path.dirname(targetPath), { recursive: true });
|
|
175
|
+
}
|
|
176
|
+
async function pathExists(targetPath) {
|
|
177
|
+
try {
|
|
178
|
+
await access(targetPath);
|
|
179
|
+
return true;
|
|
180
|
+
} catch {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const exists = pathExists;
|
|
185
|
+
async function ensureDir(targetPath) {
|
|
186
|
+
await mkdir(targetPath, { recursive: true });
|
|
187
|
+
}
|
|
188
|
+
async function ensureFile(targetPath) {
|
|
189
|
+
await ensureParentDir(targetPath);
|
|
190
|
+
await (await open(targetPath, "a")).close();
|
|
191
|
+
}
|
|
192
|
+
async function remove(targetPath) {
|
|
193
|
+
await rm(targetPath, {
|
|
194
|
+
recursive: true,
|
|
195
|
+
force: true,
|
|
196
|
+
maxRetries: 3,
|
|
197
|
+
retryDelay: 100
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
async function copy(sourcePath, targetPath) {
|
|
201
|
+
await cp(sourcePath, targetPath, {
|
|
202
|
+
recursive: true,
|
|
203
|
+
force: true
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
async function outputFile(targetPath, data, options) {
|
|
207
|
+
await ensureParentDir(targetPath);
|
|
208
|
+
await writeFile(targetPath, data, options);
|
|
209
|
+
}
|
|
210
|
+
async function readJson(targetPath) {
|
|
211
|
+
return JSON.parse(await readFile(targetPath, "utf8"));
|
|
212
|
+
}
|
|
213
|
+
const readJSON = readJson;
|
|
214
|
+
async function writeJson(targetPath, data, options) {
|
|
215
|
+
await writeFile(targetPath, stringifyJson(data, options), "utf8");
|
|
216
|
+
}
|
|
217
|
+
const writeJSON = writeJson;
|
|
218
|
+
async function outputJson(targetPath, data, options) {
|
|
219
|
+
await ensureParentDir(targetPath);
|
|
220
|
+
await writeJson(targetPath, data, options);
|
|
221
|
+
}
|
|
222
|
+
const outputJSON = outputJson;
|
|
223
|
+
/**
|
|
224
|
+
* 判断是否为可忽略的文件系统错误。
|
|
225
|
+
* - ENOENT: 文件已被删除
|
|
226
|
+
* - EBUSY: Windows 中资源被系统占用
|
|
227
|
+
*/
|
|
228
|
+
function isIgnorableFsError(error) {
|
|
229
|
+
if (!error) return false;
|
|
230
|
+
const code = error.code;
|
|
231
|
+
return code === "ENOENT" || code === "EBUSY" || code === "EEXIST";
|
|
232
|
+
}
|
|
233
|
+
const fs = {
|
|
234
|
+
copy,
|
|
235
|
+
ensureDir,
|
|
236
|
+
ensureFile,
|
|
237
|
+
exists,
|
|
238
|
+
mkdtemp,
|
|
239
|
+
outputFile,
|
|
240
|
+
outputJSON,
|
|
241
|
+
outputJson,
|
|
242
|
+
pathExists,
|
|
243
|
+
readFile,
|
|
244
|
+
readJSON,
|
|
245
|
+
readJson,
|
|
246
|
+
remove,
|
|
247
|
+
stat,
|
|
248
|
+
writeFile,
|
|
249
|
+
writeJSON,
|
|
250
|
+
writeJson
|
|
251
|
+
};
|
|
268
252
|
//#endregion
|
|
269
253
|
//#region src/core/logger.ts
|
|
270
254
|
/**
|
|
271
255
|
* 统一的日志实例,便于在命令行中输出带有前缀和颜色的消息。
|
|
272
256
|
*/
|
|
273
257
|
const logger = createConsola();
|
|
274
|
-
|
|
275
258
|
//#endregion
|
|
276
259
|
//#region src/commands/ai.ts
|
|
277
260
|
const agenticSections = [
|
|
@@ -302,7 +285,7 @@ function createTimestampFolderName(date = /* @__PURE__ */ new Date()) {
|
|
|
302
285
|
async function generateAgenticTemplate(options = {}) {
|
|
303
286
|
const cwd = options.cwd ?? process.cwd();
|
|
304
287
|
const format = options.format ?? "md";
|
|
305
|
-
const baseDir = options.baseDir ??
|
|
288
|
+
const baseDir = options.baseDir ?? "agentic/prompts";
|
|
306
289
|
if (format !== "md" && format !== "json") throw new Error(`不支持的模板格式:${format}`);
|
|
307
290
|
const template = format === "md" ? renderMarkdownTemplate() : renderJsonTemplate();
|
|
308
291
|
const ext = format === "json" ? "json" : "md";
|
|
@@ -342,175 +325,127 @@ async function generateAgenticTemplates(tasks, defaults = {}) {
|
|
|
342
325
|
}
|
|
343
326
|
return results;
|
|
344
327
|
}
|
|
345
|
-
|
|
346
328
|
//#endregion
|
|
347
|
-
//#region
|
|
348
|
-
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
* Copyright (c) 2014-present, Jon Schlinkert.
|
|
352
|
-
* Released under the MIT License.
|
|
329
|
+
//#region src/utils/github.ts
|
|
330
|
+
/**
|
|
331
|
+
* 将 Issue 模版里的 discussions 链接同步为当前仓库的 discussions 地址。
|
|
353
332
|
*/
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
360
|
-
|
|
333
|
+
function updateIssueTemplateConfig(source, repoName) {
|
|
334
|
+
if (!repoName) return source;
|
|
335
|
+
let doc;
|
|
336
|
+
try {
|
|
337
|
+
doc = parseDocument(source);
|
|
338
|
+
} catch {
|
|
339
|
+
return source;
|
|
340
|
+
}
|
|
341
|
+
const contactLinks = doc.get("contact_links");
|
|
342
|
+
if (!isSeq(contactLinks)) return source;
|
|
343
|
+
const nextUrl = `https://github.com/${repoName}/discussions`;
|
|
344
|
+
let changed = false;
|
|
345
|
+
contactLinks.items.forEach((_, index) => {
|
|
346
|
+
const url = doc.getIn([
|
|
347
|
+
"contact_links",
|
|
348
|
+
index,
|
|
349
|
+
"url"
|
|
350
|
+
]);
|
|
351
|
+
if (typeof url !== "string") return;
|
|
352
|
+
if (!url.includes("/discussions")) return;
|
|
353
|
+
if (url === nextUrl) return;
|
|
354
|
+
doc.setIn([
|
|
355
|
+
"contact_links",
|
|
356
|
+
index,
|
|
357
|
+
"url"
|
|
358
|
+
], nextUrl);
|
|
359
|
+
changed = true;
|
|
360
|
+
});
|
|
361
|
+
if (!changed) return source;
|
|
362
|
+
return doc.toString();
|
|
363
|
+
}
|
|
361
364
|
//#endregion
|
|
362
|
-
//#region
|
|
363
|
-
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
* Copyright (c) 2014-2017, Jon Schlinkert.
|
|
367
|
-
* Released under the MIT License.
|
|
365
|
+
//#region src/utils/hash.ts
|
|
366
|
+
/**
|
|
367
|
+
* 生成给定二进制内容的 md5 摘要,用于快速比较文件内容。
|
|
368
368
|
*/
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
//#region ../../node_modules/.pnpm/is-plain-object@2.0.4/node_modules/is-plain-object/index.js
|
|
377
|
-
/*!
|
|
378
|
-
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
|
|
379
|
-
*
|
|
380
|
-
* Copyright (c) 2014-2017, Jon Schlinkert.
|
|
381
|
-
* Released under the MIT License.
|
|
369
|
+
function getFileHash(data) {
|
|
370
|
+
const hashSum = crypto.createHash("md5");
|
|
371
|
+
hashSum.update(data);
|
|
372
|
+
return hashSum.digest("hex");
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* 对比两个文件的 md5,如果不一致则认为内容有变化。
|
|
382
376
|
*/
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
377
|
+
function isFileChanged(src, dest) {
|
|
378
|
+
try {
|
|
379
|
+
return getFileHash(src) !== getFileHash(dest);
|
|
380
|
+
} catch (err) {
|
|
381
|
+
logger.error("Error calculating file hash:", err);
|
|
382
|
+
return false;
|
|
387
383
|
}
|
|
388
|
-
|
|
389
|
-
var ctor, prot;
|
|
390
|
-
if (isObjectObject(o) === false) return false;
|
|
391
|
-
ctor = o.constructor;
|
|
392
|
-
if (typeof ctor !== "function") return false;
|
|
393
|
-
prot = ctor.prototype;
|
|
394
|
-
if (isObjectObject(prot) === false) return false;
|
|
395
|
-
if (prot.hasOwnProperty("isPrototypeOf") === false) return false;
|
|
396
|
-
return true;
|
|
397
|
-
};
|
|
398
|
-
}));
|
|
399
|
-
|
|
384
|
+
}
|
|
400
385
|
//#endregion
|
|
401
|
-
//#region
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
const isUnsafeKey = (key) => {
|
|
416
|
-
return key === "__proto__" || key === "constructor" || key === "prototype";
|
|
417
|
-
};
|
|
418
|
-
const validateKey = (key) => {
|
|
419
|
-
if (!isPrimitive(key)) throw new TypeError("Object keys must be strings or symbols");
|
|
420
|
-
if (isUnsafeKey(key)) throw new Error(`Cannot set unsafe key: "${key}"`);
|
|
421
|
-
};
|
|
422
|
-
const toStringKey = (input) => {
|
|
423
|
-
return Array.isArray(input) ? input.flat().map(String).join(",") : input;
|
|
424
|
-
};
|
|
425
|
-
const createMemoKey = (input, options) => {
|
|
426
|
-
if (typeof input !== "string" || !options) return input;
|
|
427
|
-
let key = input + ";";
|
|
428
|
-
if (options.arrays !== void 0) key += `arrays=${options.arrays};`;
|
|
429
|
-
if (options.separator !== void 0) key += `separator=${options.separator};`;
|
|
430
|
-
if (options.split !== void 0) key += `split=${options.split};`;
|
|
431
|
-
if (options.merge !== void 0) key += `merge=${options.merge};`;
|
|
432
|
-
if (options.preservePaths !== void 0) key += `preservePaths=${options.preservePaths};`;
|
|
433
|
-
return key;
|
|
434
|
-
};
|
|
435
|
-
const memoize = (input, options, fn) => {
|
|
436
|
-
const key = toStringKey(options ? createMemoKey(input, options) : input);
|
|
437
|
-
validateKey(key);
|
|
438
|
-
const value = setValue.cache.get(key) || fn();
|
|
439
|
-
setValue.cache.set(key, value);
|
|
440
|
-
return value;
|
|
441
|
-
};
|
|
442
|
-
const splitString = (input, options = {}) => {
|
|
443
|
-
const sep = options.separator || ".";
|
|
444
|
-
const preserve = sep === "/" ? false : options.preservePaths;
|
|
445
|
-
if (typeof input === "string" && preserve !== false && /\//.test(input)) return [input];
|
|
446
|
-
const parts = [];
|
|
447
|
-
let part = "";
|
|
448
|
-
const push = (part) => {
|
|
449
|
-
let number;
|
|
450
|
-
if (part.trim() !== "" && Number.isInteger(number = Number(part))) parts.push(number);
|
|
451
|
-
else parts.push(part);
|
|
452
|
-
};
|
|
453
|
-
for (let i = 0; i < input.length; i++) {
|
|
454
|
-
const value = input[i];
|
|
455
|
-
if (value === "\\") {
|
|
456
|
-
part += input[++i];
|
|
457
|
-
continue;
|
|
458
|
-
}
|
|
459
|
-
if (value === sep) {
|
|
460
|
-
push(part);
|
|
461
|
-
part = "";
|
|
462
|
-
continue;
|
|
463
|
-
}
|
|
464
|
-
part += value;
|
|
386
|
+
//#region src/utils/object.ts
|
|
387
|
+
const arrayIndexPattern = /^\d+$/;
|
|
388
|
+
function isArrayIndex(value) {
|
|
389
|
+
return arrayIndexPattern.test(value);
|
|
390
|
+
}
|
|
391
|
+
function parsePath(input) {
|
|
392
|
+
const segments = [];
|
|
393
|
+
let current = "";
|
|
394
|
+
let escaped = false;
|
|
395
|
+
for (const char of input) {
|
|
396
|
+
if (escaped) {
|
|
397
|
+
current += char;
|
|
398
|
+
escaped = false;
|
|
399
|
+
continue;
|
|
465
400
|
}
|
|
466
|
-
if (
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
const split = (input, options) => {
|
|
470
|
-
if (options && typeof options.split === "function") return options.split(input);
|
|
471
|
-
if (typeof input === "symbol") return [input];
|
|
472
|
-
if (Array.isArray(input)) return input;
|
|
473
|
-
return memoize(input, options, () => splitString(input, options));
|
|
474
|
-
};
|
|
475
|
-
const assignProp = (obj, prop, value, options) => {
|
|
476
|
-
validateKey(prop);
|
|
477
|
-
if (value === void 0) deleteProperty(obj, prop);
|
|
478
|
-
else if (options && options.merge) {
|
|
479
|
-
const merge = options.merge === "function" ? options.merge : Object.assign;
|
|
480
|
-
if (merge && isPlainObject(obj[prop]) && isPlainObject(value)) obj[prop] = merge(obj[prop], value);
|
|
481
|
-
else obj[prop] = value;
|
|
482
|
-
} else obj[prop] = value;
|
|
483
|
-
return obj;
|
|
484
|
-
};
|
|
485
|
-
const setValue = (target, path, value, options) => {
|
|
486
|
-
if (!path || !isObject(target)) return target;
|
|
487
|
-
const keys = split(path, options);
|
|
488
|
-
let obj = target;
|
|
489
|
-
for (let i = 0; i < keys.length; i++) {
|
|
490
|
-
const key = keys[i];
|
|
491
|
-
const next = keys[i + 1];
|
|
492
|
-
validateKey(key);
|
|
493
|
-
if (next === void 0) {
|
|
494
|
-
assignProp(obj, key, value, options);
|
|
495
|
-
break;
|
|
496
|
-
}
|
|
497
|
-
if (typeof next === "number" && !Array.isArray(obj[key])) {
|
|
498
|
-
obj = obj[key] = [];
|
|
499
|
-
continue;
|
|
500
|
-
}
|
|
501
|
-
if (!isObject(obj[key])) obj[key] = {};
|
|
502
|
-
obj = obj[key];
|
|
401
|
+
if (char === "\\") {
|
|
402
|
+
escaped = true;
|
|
403
|
+
continue;
|
|
503
404
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
405
|
+
if (char === ".") {
|
|
406
|
+
segments.push(current);
|
|
407
|
+
current = "";
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
current += char;
|
|
411
|
+
}
|
|
412
|
+
segments.push(current);
|
|
413
|
+
return segments;
|
|
414
|
+
}
|
|
415
|
+
function setByPath(target, path, value) {
|
|
416
|
+
const segments = typeof path === "string" ? parsePath(path) : [...path];
|
|
417
|
+
if (!segments.length) return target;
|
|
418
|
+
let current = target;
|
|
419
|
+
for (let index = 0; index < segments.length - 1; index++) {
|
|
420
|
+
const segment = segments[index];
|
|
421
|
+
const nextSegment = segments[index + 1];
|
|
422
|
+
const key = Array.isArray(current) && isArrayIndex(segment) ? Number(segment) : segment;
|
|
423
|
+
const existing = current[key];
|
|
424
|
+
if (typeof existing !== "object" || existing === null) current[key] = isArrayIndex(nextSegment) ? [] : {};
|
|
425
|
+
current = current[key];
|
|
426
|
+
}
|
|
427
|
+
const lastSegment = segments.at(-1);
|
|
428
|
+
const lastKey = Array.isArray(current) && isArrayIndex(lastSegment) ? Number(lastSegment) : lastSegment;
|
|
429
|
+
current[lastKey] = value;
|
|
430
|
+
return target;
|
|
431
|
+
}
|
|
432
|
+
//#endregion
|
|
433
|
+
//#region src/utils/regexp.ts
|
|
434
|
+
const regexpSpecialCharacterPattern = /[|\\{}()[\]^$+*?.]/g;
|
|
435
|
+
const hyphenPattern = /-/g;
|
|
436
|
+
/**
|
|
437
|
+
* 逃逸正则表达式中所有特殊字符,避免被当做模式解析。
|
|
438
|
+
*/
|
|
439
|
+
function escapeStringRegexp(str) {
|
|
440
|
+
return str.replace(regexpSpecialCharacterPattern, "\\$&").replace(hyphenPattern, "\\x2d");
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* 判断字符串是否命中任意一个正则,用于过滤要同步的资产文件。
|
|
444
|
+
*/
|
|
445
|
+
function isMatch(str, arr) {
|
|
446
|
+
for (const reg of arr) if (reg.test(str)) return true;
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
514
449
|
//#endregion
|
|
515
450
|
//#region src/core/config.ts
|
|
516
451
|
/**
|
|
@@ -555,12 +490,10 @@ async function loadMonorepoConfig(cwd) {
|
|
|
555
490
|
async function resolveCommandConfig(name, cwd) {
|
|
556
491
|
return ((await loadMonorepoConfig(cwd)).commands ?? {})[name] ?? {};
|
|
557
492
|
}
|
|
558
|
-
|
|
559
493
|
//#endregion
|
|
560
494
|
//#region package.json
|
|
561
495
|
var name = "@icebreakers/monorepo";
|
|
562
|
-
var version = "3.2.
|
|
563
|
-
|
|
496
|
+
var version = "3.2.15";
|
|
564
497
|
//#endregion
|
|
565
498
|
//#region src/constants.ts
|
|
566
499
|
/**
|
|
@@ -575,7 +508,6 @@ const packageDir = path$1.dirname(packageJsonPath);
|
|
|
575
508
|
* monorepo 根目录,方便需要跳出当前包的逻辑(例如定位工作区文件)。
|
|
576
509
|
*/
|
|
577
510
|
const rootDir = path$1.resolve(packageDir, "..", "..");
|
|
578
|
-
|
|
579
511
|
//#endregion
|
|
580
512
|
//#region src/commands/skills.ts
|
|
581
513
|
const skillName = "icebreakers-monorepo-cli";
|
|
@@ -589,7 +521,7 @@ function getSkillTargetPaths(homeDir = os.homedir()) {
|
|
|
589
521
|
}
|
|
590
522
|
function normalizeTargets(values) {
|
|
591
523
|
if (!values?.length) return;
|
|
592
|
-
return
|
|
524
|
+
return [...new Set(values)];
|
|
593
525
|
}
|
|
594
526
|
async function syncSkills(options = {}) {
|
|
595
527
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -621,10 +553,8 @@ async function syncSkills(options = {}) {
|
|
|
621
553
|
}
|
|
622
554
|
return results;
|
|
623
555
|
}
|
|
624
|
-
|
|
625
556
|
//#endregion
|
|
626
557
|
//#region src/commands/clean.ts
|
|
627
|
-
var import_set_value = /* @__PURE__ */ __toESM(require_set_value(), 1);
|
|
628
558
|
function mergeCleanConfig(base, overrides) {
|
|
629
559
|
const normalizedBase = base ?? {};
|
|
630
560
|
if (!overrides) return normalizedBase;
|
|
@@ -666,22 +596,21 @@ async function cleanProjects(cwd, overrides) {
|
|
|
666
596
|
const qoderDir = path.resolve(workspaceDir, ".qoder");
|
|
667
597
|
const docsPlansDir = path.resolve(workspaceDir, "docs/plans");
|
|
668
598
|
const skillTargets = Object.values(getSkillTargetPaths());
|
|
669
|
-
const candidates =
|
|
599
|
+
const candidates = [...new Set([
|
|
670
600
|
...cleanDirs.filter(Boolean),
|
|
671
601
|
readmeZh,
|
|
672
602
|
qoderDir,
|
|
673
603
|
docsPlansDir,
|
|
674
604
|
...skillTargets
|
|
675
|
-
])
|
|
605
|
+
])];
|
|
676
606
|
await Promise.all(candidates.map(async (dir) => {
|
|
677
607
|
if (await fs.pathExists(dir)) await fs.remove(dir);
|
|
678
608
|
}));
|
|
679
609
|
const name = path.resolve(workspaceDir, "package.json");
|
|
680
610
|
const pkgJson = await fs.readJson(name);
|
|
681
|
-
(
|
|
611
|
+
setByPath(pkgJson, "devDependencies.@icebreakers/monorepo", cleanConfig?.pinnedVersion ?? "latest");
|
|
682
612
|
await fs.outputJson(name, pkgJson, { spaces: 2 });
|
|
683
613
|
}
|
|
684
|
-
|
|
685
614
|
//#endregion
|
|
686
615
|
//#region src/commands/create.ts
|
|
687
616
|
/**
|
|
@@ -786,7 +715,7 @@ async function applyGitMetadata(pkgJson, repoDir, targetDir) {
|
|
|
786
715
|
const git = new GitClient({ baseDir: repoDir });
|
|
787
716
|
const repoName = await git.getRepoName();
|
|
788
717
|
if (!repoName) return;
|
|
789
|
-
(
|
|
718
|
+
setByPath(pkgJson, ["bugs", "url"], `https://github.com/${repoName}/issues`);
|
|
790
719
|
const repository = {
|
|
791
720
|
type: "git",
|
|
792
721
|
url: `git+https://github.com/${repoName}.git`
|
|
@@ -794,9 +723,9 @@ async function applyGitMetadata(pkgJson, repoDir, targetDir) {
|
|
|
794
723
|
const directoryBase = await git.getRepoRoot() ?? repoDir;
|
|
795
724
|
const relative = path.relative(directoryBase, targetDir);
|
|
796
725
|
if (relative && relative !== ".") repository.directory = relative.split(path.sep).join("/");
|
|
797
|
-
(
|
|
726
|
+
setByPath(pkgJson, "repository", repository);
|
|
798
727
|
const gitUser = await git.getUser();
|
|
799
|
-
if (gitUser?.name && gitUser?.email) (
|
|
728
|
+
if (gitUser?.name && gitUser?.email) setByPath(pkgJson, "author", `${gitUser.name} <${gitUser.email}>`);
|
|
800
729
|
} catch {}
|
|
801
730
|
}
|
|
802
731
|
/**
|
|
@@ -808,10 +737,10 @@ async function createNewProject(options) {
|
|
|
808
737
|
const renameJson = options?.renameJson ?? createConfig?.renameJson ?? false;
|
|
809
738
|
const rawName = options?.name ?? createConfig?.name;
|
|
810
739
|
const name = typeof rawName === "string" ? rawName.trim() : void 0;
|
|
811
|
-
const requestedTemplate = options?.type ?? createConfig?.type ?? createConfig?.defaultTemplate ??
|
|
740
|
+
const requestedTemplate = options?.type ?? createConfig?.type ?? createConfig?.defaultTemplate ?? "unbuild";
|
|
812
741
|
const templateDefinitions = getTemplateMap(createConfig?.templateMap);
|
|
813
742
|
const templatesRoot = createConfig?.templatesDir ? path.resolve(cwd, createConfig.templatesDir) : templatesDir;
|
|
814
|
-
const fallbackTemplate = createConfig?.defaultTemplate ??
|
|
743
|
+
const fallbackTemplate = createConfig?.defaultTemplate ?? "unbuild";
|
|
815
744
|
const bundlerName = typeof requestedTemplate === "string" && templateDefinitions[requestedTemplate] ? requestedTemplate : fallbackTemplate;
|
|
816
745
|
const templateDefinition = templateDefinitions[bundlerName];
|
|
817
746
|
if (!templateDefinition) throw new Error(`未找到名为 ${bundlerName} 的模板,请检查 monorepo.config.ts`);
|
|
@@ -829,14 +758,13 @@ async function createNewProject(options) {
|
|
|
829
758
|
});
|
|
830
759
|
if (hasPackageJson) {
|
|
831
760
|
const sourceJson = await fs.readJson(sourceJsonPath);
|
|
832
|
-
(
|
|
833
|
-
(
|
|
761
|
+
setByPath(sourceJson, "version", "0.0.0");
|
|
762
|
+
setByPath(sourceJson, "name", name?.startsWith("@") ? name : path.basename(targetName));
|
|
834
763
|
await applyGitMetadata(sourceJson, cwd, to);
|
|
835
764
|
await fs.outputJson(path.resolve(to, renameJson ? "package.mock.json" : "package.json"), sourceJson, { spaces: 2 });
|
|
836
765
|
}
|
|
837
766
|
logger.success(`${pc.bgGreenBright(pc.white(`[${bundlerName}]`))} ${targetName} 项目创建成功!`);
|
|
838
767
|
}
|
|
839
|
-
|
|
840
768
|
//#endregion
|
|
841
769
|
//#region src/core/context.ts
|
|
842
770
|
/**
|
|
@@ -857,7 +785,6 @@ async function createContext(cwd) {
|
|
|
857
785
|
config: await loadMonorepoConfig(workspaceDir)
|
|
858
786
|
};
|
|
859
787
|
}
|
|
860
|
-
|
|
861
788
|
//#endregion
|
|
862
789
|
//#region src/commands/init/setChangeset.ts
|
|
863
790
|
/**
|
|
@@ -870,101 +797,12 @@ async function setChangeset_default(ctx) {
|
|
|
870
797
|
if (await fs.exists(changesetConfigPath)) {
|
|
871
798
|
const changesetConfig = await fs.readJson(changesetConfigPath);
|
|
872
799
|
if (gitUrl.full_name) {
|
|
873
|
-
(
|
|
800
|
+
setByPath(changesetConfig, "changelog.1.repo", gitUrl.full_name);
|
|
874
801
|
await fs.outputJson(changesetConfigPath, changesetConfig, { spaces: 2 });
|
|
875
802
|
}
|
|
876
803
|
}
|
|
877
804
|
}
|
|
878
805
|
}
|
|
879
|
-
|
|
880
|
-
//#endregion
|
|
881
|
-
//#region src/utils/fs.ts
|
|
882
|
-
/**
|
|
883
|
-
* 判断是否为可忽略的文件系统错误。
|
|
884
|
-
* - ENOENT: 文件已被删除
|
|
885
|
-
* - EBUSY: Windows 中资源被系统占用
|
|
886
|
-
*/
|
|
887
|
-
function isIgnorableFsError(error) {
|
|
888
|
-
if (!error) return false;
|
|
889
|
-
const code = error.code;
|
|
890
|
-
return code === "ENOENT" || code === "EBUSY" || code === "EEXIST";
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
//#endregion
|
|
894
|
-
//#region src/utils/github.ts
|
|
895
|
-
/**
|
|
896
|
-
* 将 Issue 模版里的 discussions 链接同步为当前仓库的 discussions 地址。
|
|
897
|
-
*/
|
|
898
|
-
function updateIssueTemplateConfig(source, repoName) {
|
|
899
|
-
if (!repoName) return source;
|
|
900
|
-
let doc;
|
|
901
|
-
try {
|
|
902
|
-
doc = parseDocument(source);
|
|
903
|
-
} catch {
|
|
904
|
-
return source;
|
|
905
|
-
}
|
|
906
|
-
const contactLinks = doc.get("contact_links");
|
|
907
|
-
if (!isSeq(contactLinks)) return source;
|
|
908
|
-
const nextUrl = `https://github.com/${repoName}/discussions`;
|
|
909
|
-
let changed = false;
|
|
910
|
-
contactLinks.items.forEach((_, index) => {
|
|
911
|
-
const url = doc.getIn([
|
|
912
|
-
"contact_links",
|
|
913
|
-
index,
|
|
914
|
-
"url"
|
|
915
|
-
]);
|
|
916
|
-
if (typeof url !== "string") return;
|
|
917
|
-
if (!url.includes("/discussions")) return;
|
|
918
|
-
if (url === nextUrl) return;
|
|
919
|
-
doc.setIn([
|
|
920
|
-
"contact_links",
|
|
921
|
-
index,
|
|
922
|
-
"url"
|
|
923
|
-
], nextUrl);
|
|
924
|
-
changed = true;
|
|
925
|
-
});
|
|
926
|
-
if (!changed) return source;
|
|
927
|
-
return doc.toString();
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
//#endregion
|
|
931
|
-
//#region src/utils/hash.ts
|
|
932
|
-
/**
|
|
933
|
-
* 生成给定二进制内容的 md5 摘要,用于快速比较文件内容。
|
|
934
|
-
*/
|
|
935
|
-
function getFileHash(data) {
|
|
936
|
-
const hashSum = crypto.createHash("md5");
|
|
937
|
-
hashSum.update(data);
|
|
938
|
-
return hashSum.digest("hex");
|
|
939
|
-
}
|
|
940
|
-
/**
|
|
941
|
-
* 对比两个文件的 md5,如果不一致则认为内容有变化。
|
|
942
|
-
*/
|
|
943
|
-
function isFileChanged(src, dest) {
|
|
944
|
-
try {
|
|
945
|
-
return getFileHash(src) !== getFileHash(dest);
|
|
946
|
-
} catch (err) {
|
|
947
|
-
logger.error("Error calculating file hash:", err);
|
|
948
|
-
return false;
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
//#endregion
|
|
953
|
-
//#region src/utils/regexp.ts
|
|
954
|
-
/**
|
|
955
|
-
* 逃逸正则表达式中所有特殊字符,避免被当做模式解析。
|
|
956
|
-
*/
|
|
957
|
-
function escapeStringRegexp(str) {
|
|
958
|
-
return str.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
|
|
959
|
-
}
|
|
960
|
-
/**
|
|
961
|
-
* 判断字符串是否命中任意一个正则,用于过滤要同步的资产文件。
|
|
962
|
-
*/
|
|
963
|
-
function isMatch(str, arr) {
|
|
964
|
-
for (const reg of arr) if (reg.test(str)) return true;
|
|
965
|
-
return false;
|
|
966
|
-
}
|
|
967
|
-
|
|
968
806
|
//#endregion
|
|
969
807
|
//#region src/commands/init/setIssueTemplateConfig.ts
|
|
970
808
|
/**
|
|
@@ -979,7 +817,6 @@ async function setIssueTemplateConfig_default(ctx) {
|
|
|
979
817
|
const next = updateIssueTemplateConfig(source, repoName);
|
|
980
818
|
if (next !== source) await fs.writeFile(configPath, next, "utf8");
|
|
981
819
|
}
|
|
982
|
-
|
|
983
820
|
//#endregion
|
|
984
821
|
//#region src/commands/init/setPkgJson.ts
|
|
985
822
|
/**
|
|
@@ -992,19 +829,18 @@ async function setPkgJson_default(ctx) {
|
|
|
992
829
|
if (!await fs.pathExists(pkg.pkgJsonPath)) return;
|
|
993
830
|
const pkgJson = JSON.parse(JSON.stringify(pkg.manifest));
|
|
994
831
|
const directory = path.relative(cwd, pkg.rootDir);
|
|
995
|
-
(
|
|
832
|
+
setByPath(pkgJson, ["bugs", "url"], `https://github.com/${gitUrl.full_name}/issues`);
|
|
996
833
|
const repository = {
|
|
997
834
|
type: "git",
|
|
998
835
|
url: `git+https://github.com/${gitUrl.full_name}.git`
|
|
999
836
|
};
|
|
1000
837
|
if (directory) repository.directory = directory;
|
|
1001
|
-
(
|
|
1002
|
-
if (gitUser?.name && gitUser?.email) (
|
|
838
|
+
setByPath(pkgJson, "repository", repository);
|
|
839
|
+
if (gitUser?.name && gitUser?.email) setByPath(pkgJson, "author", `${gitUser.name} <${gitUser.email}>`);
|
|
1003
840
|
const nextContent = `${JSON.stringify(pkgJson, void 0, 2)}\n`;
|
|
1004
841
|
if (await fs.readFile(pkg.pkgJsonPath, "utf8") !== nextContent) await fs.writeFile(pkg.pkgJsonPath, nextContent, "utf8");
|
|
1005
842
|
}));
|
|
1006
843
|
}
|
|
1007
|
-
|
|
1008
844
|
//#endregion
|
|
1009
845
|
//#region src/commands/init/setReadme.ts
|
|
1010
846
|
async function getRows(ctx) {
|
|
@@ -1012,7 +848,7 @@ async function getRows(ctx) {
|
|
|
1012
848
|
const rows = [];
|
|
1013
849
|
if (gitUrl) rows.push(`# ${gitUrl.name}\n`);
|
|
1014
850
|
rows.push("## Packages\n");
|
|
1015
|
-
const sortedPackages =
|
|
851
|
+
const sortedPackages = packages.toSorted((a, b) => {
|
|
1016
852
|
const left = a.manifest.name ?? "";
|
|
1017
853
|
const right = b.manifest.name ?? "";
|
|
1018
854
|
return left.localeCompare(right);
|
|
@@ -1051,7 +887,6 @@ async function setReadme_default(ctx) {
|
|
|
1051
887
|
const rows = await getRows(ctx);
|
|
1052
888
|
await fs.writeFile(path.resolve(ctx.cwd, "README.md"), `${rows.join("\n")}\n`);
|
|
1053
889
|
}
|
|
1054
|
-
|
|
1055
890
|
//#endregion
|
|
1056
891
|
//#region src/commands/init/index.ts
|
|
1057
892
|
/**
|
|
@@ -1065,7 +900,6 @@ async function init(cwd) {
|
|
|
1065
900
|
if (!initConfig.skipReadme) await setReadme_default(ctx);
|
|
1066
901
|
if (!initConfig.skipIssueTemplateConfig) await setIssueTemplateConfig_default(ctx);
|
|
1067
902
|
}
|
|
1068
|
-
|
|
1069
903
|
//#endregion
|
|
1070
904
|
//#region src/commands/mirror/sources.ts
|
|
1071
905
|
const chinaMirrorsEnvs = {
|
|
@@ -1096,7 +930,6 @@ const chinaMirrorsEnvs = {
|
|
|
1096
930
|
npm_config_sharp_libvips_binary_host: "https://cdn.npmmirror.com/binaries/sharp-libvips",
|
|
1097
931
|
npm_config_robotjs_binary_host: "https://cdn.npmmirror.com/binaries/robotjs"
|
|
1098
932
|
};
|
|
1099
|
-
|
|
1100
933
|
//#endregion
|
|
1101
934
|
//#region src/commands/mirror/utils.ts
|
|
1102
935
|
/**
|
|
@@ -1109,9 +942,8 @@ function setMirror(obj, envs = chinaMirrorsEnvs) {
|
|
|
1109
942
|
"osx"
|
|
1110
943
|
];
|
|
1111
944
|
const prefix = "terminal.integrated.env";
|
|
1112
|
-
if (typeof obj === "object" && obj) for (const platform of platforms) (
|
|
945
|
+
if (typeof obj === "object" && obj) for (const platform of platforms) setByPath(obj, [prefix, platform].join(".").replaceAll(".", "\\."), envs);
|
|
1113
946
|
}
|
|
1114
|
-
|
|
1115
947
|
//#endregion
|
|
1116
948
|
//#region src/commands/mirror/binaryMirror.ts
|
|
1117
949
|
/**
|
|
@@ -1129,7 +961,6 @@ async function setVscodeBinaryMirror(cwd) {
|
|
|
1129
961
|
json && typeof json === "object" && setMirror(json, env);
|
|
1130
962
|
await fs.writeFile(targetJsonPath, `${stringify(json, void 0, 2)}\n`, "utf8");
|
|
1131
963
|
}
|
|
1132
|
-
|
|
1133
964
|
//#endregion
|
|
1134
965
|
//#region src/commands/sync.ts
|
|
1135
966
|
function renderCommand(template, pkgName) {
|
|
@@ -1147,9 +978,9 @@ async function syncNpmMirror(cwd, options) {
|
|
|
1147
978
|
logger.info(`[当前工作区Repo]:\n${packages.map((x) => `- ${pc.green(x.manifest.name)} : ${path.relative(workspaceDir, x.rootDir)}`).join("\n")}\n`);
|
|
1148
979
|
const set = new Set(packages.map((x) => x.manifest.name));
|
|
1149
980
|
if (packageFilter?.length) {
|
|
1150
|
-
for (const name of
|
|
981
|
+
for (const name of [...set]) if (!name || !packageFilter.includes(name)) set.delete(name);
|
|
1151
982
|
}
|
|
1152
|
-
logger.info(`[即将同步的包]:\n${Array.from(set
|
|
983
|
+
logger.info(`[即将同步的包]:\n${Array.from(set, (x) => `- ${pc.green(x ?? "")}`).join("\n")}\n`);
|
|
1153
984
|
const queue = new PQueue({ concurrency: configConcurrency ?? Math.max(os.cpus().length, 1) });
|
|
1154
985
|
const template = configCommand ?? "cnpm sync {name}";
|
|
1155
986
|
const tasks = [];
|
|
@@ -1161,17 +992,18 @@ async function syncNpmMirror(cwd, options) {
|
|
|
1161
992
|
}
|
|
1162
993
|
await Promise.all(tasks);
|
|
1163
994
|
}
|
|
1164
|
-
|
|
1165
995
|
//#endregion
|
|
1166
996
|
//#region src/commands/upgrade/agents.ts
|
|
997
|
+
const crlfPattern$1 = /\r\n/g;
|
|
998
|
+
const h2HeadingPrefixPattern = /^##\s+/;
|
|
1167
999
|
function normalizeEol$1(input) {
|
|
1168
|
-
return input.replace(
|
|
1000
|
+
return input.replace(crlfPattern$1, "\n");
|
|
1169
1001
|
}
|
|
1170
1002
|
function normalizeComparableContent(input) {
|
|
1171
1003
|
return normalizeEol$1(input).trimEnd();
|
|
1172
1004
|
}
|
|
1173
1005
|
function normalizeHeadingKey(line) {
|
|
1174
|
-
return line.replace(
|
|
1006
|
+
return line.replace(h2HeadingPrefixPattern, "").trim().toLowerCase();
|
|
1175
1007
|
}
|
|
1176
1008
|
function trimEdgeEmptyLines(lines) {
|
|
1177
1009
|
const next = [...lines];
|
|
@@ -1193,7 +1025,7 @@ function parseMarkdownByH2(content) {
|
|
|
1193
1025
|
const sections = [];
|
|
1194
1026
|
let current;
|
|
1195
1027
|
for (const line of lines) {
|
|
1196
|
-
if (
|
|
1028
|
+
if (h2HeadingPrefixPattern.test(line)) {
|
|
1197
1029
|
if (current) sections.push(current);
|
|
1198
1030
|
current = {
|
|
1199
1031
|
key: normalizeHeadingKey(line),
|
|
@@ -1259,11 +1091,10 @@ function mergeAgentsMarkdown(source, target) {
|
|
|
1259
1091
|
function isAgentsMarkdownEquivalent(left, right) {
|
|
1260
1092
|
return normalizeComparableContent(left) === normalizeComparableContent(right);
|
|
1261
1093
|
}
|
|
1262
|
-
|
|
1263
1094
|
//#endregion
|
|
1264
1095
|
//#region src/commands/upgrade/overwrite.ts
|
|
1265
1096
|
function asBuffer(data) {
|
|
1266
|
-
return typeof data === "string" ? Buffer
|
|
1097
|
+
return typeof data === "string" ? Buffer.from(data) : data;
|
|
1267
1098
|
}
|
|
1268
1099
|
async function evaluateWriteIntent(targetPath, options) {
|
|
1269
1100
|
const { skipOverwrite, source } = options;
|
|
@@ -1324,21 +1155,13 @@ async function flushPendingOverwrites(pending) {
|
|
|
1324
1155
|
const selectedSet = new Set(selected);
|
|
1325
1156
|
for (const item of pending) if (selectedSet.has(item.targetPath)) await item.action();
|
|
1326
1157
|
}
|
|
1327
|
-
|
|
1328
|
-
//#endregion
|
|
1329
|
-
//#region src/commands/upgrade/scripts.ts
|
|
1330
|
-
/**
|
|
1331
|
-
* 升级时注入到 package.json 的脚本命令集合,保证常用脚本齐全。
|
|
1332
|
-
*/
|
|
1333
|
-
const scripts = {
|
|
1158
|
+
const scriptsEntries = Object.entries({
|
|
1334
1159
|
"script:init": "monorepo init",
|
|
1335
1160
|
"script:sync": "monorepo sync",
|
|
1336
1161
|
"script:clean": "monorepo clean",
|
|
1337
1162
|
"script:mirror": "monorepo mirror",
|
|
1338
1163
|
"commitlint": "commitlint --edit"
|
|
1339
|
-
};
|
|
1340
|
-
const scriptsEntries = Object.entries(scripts);
|
|
1341
|
-
|
|
1164
|
+
});
|
|
1342
1165
|
//#endregion
|
|
1343
1166
|
//#region src/commands/upgrade/pkg-json.ts
|
|
1344
1167
|
const NON_OVERRIDABLE_PREFIXES = ["workspace:", "catalog:"];
|
|
@@ -1402,7 +1225,6 @@ function setPkgJson(sourcePkgJson, targetPkgJson, options) {
|
|
|
1402
1225
|
targetPkgJson.scripts = scripts;
|
|
1403
1226
|
}
|
|
1404
1227
|
}
|
|
1405
|
-
|
|
1406
1228
|
//#endregion
|
|
1407
1229
|
//#region src/commands/upgrade/workspace.ts
|
|
1408
1230
|
function isPlainObject(value) {
|
|
@@ -1458,11 +1280,11 @@ function mergeWorkspaceManifest(source, target) {
|
|
|
1458
1280
|
}
|
|
1459
1281
|
return result;
|
|
1460
1282
|
}
|
|
1461
|
-
|
|
1462
1283
|
//#endregion
|
|
1463
1284
|
//#region src/commands/upgrade/index.ts
|
|
1285
|
+
const crlfPattern = /\r\n/g;
|
|
1464
1286
|
function normalizeEol(input) {
|
|
1465
|
-
return input.replace(
|
|
1287
|
+
return input.replace(crlfPattern, "\n");
|
|
1466
1288
|
}
|
|
1467
1289
|
function normalizeGitignoreLine(line) {
|
|
1468
1290
|
const trimmed = line.trim();
|
|
@@ -1511,7 +1333,7 @@ async function upgradeMonorepo(opts) {
|
|
|
1511
1333
|
const baseTargets = getAssetTargets(useCoreAssets);
|
|
1512
1334
|
const configTargets = upgradeConfig?.targets ?? [];
|
|
1513
1335
|
const mergeTargets = upgradeConfig?.mergeTargets;
|
|
1514
|
-
let targets = configTargets.length ? mergeTargets === false ? [...configTargets] :
|
|
1336
|
+
let targets = configTargets.length ? mergeTargets === false ? [...configTargets] : [...new Set([...baseTargets, ...configTargets])] : baseTargets;
|
|
1515
1337
|
if (merged.interactive) targets = await checkbox({
|
|
1516
1338
|
message: "选择你需要的文件",
|
|
1517
1339
|
choices: targets.map((x) => {
|
|
@@ -1620,7 +1442,7 @@ async function upgradeMonorepo(opts) {
|
|
|
1620
1442
|
}
|
|
1621
1443
|
if (relPath === ".changeset/config.json" && repoName) {
|
|
1622
1444
|
const changesetJson = await fs.readJson(file.path);
|
|
1623
|
-
(
|
|
1445
|
+
setByPath(changesetJson, "changelog.1.repo", repoName);
|
|
1624
1446
|
const data = `${JSON.stringify(changesetJson, void 0, 2)}\n`;
|
|
1625
1447
|
const intent = await evaluateWriteIntent(targetPath, buildWriteIntentOptions(data));
|
|
1626
1448
|
const action = async () => {
|
|
@@ -1687,6 +1509,5 @@ async function upgradeMonorepo(opts) {
|
|
|
1687
1509
|
}
|
|
1688
1510
|
await flushPendingOverwrites(pendingOverwrites);
|
|
1689
1511
|
}
|
|
1690
|
-
|
|
1691
1512
|
//#endregion
|
|
1692
|
-
export {
|
|
1513
|
+
export { getWorkspaceData as $, toPublishGitignorePath as A, ensureDir as B, resolveCommandConfig as C, getFileHash as D, setByPath as E, generateAgenticTemplate as F, outputJSON as G, exists as H, generateAgenticTemplates as I, readJSON as J, outputJson as K, loadAgenticTasks as L, updateIssueTemplateConfig as M, createTimestampFolderName as N, isFileChanged as O, defaultAgenticBaseDir as P, writeJson as Q, logger as R, loadMonorepoConfig as S, isMatch as T, isIgnorableFsError as U, ensureFile as V, outputFile as W, remove as X, readJson as Y, writeJSON as Z, rootDir as _, createContext as a, version as b, getCreateChoices as c, cleanProjects as d, getWorkspacePackages as et, getSkillTargetPaths as f, packageDir as g, assetsDir as h, init as i, toWorkspaceGitignorePath as j, isGitignoreFile as k, getTemplateMap as l, syncSkills as m, syncNpmMirror as n, createNewProject as o, skillTargets as p, pathExists as q, setVscodeBinaryMirror as r, defaultTemplate as s, upgradeMonorepo as t, GitClient as tt, templateMap as u, templatesDir as v, escapeStringRegexp as w, defineMonorepoConfig as x, name as y, copy as z };
|