@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.
@@ -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 fs from "fs-extra";
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 as Buffer$1 } from "node: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 = index_default(await this.getConfig(), "remote.origin.url");
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: index_default(config, "user.name"),
172
- email: index_default(config, "user.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
- const defuFn = createDefu((object, key, currentValue) => {
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
- const defuArrayFn = createDefu((object, key, currentValue) => {
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 ?? defaultAgenticBaseDir;
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 ../../node_modules/.pnpm/is-primitive@3.0.1/node_modules/is-primitive/index.js
348
- /*!
349
- * is-primitive <https://github.com/jonschlinkert/is-primitive>
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
- var require_is_primitive = /* @__PURE__ */ __commonJSMin(((exports, module) => {
355
- module.exports = function isPrimitive(val) {
356
- if (typeof val === "object") return val === null;
357
- return typeof val !== "function";
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 ../../node_modules/.pnpm/isobject@3.0.1/node_modules/isobject/index.js
363
- /*!
364
- * isobject <https://github.com/jonschlinkert/isobject>
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
- var require_isobject = /* @__PURE__ */ __commonJSMin(((exports, module) => {
370
- module.exports = function isObject(val) {
371
- return val != null && typeof val === "object" && Array.isArray(val) === false;
372
- };
373
- }));
374
-
375
- //#endregion
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
- var require_is_plain_object = /* @__PURE__ */ __commonJSMin(((exports, module) => {
384
- var isObject = require_isobject();
385
- function isObjectObject(o) {
386
- return isObject(o) === true && Object.prototype.toString.call(o) === "[object Object]";
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
- module.exports = function isPlainObject(o) {
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 ../../node_modules/.pnpm/set-value@4.1.0/node_modules/set-value/index.js
402
- /*!
403
- * set-value <https://github.com/jonschlinkert/set-value>
404
- *
405
- * Copyright (c) Jon Schlinkert (https://github.com/jonschlinkert).
406
- * Released under the MIT License.
407
- */
408
- var require_set_value = /* @__PURE__ */ __commonJSMin(((exports, module) => {
409
- const { deleteProperty } = Reflect;
410
- const isPrimitive = require_is_primitive();
411
- const isPlainObject = require_is_plain_object();
412
- const isObject = (value) => {
413
- return typeof value === "object" && value !== null || typeof value === "function";
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 (part) push(part);
467
- return parts;
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
- return target;
505
- };
506
- setValue.split = split;
507
- setValue.cache = /* @__PURE__ */ new Map();
508
- setValue.clear = () => {
509
- setValue.cache = /* @__PURE__ */ new Map();
510
- };
511
- module.exports = setValue;
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.13";
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 Array.from(new Set(values));
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 = Array.from(new Set([
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
- (0, import_set_value.default)(pkgJson, "devDependencies.@icebreakers/monorepo", cleanConfig?.pinnedVersion ?? "latest", { preservePaths: false });
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
- (0, import_set_value.default)(pkgJson, ["bugs", "url"], `https://github.com/${repoName}/issues`);
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
- (0, import_set_value.default)(pkgJson, "repository", repository);
726
+ setByPath(pkgJson, "repository", repository);
798
727
  const gitUser = await git.getUser();
799
- if (gitUser?.name && gitUser?.email) (0, import_set_value.default)(pkgJson, "author", `${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 ?? 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 ?? 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
- (0, import_set_value.default)(sourceJson, "version", "0.0.0");
833
- (0, import_set_value.default)(sourceJson, "name", name?.startsWith("@") ? name : path.basename(targetName));
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
- (0, import_set_value.default)(changesetConfig, "changelog.1.repo", gitUrl.full_name);
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
- (0, import_set_value.default)(pkgJson, ["bugs", "url"], `https://github.com/${gitUrl.full_name}/issues`);
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
- (0, import_set_value.default)(pkgJson, "repository", repository);
1002
- if (gitUser?.name && gitUser?.email) (0, import_set_value.default)(pkgJson, "author", `${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 = [...packages].sort((a, b) => {
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) (0, import_set_value.default)(obj, [prefix, platform].join(".").replaceAll(".", "\\."), envs);
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 Array.from(set)) if (!name || !packageFilter.includes(name)) set.delete(name);
981
+ for (const name of [...set]) if (!name || !packageFilter.includes(name)) set.delete(name);
1151
982
  }
1152
- logger.info(`[即将同步的包]:\n${Array.from(set).map((x) => `- ${pc.green(x ?? "")}`).join("\n")}\n`);
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(/\r\n/g, "\n");
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(/^##\s+/, "").trim().toLowerCase();
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 (/^##\s+/.test(line)) {
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$1.from(data) : data;
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(/\r\n/g, "\n");
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] : Array.from(new Set([...baseTargets, ...configTargets])) : baseTargets;
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
- (0, import_set_value.default)(changesetJson, "changelog.1.repo", repoName);
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 { defineMonorepoConfig as A, getWorkspacePackages as B, syncSkills as C, templatesDir as D, rootDir as E, generateAgenticTemplate as F, generateAgenticTemplates as I, loadAgenticTasks as L, resolveCommandConfig as M, createTimestampFolderName as N, name as O, defaultAgenticBaseDir as P, logger as R, skillTargets as S, packageDir as T, GitClient as V, getCreateChoices as _, escapeStringRegexp as a, cleanProjects as b, isFileChanged as c, toWorkspaceGitignorePath as d, updateIssueTemplateConfig as f, defaultTemplate as g, createNewProject as h, init as i, loadMonorepoConfig as j, version as k, isGitignoreFile as l, createContext as m, syncNpmMirror as n, isMatch as o, isIgnorableFsError as p, setVscodeBinaryMirror as r, getFileHash as s, upgradeMonorepo as t, toPublishGitignorePath as u, getTemplateMap as v, assetsDir as w, getSkillTargetPaths as x, templateMap as y, getWorkspaceData as z };
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 };