@coze-arch/cli 0.0.1-alpha.fd3d56 → 0.0.1-alpha.ff3d06

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/README.md +1 -0
  2. package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +13 -12
  3. package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +9 -8
  4. package/lib/__templates__/expo/_npmrc +1 -0
  5. package/lib/__templates__/expo/client/components/Screen.tsx +2 -2
  6. package/lib/__templates__/expo/client/eslint.config.mjs +11 -1
  7. package/lib/__templates__/expo/client/metro.config.js +3 -0
  8. package/lib/__templates__/expo/client/package.json +35 -35
  9. package/lib/__templates__/expo/client/screens/demo/index.tsx +3 -3
  10. package/lib/__templates__/expo/client/scripts/install-missing-deps.js +10 -10
  11. package/lib/__templates__/expo/eslint-plugins/forbid-emoji/index.js +9 -0
  12. package/lib/__templates__/expo/eslint-plugins/forbid-emoji/rule.js +112 -0
  13. package/lib/__templates__/expo/eslint-plugins/forbid-emoji/tech.md +94 -0
  14. package/lib/__templates__/expo/eslint-plugins/react-native/index.js +9 -0
  15. package/lib/__templates__/expo/eslint-plugins/react-native/rule.js +64 -0
  16. package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/index.js +9 -0
  17. package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/rule.js +120 -0
  18. package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/tech.md +58 -0
  19. package/lib/__templates__/expo/package.json +1 -1
  20. package/lib/__templates__/expo/patches/{expo@54.0.32.patch → expo@54.0.33.patch} +3 -2
  21. package/lib/__templates__/expo/pnpm-lock.yaml +340 -1736
  22. package/lib/__templates__/expo/server/package.json +9 -7
  23. package/lib/__templates__/expo/server/src/index.ts +1 -0
  24. package/lib/__templates__/expo/template.config.js +56 -0
  25. package/lib/__templates__/native-static/.coze +11 -0
  26. package/lib/__templates__/native-static/index.html +33 -0
  27. package/lib/__templates__/native-static/styles/main.css +136 -0
  28. package/lib/__templates__/native-static/template.config.js +22 -0
  29. package/lib/__templates__/nextjs/AGENTS.md +54 -0
  30. package/lib/__templates__/nextjs/README.md +5 -0
  31. package/lib/__templates__/nextjs/eslint.config.mjs +5 -0
  32. package/lib/__templates__/nextjs/next.config.ts +1 -2
  33. package/lib/__templates__/nextjs/package.json +15 -6
  34. package/lib/__templates__/nextjs/pnpm-lock.yaml +1859 -736
  35. package/lib/__templates__/nextjs/scripts/build.sh +4 -1
  36. package/lib/__templates__/nextjs/scripts/dev.sh +8 -2
  37. package/lib/__templates__/nextjs/scripts/start.sh +7 -1
  38. package/lib/__templates__/nextjs/src/app/layout.tsx +1 -1
  39. package/lib/__templates__/nextjs/src/app/page.tsx +17 -60
  40. package/lib/__templates__/nextjs/src/server.ts +35 -0
  41. package/lib/__templates__/nextjs/template.config.js +49 -14
  42. package/lib/__templates__/nextjs/tsconfig.json +1 -1
  43. package/lib/__templates__/nuxt-vue/.coze +12 -0
  44. package/lib/__templates__/nuxt-vue/AGENTS.md +42 -0
  45. package/lib/__templates__/nuxt-vue/README.md +73 -0
  46. package/lib/__templates__/nuxt-vue/_gitignore +24 -0
  47. package/lib/__templates__/nuxt-vue/_npmrc +23 -0
  48. package/lib/__templates__/nuxt-vue/app/app.vue +6 -0
  49. package/lib/__templates__/nuxt-vue/app/pages/index.vue +23 -0
  50. package/lib/__templates__/nuxt-vue/assets/css/main.css +24 -0
  51. package/lib/__templates__/nuxt-vue/nuxt.config.ts +116 -0
  52. package/lib/__templates__/nuxt-vue/package.json +35 -0
  53. package/lib/__templates__/nuxt-vue/pnpm-lock.yaml +8759 -0
  54. package/lib/__templates__/nuxt-vue/postcss.config.mjs +8 -0
  55. package/lib/__templates__/nuxt-vue/public/favicon.ico +0 -0
  56. package/lib/__templates__/nuxt-vue/public/robots.txt +2 -0
  57. package/lib/__templates__/nuxt-vue/scripts/build.sh +14 -0
  58. package/lib/__templates__/nuxt-vue/scripts/dev.sh +39 -0
  59. package/lib/__templates__/nuxt-vue/scripts/prepare.sh +14 -0
  60. package/lib/__templates__/nuxt-vue/scripts/start.sh +21 -0
  61. package/lib/__templates__/nuxt-vue/server/api/hello.ts +10 -0
  62. package/lib/__templates__/nuxt-vue/server/middleware/logger.ts +10 -0
  63. package/lib/__templates__/nuxt-vue/server/routes/health.ts +10 -0
  64. package/lib/__templates__/nuxt-vue/tailwind.config.js +13 -0
  65. package/lib/__templates__/nuxt-vue/template.config.js +87 -0
  66. package/lib/__templates__/nuxt-vue/tsconfig.json +18 -0
  67. package/lib/__templates__/taro/.coze +14 -0
  68. package/lib/__templates__/taro/.cozeproj/scripts/deploy_build.sh +19 -0
  69. package/lib/__templates__/taro/.cozeproj/scripts/deploy_run.sh +14 -0
  70. package/lib/__templates__/taro/.cozeproj/scripts/dev_build.sh +2 -0
  71. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +151 -0
  72. package/lib/__templates__/taro/.cozeproj/scripts/init_env.sh +5 -0
  73. package/lib/__templates__/taro/.cozeproj/scripts/pack.sh +24 -0
  74. package/lib/__templates__/taro/README.md +763 -0
  75. package/lib/__templates__/taro/_gitignore +40 -0
  76. package/lib/__templates__/taro/_npmrc +18 -0
  77. package/lib/__templates__/taro/babel.config.js +12 -0
  78. package/lib/__templates__/taro/config/dev.ts +9 -0
  79. package/lib/__templates__/taro/config/index.ts +238 -0
  80. package/lib/__templates__/taro/config/prod.ts +34 -0
  81. package/lib/__templates__/taro/eslint.config.mjs +135 -0
  82. package/lib/__templates__/taro/key/private.appid.key +0 -0
  83. package/lib/__templates__/taro/package.json +112 -0
  84. package/lib/__templates__/taro/patches/@tarojs__plugin-mini-ci@4.1.9.patch +30 -0
  85. package/lib/__templates__/taro/pnpm-lock.yaml +23412 -0
  86. package/lib/__templates__/taro/pnpm-workspace.yaml +2 -0
  87. package/lib/__templates__/taro/project.config.json +15 -0
  88. package/lib/__templates__/taro/server/nest-cli.json +10 -0
  89. package/lib/__templates__/taro/server/package.json +40 -0
  90. package/lib/__templates__/taro/server/src/app.controller.ts +23 -0
  91. package/lib/__templates__/taro/server/src/app.module.ts +10 -0
  92. package/lib/__templates__/taro/server/src/app.service.ts +8 -0
  93. package/lib/__templates__/taro/server/src/interceptors/http-status.interceptor.ts +23 -0
  94. package/lib/__templates__/taro/server/src/main.ts +49 -0
  95. package/lib/__templates__/taro/server/tsconfig.json +24 -0
  96. package/lib/__templates__/taro/src/app.config.ts +11 -0
  97. package/lib/__templates__/taro/src/app.css +156 -0
  98. package/lib/__templates__/taro/src/app.tsx +9 -0
  99. package/lib/__templates__/taro/src/components/ui/accordion.tsx +159 -0
  100. package/lib/__templates__/taro/src/components/ui/alert-dialog.tsx +260 -0
  101. package/lib/__templates__/taro/src/components/ui/alert.tsx +60 -0
  102. package/lib/__templates__/taro/src/components/ui/aspect-ratio.tsx +36 -0
  103. package/lib/__templates__/taro/src/components/ui/avatar.tsx +84 -0
  104. package/lib/__templates__/taro/src/components/ui/badge.tsx +37 -0
  105. package/lib/__templates__/taro/src/components/ui/breadcrumb.tsx +117 -0
  106. package/lib/__templates__/taro/src/components/ui/button-group.tsx +83 -0
  107. package/lib/__templates__/taro/src/components/ui/button.tsx +67 -0
  108. package/lib/__templates__/taro/src/components/ui/calendar.tsx +394 -0
  109. package/lib/__templates__/taro/src/components/ui/card.tsx +108 -0
  110. package/lib/__templates__/taro/src/components/ui/carousel.tsx +228 -0
  111. package/lib/__templates__/taro/src/components/ui/checkbox.tsx +58 -0
  112. package/lib/__templates__/taro/src/components/ui/code-block.tsx +169 -0
  113. package/lib/__templates__/taro/src/components/ui/collapsible.tsx +71 -0
  114. package/lib/__templates__/taro/src/components/ui/command.tsx +385 -0
  115. package/lib/__templates__/taro/src/components/ui/context-menu.tsx +614 -0
  116. package/lib/__templates__/taro/src/components/ui/dialog.tsx +256 -0
  117. package/lib/__templates__/taro/src/components/ui/drawer.tsx +192 -0
  118. package/lib/__templates__/taro/src/components/ui/dropdown-menu.tsx +561 -0
  119. package/lib/__templates__/taro/src/components/ui/field.tsx +228 -0
  120. package/lib/__templates__/taro/src/components/ui/hover-card.tsx +282 -0
  121. package/lib/__templates__/taro/src/components/ui/input-group.tsx +197 -0
  122. package/lib/__templates__/taro/src/components/ui/input-otp.tsx +136 -0
  123. package/lib/__templates__/taro/src/components/ui/input.tsx +56 -0
  124. package/lib/__templates__/taro/src/components/ui/label.tsx +24 -0
  125. package/lib/__templates__/taro/src/components/ui/menubar.tsx +595 -0
  126. package/lib/__templates__/taro/src/components/ui/navigation-menu.tsx +264 -0
  127. package/lib/__templates__/taro/src/components/ui/pagination.tsx +118 -0
  128. package/lib/__templates__/taro/src/components/ui/popover.tsx +291 -0
  129. package/lib/__templates__/taro/src/components/ui/portal.tsx +19 -0
  130. package/lib/__templates__/taro/src/components/ui/progress.tsx +28 -0
  131. package/lib/__templates__/taro/src/components/ui/radio-group.tsx +64 -0
  132. package/lib/__templates__/taro/src/components/ui/resizable.tsx +346 -0
  133. package/lib/__templates__/taro/src/components/ui/scroll-area.tsx +34 -0
  134. package/lib/__templates__/taro/src/components/ui/select.tsx +438 -0
  135. package/lib/__templates__/taro/src/components/ui/separator.tsx +30 -0
  136. package/lib/__templates__/taro/src/components/ui/sheet.tsx +262 -0
  137. package/lib/__templates__/taro/src/components/ui/skeleton.tsx +17 -0
  138. package/lib/__templates__/taro/src/components/ui/slider.tsx +203 -0
  139. package/lib/__templates__/taro/src/components/ui/sonner.tsx +1 -0
  140. package/lib/__templates__/taro/src/components/ui/switch.tsx +55 -0
  141. package/lib/__templates__/taro/src/components/ui/table.tsx +142 -0
  142. package/lib/__templates__/taro/src/components/ui/tabs.tsx +114 -0
  143. package/lib/__templates__/taro/src/components/ui/textarea.tsx +54 -0
  144. package/lib/__templates__/taro/src/components/ui/toast.tsx +517 -0
  145. package/lib/__templates__/taro/src/components/ui/toggle-group.tsx +120 -0
  146. package/lib/__templates__/taro/src/components/ui/toggle.tsx +77 -0
  147. package/lib/__templates__/taro/src/components/ui/tooltip.tsx +455 -0
  148. package/lib/__templates__/taro/src/index.html +39 -0
  149. package/lib/__templates__/taro/src/lib/hooks/use-keyboard-offset.ts +37 -0
  150. package/lib/__templates__/taro/src/lib/measure.ts +115 -0
  151. package/lib/__templates__/taro/src/lib/platform.ts +12 -0
  152. package/lib/__templates__/taro/src/lib/utils.ts +6 -0
  153. package/lib/__templates__/taro/src/network.ts +39 -0
  154. package/lib/__templates__/taro/src/pages/index/index.config.ts +3 -0
  155. package/lib/__templates__/taro/src/pages/index/index.css +1 -0
  156. package/lib/__templates__/taro/src/pages/index/index.tsx +33 -0
  157. package/lib/__templates__/taro/src/presets/dev-debug.ts +23 -0
  158. package/lib/__templates__/taro/src/presets/h5-container.tsx +15 -0
  159. package/lib/__templates__/taro/src/presets/h5-navbar.tsx +238 -0
  160. package/lib/__templates__/taro/src/presets/h5-styles.ts +220 -0
  161. package/lib/__templates__/taro/src/presets/index.tsx +18 -0
  162. package/lib/__templates__/taro/stylelint.config.mjs +4 -0
  163. package/lib/__templates__/taro/template.config.js +68 -0
  164. package/lib/__templates__/taro/tsconfig.json +29 -0
  165. package/lib/__templates__/taro/types/global.d.ts +32 -0
  166. package/lib/__templates__/templates.json +75 -0
  167. package/lib/__templates__/vite/AGENTS.md +41 -0
  168. package/lib/__templates__/vite/README.md +190 -11
  169. package/lib/__templates__/vite/_gitignore +1 -0
  170. package/lib/__templates__/vite/eslint.config.mjs +6 -1
  171. package/lib/__templates__/vite/package.json +14 -3
  172. package/lib/__templates__/vite/pnpm-lock.yaml +820 -1593
  173. package/lib/__templates__/vite/scripts/build.sh +4 -1
  174. package/lib/__templates__/vite/scripts/dev.sh +9 -2
  175. package/lib/__templates__/vite/scripts/start.sh +9 -3
  176. package/lib/__templates__/vite/server/routes/index.ts +31 -0
  177. package/lib/__templates__/vite/server/server.ts +65 -0
  178. package/lib/__templates__/vite/server/vite.ts +67 -0
  179. package/lib/__templates__/vite/src/main.ts +17 -47
  180. package/lib/__templates__/vite/template.config.js +49 -14
  181. package/lib/__templates__/vite/tsconfig.json +4 -3
  182. package/lib/__templates__/vite/vite.config.ts +5 -0
  183. package/lib/cli.js +2983 -209
  184. package/package.json +10 -3
package/lib/cli.js CHANGED
@@ -4,6 +4,11 @@
4
4
  var commander = require('commander');
5
5
  var path = require('path');
6
6
  var fs = require('fs');
7
+ var debug = require('debug');
8
+ var node_http = require('node:http');
9
+ var node_https = require('node:https');
10
+ var node_path = require('node:path');
11
+ var node_fs = require('node:fs');
7
12
  var shelljs = require('shelljs');
8
13
  var perf_hooks = require('perf_hooks');
9
14
  var fs$1 = require('fs/promises');
@@ -127,6 +132,2156 @@ const generateTemplatesHelpText = () => {
127
132
  return lines.join('\n');
128
133
  };
129
134
 
