@pschroee/redmine-mcp 0.5.10 → 0.5.13
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/formatters/issue.js
CHANGED
|
@@ -144,9 +144,23 @@ export function formatIssueList(response) {
|
|
|
144
144
|
lines.push("No issues found.");
|
|
145
145
|
return lines.join("\n");
|
|
146
146
|
}
|
|
147
|
+
// Collect all unique custom field names (preserving order by ID)
|
|
148
|
+
const customFieldMap = new Map(); // id -> name
|
|
149
|
+
for (const issue of issues) {
|
|
150
|
+
if (issue.custom_fields) {
|
|
151
|
+
for (const cf of issue.custom_fields) {
|
|
152
|
+
if (!customFieldMap.has(cf.id)) {
|
|
153
|
+
customFieldMap.set(cf.id, cf.name);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const customFieldIds = Array.from(customFieldMap.keys()).sort((a, b) => a - b);
|
|
159
|
+
const customFieldNames = customFieldIds.map(id => customFieldMap.get(id));
|
|
147
160
|
// Table header
|
|
148
|
-
|
|
149
|
-
lines.push("
|
|
161
|
+
const headerCols = ["ID", "Subject", "Status", "Priority", "Assigned", "Version", "Created", "Updated", ...customFieldNames];
|
|
162
|
+
lines.push("| " + headerCols.join(" | ") + " |");
|
|
163
|
+
lines.push("|" + headerCols.map(() => "---").join("|") + "|");
|
|
150
164
|
// Table rows
|
|
151
165
|
for (const issue of issues) {
|
|
152
166
|
const id = `#${issue.id}`;
|
|
@@ -154,8 +168,23 @@ export function formatIssueList(response) {
|
|
|
154
168
|
const status = issue.status.name;
|
|
155
169
|
const priority = issue.priority.name;
|
|
156
170
|
const assigned = issue.assigned_to?.name ?? "_(unassigned)_";
|
|
171
|
+
const version = issue.fixed_version?.name ?? "";
|
|
172
|
+
const created = formatDateShort(issue.created_on);
|
|
157
173
|
const updated = formatDateShort(issue.updated_on);
|
|
158
|
-
|
|
174
|
+
// Build custom field values in order
|
|
175
|
+
const cfValues = [];
|
|
176
|
+
for (const cfId of customFieldIds) {
|
|
177
|
+
const cf = issue.custom_fields?.find(f => f.id === cfId);
|
|
178
|
+
if (cf) {
|
|
179
|
+
const value = Array.isArray(cf.value) ? cf.value.join(", ") : cf.value;
|
|
180
|
+
cfValues.push(value || "");
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
cfValues.push("");
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const cols = [id, subject, status, priority, assigned, version, created, updated, ...cfValues];
|
|
187
|
+
lines.push("| " + cols.join(" | ") + " |");
|
|
159
188
|
}
|
|
160
189
|
return lines.join("\n");
|
|
161
190
|
}
|
|
@@ -125,9 +125,12 @@ export declare function formatCategory(response: {
|
|
|
125
125
|
*/
|
|
126
126
|
export declare function formatCustomFieldList(response: RedmineCustomFieldsResponse): string;
|
|
127
127
|
/**
|
|
128
|
-
* Project lookup map: ID -> name
|
|
128
|
+
* Project lookup map: ID -> { name, identifier }
|
|
129
129
|
*/
|
|
130
|
-
export type ProjectLookup = Record<number,
|
|
130
|
+
export type ProjectLookup = Record<number, {
|
|
131
|
+
name: string;
|
|
132
|
+
identifier: string;
|
|
133
|
+
}>;
|
|
131
134
|
/**
|
|
132
135
|
* Format a list of saved queries as a Markdown table
|
|
133
136
|
*/
|
|
@@ -184,16 +184,24 @@ export function formatQueryList(response, projectLookup = {}) {
|
|
|
184
184
|
const lines = [];
|
|
185
185
|
lines.push(`# Saved Queries (${queries.length})`);
|
|
186
186
|
lines.push("");
|
|
187
|
-
lines.push("| ID | Name | Project | Visibility |");
|
|
188
|
-
lines.push("
|
|
187
|
+
lines.push("| ID | Name | Project | Project Identifier | Visibility |");
|
|
188
|
+
lines.push("|----|------|---------|-------------------|------------|");
|
|
189
189
|
for (const query of queries) {
|
|
190
190
|
const visibility = query.is_public ? "Public" : "Private";
|
|
191
|
-
let
|
|
191
|
+
let projectName = "";
|
|
192
|
+
let projectIdentifier = "";
|
|
192
193
|
if (query.project_id) {
|
|
193
|
-
const
|
|
194
|
-
|
|
194
|
+
const projectInfo = projectLookup[query.project_id];
|
|
195
|
+
if (projectInfo) {
|
|
196
|
+
projectName = projectInfo.name;
|
|
197
|
+
projectIdentifier = projectInfo.identifier;
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
projectName = `#${query.project_id}`;
|
|
201
|
+
projectIdentifier = `#${query.project_id}`;
|
|
202
|
+
}
|
|
195
203
|
}
|
|
196
|
-
lines.push(`| ${query.id} | ${query.name} | ${
|
|
204
|
+
lines.push(`| ${query.id} | ${query.name} | ${projectName} | ${projectIdentifier} | ${visibility} |`);
|
|
197
205
|
}
|
|
198
206
|
return lines.join("\n");
|
|
199
207
|
}
|
package/dist/tools/metadata.js
CHANGED
|
@@ -129,13 +129,13 @@ export function registerMetadataTools(server, client) {
|
|
|
129
129
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
130
130
|
};
|
|
131
131
|
}
|
|
132
|
-
// Build project lookup for resolving project names
|
|
132
|
+
// Build project lookup for resolving project names and identifiers
|
|
133
133
|
const projectLookup = {};
|
|
134
134
|
const projectsResult = await client.listProjects({ limit: 100 });
|
|
135
135
|
let filterProjectId;
|
|
136
136
|
if (!("error" in projectsResult)) {
|
|
137
137
|
for (const project of projectsResult.projects) {
|
|
138
|
-
projectLookup[project.id] = project.name;
|
|
138
|
+
projectLookup[project.id] = { name: project.name, identifier: project.identifier };
|
|
139
139
|
// Find the numeric ID for the filter project identifier
|
|
140
140
|
if (params.project_id && project.identifier === params.project_id) {
|
|
141
141
|
filterProjectId = project.id;
|