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.cjs CHANGED
@@ -144,6 +144,26 @@ const ISSUE_TYPES_QUERY = `
144
144
  }
145
145
  }
146
146
  `;
147
+ const PROJECTS_QUERY = `
148
+ query Projects($groupBy: GroupBy, $orderBy: OrderBy, $pagination: Pagination, $projectOrderBy: OrderBy, $projectFilterGroup: [Filter!]) {
149
+ buckets(groupBy: $groupBy, orderBy: $orderBy, pagination: $pagination) {
150
+ key
151
+ projects(limit: 10000, orderBy: $projectOrderBy, filterGroup: $projectFilterGroup) {
152
+ key
153
+ uuid
154
+ name
155
+ identifier
156
+ }
157
+ }
158
+ }
159
+ `;
160
+ const ADD_MANHOUR_MUTATION = `
161
+ mutation AddManhour {
162
+ addManhour(mode: $mode, owner: $owner, task: $task, type: $type, start_time: $start_time, hours: $hours, description: $description, customData: $customData) {
163
+ key
164
+ }
165
+ }
166
+ `;
147
167
  const TASK_BY_NUMBER_QUERY = SEARCH_TASKS_QUERY;
148
168
  const RELATED_TASKS_QUERY = `
149
169
  query Task($key: Key) {
@@ -350,6 +370,74 @@ function parseOnesWikiPageRoute(input) {
350
370
  function isOnesWikiUrlInput(input) {
351
371
  return input.includes("/wiki/");
352
372
  }
373
+ function parseAuthorizeRequestId(location) {
374
+ try {
375
+ const parsed = new URL(location);
376
+ return parsed.searchParams.get("auth_request_id") ?? parsed.searchParams.get("id");
377
+ } catch {
378
+ const match = location.match(/[?&](?:auth_request_id|id)=([^&#]+)/);
379
+ return match?.[1] ? decodeURIComponent(match[1]) : null;
380
+ }
381
+ }
382
+ function parseAuthorizationCode(location) {
383
+ try {
384
+ return new URL(location).searchParams.get("code");
385
+ } catch {
386
+ const match = location.match(/[?&]code=([^&#]+)/);
387
+ return match?.[1] ? decodeURIComponent(match[1]) : null;
388
+ }
389
+ }
390
+ function parseDisplayId(input) {
391
+ const match = input.trim().match(/^([a-z]\w*)-(\d+)$/i);
392
+ if (!match?.[1] || !match[2]) return null;
393
+ return {
394
+ identifier: match[1],
395
+ number: Number.parseInt(match[2], 10)
396
+ };
397
+ }
398
+ function isValidOnesDate(value) {
399
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) return false;
400
+ const [yearText, monthText, dayText] = value.split("-");
401
+ const year = Number.parseInt(yearText, 10);
402
+ const month = Number.parseInt(monthText, 10);
403
+ const day = Number.parseInt(dayText, 10);
404
+ const date = new Date(Date.UTC(year, month - 1, day));
405
+ return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
406
+ }
407
+ function toOnesHours(hours) {
408
+ if (!Number.isFinite(hours) || hours <= 0) throw new Error("ONES: hours must be a positive number");
409
+ return Math.round(hours * 1e5);
410
+ }
411
+ function getTodayStartUnixSeconds() {
412
+ const now = /* @__PURE__ */ new Date();
413
+ const localStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
414
+ return Math.floor(localStart.getTime() / 1e3);
415
+ }
416
+ function toLocalDateString(date) {
417
+ return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
418
+ }
419
+ function getLocalStartUnixSeconds(year, month, day) {
420
+ return Math.floor(new Date(year, month - 1, day).getTime() / 1e3);
421
+ }
422
+ function parseManhourDate(input) {
423
+ const value = input?.trim();
424
+ if (!value) return {
425
+ date: null,
426
+ startTime: getTodayStartUnixSeconds()
427
+ };
428
+ const fullDateMatch = value.match(/^(\d{4})-(\d{2})-(\d{2})$/);
429
+ const dayOnlyMatch = value.match(/^(\d{1,2})号?$/);
430
+ const now = /* @__PURE__ */ new Date();
431
+ const year = fullDateMatch ? Number.parseInt(fullDateMatch[1], 10) : now.getFullYear();
432
+ const month = fullDateMatch ? Number.parseInt(fullDateMatch[2], 10) : now.getMonth() + 1;
433
+ const day = fullDateMatch ? Number.parseInt(fullDateMatch[3], 10) : dayOnlyMatch ? Number.parseInt(dayOnlyMatch[1], 10) : NaN;
434
+ const parsed = new Date(year, month - 1, day);
435
+ 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");
436
+ return {
437
+ date: toLocalDateString(parsed),
438
+ startTime: getLocalStartUnixSeconds(year, month, day)
439
+ };
440
+ }
353
441
  function htmlToPlainText(html) {
354
442
  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();
355
443
  }
@@ -544,32 +632,35 @@ var OnesAdapter = class extends BaseAdapter {
544
632
  redirect: "manual"
545
633
  })).headers.get("location");
546
634
  if (!authorizeLocation) throw new Error("ONES: Authorize response missing location header");
547
- const authRequestId = new URL(authorizeLocation).searchParams.get("id");
548
- if (!authRequestId) throw new Error("ONES: Cannot parse auth_request_id from authorize redirect");
549
- const finalizeRes = await fetch(`${baseUrl}/identity/api/auth_request/finalize`, {
550
- method: "POST",
551
- headers: {
552
- "Content-Type": "application/json;charset=UTF-8",
553
- "Cookie": cookies
554
- },
555
- body: JSON.stringify({
556
- auth_request_id: authRequestId,
557
- region_uuid: orgUser.region_uuid,
558
- org_uuid: orgUser.org_uuid,
559
- org_user_uuid: orgUser.org_user.org_user_uuid
560
- })
561
- });
562
- if (!finalizeRes.ok) {
563
- const text = await finalizeRes.text().catch(() => "");
564
- throw new Error(`ONES: Finalize failed: ${finalizeRes.status} ${text}`);
635
+ let code = parseAuthorizationCode(authorizeLocation);
636
+ if (!code) {
637
+ const authRequestId = parseAuthorizeRequestId(authorizeLocation);
638
+ if (!authRequestId) throw new Error("ONES: Cannot parse auth_request_id from authorize redirect");
639
+ const finalizeRes = await fetch(`${baseUrl}/identity/api/auth_request/finalize`, {
640
+ method: "POST",
641
+ headers: {
642
+ "Content-Type": "application/json;charset=UTF-8",
643
+ "Cookie": cookies
644
+ },
645
+ body: JSON.stringify({
646
+ auth_request_id: authRequestId,
647
+ region_uuid: orgUser.region_uuid,
648
+ org_uuid: orgUser.org_uuid,
649
+ org_user_uuid: orgUser.org_user.org_user_uuid
650
+ })
651
+ });
652
+ if (!finalizeRes.ok) {
653
+ const text = await finalizeRes.text().catch(() => "");
654
+ throw new Error(`ONES: Finalize failed: ${finalizeRes.status} ${text}`);
655
+ }
656
+ const callbackLocation = (await fetch(`${baseUrl}/identity/authorize/callback?id=${authRequestId}&lang=zh`, {
657
+ method: "GET",
658
+ headers: { Cookie: cookies },
659
+ redirect: "manual"
660
+ })).headers.get("location");
661
+ if (!callbackLocation) throw new Error("ONES: Callback response missing location header");
662
+ code = parseAuthorizationCode(callbackLocation);
565
663
  }
566
- const callbackLocation = (await fetch(`${baseUrl}/identity/authorize/callback?id=${authRequestId}&lang=zh`, {
567
- method: "GET",
568
- headers: { Cookie: cookies },
569
- redirect: "manual"
570
- })).headers.get("location");
571
- if (!callbackLocation) throw new Error("ONES: Callback response missing location header");
572
- const code = new URL(callbackLocation).searchParams.get("code");
573
664
  if (!code) throw new Error("ONES: Cannot parse authorization code from callback redirect");
574
665
  const tokenRes = await fetch(`${baseUrl}/identity/oauth/token`, {
575
666
  method: "POST",
@@ -639,11 +730,107 @@ var OnesAdapter = class extends BaseAdapter {
639
730
  }
640
731
  return response.json();
641
732
  }
733
+ async searchTaskByNumber(taskNumber) {
734
+ const session = await this.login();
735
+ const url = `${this.config.apiBase}/project/api/project/team/${session.teamUuid}/search?q=${encodeURIComponent(String(taskNumber))}&start=0&limit=10&types=task`;
736
+ const response = await fetch(url, { headers: { Authorization: `Bearer ${session.accessToken}` } });
737
+ if (!response.ok) return null;
738
+ const found = ((await response.json()).datas?.task ?? []).map((item) => item.fields).find((fields) => fields?.uuid && fields.number === taskNumber);
739
+ if (!found?.uuid) return null;
740
+ return {
741
+ key: `task-${found.uuid}`,
742
+ uuid: found.uuid,
743
+ number: found.number ?? taskNumber,
744
+ name: found.summary ?? "",
745
+ status: {
746
+ uuid: "",
747
+ name: "",
748
+ category: void 0
749
+ },
750
+ issueType: found.issue_type_uuid || found.issue_type_name ? {
751
+ uuid: found.issue_type_uuid ?? "",
752
+ name: found.issue_type_name ?? ""
753
+ } : void 0,
754
+ project: found.project_uuid || found.project_name ? {
755
+ uuid: found.project_uuid ?? "",
756
+ name: found.project_name ?? ""
757
+ } : void 0
758
+ };
759
+ }
642
760
  async fetchIssueTypes() {
643
761
  if (this.issueTypesCache) return this.issueTypesCache;
644
762
  this.issueTypesCache = (await this.graphql(ISSUE_TYPES_QUERY, { orderBy: { namePinyin: "ASC" } }, "issueTypes")).data?.issueTypes ?? [];
645
763
  return this.issueTypesCache;
646
764
  }
765
+ async fetchProjects() {
766
+ return (await this.graphql(PROJECTS_QUERY, {
767
+ projectOrderBy: {
768
+ isPin: "DESC",
769
+ namePinyin: "ASC",
770
+ createTime: "DESC"
771
+ },
772
+ projectFilterGroup: [{
773
+ visibleInProject_equal: true,
774
+ isArchive_equal: false
775
+ }],
776
+ groupBy: { projects: {} },
777
+ orderBy: null,
778
+ pagination: {
779
+ limit: 50,
780
+ after: "",
781
+ preciseCount: true
782
+ }
783
+ }, "projects-group-list-for-project-view")).data?.buckets?.flatMap((bucket) => bucket.projects ?? []) ?? [];
784
+ }
785
+ async findTaskByNumber(taskNumber, projectUuid) {
786
+ const filter = { number_in: [taskNumber] };
787
+ if (projectUuid) filter.project_in = [projectUuid];
788
+ const found = ((await this.graphql(TASK_BY_NUMBER_QUERY, {
789
+ groupBy: { tasks: {} },
790
+ groupOrderBy: null,
791
+ orderBy: { createTime: "DESC" },
792
+ filterGroup: [filter],
793
+ search: null,
794
+ pagination: {
795
+ limit: 10,
796
+ preciseCount: false
797
+ },
798
+ limit: 10
799
+ }, "group-task-data")).data?.buckets?.flatMap((b) => b.tasks ?? []) ?? []).find((task) => task.number === taskNumber && (!projectUuid || task.project?.uuid === projectUuid));
800
+ if (found) return found;
801
+ if (projectUuid) return null;
802
+ return this.searchTaskByNumber(taskNumber);
803
+ }
804
+ async resolveTaskRef(input) {
805
+ const taskId = input.trim();
806
+ if (!taskId) throw new Error("ONES: taskId is required");
807
+ const numMatch = taskId.match(/^#?(\d+)$/);
808
+ if (numMatch) {
809
+ const taskNumber = Number.parseInt(numMatch[1], 10);
810
+ const found = await this.findTaskByNumber(taskNumber);
811
+ if (!found) throw new Error(`ONES: Task #${taskNumber} not found in current team`);
812
+ return {
813
+ key: found.key ?? `task-${found.uuid}`,
814
+ uuid: found.uuid
815
+ };
816
+ }
817
+ const displayId = parseDisplayId(taskId);
818
+ if (displayId) {
819
+ const project = (await this.fetchProjects()).find((item) => item.identifier?.toLowerCase() === displayId.identifier.toLowerCase());
820
+ if (!project) throw new Error(`ONES: Project identifier "${displayId.identifier}" not found in current team`);
821
+ const found = await this.findTaskByNumber(displayId.number, project.uuid);
822
+ if (!found) throw new Error(`ONES: Task "${taskId}" not found in current team`);
823
+ return {
824
+ key: found.key ?? `task-${found.uuid}`,
825
+ uuid: found.uuid
826
+ };
827
+ }
828
+ const key = taskId.startsWith("task-") ? taskId : `task-${taskId}`;
829
+ return {
830
+ key,
831
+ uuid: key.slice(5)
832
+ };
833
+ }
647
834
  async searchTeamUsers(keyword) {
648
835
  const session = await this.login();
649
836
  const url = `${this.config.apiBase}/project/api/project/team/${session.teamUuid}/users/search`;
@@ -832,27 +1019,9 @@ var OnesAdapter = class extends BaseAdapter {
832
1019
  };
833
1020
  }