135
+ var DEFAULT_SIZE = 10;
136
+ var DEFAULT_WAIT = 1000;
137
+ var stringifyBatch = function (list) {
138
+ return JSON.stringify({
139
+ ev_type: 'batch',
140
+ list: list,
141
+ });
142
+ };
143
+ function createBatchSender(config) {
144
+ var transport = config.transport;
145
+ var endpoint = config.endpoint, _a = config.size, size = _a === void 0 ? DEFAULT_SIZE : _a, _b = config.wait, wait = _b === void 0 ? DEFAULT_WAIT : _b;
146
+ var batch = [];
147
+ var tid = 0;
148
+ var fail;
149
+ var success;
150
+ var sender = {
151
+ getSize: function () {
152
+ return size;
153
+ },
154
+ getWait: function () {
155
+ return wait;
156
+ },
157
+ setSize: function (v) {
158
+ size = v;
159
+ },
160
+ setWait: function (v) {
161
+ wait = v;
162
+ },
163
+ getEndpoint: function () {
164
+ return endpoint;
165
+ },
166
+ setEndpoint: function (v) {
167
+ endpoint = v;
168
+ },
169
+ send: function (e) {
170
+ batch.push(e);
171
+ if (batch.length >= size) {
172
+ sendBatch.call(this);
173
+ }
174
+ clearTimeout(tid);
175
+ tid = setTimeout(sendBatch.bind(this), wait);
176
+ },
177
+ flush: function () {
178
+ clearTimeout(tid);
179
+ sendBatch.call(this);
180
+ },
181
+ getBatchData: function () {
182
+ return batch.length ? stringifyBatch(batch) : '';
183
+ },
184
+ clear: function () {
185
+ clearTimeout(tid);
186
+ batch = [];
187
+ },
188
+ fail: function (cb) {
189
+ fail = cb;
190
+ },
191
+ success: function (cb) {
192
+ success = cb;
193
+ },
194
+ };
195
+ function sendBatch() {
196
+ if (!batch.length) {
197
+ return;
198
+ }
199
+ var data = this.getBatchData();
200
+ transport.post({
201
+ url: endpoint,
202
+ data: data,
203
+ fail: function (err) {
204
+ fail && fail(err, data);
205
+ },
206
+ success: function () {
207
+ success && success(data);
208
+ },
209
+ });
210
+ batch = [];
211
+ }
212
+ return sender;
213
+ }
214
+
215
+ /*! *****************************************************************************
216
+ Copyright (c) Microsoft Corporation.
217
+
218
+ Permission to use, copy, modify, and/or distribute this software for any
219
+ purpose with or without fee is hereby granted.
220
+
221
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
222
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
223
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
224
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
225
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
226
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
227
+ PERFORMANCE OF THIS SOFTWARE.
228
+ ***************************************************************************** */
229
+
230
+ var __assign = function() {
231
+ __assign = Object.assign || function __assign(t) {
232
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
233
+ s = arguments[i];
234
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
235
+ }
236
+ return t;
237
+ };
238
+ return __assign.apply(this, arguments);
239
+ };
240
+
241
+ function __values(o) {
242
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
243
+ if (m) return m.call(o);
244
+ if (o && typeof o.length === "number") return {
245
+ next: function () {
246
+ if (o && i >= o.length) o = void 0;
247
+ return { value: o && o[i++], done: !o };
248
+ }
249
+ };
250
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
251
+ }
252
+
253
+ function __read(o, n) {
254
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
255
+ if (!m) return o;
256
+ var i = m.call(o), r, ar = [], e;
257
+ try {
258
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
259
+ }
260
+ catch (error) { e = { error: error }; }
261
+ finally {
262
+ try {
263
+ if (r && !r.done && (m = i["return"])) m.call(i);
264
+ }
265
+ finally { if (e) throw e.error; }
266
+ }
267
+ return ar;
268
+ }
269
+
270
+ function __spreadArray(to, from, pack) {
271
+ if (arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
272
+ if (ar || !(i in from)) {
273
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
274
+ ar[i] = from[i];
275
+ }
276
+ }
277
+ return to.concat(ar || Array.prototype.slice.call(from));
278
+ }
279
+
280
+ var noop$1 = function () { return ({}); };
281
+ function id(v) {
282
+ return v;
283
+ }
284
+
285
+ // eslint-disable-next-line @typescript-eslint/ban-types
286
+ function isObject(o) {
287
+ return typeof o === 'object' && o !== null;
288
+ }
289
+ var objProto = Object.prototype;
290
+ function isArray(o) {
291
+ return objProto.toString.call(o) === '[object Array]';
292
+ }
293
+ function isBoolean(o) {
294
+ return typeof o === 'boolean';
295
+ }
296
+ function isNumber(o) {
297
+ return typeof o === 'number';
298
+ }
299
+ function isString(o) {
300
+ return typeof o === 'string';
301
+ }
302
+
303
+ // 检查数组中是否有元素
304
+ function arrayIncludes(array, value) {
305
+ if (!isArray(array)) {
306
+ return false;
307
+ }
308
+ if (array.length === 0) {
309
+ return false;
310
+ }
311
+ var k = 0;
312
+ while (k < array.length) {
313
+ if (array[k] === value) {
314
+ return true;
315
+ }
316
+ k++;
317
+ }
318
+ return false;
319
+ }
320
+ var arrayRemove = function (arr, e) {
321
+ if (!isArray(arr)) {
322
+ return arr;
323
+ }
324
+ var i = arr.indexOf(e);
325
+ if (i >= 0) {
326
+ var arr_ = arr.slice();
327
+ arr_.splice(i, 1);
328
+ return arr_;
329
+ }
330
+ return arr;
331
+ };
332
+ /**
333
+ * 按路径访问对象属性
334
+ * @param target 待访问对象
335
+ * @param property 访问属性路径
336
+ * @param { (target: any, property: string): any } visitor 访问器
337
+ */
338
+ var safeVisit = function (target, path, visitor) {
339
+ var _a, _b;
340
+ var paths = path.split('.');
341
+ var _c = __read(paths), method = _c[0], rest = _c.slice(1);
342
+ while (target && rest.length > 0) {
343
+ target = target[method];
344
+ _a = rest, _b = __read(_a), method = _b[0], rest = _b.slice(1);
345
+ }
346
+ if (!target) {
347
+ return undefined;
348
+ }
349
+ return visitor(target, method);
350
+ };
351
+
352
+ function safeStringify(a) {
353
+ try {
354
+ return isString(a) ? a : JSON.stringify(a);
355
+ }
356
+ catch (err) {
357
+ return '[FAILED_TO_STRINGIFY]:' + String(err);
358
+ }
359
+ }
360
+
361
+ function createContextAgent() {
362
+ var context = {};
363
+ var stringified = {};
364
+ var contextAgent = {
365
+ set: function (k, v) {
366
+ context[k] = v;
367
+ stringified[k] = safeStringify(v);
368
+ return contextAgent;
369
+ },
370
+ merge: function (ctx) {
371
+ context = __assign(__assign({}, context), ctx);
372
+ Object.keys(ctx).forEach(function (key) {
373
+ stringified[key] = safeStringify(ctx[key]);
374
+ });
375
+ return contextAgent;
376
+ },
377
+ delete: function (k) {
378
+ delete context[k];
379
+ delete stringified[k];
380
+ return contextAgent;
381
+ },
382
+ clear: function () {
383
+ context = {};
384
+ stringified = {};
385
+ return contextAgent;
386
+ },
387
+ get: function (k) {
388
+ return stringified[k];
389
+ },
390
+ toString: function () {
391
+ return __assign({}, stringified);
392
+ },
393
+ };
394
+ return contextAgent;
395
+ }
396
+
397
+ var getPrintString = function () {
398
+ // @ts-expect-error
399
+ if (''.padStart) {
400
+ return function (str, prefixLength) {
401
+ if (prefixLength === void 0) { prefixLength = 8; }
402
+ return str.padStart(prefixLength, ' ');
403
+ };
404
+ }
405
+ return function (str) { return str; };
406
+ };
407
+ var printString = getPrintString();
408
+ var errCount = 0;
409
+ var error = function () {
410
+ var args = [];
411
+ for (var _i = 0; _i < arguments.length; _i++) {
412
+ args[_i] = arguments[_i];
413
+ }
414
+ // eslint-disable-next-line no-console
415
+ console.error.apply(console, __spreadArray(['[SDK]', Date.now(), printString("" + errCount++)], __read(args), false));
416
+ };
417
+ var warnCount = 0;
418
+ var warn = function () {
419
+ var args = [];
420
+ for (var _i = 0; _i < arguments.length; _i++) {
421
+ args[_i] = arguments[_i];
422
+ }
423
+ // eslint-disable-next-line no-console
424
+ console.warn.apply(console, __spreadArray(['[SDK]', Date.now(), printString("" + warnCount++)], __read(args), false));
425
+ };
426
+
427
+ var isHitBySampleRate = function (sampleRate) {
428
+ if (Math.random() < Number(sampleRate)) {
429
+ return true;
430
+ }
431
+ return false;
432
+ };
433
+ var isHitByRandom = function (random, sampleRate) {
434
+ if (random < Number(sampleRate)) {
435
+ return true;
436
+ }
437
+ return false;
438
+ };
439
+
440
+ var runProcessors = function (fns) {
441
+ return function (e) {
442
+ var r = e;
443
+ for (var i = 0; i < fns.length; i++) {
444
+ if (r) {
445
+ try {
446
+ r = fns[i](r);
447
+ }
448
+ catch (err) {
449
+ error(err);
450
+ }
451
+ }
452
+ else {
453
+ break;
454
+ }
455
+ }
456
+ return r;
457
+ };
458
+ };
459
+
460
+ /**
461
+ * 生成uuid
462
+ * stolen from https://github.com/kelektiv/node-uuid#readme uuid/v4
463
+ *
464
+ * @returns
465
+ */
466
+ function mathRNG() {
467
+ var rnds = new Array(16);
468
+ var r = 0;
469
+ for (var i = 0; i < 16; i++) {
470
+ if ((i & 0x03) === 0) {
471
+ r = Math.random() * 0x100000000;
472
+ }
473
+ rnds[i] = (r >>> ((i & 0x03) << 3)) & 0xff;
474
+ }
475
+ return rnds;
476
+ }
477
+ function bytesToUuid(buf) {
478
+ var byteToHex = [];
479
+ for (var index = 0; index < 256; ++index) {
480
+ byteToHex[index] = (index + 0x100).toString(16).substr(1);
481
+ }
482
+ var i = 0;
483
+ var bth = byteToHex;
484
+ // join used to fix memory issue caused by concatenation: https://bugs.chromium.org/p/v8/issues/detail?id=3175#c4
485
+ return [
486
+ bth[buf[i++]],
487
+ bth[buf[i++]],
488
+ bth[buf[i++]],
489
+ bth[buf[i++]],
490
+ '-',
491
+ bth[buf[i++]],
492
+ bth[buf[i++]],
493
+ '-',
494
+ bth[buf[i++]],
495
+ bth[buf[i++]],
496
+ '-',
497
+ bth[buf[i++]],
498
+ bth[buf[i++]],
499
+ '-',
500
+ bth[buf[i++]],
501
+ bth[buf[i++]],
502
+ bth[buf[i++]],
503
+ bth[buf[i++]],
504
+ bth[buf[i++]],
505
+ bth[buf[i++]],
506
+ ].join('');
507
+ }
508
+ function uuid() {
509
+ var rnds = mathRNG();
510
+ // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
511
+ rnds[6] = (rnds[6] & 0x0f) | 0x40;
512
+ rnds[8] = (rnds[8] & 0x3f) | 0x80;
513
+ return bytesToUuid(rnds);
514
+ }
515
+
516
+ function createDestroyAgent() {
517
+ var destroyed = false;
518
+ var data = {};
519
+ var removeTearDownGroup = function (tearDownGroup) {
520
+ tearDownGroup.length &&
521
+ tearDownGroup.forEach(function (v) {
522
+ try {
523
+ v();
524
+ // eslint-disable-next-line no-empty
525
+ }
526
+ catch (_a) { }
527
+ });
528
+ tearDownGroup.length = 0;
529
+ };
530
+ var removeByPluginName = function (pluginName) {
531
+ data[pluginName] &&
532
+ data[pluginName].forEach(function (e) {
533
+ removeTearDownGroup(e[1]);
534
+ });
535
+ data[pluginName] = undefined;
536
+ };
537
+ var removeByEvType = function (evType) {
538
+ Object.keys(data).forEach(function (k) {
539
+ data[k] &&
540
+ data[k].forEach(function (e) {
541
+ if (e[0] === evType) {
542
+ removeTearDownGroup(e[1]);
543
+ }
544
+ });
545
+ });
546
+ };
547
+ return {
548
+ /**
549
+ * register tearDownGroup for a single plugin.
550
+ */
551
+ set: function (pluginName, evType, tearDownGroup) {
552
+ if (data[pluginName])
553
+ data[pluginName].push([evType, tearDownGroup]);
554
+ else
555
+ data[pluginName] = [[evType, tearDownGroup]];
556
+ // auto remove tearDownGroup if destroyed
557
+ destroyed && removeTearDownGroup(tearDownGroup);
558
+ },
559
+ has: function (pluginName) {
560
+ return !!data[pluginName];
561
+ },
562
+ /**
563
+ * remove tearDownGroup for a single plugin.
564
+ */
565
+ remove: removeByPluginName,
566
+ /**
567
+ * remove tearDownGroup by event type
568
+ */
569
+ removeByEvType: removeByEvType,
570
+ /**
571
+ * clear all tearDownGroup
572
+ */
573
+ clear: function () {
574
+ destroyed = true;
575
+ Object.keys(data).forEach(function (k) {
576
+ removeByPluginName(k);
577
+ });
578
+ },
579
+ };
580
+ }
581
+
582
+ // max size of preStartQueue
583
+ var PRESTART_QUEUE_MAX_SIZE = 500;
584
+ // slice size to operate preStartQueue
585
+ var PRESTART_QUEUE_OP_SLICE_SIZE = 50;
586
+ function cachePreStartData(client, preStartQueue, processed) {
587
+ preStartQueue.push(processed);
588
+ if (preStartQueue.length < PRESTART_QUEUE_MAX_SIZE) {
589
+ return;
590
+ }
591
+ // delete some data to prevent OOM
592
+ var deleteData = preStartQueue.splice(0, PRESTART_QUEUE_OP_SLICE_SIZE);
593
+ if (client.savePreStartDataToDb) {
594
+ void client.savePreStartDataToDb(deleteData);
595
+ }
596
+ }
597
+ function consumePreStartData(client) {
598
+ var preStartQueue = client.getPreStartQueue();
599
+ preStartQueue.forEach(function (e) { return client.build(e); });
600
+ preStartQueue.length = 0;
601
+ }
602
+
603
+ var EVENTS = [
604
+ 'init',
605
+ 'start',
606
+ 'config',
607
+ 'beforeDestroy',
608
+ 'provide',
609
+ 'beforeReport',
610
+ 'report',
611
+ 'beforeBuild',
612
+ 'build',
613
+ 'beforeSend',
614
+ 'send',
615
+ 'beforeConfig',
616
+ ];
617
+
618
+ function createClient(creationConfig) {
619
+ var builder = creationConfig.builder, createSender = creationConfig.createSender, createDefaultConfig = creationConfig.createDefaultConfig, createConfigManager = creationConfig.createConfigManager, userConfigNormalizer = creationConfig.userConfigNormalizer, initConfigNormalizer = creationConfig.initConfigNormalizer, validateInitConfig = creationConfig.validateInitConfig;
620
+ var sender;
621
+ var configManager;
622
+ var handlers = {};
623
+ EVENTS.forEach(function (e) { return (handlers[e] = []); });
624
+ var inited = false;
625
+ var started = false;
626
+ var destroyed = false;
627
+ // 缓存 start 之前 build 的事件
628
+ var preStartQueue = [];
629
+ // 禁止通过 provide 挂载的字段名
630
+ var reservedNames = [];
631
+ var destroyAgent = createDestroyAgent();
632
+ var client = {
633
+ getBuilder: function () { return builder; },
634
+ getSender: function () { return sender; },
635
+ getPreStartQueue: function () { return preStartQueue; },
636
+ init: function (c) {
637
+ if (inited) {
638
+ warn('already inited');
639
+ return;
640
+ }
641
+ if (c && isObject(c) && validateInitConfig(c)) {
642
+ var defaultConfig = createDefaultConfig(c);
643
+ if (!defaultConfig) {
644
+ throw new Error('defaultConfig missing');
645
+ }
646
+ var initConfig = initConfigNormalizer(c);
647
+ configManager = createConfigManager(defaultConfig);
648
+ configManager.setConfig(initConfig);
649
+ configManager.onChange(function () {
650
+ handle('config');
651
+ });
652
+ sender = createSender(configManager.getConfig());
653
+ if (!sender) {
654
+ throw new Error('sender missing');
655
+ }
656
+ inited = true;
657
+ handle('init', true);
658
+ }
659
+ else {
660
+ throw new Error('invalid InitConfig, init failed');
661
+ }
662
+ },
663
+ set: function (c) {
664
+ if (!inited) {
665
+ return;
666
+ }
667
+ if (c && isObject(c)) {
668
+ handle('beforeConfig', false, c);
669
+ configManager === null || configManager === void 0 ? void 0 : configManager.setConfig(c);
670
+ }
671
+ },
672
+ config: function (c) {
673
+ if (!inited) {
674
+ return;
675
+ }
676
+ if (c && isObject(c)) {
677
+ handle('beforeConfig', false, c);
678
+ configManager === null || configManager === void 0 ? void 0 : configManager.setConfig(userConfigNormalizer(c));
679
+ }
680
+ return configManager === null || configManager === void 0 ? void 0 : configManager.getConfig();
681
+ },
682
+ provide: function (name, value) {
683
+ if (arrayIncludes(reservedNames, name)) {
684
+ warn("cannot provide " + name + ", reserved");
685
+ return;
686
+ }
687
+ client[name] = value;
688
+ handle('provide', false, name);
689
+ },
690
+ start: function () {
691
+ if (!inited) {
692
+ return;
693
+ }
694
+ if (started) {
695
+ return;
696
+ }
697
+ configManager === null || configManager === void 0 ? void 0 : configManager.onReady(function () {
698
+ started = true;
699
+ handle('start', true);
700
+ consumePreStartData(client);
701
+ });
702
+ },
703
+ report: function (data) {
704
+ if (!data) {
705
+ return;
706
+ }
707
+ var preReport = runProcessors(handlers['beforeReport'])(data);
708
+ if (!preReport) {
709
+ return;
710
+ }
711
+ var processed = runProcessors(handlers['report'])(preReport);
712
+ if (!processed) {
713
+ return;
714
+ }
715
+ if (started) {
716
+ this.build(processed);
717
+ }
718
+ else {
719
+ cachePreStartData(client, preStartQueue, processed);
720
+ }
721
+ },
722
+ build: function (data) {
723
+ if (!started) {
724
+ return;
725
+ }
726
+ var preBuild = runProcessors(handlers['beforeBuild'])(data);
727
+ if (!preBuild) {
728
+ return;
729
+ }
730
+ var built = builder.build(preBuild);
731
+ if (!built) {
732
+ return;
733
+ }
734
+ var processed = runProcessors(handlers['build'])(built);
735
+ if (!processed) {
736
+ return;
737
+ }
738
+ this.send(processed);
739
+ },
740
+ send: function (data) {
741
+ if (!started) {
742
+ return;
743
+ }
744
+ var processed = runProcessors(handlers['beforeSend'])(data);
745
+ if (processed) {
746
+ sender.send(processed);
747
+ handle('send', false, processed);
748
+ }
749
+ },
750
+ destroy: function () {
751
+ destroyAgent.clear();
752
+ destroyed = true;
753
+ preStartQueue.length = 0;
754
+ handle('beforeDestroy', true);
755
+ },
756
+ on: function (ev, handler) {
757
+ if ((ev === 'init' && inited) || (ev === 'start' && started) || (ev === 'beforeDestroy' && destroyed)) {
758
+ try {
759
+ ;
760
+ handler();
761
+ }
762
+ catch (_err) {
763
+ // ignore
764
+ }
765
+ }
766
+ else if (handlers[ev]) {
767
+ handlers[ev].push(handler);
768
+ }
769
+ },
770
+ off: function (ev, handler) {
771
+ if (handlers[ev])
772
+ handlers[ev] = arrayRemove(handlers[ev], handler);
773
+ },
774
+ destroyAgent: destroyAgent,
775
+ };
776
+ reservedNames = Object.keys(client);
777
+ return client;
778
+ function handle(ev, once) {
779
+ if (once === void 0) { once = false; }
780
+ var args = [];
781
+ for (var _i = 2; _i < arguments.length; _i++) {
782
+ args[_i - 2] = arguments[_i];
783
+ }
784
+ handlers[ev].forEach(function (f) {
785
+ try {
786
+ f.apply(void 0, __spreadArray([], __read(args), false));
787
+ }
788
+ catch (_err) {
789
+ // ignore
790
+ }
791
+ });
792
+ if (once) {
793
+ handlers[ev].length = 0;
794
+ }
795
+ }
796
+ }
797
+
798
+ var ContextPlugin = function (client) {
799
+ var contextAgent = createContextAgent();
800
+ client.provide('context', contextAgent);
801
+ client.on('report', function (ev) {
802
+ if (!ev.extra) {
803
+ ev.extra = {};
804
+ }
805
+ ev.extra.context = contextAgent.toString();
806
+ return ev;
807
+ });
808
+ };
809
+
810
+ function IntegrationPlugin(client, runAfterSetup) {
811
+ client.on('init', function () {
812
+ var nameList = [];
813
+ var applyIntegrations = function (integrations) {
814
+ integrations.forEach(function (integration) {
815
+ var integrationName = integration.name;
816
+ if (!arrayIncludes(nameList, integrationName)) {
817
+ nameList.push(integrationName);
818
+ integration.setup(client);
819
+ client.destroyAgent.set(integrationName, integrationName, [
820
+ function () {
821
+ nameList = arrayRemove(nameList, integrationName);
822
+ integration.tearDown && integration.tearDown();
823
+ },
824
+ ]);
825
+ }
826
+ });
827
+ };
828
+ client.provide('applyIntegrations', applyIntegrations);
829
+ var config = client.config();
830
+ if (config && config.integrations) {
831
+ applyIntegrations(config.integrations);
832
+ }
833
+ });
834
+ }
835
+
836
+ var DevtoolsPlugin = function (client) {
837
+ try {
838
+ if (typeof window === 'object' && isObject(window) && window.__SLARDAR_DEVTOOLS_GLOBAL_HOOK__) {
839
+ window.__SLARDAR_DEVTOOLS_GLOBAL_HOOK__.push(client);
840
+ }
841
+ }
842
+ catch (e) {
843
+ // ignore
844
+ }
845
+ };
846
+
847
+ var now = function () { return Date.now(); };
848
+
849
+ function getDefaultBrowser() {
850
+ if (typeof window === 'object' && isObject(window))
851
+ return window;
852
+ }
853
+
854
+ // 获取全局注册表
855
+ var getGlobalRegistry = function (global) {
856
+ if (!global)
857
+ return;
858
+ if (!global.__SLARDAR_REGISTRY__) {
859
+ global.__SLARDAR_REGISTRY__ = {
860
+ Slardar: {
861
+ plugins: [],
862
+ errors: [],
863
+ subject: {},
864
+ },
865
+ };
866
+ }
867
+ return global.__SLARDAR_REGISTRY__.Slardar;
868
+ };
869
+ var reportSelfError = function () {
870
+ var errorInfo = [];
871
+ for (var _i = 0; _i < arguments.length; _i++) {
872
+ errorInfo[_i] = arguments[_i];
873
+ }
874
+ var registry = getGlobalRegistry(getDefaultBrowser());
875
+ if (!registry)
876
+ return;
877
+ if (!registry.errors) {
878
+ registry.errors = [];
879
+ }
880
+ registry.errors.push(errorInfo);
881
+ };
882
+
883
+ /**
884
+ * Special support in Perfsee for analyzing call stacks of custom events and custom metrics.
885
+ */
886
+ // eslint-disable-next-line
887
+ var getStacksOnPerfsee = function (constructor) {
888
+ var _a;
889
+ // @ts-expect-error
890
+ if (typeof window !== 'object' || !window.__perfsee__) {
891
+ return;
892
+ }
893
+ var obj = {};
894
+ (_a = Error.captureStackTrace) === null || _a === void 0 ? void 0 : _a.call(Error, obj, constructor);
895
+ return obj.stack;
896
+ };
897
+
898
+ var CUSTOM_EV_TYPE = 'custom';
899
+
900
+ var CUSTOM_EVENT_TYPE = 'event';
901
+ var CUSTOM_LOG_TYPE = 'log';
902
+ var normalizeCustomEventData = function (raw) {
903
+ if (!raw || !isObject(raw)) {
904
+ return;
905
+ }
906
+ // name is required
907
+ if (!raw['name'] || !isString(raw['name'])) {
908
+ return;
909
+ }
910
+ var res = {
911
+ name: raw['name'],
912
+ type: CUSTOM_EVENT_TYPE,
913
+ };
914
+ if ('metrics' in raw && isObject(raw['metrics'])) {
915
+ var rMetrics = raw['metrics'];
916
+ var metrics = {};
917
+ for (var k in rMetrics) {
918
+ if (isNumber(rMetrics[k])) {
919
+ metrics[k] = rMetrics[k];
920
+ }
921
+ }
922
+ res.metrics = metrics;
923
+ }
924
+ if ('categories' in raw && isObject(raw['categories'])) {
925
+ var rCategories = raw['categories'];
926
+ var categories = {};
927
+ for (var k in rCategories) {
928
+ categories[k] = safeStringify(rCategories[k]);
929
+ }
930
+ res.categories = categories;
931
+ }
932
+ if ('attached_log' in raw && isString(raw['attached_log'])) {
933
+ res.attached_log = raw['attached_log'];
934
+ }
935
+ return res;
936
+ };
937
+ var normalizeCustomLogData = function (raw) {
938
+ if (!raw || !isObject(raw)) {
939
+ return;
940
+ }
941
+ // content is required
942
+ if (!raw['content'] || !isString(raw['content'])) {
943
+ return;
944
+ }
945
+ var rContent = raw['content'];
946
+ var res = {
947
+ content: safeStringify(rContent),
948
+ type: CUSTOM_LOG_TYPE,
949
+ level: 'info',
950
+ };
951
+ if ('level' in raw) {
952
+ res.level = raw['level'];
953
+ }
954
+ if ('extra' in raw && isObject(raw['extra'])) {
955
+ var rExtra = raw['extra'];
956
+ var metrics = {};
957
+ var categories = {};
958
+ for (var k in rExtra) {
959
+ if (isNumber(rExtra[k])) {
960
+ metrics[k] = rExtra[k];
961
+ }
962
+ else {
963
+ categories[k] = safeStringify(rExtra[k]);
964
+ }
965
+ }
966
+ res.metrics = metrics;
967
+ res.categories = categories;
968
+ }
969
+ if ('attached_log' in raw && isString(raw['attached_log'])) {
970
+ res.attached_log = raw['attached_log'];
971
+ }
972
+ return res;
973
+ };
974
+ var CustomPlugin = function (client) {
975
+ var sendEvent = function (data) {
976
+ var normalized = normalizeCustomEventData(data);
977
+ if (normalized) {
978
+ var stacks = getStacksOnPerfsee(sendEvent);
979
+ if (stacks) {
980
+ // @ts-expect-error
981
+ normalized.stacks = stacks;
982
+ }
983
+ client.report({
984
+ ev_type: CUSTOM_EV_TYPE,
985
+ payload: normalized,
986
+ extra: {
987
+ timestamp: now(),
988
+ },
989
+ });
990
+ }
991
+ };
992
+ var sendLog = function (data) {
993
+ var normalized = normalizeCustomLogData(data);
994
+ if (normalized) {
995
+ client.report({
996
+ ev_type: CUSTOM_EV_TYPE,
997
+ payload: normalized,
998
+ extra: {
999
+ timestamp: now(),
1000
+ },
1001
+ });
1002
+ }
1003
+ };
1004
+ client.provide('sendEvent', sendEvent);
1005
+ client.provide('sendLog', sendLog);
1006
+ };
1007
+
1008
+ /* eslint-disable @typescript-eslint/prefer-for-of */
1009
+ var withSampleRate = function (ev, sampleRate) {
1010
+ var common = ev.common || {};
1011
+ common.sample_rate = sampleRate;
1012
+ ev.common = common;
1013
+ return ev;
1014
+ };
1015
+ var hitFnWithRandom = function (preCalc, sampleRate, isHitBySampleRate, random, isHitByRandom) {
1016
+ return preCalc
1017
+ ? (function (h) { return function () {
1018
+ return h;
1019
+ }; })(isHitByRandom(random, sampleRate))
1020
+ : function () { return isHitBySampleRate(sampleRate); };
1021
+ };
1022
+ var parseValues = function (values, type) {
1023
+ return values.map(function (v) {
1024
+ switch (type) {
1025
+ case 'number':
1026
+ return Number(v);
1027
+ case 'boolean':
1028
+ return v === '1';
1029
+ case 'string': // default to string
1030
+ default:
1031
+ return String(v);
1032
+ }
1033
+ });
1034
+ };
1035
+ var checkVal = function (val, values, op) {
1036
+ switch (op) {
1037
+ case 'eq':
1038
+ return arrayIncludes(values, val);
1039
+ case 'neq':
1040
+ return !arrayIncludes(values, val);
1041
+ case 'gt':
1042
+ return val > values[0];
1043
+ case 'gte':
1044
+ return val >= values[0];
1045
+ case 'lt':
1046
+ return val < values[0];
1047
+ case 'lte':
1048
+ return val <= values[0];
1049
+ case 'regex':
1050
+ return Boolean(val.match(new RegExp(values.join('|'))));
1051
+ case 'not_regex':
1052
+ return !val.match(new RegExp(values.join('|')));
1053
+ default: {
1054
+ // unknown op
1055
+ return false;
1056
+ }
1057
+ }
1058
+ };
1059
+ var checkFilter = function (ev, field, op, values) {
1060
+ var val = safeVisit(ev, field, function (t, p) {
1061
+ return t[p];
1062
+ });
1063
+ if (val === undefined) {
1064
+ return false;
1065
+ }
1066
+ var field_type = isBoolean(val) ? 'bool' : isNumber(val) ? 'number' : 'string';
1067
+ return checkVal(val, parseValues(values, field_type), op);
1068
+ };
1069
+ var matchFilter = function (ev, filter) {
1070
+ try {
1071
+ return filter.type === 'rule'
1072
+ ? checkFilter(ev, filter.field, filter.op, filter.values)
1073
+ : filter.type === 'and'
1074
+ ? filter.children.every(function (f) { return matchFilter(ev, f); })
1075
+ : filter.children.some(function (f) { return matchFilter(ev, f); });
1076
+ }
1077
+ catch (e) {
1078
+ reportSelfError(e);
1079
+ return false;
1080
+ }
1081
+ };
1082
+ var getHitMap = function (rules, preCalcHit, baseRate, isHitBySampleRate, random, isHitByRandom) {
1083
+ var hitMap = {};
1084
+ Object.keys(rules).forEach(function (name) {
1085
+ var _a = rules[name], enable = _a.enable, sample_rate = _a.sample_rate, conditional_sample_rules = _a.conditional_sample_rules;
1086
+ if (enable) {
1087
+ hitMap[name] = {
1088
+ enable: enable,
1089
+ sample_rate: sample_rate,
1090
+ effectiveSampleRate: sample_rate * baseRate,
1091
+ hit: hitFnWithRandom(preCalcHit, sample_rate, isHitBySampleRate, random, isHitByRandom),
1092
+ };
1093
+ if (conditional_sample_rules) {
1094
+ hitMap[name].conditional_hit_rules = conditional_sample_rules.map(function (_a) {
1095
+ var s = _a.sample_rate, filter = _a.filter;
1096
+ return ({
1097
+ sample_rate: s,
1098
+ hit: hitFnWithRandom(preCalcHit, s, isHitBySampleRate, random, isHitByRandom),
1099
+ effectiveSampleRate: s * baseRate,
1100
+ filter: filter,
1101
+ });
1102
+ });
1103
+ }
1104
+ }
1105
+ else {
1106
+ hitMap[name] = {
1107
+ enable: enable,
1108
+ hit: function () {
1109
+ /* istanbul ignore next */
1110
+ return false;
1111
+ },
1112
+ sample_rate: 0,
1113
+ effectiveSampleRate: 0,
1114
+ };
1115
+ }
1116
+ });
1117
+ return hitMap;
1118
+ };
1119
+ var getSampler = function (userId, config, isHitBySampleRate, isHitByRandom, destroyFns) {
1120
+ if (!config)
1121
+ return id;
1122
+ // r的设计是为了允许外部传入随机数,用于彻底实现按用户采样
1123
+ var baseRate = config.sample_rate, include_users = config.include_users, sample_granularity = config.sample_granularity, rules = config.rules, _a = config.r, random = _a === void 0 ? Math.random() : _a;
1124
+ // 用户名单采样
1125
+ var userHit = arrayIncludes(include_users, userId);
1126
+ if (userHit) {
1127
+ return function (ev) { return withSampleRate(ev, 1); };
1128
+ }
1129
+ // should pre calculate hit
1130
+ var preCalcHit = sample_granularity === 'session';
1131
+ var baseHit = hitFnWithRandom(preCalcHit, baseRate, isHitBySampleRate, random, isHitByRandom);
1132
+ var hitMap = getHitMap(rules, preCalcHit, baseRate, isHitBySampleRate, random, isHitByRandom);
1133
+ return function (ev) {
1134
+ var _a;
1135
+ // 总采样必须命中才有后续
1136
+ if (!baseHit()) {
1137
+ preCalcHit && destroyFns[0]();
1138
+ return false;
1139
+ }
1140
+ // 未配置的事件类型
1141
+ if (!(ev.ev_type in hitMap)) {
1142
+ return withSampleRate(ev, baseRate);
1143
+ }
1144
+ // 忽略未开启的事件类型
1145
+ if (!hitMap[ev.ev_type].enable) {
1146
+ preCalcHit && destroyFns[1](ev.ev_type);
1147
+ return false;
1148
+ }
1149
+ // 跳过采样配置
1150
+ if ((_a = ev.common) === null || _a === void 0 ? void 0 : _a.sample_rate) {
1151
+ return ev;
1152
+ }
1153
+ var hitConfig = hitMap[ev.ev_type];
1154
+ var conditions = hitConfig.conditional_hit_rules;
1155
+ if (conditions) {
1156
+ // 先判断条件采样
1157
+ for (var i = 0; i < conditions.length; i++) {
1158
+ if (matchFilter(ev, conditions[i].filter)) {
1159
+ if (conditions[i].hit()) {
1160
+ return withSampleRate(ev, conditions[i].effectiveSampleRate);
1161
+ }
1162
+ // 条件匹配后不再搜索
1163
+ return false;
1164
+ }
1165
+ }
1166
+ }
1167
+ // 事件类型采样
1168
+ if (!hitConfig.hit()) {
1169
+ // not hit ev_type and no condition, destroy side effect
1170
+ !(conditions && conditions.length) && preCalcHit && destroyFns[1](ev.ev_type);
1171
+ return false;
1172
+ }
1173
+ // 事件类型默认采样已经命中
1174
+ return withSampleRate(ev, hitConfig.effectiveSampleRate);
1175
+ };
1176
+ };
1177
+ var SamplePlugin = function (client) {
1178
+ client.on('start', function () {
1179
+ var _a = client.config(), userId = _a.userId, sample = _a.sample;
1180
+ var destroyFns = [
1181
+ function () {
1182
+ client.destroy();
1183
+ },
1184
+ function (ev_type) {
1185
+ client.destroyAgent.removeByEvType(ev_type);
1186
+ },
1187
+ ];
1188
+ var sampler = getSampler(userId, sample, isHitBySampleRate, isHitByRandom, destroyFns);
1189
+ client.on('build', sampler);
1190
+ });
1191
+ };
1192
+
1193
+ var builder = {
1194
+ build: function (e) {
1195
+ return {
1196
+ ev_type: e.ev_type,
1197
+ payload: e.payload,
1198
+ common: __assign(__assign({}, (e.extra || {})), (e.overrides || {})),
1199
+ };
1200
+ },
1201
+ };
1202
+
1203
+ var REPORT_DOMAIN = "mon.zijieapi.com";
1204
+ var SDK_VERSION = "2.1.8" ;
1205
+ var SDK_NAME = 'SDK_BASE';
1206
+ var SETTINGS_PATH = '/monitor_web/settings/browser-settings';
1207
+ var BATCH_REPORT_PATH = "/monitor_browser/collect/batch/";
1208
+ var DEFAULT_SAMPLE_CONFIG = {
1209
+ sample_rate: 1,
1210
+ include_users: [],
1211
+ sample_granularity: 'session',
1212
+ rules: {},
1213
+ };
1214
+ var DEFAULT_SENDER_SIZE = 20;
1215
+ var DEFAULT_SAMPLE_GRANULARITY = 'session';
1216
+
1217
+ function normalizeStrictFields(config) {
1218
+ var e_1, _a;
1219
+ var strictFields = ['userId', 'deviceId', 'sessionId', 'env'];
1220
+ try {
1221
+ for (var strictFields_1 = __values(strictFields), strictFields_1_1 = strictFields_1.next(); !strictFields_1_1.done; strictFields_1_1 = strictFields_1.next()) {
1222
+ var k = strictFields_1_1.value;
1223
+ if (!config[k]) {
1224
+ delete config[k];
1225
+ }
1226
+ }
1227
+ }
1228
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1229
+ finally {
1230
+ try {
1231
+ if (strictFields_1_1 && !strictFields_1_1.done && (_a = strictFields_1.return)) _a.call(strictFields_1);
1232
+ }
1233
+ finally { if (e_1) throw e_1.error; }
1234
+ }
1235
+ return config;
1236
+ }
1237
+ function normalizeInitConfig(config) {
1238
+ return normalizeStrictFields(__assign({}, config));
1239
+ }
1240
+ function validateInitConfig(config) {
1241
+ return isObject(config) && 'bid' in config && 'transport' in config;
1242
+ }
1243
+ function normalizeUserConfig(config) {
1244
+ return normalizeStrictFields(__assign({}, config));
1245
+ }
1246
+ function parseServerConfig(serverConfig) {
1247
+ if (!serverConfig) {
1248
+ return {};
1249
+ }
1250
+ var sample = serverConfig.sample, timestamp = serverConfig.timestamp, _a = serverConfig.quota_rate, quota_rate = _a === void 0 ? 1 : _a;
1251
+ if (!sample) {
1252
+ return {};
1253
+ }
1254
+ var sample_rate = sample.sample_rate, _b = sample.sample_granularity, sample_granularity = _b === void 0 ? DEFAULT_SAMPLE_GRANULARITY : _b, include_users = sample.include_users, _c = sample.rules, rules = _c === void 0 ? [] : _c;
1255
+ return {
1256
+ sample: {
1257
+ include_users: include_users,
1258
+ sample_rate: sample_rate * quota_rate,
1259
+ sample_granularity: sample_granularity,
1260
+ rules: rules.reduce(function (prev, cur) {
1261
+ var name = cur.name, enable = cur.enable, sample_rate = cur.sample_rate, conditional_sample_rules = cur.conditional_sample_rules;
1262
+ prev[name] = {
1263
+ enable: enable,
1264
+ sample_rate: sample_rate,
1265
+ conditional_sample_rules: conditional_sample_rules,
1266
+ };
1267
+ return prev;
1268
+ }, {}),
1269
+ },
1270
+ serverTimestamp: timestamp,
1271
+ };
1272
+ }
1273
+
1274
+ /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
1275
+ var getReportUrl = function (domain, path) {
1276
+ if (path === void 0) { path = BATCH_REPORT_PATH; }
1277
+ return "" + (domain && domain.indexOf('//') >= 0 ? '' : 'https://') + domain + path;
1278
+ };
1279
+ var getSettingsUrl = function (domain, path) {
1280
+ if (path === void 0) { path = SETTINGS_PATH; }
1281
+ return "" + (domain && domain.indexOf('//') >= 0 ? '' : 'https://') + domain + path;
1282
+ };
1283
+ var getDefaultUserId = function () {
1284
+ return uuid();
1285
+ };
1286
+ var getDefaultDeviceId = function () {
1287
+ return uuid();
1288
+ };
1289
+ var getViewId = function (pid) { return pid + "_" + Date.now(); };
1290
+ var getDefaultSessionId = function () {
1291
+ return uuid();
1292
+ };
1293
+
1294
+ var createConfigManager = function (defaultConfig) {
1295
+ // the merged config
1296
+ var config = defaultConfig;
1297
+ // save it so we know when initConfig is set
1298
+ var initConfig;
1299
+ // save UserConfig so we can merge with priority
1300
+ var userConfig = {};
1301
+ // save the original server config, from get_setting response
1302
+ var serverConfig;
1303
+ // cache the parsed ServerConfig, used in merge
1304
+ var parsedServerConfig;
1305
+ var onReady = noop$1;
1306
+ // call when config changed
1307
+ var onChange = noop$1;
1308
+ return {
1309
+ getConfig: function () {
1310
+ return config;
1311
+ },
1312
+ setConfig: function (c) {
1313
+ userConfig = __assign(__assign({}, userConfig), (c || {}));
1314
+ updateConfig();
1315
+ if (!initConfig) {
1316
+ // handle init
1317
+ initConfig = c;
1318
+ if (config.useLocalConfig || !config.bid) {
1319
+ parsedServerConfig = {};
1320
+ onReady();
1321
+ }
1322
+ else {
1323
+ getServerConfig(config.transport, config.domain, config.bid, function (res) {
1324
+ serverConfig = res;
1325
+ handleServerConfig();
1326
+ });
1327
+ }
1328
+ }
1329
+ return config;
1330
+ },
1331
+ onChange: function (fn) {
1332
+ onChange = fn;
1333
+ },
1334
+ onReady: function (fn) {
1335
+ onReady = fn;
1336
+ if (parsedServerConfig) {
1337
+ onReady();
1338
+ }
1339
+ },
1340
+ };
1341
+ function updateConfig() {
1342
+ var newConfig = __assign(__assign(__assign({}, defaultConfig), (parsedServerConfig || {})), userConfig);
1343
+ newConfig.sample = mergeSampleConfig(mergeSampleConfig(defaultConfig.sample, parsedServerConfig === null || parsedServerConfig === void 0 ? void 0 : parsedServerConfig.sample), userConfig.sample);
1344
+ config = newConfig;
1345
+ onChange();
1346
+ }
1347
+ function handleServerConfig() {
1348
+ parsedServerConfig = parseServerConfig(serverConfig);
1349
+ updateConfig();
1350
+ onReady();
1351
+ }
1352
+ };
1353
+ function getServerConfig(transport, domain, bid, cb) {
1354
+ if (!transport.get) {
1355
+ return cb({});
1356
+ }
1357
+ transport.get({
1358
+ withCredentials: true,
1359
+ url: getSettingsUrl(domain) + "?bid=" + bid + "&store=1",
1360
+ success: function (res) {
1361
+ cb(res.data || {});
1362
+ },
1363
+ fail: function () {
1364
+ cb({ sample: { sample_rate: 0.001 } });
1365
+ },
1366
+ });
1367
+ }
1368
+ function mergeSampleConfig(a, b) {
1369
+ if (!a || !b)
1370
+ return a || b;
1371
+ var res = __assign(__assign({}, a), b);
1372
+ res.include_users = __spreadArray(__spreadArray([], __read((a.include_users || [])), false), __read((b.include_users || [])), false);
1373
+ res.rules = __spreadArray(__spreadArray([], __read(Object.keys(a.rules || {})), false), __read(Object.keys(b.rules || {})), false).reduce(function (obj, key) {
1374
+ var _a, _b;
1375
+ if (!(key in obj)) {
1376
+ if (key in (a.rules || {}) && key in (b.rules || {})) {
1377
+ obj[key] = __assign(__assign({}, a.rules[key]), b.rules[key]);
1378
+ obj[key].conditional_sample_rules = __spreadArray(__spreadArray([], __read((a.rules[key].conditional_sample_rules || [])), false), __read((b.rules[key].conditional_sample_rules || [])), false);
1379
+ }
1380
+ else {
1381
+ obj[key] = ((_a = a.rules) === null || _a === void 0 ? void 0 : _a[key]) || ((_b = b.rules) === null || _b === void 0 ? void 0 : _b[key]);
1382
+ }
1383
+ }
1384
+ return obj;
1385
+ }, {});
1386
+ return res;
1387
+ }
1388
+
1389
+ var addEnvToSendEvent = function (ev, config) {
1390
+ var _a = config || {}, version = _a.version, name = _a.name;
1391
+ var extra = {
1392
+ url: '',
1393
+ protocol: '',
1394
+ domain: '',
1395
+ path: '',
1396
+ query: '',
1397
+ timestamp: Date.now(),
1398
+ sdk_version: version || SDK_VERSION,
1399
+ sdk_name: name || SDK_NAME,
1400
+ };
1401
+ return __assign(__assign({}, ev), { extra: __assign(__assign({}, extra), (ev.extra || {})) });
1402
+ };
1403
+ var InjectEnvPlugin = function (client) {
1404
+ client.on('report', function (ev) {
1405
+ return addEnvToSendEvent(ev, client.config());
1406
+ });
1407
+ };
1408
+
1409
+ var addConfigToReportEvent = function (ev, config) {
1410
+ var extra = {};
1411
+ extra.bid = config.bid;
1412
+ extra.pid = config.pid;
1413
+ extra.view_id = config.viewId;
1414
+ extra.user_id = config.userId;
1415
+ extra.device_id = config.deviceId;
1416
+ extra.session_id = config.sessionId;
1417
+ extra.release = config.release;
1418
+ extra.env = config.env;
1419
+ return __assign(__assign({}, ev), { extra: __assign(__assign({}, extra), (ev.extra || {})) });
1420
+ };
1421
+ var InjectConfigPlugin = function (client) {
1422
+ client.on('beforeBuild', function (ev) {
1423
+ return addConfigToReportEvent(ev, client.config());
1424
+ });
1425
+ };
1426
+
1427
+ // createSender has side effects(register onClose behaviour)
1428
+ // so it must be create lazily
1429
+ function createSender(config) {
1430
+ return createBatchSender(config);
1431
+ }
1432
+
1433
+ /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
1434
+ var getDefaultConfig = function (_c) { return ({
1435
+ bid: '',
1436
+ pid: '',
1437
+ viewId: getViewId('_'),
1438
+ userId: getDefaultUserId(),
1439
+ deviceId: getDefaultDeviceId(),
1440
+ sessionId: getDefaultSessionId(),
1441
+ domain: REPORT_DOMAIN,
1442
+ release: '',
1443
+ env: 'production',
1444
+ sample: DEFAULT_SAMPLE_CONFIG,
1445
+ plugins: {},
1446
+ transport: {
1447
+ get: noop$1,
1448
+ post: noop$1,
1449
+ },
1450
+ useLocalConfig: false,
1451
+ }); };
1452
+ var createMinimalClient = function (_a) {
1453
+ var _b = _a === void 0 ? {} : _a, _d = _b.createSender, createSender$1 = _d === void 0 ? function (config) {
1454
+ return createSender({
1455
+ size: DEFAULT_SENDER_SIZE,
1456
+ endpoint: getReportUrl(config.domain),
1457
+ transport: config.transport,
1458
+ });
1459
+ } : _d, _e = _b.builder, builder$1 = _e === void 0 ? builder : _e, _f = _b.createDefaultConfig, createDefaultConfig = _f === void 0 ? getDefaultConfig : _f;
1460
+ var client = createClient({
1461
+ validateInitConfig: validateInitConfig,
1462
+ initConfigNormalizer: normalizeInitConfig,
1463
+ userConfigNormalizer: normalizeUserConfig,
1464
+ createSender: createSender$1,
1465
+ builder: builder$1,
1466
+ createDefaultConfig: createDefaultConfig,
1467
+ createConfigManager: createConfigManager,
1468
+ });
1469
+ ContextPlugin(client);
1470
+ InjectConfigPlugin(client);
1471
+ InjectEnvPlugin(client);
1472
+ IntegrationPlugin(client);
1473
+ DevtoolsPlugin(client);
1474
+ return client;
1475
+ };
1476
+ var createBaseClient = function (config) {
1477
+ if (config === void 0) { config = {}; }
1478
+ var client = createMinimalClient(config);
1479
+ SamplePlugin(client);
1480
+ CustomPlugin(client);
1481
+ return client;
1482
+ };
1483
+
1484
+ var browserClient = createBaseClient();
1485
+
1486
+ /**
1487
+ * Node.js 环境的 HTTP Transport 实现
1488
+ * 使用原生 http/https 模块实现网络请求
1489
+ */
1490
+
1491
+
1492
+
1493
+ const log$2 = debug('slardar:transport');
1494
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
1495
+ const noop = () => {};
1496
+
1497
+
1498
+
1499
+
1500
+
1501
+
1502
+
1503
+
1504
+
1505
+
1506
+
1507
+ /**
1508
+ * 执行 HTTP/HTTPS 请求
1509
+ */
1510
+ function makeRequest(options) {
1511
+ const { url, method, data, success = noop, fail = noop, getResponseText = noop } = options;
1512
+
1513
+ log$2('Making %s request to %s', method, url);
1514
+ if (data) {
1515
+ log$2('Request data: %s', data.slice(0, 200));
1516
+ }
1517
+
1518
+ // 检查 URL 是否有效
1519
+ if (!url || typeof url !== 'string') {
1520
+ const error = new Error(`Invalid URL: ${url}`);
1521
+ log$2('Invalid URL provided: %o', url);
1522
+ fail(error);
1523
+ return;
1524
+ }
1525
+
1526
+ try {
1527
+ const urlObj = new URL(url);
1528
+ log$2('Parsed URL - protocol: %s, hostname: %s, port: %s, path: %s',
1529
+ urlObj.protocol, urlObj.hostname, urlObj.port, urlObj.pathname);
1530
+
1531
+ const isHttps = urlObj.protocol === 'https:';
1532
+ const request = isHttps ? node_https.request : node_http.request;
1533
+
1534
+ const req = request(
1535
+ {
1536
+ hostname: urlObj.hostname,
1537
+ port: urlObj.port,
1538
+ path: urlObj.pathname + urlObj.search,
1539
+ method,
1540
+ headers: {
1541
+ 'Content-Type': 'application/json',
1542
+ ...(data && { 'Content-Length': Buffer.byteLength(data) }),
1543
+ },
1544
+ },
1545
+ res => {
1546
+ log$2('Response callback triggered: status=%s', res.statusCode);
1547
+ let responseText = '';
1548
+
1549
+ res.on('data', chunk => {
1550
+ log$2('Response data chunk received: %s bytes', chunk.length);
1551
+ responseText += chunk.toString();
1552
+ });
1553
+
1554
+ res.on('end', () => {
1555
+ log$2('Response end event fired');
1556
+ log$2('Response received: status=%s, body=%s', res.statusCode, responseText.slice(0, 200));
1557
+ getResponseText(responseText);
1558
+
1559
+ try {
1560
+ if (res.statusCode && res.statusCode >= 400) {
1561
+ log$2('Request failed with status %s: %s', res.statusCode, responseText);
1562
+ fail(new Error(responseText || res.statusMessage || 'Request failed'));
1563
+ } else if (responseText) {
1564
+ // eslint-disable-next-line no-restricted-syntax -- Parsing trusted Slardar API responses
1565
+ const result = JSON.parse(responseText);
1566
+ log$2('Request succeeded');
1567
+ success(result);
1568
+ } else {
1569
+ log$2('Request succeeded with empty response');
1570
+ success({});
1571
+ }
1572
+ } catch (e) {
1573
+ log$2('Failed to parse response: %s', (e ).message);
1574
+ fail(e );
1575
+ }
1576
+ });
1577
+ },
1578
+ );
1579
+
1580
+ req.on('error', err => {
1581
+ log$2('Request error: %s', err.message);
1582
+ fail(err);
1583
+ });
1584
+
1585
+ req.on('timeout', () => {
1586
+ log$2('Request timeout');
1587
+ req.destroy();
1588
+ fail(new Error('Request timeout'));
1589
+ });
1590
+
1591
+ if (data) {
1592
+ req.write(data);
1593
+ }
1594
+
1595
+ req.end();
1596
+ } catch (e) {
1597
+ log$2('Exception during request: %s', (e ).message);
1598
+ fail(e );
1599
+ }
1600
+ }
1601
+
1602
+ /**
1603
+ * 创建 Node.js 环境的 Transport
1604
+ */
1605
+ function createNodeTransport() {
1606
+ return {
1607
+ get(options) {
1608
+ log$2('Transport GET called: %s', options.url);
1609
+ makeRequest({
1610
+ method: 'GET',
1611
+ ...options,
1612
+ });
1613
+ },
1614
+ post({ url, data }) {
1615
+ log$2('Transport POST called: %s', url);
1616
+ makeRequest({
1617
+ method: 'POST',
1618
+ url,
1619
+ data: typeof data === 'string' ? data : JSON.stringify(data),
1620
+ });
1621
+ },
1622
+ };
1623
+ }
1624
+
1625
+ function _nullishCoalesce$3(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$6(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }/**
1626
+ * Slardar CLI Reporter 主类
1627
+ * 封装 @slardar/base 的初始化和上报逻辑
1628
+ */
1629
+
1630
+
1631
+
1632
+
1633
+
1634
+
1635
+ // 创建 debug 实例
1636
+ // 使用方式: DEBUG=slardar:* your-cli-command
1637
+ const log$1 = debug('slardar:reporter');
1638
+
1639
+ /**
1640
+ * Slardar CLI Reporter
1641
+ * 提供简洁的 API 用于 CLI 工具的监控数据上报
1642
+ */
1643
+ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.call(this);SlardarCLIReporter.prototype.__init2.call(this); }
1644
+ __init() {this.initialized = false;}
1645
+ __init2() {this.client = browserClient;}
1646
+
1647
+ /**
1648
+ * 初始化 Slardar Reporter
1649
+ * @param config 初始化配置
1650
+ *
1651
+ * @example
1652
+ * ```typescript
1653
+ * reporter.setup({
1654
+ * bid: 'my_cli_app',
1655
+ * release: '1.0.0',
1656
+ * env: 'production',
1657
+ * });
1658
+ * ```
1659
+ */
1660
+ setup(config) {
1661
+ if (this.initialized) {
1662
+ log$1('Already initialized, skipping setup');
1663
+ return;
1664
+ }
1665
+
1666
+ try {
1667
+ log$1('Initializing Slardar with config:', {
1668
+ bid: config.bid,
1669
+ release: config.release,
1670
+ env: config.env,
1671
+ userId: config.userId,
1672
+ });
1673
+
1674
+ const transport = createNodeTransport();
1675
+
1676
+ this.client.init({
1677
+ bid: config.bid,
1678
+ transport,
1679
+ userId: config.userId,
1680
+ deviceId: config.deviceId,
1681
+ sessionId: config.sessionId,
1682
+ release: config.release,
1683
+ env: config.env,
1684
+ name: config.name,
1685
+ useLocalConfig: _nullishCoalesce$3(config.useLocalConfig, () => ( false)), // 默认使用服务端配置
1686
+ domain: config.domain,
1687
+ // 设置本地采样率,确保事件不被过滤
1688
+ sample: {
1689
+ event: 1, // 100% 采样自定义事件
1690
+ },
1691
+ });
1692
+
1693
+ // 添加 beforeSend 钩子来追踪事件是否被过滤
1694
+ this.client.on('beforeSend', (ev) => {
1695
+ log$1('beforeSend hook called for event: %s', (_optionalChain$6([ev, 'optionalAccess', _ => _.ev_type]) ) || 'unknown');
1696
+ return ev; // 必须返回 ev 才能继续上报
1697
+ });
1698
+
1699
+ this.client.start();
1700
+ this.initialized = true;
1701
+ log$1('Slardar initialized successfully');
1702
+ } catch (error) {
1703
+ log$1('Failed to initialize:', error);
1704
+ }
1705
+ }
1706
+
1707
+ /**
1708
+ * 检查是否已初始化
1709
+ */
1710
+ ensureInitialized() {
1711
+ if (!this.initialized) {
1712
+ log$1('Not initialized, call setup() first');
1713
+ return false;
1714
+ }
1715
+ return true;
1716
+ }
1717
+
1718
+ /**
1719
+ * 上报自定义事件
1720
+ * @param name 事件名称
1721
+ * @param metrics 指标数据(数值类型)
1722
+ * @param categories 分类维度(字符串类型)
1723
+ */
1724
+ sendEvent(
1725
+ name,
1726
+ metrics,
1727
+ categories,
1728
+ ) {
1729
+ if (!this.ensureInitialized()) {
1730
+ return;
1731
+ }
1732
+
1733
+ try {
1734
+ log$1('Sending event:', { name, metrics, categories });
1735
+ this.client.sendEvent({
1736
+ name,
1737
+ metrics,
1738
+ categories,
1739
+ });
1740
+ } catch (error) {
1741
+ log$1('Failed to send event:', error);
1742
+ }
1743
+ }
1744
+
1745
+ /**
1746
+ * 上报 JS 错误(会显示在 Slardar JS 错误总览页面)
1747
+ * @param error Error 对象
1748
+ * @param extra 额外的上下文信息
1749
+ * @param source 错误来源信息
1750
+ */
1751
+ reportError(
1752
+ error,
1753
+ extra,
1754
+ source,
1755
+ ) {
1756
+ if (!this.ensureInitialized()) {
1757
+ return;
1758
+ }
1759
+
1760
+ try {
1761
+ const errorEvent = {
1762
+ ev_type: 'js_error' ,
1763
+ payload: {
1764
+ error: {
1765
+ name: error.name,
1766
+ message: error.message,
1767
+ stack: error.stack,
1768
+ },
1769
+ breadcrumbs: [], // CLI 环境暂不收集面包屑
1770
+ extra,
1771
+ source: source || { type: 'manual' }, // 默认为手动捕获
1772
+ },
1773
+ };
1774
+
1775
+ log$1('Reporting JS error:', {
1776
+ name: error.name,
1777
+ message: error.message.slice(0, 100),
1778
+ stack: _optionalChain$6([error, 'access', _2 => _2.stack, 'optionalAccess', _3 => _3.slice, 'call', _4 => _4(0, 200)]),
1779
+ extra,
1780
+ source,
1781
+ });
1782
+
1783
+ // 使用 Slardar 的 js_error 事件类型,这样会显示在 JS 错误总览页面
1784
+ this.client.report(errorEvent);
1785
+ log$1('JS error reported successfully');
1786
+ } catch (err) {
1787
+ log$1('Failed to report error:', err);
1788
+ }
1789
+ }
1790
+
1791
+
1792
+ /**
1793
+ * 设置全局上下文
1794
+ */
1795
+ setContext(key, value) {
1796
+ if (!this.ensureInitialized()) {
1797
+ return;
1798
+ }
1799
+ this.client.context.set(key, value);
1800
+ }
1801
+
1802
+ /**
1803
+ * 批量设置全局上下文
1804
+ */
1805
+ mergeContext(context) {
1806
+ if (!this.ensureInitialized()) {
1807
+ return;
1808
+ }
1809
+ log$1('Merging context:', context);
1810
+ this.client.context.merge(context);
1811
+ }
1812
+
1813
+ /**
1814
+ * 删除全局上下文
1815
+ */
1816
+ deleteContext(key) {
1817
+ if (!this.ensureInitialized()) {
1818
+ return;
1819
+ }
1820
+ this.client.context.delete(key);
1821
+ }
1822
+
1823
+ /**
1824
+ * 清空全局上下文
1825
+ */
1826
+ clearContext() {
1827
+ if (!this.ensureInitialized()) {
1828
+ return;
1829
+ }
1830
+ this.client.context.clear();
1831
+ }
1832
+
1833
+ /**
1834
+ * 更新用户配置
1835
+ */
1836
+ updateConfig(
1837
+ config
1838
+
1839
+ ,
1840
+ ) {
1841
+ if (!this.ensureInitialized()) {
1842
+ return;
1843
+ }
1844
+
1845
+ try {
1846
+ log$1('Updating config:', config);
1847
+ this.client.config({
1848
+ userId: config.userId,
1849
+ release: config.release,
1850
+ sessionId: config.sessionId,
1851
+ env: config.env,
1852
+ });
1853
+ } catch (error) {
1854
+ log$1('Failed to update config:', error);
1855
+ }
1856
+ }
1857
+
1858
+ /**
1859
+ * 立即上报(不等待队列)
1860
+ * @param waitMs 等待时间(毫秒),默认 1500ms,用于确保设置请求完成和事件发送
1861
+ */
1862
+ async flush(waitMs = 1500) {
1863
+ if (!this.ensureInitialized()) {
1864
+ return;
1865
+ }
1866
+ log$1('Flushing Slardar data...');
1867
+ this.client.getSender().flush();
1868
+ log$1('Waiting %dms for events to be sent...', waitMs);
1869
+ await new Promise(resolve => setTimeout(resolve, waitMs));
1870
+ log$1('Slardar data flushed');
1871
+ }
1872
+
1873
+ /**
1874
+ * 获取原始 Slardar client(用于高级用法)
1875
+ */
1876
+ getRawClient() {
1877
+ return this.client;
1878
+ }
1879
+ }
1880
+
1881
+ /**
1882
+ * 默认导出的单例实例
1883
+ */
1884
+ const reporter = new SlardarCLIReporter();
1885
+
1886
+ function _optionalChain$5(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
1887
+
1888
+
1889
+
1890
+
1891
+
1892
+ /**
1893
+ * CLI 通用事件类型常量
1894
+ * 仅包含通用的 CLI 工具事件,不包含具体业务逻辑
1895
+ */
1896
+ const CLI_EVENTS = {
1897
+ /** CLI 启动 */
1898
+ CLI_START: 'cli_start',
1899
+ /** CLI 命令执行 */
1900
+ CLI_COMMAND: 'cli_command',
1901
+ /** CLI 命令完成 */
1902
+ CLI_COMMAND_COMPLETE: 'cli_command_complete',
1903
+ /** CLI 错误 */
1904
+ CLI_ERROR: 'cli_error',
1905
+ /** 网络请求 */
1906
+ NETWORK_REQUEST: 'network_request',
1907
+ /** 文件操作 */
1908
+ FILE_OPERATION: 'file_operation',
1909
+ } ;
1910
+
1911
+
1912
+
1913
+ /**
1914
+ * 事件构建器 - 提供更友好的事件创建接口
1915
+ */
1916
+ // eslint-disable-next-line @typescript-eslint/naming-convention
1917
+ const EventBuilder = {
1918
+ /**
1919
+ * 构建 CLI 启动事件
1920
+ */
1921
+ cliStart(metrics) {
1922
+ return {
1923
+ name: CLI_EVENTS.CLI_START,
1924
+ metrics: {
1925
+ duration: 0,
1926
+ ...metrics,
1927
+ },
1928
+ };
1929
+ },
1930
+
1931
+ /**
1932
+ * 构建 CLI 命令执行事件
1933
+ */
1934
+ cliCommand(
1935
+ command,
1936
+ options
1937
+
1938
+
1939
+
1940
+ ,
1941
+ ) {
1942
+ return {
1943
+ name: CLI_EVENTS.CLI_COMMAND,
1944
+ categories: {
1945
+ command,
1946
+ args: _optionalChain$5([options, 'optionalAccess', _ => _.args]),
1947
+ status: 'running' ,
1948
+ ..._optionalChain$5([options, 'optionalAccess', _2 => _2.categories]),
1949
+ },
1950
+ metrics: _optionalChain$5([options, 'optionalAccess', _3 => _3.metrics]),
1951
+ };
1952
+ },
1953
+
1954
+ /**
1955
+ * 构建 CLI 命令完成事件
1956
+ */
1957
+ cliCommandComplete(
1958
+ command,
1959
+ success,
1960
+ duration,
1961
+ options
1962
+
1963
+
1964
+
1965
+ ,
1966
+ ) {
1967
+ return {
1968
+ name: CLI_EVENTS.CLI_COMMAND_COMPLETE,
1969
+ categories: {
1970
+ command,
1971
+ args: _optionalChain$5([options, 'optionalAccess', _4 => _4.args]),
1972
+ status: success ? ('success' ) : ('fail' ),
1973
+ ..._optionalChain$5([options, 'optionalAccess', _5 => _5.categories]),
1974
+ },
1975
+ metrics: {
1976
+ duration,
1977
+ ...(_optionalChain$5([options, 'optionalAccess', _6 => _6.errorCode]) && { errorCode: options.errorCode }),
1978
+ },
1979
+ };
1980
+ },
1981
+
1982
+ /**
1983
+ * 构建网络请求事件
1984
+ */
1985
+ networkRequest(
1986
+ url,
1987
+ options
1988
+
1989
+
1990
+
1991
+
1992
+ ,
1993
+ ) {
1994
+ return {
1995
+ name: CLI_EVENTS.NETWORK_REQUEST,
1996
+ categories: {
1997
+ url,
1998
+ method: _optionalChain$5([options, 'optionalAccess', _7 => _7.method]) || 'GET',
1999
+ statusCode: _optionalChain$5([options, 'optionalAccess', _8 => _8.statusCode, 'optionalAccess', _9 => _9.toString, 'call', _10 => _10()]),
2000
+ status: _optionalChain$5([options, 'optionalAccess', _11 => _11.success]) ? ('success' ) : ('fail' ),
2001
+ },
2002
+ metrics: {
2003
+ duration: _optionalChain$5([options, 'optionalAccess', _12 => _12.duration]),
2004
+ },
2005
+ };
2006
+ },
2007
+
2008
+ /**
2009
+ * 构建文件操作事件
2010
+ */
2011
+ fileOperation(
2012
+ operation,
2013
+ filePath,
2014
+ options
2015
+
2016
+
2017
+
2018
+ ,
2019
+ ) {
2020
+ return {
2021
+ name: CLI_EVENTS.FILE_OPERATION,
2022
+ categories: {
2023
+ operation,
2024
+ filePath,
2025
+ status: _optionalChain$5([options, 'optionalAccess', _13 => _13.success]) ? ('success' ) : ('fail' ),
2026
+ },
2027
+ metrics: {
2028
+ duration: _optionalChain$5([options, 'optionalAccess', _14 => _14.duration]),
2029
+ fileSize: _optionalChain$5([options, 'optionalAccess', _15 => _15.fileSize]),
2030
+ },
2031
+ };
2032
+ },
2033
+
2034
+ /**
2035
+ * 构建错误事件
2036
+ */
2037
+ cliError(
2038
+ error,
2039
+ context,
2040
+ ) {
2041
+ return {
2042
+ name: CLI_EVENTS.CLI_ERROR,
2043
+ categories: {
2044
+ errorName: error.name,
2045
+ errorMessage: error.message,
2046
+ stack: error.stack || '',
2047
+ ...context,
2048
+ },
2049
+ metrics: {
2050
+ errorCode: 1,
2051
+ },
2052
+ };
2053
+ },
2054
+ };
2055
+
2056
+ var name = "@coze-arch/cli";
2057
+ var version = "0.0.1-alpha.ff3d06";
2058
+ var description = "coze coding devtools cli";
2059
+ var license = "MIT";
2060
+ var author = "fanwenjie.fe@bytedance.com";
2061
+ var maintainers = [
2062
+ ];
2063
+ var bin = {
2064
+ coze: "bin/main"
2065
+ };
2066
+ var files = [
2067
+ "lib",
2068
+ "bin",
2069
+ "lib/**/.npmrc",
2070
+ "!**/*.tsbuildinfo",
2071
+ "!**/*.map"
2072
+ ];
2073
+ var scripts = {
2074
+ prebuild: "tsx scripts/prebuild.ts",
2075
+ build: "tsx scripts/build.ts",
2076
+ create: "tsx scripts/create-template.ts",
2077
+ lint: "eslint ./ --cache",
2078
+ postpublish: "bash scripts/sync-npmmirror.sh",
2079
+ test: "vitest --run --passWithNoTests",
2080
+ "test:all": "bash scripts/test-coverage.sh",
2081
+ "test:cov": "vitest --run --passWithNoTests --coverage",
2082
+ "test:e2e": "NODE_ENV=test bash scripts/e2e.sh",
2083
+ "test:perf": "vitest bench --run --config vitest.perf.config.ts",
2084
+ "test:perf:compare": "bash scripts/compare-perf.sh",
2085
+ "test:perf:save": "bash scripts/run-perf-with-output.sh"
2086
+ };
2087
+ var dependencies = {
2088
+ "@iarna/toml": "^2.2.5",
2089
+ ajv: "^8.17.1",
2090
+ "ajv-formats": "^3.0.1",
2091
+ "change-case": "^5.4.4",
2092
+ commander: "~12.1.0",
2093
+ debug: "^4.3.7",
2094
+ ejs: "^3.1.10",
2095
+ "js-yaml": "^4.1.0",
2096
+ minimist: "^1.2.5",
2097
+ shelljs: "^0.10.0"
2098
+ };
2099
+ var devDependencies = {
2100
+ "@coze-arch/cli-logger": "workspace:*",
2101
+ "@coze-arch/cli-slardar": "workspace:*",
2102
+ "@coze-arch/eslint-config": "workspace:*",
2103
+ "@coze-arch/monorepo-kits": "workspace:*",
2104
+ "@coze-arch/rollup-config": "workspace:*",
2105
+ "@coze-arch/ts-config": "workspace:*",
2106
+ "@coze-arch/vitest-config": "workspace:*",
2107
+ "@coze-coding/lambda": "workspace:*",
2108
+ "@inquirer/prompts": "^3.2.0",
2109
+ "@playwright/test": "~1.55.0",
2110
+ "@types/debug": "^4.1.12",
2111
+ "@types/ejs": "^3.1.5",
2112
+ "@types/iarna__toml": "^2.0.5",
2113
+ "@types/js-yaml": "^4.0.9",
2114
+ "@types/minimatch": "^5.1.2",
2115
+ "@types/minimist": "^1.2.5",
2116
+ "@types/node": "^24",
2117
+ "@types/shelljs": "^0.10.0",
2118
+ "@vitest/coverage-v8": "~4.0.18",
2119
+ "json-schema-to-typescript": "^15.0.3",
2120
+ minimatch: "^10.0.1",
2121
+ playwright: "~1.55.0",
2122
+ rollup: "^4.41.1",
2123
+ sucrase: "^3.35.0",
2124
+ "tree-kill": "^1.2.2",
2125
+ tsx: "^4.20.6",
2126
+ "vite-tsconfig-paths": "^4.2.1",
2127
+ vitest: "~4.0.18"
2128
+ };
2129
+ var publishConfig = {
2130
+ access: "public",
2131
+ registry: "https://registry.npmjs.org"
2132
+ };
2133
+ var cozePublishConfig = {
2134
+ bin: {
2135
+ coze: "bin/main"
2136
+ }
2137
+ };
2138
+ var packageJson = {
2139
+ name: name,
2140
+ version: version,
2141
+ "private": false,
2142
+ description: description,
2143
+ license: license,
2144
+ author: author,
2145
+ maintainers: maintainers,
2146
+ bin: bin,
2147
+ files: files,
2148
+ scripts: scripts,
2149
+ dependencies: dependencies,
2150
+ devDependencies: devDependencies,
2151
+ publishConfig: publishConfig,
2152
+ cozePublishConfig: cozePublishConfig
2153
+ };
2154
+
2155
+ function _optionalChain$4(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }/**
2156
+ * Slardar 监控初始化和上报
2157
+ */
2158
+
2159
+ const log = debug('slardar:cli');
2160
+
2161
+ /**
2162
+ * 安全执行函数包装器
2163
+ * 捕获并静默处理所有错误,确保 Slardar 上报失败不影响 CLI 正常运行
2164
+ * 支持同步和异步函数
2165
+ */
2166
+ function safeRun(
2167
+ name,
2168
+ fn,
2169
+ ) {
2170
+ return ((...args) => {
2171
+ try {
2172
+ log('Calling Slardar function: %s', name);
2173
+ const result = fn(...args);
2174
+
2175
+ // 如果是 Promise,处理异步错误
2176
+ if (result instanceof Promise) {
2177
+ return result
2178
+ .then(res => {
2179
+ log('Slardar function %s completed', name);
2180
+ return res;
2181
+ })
2182
+ .catch(error => {
2183
+ log(
2184
+ 'Slardar function %s failed: %s',
2185
+ name,
2186
+ (error ).message,
2187
+ );
2188
+ void error;
2189
+ });
2190
+ }
2191
+
2192
+ log('Slardar function %s completed', name);
2193
+ return result;
2194
+ } catch (error) {
2195
+ // Slardar 上报失败不应影响 CLI 正常运行,但要记录错误
2196
+ log('Slardar function %s failed: %s', name, (error ).message);
2197
+ }
2198
+ }) ;
2199
+ }
2200
+
2201
+ /**
2202
+ * 初始化 Slardar Reporter
2203
+ */
2204
+ const initSlardar = safeRun('initSlardar', () => {
2205
+ reporter.setup({
2206
+ bid: 'coze_codign_cli',
2207
+ release: packageJson.version,
2208
+ env: process.env.NODE_ENV || 'production',
2209
+ userId: process.env.USER,
2210
+ useLocalConfig: false, // 启用服务端采样率配置
2211
+ domain: 'mon.zijieapi.com', // Node.js 环境上报域名
2212
+ });
2213
+
2214
+ // 设置全局上下文
2215
+ reporter.mergeContext({
2216
+ platform: process.platform,
2217
+ nodeVersion: process.version,
2218
+ cliVersion: packageJson.version,
2219
+ });
2220
+ });
2221
+
2222
+ /**
2223
+ * 上报命令执行
2224
+ */
2225
+ const reportCommandStart = safeRun(
2226
+ 'reportCommandStart',
2227
+ (command, args, extraCategories) => {
2228
+ const event = EventBuilder.cliCommand(command, {
2229
+ args,
2230
+ categories: extraCategories,
2231
+ });
2232
+ reporter.sendEvent(event.name, event.metrics, event.categories);
2233
+ },
2234
+ );
2235
+
2236
+ /**
2237
+ * 上报命令完成
2238
+ */
2239
+ const reportCommandComplete = safeRun(
2240
+ 'reportCommandComplete',
2241
+ (
2242
+ command,
2243
+ success,
2244
+ duration,
2245
+ options
2246
+
2247
+
2248
+
2249
+
2250
+ ,
2251
+ ) => {
2252
+ const event = EventBuilder.cliCommandComplete(command, success, duration, {
2253
+ args: _optionalChain$4([options, 'optionalAccess', _ => _.args]),
2254
+ errorCode: _optionalChain$4([options, 'optionalAccess', _2 => _2.errorCode]),
2255
+ categories: {
2256
+ ...(_optionalChain$4([options, 'optionalAccess', _3 => _3.errorMessage]) && { errorMessage: options.errorMessage }),
2257
+ ..._optionalChain$4([options, 'optionalAccess', _4 => _4.categories]),
2258
+ },
2259
+ });
2260
+ reporter.sendEvent(event.name, event.metrics, event.categories);
2261
+ },
2262
+ );
2263
+
2264
+ /**
2265
+ * 上报错误(使用 JS 错误上报,会显示在 Slardar JS 错误总览页面)
2266
+ */
2267
+ const reportError = safeRun(
2268
+ 'reportError',
2269
+ (error, context) => {
2270
+ reporter.reportError(error, context, {
2271
+ type: 'cli',
2272
+ data: context,
2273
+ });
2274
+ },
2275
+ );
2276
+
2277
+ /**
2278
+ * 立即上报(在 CLI 退出前调用)
2279
+ * 等待 500ms 确保设置请求完成和事件发送
2280
+ */
2281
+ const flushSlardar = safeRun('flushSlardar', async () => {
2282
+ await reporter.flush();
2283
+ });
2284
+
130
2285
  function _nullishCoalesce$2(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$3(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var LogLevel; (function (LogLevel) {
131
2286
  const ERROR = 0; LogLevel[LogLevel["ERROR"] = ERROR] = "ERROR";
132
2287
  const WARN = 1; LogLevel[LogLevel["WARN"] = WARN] = "WARN";
@@ -481,6 +2636,14 @@ const warmupTemplate = (templatePath, templateName) => {
481
2636
  logger.info(`\nWarming up template: ${templateName}`);
482
2637
  logger.info(` Path: ${templatePath}`);
483
2638
 
2639
+ // 检查是否存在 package.json
2640
+ const packageJsonPath = node_path.join(templatePath, 'package.json');
2641
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
2642
+ if (!node_fs.existsSync(packageJsonPath)) {
2643
+ logger.info(` ⊘ Skipping ${templateName} (no package.json found)`);
2644
+ return;
2645
+ }
2646
+
484
2647
  const result = shelljs.exec('pnpm install', {
485
2648
  cwd: templatePath,
486
2649
  silent: true,
@@ -514,13 +2677,7 @@ const warmupTemplate = (templatePath, templateName) => {
514
2677
  /**
515
2678
  * 执行 warmup 命令的内部实现
516
2679
  */
517
- const executeWarmup = async (
518
- options
519
-
520
- ,
521
-
522
- command,
523
- ) => {
2680
+ const executeWarmup = async (options) => {
524
2681
  const timer = new TimeTracker();
525
2682
 
526
2683
  try {
@@ -585,16 +2742,361 @@ const executeWarmup = async (
585
2742
  /**
586
2743
  * 注册 warmup 命令到 program
587
2744
  */
588
- const registerCommand$3 = program => {
2745
+ const registerCommand$4 = program => {
589
2746
  program
590
2747
  .command('warmup')
591
2748
  .description('Pre-install dependencies for templates to speed up init')
592
2749
  .option('-t, --template <name>', 'Warmup a specific template only')
593
- .action(async (options, command) => {
2750
+ .action(async options => {
594
2751
  await executeWarmup(options);
595
2752
  });
596
2753
  };
597
2754
 
2755
+ // ABOUTME: This file implements the update command for coze CLI
2756
+ // ABOUTME: It wraps pnpm update/install to update package dependencies with logging support
2757
+
2758
+
2759
+
2760
+ /**
2761
+ * 日志文件名常量
2762
+ */
2763
+ const LOG_FILE_NAME$1 = 'update.log';
2764
+
2765
+ /**
2766
+ * 获取日志目录
2767
+ * 优先使用环境变量 COZE_LOG_DIR,否则使用 ~/.coze-logs
2768
+ */
2769
+ const getLogDir$1 = () =>
2770
+ process.env.COZE_LOG_DIR || path.join(os.homedir(), '.coze-logs');
2771
+
2772
+ /**
2773
+ * 解析日志文件路径
2774
+ * - 如果是绝对路径,直接使用
2775
+ * - 如果是相对路径,基于 getLogDir() + 相对路径
2776
+ * - 如果为空,使用 getLogDir() + LOG_FILE_NAME
2777
+ */
2778
+ const resolveLogFilePath$1 = (logFile) => {
2779
+ if (!logFile) {
2780
+ return path.join(getLogDir$1(), LOG_FILE_NAME$1);
2781
+ }
2782
+
2783
+ if (path.isAbsolute(logFile)) {
2784
+ return logFile;
2785
+ }
2786
+
2787
+ return path.join(getLogDir$1(), logFile);
2788
+ };
2789
+
2790
+ /**
2791
+ * 创建日志写入流
2792
+ */
2793
+ const createLogStream$1 = (logFilePath) => {
2794
+ const logDir = path.dirname(logFilePath);
2795
+
2796
+ // 确保日志目录存在
2797
+ if (!fs.existsSync(logDir)) {
2798
+ fs.mkdirSync(logDir, { recursive: true });
2799
+ }
2800
+
2801
+ // 使用 'w' 标志覆盖之前的日志
2802
+ return fs.createWriteStream(logFilePath, { flags: 'w' });
2803
+ };
2804
+
2805
+ /**
2806
+ * 格式化时间戳
2807
+ */
2808
+ const formatTimestamp = () => {
2809
+ const now = new Date();
2810
+ return now.toISOString();
2811
+ };
2812
+
2813
+ /**
2814
+ * 写入带时间戳的日志
2815
+ */
2816
+ const writeLogWithTimestamp = (stream, message) => {
2817
+ const timestamp = formatTimestamp();
2818
+ const lines = message.split('\n');
2819
+ lines.forEach(line => {
2820
+ if (line) {
2821
+ stream.write(`[${timestamp}] ${line}\n`);
2822
+ } else {
2823
+ stream.write('\n');
2824
+ }
2825
+ });
2826
+ // 确保数据写入磁盘
2827
+ stream.uncork();
2828
+ };
2829
+
2830
+ /**
2831
+ * 同时输出到控制台和日志文件
2832
+ */
2833
+ const logWithFile = (
2834
+ stream,
2835
+ level,
2836
+ message,
2837
+ ) => {
2838
+ // 输出到控制台
2839
+ switch (level) {
2840
+ case 'info':
2841
+ logger.info(message);
2842
+ break;
2843
+ case 'success':
2844
+ logger.success(message);
2845
+ break;
2846
+ case 'error':
2847
+ logger.error(message);
2848
+ break;
2849
+ default:
2850
+ logger.info(message);
2851
+ break;
2852
+ }
2853
+
2854
+ // 写入日志文件(带时间戳)
2855
+ writeLogWithTimestamp(stream, `[${level.toUpperCase()}] ${message}`);
2856
+ };
2857
+
2858
+ // start_aigc
2859
+ /**
2860
+ * 构建 pnpm add 命令
2861
+ */
2862
+ const buildPnpmCommand = (
2863
+ packageName,
2864
+ options
2865
+
2866
+
2867
+
2868
+
2869
+ ,
2870
+ ) => {
2871
+ const { global, version, registry, extraArgs } = options;
2872
+
2873
+ const parts = ['pnpm', 'add'];
2874
+
2875
+ // 添加全局标记
2876
+ if (global) {
2877
+ parts.push('-g');
2878
+ }
2879
+
2880
+ // 添加包名和版本
2881
+ if (version && version !== 'latest') {
2882
+ parts.push(`${packageName}@${version}`);
2883
+ } else {
2884
+ parts.push(`${packageName}@latest`);
2885
+ }
2886
+
2887
+ // 添加 registry
2888
+ if (registry) {
2889
+ parts.push(`--registry=${registry}`);
2890
+ }
2891
+
2892
+ // 添加额外参数
2893
+ if (extraArgs.length > 0) {
2894
+ parts.push(...extraArgs);
2895
+ }
2896
+
2897
+ return parts.join(' ');
2898
+ };
2899
+ // end_aigc
2900
+
2901
+ /**
2902
+ * 处理更新失败的错误
2903
+ */
2904
+ const handleUpdateError = (
2905
+ error,
2906
+ packageName,
2907
+ options,
2908
+ cmdStartTime,
2909
+ logStream,
2910
+ ) => {
2911
+ const err = error instanceof Error ? error : new Error(String(error));
2912
+ logger.error('Failed to update package:');
2913
+ logger.error(err.message);
2914
+
2915
+ // 上报错误
2916
+ reportError(err, {
2917
+ command: 'update',
2918
+ packageName,
2919
+ type: 'execution_error',
2920
+ });
2921
+ reportCommandComplete('update', false, Date.now() - cmdStartTime, {
2922
+ args: JSON.stringify({ packageName, ...options }),
2923
+ errorCode: 1,
2924
+ errorMessage: err.message,
2925
+ });
2926
+
2927
+ // 写入错误到日志文件
2928
+ if (logStream) {
2929
+ writeLogWithTimestamp(logStream, `[ERROR] ${err.message}`);
2930
+ // 等待流关闭后再退出
2931
+ logStream.end(() => {
2932
+ flushSlardar().then(() => {
2933
+ process.exit(1);
2934
+ });
2935
+ });
2936
+ } else {
2937
+ flushSlardar().then(() => {
2938
+ process.exit(1);
2939
+ });
2940
+ }
2941
+ };
2942
+
2943
+ // start_aigc
2944
+ /**
2945
+ * 执行 update 命令的内部实现
2946
+ */
2947
+ const executeUpdate = (
2948
+ packageName,
2949
+ options
2950
+
2951
+
2952
+
2953
+
2954
+
2955
+
2956
+ ,
2957
+ ) => {
2958
+ const cmdStartTime = Date.now();
2959
+ let logStream = null;
2960
+
2961
+ try {
2962
+ const { global, cwd, version, registry, logFile, extraArgs } = options;
2963
+
2964
+ // 上报命令开始
2965
+ reportCommandStart('update', JSON.stringify({ packageName, ...options }));
2966
+
2967
+ // 准备日志
2968
+ const logFilePath = resolveLogFilePath$1(logFile);
2969
+
2970
+ // 调试:确认日志路径
2971
+ logger.info(`Log file path resolved to: ${logFilePath}`);
2972
+
2973
+ logStream = createLogStream$1(logFilePath);
2974
+
2975
+ // 调试:确认流已创建
2976
+ logger.info('Log stream created successfully');
2977
+
2978
+ logWithFile(logStream, 'info', `Updating package: ${packageName}`);
2979
+
2980
+ // 构建命令
2981
+ const command = buildPnpmCommand(packageName, {
2982
+ global,
2983
+ version,
2984
+ registry,
2985
+ extraArgs,
2986
+ });
2987
+
2988
+ // 确定工作目录
2989
+ const workingDir = cwd
2990
+ ? path.isAbsolute(cwd)
2991
+ ? cwd
2992
+ : path.join(process.cwd(), cwd)
2993
+ : process.cwd();
2994
+
2995
+ logWithFile(logStream, 'info', `Executing: ${command}`);
2996
+ logWithFile(logStream, 'info', `Working directory: ${workingDir}`);
2997
+ logWithFile(logStream, 'info', `Log file: ${logFilePath}`);
2998
+
2999
+ // 记录命令开始时间
3000
+ writeLogWithTimestamp(logStream, '--- Command execution started ---');
3001
+
3002
+ // 同步执行命令
3003
+ const result = shelljs.exec(command, {
3004
+ cwd: workingDir,
3005
+ silent: true, // 使用 silent 来捕获输出
3006
+ });
3007
+
3008
+ // 将输出写入控制台和日志文件(带时间戳)
3009
+ if (result.stdout) {
3010
+ process.stdout.write(result.stdout);
3011
+ writeLogWithTimestamp(logStream, result.stdout.trim());
3012
+ }
3013
+
3014
+ if (result.stderr) {
3015
+ process.stderr.write(result.stderr);
3016
+ writeLogWithTimestamp(logStream, result.stderr.trim());
3017
+ }
3018
+
3019
+ // 记录命令结束时间
3020
+ writeLogWithTimestamp(logStream, '--- Command execution ended ---');
3021
+
3022
+ // 检查执行结果并记录到日志
3023
+ if (result.code === 0) {
3024
+ logWithFile(logStream, 'success', 'Package updated successfully');
3025
+ logWithFile(logStream, 'info', `Log file: ${logFilePath}`);
3026
+
3027
+ // 上报命令成功
3028
+ reportCommandComplete('update', true, Date.now() - cmdStartTime, {
3029
+ args: JSON.stringify({ packageName, ...options }),
3030
+ });
3031
+ // flush 由 main 函数统一处理
3032
+ } else {
3033
+ const errorMessage = `Command exited with code ${result.code}`;
3034
+ logWithFile(logStream, 'error', errorMessage);
3035
+ logWithFile(
3036
+ logStream,
3037
+ 'error',
3038
+ `Check log file for details: ${logFilePath}`,
3039
+ );
3040
+
3041
+ // 上报命令失败
3042
+ reportError(new Error(errorMessage), {
3043
+ command: 'update',
3044
+ packageName,
3045
+ exitCode: String(result.code),
3046
+ });
3047
+ reportCommandComplete('update', false, Date.now() - cmdStartTime, {
3048
+ args: JSON.stringify({ packageName, ...options }),
3049
+ errorCode: result.code || 1,
3050
+ errorMessage,
3051
+ });
3052
+ }
3053
+
3054
+ // 关闭日志流并等待写入完成
3055
+ logStream.end(() => {
3056
+ // 流关闭后再退出进程
3057
+ if (result.code !== 0) {
3058
+ // flush 后再退出
3059
+ flushSlardar().then(() => {
3060
+ process.exit(result.code || 1);
3061
+ });
3062
+ }
3063
+ // 成功时 flush 由 main 函数统一处理
3064
+ });
3065
+ } catch (error) {
3066
+ handleUpdateError(error, packageName, options, cmdStartTime, logStream);
3067
+ }
3068
+ };
3069
+ // end_aigc
3070
+
3071
+ /**
3072
+ * 注册 update 命令到 program
3073
+ */
3074
+ const registerCommand$3 = program => {
3075
+ program
3076
+ .command('update <package>')
3077
+ .description('Update a package dependency')
3078
+ .option('-g, --global', 'Update package globally', false)
3079
+ .option('-c, --cwd <path>', 'Working directory for the update')
3080
+ .option(
3081
+ '--to <version>',
3082
+ 'Version to update to (default: latest)',
3083
+ 'latest',
3084
+ )
3085
+ .option('--registry <url>', 'Registry URL to use for the update')
3086
+ .option('--log-file <path>', 'Log file path')
3087
+ .allowUnknownOption() // 允许透传参数给 pnpm
3088
+ .action((packageName, options, command) => {
3089
+ // 收集所有未知选项作为额外参数
3090
+ const extraArgs = command.args.slice(1);
3091
+
3092
+ executeUpdate(packageName, {
3093
+ ...options,
3094
+ version: options.to, // 将 --to 映射到 version
3095
+ extraArgs,
3096
+ });
3097
+ });
3098
+ };
3099
+
598
3100
  function _optionalChain$2(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }/* eslint-disable @typescript-eslint/no-explicit-any */
599
3101
  // Safe JSON parsing utilities with type safety and error handling
600
3102
  // Provides fallback values, validation, and error monitoring capabilities
@@ -975,7 +3477,9 @@ const rules = [
975
3477
  /**
976
3478
  * 执行 fix 命令的内部实现
977
3479
  */
978
- const executeFix = async (options = {}) => {
3480
+ const executeFix = async (
3481
+ options = {},
3482
+ ) => {
979
3483
  try {
980
3484
  const cwd = process.cwd();
981
3485
  const projectFolder = options.directory
@@ -1101,9 +3605,14 @@ const executeRun = async (
1101
3605
  commandName,
1102
3606
  options = {},
1103
3607
  ) => {
3608
+ const cmdStartTime = Date.now();
3609
+
1104
3610
  try {
1105
3611
  logger.info(`Running ${commandName} command...`);
1106
3612
 
3613
+ // 上报命令开始
3614
+ reportCommandStart(commandName, JSON.stringify(options));
3615
+
1107
3616
  // 1. 对于 build 命令,先执行 fix 以确保项目配置正确
1108
3617
  if (['dev', 'build'].includes(commandName)) {
1109
3618
  logger.info('\n🔧 Running fix command before build...\n');
@@ -1155,14 +3664,34 @@ const executeRun = async (
1155
3664
  logStream.end();
1156
3665
 
1157
3666
  if (code !== 0) {
1158
- logger.error(
1159
- `Command exited with code ${_nullishCoalesce$1(code, () => ( 'unknown'))}${signal ? ` and signal ${signal}` : ''}`,
1160
- );
3667
+ const errorMessage = `Command exited with code ${_nullishCoalesce$1(code, () => ( 'unknown'))}${signal ? ` and signal ${signal}` : ''}`;
3668
+ logger.error(errorMessage);
1161
3669
  logger.error(`Check log file for details: ${logFilePath}`);
1162
- process.exit(code || 1);
3670
+
3671
+ // 上报命令失败
3672
+ reportError(new Error(errorMessage), {
3673
+ command: commandName,
3674
+ exitCode: String(_nullishCoalesce$1(code, () => ( 'unknown'))),
3675
+ signal: _nullishCoalesce$1(signal, () => ( 'none')),
3676
+ logFile: logFilePath,
3677
+ });
3678
+ reportCommandComplete(commandName, false, Date.now() - cmdStartTime, {
3679
+ args: JSON.stringify(options),
3680
+ errorCode: _nullishCoalesce$1(code, () => ( 1)),
3681
+ errorMessage,
3682
+ });
3683
+ flushSlardar().then(() => {
3684
+ process.exit(code || 1);
3685
+ });
1163
3686
  } else {
1164
3687
  logger.success('Command completed successfully');
1165
3688
  logger.info(`Log file: ${logFilePath}`);
3689
+
3690
+ // 上报命令成功
3691
+ reportCommandComplete(commandName, true, Date.now() - cmdStartTime, {
3692
+ args: JSON.stringify(options),
3693
+ });
3694
+ // flush 由 main 函数统一处理
1166
3695
  }
1167
3696
  });
1168
3697
 
@@ -1173,12 +3702,39 @@ const executeRun = async (
1173
3702
  logger.error(`Stack trace:\n${error.stack}`);
1174
3703
  }
1175
3704
  logStream.end();
1176
- process.exit(1);
3705
+
3706
+ // 上报错误
3707
+ reportError(error, {
3708
+ command: commandName,
3709
+ type: 'child_process_error',
3710
+ });
3711
+ reportCommandComplete(commandName, false, Date.now() - cmdStartTime, {
3712
+ args: JSON.stringify(options),
3713
+ errorCode: 1,
3714
+ errorMessage: error.message,
3715
+ });
3716
+ flushSlardar().then(() => {
3717
+ process.exit(1);
3718
+ });
1177
3719
  });
1178
3720
  } catch (error) {
3721
+ const err = error instanceof Error ? error : new Error(String(error));
1179
3722
  logger.error(`Failed to run ${commandName} command:`);
1180
- logger.error(error instanceof Error ? error.message : String(error));
1181
- process.exit(1);
3723
+ logger.error(err.message);
3724
+
3725
+ // 上报错误
3726
+ reportError(err, {
3727
+ command: commandName,
3728
+ type: 'execution_error',
3729
+ });
3730
+ reportCommandComplete(commandName, false, Date.now() - cmdStartTime, {
3731
+ args: JSON.stringify(options),
3732
+ errorCode: 1,
3733
+ errorMessage: err.message,
3734
+ });
3735
+ flushSlardar().then(() => {
3736
+ process.exit(1);
3737
+ });
1182
3738
  }
1183
3739
  };
1184
3740
 
@@ -1511,58 +4067,12 @@ const convertDotfileName = (filePath) => {
1511
4067
 
1512
4068
  return filePath;
1513
4069
  };
1514
-
1515
- /**
1516
- * 复制 node_modules 目录(如果存在)
1517
- *
1518
- * @param sourceNodeModules - 源 node_modules 路径
1519
- * @param targetNodeModules - 目标 node_modules 路径
1520
- */
1521
- const copyNodeModules = (
1522
- sourceNodeModules,
1523
- targetNodeModules,
1524
- ) => {
1525
- if (!fs.existsSync(sourceNodeModules)) {
1526
- return;
1527
- }
1528
-
1529
- logger.info('\nCopying node_modules from pre-warmed template...');
1530
- logger.verbose(` From: ${sourceNodeModules}`);
1531
- logger.verbose(` To: ${targetNodeModules}`);
1532
-
1533
- const result = shelljs.exec(`cp -R "${sourceNodeModules}" "${targetNodeModules}"`, {
1534
- silent: true,
1535
- });
1536
-
1537
- if (result.stdout) {
1538
- process.stdout.write(result.stdout);
1539
- }
1540
-
1541
- if (result.stderr) {
1542
- process.stderr.write(result.stderr);
1543
- }
1544
-
1545
- if (result.code === 0) {
1546
- logger.success('✓ node_modules copied successfully');
1547
- } else {
1548
- logger.warn(
1549
- `Failed to copy node_modules: ${result.stderr || 'unknown error'}`,
1550
- );
1551
- logger.info('Will need to run pnpm install manually');
1552
- }
1553
- };
1554
4070
  // end_aigc
1555
4071
 
1556
4072
  // ABOUTME: File rendering utilities for template processing
1557
4073
  // ABOUTME: Handles file content rendering, hook execution, and file writing
1558
4074
 
1559
4075
 
1560
-
1561
-
1562
-
1563
-
1564
-
1565
-
1566
4076
  // start_aigc
1567
4077
  /**
1568
4078
  * 执行文件渲染钩子
@@ -1713,11 +4223,6 @@ const writeRenderedFile = async (options
1713
4223
  // ABOUTME: Provides dry-run file collection and conflict checking
1714
4224
 
1715
4225
 
1716
-
1717
-
1718
-
1719
-
1720
-
1721
4226
  // start_aigc
1722
4227
  /**
1723
4228
  * 收集所有将要写入的文件路径(dry-run 阶段)
@@ -1796,7 +4301,6 @@ const detectFileConflicts = (
1796
4301
  // ABOUTME: Coordinates file system, rendering, and conflict detection layers
1797
4302
 
1798
4303
 
1799
-
1800
4304
  // start_aigc
1801
4305
  /**
1802
4306
  * 处理单个文件(准备 + 写入)
@@ -1845,7 +4349,7 @@ const processSingleFile = async (options
1845
4349
  * 1. 验证模板目录
1846
4350
  * 2. 扫描所有模板文件
1847
4351
  * 3. Dry-run:收集将要写入的文件列表(考虑 hooks 影响)
1848
- * 4. 冲突检测:检查是否有文件会被覆盖
4352
+ * 4. 冲突检测:检查是否有文件会被覆盖(可通过 force 跳过)
1849
4353
  * 5. 实际写入:渲染并写入所有文件
1850
4354
  * 6. 复制 node_modules(如果存在)
1851
4355
  *
@@ -1856,8 +4360,9 @@ const processTemplateFiles = async (options
1856
4360
 
1857
4361
 
1858
4362
 
4363
+
1859
4364
  ) => {
1860
- const { templatePath, outputPath, context, templateConfig } = options;
4365
+ const { templatePath, outputPath, context, templateConfig, force } = options;
1861
4366
  logger.verbose('Processing template files:');
1862
4367
  logger.verbose(` - Template path: ${templatePath}`);
1863
4368
  logger.verbose(` - Output path: ${outputPath}`);
@@ -1896,16 +4401,23 @@ const processTemplateFiles = async (options
1896
4401
  templateConfig,
1897
4402
  });
1898
4403
 
1899
- // 阶段 3: 冲突检测
1900
- const conflicts = detectFileConflicts(outputPath, filesToWrite);
1901
-
1902
- if (conflicts.length > 0) {
1903
- // 有冲突,抛出详细的错误信息
1904
- const conflictList = conflicts.map(f => ` - ${f}`).join('\n');
1905
- throw new Error(
1906
- `File conflicts detected in output directory: ${outputPath}\n\n` +
1907
- `The following files already exist and would be overwritten:\n${conflictList}\n\n` +
1908
- 'Please remove these files or use a different output directory.',
4404
+ // 阶段 3: 冲突检测(force 为 true 时跳过)
4405
+ if (!force) {
4406
+ const conflicts = detectFileConflicts(outputPath, filesToWrite);
4407
+
4408
+ if (conflicts.length > 0) {
4409
+ // 有冲突,抛出详细的错误信息
4410
+ const conflictList = conflicts.map(f => ` - ${f}`).join('\n');
4411
+ throw new Error(
4412
+ `File conflicts detected in output directory: ${outputPath}\n\n` +
4413
+ `The following files already exist and would be overwritten:\n${conflictList}\n\n` +
4414
+ 'Please remove these files or use a different output directory.\n' +
4415
+ 'Or use --force to overwrite existing files.',
4416
+ );
4417
+ }
4418
+ } else {
4419
+ logger.verbose(
4420
+ ' - Force mode enabled, skipping conflict detection. Existing files will be overwritten.',
1909
4421
  );
1910
4422
  }
1911
4423
 
@@ -1925,11 +4437,7 @@ const processTemplateFiles = async (options
1925
4437
 
1926
4438
  logger.verbose('✓ All files processed successfully');
1927
4439
 
1928
- // 阶段 5: 单独处理 node_modules 目录(如果存在)
1929
- const sourceNodeModules = path.join(templatePath, 'node_modules');
1930
- const targetNodeModules = path.join(outputPath, 'node_modules');
1931
-
1932
- copyNodeModules(sourceNodeModules, targetNodeModules);
4440
+ // node_modules 将由 pnpm install 处理(利用缓存和硬链接机制)
1933
4441
  };
1934
4442
  // end_aigc
1935
4443
 
@@ -1942,6 +4450,7 @@ const processTemplateFiles = async (options
1942
4450
 
1943
4451
 
1944
4452
 
4453
+
1945
4454
  /**
1946
4455
  * 加载模板元数据和路径
1947
4456
  */
@@ -2011,6 +4520,19 @@ const executeAfterRenderHook = async (
2011
4520
  }
2012
4521
  };
2013
4522
 
4523
+ /**
4524
+ * 执行完成钩子
4525
+ */
4526
+ const executeCompleteHook = async (
4527
+ templateConfig,
4528
+ context,
4529
+ outputPath,
4530
+ ) => {
4531
+ if (templateConfig.onComplete) {
4532
+ await templateConfig.onComplete(context, outputPath);
4533
+ }
4534
+ };
4535
+
2014
4536
  /**
2015
4537
  * 准备输出目录
2016
4538
  */
@@ -2020,13 +4542,25 @@ const prepareOutputDirectory = (outputPath) => {
2020
4542
  return absolutePath;
2021
4543
  };
2022
4544
 
4545
+ /**
4546
+ * 模板引擎执行结果
4547
+ */
4548
+
4549
+
4550
+
4551
+
4552
+
4553
+
4554
+
4555
+
4556
+
2023
4557
  /**
2024
4558
  * 执行完整的模板渲染流程
2025
4559
  */
2026
4560
  const execute = async (
2027
4561
  options,
2028
4562
  ) => {
2029
- const { templateName, outputPath, command } = options;
4563
+ const { templateName, outputPath, command, force } = options;
2030
4564
 
2031
4565
  // 1. 加载模板
2032
4566
  const { templatePath } = await loadTemplateMetadata(templateName);
@@ -2051,12 +4585,17 @@ const execute = async (
2051
4585
  outputPath: absoluteOutputPath,
2052
4586
  context,
2053
4587
  templateConfig,
4588
+ force,
2054
4589
  });
2055
4590
 
2056
4591
  // 7. 执行 onAfterRender 钩子
2057
4592
  await executeAfterRenderHook(templateConfig, context, absoluteOutputPath);
2058
4593
 
2059
- return absoluteOutputPath;
4594
+ return {
4595
+ outputPath: absoluteOutputPath,
4596
+ templateConfig,
4597
+ context,
4598
+ };
2060
4599
  };
2061
4600
 
2062
4601
  function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
@@ -2098,12 +4637,46 @@ const runPnpmInstall = (projectPath) => {
2098
4637
  };
2099
4638
 
2100
4639
  /**
2101
- * 初始化 git 仓库并创建初始提交
4640
+ * 运行 git 命令的辅助函数
4641
+ */
4642
+ const runGitCommand = (command, projectPath) => {
4643
+ logger.info(`Executing: ${command}`);
4644
+
4645
+ const result = shelljs.exec(command, {
4646
+ cwd: projectPath,
4647
+ silent: true,
4648
+ });
4649
+
4650
+ // 输出命令的结果
4651
+ if (result.stdout) {
4652
+ process.stdout.write(result.stdout);
4653
+ }
4654
+
4655
+ if (result.stderr) {
4656
+ process.stderr.write(result.stderr);
4657
+ }
4658
+
4659
+ if (result.code !== 0) {
4660
+ const errorMessage = [
4661
+ `${command} failed with exit code ${result.code}`,
4662
+ result.stderr ? `\nStderr:\n${result.stderr}` : '',
4663
+ result.stdout ? `\nStdout:\n${result.stdout}` : '',
4664
+ ]
4665
+ .filter(Boolean)
4666
+ .join('');
4667
+
4668
+ throw new Error(errorMessage);
4669
+ }
4670
+ };
4671
+
4672
+ /**
4673
+ * 初始化 git 仓库
2102
4674
  * 如果目录中已存在 .git,则跳过初始化
2103
4675
  */
2104
4676
  const runGitInit = (projectPath) => {
2105
4677
  // 检查是否已存在 .git 目录
2106
4678
  const gitDir = path.join(projectPath, '.git');
4679
+
2107
4680
  if (fs.existsSync(gitDir)) {
2108
4681
  logger.info(
2109
4682
  '\n💡 Git repository already exists, skipping git initialization',
@@ -2111,53 +4684,43 @@ const runGitInit = (projectPath) => {
2111
4684
  return;
2112
4685
  }
2113
4686
 
2114
- const runGitCommand = (command) => {
2115
- logger.info(`Executing: ${command}`);
2116
-
2117
- const result = shelljs.exec(command, {
2118
- cwd: projectPath,
2119
- silent: true,
2120
- });
2121
-
2122
- // 输出命令的结果
2123
- if (result.stdout) {
2124
- process.stdout.write(result.stdout);
2125
- }
2126
-
2127
- if (result.stderr) {
2128
- process.stderr.write(result.stderr);
2129
- }
2130
-
2131
- if (result.code !== 0) {
2132
- const errorMessage = [
2133
- `${command} failed with exit code ${result.code}`,
2134
- result.stderr ? `\nStderr:\n${result.stderr}` : '',
2135
- result.stdout ? `\nStdout:\n${result.stdout}` : '',
2136
- ]
2137
- .filter(Boolean)
2138
- .join('');
2139
-
2140
- throw new Error(errorMessage);
2141
- }
2142
- };
2143
-
2144
4687
  try {
2145
4688
  logger.info('\nInitializing git repository...');
2146
- runGitCommand('git init');
2147
-
2148
- logger.info('Adding files to git...');
2149
- runGitCommand('git add .');
2150
-
2151
- logger.info('Creating initial commit...');
2152
- runGitCommand('git commit -m "chore: initial commit"');
2153
-
4689
+ runGitCommand('git init', projectPath);
2154
4690
  logger.success('Git repository initialized successfully!');
2155
4691
  } catch (error) {
2156
4692
  // Git 初始化失败不应该导致整个流程失败
4693
+ const errorMessage = error instanceof Error ? error.message : String(error);
4694
+ logger.warn(`Git initialization failed: ${errorMessage}`);
4695
+ logger.info('You can manually initialize git later with: git init');
4696
+ }
4697
+ };
4698
+
4699
+ /**
4700
+ * 提交初始化生成的所有文件
4701
+ */
4702
+ const commitChanges = (projectPath) => {
4703
+ // 检查是否存在 .git 目录
4704
+ const gitDir = path.join(projectPath, '.git');
4705
+ if (!fs.existsSync(gitDir)) {
2157
4706
  logger.warn(
2158
- `Git initialization failed: ${error instanceof Error ? error.message : String(error)}`,
4707
+ '\n⚠️ Git repository does not exist, skipping commit. Run git init first.',
4708
+ );
4709
+ return;
4710
+ }
4711
+
4712
+ try {
4713
+ logger.info('\nCommitting initialized files...');
4714
+ runGitCommand('git add --all', projectPath);
4715
+ runGitCommand('git commit -m "chore: init env"', projectPath);
4716
+ logger.success('Changes committed successfully!');
4717
+ } catch (error) {
4718
+ // Commit 失败不应该导致整个流程失败
4719
+ const errorMessage = error instanceof Error ? error.message : String(error);
4720
+ logger.warn(`Git commit failed: ${errorMessage}`);
4721
+ logger.info(
4722
+ 'You can manually commit later with: git add --all && git commit -m "chore: init env"',
2159
4723
  );
2160
- logger.info('You can manually initialize git later with: git init');
2161
4724
  }
2162
4725
  };
2163
4726
 
@@ -2175,23 +4738,213 @@ const runDev = (projectPath) => {
2175
4738
 
2176
4739
  logger.info(`Executing: ${cliPath} dev in ${projectPath}`);
2177
4740
 
2178
- // 使用通用的后台执行函数启动开发服务器
2179
- // 调用 CLI 自己的 dev 命令
2180
- const pid = spawnDetached(process.argv[0], [cliPath, 'dev'], {
2181
- cwd: projectPath,
2182
- verbose: false, // 不输出额外的进程信息,由 logger 统一处理
4741
+ try {
4742
+ // 使用通用的后台执行函数启动开发服务器
4743
+ // 调用 CLI 自己的 dev 命令
4744
+ const pid = spawnDetached(process.argv[0], [cliPath, 'dev'], {
4745
+ cwd: projectPath,
4746
+ verbose: false, // 不输出额外的进程信息,由 logger 统一处理
4747
+ });
4748
+
4749
+ if (pid) {
4750
+ logger.success('Development server started in background!');
4751
+ logger.info(`Process ID: ${pid}`);
4752
+ logger.info(
4753
+ '\nThe dev server is running independently. You can close this terminal.',
4754
+ );
4755
+ logger.info(`To stop the server later, use: kill ${pid}`);
4756
+ } else {
4757
+ logger.warn('Failed to get process ID for dev server');
4758
+ }
4759
+ } catch (error) {
4760
+ const errorMessage = error instanceof Error ? error.message : String(error);
4761
+ logger.error(`Failed to start dev server: ${errorMessage}`);
4762
+ }
4763
+ };
4764
+
4765
+ /**
4766
+ * Init 命令执行上下文
4767
+ */
4768
+
4769
+
4770
+
4771
+
4772
+
4773
+
4774
+
4775
+
4776
+
4777
+
4778
+
4779
+
4780
+
4781
+
4782
+
4783
+
4784
+
4785
+
4786
+
4787
+
4788
+
4789
+
4790
+
4791
+
4792
+
4793
+
4794
+
4795
+
4796
+
4797
+
4798
+
4799
+ /**
4800
+ * 步骤1: 执行模板引擎
4801
+ */
4802
+ const executeTemplateEngineStep = async ctx => {
4803
+ logger.info(`Initializing project with template: ${ctx.templateName}`);
4804
+ ctx.timer.logPhase('Initialization');
4805
+
4806
+ const result = await execute({
4807
+ templateName: ctx.templateName,
4808
+ outputPath: ctx.outputPath,
4809
+ command: ctx.command,
4810
+ force: _nullishCoalesce(ctx.options.force, () => ( false)),
2183
4811
  });
2184
4812
 
2185
- logger.success('Development server started in background!');
2186
- if (pid) {
2187
- logger.info(`Process ID: ${pid}`);
2188
- logger.info(
2189
- '\nThe dev server is running independently. You can close this terminal.',
2190
- );
2191
- logger.info(`To stop the server later, use: kill ${pid}`);
4813
+ // 保存结果到上下文
4814
+ ctx.absoluteOutputPath = result.outputPath;
4815
+ ctx.templateConfig = result.templateConfig;
4816
+ ctx.context = result.context;
4817
+
4818
+ ctx.timer.logPhase('Template engine execution');
4819
+ logger.success('Project created successfully!');
4820
+ };
4821
+
4822
+ /**
4823
+ * 步骤2: 检查 package.json 是否存在
4824
+ */
4825
+ const checkPackageJsonStep = ctx => {
4826
+ if (!ctx.absoluteOutputPath) {
4827
+ return;
4828
+ }
4829
+
4830
+ const packageJsonPath = path.join(ctx.absoluteOutputPath, 'package.json');
4831
+ ctx.hasPackageJson = fs.existsSync(packageJsonPath);
4832
+ };
4833
+
4834
+ /**
4835
+ * 步骤3: 安装依赖
4836
+ */
4837
+ const installDependenciesStep = ctx => {
4838
+ if (!ctx.absoluteOutputPath) {
4839
+ return;
4840
+ }
4841
+
4842
+ const { skipInstall } = ctx.options;
4843
+
4844
+ if (!skipInstall) {
4845
+ if (ctx.hasPackageJson) {
4846
+ runPnpmInstall(ctx.absoluteOutputPath);
4847
+ ctx.timer.logPhase('Dependencies installation');
4848
+ } else {
4849
+ logger.info(
4850
+ '\n💡 No package.json found, skipping dependency installation',
4851
+ );
4852
+ }
4853
+ }
4854
+ };
4855
+
4856
+ /**
4857
+ * 步骤4: 执行完成钩子
4858
+ */
4859
+ const executeCompleteHookStep = async ctx => {
4860
+ if (!ctx.absoluteOutputPath || !ctx.templateConfig || !ctx.context) {
4861
+ return;
4862
+ }
4863
+
4864
+ await executeCompleteHook(
4865
+ ctx.templateConfig,
4866
+ ctx.context,
4867
+ ctx.absoluteOutputPath,
4868
+ );
4869
+
4870
+ ctx.timer.logPhase('Complete hook execution');
4871
+ };
4872
+
4873
+ /**
4874
+ * 步骤5: 初始化 Git 仓库
4875
+ */
4876
+ const gitInitStep = ctx => {
4877
+ if (!ctx.absoluteOutputPath) {
4878
+ return;
4879
+ }
4880
+
4881
+ const { skipGit } = ctx.options;
4882
+
4883
+ if (!skipGit) {
4884
+ runGitInit(ctx.absoluteOutputPath);
4885
+ ctx.timer.logPhase('Git initialization');
4886
+ }
4887
+ };
4888
+
4889
+ /**
4890
+ * 步骤6: 提交 Git 变更
4891
+ */
4892
+ const gitCommitStep = ctx => {
4893
+ if (!ctx.absoluteOutputPath) {
4894
+ return;
4895
+ }
4896
+
4897
+ const { skipCommit } = ctx.options;
4898
+
4899
+ if (!skipCommit) {
4900
+ commitChanges(ctx.absoluteOutputPath);
4901
+ ctx.timer.logPhase('Git commit');
4902
+ }
4903
+ };
4904
+
4905
+ /**
4906
+ * 步骤7: 启动开发服务器
4907
+ */
4908
+ const startDevServerStep = ctx => {
4909
+ if (!ctx.absoluteOutputPath) {
4910
+ return;
4911
+ }
4912
+
4913
+ const { skipDev, skipInstall, skipGit, skipCommit } = ctx.options;
4914
+
4915
+ if (!skipDev) {
4916
+ runDev(ctx.absoluteOutputPath);
4917
+ ctx.timer.logPhase('Dev server startup');
4918
+ } else {
4919
+ // 只有跳过 dev 时才显示 Next steps
4920
+ logger.info('\nNext steps:');
4921
+ logger.info(` cd ${ctx.outputPath}`);
4922
+ if (skipInstall && ctx.hasPackageJson) {
4923
+ logger.info(' pnpm install');
4924
+ }
4925
+ if (skipGit) {
4926
+ logger.info(' git init');
4927
+ }
4928
+ if (skipCommit) {
4929
+ logger.info(' git add --all && git commit -m "chore: init env"');
4930
+ }
4931
+ logger.info(' coze dev');
2192
4932
  }
2193
4933
  };
2194
4934
 
4935
+ /**
4936
+ * Init 命令的所有执行步骤
4937
+ */
4938
+ const initSteps = [
4939
+ executeTemplateEngineStep,
4940
+ checkPackageJsonStep,
4941
+ installDependenciesStep,
4942
+ executeCompleteHookStep,
4943
+ gitInitStep,
4944
+ gitCommitStep,
4945
+ startDevServerStep,
4946
+ ];
4947
+
2195
4948
  /**
2196
4949
  * 执行 init 命令的内部实现
2197
4950
  */
@@ -2202,80 +4955,68 @@ const executeInit = async (
2202
4955
 
2203
4956
 
2204
4957
 
4958
+
4959
+
2205
4960
  ,
2206
4961
  command,
2207
4962
  ) => {
2208
4963
  const timer = new TimeTracker();
4964
+ const cmdStartTime = Date.now();
4965
+
4966
+ // 初始化执行上下文
4967
+ const ctx = {
4968
+ options,
4969
+ command,
4970
+ timer,
4971
+ cmdStartTime,
4972
+ templateName: options.template,
4973
+ outputPath: options.output,
4974
+ };
2209
4975
 
2210
4976
  try {
2211
- const {
2212
- template: templateName,
2213
- output: outputPath,
2214
- skipInstall,
2215
- skipGit,
2216
- skipDev,
2217
- } = options;
2218
-
2219
- logger.info(`Initializing project with template: ${templateName}`);
2220
- timer.logPhase('Initialization');
2221
-
2222
- // 执行模板引擎,返回绝对路径
2223
- const absoluteOutputPath = await execute({
2224
- templateName,
2225
- outputPath,
2226
- command,
2227
- });
2228
-
2229
- timer.logPhase('Template engine execution');
2230
- logger.success('Project created successfully!');
2231
-
2232
- // 如果没有跳过安装,检查是否需要运行 pnpm install
2233
- if (!skipInstall) {
2234
- const nodeModulesPath = path.join(absoluteOutputPath, 'node_modules');
2235
- const hasNodeModules = fs.existsSync(nodeModulesPath);
2236
-
2237
- if (hasNodeModules) {
2238
- logger.info(
2239
- '\n💡 Using pre-warmed node_modules, skipping pnpm install',
2240
- );
2241
- timer.logPhase('Node modules (pre-warmed)');
2242
- } else {
2243
- runPnpmInstall(absoluteOutputPath);
2244
- timer.logPhase('Dependencies installation');
2245
- }
2246
- }
2247
-
2248
- // 如果没有跳过 git,则初始化 git 仓库
2249
- if (!skipGit) {
2250
- runGitInit(absoluteOutputPath);
2251
- timer.logPhase('Git initialization');
2252
- }
4977
+ // 上报命令开始
4978
+ reportCommandStart(
4979
+ 'init',
4980
+ JSON.stringify({ template: ctx.templateName, output: ctx.outputPath }),
4981
+ { template: ctx.templateName },
4982
+ );
2253
4983
 
2254
- // 如果没有跳过 dev,则启动开发服务器
2255
- if (!skipDev) {
2256
- runDev(absoluteOutputPath);
2257
- timer.logPhase('Dev server startup');
2258
- } else {
2259
- // 只有跳过 dev 时才显示 Next steps
2260
- logger.info('\nNext steps:');
2261
- logger.info(` cd ${outputPath}`);
2262
- if (skipInstall) {
2263
- logger.info(' pnpm install');
2264
- }
2265
- if (skipGit) {
2266
- logger.info(
2267
- ' git init && git add . && git commit -m "initial commit"',
2268
- );
2269
- }
2270
- logger.info(' coze dev');
4984
+ // 逐个执行步骤
4985
+ for (const step of initSteps) {
4986
+ await step(ctx);
2271
4987
  }
2272
4988
 
2273
4989
  // 输出总耗时
2274
4990
  timer.logTotal();
4991
+
4992
+ // 上报命令成功
4993
+ reportCommandComplete('init', true, Date.now() - cmdStartTime, {
4994
+ args: JSON.stringify(options),
4995
+ categories: { template: ctx.templateName },
4996
+ });
4997
+ // flush 由 main 函数统一处理
2275
4998
  } catch (error) {
2276
4999
  timer.logTotal();
5000
+
5001
+ // 上报错误
5002
+ const err = error instanceof Error ? error : new Error(String(error));
5003
+ reportError(err, {
5004
+ command: 'init',
5005
+ template: options.template,
5006
+ output: options.output,
5007
+ });
5008
+
5009
+ // 上报命令失败
5010
+ reportCommandComplete('init', false, Date.now() - cmdStartTime, {
5011
+ args: JSON.stringify(options),
5012
+ errorCode: 1,
5013
+ errorMessage: err.message,
5014
+ categories: { template: options.template },
5015
+ });
5016
+ await flushSlardar();
5017
+
2277
5018
  logger.error('Failed to initialize project:');
2278
- logger.error(error instanceof Error ? error.message : String(error));
5019
+ logger.error(err.message);
2279
5020
  process.exit(1);
2280
5021
  }
2281
5022
  };
@@ -2292,27 +5033,55 @@ const registerCommand = program => {
2292
5033
  .option('-o, --output <path>', 'Output directory', process.cwd())
2293
5034
  .option('--skip-install', 'Skip automatic pnpm install', false)
2294
5035
  .option('--skip-git', 'Skip automatic git initialization', false)
5036
+ .option(
5037
+ '--skip-commit',
5038
+ 'Skip automatic git commit after initialization',
5039
+ false,
5040
+ )
2295
5041
  .option('--skip-dev', 'Skip automatic dev server start', false)
2296
5042
  .allowUnknownOption() // 允许透传参数
2297
5043
  .action(async (directory, options, command) => {
2298
5044
  // 位置参数优先级高于 --output 选项
2299
5045
  const outputPath = _nullishCoalesce(directory, () => ( options.output));
2300
- await executeInit({ ...options, output: outputPath }, command);
5046
+ // Always use force mode - overwrite existing files without conflict check
5047
+ const force = true;
5048
+ await executeInit({ ...options, output: outputPath, force }, command);
2301
5049
  });
2302
5050
  };
2303
5051
 
2304
- var version = "0.0.1-alpha.fd3d56";
2305
- var packageJson = {
2306
- version: version};
2307
-
2308
5052
  const commands = [
2309
5053
  registerCommand,
2310
5054
  registerCommand$1,
2311
- registerCommand$3,
5055
+ registerCommand$4,
2312
5056
  registerCommand$2,
5057
+ registerCommand$3,
2313
5058
  ];
2314
5059
 
2315
- const main = () => {
5060
+ const main = async () => {
5061
+ // 初始化 Slardar 监控
5062
+ initSlardar();
5063
+
5064
+ // 监听未捕获的异常
5065
+ process.on('uncaughtException', async (error) => {
5066
+ reportError(error, {
5067
+ type: 'uncaughtException',
5068
+ context: 'global',
5069
+ });
5070
+ await flushSlardar();
5071
+ process.exit(1);
5072
+ });
5073
+
5074
+ // 监听未处理的 Promise rejection
5075
+ process.on('unhandledRejection', async (reason) => {
5076
+ const error = reason instanceof Error ? reason : new Error(String(reason));
5077
+ reportError(error, {
5078
+ type: 'unhandledRejection',
5079
+ context: 'global',
5080
+ });
5081
+ await flushSlardar();
5082
+ process.exit(1);
5083
+ });
5084
+
2316
5085
  const program = new commander.Command();
2317
5086
 
2318
5087
  program
@@ -2327,7 +5096,12 @@ const main = () => {
2327
5096
  // 在 help 输出中添加模板信息
2328
5097
  program.addHelpText('after', generateTemplatesHelpText());
2329
5098
 
2330
- program.parse(process.argv);
5099
+ // 使用 parseAsync 等待命令执行完成
5100
+ await program.parseAsync(process.argv);
5101
+
5102
+ // 统一在命令执行完成后 flush
5103
+ // 注意:如果命令中调用了 process.exit(),不会执行到这里
5104
+ await flushSlardar();
2331
5105
  };
2332
5106
 
2333
5107
  main();