@hangox/pm-cli 1.1.2 → 1.1.4

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
@@ -530,6 +530,9 @@ function outputError(error, pretty = false) {
530
530
  const finalResult = addKeyMappingToResult(result);
531
531
  console.log(JSON.stringify(finalResult, null, pretty ? 2 : 0));
532
532
  }
533
+ function extractErrorMessage(result, defaultMsg = "\u64CD\u4F5C\u5931\u8D25") {
534
+ return result.post_error_msg || result.api_error_msg || result.message || result.msg || defaultMsg;
535
+ }
533
536
 
534
537
  // src/commands/test.ts
535
538
  function createTestCommand() {
@@ -553,7 +556,7 @@ function createTestCommand() {
553
556
  data: result.data
554
557
  }, options.pretty);
555
558
  } else {
556
- outputError(result.message || result.msg || result.api_error_msg || "\u8FDE\u63A5\u5931\u8D25", options.pretty);
559
+ outputError(extractErrorMessage(result, "\u8FDE\u63A5\u5931\u8D25"), options.pretty);
557
560
  process.exit(1);
558
561
  }
559
562
  });
@@ -1168,7 +1171,7 @@ var IssueService = class {
1168
1171
  return {
1169
1172
  id: issueId,
1170
1173
  success: false,
1171
- error: result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u5931\u8D25"
1174
+ error: result.post_error_msg || result.api_error_msg || result.message || result.msg || "\u83B7\u53D6\u5931\u8D25"
1172
1175
  };
1173
1176
  }
1174
1177
  } catch (error) {
@@ -1351,6 +1354,23 @@ var IssueService = class {
1351
1354
  }
1352
1355
  }
1353
1356
  }
1357
+ } else if (field.field_format === "user") {
1358
+ if (field.multiple && Array.isArray(field.value)) {
1359
+ const userIds = [];
1360
+ for (const item of field.value) {
1361
+ if (item.user?.id) {
1362
+ userIds.push(item.user.id);
1363
+ }
1364
+ }
1365
+ if (userIds.length > 0) {
1366
+ customFieldMap[field.id] = userIds.join(",");
1367
+ }
1368
+ } else {
1369
+ const userValue = field.value;
1370
+ if (userValue.user?.id) {
1371
+ customFieldMap[field.id] = userValue.user.id;
1372
+ }
1373
+ }
1354
1374
  } else {
1355
1375
  customFieldMap[field.id] = field.value;
1356
1376
  }
@@ -1420,7 +1440,7 @@ var IssueService = class {
1420
1440
  );
1421
1441
  }
