ai-dev-requirements 0.1.11 → 0.1.12

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.mjs CHANGED
@@ -116,6 +116,26 @@ const ISSUE_TYPES_QUERY = `
116
116
  }
117
117
  }
118
118
  `;
119
+ const PROJECTS_QUERY = `
120
+ query Projects($groupBy: GroupBy, $orderBy: OrderBy, $pagination: Pagination, $projectOrderBy: OrderBy, $projectFilterGroup: [Filter!]) {
121
+ buckets(groupBy: $groupBy, orderBy: $orderBy, pagination: $pagination) {
122
+ key
123
+ projects(limit: 10000, orderBy: $projectOrderBy, filterGroup: $projectFilterGroup) {
124
+ key
125
+ uuid
126
+ name
127
+ identifier
128
+ }
129
+ }
130
+ }
131
+ `;
132
+ const ADD_MANHOUR_MUTATION = `
133
+ mutation AddManhour {
134
+ addManhour(mode: $mode, owner: $owner, task: $task, type: $type, start_time: $start_time, hours: $hours, description: $description, customData: $customData) {
135
+ key
136
+ }
137
+ }
138
+ `;
119
139
  const TASK_BY_NUMBER_QUERY = SEARCH_TASKS_QUERY;
120
140
  const RELATED_TASKS_QUERY = `
121
141
  query Task($key: Key) {
@@ -322,6 +342,74 @@ function parseOnesWikiPageRoute(input) {
322
342
  function isOnesWikiUrlInput(input) {
323
343
  return input.includes("/wiki/");
324
344
  }
345
+ function parseAuthorizeRequestId(location) {
346
+ try {
347
+ const parsed = new URL(location);
348
+ return parsed.searchParams.get("auth_request_id") ?? parsed.searchParams.get("id");
349
+ } catch {
350
+ const match = location.match(/[?&](?:auth_request_id|id)=([^&#]+)/);
351
+ return match?.[1] ? decodeURIComponent(match[1]) : null;
352
+ }
353
+ }
354
+ function parseAuthorizationCode(location) {
355
+ try {
356
+ return new URL(location).searchParams.get("code");
357
+ } catch {
358
+ const match = location.match(/[?&]code=([^&#]+)/);
359
+ return match?.[1] ? decodeURIComponent(match[1]) : null;
360
+ }
361
+ }
362
+ function parseDisplayId(input) {
363
+ const match = input.trim().match(/^([a-z]\w*)-(\d+)$/i);
364
+ if (!match?.[1] || !match[2]) return null;
365
+ return {
366
+ identifier: match[1],
367
+ number: Number.parseInt(match[2], 10)
368
+ };
369
+ }
370
+ function isValidOnesDate(value) {
371
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) return false;
372
+ const [yearText, monthText, dayText] = value.split("-");
373
+ const year = Number.parseInt(yearText, 10);
374
+ const month = Number.parseInt(monthText, 10);
375
+ const day = Number.parseInt(dayText, 10);
376
+ const date = new Date(Date.UTC(year, month - 1, day));
377
+ return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
378
+ }
379
+ function toOnesHours(hours) {
380
+ if (!Number.isFinite(hours) || hours <= 0) throw new Error("ONES: hours must be a positive number");
381
+ return Math.round(hours * 1e5);
382
+ }
383
+ function getTodayStartUnixSeconds() {
384
+ const now = /* @__PURE__ */ new Date();
385
+ const localStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
386
+ return Math.floor(localStart.getTime() / 1e3);
387
+ }
388
+ function toLocalDateString(date) {
389
+ return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
390
+ }
391
+ function getLocalStartUnixSeconds(year, month, day) {
392
+ return Math.floor(new Date(year, month - 1, day).getTime() / 1e3);
393
+ }
394
+ function parseManhourDate(input) {
395
+ const value = input?.trim();
396
+ if (!value) return {
397
+ date: null,
398
+ startTime: getTodayStartUnixSeconds()
399
+ };
400
+ const fullDateMatch = value.match(/^(\d{4})-(\d{2})-(\d{2})$/);
401
+ const dayOnlyMatch = value.match(/^(\d{1,2})号?$/);
402
+ const now = /* @__PURE__ */ new Date();
403
+ const year = fullDateMatch ? Number.parseInt(fullDateMatch[1], 10) : now.getFullYear();
404
+ const month = fullDateMatch ? Number.parseInt(fullDateMatch[2], 10) : now.getMonth() + 1;
405
+ const day = fullDateMatch ? Number.parseInt(fullDateMatch[3], 10) : dayOnlyMatch ? Number.parseInt(dayOnlyMatch[1], 10) : NaN;
406
+ const parsed = new Date(year, month - 1, day);
407
+ if (!(Number.isInteger(day) && parsed.getFullYear() === year && parsed.getMonth() === month - 1 && parsed.getDate() === day)) throw new Error("ONES: date must be a valid YYYY-MM-DD date or day of current month");
408
+ return {
409
+ date: toLocalDateString(parsed),
410
+ startTime: getLocalStartUnixSeconds(year, month, day)
411
+ };
412
+ }
325
413
  function htmlToPlainText(html) {
326
414
  return html.replace(/<br\s*\/?>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<[^>]+>/g, "").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/\n{3,}/g, "\n\n").trim();
327
415
  }
@@ -516,32 +604,35 @@ var OnesAdapter = class extends BaseAdapter {
516
604
  redirect: "manual"
517
605
  })).headers.get("location");
518
606
  if (!authorizeLocation) throw new Error("ONES: Authorize response missing location header");
519
- const authRequestId = new URL(authorizeLocation).searchParams.get("id");
520
- if (!authRequestId) throw new Error("ONES: Cannot parse auth_request_id from authorize redirect");
521
- const finalizeRes = await fetch(`${baseUrl}/identity/api/auth_request/finalize`, {
522
- method: "POST",
523
- headers: {
524
- "Content-Type": "application/json;charset=UTF-8",
525
- "Cookie": cookies
526
- },
527
- body: JSON.stringify({
528
- auth_request_id: authRequestId,
529
- region_uuid: orgUser.region_uuid,
530
- org_uuid: orgUser.org_uuid,
531
- org_user_uuid: orgUser.org_user.org_user_uuid
532
- })
533
- });
534
- if (!finalizeRes.ok) {
535
- const text = await finalizeRes.text().catch(() => "");
536
- throw new Error(`ONES: Finalize failed: ${finalizeRes.status} ${text}`);
607
+ let code = parseAuthorizationCode(authorizeLocation);
608
+ if (!code) {
609
+ const authRequestId = parseAuthorizeRequestId(authorizeLocation);
610
+ if (!authRequestId) throw new Error("ONES: Cannot parse auth_request_id from authorize redirect");
611
+ const finalizeRes = await fetch(`${baseUrl}/identity/api/auth_request/finalize`, {
612
+ method: "POST",
613
+ headers: {
614
+ "Content-Type": "application/json;charset=UTF-8",
615
+ "Cookie": cookies
616
+ },
617
+ body: JSON.stringify({
618
+ auth_request_id: authRequestId,
619
+ region_uuid: orgUser.region_uuid,
620
+ org_uuid: orgUser.org_uuid,
621
+ org_user_uuid: orgUser.org_user.org_user_uuid
622
+ })
623
+ });
624
+ if (!finalizeRes.ok) {
625
+ const text = await finalizeRes.text().catch(() => "");
626
+ throw new Error(`ONES: Finalize failed: ${finalizeRes.status} ${text}`);
627
+ }
628
+ const callbackLocation = (await fetch(`${baseUrl}/identity/authorize/callback?id=${authRequestId}&lang=zh`, {
629
+ method: "GET",
630
+ headers: { Cookie: cookies },
631
+ redirect: "manual"
632
+ })).headers.get("location");
633
+ if (!callbackLocation) throw new Error("ONES: Callback response missing location header");
634
+ code = parseAuthorizationCode(callbackLocation);
537
635
  }
538
- const callbackLocation = (await fetch(`${baseUrl}/identity/authorize/callback?id=${authRequestId}&lang=zh`, {
539
- method: "GET",
540
- headers: { Cookie: cookies },
541
- redirect: "manual"
542
- })).headers.get("location");
543
- if (!callbackLocation) throw new Error("ONES: Callback response missing location header");
544
- const code = new URL(callbackLocation).searchParams.get("code");
545
636
  if (!code) throw new Error("ONES: Cannot parse authorization code from callback redirect");
546
637
  const tokenRes = await fetch(`${baseUrl}/identity/oauth/token`, {
547
638
  method: "POST",
@@ -611,11 +702,107 @@ var OnesAdapter = class extends BaseAdapter {
611
702
  }
612
703
  return response.json();
613
704
  }
705
+ async searchTaskByNumber(taskNumber) {
706
+ const session = await this.login();
707
+ const url = `${this.config.apiBase}/project/api/project/team/${session.teamUuid}/search?q=${encodeURIComponent(String(taskNumber))}&start=0&limit=10&types=task`;
708
+ const response = await fetch(url, { headers: { Authorization: `Bearer ${session.accessToken}` } });
709
+ if (!response.ok) return null;
710
+ const found = ((await response.json()).datas?.task ?? []).map((item) => item.fields).find((fields) => fields?.uuid && fields.number === taskNumber);
711
+ if (!found?.uuid) return null;
712
+ return {
713
+ key: `task-${found.uuid}`,
714
+ uuid: found.uuid,
715
+ number: found.number ?? taskNumber,
716
+ name: found.summary ?? "",
717
+ status: {
718
+ uuid: "",
719
+ name: "",
720
+ category: void 0
721
+ },
722
+ issueType: found.issue_type_uuid || found.issue_type_name ? {
723
+ uuid: found.issue_type_uuid ?? "",
724
+ name: found.issue_type_name ?? ""
725
+ } : void 0,
726
+ project: found.project_uuid || found.project_name ? {
727
+ uuid: found.project_uuid ?? "",
728
+ name: found.project_name ?? ""
729
+ } : void 0
730
+ };
731
+ }
614
732
  async fetchIssueTypes() {
615
733
  if (this.issueTypesCache) return this.issueTypesCache;
616
734
  this.issueTypesCache = (await this.graphql(ISSUE_TYPES_QUERY, { orderBy: { namePinyin: "ASC" } }, "issueTypes")).data?.issueTypes ?? [];
617
735
  return this.issueTypesCache;
618
736
  }
737
+ async fetchProjects() {
738
+ return (await this.graphql(PROJECTS_QUERY, {
739
+ projectOrderBy: {
740
+ isPin: "DESC",
741
+ namePinyin: "ASC",
742
+ createTime: "DESC"
743
+ },
744
+ projectFilterGroup: [{
745
+ visibleInProject_equal: true,
746
+ isArchive_equal: false
747
+ }],
748
+ groupBy: { projects: {} },
749
+ orderBy: null,
750
+ pagination: {
751
+ limit: 50,
752
+ after: "",
753
+ preciseCount: true
754
+ }
755
+ }, "projects-group-list-for-project-view")).data?.buckets?.flatMap((bucket) => bucket.projects ?? []) ?? [];
756
+ }
757
+ async findTaskByNumber(taskNumber, projectUuid) {
758
+ const filter = { number_in: [taskNumber] };
759
+ if (projectUuid) filter.project_in = [projectUuid];
760
+ const found = ((await this.graphql(TASK_BY_NUMBER_QUERY, {
761
+ groupBy: { tasks: {} },
762
+ groupOrderBy: null,
763
+ orderBy: { createTime: "DESC" },
764
+ filterGroup: [filter],
765
+ search: null,
766
+ pagination: {
767
+ limit: 10,
768
+ preciseCount: false
769
+ },
770
+ limit: 10
771
+ }, "group-task-data")).data?.buckets?.flatMap((b) => b.tasks ?? []) ?? []).find((task) => task.number === taskNumber && (!projectUuid || task.project?.uuid === projectUuid));
772
+ if (found) return found;
773
+ if (projectUuid) return null;
774
+ return this.searchTaskByNumber(taskNumber);
775
+ }
776
+ async resolveTaskRef(input) {
777
+ const taskId = input.trim();
778
+ if (!taskId) throw new Error("ONES: taskId is required");
779
+ const numMatch = taskId.match(/^#?(\d+)$/);
780
+ if (numMatch) {
781
+ const taskNumber = Number.parseInt(numMatch[1], 10);
782
+ const found = await this.findTaskByNumber(taskNumber);
783
+ if (!found) throw new Error(`ONES: Task #${taskNumber} not found in current team`);
784
+ return {
785
+ key: found.key ?? `task-${found.uuid}`,
786
+ uuid: found.uuid
787
+ };
788
+ }
789
+ const displayId = parseDisplayId(taskId);
790
+ if (displayId) {
791
+ const project = (await this.fetchProjects()).find((item) => item.identifier?.toLowerCase() === displayId.identifier.toLowerCase());
792
+ if (!project) throw new Error(`ONES: Project identifier "${displayId.identifier}" not found in current team`);
793
+ const found = await this.findTaskByNumber(displayId.number, project.uuid);
794
+ if (!found) throw new Error(`ONES: Task "${taskId}" not found in current team`);
795
+ return {
796
+ key: found.key ?? `task-${found.uuid}`,
797
+ uuid: found.uuid
798
+ };
799
+ }
800
+ const key = taskId.startsWith("task-") ? taskId : `task-${taskId}`;
801
+ return {
802
+ key,
803
+ uuid: key.slice(5)
804
+ };
805
+ }
619
806
  async searchTeamUsers(keyword) {
620
807
  const session = await this.login();
621
808
  const url = `${this.config.apiBase}/project/api/project/team/${session.teamUuid}/users/search`;
@@ -804,27 +991,9 @@ var OnesAdapter = class extends BaseAdapter {
804
991
  };
805
992
  }
