@thinkingai/ae-cli 6.1.4 → 6.1.5

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 (130) hide show
  1. package/dist/{auth-MEJ642P4.js → auth-ENM3FE6L.js} +3 -2
  2. package/dist/{auth-7H3HAAJ3.js → auth-UPGUOKTW.js} +13 -6
  3. package/dist/{capability-QW4AVJHI.js → capability-AJC5CBRT.js} +49 -17
  4. package/dist/{capability-SCRFGODD.js → capability-TQ5KU5Q6.js} +49 -17
  5. package/dist/chunk-24BAVOX3.js +51 -0
  6. package/dist/{chunk-MDJGDI6K.js → chunk-3KI3RRXX.js} +5 -5
  7. package/dist/{chunk-PKRD2IEM.js → chunk-3P3562ZX.js} +9 -7
  8. package/dist/{chunk-R77JT7XD.js → chunk-4Q5TNP4Q.js} +4 -4
  9. package/dist/{chunk-7OLGDQQ2.js → chunk-6CHYBI64.js} +2 -2
  10. package/dist/{chunk-6LEYLOV3.js → chunk-CPVTECJ3.js} +9 -7
  11. package/dist/{chunk-KCA6BA5D.js → chunk-DB4Q3ANU.js} +5 -3
  12. package/dist/{chunk-2NDGFQHW.js → chunk-E7UXXHO3.js} +11 -3
  13. package/dist/{chunk-I4A62X3N.js → chunk-HQ2A7ITL.js} +23 -14
  14. package/dist/chunk-IMMGMU54.js +674 -0
  15. package/dist/{chunk-AJTH7LT3.js → chunk-IR4ZLVPW.js} +4 -2
  16. package/dist/{chunk-TBHBYKXZ.js → chunk-ISY6HMHM.js} +2 -2
  17. package/dist/{chunk-KGJQCYVC.js → chunk-LCXU3AAT.js} +4 -2
  18. package/dist/chunk-LYVNONC4.js +86 -0
  19. package/dist/{chunk-DYOS6YY7.js → chunk-RGXCNC4N.js} +23 -14
  20. package/dist/{chunk-YCLVYFK7.js → chunk-V6FR6WTW.js} +45 -87
  21. package/dist/chunk-VTWMIC5L.js +27 -0
  22. package/dist/{cli-token-TVQRSE46.js → cli-token-4SBMXAUK.js} +6 -3
  23. package/dist/{client-2643Z5AG.js → client-PP5FETMW.js} +4 -3
  24. package/dist/community-report-client-KK2QBANO.js +145 -0
  25. package/dist/{config-7UZWDE74.js → config-RCCGHHYA.js} +6 -3
  26. package/dist/index.js +506 -221
  27. package/dist/{metadata-BFDL6RUK.js → metadata-3M5F2AED.js} +14 -13
  28. package/dist/{metadata-FCLDBXX2.js → metadata-W2MEOI4Z.js} +14 -13
  29. package/dist/{model-T3KZJWLW.js → model-OYQLXCQY.js} +3 -2
  30. package/dist/{raw-CN542NGT.js → raw-TPB7KSZO.js} +6 -4
  31. package/dist/{sync-ERNHDPB5.js → sync-EFJKFZK2.js} +6 -3
  32. package/dist/{te-agent-FCCWUDTJ.js → te-agent-K2OWMZXT.js} +3 -2
  33. package/dist/{te-analysis-PUVF5IF4.js → te-analysis-I73ZS4NK.js} +903 -33
  34. package/dist/{te-analysis-UJDOKPAN.js → te-analysis-Q7AZCDU4.js} +903 -33
  35. package/dist/{te-common-XLAGWNIV.js → te-common-ST3QPSXJ.js} +7 -6
  36. package/dist/{te-common-VUX3VOXZ.js → te-common-WSLIKKPC.js} +7 -6
  37. package/dist/te-community-WXGB6IOX.js +1659 -0
  38. package/dist/te-community-X2AHXGCA.js +1659 -0
  39. package/dist/{te-dataops-ZNJBQ6VT.js → te-dataops-MJV54MNY.js} +10 -8
  40. package/dist/{te-dataops-F36T656A.js → te-dataops-OA7I6HBG.js} +10 -8
  41. package/dist/{te-engage-K4AEUPK5.js → te-engage-GJRVQMK3.js} +10 -9
  42. package/dist/{te-engage-QBCCME22.js → te-engage-JIXX3WBI.js} +10 -9
  43. package/dist/{te-experiment-JINSMHMW.js → te-experiment-JKX4FH6D.js} +7 -6
  44. package/dist/{te-experiment-NWNQHJS5.js → te-experiment-UMSHBBKI.js} +7 -6
  45. package/dist/{te-kb-AYCODNU6.js → te-kb-CIZXRWMO.js} +49 -6
  46. package/dist/{te-meta-ARDIW3YI.js → te-meta-Q4L6EE3Q.js} +7 -6
  47. package/dist/{te-meta-UUROEODR.js → te-meta-VHCN4Q62.js} +7 -6
  48. package/dist/{te-team-OKCOX7OE.js → te-team-PDKKW7Q5.js} +7 -6
  49. package/dist/tracking/i18n/resources/cli/en.json +4 -3
  50. package/dist/tracking/i18n/resources/cli/ja.json +4 -3
  51. package/dist/tracking/i18n/resources/cli/ko.json +4 -3
  52. package/dist/tracking/i18n/resources/cli/zh.json +4 -3
  53. package/package.json +6 -2
  54. package/skills/ae-agent/SKILL.md +2 -1
  55. package/skills/ae-analysis/SKILL.md +12 -1
  56. package/skills/ae-analysis/references/adhoc_export.md +2 -0
  57. package/skills/ae-analysis/references/adhoc_run.md +2 -0
  58. package/skills/ae-analysis/references/alert_create.md +25 -0
  59. package/skills/ae-analysis/references/alert_definition_schema_get.md +24 -0
  60. package/skills/ae-analysis/references/alert_delete.md +26 -0
  61. package/skills/ae-analysis/references/alert_detail_list.md +27 -0
  62. package/skills/ae-analysis/references/alert_get.md +25 -0
  63. package/skills/ae-analysis/references/alert_job_list.md +24 -0
  64. package/skills/ae-analysis/references/alert_list.md +27 -0
  65. package/skills/ae-analysis/references/alert_notice_config_list.md +24 -0
  66. package/skills/ae-analysis/references/alert_start.md +25 -0
  67. package/skills/ae-analysis/references/alert_stop.md +25 -0
  68. package/skills/ae-analysis/references/alert_update.md +26 -0
  69. package/skills/ae-analysis/references/bi_panel_create.md +3 -3
  70. package/skills/ae-analysis/references/check_delete.md +27 -0
  71. package/skills/ae-analysis/references/check_export.md +27 -0
  72. package/skills/ae-analysis/references/check_get.md +27 -0
  73. package/skills/ae-analysis/references/check_list.md +24 -0
  74. package/skills/ae-analysis/references/check_retry.md +27 -0
  75. package/skills/ae-analysis/references/check_run.md +25 -0
  76. package/skills/ae-analysis/references/command_index.md +61 -27
  77. package/skills/ae-analysis/references/dashboard_create.md +3 -3
  78. package/skills/ae-analysis/references/dashboard_daily_report_send.md +1 -0
  79. package/skills/ae-analysis/references/dashboard_daily_report_update.md +2 -0
  80. package/skills/ae-analysis/references/dashboard_report_data_export.md +3 -3
  81. package/skills/ae-analysis/references/dashboard_report_data_run.md +3 -3
  82. package/skills/ae-analysis/references/event_blacklist_add.md +25 -0
  83. package/skills/ae-analysis/references/event_blacklist_list.md +24 -0
  84. package/skills/ae-analysis/references/event_blacklist_update.md +26 -0
  85. package/skills/ae-analysis/references/ingest_error_list.md +27 -0
  86. package/skills/ae-analysis/references/ingest_summary.md +26 -0
  87. package/skills/ae-analysis/references/live_data_export.md +27 -0
  88. package/skills/ae-analysis/references/live_data_list.md +27 -0
  89. package/skills/ae-analysis/references/plan_change_log_export.md +27 -0
  90. package/skills/ae-analysis/references/plan_change_log_list.md +24 -0
  91. package/skills/ae-analysis/references/plan_delete_items.md +30 -0
  92. package/skills/ae-analysis/references/plan_export.md +26 -0
  93. package/skills/ae-analysis/references/plan_generate.md +27 -0
  94. package/skills/ae-analysis/references/plan_get.md +24 -0
  95. package/skills/ae-analysis/references/plan_import_excel.md +26 -0
  96. package/skills/ae-analysis/references/plan_save_items.md +27 -0
  97. package/skills/ae-analysis/references/plan_sync_from_meta.md +24 -0
  98. package/skills/ae-analysis/references/project_role_delete.md +4 -3
  99. package/skills/ae-analysis/references/project_role_get.md +4 -3
  100. package/skills/ae-analysis/references/project_role_user_list.md +4 -3
  101. package/skills/ae-analysis/references/query_create_result_cluster.md +2 -1
  102. package/skills/ae-analysis/references/report_data_export.md +3 -1
  103. package/skills/ae-analysis/references/report_data_run.md +12 -2
  104. package/skills/ae-analysis/references/sdk_sample_generate.md +24 -0
  105. package/skills/ae-analysis/references/user_cluster_create.md +2 -0
  106. package/skills/ae-analysis/references/user_cluster_create_id.md +2 -0
  107. package/skills/ae-analysis/references/user_cluster_update.md +2 -0
  108. package/skills/ae-analysis/references/user_cluster_update_id.md +2 -0
  109. package/skills/ae-analysis/references/user_tag_create.md +2 -0
  110. package/skills/ae-analysis/references/user_tag_create_id.md +2 -0
  111. package/skills/ae-analysis/references/user_tag_update.md +2 -0
  112. package/skills/ae-analysis/references/user_tag_update_id.md +2 -0
  113. package/skills/ae-analysis-global/SKILL.md +2 -0
  114. package/skills/ae-capability/SKILL.md +7 -5
  115. package/skills/ae-community/SKILL.md +72 -8
  116. package/skills/ae-community/references/community-chat-analysis.md +341 -0
  117. package/skills/ae-community/references/community-data-report.md +301 -0
  118. package/skills/ae-dataops/SKILL.md +2 -1
  119. package/skills/ae-engage/SKILL.md +2 -1
  120. package/skills/ae-generate-tracking-code/SKILL.md +4 -4
  121. package/skills/ae-generate-tracking-plan/SKILL.md +132 -11
  122. package/skills/ae-generate-tracking-plan/references/business-dimension-mapping.md +98 -33
  123. package/skills/ae-generate-tracking-plan/references/xlsx-schema.md +16 -14
  124. package/skills/ae-kb/SKILL.md +2 -1
  125. package/skills/ae-metadata/SKILL.md +2 -1
  126. package/skills/ae-team/SKILL.md +2 -1
  127. package/dist/chunk-NOO24N7W.js +0 -11
  128. package/dist/chunk-TNW2CI4W.js +0 -129
  129. package/dist/te-community-PEZ2VEF7.js +0 -687
  130. package/dist/te-community-TSKJ652U.js +0 -687