834
1021
  if (isOnesWikiUrlInput(params.id)) throw new Error("ONES: Unsupported wiki page URL. Expected /wiki/#/team/{teamUuid}/space/{spaceUuid}/page/{wikiUuid}");
835
- let taskUuid = params.id;
836
- const numMatch = taskUuid.match(/^#?(\d+)$/);
837
- if (numMatch) {
838
- const taskNumber = Number.parseInt(numMatch[1], 10);
839
- const found = ((await this.graphql(TASK_BY_NUMBER_QUERY, {
840
- groupBy: { tasks: {} },
841
- groupOrderBy: null,
842
- orderBy: { createTime: "DESC" },
843
- filterGroup: [{ number_in: [taskNumber] }],
844
- search: null,
845
- pagination: {
846
- limit: 10,
847
- preciseCount: false
848
- },
849
- limit: 10
850
- }, "group-task-data")).data?.buckets?.flatMap((b) => b.tasks ?? []) ?? []).find((t) => t.number === taskNumber);
851
- if (!found) throw new Error(`ONES: Task #${taskNumber} not found in current team`);
852
- taskUuid = found.uuid;
853
- }
854
- const task = (await this.graphql(TASK_DETAIL_QUERY, { key: `task-${taskUuid}` }, "Task")).data?.task;
855
- if (!task) throw new Error(`ONES: Task "${taskUuid}" not found`);
1022
+ const taskRef = await this.resolveTaskRef(params.id);
1023
+ const task = (await this.graphql(TASK_DETAIL_QUERY, { key: taskRef.key }, "Task")).data?.task;
1024
+ if (!task) throw new Error(`ONES: Task "${params.id}" not found`);
856
1025
  const wikiRefs = /* @__PURE__ */ new Map();
857
1026
  for (const wiki of task.relatedWikiPages ?? []) if (!wiki.errorMessage) wikiRefs.set(wiki.uuid, {
858
1027
  title: wiki.title,
@@ -987,6 +1156,69 @@ var OnesAdapter = class extends BaseAdapter {
987
1156
  pageSize
988
1157
  };
989
1158
  }
1159
+ async addManhour(params) {
1160
+ const description = params.description.trim();
1161
+ if (!description) throw new Error("ONES: description is required");
1162
+ const taskRef = await this.resolveTaskRef(params.taskId);
1163
+ const onesHours = toOnesHours(params.hours);
1164
+ const workDate = parseManhourDate(params.date);
1165
+ const key = (await this.graphql(ADD_MANHOUR_MUTATION, {
1166
+ mode: "simple",
1167
+ type: "recorded",
1168
+ customData: {},
1169
+ owner: (await this.login()).userUuid,
1170
+ task: taskRef.uuid,
1171
+ start_time: workDate.startTime,
1172
+ hours: onesHours,
1173
+ description
1174
+ }, "add-manhour")).data?.addManhour?.key;
1175
+ if (!key) throw new Error("ONES: Failed to add manhour");
1176
+ return {
1177
+ key,
1178
+ taskUuid: taskRef.uuid,
1179
+ hours: params.hours,
1180
+ description,
1181
+ date: workDate.date
1182
+ };
1183
+ }
1184
+ async updateTaskPlanDates(params) {
1185
+ const planStartDate = params.planStartDate?.trim();
1186
+ const planEndDate = params.planEndDate?.trim();
1187
+ if (!planStartDate && !planEndDate) throw new Error("ONES: planStartDate or planEndDate is required");
1188
+ if (planStartDate && !isValidOnesDate(planStartDate)) throw new Error("ONES: planStartDate must be a valid YYYY-MM-DD date");
1189
+ if (planEndDate && !isValidOnesDate(planEndDate)) throw new Error("ONES: planEndDate must be a valid YYYY-MM-DD date");
1190
+ const taskRef = await this.resolveTaskRef(params.taskId);
1191
+ const session = await this.login();
1192
+ const fieldValues = [];
1193
+ if (planStartDate) fieldValues.push({
1194
+ field_uuid: "field027",
1195
+ value: planStartDate
1196
+ });
1197
+ if (planEndDate) fieldValues.push({
1198
+ field_uuid: "field028",
1199
+ value: planEndDate
1200
+ });
1201
+ const response = await fetch(`${this.config.apiBase}/project/api/project/team/${session.teamUuid}/tasks/update3`, {
1202
+ method: "POST",
1203
+ headers: {
1204
+ "Authorization": `Bearer ${session.accessToken}`,
1205
+ "Content-Type": "application/json"
1206
+ },
1207
+ body: JSON.stringify({ tasks: [{
1208
+ uuid: taskRef.uuid,
1209
+ field_values: fieldValues
1210
+ }] })
1211
+ });
1212
+ if (!response.ok) {
1213
+ const text = await response.text().catch(() => "");
1214
+ throw new Error(`ONES: Failed to update task plan dates: ${response.status} ${text}`);
1215
+ }
1216
+ return {
1217
+ taskUuid: taskRef.uuid,
1218
+ planStartDate: planStartDate ?? null,
1219
+ planEndDate: planEndDate ?? null
1220
+ };
1221
+ }
990
1222
  async getRelatedIssues(params) {
991
1223
  const session = await this.login();
992
1224
  const taskKey = params.taskId.startsWith("task-") ? params.taskId : `task-${params.taskId}`;
@@ -1334,6 +1566,42 @@ function loadConfig(startDir) {
1334
1566
  };
1335
1567
  }
1336
1568
 
1569
+ //#endregion
1570
+ //#region src/tools/add-manhour.ts
1571
+ const AddManhourSchema = zod_v4.z.object({
1572
+ taskId: zod_v4.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\")"),
1573
+ hours: zod_v4.z.number().positive().describe("Work hours to record. Natural hours are converted to ONES internal units."),
1574
+ description: zod_v4.z.string().min(1).describe("Work log description."),
1575
+ date: zod_v4.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."),
1576
+ source: zod_v4.z.string().optional().describe("Source to update. If omitted, uses the default source.")
1577
+ });
1578
+ async function handleAddManhour(input, adapters, defaultSource) {
1579
+ const sourceType = input.source ?? defaultSource;
1580
+ if (!sourceType) throw new Error("No source specified and no default source configured");
1581
+ const adapter = adapters.get(sourceType);
1582
+ if (!adapter) throw new Error(`Source "${sourceType}" is not configured. Available: ${[...adapters.keys()].join(", ")}`);
1583
+ return { content: [{
1584
+ type: "text",
1585
+ text: formatAddManhourResult(await adapter.addManhour({
1586
+ taskId: input.taskId,
1587
+ hours: input.hours,
1588
+ description: input.description,
1589
+ date: input.date
1590
+ }))
1591
+ }] };
1592
+ }
1593
+ function formatAddManhourResult(result) {
1594
+ return [
1595
+ "Added manhour.",
1596
+ "",
1597
+ `- **Key**: ${result.key}`,
1598
+ `- **Task UUID**: ${result.taskUuid}`,
1599
+ `- **Hours**: ${result.hours}`,
1600
+ `- **Date**: ${result.date ?? "today"}`,
1601
+ `- **Description**: ${result.description}`
1602
+ ].join("\n");
1603
+ }
1604
+
1337
1605
  //#endregion
1338
1606
  //#region src/tools/get-issue-detail.ts
1339
1607
  const GetIssueDetailSchema = zod_v4.z.object({
@@ -1648,6 +1916,40 @@ async function handleSearchRequirements(input, adapters, defaultSource) {
1648
1916
  }] };
1649
1917
  }