806
993
  if (isOnesWikiUrlInput(params.id)) throw new Error("ONES: Unsupported wiki page URL. Expected /wiki/#/team/{teamUuid}/space/{spaceUuid}/page/{wikiUuid}");
807
- let taskUuid = params.id;
808
- const numMatch = taskUuid.match(/^#?(\d+)$/);
809
- if (numMatch) {
810
- const taskNumber = Number.parseInt(numMatch[1], 10);
811
- const found = ((await this.graphql(TASK_BY_NUMBER_QUERY, {
812
- groupBy: { tasks: {} },
813
- groupOrderBy: null,
814
- orderBy: { createTime: "DESC" },
815
- filterGroup: [{ number_in: [taskNumber] }],
816
- search: null,
817
- pagination: {
818
- limit: 10,
819
- preciseCount: false
820
- },
821
- limit: 10
822
- }, "group-task-data")).data?.buckets?.flatMap((b) => b.tasks ?? []) ?? []).find((t) => t.number === taskNumber);
823
- if (!found) throw new Error(`ONES: Task #${taskNumber} not found in current team`);
824
- taskUuid = found.uuid;
825
- }
826
- const task = (await this.graphql(TASK_DETAIL_QUERY, { key: `task-${taskUuid}` }, "Task")).data?.task;
827
- if (!task) throw new Error(`ONES: Task "${taskUuid}" not found`);
994
+ const taskRef = await this.resolveTaskRef(params.id);
995
+ const task = (await this.graphql(TASK_DETAIL_QUERY, { key: taskRef.key }, "Task")).data?.task;
996
+ if (!task) throw new Error(`ONES: Task "${params.id}" not found`);
828
997
  const wikiRefs = /* @__PURE__ */ new Map();
829
998
  for (const wiki of task.relatedWikiPages ?? []) if (!wiki.errorMessage) wikiRefs.set(wiki.uuid, {
830
999
  title: wiki.title,
@@ -959,6 +1128,69 @@ var OnesAdapter = class extends BaseAdapter {
959
1128
  pageSize
960
1129
  };
961
1130
  }
1131
+ async addManhour(params) {
1132
+ const description = params.description.trim();
1133
+ if (!description) throw new Error("ONES: description is required");
1134
+ const taskRef = await this.resolveTaskRef(params.taskId);
1135
+ const onesHours = toOnesHours(params.hours);
1136
+ const workDate = parseManhourDate(params.date);
1137
+ const key = (await this.graphql(ADD_MANHOUR_MUTATION, {
1138
+ mode: "simple",
1139
+ type: "recorded",
1140
+ customData: {},
1141
+ owner: (await this.login()).userUuid,
1142
+ task: taskRef.uuid,
1143
+ start_time: workDate.startTime,
1144
+ hours: onesHours,
1145
+ description
1146
+ }, "add-manhour")).data?.addManhour?.key;
1147
+ if (!key) throw new Error("ONES: Failed to add manhour");
1148
+ return {
1149
+ key,
1150
+ taskUuid: taskRef.uuid,
1151
+ hours: params.hours,
1152
+ description,
1153
+ date: workDate.date
1154
+ };
1155
+ }
1156
+ async updateTaskPlanDates(params) {
1157
+ const planStartDate = params.planStartDate?.trim();
1158
+ const planEndDate = params.planEndDate?.trim();
1159
+ if (!planStartDate && !planEndDate) throw new Error("ONES: planStartDate or planEndDate is required");
1160
+ if (planStartDate && !isValidOnesDate(planStartDate)) throw new Error("ONES: planStartDate must be a valid YYYY-MM-DD date");
1161
+ if (planEndDate && !isValidOnesDate(planEndDate)) throw new Error("ONES: planEndDate must be a valid YYYY-MM-DD date");
1162
+ const taskRef = await this.resolveTaskRef(params.taskId);
1163
+ const session = await this.login();
1164
+ const fieldValues = [];
1165
+ if (planStartDate) fieldValues.push({
1166
+ field_uuid: "field027",
1167
+ value: planStartDate
1168
+ });
1169
+ if (planEndDate) fieldValues.push({
1170
+ field_uuid: "field028",
1171
+ value: planEndDate
1172
+ });
1173
+ const response = await fetch(`${this.config.apiBase}/project/api/project/team/${session.teamUuid}/tasks/update3`, {
1174
+ method: "POST",
1175
+ headers: {
1176
+ "Authorization": `Bearer ${session.accessToken}`,
1177
+ "Content-Type": "application/json"
1178
+ },
1179
+ body: JSON.stringify({ tasks: [{
1180
+ uuid: taskRef.uuid,
1181
+ field_values: fieldValues
1182
+ }] })
1183
+ });
1184
+ if (!response.ok) {
1185
+ const text = await response.text().catch(() => "");
1186
+ throw new Error(`ONES: Failed to update task plan dates: ${response.status} ${text}`);
1187
+ }
1188
+ return {
1189
+ taskUuid: taskRef.uuid,
1190
+ planStartDate: planStartDate ?? null,
1191
+ planEndDate: planEndDate ?? null
1192
+ };
1193
+ }
962
1194
  async getRelatedIssues(params) {
963
1195
  const session = await this.login();
964
1196
  const taskKey = params.taskId.startsWith("task-") ? params.taskId : `task-${params.taskId}`;
@@ -1306,6 +1538,42 @@ function loadConfig(startDir) {
1306
1538
  };
1307
1539
  }
1308
1540
 
1541
+ //#endregion
1542
+ //#region src/tools/add-manhour.ts
1543
+ const AddManhourSchema = z.object({
1544
+ taskId: z.string().min(1).describe("The task or requirement ID, key, number, or displayId (e.g. \"task-mock-uuid\", \"mock-uuid\", \"1001\", or \"DEMO-1001\")"),
1545
+ hours: z.number().positive().describe("Work hours to record. Natural hours are converted to ONES internal units."),
1546
+ description: z.string().min(1).describe("Work log description."),
1547
+ date: z.string().optional().describe("Optional work date. Accepts YYYY-MM-DD, a day number like \"11\", or a day-of-month phrase like \"11号\"; day-only values use the current year and month."),
1548
+ source: z.string().optional().describe("Source to update. If omitted, uses the default source.")
1549
+ });
1550
+ async function handleAddManhour(input, adapters, defaultSource) {
1551
+ const sourceType = input.source ?? defaultSource;
1552
+ if (!sourceType) throw new Error("No source specified and no default source configured");
1553
+ const adapter = adapters.get(sourceType);
1554
+ if (!adapter) throw new Error(`Source "${sourceType}" is not configured. Available: ${[...adapters.keys()].join(", ")}`);
1555
+ return { content: [{
1556
+ type: "text",
1557
+ text: formatAddManhourResult(await adapter.addManhour({
1558
+ taskId: input.taskId,
1559
+ hours: input.hours,
1560
+ description: input.description,
1561
+ date: input.date
1562
+ }))
1563
+ }] };
1564
+ }
1565
+ function formatAddManhourResult(result) {
1566
+ return [
1567
+ "Added manhour.",
1568
+ "",
1569
+ `- **Key**: ${result.key}`,
1570
+ `- **Task UUID**: ${result.taskUuid}`,
1571
+ `- **Hours**: ${result.hours}`,
1572
+ `- **Date**: ${result.date ?? "today"}`,
1573
+ `- **Description**: ${result.description}`
1574
+ ].join("\n");
1575
+ }
1576
+
1309
1577
  //#endregion
1310
1578
  //#region src/tools/get-issue-detail.ts
1311
1579
  const GetIssueDetailSchema = z.object({
@@ -1620,6 +1888,40 @@ async function handleSearchRequirements(input, adapters, defaultSource) {
1620
1888
  }] };
1621
1889
  }
1622
1890
 
1891
+ //#endregion
1892
+ //#region src/tools/update-task-plan-dates.ts
1893
+ const DateSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Expected YYYY-MM-DD");
1894
+ const UpdateTaskPlanDatesSchema = z.object({
1895
+ taskId: z.string().min(1).describe("The task or requirement ID, key, number, or displayId (e.g. \"task-mock-uuid\", \"mock-uuid\", \"1001\", or \"DEMO-1001\")"),
1896
+ planStartDate: DateSchema.optional().describe("Plan start date in YYYY-MM-DD format."),
1897
+ planEndDate: DateSchema.optional().describe("Plan end date in YYYY-MM-DD format."),
1898
+ source: z.string().optional().describe("Source to update. If omitted, uses the default source.")
1899
+ });
1900
+ async function handleUpdateTaskPlanDates(input, adapters, defaultSource) {
1901
+ const sourceType = input.source ?? defaultSource;
1902
+ if (!sourceType) throw new Error("No source specified and no default source configured");
1903
+ const adapter = adapters.get(sourceType);
1904
+ if (!adapter) throw new Error(`Source "${sourceType}" is not configured. Available: ${[...adapters.keys()].join(", ")}`);
1905
+ return { content: [{
1906
+ type: "text",
1907
+ text: formatUpdateTaskPlanDatesResult(await adapter.updateTaskPlanDates({
1908
+ taskId: input.taskId,
1909
+ planStartDate: input.planStartDate,
1910
+ planEndDate: input.planEndDate
1911
+ }))
1912
+ }] };
1913
+ }
1914
+ function formatUpdateTaskPlanDatesResult(result) {
1915
+ const lines = [
1916
+ "Updated task plan dates.",
1917
+ "",
1918
+ `- **Task UUID**: ${result.taskUuid}`
1919
+ ];
1920
+ if (result.planStartDate) lines.push(`- **Plan Start Date**: ${result.planStartDate}`);
1921
+ if (result.planEndDate) lines.push(`- **Plan End Date**: ${result.planEndDate}`);
1922
+ return lines.join("\n");
1923
+ }
1924
+
1623
1925
  //#endregion
1624
1926
  //#region src/index.ts
1625
1927
  /**
@@ -1745,6 +2047,32 @@ async function main() {
1745
2047
  };
1746
2048
  }
1747
2049
  });
2050
+ server.tool("add_manhour", "Add a work-hour record to a ONES task, bug, or requirement. Supports task key, uuid, number, or displayId.", AddManhourSchema.shape, async (params) => {
2051
+ try {
2052
+ return await handleAddManhour(params, adapters, config.config.defaultSource);
2053
+ } catch (err) {
2054
+ return {
2055
+ content: [{
2056
+ type: "text",
2057
+ text: `Error: ${err.message}`
2058
+ }],
2059
+ isError: true
2060
+ };
2061
+ }
2062
+ });
2063
+ server.tool("update_task_plan_dates", "Update plan start and/or plan end dates for a ONES task, bug, or requirement. Supports task key, uuid, number, or displayId.", UpdateTaskPlanDatesSchema.shape, async (params) => {
2064
+ try {
2065
+ return await handleUpdateTaskPlanDates(params, adapters, config.config.defaultSource);
2066
+ } catch (err) {
2067
+ return {
2068
+ content: [{
2069
+ type: "text",
2070
+ text: `Error: ${err.message}`
2071
+ }],
2072
+ isError: true
2073
+ };
2074
+ }
2075
+ });
1748
2076
  const transport = new StdioServerTransport();
1749
2077
  await server.connect(transport);
1750
2078
  }