@hangox/pm-cli 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -495,49 +495,49 @@ function addKeyMappingToResult(result) {
495
495
  _key_mapping: mapping
496
496
  };
497
497
  }
498
- function outputToFile(data, filePath) {
498
+ function outputToFile(data, filePath, pretty = false) {
499
499
  const result = {
500
500
  success: true,
501
501
  data
502
502
  };
503
503
  const finalResult = addKeyMappingToResult(result);
504
- writeFileSync2(filePath, JSON.stringify(finalResult, null, 2), "utf-8");
504
+ writeFileSync2(filePath, JSON.stringify(finalResult, null, pretty ? 2 : 0), "utf-8");
505
505
  return filePath;
506
506
  }
507
507
  function smartOutput(data, options) {
508
508
  if (options.stdout) {
509
- outputSuccess(data);
509
+ outputSuccess(data, options.pretty);
510
510
  return void 0;
511
511
  }
512
512
  const filePath = options.output || generateOutputPath(options.command, options.identifier);
513
- outputToFile(data, filePath);
514
- console.log(JSON.stringify({ success: true, output: filePath }, null, 2));
513
+ outputToFile(data, filePath, options.pretty);
514
+ console.log(JSON.stringify({ success: true, output: filePath }, null, options.pretty ? 2 : 0));
515
515
  return filePath;
516
516
  }
517
- function outputSuccess(data) {
517
+ function outputSuccess(data, pretty = false) {
518
518
  const result = {
519
519
  success: true,
520
520
  data
521
521
  };
522
522
  const finalResult = addKeyMappingToResult(result);
523
- console.log(JSON.stringify(finalResult, null, 2));
523
+ console.log(JSON.stringify(finalResult, null, pretty ? 2 : 0));
524
524
  }
525
- function outputError(error) {
525
+ function outputError(error, pretty = false) {
526
526
  const result = {
527
527
  success: false,
528
528
  error
529
529
  };
530
530
  const finalResult = addKeyMappingToResult(result);
531
- console.log(JSON.stringify(finalResult, null, 2));
531
+ console.log(JSON.stringify(finalResult, null, pretty ? 2 : 0));
532
532
  }
533
533
 
534
534
  // src/commands/test.ts
535
535
  function createTestCommand() {
536
- const testCmd = new Command("test").description("\u6D4B\u8BD5\u7F51\u6613\u6613\u534F\u4F5C\u8FDE\u63A5").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (options) => {
536
+ const testCmd = new Command("test").description("\u6D4B\u8BD5\u7F51\u6613\u6613\u534F\u4F5C\u8FDE\u63A5").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (options) => {
537
537
  const creds = resolveCredentials(options);
538
538
  const validation = validateCredentials(creds);
539
539
  if (!validation.valid) {
540
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
540
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
541
541
  process.exit(1);
542
542
  }
543
543
  const result = await userService.testConnection(
@@ -551,9 +551,9 @@ function createTestCommand() {
551
551
  host: creds.host,
552
552
  project: creds.project,
553
553
  data: result.data
554
- });
554
+ }, options.pretty);
555
555
  } else {
556
- outputError(result.message || result.msg || result.api_error_msg || "\u8FDE\u63A5\u5931\u8D25");
556
+ outputError(result.message || result.msg || result.api_error_msg || "\u8FDE\u63A5\u5931\u8D25", options.pretty);
557
557
  process.exit(1);
558
558
  }
559
559
  });
@@ -564,40 +564,40 @@ function createTestCommand() {
564
564
  import { Command as Command2 } from "commander";
565
565
  function createConfigCommand() {
566
566
  const configCmd = new Command2("config").description("\u914D\u7F6E\u7BA1\u7406");
567
- configCmd.command("set <key> <value>").description("\u8BBE\u7F6E\u914D\u7F6E\u9879").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action((key, value, options) => {
567
+ configCmd.command("set <key> <value>").description("\u8BBE\u7F6E\u914D\u7F6E\u9879").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action((key, value, options) => {
568
568
  setConfigValue(key, value, options.config);
569
569
  outputSuccess({
570
570
  message: `\u914D\u7F6E\u9879 ${key} \u5DF2\u8BBE\u7F6E`,
571
571
  key,
572
572
  value,
573
573
  configPath: getConfigPath(options.config)
574
- });
574
+ }, options.pretty);
575
575
  });
576
- configCmd.command("get <key>").description("\u83B7\u53D6\u914D\u7F6E\u9879").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action((key, options) => {
576
+ configCmd.command("get <key>").description("\u83B7\u53D6\u914D\u7F6E\u9879").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action((key, options) => {
577
577
  const value = getConfigValue(key, options.config);
578
578
  if (value !== void 0) {
579
- outputSuccess({ key, value });
579
+ outputSuccess({ key, value }, options.pretty);
580
580
  } else {
581
- outputError(`\u914D\u7F6E\u9879 ${key} \u4E0D\u5B58\u5728`);
581
+ outputError(`\u914D\u7F6E\u9879 ${key} \u4E0D\u5B58\u5728`, options.pretty);
582
582
  process.exit(1);
583
583
  }
584
584
  });
585
- configCmd.command("list").description("\u5217\u51FA\u6240\u6709\u914D\u7F6E").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action((options) => {
585
+ configCmd.command("list").description("\u5217\u51FA\u6240\u6709\u914D\u7F6E").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action((options) => {
586
586
  const config = readConfig(options.config);
587
587
  outputSuccess({
588
588
  configPath: getConfigPath(options.config),
589
589
  config
590
- });
590
+ }, options.pretty);
591
591
  });
592
592
  const profileCmd = new Command2("profile").description("Profile \u7BA1\u7406");
593
- profileCmd.command("add <name>").description("\u6DFB\u52A0 profile").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--token <token>", "API Token").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(
593
+ profileCmd.command("add <name>").description("\u6DFB\u52A0 profile").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--token <token>", "API Token").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(
594
594
  (name, options) => {
595
595
  const profile = {};
596
596
  if (options.host) profile.host = options.host;
597
597
  if (options.project) profile.project = options.project;
598
598
  if (options.token) profile.token = options.token;
599
599
  if (Object.keys(profile).length === 0) {
600
- outputError("\u8BF7\u81F3\u5C11\u6307\u5B9A\u4E00\u4E2A\u914D\u7F6E\u9879 (--host, --project, --token)");
600
+ outputError("\u8BF7\u81F3\u5C11\u6307\u5B9A\u4E00\u4E2A\u914D\u7F6E\u9879 (--host, --project, --token)", options.pretty);
601
601
  process.exit(1);
602
602
  }
603
603
  setProfile(name, profile, options.config);
@@ -605,19 +605,19 @@ function createConfigCommand() {
605
605
  message: `Profile ${name} \u5DF2\u6DFB\u52A0`,
606
606
  name,
607
607
  profile
608
- });
608
+ }, options.pretty);
609
609
  }
610
610
  );
611
- profileCmd.command("remove <name>").description("\u5220\u9664 profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action((name, options) => {
611
+ profileCmd.command("remove <name>").description("\u5220\u9664 profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action((name, options) => {
612
612
  const removed = removeProfile(name, options.config);
613
613
  if (removed) {
614
- outputSuccess({ message: `Profile ${name} \u5DF2\u5220\u9664`, name });
614
+ outputSuccess({ message: `Profile ${name} \u5DF2\u5220\u9664`, name }, options.pretty);
615
615
  } else {
616
- outputError(`Profile ${name} \u4E0D\u5B58\u5728`);
616
+ outputError(`Profile ${name} \u4E0D\u5B58\u5728`, options.pretty);
617
617
  process.exit(1);
618
618
  }
619
619
  });
620
- profileCmd.command("list").description("\u5217\u51FA\u6240\u6709 profiles").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action((options) => {
620
+ profileCmd.command("list").description("\u5217\u51FA\u6240\u6709 profiles").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action((options) => {
621
621
  const profiles = listProfiles(options.config);
622
622
  const profileDetails = {};
623
623
  for (const name of profiles) {
@@ -626,7 +626,7 @@ function createConfigCommand() {
626
626
  outputSuccess({
627
627
  profiles: profileDetails,
628
628
  count: profiles.length
629
- });
629
+ }, options.pretty);
630
630
  });
631
631
  configCmd.addCommand(profileCmd);
632
632
  return configCmd;
@@ -636,6 +636,9 @@ function createConfigCommand() {
636
636
  import { Command as Command3 } from "commander";
637
637
 
638
638
  // src/services/issue-service.ts
639
+ function sleep(ms) {
640
+ return new Promise((resolve) => setTimeout(resolve, ms));
641
+ }
639
642
  var IssueService = class {
640
643
  /**
641
644
  * 获取问题详情
@@ -882,6 +885,241 @@ var IssueService = class {
882
885
  data: results
883
886
  };
884
887
  }
888
+ /**
889
+ * 同步子单:从源父单复制子单到目标父单
890
+ * @param sourceParentId 源父单 ID
891
+ * @param targetParentId 目标父单 ID
892
+ * @param assignedToMail 新子单的指派人邮箱
893
+ * @param options 选项
894
+ */
895
+ async syncChildIssues(token, host, project, sourceParentId, targetParentId, assignedToMail, options) {
896
+ const { dryRun = false, depth = 10, skipExisting = true } = options || {};
897
+ logger_default.info("\u5F00\u59CB\u540C\u6B65\u5B50\u5355", {
898
+ sourceParentId,
899
+ targetParentId,
900
+ assignedToMail,
901
+ dryRun,
902
+ depth,
903
+ skipExisting
904
+ });
905
+ const result = {
906
+ totalCreated: 0,
907
+ totalSkipped: 0,
908
+ totalFailed: 0,
909
+ created: [],
910
+ skipped: [],
911
+ failed: []
912
+ };
913
+ try {
914
+ logger_default.info("\u6B63\u5728\u83B7\u53D6\u6E90\u7236\u5355\u7684\u5B50\u5355\u6811\u5F62\u7ED3\u6784...");
915
+ const sourceResult = await this.getIssueWithChildren(token, host, project, sourceParentId, depth);
916
+ if (!sourceResult.success || !sourceResult.data) {
917
+ return {
918
+ success: false,
919
+ message: `\u83B7\u53D6\u6E90\u7236\u5355 #${sourceParentId} \u5931\u8D25: ${sourceResult.message || "\u672A\u77E5\u9519\u8BEF"}`
920
+ };
921
+ }
922
+ const sourceIssue = sourceResult.data;
923
+ logger_default.info("\u6B63\u5728\u83B7\u53D6\u76EE\u6807\u7236\u5355\u4FE1\u606F...");
924
+ const targetResult = await this.getIssue(token, host, project, targetParentId, false, false);
925
+ if (!targetResult.success || !targetResult.data) {
926
+ return {
927
+ success: false,
928
+ message: `\u83B7\u53D6\u76EE\u6807\u7236\u5355 #${targetParentId} \u5931\u8D25: ${targetResult.message || "\u672A\u77E5\u9519\u8BEF"}`
929
+ };
930
+ }
931
+ const targetParentInfo = targetResult.data;
932
+ let existingTaskNames = /* @__PURE__ */ new Set();
933
+ if (skipExisting) {
934
+ logger_default.info("\u6B63\u5728\u83B7\u53D6\u76EE\u6807\u7236\u5355\u5DF2\u6709\u7684\u5B50\u5355...");
935
+ const existingResult = await this.getIssueWithChildren(token, host, project, targetParentId, depth);
936
+ if (existingResult.success && existingResult.data) {
937
+ existingTaskNames = this.collectAllTaskNames(existingResult.data);
938
+ logger_default.info(`\u76EE\u6807\u7236\u5355\u5DF2\u6709 ${existingTaskNames.size} \u4E2A\u5B50\u5355`);
939
+ }
940
+ }
941
+ logger_default.info("\u5F00\u59CB\u9012\u5F52\u540C\u6B65\u5B50\u5355...");
942
+ await this.syncChildrenRecursive(
943
+ token,
944
+ host,
945
+ project,
946
+ sourceIssue,
947
+ targetParentId,
948
+ targetParentInfo,
949
+ existingTaskNames,
950
+ assignedToMail,
951
+ dryRun,
952
+ result
953
+ );
954
+ logger_default.info("\u540C\u6B65\u5B8C\u6210", {
955
+ totalCreated: result.totalCreated,
956
+ totalSkipped: result.totalSkipped,
957
+ totalFailed: result.totalFailed
958
+ });
959
+ return { success: true, data: result };
960
+ } catch (error) {
961
+ logger_default.error("\u540C\u6B65\u5B50\u5355\u65F6\u53D1\u751F\u9519\u8BEF", error);
962
+ return {
963
+ success: false,
964
+ message: `\u540C\u6B65\u5B50\u5355\u65F6\u53D1\u751F\u9519\u8BEF: ${error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"}`
965
+ };
966
+ }
967
+ }
968
+ /**
969
+ * 收集所有任务名称(递归)
970
+ */
971
+ collectAllTaskNames(issue) {
972
+ const names = /* @__PURE__ */ new Set();
973
+ if (issue.subject?.trim()) {
974
+ names.add(issue.subject.trim());
975
+ }
976
+ for (const child of issue.children || []) {
977
+ const childNames = this.collectAllTaskNames(child);
978
+ childNames.forEach((name) => names.add(name));
979
+ }
980
+ return names;
981
+ }
982
+ /**
983
+ * 递归同步子单
984
+ */
985
+ async syncChildrenRecursive(token, host, project, sourceNode, targetParentId, targetParentInfo, existingTaskNames, assignedToMail, dryRun, result) {
986
+ for (const child of sourceNode.children || []) {
987
+ const taskName = child.subject?.trim() || "\u672A\u547D\u540D\u4EFB\u52A1";
988
+ const sourceId = child.id;
989
+ if (existingTaskNames.has(taskName)) {
990
+ logger_default.info(`\u23ED\uFE0F \u8DF3\u8FC7\u5DF2\u5B58\u5728\u7684\u4EFB\u52A1: ${taskName}`);
991
+ result.totalSkipped++;
992
+ result.skipped.push({
993
+ sourceId,
994
+ subject: taskName,
995
+ reason: "\u76EE\u6807\u7236\u5355\u4E0B\u5DF2\u5B58\u5728\u540C\u540D\u4EFB\u52A1"
996
+ });
997
+ continue;
998
+ }
999
+ const isLeafNode = !child.children || child.children.length === 0;
1000
+ const createParams = {
1001
+ token,
1002
+ host,
1003
+ project,
1004
+ parent_issue_id: targetParentId,
1005
+ subject: taskName,
1006
+ // 继承自目标父单
1007
+ tracker: targetParentInfo.tracker?.name,
1008
+ status: "\u65B0\u5EFA",
1009
+ // 覆盖指派人为"我"
1010
+ assigned_to_mail: assignedToMail,
1011
+ // 只有叶子节点才设置工时
1012
+ estimated_hours: isLeafNode ? child.estimated_hours : void 0,
1013
+ // 保留原任务的优先级
1014
+ priority_id: child.priority?.id
1015
+ };
1016
+ const targetWithVersion = targetParentInfo;
1017
+ if (targetWithVersion.fixed_version?.name) {
1018
+ createParams.version = targetWithVersion.fixed_version.name;
1019
+ }
1020
+ const targetWithCustomFields = targetParentInfo;
1021
+ if (targetWithCustomFields.custom_fields && targetWithCustomFields.custom_fields.length > 0) {
1022
+ const customFieldMap = {};
1023
+ const followsMails = [];
1024
+ for (const field of targetWithCustomFields.custom_fields) {
1025
+ if (field.value !== null && field.value !== void 0 && field.value !== "") {
1026
+ if (field.identify === "IssuesQCFollow") {
1027
+ const followsValue = field.value;
1028
+ if (Array.isArray(followsValue)) {
1029
+ for (const item of followsValue) {
1030
+ if (item.user?.mail) {
1031
+ followsMails.push(item.user.mail);
1032
+ }
1033
+ }
1034
+ }
1035
+ } else {
1036
+ customFieldMap[field.id] = field.value;
1037
+ }
1038
+ }
1039
+ }
1040
+ if (Object.keys(customFieldMap).length > 0) {
1041
+ createParams.custom_field = JSON.stringify(customFieldMap);
1042
+ }
1043
+ if (followsMails.length > 0) {
1044
+ createParams.follows = followsMails;
1045
+ }
1046
+ }
1047
+ logger_default.info(`\u6B63\u5728\u521B\u5EFA\u5B50\u4EFB\u52A1: ${taskName}`, { sourceId, targetParentId, isLeafNode });
1048
+ if (dryRun) {
1049
+ logger_default.info(`[\u6A21\u62DF] \u5C06\u521B\u5EFA\u5B50\u4EFB\u52A1: ${taskName}`);
1050
+ result.totalCreated++;
1051
+ result.created.push({
1052
+ sourceId,
1053
+ newId: 0,
1054
+ // 模拟模式没有真实 ID
1055
+ subject: taskName,
1056
+ parentId: targetParentId
1057
+ });
1058
+ if (child.children && child.children.length > 0) {
1059
+ await this.syncChildrenRecursive(
1060
+ token,
1061
+ host,
1062
+ project,
1063
+ child,
1064
+ 0,
1065
+ // 模拟模式下没有真实的新 ID
1066
+ targetParentInfo,
1067
+ existingTaskNames,
1068
+ assignedToMail,
1069
+ dryRun,
1070
+ result
1071
+ );
1072
+ }
1073
+ } else {
1074
+ try {
1075
+ const createResult = await this.createIssue(createParams);
1076
+ if (createResult.success && createResult.data) {
1077
+ const newId = createResult.data.id;
1078
+ logger_default.info(`\u2705 \u6210\u529F\u521B\u5EFA\u5B50\u4EFB\u52A1: ID=${newId}, \u6807\u9898=${taskName}`);
1079
+ result.totalCreated++;
1080
+ result.created.push({
1081
+ sourceId,
1082
+ newId,
1083
+ subject: taskName,
1084
+ parentId: targetParentId
1085
+ });
1086
+ if (child.children && child.children.length > 0) {
1087
+ logger_default.info(`\u{1F4C1} \u53D1\u73B0\u5B50\u4EFB\u52A1 ${newId} \u6709 ${child.children.length} \u4E2A\u5B50\u4EFB\u52A1\uFF0C\u7EE7\u7EED\u9012\u5F52\u521B\u5EFA...`);
1088
+ await this.syncChildrenRecursive(
1089
+ token,
1090
+ host,
1091
+ project,
1092
+ child,
1093
+ newId,
1094
+ targetParentInfo,
1095
+ existingTaskNames,
1096
+ assignedToMail,
1097
+ dryRun,
1098
+ result
1099
+ );
1100
+ }
1101
+ } else {
1102
+ logger_default.error(`\u274C \u521B\u5EFA\u5B50\u4EFB\u52A1\u5931\u8D25: ${taskName}`, createResult.message || createResult.api_error_msg);
1103
+ result.totalFailed++;
1104
+ result.failed.push({
1105
+ sourceId,
1106
+ subject: taskName,
1107
+ error: createResult.message || createResult.api_error_msg || "\u521B\u5EFA\u5931\u8D25"
1108
+ });
1109
+ }
1110
+ } catch (error) {
1111
+ logger_default.error(`\u274C \u521B\u5EFA\u5B50\u4EFB\u52A1\u65F6\u53D1\u751F\u9519\u8BEF: ${taskName}`, error);
1112
+ result.totalFailed++;
1113
+ result.failed.push({
1114
+ sourceId,
1115
+ subject: taskName,
1116
+ error: error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"
1117
+ });
1118
+ }
1119
+ await sleep(500);
1120
+ }
1121
+ }
1122
+ }
885
1123
  };
886
1124
  var issueService = new IssueService();
887
1125
 
@@ -913,13 +1151,13 @@ function parsePmLink(url) {
913
1151
  // src/commands/issue/index.ts
914
1152
  function createIssueCommand() {
915
1153
  const issueCmd = new Command3("issue").description("\u95EE\u9898\u7BA1\u7406");
916
- issueCmd.command("get [id]").description("\u83B7\u53D6\u95EE\u9898\u8BE6\u60C5\uFF08\u9ED8\u8BA4\u9012\u5F52\u83B7\u53D6\u5B50\u5355\uFF0C\u8F93\u51FA\u5230\u6587\u4EF6\uFF09").option("--url <url>", "PM \u94FE\u63A5").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--depth <depth>", "\u9012\u5F52\u83B7\u53D6\u5B50\u5355\u7684\u6DF1\u5EA6\uFF080 \u8868\u793A\u4E0D\u83B7\u53D6\u5B50\u5355\uFF09", "10").option("-o, --output <path>", "\u8F93\u51FA JSON \u5230\u6307\u5B9A\u6587\u4EF6\uFF08\u9ED8\u8BA4\u8F93\u51FA\u5230 /tmp\uFF09").option("--stdout", "\u5F3A\u5236\u8F93\u51FA\u5230\u63A7\u5236\u53F0\u800C\u975E\u6587\u4EF6").option("--include-relations", "\u5305\u542B\u5173\u8054\u95EE\u9898").action(async (id, options) => {
1154
+ issueCmd.command("get [id]").description("\u83B7\u53D6\u95EE\u9898\u8BE6\u60C5\uFF08\u9ED8\u8BA4\u9012\u5F52\u83B7\u53D6\u5B50\u5355\uFF0C\u8F93\u51FA\u5230\u6587\u4EF6\uFF09").option("--url <url>", "PM \u94FE\u63A5").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--depth <depth>", "\u9012\u5F52\u83B7\u53D6\u5B50\u5355\u7684\u6DF1\u5EA6\uFF080 \u8868\u793A\u4E0D\u83B7\u53D6\u5B50\u5355\uFF09", "10").option("-o, --output <path>", "\u8F93\u51FA JSON \u5230\u6307\u5B9A\u6587\u4EF6\uFF08\u9ED8\u8BA4\u8F93\u51FA\u5230 /tmp\uFF09").option("--stdout", "\u5F3A\u5236\u8F93\u51FA\u5230\u63A7\u5236\u53F0\u800C\u975E\u6587\u4EF6").option("--include-relations", "\u5305\u542B\u5173\u8054\u95EE\u9898").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (id, options) => {
917
1155
  let issueId;
918
1156
  let host;
919
1157
  if (options.url) {
920
1158
  const linkInfo = parsePmLink(options.url);
921
1159
  if (!linkInfo) {
922
- outputError("\u65E0\u6548\u7684 PM \u94FE\u63A5\u683C\u5F0F");
1160
+ outputError("\u65E0\u6548\u7684 PM \u94FE\u63A5\u683C\u5F0F", options.pretty);
923
1161
  process.exit(1);
924
1162
  }
925
1163
  issueId = parseInt(linkInfo.issueId, 10);
@@ -928,11 +1166,11 @@ function createIssueCommand() {
928
1166
  const cleanId = id.replace(/^#/, "");
929
1167
  issueId = parseInt(cleanId, 10);
930
1168
  if (isNaN(issueId)) {
931
- outputError("\u65E0\u6548\u7684\u95EE\u9898 ID");
1169
+ outputError("\u65E0\u6548\u7684\u95EE\u9898 ID", options.pretty);
932
1170
  process.exit(1);
933
1171
  }
934
1172
  } else {
935
- outputError("\u8BF7\u63D0\u4F9B\u95EE\u9898 ID \u6216 --url \u53C2\u6570");
1173
+ outputError("\u8BF7\u63D0\u4F9B\u95EE\u9898 ID \u6216 --url \u53C2\u6570", options.pretty);
936
1174
  process.exit(1);
937
1175
  }
938
1176
  const creds = resolveCredentials({
@@ -941,7 +1179,7 @@ function createIssueCommand() {
941
1179
  });
942
1180
  const validation = validateCredentials(creds, ["token", "host"]);
943
1181
  if (!validation.valid) {
944
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
1182
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
945
1183
  process.exit(1);
946
1184
  }
947
1185
  const depth = parseInt(options.depth, 10);
@@ -958,10 +1196,11 @@ function createIssueCommand() {
958
1196
  stdout: options.stdout,
959
1197
  output: options.output,
960
1198
  command: "issue-get",
961
- identifier: issueId.toString()
1199
+ identifier: issueId.toString(),
1200
+ pretty: options.pretty
962
1201
  });
963
1202
  } else {
964
- outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u95EE\u9898\u5931\u8D25");
1203
+ outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u95EE\u9898\u5931\u8D25", options.pretty);
965
1204
  process.exit(1);
966
1205
  }
967
1206
  } else {
@@ -978,19 +1217,20 @@ function createIssueCommand() {
978
1217
  stdout: options.stdout,
979
1218
  output: options.output,
980
1219
  command: "issue-get",
981
- identifier: issueId.toString()
1220
+ identifier: issueId.toString(),
1221
+ pretty: options.pretty
982
1222
  });
983
1223
  } else {
984
- outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u95EE\u9898\u5931\u8D25");
1224
+ outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u95EE\u9898\u5931\u8D25", options.pretty);
985
1225
  process.exit(1);
986
1226
  }
987
1227
  }
988
1228
  });
989
- issueCmd.command("create").description("\u521B\u5EFA\u95EE\u9898").requiredOption("--subject <subject>", "\u95EE\u9898\u6807\u9898").option("--description <description>", "\u95EE\u9898\u63CF\u8FF0").option("--tracker <tracker>", "\u8DDF\u8E2A\u5668\u540D\u79F0").option("--tracker-id <id>", "\u8DDF\u8E2A\u5668 ID").option("--priority-id <id>", "\u4F18\u5148\u7EA7 ID").option("--assigned-to-mail <email>", "\u6307\u6D3E\u4EBA\u90AE\u7BB1").option("--assigned-to-id <id>", "\u6307\u6D3E\u4EBA ID").option("--parent-id <id>", "\u7236\u95EE\u9898 ID\uFF08\u5B50\u5355\u4F1A\u7EE7\u627F\u7236\u5355\u7684 tracker\u3001version\u3001assigned_to \u7B49\u4FE1\u606F\uFF09").option("--version <version>", "\u76EE\u6807\u7248\u672C\u540D\u79F0").option("--start-date <date>", "\u5F00\u59CB\u65E5\u671F").option("--due-date <date>", "\u622A\u6B62\u65E5\u671F").option("--estimated-hours <hours>", "\u9884\u4F30\u5DE5\u65F6").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (options) => {
1229
+ issueCmd.command("create").description("\u521B\u5EFA\u95EE\u9898").requiredOption("--subject <subject>", "\u95EE\u9898\u6807\u9898").option("--description <description>", "\u95EE\u9898\u63CF\u8FF0").option("--tracker <tracker>", "\u8DDF\u8E2A\u5668\u540D\u79F0").option("--tracker-id <id>", "\u8DDF\u8E2A\u5668 ID").option("--priority-id <id>", "\u4F18\u5148\u7EA7 ID").option("--assigned-to-mail <email>", "\u6307\u6D3E\u4EBA\u90AE\u7BB1").option("--assigned-to-id <id>", "\u6307\u6D3E\u4EBA ID").option("--parent-id <id>", "\u7236\u95EE\u9898 ID\uFF08\u5B50\u5355\u4F1A\u7EE7\u627F\u7236\u5355\u7684 tracker\u3001version\u3001assigned_to \u7B49\u4FE1\u606F\uFF09").option("--version <version>", "\u76EE\u6807\u7248\u672C\u540D\u79F0").option("--start-date <date>", "\u5F00\u59CB\u65E5\u671F").option("--due-date <date>", "\u622A\u6B62\u65E5\u671F").option("--estimated-hours <hours>", "\u9884\u4F30\u5DE5\u65F6").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (options) => {
990
1230
  const creds = resolveCredentials(options);
991
1231
  const validation = validateCredentials(creds);
992
1232
  if (!validation.valid) {
993
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
1233
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
994
1234
  process.exit(1);
995
1235
  }
996
1236
  const params = {
@@ -1052,7 +1292,7 @@ function createIssueCommand() {
1052
1292
  }
1053
1293
  }
1054
1294
  } else {
1055
- outputError(`\u65E0\u6CD5\u83B7\u53D6\u7236\u5355 #${parentId} \u7684\u4FE1\u606F: ${parentResult.message || "\u672A\u77E5\u9519\u8BEF"}`);
1295
+ outputError(`\u65E0\u6CD5\u83B7\u53D6\u7236\u5355 #${parentId} \u7684\u4FE1\u606F: ${parentResult.message || "\u672A\u77E5\u9519\u8BEF"}`, options.pretty);
1056
1296
  process.exit(1);
1057
1297
  }
1058
1298
  params.parent_issue_id = parentId;
@@ -1069,19 +1309,19 @@ function createIssueCommand() {
1069
1309
  if (options.estimatedHours) params.estimated_hours = parseFloat(options.estimatedHours);
1070
1310
  const result = await issueService.createIssue(params);
1071
1311
  if (result.success && result.data) {
1072
- outputSuccess(result.data);
1312
+ outputSuccess(result.data, options.pretty);
1073
1313
  } else {
1074
- outputError(result.message || result.msg || result.api_error_msg || "\u521B\u5EFA\u95EE\u9898\u5931\u8D25");
1314
+ outputError(result.message || result.msg || result.api_error_msg || "\u521B\u5EFA\u95EE\u9898\u5931\u8D25", options.pretty);
1075
1315
  process.exit(1);
1076
1316
  }
1077
1317
  });
1078
- issueCmd.command("update <id>").description("\u66F4\u65B0\u95EE\u9898").option("--subject <subject>", "\u95EE\u9898\u6807\u9898").option("--description <description>", "\u95EE\u9898\u63CF\u8FF0").option("--status <status>", "\u72B6\u6001\u540D\u79F0 (\u5982: \u65B0\u5EFA\u3001\u5F00\u53D1\u4E2D\u3001\u5DF2\u89E3\u51B3)").option("--tracker <tracker>", "\u8DDF\u8E2A\u6807\u7B7E\u540D\u79F0 (\u5982: BUG\u3001\u4EFB\u52A1)").option("--version <version>", "\u76EE\u6807\u7248\u672C\u540D\u79F0").option("--assigned-to-mail <email>", "\u6307\u6D3E\u4EBA\u90AE\u7BB1").option("--notes <notes>", "\u66F4\u65B0\u8BF4\u660E/\u5907\u6CE8").option("--start-date <date>", "\u5F00\u59CB\u65E5\u671F (\u683C\u5F0F: YYYY-MM-DD)").option("--due-date <date>", "\u622A\u6B62\u65E5\u671F (\u683C\u5F0F: YYYY-MM-DD)").option("--estimated-hours <hours>", "\u9884\u4F30\u5DE5\u65F6").option("--follows <email>", "\u8DDF\u8FDBQA\u90AE\u7BB1").option("--url <url>", "PM \u94FE\u63A5 (\u81EA\u52A8\u89E3\u6790 host \u548C issue_id)").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (id, options) => {
1318
+ issueCmd.command("update <id>").description("\u66F4\u65B0\u95EE\u9898").option("--subject <subject>", "\u95EE\u9898\u6807\u9898").option("--description <description>", "\u95EE\u9898\u63CF\u8FF0").option("--status <status>", "\u72B6\u6001\u540D\u79F0 (\u5982: \u65B0\u5EFA\u3001\u5F00\u53D1\u4E2D\u3001\u5DF2\u89E3\u51B3)").option("--tracker <tracker>", "\u8DDF\u8E2A\u6807\u7B7E\u540D\u79F0 (\u5982: BUG\u3001\u4EFB\u52A1)").option("--version <version>", "\u76EE\u6807\u7248\u672C\u540D\u79F0").option("--assigned-to-mail <email>", "\u6307\u6D3E\u4EBA\u90AE\u7BB1").option("--notes <notes>", "\u66F4\u65B0\u8BF4\u660E/\u5907\u6CE8").option("--start-date <date>", "\u5F00\u59CB\u65E5\u671F (\u683C\u5F0F: YYYY-MM-DD)").option("--due-date <date>", "\u622A\u6B62\u65E5\u671F (\u683C\u5F0F: YYYY-MM-DD)").option("--estimated-hours <hours>", "\u9884\u4F30\u5DE5\u65F6").option("--follows <email>", "\u8DDF\u8FDBQA\u90AE\u7BB1").option("--custom-field <key=value>", "\u81EA\u5B9A\u4E49\u5B57\u6BB5 (\u683C\u5F0F: \u5B57\u6BB5ID=\u503C \u6216 \u5B57\u6BB5\u540D=\u503C\uFF0C\u53EF\u591A\u6B21\u4F7F\u7528)").option("--cf <key=value>", "\u81EA\u5B9A\u4E49\u5B57\u6BB5\u7684\u7B80\u5199\u522B\u540D").option("--url <url>", "PM \u94FE\u63A5 (\u81EA\u52A8\u89E3\u6790 host \u548C issue_id)").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (id, options) => {
1079
1319
  let issueId;
1080
1320
  let urlHost;
1081
1321
  if (options.url) {
1082
1322
  const linkInfo = parsePmLink(options.url);
1083
1323
  if (!linkInfo) {
1084
- outputError("\u65E0\u6548\u7684 PM \u94FE\u63A5\u683C\u5F0F");
1324
+ outputError("\u65E0\u6548\u7684 PM \u94FE\u63A5\u683C\u5F0F", options.pretty);
1085
1325
  process.exit(1);
1086
1326
  }
1087
1327
  issueId = parseInt(linkInfo.issueId, 10);
@@ -1089,7 +1329,7 @@ function createIssueCommand() {
1089
1329
  } else {
1090
1330
  issueId = parseInt(id.replace(/^#/, ""), 10);
1091
1331
  if (isNaN(issueId)) {
1092
- outputError("\u65E0\u6548\u7684\u95EE\u9898 ID");
1332
+ outputError("\u65E0\u6548\u7684\u95EE\u9898 ID", options.pretty);
1093
1333
  process.exit(1);
1094
1334
  }
1095
1335
  }
@@ -1099,7 +1339,7 @@ function createIssueCommand() {
1099
1339
  });
1100
1340
  const validation = validateCredentials(creds);
1101
1341
  if (!validation.valid) {
1102
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
1342
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1103
1343
  process.exit(1);
1104
1344
  }
1105
1345
  const params = {
@@ -1119,19 +1359,86 @@ function createIssueCommand() {
1119
1359
  if (options.dueDate) params.due_date = options.dueDate;
1120
1360
  if (options.estimatedHours) params.estimated_hours = parseFloat(options.estimatedHours);
1121
1361
  if (options.follows) params.follows = options.follows;
1362
+ const customFieldInputs = [];
1363
+ if (options.customField) {
1364
+ customFieldInputs.push(...Array.isArray(options.customField) ? options.customField : [options.customField]);
1365
+ }
1366
+ if (options.cf) {
1367
+ customFieldInputs.push(...Array.isArray(options.cf) ? options.cf : [options.cf]);
1368
+ }
1369
+ if (customFieldInputs.length > 0) {
1370
+ try {
1371
+ const customFieldData = {};
1372
+ for (const input of customFieldInputs) {
1373
+ const match = input.match(/^([^=]+)=(.*)$/);
1374
+ if (!match) {
1375
+ outputError(`\u81EA\u5B9A\u4E49\u5B57\u6BB5\u683C\u5F0F\u9519\u8BEF: ${input}\uFF0C\u6B63\u786E\u683C\u5F0F\u4E3A "\u5B57\u6BB5ID=\u503C" \u6216 "\u5B57\u6BB5\u540D=\u503C"`, options.pretty);
1376
+ process.exit(1);
1377
+ }
1378
+ const [, key, value] = match;
1379
+ customFieldData[key.trim()] = value.trim();
1380
+ }
1381
+ const hasNonNumericKey = Object.keys(customFieldData).some((key) => isNaN(Number(key)));
1382
+ if (hasNonNumericKey) {
1383
+ const fieldOptionsResult = await issueService.getIssueFieldOptions(
1384
+ creds.token,
1385
+ creds.host,
1386
+ creds.project
1387
+ );
1388
+ if (fieldOptionsResult.success && fieldOptionsResult.data) {
1389
+ const fieldOptions = fieldOptionsResult.data;
1390
+ if (fieldOptions.data?.custom_fields) {
1391
+ const fieldMap = /* @__PURE__ */ new Map();
1392
+ for (const field of fieldOptions.data.custom_fields) {
1393
+ fieldMap.set(field.name, field.id);
1394
+ }
1395
+ const convertedData = {};
1396
+ for (const [key, value] of Object.entries(customFieldData)) {
1397
+ const fieldId = isNaN(Number(key)) ? fieldMap.get(key) : Number(key);
1398
+ if (fieldId !== void 0) {
1399
+ convertedData[fieldId] = value;
1400
+ } else {
1401
+ outputError(`\u672A\u627E\u5230\u81EA\u5B9A\u4E49\u5B57\u6BB5: ${key}`, options.pretty);
1402
+ process.exit(1);
1403
+ }
1404
+ }
1405
+ params.custom_field = JSON.stringify(convertedData);
1406
+ } else {
1407
+ outputError("\u65E0\u6CD5\u83B7\u53D6\u81EA\u5B9A\u4E49\u5B57\u6BB5\u5217\u8868", options.pretty);
1408
+ process.exit(1);
1409
+ }
1410
+ } else {
1411
+ outputError("\u83B7\u53D6\u81EA\u5B9A\u4E49\u5B57\u6BB5\u5217\u8868\u5931\u8D25", options.pretty);
1412
+ process.exit(1);
1413
+ }
1414
+ } else {
1415
+ const convertedData = {};
1416
+ for (const [key, value] of Object.entries(customFieldData)) {
1417
+ convertedData[Number(key)] = value;
1418
+ }
1419
+ params.custom_field = JSON.stringify(convertedData);
1420
+ }
1421
+ } catch (error) {
1422
+ outputError(
1423
+ `\u81EA\u5B9A\u4E49\u5B57\u6BB5\u89E3\u6790\u9519\u8BEF: ${error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"}`,
1424
+ options.pretty
1425
+ );
1426
+ process.exit(1);
1427
+ }
1428
+ }
1122
1429
  const result = await issueService.updateIssue(params);
1123
1430
  if (result.success && result.data) {
1124
- outputSuccess(result.data);
1431
+ outputSuccess(result.data, options.pretty);
1125
1432
  } else {
1126
- outputError(result.message || result.msg || result.api_error_msg || "\u66F4\u65B0\u95EE\u9898\u5931\u8D25");
1433
+ outputError(result.message || result.msg || result.api_error_msg || "\u66F4\u65B0\u95EE\u9898\u5931\u8D25", options.pretty);
1127
1434
  process.exit(1);
1128
1435
  }
1129
1436
  });
1130
- issueCmd.command("query").description("\u81EA\u5B9A\u4E49\u67E5\u8BE2").requiredOption("--query-id <id>", "\u67E5\u8BE2 ID").option("--limit <limit>", "\u8FD4\u56DE\u6570\u91CF\u9650\u5236").option("--offset <offset>", "\u504F\u79FB\u91CF").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (options) => {
1437
+ issueCmd.command("query").description("\u81EA\u5B9A\u4E49\u67E5\u8BE2").requiredOption("--query-id <id>", "\u67E5\u8BE2 ID").option("--limit <limit>", "\u8FD4\u56DE\u6570\u91CF\u9650\u5236").option("--offset <offset>", "\u504F\u79FB\u91CF").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (options) => {
1131
1438
  const creds = resolveCredentials(options);
1132
1439
  const validation = validateCredentials(creds);
1133
1440
  if (!validation.valid) {
1134
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
1441
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1135
1442
  process.exit(1);
1136
1443
  }
1137
1444
  const queryId = parseInt(options.queryId, 10);
@@ -1146,17 +1453,17 @@ function createIssueCommand() {
1146
1453
  offset
1147
1454
  );
1148
1455
  if (result.success && result.data) {
1149
- outputSuccess(result.data);
1456
+ outputSuccess(result.data, options.pretty);
1150
1457
  } else {
1151
- outputError(result.message || result.msg || result.api_error_msg || "\u67E5\u8BE2\u5931\u8D25");
1458
+ outputError(result.message || result.msg || result.api_error_msg || "\u67E5\u8BE2\u5931\u8D25", options.pretty);
1152
1459
  process.exit(1);
1153
1460
  }
1154
1461
  });
1155
- issueCmd.command("filter").description("V6 \u8FC7\u6EE4\u5668\u67E5\u8BE2").option("--mode <mode>", "\u67E5\u8BE2\u6A21\u5F0F (normal/simple/advanced)", "normal").option("--status <status>", "\u72B6\u6001\u8FC7\u6EE4").option("--tracker <tracker>", "\u8DDF\u8E2A\u5668\u8FC7\u6EE4").option("--assigned-to <user>", "\u6307\u6D3E\u4EBA\u8FC7\u6EE4").option("--limit <limit>", "\u8FD4\u56DE\u6570\u91CF\u9650\u5236").option("--offset <offset>", "\u504F\u79FB\u91CF").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (options) => {
1462
+ issueCmd.command("filter").description("V6 \u8FC7\u6EE4\u5668\u67E5\u8BE2").option("--mode <mode>", "\u67E5\u8BE2\u6A21\u5F0F (normal/simple/advanced)", "normal").option("--status <status>", "\u72B6\u6001\u8FC7\u6EE4").option("--tracker <tracker>", "\u8DDF\u8E2A\u5668\u8FC7\u6EE4").option("--assigned-to <user>", "\u6307\u6D3E\u4EBA\u8FC7\u6EE4").option("--limit <limit>", "\u8FD4\u56DE\u6570\u91CF\u9650\u5236").option("--offset <offset>", "\u504F\u79FB\u91CF").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (options) => {
1156
1463
  const creds = resolveCredentials(options);
1157
1464
  const validation = validateCredentials(creds);
1158
1465
  if (!validation.valid) {
1159
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
1466
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1160
1467
  process.exit(1);
1161
1468
  }
1162
1469
  const filterParams = {};
@@ -1173,17 +1480,17 @@ function createIssueCommand() {
1173
1480
  filterParams
1174
1481
  );
1175
1482
  if (result.success && result.data) {
1176
- outputSuccess(result.data);
1483
+ outputSuccess(result.data, options.pretty);
1177
1484
  } else {
1178
- outputError(result.message || result.msg || result.api_error_msg || "\u67E5\u8BE2\u5931\u8D25");
1485
+ outputError(result.message || result.msg || result.api_error_msg || "\u67E5\u8BE2\u5931\u8D25", options.pretty);
1179
1486
  process.exit(1);
1180
1487
  }
1181
1488
  });
1182
- issueCmd.command("field-options").description("\u83B7\u53D6\u95EE\u9898\u5B57\u6BB5\u9009\u9879").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (options) => {
1489
+ issueCmd.command("field-options").description("\u83B7\u53D6\u95EE\u9898\u5B57\u6BB5\u9009\u9879").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (options) => {
1183
1490
  const creds = resolveCredentials(options);
1184
1491
  const validation = validateCredentials(creds);
1185
1492
  if (!validation.valid) {
1186
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
1493
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1187
1494
  process.exit(1);
1188
1495
  }
1189
1496
  const result = await issueService.getIssueFieldOptions(
@@ -1192,19 +1499,19 @@ function createIssueCommand() {
1192
1499
  creds.project
1193
1500
  );
1194
1501
  if (result.success) {
1195
- outputSuccess(result.data);
1502
+ outputSuccess(result.data, options.pretty);
1196
1503
  } else {
1197
- outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u5B57\u6BB5\u9009\u9879\u5931\u8D25");
1504
+ outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u5B57\u6BB5\u9009\u9879\u5931\u8D25", options.pretty);
1198
1505
  process.exit(1);
1199
1506
  }
1200
1507
  });
1201
- issueCmd.command("children <id>").description("\u67E5\u8BE2\u5B50\u4EFB\u52A1\uFF08\u652F\u6301\u6309\u8D1F\u8D23\u4EBA\u8FC7\u6EE4\uFF09").option("--url <url>", "PM \u94FE\u63A5").option("--assigned-to <name>", "\u8D1F\u8D23\u4EBA\u59D3\u540D\uFF08\u652F\u6301\u6A21\u7CCA\u5339\u914D\uFF09").option("--assigned-to-id <id>", "\u8D1F\u8D23\u4EBA ID").option("--limit <limit>", "\u8FD4\u56DE\u6570\u91CF\u9650\u5236", "100").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (id, options) => {
1508
+ issueCmd.command("children <id>").description("\u67E5\u8BE2\u5B50\u4EFB\u52A1\uFF08\u652F\u6301\u6309\u8D1F\u8D23\u4EBA\u8FC7\u6EE4\uFF09").option("--url <url>", "PM \u94FE\u63A5").option("--assigned-to <name>", "\u8D1F\u8D23\u4EBA\u59D3\u540D\uFF08\u652F\u6301\u6A21\u7CCA\u5339\u914D\uFF09").option("--assigned-to-id <id>", "\u8D1F\u8D23\u4EBA ID").option("--limit <limit>", "\u8FD4\u56DE\u6570\u91CF\u9650\u5236", "100").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (id, options) => {
1202
1509
  let issueId;
1203
1510
  let host;
1204
1511
  if (options.url) {
1205
1512
  const linkInfo = parsePmLink(options.url);
1206
1513
  if (!linkInfo) {
1207
- outputError("\u65E0\u6548\u7684 PM \u94FE\u63A5\u683C\u5F0F");
1514
+ outputError("\u65E0\u6548\u7684 PM \u94FE\u63A5\u683C\u5F0F", options.pretty);
1208
1515
  process.exit(1);
1209
1516
  }
1210
1517
  issueId = parseInt(linkInfo.issueId, 10);
@@ -1213,7 +1520,7 @@ function createIssueCommand() {
1213
1520
  const cleanId = id.replace(/^#/, "");
1214
1521
  issueId = parseInt(cleanId, 10);
1215
1522
  if (isNaN(issueId)) {
1216
- outputError("\u65E0\u6548\u7684\u95EE\u9898 ID");
1523
+ outputError("\u65E0\u6548\u7684\u95EE\u9898 ID", options.pretty);
1217
1524
  process.exit(1);
1218
1525
  }
1219
1526
  }
@@ -1223,7 +1530,7 @@ function createIssueCommand() {
1223
1530
  });
1224
1531
  const validation = validateCredentials(creds);
1225
1532
  if (!validation.valid) {
1226
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
1533
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1227
1534
  process.exit(1);
1228
1535
  }
1229
1536
  let assignedToId;
@@ -1242,11 +1549,11 @@ function createIssueCommand() {
1242
1549
  if (matchedUser) {
1243
1550
  assignedToId = matchedUser.id;
1244
1551
  } else {
1245
- outputError(`\u672A\u627E\u5230\u5339\u914D\u7684\u7528\u6237: ${options.assignedTo}`);
1552
+ outputError(`\u672A\u627E\u5230\u5339\u914D\u7684\u7528\u6237: ${options.assignedTo}`, options.pretty);
1246
1553
  process.exit(1);
1247
1554
  }
1248
1555
  } else {
1249
- outputError("\u83B7\u53D6\u7528\u6237\u5217\u8868\u5931\u8D25");
1556
+ outputError("\u83B7\u53D6\u7528\u6237\u5217\u8868\u5931\u8D25", options.pretty);
1250
1557
  process.exit(1);
1251
1558
  }
1252
1559
  } else if (options.assignedToId) {
@@ -1267,16 +1574,16 @@ function createIssueCommand() {
1267
1574
  outputSuccess({
1268
1575
  total: data.data.list.length,
1269
1576
  issues: data.data.list
1270
- });
1577
+ }, options.pretty);
1271
1578
  } else {
1272
- outputSuccess(result.data);
1579
+ outputSuccess(result.data, options.pretty);
1273
1580
  }
1274
1581
  } else {
1275
- outputError(result.message || result.msg || result.api_error_msg || "\u67E5\u8BE2\u5B50\u4EFB\u52A1\u5931\u8D25");
1582
+ outputError(result.message || result.msg || result.api_error_msg || "\u67E5\u8BE2\u5B50\u4EFB\u52A1\u5931\u8D25", options.pretty);
1276
1583
  process.exit(1);
1277
1584
  }
1278
1585
  });
1279
- issueCmd.command("mget [ids...]").description("\u6279\u91CF\u83B7\u53D6\u591A\u4E2A\u95EE\u9898\u8BE6\u60C5").option("--ids <ids>", "\u9017\u53F7\u5206\u9694\u7684\u95EE\u9898 ID \u5217\u8868").option("--depth <depth>", "\u9012\u5F52\u83B7\u53D6\u5B50\u5355\u7684\u6DF1\u5EA6\uFF080 \u8868\u793A\u4E0D\u83B7\u53D6\u5B50\u5355\uFF09", "0").option("--include-relations", "\u5305\u542B\u5173\u8054\u95EE\u9898").option("-o, --output <path>", "\u8F93\u51FA JSON \u5230\u6307\u5B9A\u6587\u4EF6\uFF08\u9ED8\u8BA4\u8F93\u51FA\u5230 /tmp\uFF09").option("--stdout", "\u5F3A\u5236\u8F93\u51FA\u5230\u63A7\u5236\u53F0\u800C\u975E\u6587\u4EF6").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (ids, options) => {
1586
+ issueCmd.command("mget [ids...]").description("\u6279\u91CF\u83B7\u53D6\u591A\u4E2A\u95EE\u9898\u8BE6\u60C5").option("--ids <ids>", "\u9017\u53F7\u5206\u9694\u7684\u95EE\u9898 ID \u5217\u8868").option("--depth <depth>", "\u9012\u5F52\u83B7\u53D6\u5B50\u5355\u7684\u6DF1\u5EA6\uFF080 \u8868\u793A\u4E0D\u83B7\u53D6\u5B50\u5355\uFF09", "0").option("--include-relations", "\u5305\u542B\u5173\u8054\u95EE\u9898").option("-o, --output <path>", "\u8F93\u51FA JSON \u5230\u6307\u5B9A\u6587\u4EF6\uFF08\u9ED8\u8BA4\u8F93\u51FA\u5230 /tmp\uFF09").option("--stdout", "\u5F3A\u5236\u8F93\u51FA\u5230\u63A7\u5236\u53F0\u800C\u975E\u6587\u4EF6").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (ids, options) => {
1280
1587
  let issueIds = [];
1281
1588
  if (ids && ids.length > 0) {
1282
1589
  const parsedIds = ids.map((id) => parseInt(id.replace(/^#/, ""), 10)).filter((id) => !isNaN(id));
@@ -1288,13 +1595,13 @@ function createIssueCommand() {
1288
1595
  }
1289
1596
  issueIds = [...new Set(issueIds)];
1290
1597
  if (issueIds.length === 0) {
1291
- outputError("\u8BF7\u63D0\u4F9B\u81F3\u5C11\u4E00\u4E2A\u95EE\u9898 ID");
1598
+ outputError("\u8BF7\u63D0\u4F9B\u81F3\u5C11\u4E00\u4E2A\u95EE\u9898 ID", options.pretty);
1292
1599
  process.exit(1);
1293
1600
  }
1294
1601
  const creds = resolveCredentials(options);
1295
1602
  const validation = validateCredentials(creds, ["token", "host"]);
1296
1603
  if (!validation.valid) {
1297
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
1604
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1298
1605
  process.exit(1);
1299
1606
  }
1300
1607
  const depth = parseInt(options.depth, 10);
@@ -1324,10 +1631,117 @@ function createIssueCommand() {
1324
1631
  stdout: options.stdout,
1325
1632
  output: options.output,
1326
1633
  command: "issue-mget",
1327
- identifier: issueIds.join("_")
1634
+ identifier: issueIds.join("_"),
1635
+ pretty: options.pretty
1636
+ });
1637
+ } else {
1638
+ outputError(result.message || result.msg || result.api_error_msg || "\u6279\u91CF\u83B7\u53D6\u95EE\u9898\u5931\u8D25", options.pretty);
1639
+ process.exit(1);
1640
+ }
1641
+ });
1642
+ issueCmd.command("sync").description("\u540C\u6B65\u5B50\u5355\uFF1A\u4ECE\u6E90\u7236\u5355\u590D\u5236\u5B50\u5355\u5230\u76EE\u6807\u7236\u5355").option("--from <id>", "\u6E90\u7236\u5355 ID").option("--to <id>", "\u76EE\u6807\u7236\u5355 ID").option("--from-url <url>", "\u6E90\u7236\u5355 PM \u94FE\u63A5").option("--to-url <url>", "\u76EE\u6807\u7236\u5355 PM \u94FE\u63A5").option("--assigned-to-mail <email>", "\u6307\u6D3E\u4EBA\u90AE\u7BB1\uFF08\u9ED8\u8BA4\u4F7F\u7528\u914D\u7F6E\u7684 userMail\uFF09").option("--depth <depth>", "\u9012\u5F52\u6DF1\u5EA6", "10").option("--dry-run", "\u6A21\u62DF\u8FD0\u884C\uFF0C\u4E0D\u5B9E\u9645\u521B\u5EFA").option("--no-skip-existing", "\u4E0D\u8DF3\u8FC7\u540C\u540D\u4EFB\u52A1").option("-o, --output <path>", "\u8F93\u51FA JSON \u5230\u6307\u5B9A\u6587\u4EF6").option("--stdout", "\u5F3A\u5236\u8F93\u51FA\u5230\u63A7\u5236\u53F0\u800C\u975E\u6587\u4EF6").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (options) => {
1643
+ let sourceId;
1644
+ let targetId;
1645
+ let sourceHost;
1646
+ let targetHost;
1647
+ if (options.fromUrl) {
1648
+ const linkInfo = parsePmLink(options.fromUrl);
1649
+ if (!linkInfo) {
1650
+ outputError("\u65E0\u6548\u7684\u6E90\u7236\u5355 PM \u94FE\u63A5\u683C\u5F0F", options.pretty);
1651
+ process.exit(1);
1652
+ }
1653
+ sourceId = parseInt(linkInfo.issueId, 10);
1654
+ sourceHost = linkInfo.host;
1655
+ } else if (options.from) {
1656
+ const cleanId = options.from.replace(/^#/, "");
1657
+ sourceId = parseInt(cleanId, 10);
1658
+ if (isNaN(sourceId)) {
1659
+ outputError("\u65E0\u6548\u7684\u6E90\u7236\u5355 ID", options.pretty);
1660
+ process.exit(1);
1661
+ }
1662
+ }
1663
+ if (options.toUrl) {
1664
+ const linkInfo = parsePmLink(options.toUrl);
1665
+ if (!linkInfo) {
1666
+ outputError("\u65E0\u6548\u7684\u76EE\u6807\u7236\u5355 PM \u94FE\u63A5\u683C\u5F0F", options.pretty);
1667
+ process.exit(1);
1668
+ }
1669
+ targetId = parseInt(linkInfo.issueId, 10);
1670
+ targetHost = linkInfo.host;
1671
+ } else if (options.to) {
1672
+ const cleanId = options.to.replace(/^#/, "");
1673
+ targetId = parseInt(cleanId, 10);
1674
+ if (isNaN(targetId)) {
1675
+ outputError("\u65E0\u6548\u7684\u76EE\u6807\u7236\u5355 ID", options.pretty);
1676
+ process.exit(1);
1677
+ }
1678
+ }
1679
+ if (!sourceId) {
1680
+ outputError("\u8BF7\u63D0\u4F9B\u6E90\u7236\u5355 ID\uFF08--from\uFF09\u6216 PM \u94FE\u63A5\uFF08--from-url\uFF09", options.pretty);
1681
+ process.exit(1);
1682
+ }
1683
+ if (!targetId) {
1684
+ outputError("\u8BF7\u63D0\u4F9B\u76EE\u6807\u7236\u5355 ID\uFF08--to\uFF09\u6216 PM \u94FE\u63A5\uFF08--to-url\uFF09", options.pretty);
1685
+ process.exit(1);
1686
+ }
1687
+ const creds = resolveCredentials({
1688
+ ...options,
1689
+ host: sourceHost || targetHost || options.host
1690
+ });
1691
+ const validation = validateCredentials(creds, ["token", "host"]);
1692
+ if (!validation.valid) {
1693
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1694
+ process.exit(1);
1695
+ }
1696
+ let assignedToMail = options.assignedToMail;
1697
+ if (!assignedToMail) {
1698
+ const config = readConfig(options.config);
1699
+ assignedToMail = config.default?.userMail;
1700
+ if (options.profile && config.profiles[options.profile]?.userMail) {
1701
+ assignedToMail = config.profiles[options.profile].userMail;
1702
+ }
1703
+ }
1704
+ if (!assignedToMail) {
1705
+ outputError("\u8BF7\u63D0\u4F9B\u6307\u6D3E\u4EBA\u90AE\u7BB1\uFF08--assigned-to-mail\uFF09\u6216\u914D\u7F6E userMail\uFF08pm-cli config set user-mail xxx\uFF09", options.pretty);
1706
+ process.exit(1);
1707
+ }
1708
+ const depth = parseInt(options.depth, 10);
1709
+ const dryRun = options.dryRun || false;
1710
+ const skipExisting = options.skipExisting !== false;
1711
+ const result = await issueService.syncChildIssues(
1712
+ creds.token,
1713
+ creds.host,
1714
+ creds.project || "",
1715
+ sourceId,
1716
+ targetId,
1717
+ assignedToMail,
1718
+ { dryRun, depth, skipExisting }
1719
+ );
1720
+ if (result.success && result.data) {
1721
+ const output = {
1722
+ success: true,
1723
+ dryRun,
1724
+ sourceParentId: sourceId,
1725
+ targetParentId: targetId,
1726
+ assignedToMail,
1727
+ summary: {
1728
+ totalCreated: result.data.totalCreated,
1729
+ totalSkipped: result.data.totalSkipped,
1730
+ totalFailed: result.data.totalFailed
1731
+ },
1732
+ created: result.data.created,
1733
+ skipped: result.data.skipped.length > 0 ? result.data.skipped : void 0,
1734
+ failed: result.data.failed.length > 0 ? result.data.failed : void 0
1735
+ };
1736
+ smartOutput(output, {
1737
+ stdout: options.stdout,
1738
+ output: options.output,
1739
+ command: "issue-sync",
1740
+ identifier: `${sourceId}_to_${targetId}`,
1741
+ pretty: options.pretty
1328
1742
  });
1329
1743
  } else {
1330
- outputError(result.message || result.msg || result.api_error_msg || "\u6279\u91CF\u83B7\u53D6\u95EE\u9898\u5931\u8D25");
1744
+ outputError(result.message || result.msg || result.api_error_msg || "\u540C\u6B65\u5B50\u5355\u5931\u8D25", options.pretty);
1331
1745
  process.exit(1);
1332
1746
  }
1333
1747
  });
@@ -1433,19 +1847,19 @@ function getWeekDateRange(week) {
1433
1847
  }
1434
1848
  function createTimeCommand() {
1435
1849
  const timeCmd = new Command4("time").description("\u5DE5\u65F6\u7BA1\u7406");
1436
- timeCmd.command("list").description("\u67E5\u8BE2\u5DE5\u65F6\u6761\u76EE").option("--from <date>", "\u5F00\u59CB\u65E5\u671F (YYYY-MM-DD)").option("--to <date>", "\u7ED3\u675F\u65E5\u671F (YYYY-MM-DD)").option("--user-id <id>", "\u7528\u6237 ID").option("--activity-id <id>", "\u6D3B\u52A8\u7C7B\u578B ID").option("--limit <limit>", "\u8FD4\u56DE\u6570\u91CF\u9650\u5236").option("--offset <offset>", "\u504F\u79FB\u91CF").option("--all-projects", "\u67E5\u8BE2\u6240\u6709\u9879\u76EE\u7684\u5DE5\u65F6").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (options) => {
1850
+ timeCmd.command("list").description("\u67E5\u8BE2\u5DE5\u65F6\u6761\u76EE").option("--from <date>", "\u5F00\u59CB\u65E5\u671F (YYYY-MM-DD)").option("--to <date>", "\u7ED3\u675F\u65E5\u671F (YYYY-MM-DD)").option("--user-id <id>", "\u7528\u6237 ID").option("--activity-id <id>", "\u6D3B\u52A8\u7C7B\u578B ID").option("--limit <limit>", "\u8FD4\u56DE\u6570\u91CF\u9650\u5236").option("--offset <offset>", "\u504F\u79FB\u91CF").option("--all-projects", "\u67E5\u8BE2\u6240\u6709\u9879\u76EE\u7684\u5DE5\u65F6").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (options) => {
1437
1851
  const creds = resolveCredentials(options);
1438
1852
  const requiredFields = options.allProjects ? ["token", "host"] : ["token", "host", "project"];
1439
1853
  const validation = validateCredentials(creds, requiredFields);
1440
1854
  if (!validation.valid) {
1441
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
1855
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1442
1856
  process.exit(1);
1443
1857
  }
1444
1858
  if (options.allProjects) {
1445
1859
  logger_default.info("\u67E5\u8BE2\u6240\u6709\u9879\u76EE\u7684\u5DE5\u65F6...");
1446
1860
  const projectsResult = await userService.getProjects(creds.token, creds.host);
1447
1861
  if (!projectsResult.success || !projectsResult.data) {
1448
- outputError(projectsResult.message || projectsResult.msg || projectsResult.api_error_msg || "\u83B7\u53D6\u9879\u76EE\u5217\u8868\u5931\u8D25");
1862
+ outputError(projectsResult.message || projectsResult.msg || projectsResult.api_error_msg || "\u83B7\u53D6\u9879\u76EE\u5217\u8868\u5931\u8D25", options.pretty);
1449
1863
  process.exit(1);
1450
1864
  }
1451
1865
  const projects = projectsResult.data;
@@ -1501,18 +1915,18 @@ function createTimeCommand() {
1501
1915
  offset: options.offset ? parseInt(options.offset, 10) : void 0
1502
1916
  });
1503
1917
  if (result.success && result.data) {
1504
- outputSuccess(result.data);
1918
+ outputSuccess(result.data, options.pretty);
1505
1919
  } else {
1506
- outputError(result.message || result.msg || result.api_error_msg || "\u67E5\u8BE2\u5DE5\u65F6\u5931\u8D25");
1920
+ outputError(result.message || result.msg || result.api_error_msg || "\u67E5\u8BE2\u5DE5\u65F6\u5931\u8D25", options.pretty);
1507
1921
  process.exit(1);
1508
1922
  }
1509
1923
  }
1510
1924
  });
1511
- timeCmd.command("create").description("\u521B\u5EFA\u5DE5\u65F6\u6761\u76EE").requiredOption("--issue <id>", "\u95EE\u9898 ID").requiredOption("--days <days>", "\u5DE5\u65F6\uFF08\u5929\uFF09").requiredOption("--activity <id>", "\u6D3B\u52A8\u7C7B\u578B ID\uFF08\u4F7F\u7528 pm-cli time options \u83B7\u53D6\u53EF\u7528\u503C\uFF09").option("--date <date>", "\u65E5\u671F (YYYY-MM-DD)\uFF0C\u9ED8\u8BA4\u4ECA\u5929").option("--comments <comments>", "\u5907\u6CE8").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (options) => {
1925
+ timeCmd.command("create").description("\u521B\u5EFA\u5DE5\u65F6\u6761\u76EE").requiredOption("--issue <id>", "\u95EE\u9898 ID").requiredOption("--days <days>", "\u5DE5\u65F6\uFF08\u5929\uFF09").requiredOption("--activity <id>", "\u6D3B\u52A8\u7C7B\u578B ID\uFF08\u4F7F\u7528 pm-cli time options \u83B7\u53D6\u53EF\u7528\u503C\uFF09").option("--date <date>", "\u65E5\u671F (YYYY-MM-DD)\uFF0C\u9ED8\u8BA4\u4ECA\u5929").option("--comments <comments>", "\u5907\u6CE8").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (options) => {
1512
1926
  const creds = resolveCredentials(options);
1513
1927
  const validation = validateCredentials(creds);
1514
1928
  if (!validation.valid) {
1515
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
1929
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1516
1930
  process.exit(1);
1517
1931
  }
1518
1932
  let userId;
@@ -1521,22 +1935,22 @@ function createTimeCommand() {
1521
1935
  userId = parseInt(configUserId, 10);
1522
1936
  }
1523
1937
  if (!userId) {
1524
- outputError("\u7F3A\u5C11\u7528\u6237 ID\uFF0C\u8BF7\u5148\u8BBE\u7F6E: pm-cli config set user-id <\u60A8\u7684\u7528\u6237ID>");
1938
+ outputError("\u7F3A\u5C11\u7528\u6237 ID\uFF0C\u8BF7\u5148\u8BBE\u7F6E: pm-cli config set user-id <\u60A8\u7684\u7528\u6237ID>", options.pretty);
1525
1939
  process.exit(1);
1526
1940
  }
1527
1941
  const issueId = parseInt(options.issue.replace(/^#/, ""), 10);
1528
1942
  if (isNaN(issueId)) {
1529
- outputError("\u65E0\u6548\u7684\u95EE\u9898 ID");
1943
+ outputError("\u65E0\u6548\u7684\u95EE\u9898 ID", options.pretty);
1530
1944
  process.exit(1);
1531
1945
  }
1532
1946
  const days = parseFloat(options.days);
1533
1947
  if (isNaN(days) || days <= 0) {
1534
- outputError("\u65E0\u6548\u7684\u5DE5\u65F6\u6570");
1948
+ outputError("\u65E0\u6548\u7684\u5DE5\u65F6\u6570", options.pretty);
1535
1949
  process.exit(1);
1536
1950
  }
1537
1951
  const activityId = parseInt(options.activity, 10);
1538
1952
  if (isNaN(activityId)) {
1539
- outputError("\u65E0\u6548\u7684\u6D3B\u52A8\u7C7B\u578B ID\uFF0C\u4F7F\u7528 pm-cli time options \u83B7\u53D6\u53EF\u7528\u503C");
1953
+ outputError("\u65E0\u6548\u7684\u6D3B\u52A8\u7C7B\u578B ID\uFF0C\u4F7F\u7528 pm-cli time options \u83B7\u53D6\u53EF\u7528\u503C", options.pretty);
1540
1954
  process.exit(1);
1541
1955
  }
1542
1956
  const params = {
@@ -1549,23 +1963,25 @@ function createTimeCommand() {
1549
1963
  spent_on: options.date || (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
1550
1964
  user_id: userId,
1551
1965
  // 用户 ID(必填)
1552
- activity_id: activityId
1966
+ activity_id: activityId,
1553
1967
  // 活动类型 ID(必填)
1968
+ bulk_create: "true"
1969
+ // 固定为 true
1554
1970
  };
1555
1971
  if (options.comments) params.comments = options.comments;
1556
1972
  const result = await timeEntryService.createTimeEntry(params);
1557
1973
  if (result.success && result.data) {
1558
- outputSuccess(result.data);
1974
+ outputSuccess(result.data, options.pretty);
1559
1975
  } else {
1560
- outputError(result.message || result.msg || result.api_error_msg || "\u521B\u5EFA\u5DE5\u65F6\u5931\u8D25");
1976
+ outputError(result.message || result.msg || result.api_error_msg || "\u521B\u5EFA\u5DE5\u65F6\u5931\u8D25", options.pretty);
1561
1977
  process.exit(1);
1562
1978
  }
1563
1979
  });
1564
- timeCmd.command("update <id>").description("\u66F4\u65B0\u5DE5\u65F6\u6761\u76EE").requiredOption("--issue <id>", "\u95EE\u9898 ID\uFF08\u5FC5\u586B\uFF09").requiredOption("--days <days>", "\u5DE5\u65F6\uFF08\u5929\uFF09\uFF08\u5FC5\u586B\uFF09").requiredOption("--activity <id>", "\u6D3B\u52A8\u7C7B\u578B ID\uFF08\u5FC5\u586B\uFF09").requiredOption("--date <date>", "\u65E5\u671F (YYYY-MM-DD)\uFF08\u5FC5\u586B\uFF09").option("--comments <comments>", "\u5907\u6CE8").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (id, options) => {
1980
+ timeCmd.command("update <id>").description("\u66F4\u65B0\u5DE5\u65F6\u6761\u76EE").requiredOption("--issue <id>", "\u95EE\u9898 ID\uFF08\u5FC5\u586B\uFF09").requiredOption("--days <days>", "\u5DE5\u65F6\uFF08\u5929\uFF09\uFF08\u5FC5\u586B\uFF09").requiredOption("--activity <id>", "\u6D3B\u52A8\u7C7B\u578B ID\uFF08\u5FC5\u586B\uFF09").requiredOption("--date <date>", "\u65E5\u671F (YYYY-MM-DD)\uFF08\u5FC5\u586B\uFF09").option("--comments <comments>", "\u5907\u6CE8").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (id, options) => {
1565
1981
  const creds = resolveCredentials(options);
1566
1982
  const validation = validateCredentials(creds);
1567
1983
  if (!validation.valid) {
1568
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
1984
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1569
1985
  process.exit(1);
1570
1986
  }
1571
1987
  let userId;
@@ -1574,17 +1990,17 @@ function createTimeCommand() {
1574
1990
  userId = parseInt(configUserId, 10);
1575
1991
  }
1576
1992
  if (!userId) {
1577
- outputError("\u7F3A\u5C11\u7528\u6237 ID\uFF0C\u8BF7\u5148\u8BBE\u7F6E: pm-cli config set user-id <\u60A8\u7684\u7528\u6237ID>");
1993
+ outputError("\u7F3A\u5C11\u7528\u6237 ID\uFF0C\u8BF7\u5148\u8BBE\u7F6E: pm-cli config set user-id <\u60A8\u7684\u7528\u6237ID>", options.pretty);
1578
1994
  process.exit(1);
1579
1995
  }
1580
1996
  const timeEntryId = parseInt(id, 10);
1581
1997
  if (isNaN(timeEntryId)) {
1582
- outputError("\u65E0\u6548\u7684\u5DE5\u65F6\u6761\u76EE ID");
1998
+ outputError("\u65E0\u6548\u7684\u5DE5\u65F6\u6761\u76EE ID", options.pretty);
1583
1999
  process.exit(1);
1584
2000
  }
1585
2001
  const issueId = parseInt(options.issue.replace(/^#/, ""), 10);
1586
2002
  if (isNaN(issueId)) {
1587
- outputError("\u65E0\u6548\u7684\u95EE\u9898 ID");
2003
+ outputError("\u65E0\u6548\u7684\u95EE\u9898 ID", options.pretty);
1588
2004
  process.exit(1);
1589
2005
  }
1590
2006
  const params = {
@@ -1609,22 +2025,22 @@ function createTimeCommand() {
1609
2025
  if (options.comments) params.comments = options.comments;
1610
2026
  const result = await timeEntryService.updateTimeEntry(params);
1611
2027
  if (result.success && result.data) {
1612
- outputSuccess(result.data);
2028
+ outputSuccess(result.data, options.pretty);
1613
2029
  } else {
1614
- outputError(result.message || result.msg || result.api_error_msg || "\u66F4\u65B0\u5DE5\u65F6\u5931\u8D25");
2030
+ outputError(result.message || result.msg || result.api_error_msg || "\u66F4\u65B0\u5DE5\u65F6\u5931\u8D25", options.pretty);
1615
2031
  process.exit(1);
1616
2032
  }
1617
2033
  });
1618
- timeCmd.command("delete <id>").description("\u5220\u9664\u5DE5\u65F6\u6761\u76EE").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (id, options) => {
2034
+ timeCmd.command("delete <id>").description("\u5220\u9664\u5DE5\u65F6\u6761\u76EE").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (id, options) => {
1619
2035
  const creds = resolveCredentials(options);
1620
2036
  const validation = validateCredentials(creds, ["token", "host"]);
1621
2037
  if (!validation.valid) {
1622
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
2038
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1623
2039
  process.exit(1);
1624
2040
  }
1625
2041
  const timeEntryId = parseInt(id, 10);
1626
2042
  if (isNaN(timeEntryId)) {
1627
- outputError("\u65E0\u6548\u7684\u5DE5\u65F6\u6761\u76EE ID");
2043
+ outputError("\u65E0\u6548\u7684\u5DE5\u65F6\u6761\u76EE ID", options.pretty);
1628
2044
  process.exit(1);
1629
2045
  }
1630
2046
  const result = await timeEntryService.deleteTimeEntry(
@@ -1633,17 +2049,17 @@ function createTimeCommand() {
1633
2049
  timeEntryId
1634
2050
  );
1635
2051
  if (result.success) {
1636
- outputSuccess({ message: "\u5DE5\u65F6\u6761\u76EE\u5DF2\u5220\u9664", id: timeEntryId });
2052
+ outputSuccess({ message: "\u5DE5\u65F6\u6761\u76EE\u5DF2\u5220\u9664", id: timeEntryId }, options.pretty);
1637
2053
  } else {
1638
- outputError(result.message || result.msg || result.api_error_msg || "\u5220\u9664\u5DE5\u65F6\u5931\u8D25");
2054
+ outputError(result.message || result.msg || result.api_error_msg || "\u5220\u9664\u5DE5\u65F6\u5931\u8D25", options.pretty);
1639
2055
  process.exit(1);
1640
2056
  }
1641
2057
  });
1642
- timeCmd.command("options").description("\u83B7\u53D6\u5DE5\u65F6\u6761\u76EE\u9009\u9879\uFF08\u6D3B\u52A8\u7C7B\u578B\u5217\u8868\u7B49\uFF09").option("--issue <id>", "\u95EE\u9898 ID\uFF08\u53EF\u9009\uFF0C\u7528\u4E8E\u83B7\u53D6\u7279\u5B9A\u95EE\u9898\u7684\u5DE5\u65F6\u9009\u9879\uFF09").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (options) => {
2058
+ timeCmd.command("options").description("\u83B7\u53D6\u5DE5\u65F6\u6761\u76EE\u9009\u9879\uFF08\u6D3B\u52A8\u7C7B\u578B\u5217\u8868\u7B49\uFF09").option("--issue <id>", "\u95EE\u9898 ID\uFF08\u53EF\u9009\uFF0C\u7528\u4E8E\u83B7\u53D6\u7279\u5B9A\u95EE\u9898\u7684\u5DE5\u65F6\u9009\u9879\uFF09").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (options) => {
1643
2059
  const creds = resolveCredentials(options);
1644
2060
  const validation = validateCredentials(creds);
1645
2061
  if (!validation.valid) {
1646
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
2062
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1647
2063
  process.exit(1);
1648
2064
  }
1649
2065
  const issueId = options.issue ? parseInt(options.issue.replace(/^#/, ""), 10) : void 0;
@@ -1657,20 +2073,20 @@ function createTimeCommand() {
1657
2073
  const data = result.data;
1658
2074
  if (data.options?.activities) {
1659
2075
  const activities = data.options.activities.map(([name, id]) => ({ id, name }));
1660
- outputSuccess({ activities });
2076
+ outputSuccess({ activities }, options.pretty);
1661
2077
  } else {
1662
- outputSuccess(result.data);
2078
+ outputSuccess(result.data, options.pretty);
1663
2079
  }
1664
2080
  } else {
1665
- outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u9009\u9879\u5931\u8D25");
2081
+ outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u9009\u9879\u5931\u8D25", options.pretty);
1666
2082
  process.exit(1);
1667
2083
  }
1668
2084
  });
1669
- timeCmd.command("summary").description("\u5DE5\u65F6\u7EDF\u8BA1\u6C47\u603B\uFF08\u67E5\u8BE2\u6307\u5B9A\u65F6\u95F4\u6BB5\u7684\u5DE5\u65F6\u5E76\u8BA1\u7B97\u7F3A\u53E3\uFF09").option("--week <week>", "\u5468\u9009\u62E9: current (\u672C\u5468), last (\u4E0A\u5468), \u6216\u6570\u5B57\u504F\u79FB", "current").option("--from <date>", "\u5F00\u59CB\u65E5\u671F (YYYY-MM-DD)\uFF0C\u4E0E --week \u4E92\u65A5").option("--to <date>", "\u7ED3\u675F\u65E5\u671F (YYYY-MM-DD)\uFF0C\u4E0E --week \u4E92\u65A5").option("--target <days>", "\u76EE\u6807\u5DE5\u65F6\uFF08\u5929\uFF09\uFF0C\u9ED8\u8BA4 5", "5").option("--detail", "\u663E\u793A\u5B8C\u6574\u5DE5\u65F6\u6761\u76EE\u8BE6\u60C5").option("--user-id <id>", "\u7528\u6237 ID\uFF08\u9ED8\u8BA4\u4F7F\u7528\u914D\u7F6E\u4E2D\u7684 user-id\uFF09").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (options) => {
2085
+ timeCmd.command("summary").description("\u5DE5\u65F6\u7EDF\u8BA1\u6C47\u603B\uFF08\u67E5\u8BE2\u6307\u5B9A\u65F6\u95F4\u6BB5\u7684\u5DE5\u65F6\u5E76\u8BA1\u7B97\u7F3A\u53E3\uFF09").option("--week <week>", "\u5468\u9009\u62E9: current (\u672C\u5468), last (\u4E0A\u5468), \u6216\u6570\u5B57\u504F\u79FB", "current").option("--from <date>", "\u5F00\u59CB\u65E5\u671F (YYYY-MM-DD)\uFF0C\u4E0E --week \u4E92\u65A5").option("--to <date>", "\u7ED3\u675F\u65E5\u671F (YYYY-MM-DD)\uFF0C\u4E0E --week \u4E92\u65A5").option("--target <days>", "\u76EE\u6807\u5DE5\u65F6\uFF08\u5929\uFF09\uFF0C\u9ED8\u8BA4 5", "5").option("--detail", "\u663E\u793A\u5B8C\u6574\u5DE5\u65F6\u6761\u76EE\u8BE6\u60C5").option("--user-id <id>", "\u7528\u6237 ID\uFF08\u9ED8\u8BA4\u4F7F\u7528\u914D\u7F6E\u4E2D\u7684 user-id\uFF09").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (options) => {
1670
2086
  const creds = resolveCredentials(options);
1671
2087
  const validation = validateCredentials(creds, ["token", "host"]);
1672
2088
  if (!validation.valid) {
1673
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
2089
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1674
2090
  process.exit(1);
1675
2091
  }
1676
2092
  let fromDate;
@@ -1701,7 +2117,7 @@ function createTimeCommand() {
1701
2117
  }
1702
2118
  const projectsResult = await userService.getProjects(creds.token, creds.host);
1703
2119
  if (!projectsResult.success || !projectsResult.data) {
1704
- outputError(projectsResult.message || projectsResult.msg || projectsResult.api_error_msg || "\u83B7\u53D6\u9879\u76EE\u5217\u8868\u5931\u8D25");
2120
+ outputError(projectsResult.message || projectsResult.msg || projectsResult.api_error_msg || "\u83B7\u53D6\u9879\u76EE\u5217\u8868\u5931\u8D25", options.pretty);
1705
2121
  process.exit(1);
1706
2122
  }
1707
2123
  const projects = projectsResult.data;
@@ -1754,7 +2170,7 @@ function createTimeCommand() {
1754
2170
  return dateA.localeCompare(dateB);
1755
2171
  });
1756
2172
  }
1757
- outputSuccess(output);
2173
+ outputSuccess(output, options.pretty);
1758
2174
  });
1759
2175
  return timeCmd;
1760
2176
  }
@@ -1763,26 +2179,26 @@ function createTimeCommand() {
1763
2179
  import { Command as Command5 } from "commander";
1764
2180
  function createProjectCommand() {
1765
2181
  const projectCmd = new Command5("project").description("\u9879\u76EE\u7BA1\u7406");
1766
- projectCmd.command("list").description("\u83B7\u53D6\u9879\u76EE\u5217\u8868").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (options) => {
2182
+ projectCmd.command("list").description("\u83B7\u53D6\u9879\u76EE\u5217\u8868").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (options) => {
1767
2183
  const creds = resolveCredentials(options);
1768
2184
  const validation = validateCredentials(creds, ["token", "host"]);
1769
2185
  if (!validation.valid) {
1770
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
2186
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1771
2187
  process.exit(1);
1772
2188
  }
1773
2189
  const result = await userService.getProjects(creds.token, creds.host);
1774
2190
  if (result.success && result.data) {
1775
- outputSuccess(result.data);
2191
+ outputSuccess(result.data, options.pretty);
1776
2192
  } else {
1777
- outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u9879\u76EE\u5217\u8868\u5931\u8D25");
2193
+ outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u9879\u76EE\u5217\u8868\u5931\u8D25", options.pretty);
1778
2194
  process.exit(1);
1779
2195
  }
1780
2196
  });
1781
- projectCmd.command("users").description("\u83B7\u53D6\u9879\u76EE\u7528\u6237\u5217\u8868").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (options) => {
2197
+ projectCmd.command("users").description("\u83B7\u53D6\u9879\u76EE\u7528\u6237\u5217\u8868").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (options) => {
1782
2198
  const creds = resolveCredentials(options);
1783
2199
  const validation = validateCredentials(creds);
1784
2200
  if (!validation.valid) {
1785
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
2201
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1786
2202
  process.exit(1);
1787
2203
  }
1788
2204
  const result = await userService.getProjectUsers(
@@ -1791,24 +2207,24 @@ function createProjectCommand() {
1791
2207
  creds.project
1792
2208
  );
1793
2209
  if (result.success && result.data) {
1794
- outputSuccess(result.data);
2210
+ outputSuccess(result.data, options.pretty);
1795
2211
  } else {
1796
- outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u7528\u6237\u5217\u8868\u5931\u8D25");
2212
+ outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u7528\u6237\u5217\u8868\u5931\u8D25", options.pretty);
1797
2213
  process.exit(1);
1798
2214
  }
1799
2215
  });
1800
- projectCmd.command("info").description("\u83B7\u53D6\u4E3B\u673A\u4FE1\u606F").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (options) => {
2216
+ projectCmd.command("info").description("\u83B7\u53D6\u4E3B\u673A\u4FE1\u606F").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--profile <name>", "\u4F7F\u7528\u914D\u7F6E profile").option("--config <path>", "\u81EA\u5B9A\u4E49\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09").action(async (options) => {
1801
2217
  const creds = resolveCredentials(options);
1802
2218
  const validation = validateCredentials(creds, ["token", "host"]);
1803
2219
  if (!validation.valid) {
1804
- outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`);
2220
+ outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
1805
2221
  process.exit(1);
1806
2222
  }
1807
2223
  const result = await userService.getHostInfo(creds.token, creds.host);
1808
2224
  if (result.success) {
1809
- outputSuccess(result.data);
2225
+ outputSuccess(result.data, options.pretty);
1810
2226
  } else {
1811
- outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u4E3B\u673A\u4FE1\u606F\u5931\u8D25");
2227
+ outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u4E3B\u673A\u4FE1\u606F\u5931\u8D25", options.pretty);
1812
2228
  process.exit(1);
1813
2229
  }
1814
2230
  });
@@ -1816,8 +2232,15 @@ function createProjectCommand() {
1816
2232
  }
1817
2233
 
1818
2234
  // src/index.ts
2235
+ import { readFileSync as readFileSync2 } from "fs";
2236
+ import { dirname as dirname2, join as join2 } from "path";
2237
+ import { fileURLToPath } from "url";
2238
+ var __filename = fileURLToPath(import.meta.url);
2239
+ var __dirname = dirname2(__filename);
2240
+ var packageJson = JSON.parse(readFileSync2(join2(__dirname, "../package.json"), "utf-8"));
2241
+ var version = packageJson.version;
1819
2242
  var program = new Command6();
1820
- program.name("pm-cli").description("\u7F51\u6613\u6613\u534F\u4F5C (PM NetEase) \u547D\u4EE4\u884C\u5DE5\u5177").version("0.1.0").option("--verbose", "\u8BE6\u7EC6\u8F93\u51FA").option("--debug", "\u8C03\u8BD5\u6A21\u5F0F").option("--no-mapping", "\u4E0D\u8F93\u51FA key \u6620\u5C04\u8868\uFF08\u9ED8\u8BA4\u8F93\u51FA\uFF09").hook("preAction", (thisCommand) => {
2243
+ program.name("pm-cli").description("\u7F51\u6613\u6613\u534F\u4F5C (PM NetEase) \u547D\u4EE4\u884C\u5DE5\u5177").version(version).option("--verbose", "\u8BE6\u7EC6\u8F93\u51FA").option("--debug", "\u8C03\u8BD5\u6A21\u5F0F").option("--no-mapping", "\u4E0D\u8F93\u51FA key \u6620\u5C04\u8868\uFF08\u9ED8\u8BA4\u8F93\u51FA\uFF09").hook("preAction", (thisCommand) => {
1821
2244
  const opts = thisCommand.opts();
1822
2245
  if (opts.debug) {
1823
2246
  logger_default.setLevel("debug");