package/dist/index.js CHANGED
@@ -1,36 +1,46 @@
1
+ import {
2
+ getLocalCliPackageInfo
3
+ } from "./chunk-VTWMIC5L.js";
1
4
  import {
2
5
  requiresConfirmation
3
6
  } from "./chunk-OO6XR6LK.js";
4
7
  import {
5
8
  TeAgentApiError,
6
9
  TeAgentCredentialsError
7
- } from "./chunk-R77JT7XD.js";
10
+ } from "./chunk-4Q5TNP4Q.js";
8
11
  import {
9
12
  CapabilityGatewayError,
10
13
  executeCapability,
11
14
  uploadInputFileBytes
12
- } from "./chunk-I4A62X3N.js";
15
+ } from "./chunk-HQ2A7ITL.js";
13
16
  import {
17
+ formatCapabilityMissCompatHint,
18
+ notifyIfUpdateAvailable,
14
19
  printError,
15
- printOutput
16
- } from "./chunk-TNW2CI4W.js";
17
- import {
18
- PermissionError
19
- } from "./chunk-NOO24N7W.js";
20
+ printOutput,
21
+ runHostCompatCheck
22
+ } from "./chunk-IMMGMU54.js";
20
23
  import {
21
24
  clearCliToken,
22
25
  getCliToken
23
- } from "./chunk-2NDGFQHW.js";
26
+ } from "./chunk-E7UXXHO3.js";
24
27
  import {
25
28
  SecureStoreAuthError,
26
29
  resolveHost
27
- } from "./chunk-AJTH7LT3.js";
30
+ } from "./chunk-IR4ZLVPW.js";
28
31
  import {
29
32
  getActiveHost,
30
33
  getConfigDir,
31
- logger,
32
34
  safeJsonParse
33
- } from "./chunk-YCLVYFK7.js";
35
+ } from "./chunk-V6FR6WTW.js";
36
+ import {
37
+ CliValidationError,
38
+ CommunityReportError,
39
+ PermissionError
40
+ } from "./chunk-24BAVOX3.js";
41
+ import {
42
+ logger
43
+ } from "./chunk-LYVNONC4.js";
34
44
 
35
45
  // src/index.ts
36
46
  import { Command as CommanderCommand } from "commander";