1650
1918
 
1919
+ //#endregion
1920
+ //#region src/tools/update-task-plan-dates.ts
1921
+ const DateSchema = zod_v4.z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Expected YYYY-MM-DD");
1922
+ const UpdateTaskPlanDatesSchema = zod_v4.z.object({
1923
+ taskId: zod_v4.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\")"),
1924
+ planStartDate: DateSchema.optional().describe("Plan start date in YYYY-MM-DD format."),
1925
+ planEndDate: DateSchema.optional().describe("Plan end date in YYYY-MM-DD format."),
1926
+ source: zod_v4.z.string().optional().describe("Source to update. If omitted, uses the default source.")
1927
+ });
1928
+ async function handleUpdateTaskPlanDates(input, adapters, defaultSource) {
1929
+ const sourceType = input.source ?? defaultSource;
1930
+ if (!sourceType) throw new Error("No source specified and no default source configured");
1931
+ const adapter = adapters.get(sourceType);
1932
+ if (!adapter) throw new Error(`Source "${sourceType}" is not configured. Available: ${[...adapters.keys()].join(", ")}`);
1933
+ return { content: [{
1934
+ type: "text",
1935
+ text: formatUpdateTaskPlanDatesResult(await adapter.updateTaskPlanDates({
1936
+ taskId: input.taskId,
1937
+ planStartDate: input.planStartDate,
1938
+ planEndDate: input.planEndDate
1939
+ }))
1940
+ }] };
1941
+ }
1942
+ function formatUpdateTaskPlanDatesResult(result) {
1943
+ const lines = [
1944
+ "Updated task plan dates.",
1945
+ "",
1946
+ `- **Task UUID**: ${result.taskUuid}`
1947
+ ];
1948
+ if (result.planStartDate) lines.push(`- **Plan Start Date**: ${result.planStartDate}`);
1949
+ if (result.planEndDate) lines.push(`- **Plan End Date**: ${result.planEndDate}`);
1950
+ return lines.join("\n");
1951
+ }
1952
+
1651
1953
  //#endregion
1652
1954
  //#region src/index.ts
1653
1955
  /**
@@ -1773,6 +2075,32 @@ async function main() {
1773
2075
  };
1774
2076
  }
1775
2077
  });
2078
+ 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) => {
2079
+ try {
2080
+ return await handleAddManhour(params, adapters, config.config.defaultSource);
2081
+ } catch (err) {
2082
+ return {
2083
+ content: [{
2084
+ type: "text",
2085
+ text: `Error: ${err.message}`
2086
+ }],
2087
+ isError: true
2088
+ };
2089
+ }
2090
+ });
2091
+ 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) => {
2092
+ try {
2093
+ return await handleUpdateTaskPlanDates(params, adapters, config.config.defaultSource);
2094
+ } catch (err) {
2095
+ return {
2096
+ content: [{
2097
+ type: "text",
2098
+ text: `Error: ${err.message}`
2099
+ }],
2100
+ isError: true
2101
+ };
2102
+ }
2103
+ });
1776
2104
  const transport = new _modelcontextprotocol_sdk_server_stdio_js.StdioServerTransport();
1777
2105
  await server.connect(transport);
1778
2106
  }