1422
1442
  } else {
1423
- const errorMsg = createResult.message || createResult.api_error_msg || "\u521B\u5EFA\u5931\u8D25";
1443
+ const errorMsg = createResult.post_error_msg || createResult.api_error_msg || createResult.message || "\u521B\u5EFA\u5931\u8D25";
1424
1444
  logger_default.error(`\u274C \u521B\u5EFA\u5B50\u4EFB\u52A1\u5931\u8D25: ${taskName}`, errorMsg);
1425
1445
  result.totalFailed++;
1426
1446
  result.failed.push({
@@ -1455,7 +1475,7 @@ var IssueService = class {
1455
1475
  * @param options 选项
1456
1476
  */
1457
1477
  async batchCreateFromMarkdown(token, host, project, parentId, markdown, assignedToMail, options) {
1458
- const { dryRun = false, interval = 5e3 } = options || {};
1478
+ const { dryRun = false, interval = 5e3, extraCustomFields = {} } = options || {};
1459
1479
  logger_default.info("\u5F00\u59CB\u6279\u91CF\u521B\u5EFA\u5B50\u5355", {
1460
1480
  parentId,
1461
1481
  assignedToMail,
@@ -1504,7 +1524,8 @@ var IssueService = class {
1504
1524
  assignedToMail,
1505
1525
  dryRun,
1506
1526
  interval,
1507
- result
1527
+ result,
1528
+ extraCustomFields
1508
1529
  );
1509
1530
  logger_default.info("\u6279\u91CF\u521B\u5EFA\u5B8C\u6210", {
1510
1531
  totalCreated: result.totalCreated,
@@ -1522,7 +1543,7 @@ var IssueService = class {
1522
1543
  /**
1523
1544
  * 递归批量创建子单
1524
1545
  */
1525
- async batchCreateRecursive(token, host, project, taskNodes, targetParentId, parentInfo, assignedToMail, dryRun, interval, result) {
1546
+ async batchCreateRecursive(token, host, project, taskNodes, targetParentId, parentInfo, assignedToMail, dryRun, interval, result, extraCustomFields = {}) {
1526
1547
  for (const node of taskNodes) {
1527
1548
  const taskName = node.subject;
1528
1549
  const isLeafNode = node.children.length === 0;
@@ -1559,19 +1580,40 @@ var IssueService = class {
1559
1580
  }
1560
1581
  }
1561
1582
  }
1583
+ } else if (field.field_format === "user") {
1584
+ if (field.multiple && Array.isArray(field.value)) {
1585
+ const userIds = [];
1586
+ for (const item of field.value) {
1587
+ if (item.user?.id) {
1588
+ userIds.push(item.user.id);
1589
+ }
1590
+ }
1591
+ if (userIds.length > 0) {
1592
+ customFieldMap[field.id] = userIds.join(",");
1593
+ }
1594
+ } else {
1595
+ const userValue = field.value;
1596
+ if (userValue.user?.id) {
1597
+ customFieldMap[field.id] = userValue.user.id;
1598
+ }
1599
+ }
1562
1600
  } else {
1563
1601
  customFieldMap[field.id] = field.value;
1564
1602
  }
1565
1603
  }
1566
1604
  }
1567
- if (Object.keys(customFieldMap).length > 0) {
1568
- createParams.custom_field = JSON.stringify(customFieldMap);
1605
+ const mergedCustomFields = { ...customFieldMap, ...extraCustomFields };
1606
+ if (Object.keys(mergedCustomFields).length > 0) {
1607
+ createParams.custom_field = JSON.stringify(mergedCustomFields);
1569
1608
  }
1570
1609
  if (followsMails.length > 0) {
1571
1610
  createParams.follows = followsMails;
1572
1611
  }
1612
+ } else if (Object.keys(extraCustomFields).length > 0) {
1613
+ createParams.custom_field = JSON.stringify(extraCustomFields);
1573
1614
  }
1574
1615
  logger_default.info(`\u6B63\u5728\u521B\u5EFA\u5B50\u4EFB\u52A1: ${taskName}`, { targetParentId, isLeafNode, estimatedHours: node.estimatedHours });
1616
+ logger_default.debug("\u521B\u5EFA\u53C2\u6570", { custom_field: createParams.custom_field, follows: createParams.follows });
1575
1617
  if (dryRun) {
1576
1618
  logger_default.info(`[\u6A21\u62DF] \u5C06\u521B\u5EFA\u5B50\u4EFB\u52A1: ${taskName}`);
1577
1619
  result.totalCreated++;
@@ -1594,7 +1636,8 @@ var IssueService = class {
1594
1636
  assignedToMail,
1595
1637
  dryRun,
1596
1638
  interval,
1597
- result
1639
+ result,
1640
+ extraCustomFields
1598
1641
  );
1599
1642
  }
1600
1643
  } else {
@@ -1624,11 +1667,12 @@ var IssueService = class {
1624
1667
  assignedToMail,
1625
1668
  dryRun,
1626
1669
  interval,
1627
- result
1670
+ result,
1671
+ extraCustomFields
1628
1672
  );
1629
1673
  }
1630
1674
  } else {
1631
- const errorMsg = createResult.message || createResult.api_error_msg || "\u521B\u5EFA\u5931\u8D25";
1675
+ const errorMsg = createResult.post_error_msg || createResult.api_error_msg || createResult.message || "\u521B\u5EFA\u5931\u8D25";
1632
1676
  logger_default.error(`\u274C \u521B\u5EFA\u5B50\u4EFB\u52A1\u5931\u8D25: ${taskName}`, errorMsg);
1633
1677
  result.totalFailed++;
1634
1678
  result.failed.push({
@@ -1856,6 +1900,74 @@ function generateAIGuideOutput(exportDir, fileCount, totalSize) {
1856
1900
  `.trim();
1857
1901
  }
1858
1902
 
1903
+ // src/utils/custom-field-parser.ts
1904
+ var issueService2 = new IssueService();
1905
+ async function parseCustomFieldInputs(customFieldInputs, token, host, project) {
1906
+ if (customFieldInputs.length === 0) {
1907
+ return { fields: {} };
1908
+ }
1909
+ const customFieldData = {};
1910
+ for (const input of customFieldInputs) {
1911
+ const match = input.match(/^([^=]+)=(.*)$/);
1912
+ if (!match) {
1913
+ return {
1914
+ fields: {},
1915
+ error: `\u81EA\u5B9A\u4E49\u5B57\u6BB5\u683C\u5F0F\u9519\u8BEF: ${input}\uFF0C\u6B63\u786E\u683C\u5F0F\u4E3A "\u5B57\u6BB5ID=\u503C" \u6216 "\u5B57\u6BB5\u540D=\u503C"`
1916
+ };
1917
+ }
1918
+ const [, key, value] = match;
1919
+ customFieldData[key.trim()] = value.trim();
1920
+ }
1921
+ const hasNonNumericKey = Object.keys(customFieldData).some((key) => isNaN(Number(key)));
1922
+ if (hasNonNumericKey) {
1923
+ const fieldOptionsResult = await issueService2.getIssueFieldOptions(token, host, project);
1924
+ if (fieldOptionsResult.success && fieldOptionsResult.data) {
1925
+ const fieldOptions = fieldOptionsResult.data;
1926
+ if (fieldOptions.data?.custom_fields) {
1927
+ const fieldMap = /* @__PURE__ */ new Map();
1928
+ for (const field of fieldOptions.data.custom_fields) {
1929
+ fieldMap.set(field.name, field.id);
1930
+ }
1931
+ const convertedData = {};
1932
+ for (const [key, value] of Object.entries(customFieldData)) {
1933
+ const fieldId = isNaN(Number(key)) ? fieldMap.get(key) : Number(key);
1934
+ if (fieldId !== void 0) {
1935
+ convertedData[fieldId] = value;
1936
+ } else {
1937
+ return { fields: {}, error: `\u672A\u627E\u5230\u81EA\u5B9A\u4E49\u5B57\u6BB5: ${key}` };
1938
+ }
1939
+ }
1940
+ return { fields: convertedData };
1941
+ } else {
1942
+ return { fields: {}, error: "\u65E0\u6CD5\u83B7\u53D6\u81EA\u5B9A\u4E49\u5B57\u6BB5\u5217\u8868" };
1943
+ }
1944
+ } else {
1945
+ return { fields: {}, error: "\u83B7\u53D6\u81EA\u5B9A\u4E49\u5B57\u6BB5\u5217\u8868\u5931\u8D25" };
1946
+ }
1947
+ } else {
1948
+ const convertedData = {};
1949
+ for (const [key, value] of Object.entries(customFieldData)) {
1950
+ convertedData[Number(key)] = value;
1951
+ }
1952
+ return { fields: convertedData };
1953
+ }
1954
+ }
1955
+ function collectCustomFieldInputs(options) {
1956
+ const customFieldInputs = [];
1957
+ if (options.customField) {
1958
+ customFieldInputs.push(
1959
+ ...Array.isArray(options.customField) ? options.customField : [options.customField]
1960
+ );
1961
+ }
1962
+ if (options.cf) {
1963
+ customFieldInputs.push(...Array.isArray(options.cf) ? options.cf : [options.cf]);
1964
+ }
1965
+ return customFieldInputs;
1966
+ }
1967
+ function mergeCustomFields(inheritedFields, userFields) {
1968
+ return { ...inheritedFields, ...userFields };
1969
+ }
1970
+
1859
1971
  // src/commands/issue/index.ts
1860
1972
  function createIssueCommand() {
1861
1973
  const issueCmd = new Command3("issue").description("\u95EE\u9898\u7BA1\u7406");
@@ -1926,7 +2038,7 @@ function createIssueCommand() {
1926
2038
  }
1927
2039
  }
1928
2040
  } else {
1929
- outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u95EE\u9898\u5931\u8D25", options.pretty);
2041
+ outputError(extractErrorMessage(result, "\u83B7\u53D6\u95EE\u9898\u5931\u8D25"), options.pretty);
1930
2042
  process.exit(1);
1931
2043
  }
1932
2044
  } else {
@@ -1947,12 +2059,12 @@ function createIssueCommand() {
1947
2059
  pretty: options.pretty
1948
2060
  });
1949
2061
  } else {
1950
- outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u95EE\u9898\u5931\u8D25", options.pretty);
2062
+ outputError(extractErrorMessage(result, "\u83B7\u53D6\u95EE\u9898\u5931\u8D25"), options.pretty);
1951
2063
  process.exit(1);
1952
2064
  }
1953
2065
  }
1954
2066
  });
1955
- 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) => {
2067
+ 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("--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("--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) => {
1956
2068
  const creds = resolveCredentials(options);
1957
2069
  const validation = validateCredentials(creds);
1958
2070
  if (!validation.valid) {
@@ -1995,8 +2107,8 @@ function createIssueCommand() {
1995
2107
  const followsMails = [];
1996
2108
  for (const field of parent.custom_fields) {
1997
2109
  if (field.value !== null && field.value !== void 0 && field.value !== "") {
1998
- const fieldWithIdentify = field;
1999
- if (fieldWithIdentify.identify === "IssuesQCFollow") {
2110
+ const fieldWithMeta = field;
2111
+ if (fieldWithMeta.identify === "IssuesQCFollow") {
2000
2112
  const followsValue = field.value;
2001
2113
  if (Array.isArray(followsValue)) {
2002
2114
  for (const item of followsValue) {
@@ -2005,6 +2117,23 @@ function createIssueCommand() {
2005
2117
  }
2006
2118
  }
2007
2119
  }
2120
+ } else if (fieldWithMeta.field_format === "user") {
2121
+ if (fieldWithMeta.multiple && Array.isArray(field.value)) {
2122
+ const userIds = [];
2123
+ for (const item of field.value) {
2124
+ if (item.user?.id) {
2125
+ userIds.push(item.user.id);
2126
+ }
2127
+ }
2128
+ if (userIds.length > 0) {
2129
+ customFieldMap[field.id] = userIds.join(",");
2130
+ }
2131
+ } else {
2132
+ const userValue = field.value;
2133
+ if (userValue.user?.id) {
2134
+ customFieldMap[field.id] = userValue.user.id;
2135
+ }
2136
+ }
2008
2137
  } else {
2009
2138
  customFieldMap[field.id] = field.value;
2010
2139
  }
@@ -2033,11 +2162,29 @@ function createIssueCommand() {
2033
2162
  if (options.startDate) params.start_date = options.startDate;
2034
2163
  if (options.dueDate) params.due_date = options.dueDate;
2035
2164
  if (options.estimatedHours) params.estimated_hours = parseFloat(options.estimatedHours);
2165
+ const customFieldInputs = collectCustomFieldInputs(options);
2166
+ if (customFieldInputs.length > 0) {
2167
+ const parseResult = await parseCustomFieldInputs(
2168
+ customFieldInputs,
2169
+ creds.token,
2170
+ creds.host,
2171
+ creds.project
2172
+ );
2173
+ if (parseResult.error) {
2174
+ outputError(parseResult.error, options.pretty);
2175
+ process.exit(1);
2176
+ }
2177
+ const existingFields = params.custom_field ? JSON.parse(params.custom_field) : {};
2178
+ const mergedFields = mergeCustomFields(existingFields, parseResult.fields);
2179
+ if (Object.keys(mergedFields).length > 0) {
2180
+ params.custom_field = JSON.stringify(mergedFields);
2181
+ }
2182
+ }
2036
2183
  const result = await issueService.createIssue(params);
2037
2184
  if (result.success && result.data) {
2038
2185
  outputSuccess(result.data, options.pretty);
2039
2186
  } else {
2040
- outputError(result.message || result.msg || result.api_error_msg || "\u521B\u5EFA\u95EE\u9898\u5931\u8D25", options.pretty);
2187
+ outputError(extractErrorMessage(result, "\u521B\u5EFA\u95EE\u9898\u5931\u8D25"), options.pretty);
2041
2188
  process.exit(1);
2042
2189
  }
2043
2190
  });
@@ -2156,7 +2303,7 @@ function createIssueCommand() {
2156
2303
  if (result.success && result.data) {
2157
2304
  outputSuccess(result.data, options.pretty);
2158
2305
  } else {
2159
- outputError(result.message || result.msg || result.api_error_msg || "\u66F4\u65B0\u95EE\u9898\u5931\u8D25", options.pretty);
2306
+ outputError(extractErrorMessage(result, "\u66F4\u65B0\u95EE\u9898\u5931\u8D25"), options.pretty);
2160
2307
  process.exit(1);
2161
2308
  }
2162
2309
  });
@@ -2181,7 +2328,7 @@ function createIssueCommand() {
2181
2328
  if (result.success && result.data) {
2182
2329
  outputSuccess(result.data, options.pretty);
2183
2330
  } else {
2184
- outputError(result.message || result.msg || result.api_error_msg || "\u67E5\u8BE2\u5931\u8D25", options.pretty);
2331
+ outputError(extractErrorMessage(result, "\u67E5\u8BE2\u5931\u8D25"), options.pretty);
2185
2332
  process.exit(1);
2186
2333
  }
2187
2334
  });
@@ -2208,7 +2355,7 @@ function createIssueCommand() {
2208
2355
  if (result.success && result.data) {
2209
2356
  outputSuccess(result.data, options.pretty);
2210
2357
  } else {
2211
- outputError(result.message || result.msg || result.api_error_msg || "\u67E5\u8BE2\u5931\u8D25", options.pretty);
2358
+ outputError(extractErrorMessage(result, "\u67E5\u8BE2\u5931\u8D25"), options.pretty);
2212
2359
  process.exit(1);
2213
2360
  }
2214
2361
  });
@@ -2227,7 +2374,7 @@ function createIssueCommand() {
2227
2374
  if (result.success) {
2228
2375
  outputSuccess(result.data, options.pretty);
2229
2376
  } else {
2230
- outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u5B57\u6BB5\u9009\u9879\u5931\u8D25", options.pretty);
2377
+ outputError(extractErrorMessage(result, "\u83B7\u53D6\u5B57\u6BB5\u9009\u9879\u5931\u8D25"), options.pretty);
2231
2378
  process.exit(1);
2232
2379
  }
2233
2380
  });
@@ -2305,7 +2452,7 @@ function createIssueCommand() {
2305
2452
  outputSuccess(result.data, options.pretty);
2306
2453
  }
2307
2454
  } else {
2308
- outputError(result.message || result.msg || result.api_error_msg || "\u67E5\u8BE2\u5B50\u4EFB\u52A1\u5931\u8D25", options.pretty);
2455
+ outputError(extractErrorMessage(result, "\u67E5\u8BE2\u5B50\u4EFB\u52A1\u5931\u8D25"), options.pretty);
2309
2456
  process.exit(1);
2310
2457
  }
2311
2458
  });
@@ -2361,7 +2508,7 @@ function createIssueCommand() {
2361
2508
  pretty: options.pretty
2362
2509
  });
2363
2510
  } else {
2364
- outputError(result.message || result.msg || result.api_error_msg || "\u6279\u91CF\u83B7\u53D6\u95EE\u9898\u5931\u8D25", options.pretty);
2511
+ outputError(extractErrorMessage(result, "\u6279\u91CF\u83B7\u53D6\u95EE\u9898\u5931\u8D25"), options.pretty);
2365
2512
  process.exit(1);
2366
2513
  }
2367
2514
  });
@@ -2467,11 +2614,11 @@ function createIssueCommand() {
2467
2614
  pretty: options.pretty
2468
2615
  });
2469
2616
  } else {
2470
- outputError(result.message || result.msg || result.api_error_msg || "\u540C\u6B65\u5B50\u5355\u5931\u8D25", options.pretty);
2617
+ outputError(extractErrorMessage(result, "\u540C\u6B65\u5B50\u5355\u5931\u8D25"), options.pretty);
2471
2618
  process.exit(1);
2472
2619
  }
2473
2620
  });
2474
- issueCmd.command("batch-create").description("\u4ECE Markdown \u6279\u91CF\u521B\u5EFA\u5B50\u5355").option("--parent-id <id>", "\u7236\u5355 ID").option("--parent-url <url>", "\u7236\u5355 PM \u94FE\u63A5").option("--markdown <file>", "Markdown \u6587\u4EF6\u8DEF\u5F84").option("--stdin", "\u4ECE\u6807\u51C6\u8F93\u5165\u8BFB\u53D6 Markdown").option("--assigned-to-mail <email>", "\u6307\u6D3E\u4EBA\u90AE\u7BB1\uFF08\u9ED8\u8BA4\u4F7F\u7528\u914D\u7F6E\u7684 userMail\uFF09").option("--interval <ms>", "\u521B\u5EFA\u95F4\u9694\uFF08\u6BEB\u79D2\uFF09", "5000").option("--dry-run", "\u6A21\u62DF\u8FD0\u884C\uFF0C\u4E0D\u5B9E\u9645\u521B\u5EFA").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) => {
2621
+ issueCmd.command("batch-create").description("\u4ECE Markdown \u6279\u91CF\u521B\u5EFA\u5B50\u5355").option("--parent-id <id>", "\u7236\u5355 ID").option("--parent-url <url>", "\u7236\u5355 PM \u94FE\u63A5").option("--markdown <file>", "Markdown \u6587\u4EF6\u8DEF\u5F84").option("--stdin", "\u4ECE\u6807\u51C6\u8F93\u5165\u8BFB\u53D6 Markdown").option("--assigned-to-mail <email>", "\u6307\u6D3E\u4EBA\u90AE\u7BB1\uFF08\u9ED8\u8BA4\u4F7F\u7528\u914D\u7F6E\u7684 userMail\uFF09").option("--interval <ms>", "\u521B\u5EFA\u95F4\u9694\uFF08\u6BEB\u79D2\uFF09", "5000").option("--dry-run", "\u6A21\u62DF\u8FD0\u884C\uFF0C\u4E0D\u5B9E\u9645\u521B\u5EFA").option("--custom-field <key=value>", "\u81EA\u5B9A\u4E49\u5B57\u6BB5 (\u683C\u5F0F: \u5B57\u6BB5ID=\u503C\uFF0C\u8986\u76D6\u7EE7\u627F\u7684\u503C\uFF0C\u53EF\u591A\u6B21\u4F7F\u7528)").option("--cf <key=value>", "\u81EA\u5B9A\u4E49\u5B57\u6BB5\u7684\u7B80\u5199\u522B\u540D").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) => {
2475
2622
  let parentId;
2476
2623
  let parentHost;
2477
2624
  if (options.parentUrl) {
@@ -2544,6 +2691,21 @@ function createIssueCommand() {
2544
2691
  }
2545
2692
  const interval = parseInt(options.interval, 10);
2546
2693
  const dryRun = options.dryRun || false;
2694
+ const customFieldInputs = collectCustomFieldInputs(options);
2695
+ let extraCustomFields = {};
2696
+ if (customFieldInputs.length > 0) {
2697
+ const parseResult = await parseCustomFieldInputs(
2698
+ customFieldInputs,
2699
+ creds.token,
2700
+ creds.host,
2701
+ creds.project || ""
2702
+ );
2703
+ if (parseResult.error) {
2704
+ outputError(parseResult.error, options.pretty);
2705
+ process.exit(1);
2706
+ }
2707
+ extraCustomFields = parseResult.fields;
2708
+ }
2547
2709
  const result = await issueService.batchCreateFromMarkdown(
2548
2710
  creds.token,
2549
2711
  creds.host,
@@ -2551,7 +2713,7 @@ function createIssueCommand() {
2551
2713
  parentId,
2552
2714
  markdown,
2553
2715
  assignedToMail,
2554
- { dryRun, interval }
2716
+ { dryRun, interval, extraCustomFields }
2555
2717
  );
2556
2718
  if (result.success && result.data) {
2557
2719
  const output = {
@@ -2578,7 +2740,7 @@ function createIssueCommand() {
2578
2740
  pretty: options.pretty
2579
2741
  });
2580
2742
  } else {
2581
- outputError(result.message || result.msg || result.api_error_msg || "\u6279\u91CF\u521B\u5EFA\u5931\u8D25", options.pretty);
2743
+ outputError(extractErrorMessage(result, "\u6279\u91CF\u521B\u5EFA\u5931\u8D25"), options.pretty);
2582
2744
  process.exit(1);
2583
2745
  }
2584
2746
  });
@@ -2707,7 +2869,7 @@ function createTimeCommand() {
2707
2869
  logger_default.info("\u67E5\u8BE2\u6240\u6709\u9879\u76EE\u7684\u5DE5\u65F6...");
2708
2870
  const projectsResult = await userService.getProjects(creds.token, creds.host);
2709
2871
  if (!projectsResult.success || !projectsResult.data) {
2710
- outputError(projectsResult.message || projectsResult.msg || projectsResult.api_error_msg || "\u83B7\u53D6\u9879\u76EE\u5217\u8868\u5931\u8D25", options.pretty);
2872
+ outputError(extractErrorMessage(projectsResult, "\u83B7\u53D6\u9879\u76EE\u5217\u8868\u5931\u8D25"), options.pretty);
2711
2873
  process.exit(1);
2712
2874
  }
2713
2875
  const projects = projectsResult.data;
@@ -2784,14 +2946,14 @@ function createTimeCommand() {
2784
2946
  if (result.success && result.data) {
2785
2947
  outputSuccess(result.data, options.pretty);
2786
2948
  } else {
2787
- outputError(result.message || result.msg || result.api_error_msg || "\u67E5\u8BE2\u5DE5\u65F6\u5931\u8D25", options.pretty);
2949
+ outputError(extractErrorMessage(result, "\u67E5\u8BE2\u5DE5\u65F6\u5931\u8D25"), options.pretty);
2788
2950
  process.exit(1);
2789
2951
  }
2790
2952
  }
2791
2953
  });
2792
- 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) => {
2954
+ 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\uFF08\u53EF\u9009\uFF0C\u4F1A\u81EA\u52A8\u4ECE\u95EE\u9898\u83B7\u53D6\uFF09").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) => {
2793
2955
  const creds = resolveCredentials(options);
2794
- const validation = validateCredentials(creds);
2956
+ const validation = validateCredentials(creds, ["token", "host"]);
2795
2957
  if (!validation.valid) {
2796
2958
  outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
2797
2959
  process.exit(1);
@@ -2820,10 +2982,27 @@ function createTimeCommand() {
2820
2982
  outputError("\u65E0\u6548\u7684\u6D3B\u52A8\u7C7B\u578B ID\uFF0C\u4F7F\u7528 pm-cli time options \u83B7\u53D6\u53EF\u7528\u503C", options.pretty);
2821
2983
  process.exit(1);
2822
2984
  }
2985
+ let projectName = creds.project;
2986
+ let projectAutoDetected = false;
2987
+ if (!projectName) {
2988
+ logger_default.info(`\u672A\u6307\u5B9A\u9879\u76EE\uFF0C\u6B63\u5728\u4ECE\u95EE\u9898 #${issueId} \u83B7\u53D6\u9879\u76EE\u4FE1\u606F...`);
2989
+ const issueResult = await issueService.getIssue(creds.token, creds.host, "", issueId);
2990
+ if (!issueResult.success || !issueResult.data) {
2991
+ outputError(extractErrorMessage(issueResult, `\u83B7\u53D6\u95EE\u9898 #${issueId} \u5931\u8D25\uFF0C\u65E0\u6CD5\u786E\u5B9A\u9879\u76EE`), options.pretty);
2992
+ process.exit(1);
2993
+ }
2994
+ projectName = issueResult.data.project?.name;
2995
+ if (!projectName) {
2996
+ outputError(`\u95EE\u9898 #${issueId} \u6CA1\u6709\u5173\u8054\u7684\u9879\u76EE\u4FE1\u606F`, options.pretty);
2997
+ process.exit(1);
2998
+ }
2999
+ logger_default.info(`\u4ECE\u95EE\u9898\u83B7\u53D6\u5230\u9879\u76EE\u540D\u79F0: ${projectName}`);
3000
+ projectAutoDetected = true;
3001
+ }
2823
3002
  const params = {
2824
3003
  token: creds.token,
2825
3004
  host: creds.host,
2826
- project: creds.project,
3005
+ project: projectName,
2827
3006
  issue_id: issueId,
2828
3007
  hours: days,
2829
3008
  // API 参数名为 hours,但单位是天
@@ -2838,15 +3017,23 @@ function createTimeCommand() {
2838
3017
  if (options.comments) params.comments = options.comments;
2839
3018
  const result = await timeEntryService.createTimeEntry(params);
2840
3019
  if (result.success && result.data) {
2841
- outputSuccess(result.data, options.pretty);
3020
+ if (projectAutoDetected) {
3021
+ const dataWithHint = {
3022
+ ...result.data,
3023
+ _hint: `\u9879\u76EE\u540D\u79F0 "${projectName}" \u662F\u4ECE\u95EE\u9898\u81EA\u52A8\u83B7\u53D6\u7684\u3002\u5982\u9700\u8BBE\u4E3A\u9ED8\u8BA4\uFF0C\u8BF7\u6267\u884C: pm-cli config set project "${projectName}"`
3024
+ };
3025
+ outputSuccess(dataWithHint, options.pretty);
3026
+ } else {
3027
+ outputSuccess(result.data, options.pretty);
3028
+ }
2842
3029
  } else {
2843
- outputError(result.message || result.msg || result.api_error_msg || "\u521B\u5EFA\u5DE5\u65F6\u5931\u8D25", options.pretty);
3030
+ outputError(extractErrorMessage(result, "\u521B\u5EFA\u5DE5\u65F6\u5931\u8D25"), options.pretty);
2844
3031
  process.exit(1);
2845
3032
  }
2846
3033
  });
2847
- 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) => {
3034
+ 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\uFF08\u53EF\u9009\uFF0C\u4F1A\u81EA\u52A8\u4ECE\u95EE\u9898\u83B7\u53D6\uFF09").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) => {
2848
3035
  const creds = resolveCredentials(options);
2849
- const validation = validateCredentials(creds);
3036
+ const validation = validateCredentials(creds, ["token", "host"]);
2850
3037
  if (!validation.valid) {
2851
3038
  outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
2852
3039
  process.exit(1);
@@ -2870,10 +3057,25 @@ function createTimeCommand() {
2870
3057
  outputError("\u65E0\u6548\u7684\u95EE\u9898 ID", options.pretty);
2871
3058
  process.exit(1);
2872
3059
  }
3060
+ let projectName = creds.project;
3061
+ if (!projectName) {
3062
+ logger_default.info(`\u672A\u6307\u5B9A\u9879\u76EE\uFF0C\u6B63\u5728\u4ECE\u95EE\u9898 #${issueId} \u83B7\u53D6\u9879\u76EE\u4FE1\u606F...`);
3063
+ const issueResult = await issueService.getIssue(creds.token, creds.host, "", issueId);
3064
+ if (!issueResult.success || !issueResult.data) {
3065
+ outputError(extractErrorMessage(issueResult, `\u83B7\u53D6\u95EE\u9898 #${issueId} \u5931\u8D25\uFF0C\u65E0\u6CD5\u786E\u5B9A\u9879\u76EE`), options.pretty);
3066
+ process.exit(1);
3067
+ }
3068
+ projectName = issueResult.data.project?.name;
3069
+ if (!projectName) {
3070
+ outputError(`\u95EE\u9898 #${issueId} \u6CA1\u6709\u5173\u8054\u7684\u9879\u76EE\u4FE1\u606F`, options.pretty);
3071
+ process.exit(1);
3072
+ }
3073
+ logger_default.info(`\u4ECE\u95EE\u9898\u83B7\u53D6\u5230\u9879\u76EE\u540D\u79F0: ${projectName}`);
3074
+ }
2873
3075
  const params = {
2874
3076
  token: creds.token,
2875
3077
  host: creds.host,
2876
- project: creds.project,
3078
+ project: projectName,
2877
3079
  id: timeEntryId,
2878
3080
  // 工时 ID
2879
3081
  issue_id: issueId,
@@ -2894,7 +3096,7 @@ function createTimeCommand() {
2894
3096
  if (result.success && result.data) {
2895
3097
  outputSuccess(result.data, options.pretty);
2896
3098
  } else {
2897
- outputError(result.message || result.msg || result.api_error_msg || "\u66F4\u65B0\u5DE5\u65F6\u5931\u8D25", options.pretty);
3099
+ outputError(extractErrorMessage(result, "\u66F4\u65B0\u5DE5\u65F6\u5931\u8D25"), options.pretty);
2898
3100
  process.exit(1);
2899
3101
  }
2900
3102
  });
@@ -2918,22 +3120,42 @@ function createTimeCommand() {
2918
3120
  if (result.success) {
2919
3121
  outputSuccess({ message: "\u5DE5\u65F6\u6761\u76EE\u5DF2\u5220\u9664", id: timeEntryId }, options.pretty);
2920
3122
  } else {
2921
- outputError(result.message || result.msg || result.api_error_msg || "\u5220\u9664\u5DE5\u65F6\u5931\u8D25", options.pretty);
3123
+ outputError(extractErrorMessage(result, "\u5220\u9664\u5DE5\u65F6\u5931\u8D25"), options.pretty);
2922
3124
  process.exit(1);
2923
3125
  }
2924
3126
  });
2925
- 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) => {
3127
+ 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\uFF0C\u540C\u65F6\u53EF\u81EA\u52A8\u63A8\u65AD\u9879\u76EE\uFF09").option("--token <token>", "API Token").option("--host <host>", "PM \u4E3B\u673A\u5730\u5740").option("--project <project>", "\u9879\u76EE\u540D\u79F0\uFF08\u53EF\u9009\uFF0C\u53EF\u4ECE\u95EE\u9898\u81EA\u52A8\u83B7\u53D6\uFF09").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) => {
2926
3128
  const creds = resolveCredentials(options);
2927
- const validation = validateCredentials(creds);
3129
+ const validation = validateCredentials(creds, ["token", "host"]);
2928
3130
  if (!validation.valid) {
2929
3131
  outputError(`\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570: ${validation.missing.join(", ")}`, options.pretty);
2930
3132
  process.exit(1);
2931
3133
  }
2932
3134
  const issueId = options.issue ? parseInt(options.issue.replace(/^#/, ""), 10) : void 0;
3135
+ let projectName = creds.project;
3136
+ if (!projectName) {
3137
+ if (issueId) {
3138
+ logger_default.info(`\u672A\u6307\u5B9A\u9879\u76EE\uFF0C\u6B63\u5728\u4ECE\u95EE\u9898 #${issueId} \u83B7\u53D6\u9879\u76EE\u4FE1\u606F...`);
3139
+ const issueResult = await issueService.getIssue(creds.token, creds.host, "", issueId);
3140
+ if (!issueResult.success || !issueResult.data) {
3141
+ outputError(extractErrorMessage(issueResult, `\u83B7\u53D6\u95EE\u9898 #${issueId} \u5931\u8D25\uFF0C\u65E0\u6CD5\u786E\u5B9A\u9879\u76EE`), options.pretty);
3142
+ process.exit(1);
3143
+ }
3144
+ projectName = issueResult.data.project?.name;
3145
+ if (!projectName) {
3146
+ outputError(`\u95EE\u9898 #${issueId} \u6CA1\u6709\u5173\u8054\u7684\u9879\u76EE\u4FE1\u606F`, options.pretty);
3147
+ process.exit(1);
3148
+ }
3149
+ logger_default.info(`\u4ECE\u95EE\u9898\u83B7\u53D6\u5230\u9879\u76EE\u540D\u79F0: ${projectName}`);
3150
+ } else {
3151
+ outputError("\u7F3A\u5C11\u9879\u76EE\u540D\u79F0\uFF0C\u8BF7\u4F7F\u7528 --project \u6307\u5B9A\u6216\u901A\u8FC7 --issue \u81EA\u52A8\u83B7\u53D6", options.pretty);
3152
+ process.exit(1);
3153
+ }
3154
+ }
2933
3155
  const result = await timeEntryService.getTimeEntryOptions(
2934
3156
  creds.token,
2935
3157
  creds.host,
2936
- creds.project,
3158
+ projectName,
2937
3159
  issueId
2938
3160
  );
2939
3161
  if (result.success && result.data) {
@@ -2945,7 +3167,7 @@ function createTimeCommand() {
2945
3167
  outputSuccess(result.data, options.pretty);
2946
3168
  }
2947
3169
  } else {
2948
- outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u9009\u9879\u5931\u8D25", options.pretty);
3170
+ outputError(extractErrorMessage(result, "\u83B7\u53D6\u9009\u9879\u5931\u8D25"), options.pretty);
2949
3171
  process.exit(1);
2950
3172
  }
2951
3173
  });
@@ -2987,7 +3209,7 @@ function createTimeCommand() {
2987
3209
  }
2988
3210
  const projectsResult = await userService.getProjects(creds.token, creds.host);
2989
3211
  if (!projectsResult.success || !projectsResult.data) {
2990
- outputError(projectsResult.message || projectsResult.msg || projectsResult.api_error_msg || "\u83B7\u53D6\u9879\u76EE\u5217\u8868\u5931\u8D25", options.pretty);
3212
+ outputError(extractErrorMessage(projectsResult, "\u83B7\u53D6\u9879\u76EE\u5217\u8868\u5931\u8D25"), options.pretty);
2991
3213
  process.exit(1);
2992
3214
  }
2993
3215
  const projects = projectsResult.data;
@@ -3061,7 +3283,7 @@ function createProjectCommand() {
3061
3283
  if (result.success && result.data) {
3062
3284
  outputSuccess(result.data, options.pretty);
3063
3285
  } else {
3064
- outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u9879\u76EE\u5217\u8868\u5931\u8D25", options.pretty);
3286
+ outputError(extractErrorMessage(result, "\u83B7\u53D6\u9879\u76EE\u5217\u8868\u5931\u8D25"), options.pretty);
3065
3287
  process.exit(1);
3066
3288
  }
3067
3289
  });
@@ -3080,7 +3302,7 @@ function createProjectCommand() {
3080
3302
  if (result.success && result.data) {
3081
3303
  outputSuccess(result.data, options.pretty);
3082
3304
  } else {
3083
- outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u7528\u6237\u5217\u8868\u5931\u8D25", options.pretty);
3305
+ outputError(extractErrorMessage(result, "\u83B7\u53D6\u7528\u6237\u5217\u8868\u5931\u8D25"), options.pretty);
3084
3306
  process.exit(1);
3085
3307
  }
3086
3308
  });
@@ -3095,7 +3317,7 @@ function createProjectCommand() {
3095
3317
  if (result.success) {
3096
3318
  outputSuccess(result.data, options.pretty);
3097
3319
  } else {
3098
- outputError(result.message || result.msg || result.api_error_msg || "\u83B7\u53D6\u4E3B\u673A\u4FE1\u606F\u5931\u8D25", options.pretty);
3320
+ outputError(extractErrorMessage(result, "\u83B7\u53D6\u4E3B\u673A\u4FE1\u606F\u5931\u8D25"), options.pretty);
3099
3321
  process.exit(1);
3100
3322
  }
3101
3323
  });