@@ -49,7 +59,11 @@ async function runCommand(cmd, opts, globalOpts) {
49
59
  try {
50
60
  const ctx = createRuntimeContext(cmd, opts, globalOpts);
51
61
  const cmdName = cmd.resource ? `${cmd.service} ${cmd.resource} ${cmd.command}` : `${cmd.service} ${cmd.command}`;
52
- logger.command(cmdName, opts);
62
+ logger.command(
63
+ cmdName,
64
+ opts,
65
+ cmd.flags.filter((flag) => flag.sensitive).map((flag) => flag.name)
66
+ );
53
67
  const missingRequired = cmd.flags.filter((flag) => {
54
68
  if (!flag.required) return false;
55
69
  const val = opts[camelCase(flag.name)];
@@ -99,6 +113,16 @@ async function runCommand(cmd, opts, globalOpts) {
99
113
  }
100
114
  }
101
115
  }
116
+ for (const flag of cmd.flags) {
117
+ if (flag.type !== "string") continue;
118
+ const val = opts[camelCase(flag.name)];
119
+ if (val === void 0 || val === null || val === "") continue;
120
+ const error = stringFlagValidationError(flag, String(val));
121
+ if (error) {
122
+ printError("validation", error.message, error.hint);
123
+ process.exit(1);
124
+ }
125
+ }
102
126
  if (globalOpts.validate && globalOpts.dryRun) {
103
127
  printError(
104
128
  "validation",
@@ -146,13 +170,25 @@ async function runCommand(cmd, opts, globalOpts) {
146
170
  process.exit(1);
147
171
  }
148
172
  const message = err.message || String(err);
149
- logger.error(`Command failed: ${message}`);
150
- if (err instanceof TeAgentCredentialsError) {
173
+ if (!(err instanceof CommunityReportError)) {
174
+ logger.error(`Command failed: ${message}`);
175
+ }
176
+ if (err instanceof CliValidationError) {
177
+ printError(
178
+ "validation",
179
+ message,
180
+ err.hint,
181
+ err.code,
182
+ err.location ? { location: err.location } : void 0
183
+ );
184
+ } else if (err instanceof TeAgentCredentialsError) {
151
185
  printError("config", message, err.hint);
152
186
  } else if (err instanceof PermissionError) {
153
187
  printError("permission", message);
154
188
  } else if (err instanceof CapabilityGatewayError) {
155
189
  printError("api", message, err.hint ?? capabilityGatewayHint(err), err.code, err.meta);
190
+ } else if (err instanceof CommunityReportError) {
191
+ printError("api", message, err.hint, err.code, err.meta, { log: false });
156
192
  } else if (err instanceof SecureStoreAuthError) {
157
193
  printError("auth", message, "Run: ae-cli auth login");
158
194
  } else if (err instanceof TeAgentApiError) {
@@ -171,15 +207,33 @@ async function runCommand(cmd, opts, globalOpts) {
171
207
  process.exit(1);
172
208
  }
173
209
  }
210
+ function stringFlagValidationError(flag, value) {
211
+ if (flag.type !== "string") return void 0;
212
+ if (flag.minLength !== void 0 && value.length < flag.minLength) {
213
+ return { message: `--${flag.name} must contain at least ${flag.minLength} characters` };
214
+ }
215
+ if (flag.maxLength !== void 0 && value.length > flag.maxLength) {
216
+ return { message: `--${flag.name} must not exceed ${flag.maxLength} characters (got: ${value.length})` };
217
+ }
218
+ if (flag.pattern !== void 0 && !new RegExp(flag.pattern).test(value)) {
219
+ return { message: `--${flag.name} has an invalid format`, hint: `Expected pattern: ${flag.pattern}` };
220
+ }
221
+ return void 0;
222
+ }
174
223
  function capabilityGatewayHint(err) {
175
224
  if (err.code === "UPLOAD_NOT_EXIST" && (err.meta?.capability_id === "engage-setting.config-table.save" || err.meta?.capability_id === "engage-setting.config-table.update-data")) {
176
225
  return "Run config-table upload first with the same --project-id and --request-id, then retry this command within 10 minutes. The upload cache is consumed after a successful save/update.";
177
226
  }
227
+ const compatExtra = formatCapabilityMissCompatHint();
178
228
  if (err.code === "CAPABILITY_NOT_FOUND") {
179
- return "The current host does not expose this capability. Do not retry with different parameters; use a supported command path or ask the platform/backend owner to enable the capability.";
229
+ const base = "The current host does not expose this capability. Do not retry with different parameters; use a supported command path or ask the platform/backend owner to enable the capability.";
230
+ return compatExtra ? `${base}
231
+ ${compatExtra}` : base;
180
232
  }
181
233
  if (err.httpStatus === 404 && !err.code) {
182
- return "The current host returned 404 for this capability route. Do not keep retrying the same command; verify the backend route/capability deployment.";
234
+ const base = "The current host returned 404 for this capability route. Do not keep retrying the same command; verify the backend route/capability deployment.";
235
+ return compatExtra ? `${base}
236
+ ${compatExtra}` : base;
183
237
  }
184
238
  return void 0;
185
239
  }
@@ -192,10 +246,17 @@ function createRuntimeContext(cmd, opts, globalOpts) {
192
246
  let _clientModule = null;
193
247
  async function getClient() {
194
248
  if (!_clientModule) {
195
- _clientModule = await import("./client-2643Z5AG.js");
249
+ _clientModule = await import("./client-PP5FETMW.js");
196
250
  }
197
251
  return _clientModule;
198
252
  }
253
+ let _communityReportModule = null;
254
+ async function getCommunityReportClient() {
255
+ if (!_communityReportModule) {
256
+ _communityReportModule = await import("./community-report-client-KK2QBANO.js");
257
+ }
258
+ return _communityReportModule;
259
+ }
199
260
  const ctx = {
200
261
  str(name) {
201
262
  return String(opts[camelCase(name)] ?? "");
@@ -223,14 +284,18 @@ function createRuntimeContext(cmd, opts, globalOpts) {
223
284
  process.exit(1);
224
285
  }
225
286
  },
226
- async api(method, path5, params, data) {
287
+ async api(method, path4, params, data) {
227
288
  const client = await getClient();
228
289
  if (method.toUpperCase() === "GET") {
229
- return client.httpGet(path5, params, ctx.host());
290
+ return client.httpGet(path4, params, ctx.host());
230
291
  } else {
231
- return client.httpRequest(method, path5, params, data, ctx.host());
292
+ return client.httpRequest(method, path4, params, data, ctx.host());
232
293
  }
233
294
  },
295
+ async communityReport(endpoint, rawBody) {
296
+ const client = await getCommunityReportClient();
297
+ return client.communityReport(endpoint, rawBody);
298
+ },
234
299
  async querySql(projectId, sql) {
235
300
  const client = await getClient();
236
301
  return client.querySql(projectId, sql, ctx.host());
@@ -240,7 +305,7 @@ function createRuntimeContext(cmd, opts, globalOpts) {
240
305
  return client.queryReportData(projectId, reportId, qp, eventModel, options, ctx.host());
241
306
  },
242
307
  async token() {
243
- const { getToken } = await import("./auth-MEJ642P4.js");
308
+ const { getToken } = await import("./auth-ENM3FE6L.js");
244
309
  return getToken(ctx.host());
245
310
  },
246
311
  host() {
@@ -309,9 +374,16 @@ function registerCommands(program2, commands) {
309
374
  sub.option(flagStr, flag.desc);
310
375
  }
311
376
  }
312
- sub.option("--host <url>", "Override active AE host URL for this command");
377
+ if (cmd.usesAeHost !== false) {
378
+ sub.option("--host <url>", "Override active AE host URL for this command");
379
+ }
313
380
  sub.option("--format <format>", "Output format: json | table. Default: json.");
314
381
  sub.option("--jq <expr>", "jq 1.8 filter over command payload, applied before output envelope wrapping.");
382
+ if (cmd.helpText) {
383
+ sub.addHelpText("after", `
384
+ ${cmd.helpText}
385
+ `);
386
+ }
315
387
  sub.action(async (opts) => {
316
388
  const globalOpts = extractGlobalOptions(program2);
317
389
  if (opts.host) globalOpts.host = opts.host;
@@ -356,150 +428,9 @@ function extractGlobalOptions(program2) {
356
428
  };
357
429
  }
358
430
 
359
- // src/core/update-check.ts
360
- import fs from "fs";
361
- import path from "path";
362
- var CONFIG_DIR = path.join(process.env.HOME || "", ".ae-cli");
363
- var CACHE_FILE = path.join(CONFIG_DIR, "update-check.json");
364
- var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
365
- var FETCH_TIMEOUT_MS = 3e3;
366
- var REGISTRY_BY_PACKAGE = {
367
- "@thinkingai/ae-cli": "https://registry.npmjs.org"
368
- };
369
- var UPDATE_CHECK_PACKAGE = "@thinkingai/ae-cli";
370
- function isUpdateCheckEnabled(packageName) {
371
- return packageName === UPDATE_CHECK_PACKAGE;
372
- }
373
- var DEFAULT_REGISTRY = "https://registry.npmjs.org";
374
- function parseVersion(version2) {
375
- const core = version2.trim().split("-")[0];
376
- return core.split(".").map((part) => {
377
- const n = Number.parseInt(part, 10);
378
- return Number.isFinite(n) ? n : 0;
379
- });
380
- }
381
- function isNewer(latest, current) {
382
- const a = parseVersion(latest);
383
- const b = parseVersion(current);
384
- const len = Math.max(a.length, b.length, 3);
385
- for (let i = 0; i < len; i += 1) {
386
- const av = a[i] ?? 0;
387
- const bv = b[i] ?? 0;
388
- if (av > bv) return true;
389
- if (av < bv) return false;
390
- }
391
- return false;
392
- }
393
- function resolveRegistry(packageName) {
394
- if (REGISTRY_BY_PACKAGE[packageName]) {
395
- return REGISTRY_BY_PACKAGE[packageName];
396
- }
397
- const envRegistry = process.env.npm_config_registry?.replace(/\/$/, "");
398
- return envRegistry || DEFAULT_REGISTRY;
399
- }
400
- function buildInstallCommand(packageName, registry) {
401
- const base = `npm install -g ${packageName}@latest`;
402
- if (registry === DEFAULT_REGISTRY) {
403
- return base;
404
- }
405
- return `${base} --registry=${registry}`;
406
- }
407
- function shouldSkipUpdateCheck(argv = process.argv) {
408
- if (process.env.AE_CLI_NO_UPDATE_CHECK === "1") return true;
409
- if (process.env.CI === "true" || process.env.CI === "1") return true;
410
- return argv.slice(2).some((arg) => {
411
- if (arg === "--no-update-check") return true;
412
- if (arg === "--version" || arg === "-V" || arg === "--help" || arg === "-h") return true;
413
- return false;
414
- });
415
- }
416
- function ensureConfigDir() {
417
- if (!fs.existsSync(CONFIG_DIR)) {
418
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
419
- }
420
- }
421
- function readCache() {
422
- try {
423
- if (!fs.existsSync(CACHE_FILE)) return null;
424
- const raw = fs.readFileSync(CACHE_FILE, "utf8");
425
- const data = JSON.parse(raw);
426
- if (!data.packageName || !data.latestVersion || !data.lastCheckedAt) return null;
427
- return data;
428
- } catch {
429
- return null;
430
- }
431
- }
432
- function writeCache(cache) {
433
- try {
434
- ensureConfigDir();
435
- fs.writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2));
436
- } catch {
437
- }
438
- }
439
- function cacheIsStale(cache, packageName) {
440
- if (!cache || cache.packageName !== packageName) return true;
441
- const age = Date.now() - new Date(cache.lastCheckedAt).getTime();
442
- return age >= CHECK_INTERVAL_MS;
443
- }
444
- function printUpdateNotice(current, latest, installCommand) {
445
- process.stderr.write(`[ae-cli] Update available: ${current} \u2192 ${latest}
446
- `);
447
- process.stderr.write(` Run: ${installCommand}
448
- `);
449
- }
450
- async function fetchLatestVersion(packageName, registry) {
451
- const url = `${registry.replace(/\/$/, "")}/${encodeURIComponent(packageName)}`;
452
- const controller = new AbortController();
453
- const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
454
- try {
455
- const resp = await fetch(url, {
456
- signal: controller.signal,
457
- headers: { Accept: "application/json" }
458
- });
459
- if (!resp.ok) return null;
460
- const data = await resp.json();
461
- const latest = data["dist-tags"]?.latest;
462
- return typeof latest === "string" && latest.trim() ? latest.trim() : null;
463
- } catch {
464
- return null;
465
- } finally {
466
- clearTimeout(timer);
467
- }
468
- }
469
- async function refreshCache(pkg2, registry) {
470
- const latest = await fetchLatestVersion(pkg2.name, registry);
471
- if (!latest) return readCache();
472
- const cache = {
473
- packageName: pkg2.name,
474
- currentVersion: pkg2.version,
475
- latestVersion: latest,
476
- lastCheckedAt: (/* @__PURE__ */ new Date()).toISOString()
477
- };
478
- writeCache(cache);
479
- return cache;
480
- }
481
- function maybeNotifyFromCache(pkg2, cache, registry) {
482
- if (!cache || cache.packageName !== pkg2.name) return;
483
- if (!isNewer(cache.latestVersion, pkg2.version)) return;
484
- printUpdateNotice(pkg2.version, cache.latestVersion, buildInstallCommand(pkg2.name, registry));
485
- }
486
- function notifyIfUpdateAvailable(pkg2) {
487
- if (!isUpdateCheckEnabled(pkg2.name)) return;
488
- if (shouldSkipUpdateCheck()) return;
489
- const registry = resolveRegistry(pkg2.name);
490
- const cache = readCache();
491
- maybeNotifyFromCache(pkg2, cache, registry);
492
- if (!cacheIsStale(cache, pkg2.name)) return;
493
- void refreshCache(pkg2, registry).then((fresh) => {
494
- if (!fresh) return;
495
- if (cache && fresh.latestVersion === cache.latestVersion) return;
496
- maybeNotifyFromCache(pkg2, fresh, registry);
497
- });
498
- }
499
-
500
431
  // src/commands/tracking/plan.ts
501
432
  import { readFile, writeFile, cp } from "fs/promises";
502
- import path3, { resolve as resolve2 } from "path";
433
+ import path2, { resolve as resolve2 } from "path";
503
434
 
504
435
  // src/tracking/xlsx/write.ts
505
436
  import ExcelJS from "exceljs";
@@ -719,13 +650,13 @@ function allHeaderNames(key) {
719
650
 
720
651
  // src/tracking/i18n/resources/xlsx/types.ts
721
652
  var PROP_TYPE_DISPLAY = {
722
- string: { zh: "\u6587\u672C", en: "string", ja: "\u30B9\u30C8\u30EA\u30F3\u30B0", ko: "string" },
723
- number: { zh: "\u6570\u503C", en: "number", ja: "\u6570\u5024", ko: "number" },
724
- bool: { zh: "\u5E03\u5C14", en: "boolean", ja: "\u30D6\u30FC\u30EB\u5024", ko: "boolean" },
725
- datetime: { zh: "\u65F6\u95F4", en: "datetime", ja: "\u6642\u9593", ko: "time" },
726
- object: { zh: "\u5BF9\u8C61", en: "object", ja: "\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8", ko: "object" },
727
- array_row: { zh: "\u5BF9\u8C61\u7EC4", en: "object[]", ja: "\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u914D\u5217", ko: "object_array" },
728
- array_string: { zh: "\u5217\u8868", en: "string[]", ja: "\u914D\u5217", ko: "string_array" }
653
+ string: { zh: "\u6587\u672C", en: "String", ja: "\u30B9\u30C8\u30EA\u30F3\u30B0", ko: "String" },
654
+ number: { zh: "\u6570\u503C", en: "Number", ja: "\u6570\u5024", ko: "Number" },
655
+ bool: { zh: "\u5E03\u5C14", en: "Boolean", ja: "\u30D6\u30FC\u30EB\u5024", ko: "Boolean" },
656
+ datetime: { zh: "\u65F6\u95F4", en: "Date", ja: "\u6642\u9593", ko: "Date" },
657
+ object: { zh: "\u5BF9\u8C61", en: "Row", ja: "\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8", ko: "Row" },
658
+ array_row: { zh: "\u5BF9\u8C61\u7EC4", en: "Array Row", ja: "\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u30B0\u30EB\u30FC\u30D7", ko: "Array Row" },
659
+ array_string: { zh: "\u5217\u8868", en: "List", ja: "\u30EA\u30B9\u30C8", ko: "List" }
729
660
  };
730
661
  function typeToDisplay(type, locale) {
731
662
  return PROP_TYPE_DISPLAY[type][locale];
@@ -739,24 +670,29 @@ for (const [canonical, locales] of Object.entries(PROP_TYPE_DISPLAY)) {
739
670
  var ALIASES = {
740
671
  // zh alias(行业模板)
741
672
  "\u5B57\u7B26\u4E32": "string",
742
- "\u5BF9\u8C61": "object",
743
- // en alias
744
- "String": "string",
745
- "Number": "number",
746
- "Boolean": "bool",
673
+ // en alias(旧值兼容 — 2026-07-15 前生成的老 xlsx)
674
+ "string": "string",
675
+ "number": "number",
676
+ "boolean": "bool",
677
+ "datetime": "datetime",
678
+ "object": "object",
679
+ "object[]": "array_row",
680
+ "string[]": "array_string",
681
+ // en 额外 alias
747
682
  "Bool": "bool",
748
683
  "DateTime": "datetime",
749
684
  "Time": "datetime",
750
685
  "Object": "object",
751
- "Row": "object",
752
686
  "Object Array": "array_row",
753
- "List": "array_string",
754
687
  "String Array": "array_string",
755
688
  // ja alias
756
689
  "\u6587\u5B57\u5217": "string",
757
690
  "\u30C6\u30AD\u30B9\u30C8": "string",
758
691
  "\u30D6\u30FC\u30EB": "bool",
759
692
  "\u65E5\u6642": "datetime",
693
+ // ja 旧值兼容
694
+ "\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u914D\u5217": "array_row",
695
+ "\u914D\u5217": "array_string",
760
696
  // ko alias
761
697
  "\uD14D\uC2A4\uD2B8": "string",
762
698
  "\uBB38\uC790\uC5F4": "string",
@@ -764,7 +700,11 @@ var ALIASES = {
764
700
  "\uBD80\uC6B8": "bool",
765
701
  "\uB0A0\uC9DC\uC2DC\uAC04": "datetime",
766
702
  "\uAC1D\uCCB4 \uBC30\uC5F4": "array_row",
767
- "\uB9AC\uC2A4\uD2B8": "array_string"
703
+ "\uB9AC\uC2A4\uD2B8": "array_string",
704
+ // ko 旧值兼容
705
+ "time": "datetime",
706
+ "object_array": "array_row",
707
+ "string_array": "array_string"
768
708
  };
769
709
  Object.assign(ALL_DISPLAY_TO_TYPE, ALIASES);
770
710
  function displayToType(raw) {
@@ -844,6 +784,193 @@ function t(key, params, locale) {
844
784
  return node;
845
785
  }
846
786
 
787
+ // src/tracking/xlsx/tag-priority.ts
788
+ var TAG_PRIORITY = {
789
+ // Account lifecycle
790
+ "Basic": 1,
791
+ // Core gameplay
792
+ "Battle": 10,
793
+ "Stage": 11,
794
+ "Dungeon": 12,
795
+ "Gacha": 13,
796
+ // Progression & economy
797
+ "Growth": 20,
798
+ "Resource": 21,
799
+ // Monetization
800
+ "Ads": 30,
801
+ "Payment": 31,
802
+ "Subscription": 32,
803
+ // Supporting systems
804
+ "Shop": 40,
805
+ "Quest": 41,
806
+ "Achievement": 42,
807
+ "Check-in": 43,
808
+ "Leaderboard": 44,
809
+ "Guild": 45,
810
+ "Social": 46,
811
+ // Genre-specific (game)
812
+ "Building": 50,
813
+ "Alliance": 51,
814
+ "Equipment": 52,
815
+ "Trade": 53,
816
+ "Revive": 54,
817
+ "Slots": 55,
818
+ "Lottery": 56,
819
+ "Reward": 57,
820
+ // Non-game
821
+ "Discovery": 60,
822
+ "Product": 61,
823
+ "Order": 62,
824
+ "After-sales": 63,
825
+ "Content": 64,
826
+ "Interaction": 65,
827
+ "Relationship": 66,
828
+ "Live": 67,
829
+ "Onboarding": 68,
830
+ "Course": 69,
831
+ "Enrollment": 70,
832
+ "Quiz": 71,
833
+ "Creation": 72,
834
+ "Material": 73,
835
+ "Export": 74,
836
+ "Playback": 75,
837
+ "Withdraw": 76
838
+ };
839
+ var DEFAULT_TAG_PRIORITY = 80;
840
+ var CANONICAL_TAG = {
841
+ // zh
842
+ "\u57FA\u7840\u4E8B\u4EF6": "Basic",
843
+ "\u6218\u6597": "Battle",
844
+ "\u5173\u5361": "Stage",
845
+ "\u526F\u672C": "Dungeon",
846
+ "\u62BD\u5361": "Gacha",
847
+ "\u517B\u6210": "Growth",
848
+ "\u6210\u957F": "Growth",
849
+ "\u8D44\u6E90": "Resource",
850
+ "\u5E7F\u544A": "Ads",
851
+ "\u652F\u4ED8": "Payment",
852
+ "\u8BA2\u9605": "Subscription",
853
+ "\u5546\u57CE": "Shop",
854
+ "\u4EFB\u52A1": "Quest",
855
+ "\u6210\u5C31": "Achievement",
856
+ "\u7B7E\u5230": "Check-in",
857
+ "\u6392\u884C\u699C": "Leaderboard",
858
+ "\u516C\u4F1A": "Guild",
859
+ "\u793E\u4EA4": "Social",
860
+ "\u5EFA\u7B51": "Building",
861
+ "\u8054\u76DF": "Alliance",
862
+ "\u88C5\u5907": "Equipment",
863
+ "\u4EA4\u6613": "Trade",
864
+ "\u590D\u6D3B": "Revive",
865
+ "\u62BD\u5956": "Lottery",
866
+ "\u5956\u52B1": "Reward",
867
+ "\u63D0\u73B0": "Withdraw",
868
+ "\u53D1\u73B0": "Discovery",
869
+ "\u5546\u54C1": "Product",
870
+ "\u8BA2\u5355": "Order",
871
+ "\u552E\u540E": "After-sales",
872
+ "\u5185\u5BB9": "Content",
873
+ "\u4E92\u52A8": "Interaction",
874
+ "\u5173\u7CFB": "Relationship",
875
+ "\u76F4\u64AD": "Live",
876
+ "\u5F15\u5BFC": "Onboarding",
877
+ "\u8BFE\u7A0B": "Course",
878
+ "\u62A5\u540D": "Enrollment",
879
+ "\u6D4B\u9A8C": "Quiz",
880
+ "\u521B\u4F5C": "Creation",
881
+ "\u7D20\u6750": "Material",
882
+ "\u5BFC\u51FA": "Export",
883
+ "\u5185\u5BB9\u64AD\u653E": "Playback",
884
+ // ja
885
+ "\u57FA\u672C\u30A4\u30D9\u30F3\u30C8": "Basic",
886
+ "\u6226\u95D8": "Battle",
887
+ "\u30B9\u30C6\u30FC\u30B8": "Stage",
888
+ "\u30C0\u30F3\u30B8\u30E7\u30F3": "Dungeon",
889
+ "\u30AC\u30C1\u30E3": "Gacha",
890
+ "\u80B2\u6210": "Growth",
891
+ "\u30EA\u30BD\u30FC\u30B9": "Resource",
892
+ "\u5E83\u544A": "Ads",
893
+ "\u652F\u6255\u3044": "Payment",
894
+ "\u30B5\u30D6\u30B9\u30AF\u30EA\u30D7\u30B7\u30E7\u30F3": "Subscription",
895
+ "\u30B7\u30E7\u30C3\u30D7": "Shop",
896
+ "\u30AF\u30A8\u30B9\u30C8": "Quest",
897
+ "\u5B9F\u7E3E": "Achievement",
898
+ "\u30C1\u30A7\u30C3\u30AF\u30A4\u30F3": "Check-in",
899
+ "\u30E9\u30F3\u30AD\u30F3\u30B0": "Leaderboard",
900
+ "\u30AE\u30EB\u30C9": "Guild",
901
+ "\u30BD\u30FC\u30B7\u30E3\u30EB": "Social",
902
+ "\u5EFA\u7BC9": "Building",
903
+ "\u540C\u76DF": "Alliance",
904
+ "\u88C5\u5099": "Equipment",
905
+ "\u30C8\u30EC\u30FC\u30C9": "Trade",
906
+ "\u5FA9\u6D3B": "Revive",
907
+ "\u30B9\u30ED\u30C3\u30C8": "Slots",
908
+ "\u62BD\u9078": "Lottery",
909
+ "\u5831\u916C": "Reward",
910
+ "\u5F15\u304D\u51FA\u3057": "Withdraw",
911
+ "\u767A\u898B": "Discovery",
912
+ "\u6CE8\u6587": "Order",
913
+ "\u30A2\u30D5\u30BF\u30FC\u30B5\u30FC\u30D3\u30B9": "After-sales",
914
+ "\u30B3\u30F3\u30C6\u30F3\u30C4": "Content",
915
+ "\u30A4\u30F3\u30BF\u30E9\u30AF\u30B7\u30E7\u30F3": "Interaction",
916
+ "\u95A2\u4FC2": "Relationship",
917
+ "\u30E9\u30A4\u30D6": "Live",
918
+ "\u30AA\u30F3\u30DC\u30FC\u30C7\u30A3\u30F3\u30B0": "Onboarding",
919
+ "\u30B3\u30FC\u30B9": "Course",
920
+ "\u7533\u3057\u8FBC\u307F": "Enrollment",
921
+ "\u30AF\u30A4\u30BA": "Quiz",
922
+ "\u5275\u4F5C": "Creation",
923
+ "\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8": "Export",
924
+ "\u518D\u751F": "Playback",
925
+ // ko
926
+ "\uAE30\uBCF8 \uC774\uBCA4\uD2B8": "Basic",
927
+ "\uC804\uD22C": "Battle",
928
+ "\uC2A4\uD14C\uC774\uC9C0": "Stage",
929
+ "\uB358\uC804": "Dungeon",
930
+ "\uAC00\uCC60": "Gacha",
931
+ "\uC721\uC131": "Growth",
932
+ "\uB9AC\uC18C\uC2A4": "Resource",
933
+ "\uAD11\uACE0": "Ads",
934
+ "\uACB0\uC81C": "Payment",
935
+ "\uAD6C\uB3C5": "Subscription",
936
+ "\uC0C1\uC810": "Shop",
937
+ "\uD018\uC2A4\uD2B8": "Quest",
938
+ "\uC5C5\uC801": "Achievement",
939
+ "\uCD9C\uC11D\uCCB4\uD06C": "Check-in",
940
+ "\uB9AC\uB354\uBCF4\uB4DC": "Leaderboard",
941
+ "\uAE38\uB4DC": "Guild",
942
+ "\uC18C\uC15C": "Social",
943
+ "\uAC74\uC124": "Building",
944
+ "\uC5F0\uB9F9": "Alliance",
945
+ "\uC7A5\uBE44": "Equipment",
946
+ "\uAC70\uB798": "Trade",
947
+ "\uBD80\uD65C": "Revive",
948
+ "\uC2AC\uB86F": "Slots",
949
+ "\uCD94\uCCA8": "Lottery",
950
+ "\uBCF4\uC0C1": "Reward",
951
+ "\uCD9C\uAE08": "Withdraw",
952
+ "\uBC1C\uACAC": "Discovery",
953
+ "\uC0C1\uD488": "Product",
954
+ "\uC8FC\uBB38": "Order",
955
+ "A/S": "After-sales",
956
+ "\uCF58\uD150\uCE20": "Content",
957
+ "\uC778\uD130\uB799\uC158": "Interaction",
958
+ "\uAD00\uACC4": "Relationship",
959
+ "\uB77C\uC774\uBE0C": "Live",
960
+ "\uC628\uBCF4\uB529": "Onboarding",
961
+ "\uCF54\uC2A4": "Course",
962
+ "\uC2E0\uCCAD": "Enrollment",
963
+ "\uD034\uC988": "Quiz",
964
+ "\uCC3D\uC791": "Creation",
965
+ "\uC18C\uC7AC": "Material",
966
+ "\uB0B4\uBCF4\uB0B4\uAE30": "Export",
967
+ "\uC7AC\uC0DD": "Playback"
968
+ };
969
+ function getTagPriority(tag) {
970
+ const canonical = CANONICAL_TAG[tag] ?? tag;
971
+ return TAG_PRIORITY[canonical] ?? DEFAULT_TAG_PRIORITY;
972
+ }
973
+
847
974
  // src/tracking/xlsx/write.ts
848
975
  var PLATFORM_TO_XLSX = {
849
976
  "client": "client",
@@ -854,6 +981,49 @@ var VALID_PROP_TYPES = /* @__PURE__ */ new Set(["string", "number", "bool", "dat
854
981
  var VALID_UPDATE_TYPES = /* @__PURE__ */ new Set(["user_set", "user_setOnce", "user_add"]);
855
982
  var SNAKE_CASE_RE = /^[a-z][a-z0-9_]*$/;
856
983
  var PROP_NAME_RE = /^[a-zA-Z#][a-zA-Z0-9_.]*$/;
984
+ var MIN_COL_WIDTH = 10;
985
+ var PADDING = 3;
986
+ function isWideChar(code) {
987
+ return code >= 19968 && code <= 40959 || // CJK Unified Ideographs
988
+ code >= 13312 && code <= 19903 || // CJK Ext-A
989
+ code >= 12352 && code <= 12447 || // Hiragana
990
+ code >= 12448 && code <= 12543 || // Katakana
991
+ code >= 44032 && code <= 55215 || // Hangul
992
+ code >= 65280 && code <= 65519;
993
+ }
994
+ function displayWidth(s) {
995
+ let w = 0;
996
+ for (const ch of s) {
997
+ w += isWideChar(ch.charCodeAt(0)) ? 2 : 1;
998
+ }
999
+ return w;
1000
+ }
1001
+ function autoFitSheet(ws, maxWidth = 55) {
1002
+ const colCount = ws.columnCount;
1003
+ if (colCount === 0) return;
1004
+ for (let i = 1; i <= colCount; i++) {
1005
+ const col = ws.getColumn(i);
1006
+ let maxDisplay = 0;
1007
+ let needsWrap = false;
1008
+ col.eachCell({ includeEmpty: false }, (cell) => {
1009
+ const text = String(cell.value ?? "");
1010
+ if (!text) return;
1011
+ const dw = displayWidth(text);
1012
+ if (dw > maxDisplay) maxDisplay = dw;
1013
+ });
1014
+ if (maxDisplay === 0) {
1015
+ col.width = MIN_COL_WIDTH;
1016
+ continue;
1017
+ }
1018
+ const capped = maxDisplay + PADDING > maxWidth;
1019
+ col.width = Math.max(MIN_COL_WIDTH, Math.min(maxWidth, maxDisplay + PADDING));
1020
+ if (capped) {
1021
+ col.eachCell({ includeEmpty: false }, (cell) => {
1022
+ cell.alignment = { ...cell.alignment, wrapText: true };
1023
+ });
1024
+ }
1025
+ }
1026
+ }
857
1027
  function validateDraft(d) {
858
1028
  const errors = [];
859
1029
  const eventNames = /* @__PURE__ */ new Set();
@@ -1027,7 +1197,26 @@ async function writeDraftXlsx(d, outPath, locale = "zh") {
1027
1197
  headerName("prop_desc", locale)
1028
1198
  ]);
1029
1199
  const propByName = new Map(d.event_properties.map((p) => [p.name, p]));
1030
- for (const evt of d.events) {
1200
+ const autotrackEvents = d.events.filter((e) => e.source === "autotrack");
1201
+ const businessEvents = d.events.filter((e) => e.source !== "autotrack");
1202
+ const tagGroups = /* @__PURE__ */ new Map();
1203
+ const tagOrder = [];
1204
+ for (const evt of businessEvents) {
1205
+ const tag = evt.event_tag || "";
1206
+ if (!tagGroups.has(tag)) {
1207
+ tagGroups.set(tag, []);
1208
+ tagOrder.push(tag);
1209
+ }
1210
+ tagGroups.get(tag).push(evt);
1211
+ }
1212
+ tagOrder.sort((a, b) => getTagPriority(a) - getTagPriority(b));
1213
+ const sorted = [...autotrackEvents];
1214
+ for (const tag of tagOrder) {
1215
+ for (const evt of tagGroups.get(tag)) {
1216
+ sorted.push(evt);
1217
+ }
1218
+ }
1219
+ for (const evt of sorted) {
1031
1220
  const startRow = eventSheet.rowCount + 1;
1032
1221
  const platformStr = evt.platform ? PLATFORM_TO_XLSX[evt.platform] : "";
1033
1222
  if (evt.prop_names.length === 0) {
@@ -1062,9 +1251,17 @@ async function writeDraftXlsx(d, outPath, locale = "zh") {
1062
1251
  for (const col of ["A", "B", "C", "D", "E"]) {
1063
1252
  eventSheet.mergeCells(`${col}${startRow}:${col}${endRow}`);
1064
1253
  }
1254
+ for (let r = startRow; r <= endRow; r++) {
1255
+ const row = eventSheet.getRow(r);
1256
+ for (const col of ["A", "B", "C", "D", "E"]) {
1257
+ const cell = row.getCell(col);
1258
+ cell.alignment = { ...cell.alignment, vertical: "middle" };
1259
+ }
1260
+ }
1065
1261
  }
1066
1262
  }
1067
1263
  }
1264
+ autoFitSheet(eventSheet, 50);
1068
1265
  const commonSheet = workbook.addWorksheet(sheetName("common_props", locale));
1069
1266
  commonSheet.addRow([
1070
1267
  headerName("common_prop_name", locale),
@@ -1080,6 +1277,7 @@ async function writeDraftXlsx(d, outPath, locale = "zh") {
1080
1277
  prop.desc ?? ""
1081
1278
  ]);
1082
1279
  }
1280
+ autoFitSheet(commonSheet, 50);
1083
1281
  const userSheet = workbook.addWorksheet(sheetName("user_data", locale));
1084
1282
  userSheet.addRow([
1085
1283
  headerName("user_prop_name", locale),
@@ -1100,6 +1298,7 @@ async function writeDraftXlsx(d, outPath, locale = "zh") {
1100
1298
  prop.prop_tag ?? ""
1101
1299
  ]);
1102
1300
  }
1301
+ autoFitSheet(userSheet, 50);
1103
1302
  const userIdSheet = workbook.addWorksheet(sheetName("user_id", locale));
1104
1303
  userIdSheet.addRow([
1105
1304
  headerName("user_id_prop_name", locale),
@@ -1109,13 +1308,14 @@ async function writeDraftXlsx(d, outPath, locale = "zh") {
1109
1308
  ]);
1110
1309
  userIdSheet.addRow(["#account_id", t("user_id.account_id_display", {}, locale), t("user_id.system_property", {}, locale), t("user_id.set_to", { field: d.meta.user_identity?.account_id_field ?? "account ID" }, locale)]);
1111
1310
  userIdSheet.addRow(["#distinct_id", t("user_id.distinct_id_display", {}, locale), t("user_id.system_property", {}, locale), t("user_id.auto_generated", {}, locale)]);
1311
+ autoFitSheet(userIdSheet, 50);
1112
1312
  await workbook.xlsx.writeFile(outPath);
1113
1313
  }
1114
1314
 
1115
1315
  // src/core/tracking-client.ts
1116
1316
  var DEBUG_BASE = "/v1/ta/bury/manage/debug";
1117
1317
  var TRACK_LOCAL_HOST = "http://localhost:8992";
1118
- var TRACK_CAPABILITY_DOMAIN = "";
1318
+ var TRACK_CAPABILITY_DOMAIN = "analysis";
1119
1319
  var TRACK_PROGRAM_QUERY = "track.program.query";
1120
1320
  var TRACK_PROGRAM_DELETE = "track.program.delete";
1121
1321
  var TRACK_PROGRAM_EXCEL_SAVE = "track.program.excel_save";
@@ -1307,8 +1507,8 @@ var TrackingClient = class {
1307
1507
  }
1308
1508
  return env;
1309
1509
  }
1310
- async debugGet(path5, params) {
1311
- const data = await this.requestJson(`${DEBUG_BASE}${path5}`, { ...params, "@t": Date.now() });
1510
+ async debugGet(path4, params) {
1511
+ const data = await this.requestJson(`${DEBUG_BASE}${path4}`, { ...params, "@t": Date.now() });
1312
1512
  return data;
1313
1513
  }
1314
1514
  async listDevice(projectId) {
@@ -1334,7 +1534,7 @@ var TrackingClient = class {
1334
1534
  }
1335
1535
  };
1336
1536
  async function createTrackingClient(host) {
1337
- return new TrackingClient(TRACK_LOCAL_HOST);
1537
+ return new TrackingClient(host || TRACK_LOCAL_HOST);
1338
1538
  }
1339
1539
 
1340
1540
  // src/tracking/te-plan/fetch.ts
@@ -1384,8 +1584,8 @@ function normalize2(data) {
1384
1584
  }
1385
1585
 
1386
1586
  // src/tracking/plan/draft.ts
1387
- import fs2 from "fs";
1388
- import path2 from "path";
1587
+ import fs from "fs";
1588
+ import path from "path";
1389
1589
 
1390
1590
  // src/tracking/plan/autotrack.ts
1391
1591
  var TAG = {
@@ -1713,6 +1913,43 @@ function fixDisplayNameDuplicates(draft) {
1713
1913
  }
1714
1914
  return fixed;
1715
1915
  }
1916
+ function fixCrossPoolDisplayNameInconsistency(draft) {
1917
+ const fixed = [];
1918
+ const commonProps = draft.common_event_properties ?? [];
1919
+ const eventProps = draft.event_properties ?? [];
1920
+ for (const cp2 of commonProps) {
1921
+ if (!cp2.display_name) continue;
1922
+ const ep = eventProps.find((p) => p.name === cp2.name);
1923
+ if (!ep) continue;
1924
+ if (ep.display_name && ep.display_name !== cp2.display_name) {
1925
+ const oldName = ep.display_name;
1926
+ ep.display_name = cp2.display_name;
1927
+ fixed.push(
1928
+ `Aligned display_name for "${cp2.name}" in event_properties: "${oldName}" \u2192 "${cp2.display_name}" (from common_event_properties)`
1929
+ );
1930
+ }
1931
+ }
1932
+ return fixed;
1933
+ }
1934
+ function fixEventPlatforms(draft) {
1935
+ const fixed = [];
1936
+ const mode = draft.meta.sdk_integration_mode;
1937
+ if (mode !== "client_only" && mode !== "server_only") return fixed;
1938
+ const targetPlatform = mode === "client_only" ? "client" : "server";
1939
+ let count = 0;
1940
+ for (const event of draft.events) {
1941
+ if (!event.platform) {
1942
+ event.platform = targetPlatform;
1943
+ count++;
1944
+ }
1945
+ }
1946
+ if (count > 0) {
1947
+ fixed.push(
1948
+ `Auto-filled platform="${targetPlatform}" for ${count} event(s) based on sdk_integration_mode="${mode}"`
1949
+ );
1950
+ }
1951
+ return fixed;
1952
+ }
1716
1953
  function fixEventPropNameInvalid(draft, errors) {
1717
1954
  const invalidNames = /* @__PURE__ */ new Set();
1718
1955
  for (const error of errors) {
@@ -1790,6 +2027,14 @@ function validateAndFix(draft) {
1790
2027
  if (displayFixes.length > 0) {
1791
2028
  fixed.push(t("fix.display_name_dedup"));
1792
2029
  }
2030
+ const crossPoolFixes = fixCrossPoolDisplayNameInconsistency(draft);
2031
+ if (crossPoolFixes.length > 0) {
2032
+ fixed.push(`Cross-pool display_name consistency: ${crossPoolFixes.length} property(s) aligned`);
2033
+ }
2034
+ const platformFixes = fixEventPlatforms(draft);
2035
+ if (platformFixes.length > 0) {
2036
+ fixed.push(...platformFixes);
2037
+ }
1793
2038
  const compositeChildren = /* @__PURE__ */ new Map();
1794
2039
  const evProps = draft.event_properties ?? draft.common_properties ?? [];
1795
2040
  for (const prop of evProps) {
@@ -1947,10 +2192,13 @@ async function listTrackingTemplates() {
1947
2192
  for (const f of entries) {
1948
2193
  if (!f.endsWith(".xlsx")) continue;
1949
2194
  const base = f.replace(/\.xlsx$/i, "");
2195
+ const xlsxPath = resolve(dir, f);
1950
2196
  const mdPath = resolve(dir, base + ".md");
1951
2197
  const hasMd = existsSync3(mdPath);
1952
2198
  found.push({
1953
- path: hasMd ? mdPath : resolve(dir, f),
2199
+ path: hasMd ? mdPath : xlsxPath,
2200
+ xlsxPath,
2201
+ ...hasMd ? { mdPath } : {},
1954
2202
  name: base,
1955
2203
  hasMd
1956
2204
  });
@@ -1984,23 +2232,23 @@ function resolveTrackingHost(program2, opts) {
1984
2232
  }
1985
2233
  return host;
1986
2234
  }
1987
- function isExistingDirectory(path5) {
1988
- if (!existsSync4(path5)) return false;
2235
+ function isExistingDirectory(path4) {
2236
+ if (!existsSync4(path4)) return false;
1989
2237
  try {
1990
- return statSync(path5).isDirectory();
2238
+ return statSync(path4).isDirectory();
1991
2239
  } catch {
1992
2240
  return false;
1993
2241
  }
1994
2242
  }
1995
- function assertOutputFilePath(path5, optionName = "--out") {
1996
- const trimmed = path5.trim();
2243
+ function assertOutputFilePath(path4, optionName = "--out") {
2244
+ const trimmed = path4.trim();
1997
2245
  if (trimmed.endsWith("/") || trimmed.endsWith("\\") || isExistingDirectory(trimmed)) {
1998
2246
  console.error(t("error.output_path_is_directory", { path: trimmed, option: optionName }));
1999
2247
  process.exit(1);
2000
2248
  }
2001
2249
  }
2002
- function assertInputFilePath(path5, optionName = "--in") {
2003
- const trimmed = path5.trim();
2250
+ function assertInputFilePath(path4, optionName = "--in") {
2251
+ const trimmed = path4.trim();
2004
2252
  if (!existsSync4(trimmed)) {
2005
2253
  console.error(t("error.input_path_not_found", { path: trimmed, option: optionName }));
2006
2254
  process.exit(1);
@@ -2070,7 +2318,7 @@ function registerPlan(cmd, rootProgram) {
2070
2318
  console.log(t("plan.validate_passed"));
2071
2319
  } catch (e) {
2072
2320
  const errorMsg = e instanceof Error ? e.message : String(e);
2073
- console.log(t("plan.validate_failed") + "\n" + errorMsg);
2321
+ console.error(t("plan.validate_failed") + "\n" + errorMsg);
2074
2322
  if (opts.fix) {
2075
2323
  console.log("\n" + t("plan.attempting_auto_fix") + "...");
2076
2324
  const fixed = validateAndFix(draft);
@@ -2082,11 +2330,15 @@ function registerPlan(cmd, rootProgram) {
2082
2330
  validateDraft(draft);
2083
2331
  console.log(t("plan.validate_passed_after_fix"));
2084
2332
  } catch (e2) {
2085
- console.log(t("plan.validate_still_errors_after_fix", { error: e2 instanceof Error ? e2.message : String(e2) }));
2333
+ console.error(t("plan.validate_still_errors_after_fix", { error: e2 instanceof Error ? e2.message : String(e2) }));
2334
+ process.exitCode = 1;
2086
2335
  }
2087
2336
  } else {
2088
2337
  console.log(t("plan.no_auto_fix_available"));
2338
+ process.exitCode = 1;
2089
2339
  }
2340
+ } else {
2341
+ process.exitCode = 1;
2090
2342
  }
2091
2343
  }
2092
2344
  });
@@ -2147,7 +2399,7 @@ function registerPlan(cmd, rootProgram) {
2147
2399
  lastRes = await client.uploadProgramExcel({
2148
2400
  projectId: opts.project,
2149
2401
  file,
2150
- filename: path3.basename(opts.xlsx),
2402
+ filename: path2.basename(opts.xlsx),
2151
2403
  lang: locale
2152
2404
  });
2153
2405
  console.log(JSON.stringify(lastRes, null, 2));
@@ -2352,7 +2604,7 @@ async function detectProject(cwd) {
2352
2604
 
2353
2605
  // src/tracking/xlsx/read.ts
2354
2606
  import XLSXMod from "xlsx";
2355
- import path4 from "path";
2607
+ import path3 from "path";
2356
2608
  var XLSX = XLSXMod.default ?? XLSXMod;
2357
2609
  var VALID_PROP_TYPES2 = /* @__PURE__ */ new Set(["string", "number", "bool", "datetime", "object", "array_row", "array_string"]);
2358
2610
  var VALID_UPDATE_TYPES2 = /* @__PURE__ */ new Set(["user_set", "user_setOnce", "user_add"]);
@@ -2639,6 +2891,22 @@ function parseUserDataSheet(rows, source, sheetName2) {
2639
2891
  }
2640
2892
  return props;
2641
2893
  }
2894
+ function fillDownMergedCells(rows, merges) {
2895
+ for (const merge of merges) {
2896
+ const { s, e } = merge;
2897
+ const topLeftValue = rows[s.r]?.[s.c];
2898
+ if (topLeftValue === null || topLeftValue === void 0) continue;
2899
+ for (let r = s.r; r <= e.r; r++) {
2900
+ if (!rows[r]) continue;
2901
+ for (let c = s.c; c <= e.c; c++) {
2902
+ if (r === s.r && c === s.c) continue;
2903
+ if (rows[r][c] === null || rows[r][c] === void 0) {
2904
+ rows[r][c] = topLeftValue;
2905
+ }
2906
+ }
2907
+ }
2908
+ }
2909
+ }
2642
2910
  async function readTemplateXlsx(filePath) {
2643
2911
  let wb;
2644
2912
  try {
@@ -2646,7 +2914,7 @@ async function readTemplateXlsx(filePath) {
2646
2914
  } catch (err) {
2647
2915
  throw new Error(t("error.xlsx_read_failed", { path: filePath, error: String(err) }));
2648
2916
  }
2649
- const planName = path4.basename(filePath, path4.extname(filePath));
2917
+ const planName = path3.basename(filePath, path3.extname(filePath));
2650
2918
  const source = "template";
2651
2919
  let events = [];
2652
2920
  let event_properties = [];
@@ -2661,6 +2929,10 @@ async function readTemplateXlsx(filePath) {
2661
2929
  raw: false,
2662
2930
  defval: null
2663
2931
  });
2932
+ const merges = ws["!merges"];
2933
+ if (merges && merges.length > 0) {
2934
+ fillDownMergedCells(rows, merges);
2935
+ }
2664
2936
  if (allSheetNames("event_data").includes(sName)) {
2665
2937
  const result = parseEventSheet(rows, source, sName);
2666
2938
  events = result.events;
@@ -2942,6 +3214,9 @@ function registerCode(cmd) {
2942
3214
  const templatePath = opts.templateName ? (await resolveTrackingTemplateByName(opts.templateName)).path : opts.template;
2943
3215
  assertInputFilePath(templatePath, opts.templateName ? "--template-name" : "--template");
2944
3216
  const draft = templatePath.endsWith(".md") ? await readTemplateMd(templatePath) : await readTemplateXlsx(templatePath);
3217
+ if (!templatePath.endsWith(".md") && draft.events.length === 0) {
3218
+ process.stderr.write(t("code.xlsx_import_empty_warning", { path: templatePath }) + "\n");
3219
+ }
2945
3220
  const inferredMode = inferSdkMode(draft.events);
2946
3221
  if (inferredMode) {
2947
3222
  draft.meta.sdk_integration_mode = inferredMode;
@@ -3069,11 +3344,19 @@ function registerLang(cmd, _rootProgram) {
3069
3344
 
3070
3345
  // src/commands/tracking/index.ts
3071
3346
  function registerTracking(program2) {
3072
- const tracking = program2.command("tracking").description("AE tracking plan lifecycle (xlsx, debug, wiki)");
3073
- registerPlan(tracking.command("plan"), program2);
3074
- registerCode(tracking.command("code"));
3075
- registerWiki(tracking.command("wiki"));
3076
- registerLang(tracking.command("lang"), program2);
3347
+ const tracking = getOrCreateCommand(program2, "tracking", "AE tracking plan lifecycle (xlsx, debug, wiki)");
3348
+ registerPlan(getOrCreateCommand(tracking, "plan", "manage AE tracking plans"), program2);
3349
+ registerCode(getOrCreateCommand(tracking, "code", "tracking code commands"));
3350
+ registerWiki(getOrCreateCommand(tracking, "wiki", "tracking wiki commands"));
3351
+ registerLang(getOrCreateCommand(tracking, "lang", "tracking language commands"), program2);
3352
+ }
3353
+ function getOrCreateCommand(parent, name, description) {
3354
+ const existing = parent.commands.find((command) => command.name() === name);
3355
+ if (existing) {
3356
+ existing.description(description);
3357
+ return existing;
3358
+ }
3359
+ return parent.command(name).description(description);
3077
3360
  }
3078
3361
 
3079
3362
  // src/index.ts
@@ -3093,57 +3376,57 @@ program.name("ae-cli").version(version).description("CLI tool for ThinkingAI (AE
3093
3376
  async function loadCommands() {
3094
3377
  const commands = [];
3095
3378
  try {
3096
- const teAnalysis = await import("./te-analysis-PUVF5IF4.js");
3379
+ const teAnalysis = await import("./te-analysis-Q7AZCDU4.js");
3097
3380
  commands.push(...teAnalysis.default);
3098
3381
  } catch {
3099
3382
  }
3100
3383
  try {
3101
- const teMeta = await import("./te-meta-UUROEODR.js");
3384
+ const teMeta = await import("./te-meta-VHCN4Q62.js");
3102
3385
  commands.push(...teMeta.default);
3103
3386
  } catch {
3104
3387
  }
3105
3388
  try {
3106
- const teCommon = await import("./te-common-VUX3VOXZ.js");
3389
+ const teCommon = await import("./te-common-ST3QPSXJ.js");
3107
3390
  commands.push(...teCommon.default);
3108
3391
  } catch {
3109
3392
  }
3110
3393
  try {
3111
- const engage = await import("./te-engage-QBCCME22.js");
3394
+ const engage = await import("./te-engage-JIXX3WBI.js");
3112
3395
  commands.push(...engage.default);
3113
3396
  } catch {
3114
3397
  }
3115
3398
  try {
3116
- const experiment = await import("./te-experiment-NWNQHJS5.js");
3399
+ const experiment = await import("./te-experiment-JKX4FH6D.js");
3117
3400
  commands.push(...experiment.default);
3118
3401
  } catch {
3119
3402
  }
3120
3403
  try {
3121
- const community = await import("./te-community-TSKJ652U.js");
3404
+ const community = await import("./te-community-X2AHXGCA.js");
3122
3405
  commands.push(...community.default);
3123
3406
  } catch {
3124
3407
  }
3125
3408
  try {
3126
- const dataops = await import("./te-dataops-F36T656A.js");
3409
+ const dataops = await import("./te-dataops-OA7I6HBG.js");
3127
3410
  commands.push(...dataops.default);
3128
3411
  } catch {
3129
3412
  }
3130
3413
  try {
3131
- const teKb = await import("./te-kb-AYCODNU6.js");
3414
+ const teKb = await import("./te-kb-CIZXRWMO.js");
3132
3415
  commands.push(...teKb.default);
3133
3416
  } catch {
3134
3417
  }
3135
3418
  try {
3136
- const teTeam = await import("./te-team-OKCOX7OE.js");
3419
+ const teTeam = await import("./te-team-PDKKW7Q5.js");
3137
3420
  commands.push(...teTeam.default);
3138
3421
  } catch {
3139
3422
  }
3140
3423
  try {
3141
- const teAgent = await import("./te-agent-FCCWUDTJ.js");
3424
+ const teAgent = await import("./te-agent-K2OWMZXT.js");
3142
3425
  commands.push(...teAgent.default);
3143
3426
  } catch {
3144
3427
  }
3145
3428
  try {
3146
- const metadata = await import("./metadata-FCLDBXX2.js");
3429
+ const metadata = await import("./metadata-3M5F2AED.js");
3147
3430
  commands.push(...metadata.default);
3148
3431
  } catch {
3149
3432
  }
@@ -3151,48 +3434,50 @@ async function loadCommands() {
3151
3434
  }
3152
3435
  async function registerAuthCommands() {
3153
3436
  try {
3154
- const { registerAuth } = await import("./auth-7H3HAAJ3.js");
3437
+ const { registerAuth } = await import("./auth-UPGUOKTW.js");
3155
3438
  registerAuth(program);
3156
3439
  } catch {
3157
3440
  }
3158
3441
  }
3159
3442
  async function registerConfigCommands() {
3160
3443
  try {
3161
- const { registerConfig } = await import("./config-7UZWDE74.js");
3444
+ const { registerConfig } = await import("./config-RCCGHHYA.js");
3162
3445
  registerConfig(program);
3163
3446
  } catch {
3164
3447
  }
3165
3448
  }
3166
3449
  async function registerApiCommand() {
3167
3450
  try {
3168
- const { registerApi } = await import("./raw-CN542NGT.js");
3451
+ const { registerApi } = await import("./raw-TPB7KSZO.js");
3169
3452
  registerApi(program);
3170
3453
  } catch {
3171
3454
  }
3172
3455
  }
3173
3456
  async function registerCapabilityCommands() {
3174
3457
  try {
3175
- const { registerCapability } = await import("./capability-SCRFGODD.js");
3458
+ const { registerCapability } = await import("./capability-AJC5CBRT.js");
3176
3459
  registerCapability(program);
3177
3460
  } catch {
3178
3461
  }
3179
3462
  }
3180
3463
  async function registerSyncCommand() {
3181
3464
  try {
3182
- const { registerSync } = await import("./sync-ERNHDPB5.js");
3465
+ const { registerSync } = await import("./sync-EFJKFZK2.js");
3183
3466
  registerSync(program);
3184
3467
  } catch {
3185
3468
  }
3186
3469
  }
3187
3470
  async function registerModelCommand() {
3188
3471
  try {
3189
- const { registerModel } = await import("./model-T3KZJWLW.js");
3472
+ const { registerModel } = await import("./model-OYQLXCQY.js");
3190
3473
  registerModel(program);
3191
3474
  } catch {
3192
3475
  }
3193
3476
  }
3194
3477
  async function main() {
3478
+ const pkgInfo = getLocalCliPackageInfo();
3195
3479
  notifyIfUpdateAvailable({ name: pkg.name, version: pkg.version });
3480
+ await runHostCompatCheck(pkgInfo);
3196
3481
  const commands = await loadCommands();
3197
3482
  registerCommands(program, commands);
3198
3483
  await registerAuthCommands();