ralph-hero-mcp-server 1.3.2 → 1.3.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 +3 -0
- package/dist/lib/helpers.js +25 -0
- package/dist/lib/workflow-states.js +22 -0
- package/dist/tools/batch-tools.js +22 -1
- package/dist/tools/issue-tools.js +3 -1
- package/dist/tools/project-management-tools.js +248 -0
- package/dist/tools/relationship-tools.js +3 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import { registerIssueTools } from "./tools/issue-tools.js";
|
|
|
17
17
|
import { registerRelationshipTools } from "./tools/relationship-tools.js";
|
|
18
18
|
import { registerDashboardTools } from "./tools/dashboard-tools.js";
|
|
19
19
|
import { registerBatchTools } from "./tools/batch-tools.js";
|
|
20
|
+
import { registerProjectManagementTools } from "./tools/project-management-tools.js";
|
|
20
21
|
/**
|
|
21
22
|
* Initialize the GitHub client from environment variables.
|
|
22
23
|
*/
|
|
@@ -242,6 +243,8 @@ async function main() {
|
|
|
242
243
|
registerDashboardTools(server, client, fieldCache);
|
|
243
244
|
// Phase 5: Batch operations
|
|
244
245
|
registerBatchTools(server, client, fieldCache);
|
|
246
|
+
// Project management tools (archive, remove, add, link repo, clear field)
|
|
247
|
+
registerProjectManagementTools(server, client, fieldCache);
|
|
245
248
|
// Connect via stdio transport
|
|
246
249
|
const transport = new StdioServerTransport();
|
|
247
250
|
await server.connect(transport);
|
package/dist/lib/helpers.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* implementations to their original versions.
|
|
7
7
|
*/
|
|
8
8
|
import { resolveProjectOwner } from "../types.js";
|
|
9
|
+
import { WORKFLOW_STATE_TO_STATUS } from "./workflow-states.js";
|
|
9
10
|
// ---------------------------------------------------------------------------
|
|
10
11
|
// Helper: Fetch project data for field cache population
|
|
11
12
|
// ---------------------------------------------------------------------------
|
|
@@ -197,4 +198,28 @@ export function resolveFullConfig(client, args) {
|
|
|
197
198
|
}
|
|
198
199
|
return { owner, repo, projectNumber, projectOwner };
|
|
199
200
|
}
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
// Helper: Sync default Status field after Workflow State change
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
/**
|
|
205
|
+
* Sync the default Status field to match a Workflow State change.
|
|
206
|
+
* Best-effort: logs warning on failure but does not throw.
|
|
207
|
+
*/
|
|
208
|
+
export async function syncStatusField(client, fieldCache, projectItemId, workflowState) {
|
|
209
|
+
const targetStatus = WORKFLOW_STATE_TO_STATUS[workflowState];
|
|
210
|
+
if (!targetStatus)
|
|
211
|
+
return;
|
|
212
|
+
const statusFieldId = fieldCache.getFieldId("Status");
|
|
213
|
+
if (!statusFieldId)
|
|
214
|
+
return;
|
|
215
|
+
const statusOptionId = fieldCache.resolveOptionId("Status", targetStatus);
|
|
216
|
+
if (!statusOptionId)
|
|
217
|
+
return;
|
|
218
|
+
try {
|
|
219
|
+
await updateProjectItemField(client, fieldCache, projectItemId, "Status", targetStatus);
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
// Best-effort sync - don't fail the primary operation
|
|
223
|
+
}
|
|
224
|
+
}
|
|
200
225
|
//# sourceMappingURL=helpers.js.map
|
|
@@ -79,4 +79,26 @@ export function isEarlierState(a, b) {
|
|
|
79
79
|
export function isValidState(state) {
|
|
80
80
|
return VALID_STATES.includes(state);
|
|
81
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Maps Ralph Workflow States to GitHub's default Status field values.
|
|
84
|
+
* Used for one-way sync: Workflow State changes -> Status field updates.
|
|
85
|
+
*
|
|
86
|
+
* Rationale:
|
|
87
|
+
* - Todo = work not yet actively started (queued states)
|
|
88
|
+
* - In Progress = work actively being processed (lock states + review)
|
|
89
|
+
* - Done = terminal/escalated states (no automated progression)
|
|
90
|
+
*/
|
|
91
|
+
export const WORKFLOW_STATE_TO_STATUS = {
|
|
92
|
+
"Backlog": "Todo",
|
|
93
|
+
"Research Needed": "Todo",
|
|
94
|
+
"Ready for Plan": "Todo",
|
|
95
|
+
"Plan in Review": "Todo",
|
|
96
|
+
"Research in Progress": "In Progress",
|
|
97
|
+
"Plan in Progress": "In Progress",
|
|
98
|
+
"In Progress": "In Progress",
|
|
99
|
+
"In Review": "In Progress",
|
|
100
|
+
"Done": "Done",
|
|
101
|
+
"Canceled": "Done",
|
|
102
|
+
"Human Needed": "Done",
|
|
103
|
+
};
|
|
82
104
|
//# sourceMappingURL=workflow-states.js.map
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* instead of one per issue).
|
|
7
7
|
*/
|
|
8
8
|
import { z } from "zod";
|
|
9
|
-
import { isEarlierState } from "../lib/workflow-states.js";
|
|
9
|
+
import { isEarlierState, WORKFLOW_STATE_TO_STATUS } from "../lib/workflow-states.js";
|
|
10
10
|
import { toolSuccess, toolError } from "../types.js";
|
|
11
11
|
import { ensureFieldCache, resolveFullConfig, } from "../lib/helpers.js";
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
@@ -267,6 +267,27 @@ export function registerBatchTools(server, client, fieldCache) {
|
|
|
267
267
|
field: op.field,
|
|
268
268
|
value: op.value,
|
|
269
269
|
});
|
|
270
|
+
// For workflow_state operations, also sync the default Status field
|
|
271
|
+
if (op.field === "workflow_state") {
|
|
272
|
+
const targetStatus = WORKFLOW_STATE_TO_STATUS[op.value];
|
|
273
|
+
if (targetStatus) {
|
|
274
|
+
const statusFieldId = fieldCache.getFieldId("Status");
|
|
275
|
+
const statusOptionId = statusFieldId
|
|
276
|
+
? fieldCache.resolveOptionId("Status", targetStatus)
|
|
277
|
+
: undefined;
|
|
278
|
+
if (statusFieldId && statusOptionId) {
|
|
279
|
+
updates.push({
|
|
280
|
+
alias: `s${num}_${opIdx}`,
|
|
281
|
+
itemId: issue.projectItemId,
|
|
282
|
+
fieldId: statusFieldId,
|
|
283
|
+
optionId: statusOptionId,
|
|
284
|
+
issueNumber: num,
|
|
285
|
+
field: "status_sync",
|
|
286
|
+
value: targetStatus,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
270
291
|
}
|
|
271
292
|
}
|
|
272
293
|
// Chunk mutations if needed
|
|
@@ -11,7 +11,7 @@ import { detectPipelinePosition, } from "../lib/pipeline-detection.js";
|
|
|
11
11
|
import { isValidState, VALID_STATES, LOCK_STATES, } from "../lib/workflow-states.js";
|
|
12
12
|
import { resolveState } from "../lib/state-resolution.js";
|
|
13
13
|
import { toolSuccess, toolError } from "../types.js";
|
|
14
|
-
import { ensureFieldCache, resolveIssueNodeId, resolveProjectItemId, updateProjectItemField, getCurrentFieldValue, resolveConfig, resolveFullConfig, } from "../lib/helpers.js";
|
|
14
|
+
import { ensureFieldCache, resolveIssueNodeId, resolveProjectItemId, updateProjectItemField, getCurrentFieldValue, resolveConfig, resolveFullConfig, syncStatusField, } from "../lib/helpers.js";
|
|
15
15
|
// ---------------------------------------------------------------------------
|
|
16
16
|
// Register issue tools
|
|
17
17
|
// ---------------------------------------------------------------------------
|
|
@@ -607,6 +607,8 @@ export function registerIssueTools(server, client, fieldCache) {
|
|
|
607
607
|
const projectItemId = await resolveProjectItemId(client, fieldCache, owner, repo, args.number);
|
|
608
608
|
// Update the field with the resolved state
|
|
609
609
|
await updateProjectItemField(client, fieldCache, projectItemId, "Workflow State", resolvedState);
|
|
610
|
+
// Sync default Status field (best-effort, one-way)
|
|
611
|
+
await syncStatusField(client, fieldCache, projectItemId, resolvedState);
|
|
610
612
|
const result = {
|
|
611
613
|
number: args.number,
|
|
612
614
|
previousState: previousState || "(unknown)",
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tools for GitHub Projects V2 management operations.
|
|
3
|
+
*
|
|
4
|
+
* Provides tools for archiving/unarchiving items, removing items from projects,
|
|
5
|
+
* adding existing issues to projects, linking repositories, and clearing field values.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { toolSuccess, toolError } from "../types.js";
|
|
9
|
+
import { ensureFieldCache, resolveIssueNodeId, resolveProjectItemId, resolveFullConfig, } from "../lib/helpers.js";
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Register project management tools
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
export function registerProjectManagementTools(server, client, fieldCache) {
|
|
14
|
+
// -------------------------------------------------------------------------
|
|
15
|
+
// ralph_hero__archive_item
|
|
16
|
+
// -------------------------------------------------------------------------
|
|
17
|
+
server.tool("ralph_hero__archive_item", "Archive or unarchive a project item. Archived items are hidden from default views but not deleted. Returns: number, archived, projectItemId.", {
|
|
18
|
+
owner: z.string().optional().describe("GitHub owner. Defaults to env var"),
|
|
19
|
+
repo: z.string().optional().describe("Repository name. Defaults to env var"),
|
|
20
|
+
number: z.number().describe("Issue number"),
|
|
21
|
+
unarchive: z.boolean().optional().default(false)
|
|
22
|
+
.describe("If true, unarchive instead of archive (default: false)"),
|
|
23
|
+
}, async (args) => {
|
|
24
|
+
try {
|
|
25
|
+
const { owner, repo, projectNumber, projectOwner } = resolveFullConfig(client, args);
|
|
26
|
+
await ensureFieldCache(client, fieldCache, projectOwner, projectNumber);
|
|
27
|
+
const projectId = fieldCache.getProjectId();
|
|
28
|
+
if (!projectId) {
|
|
29
|
+
return toolError("Could not resolve project ID");
|
|
30
|
+
}
|
|
31
|
+
const projectItemId = await resolveProjectItemId(client, fieldCache, owner, repo, args.number);
|
|
32
|
+
if (args.unarchive) {
|
|
33
|
+
await client.projectMutate(`mutation($projectId: ID!, $itemId: ID!) {
|
|
34
|
+
unarchiveProjectV2Item(input: {
|
|
35
|
+
projectId: $projectId,
|
|
36
|
+
itemId: $itemId
|
|
37
|
+
}) {
|
|
38
|
+
item { id }
|
|
39
|
+
}
|
|
40
|
+
}`, { projectId, itemId: projectItemId });
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
await client.projectMutate(`mutation($projectId: ID!, $itemId: ID!) {
|
|
44
|
+
archiveProjectV2Item(input: {
|
|
45
|
+
projectId: $projectId,
|
|
46
|
+
itemId: $itemId
|
|
47
|
+
}) {
|
|
48
|
+
item { id }
|
|
49
|
+
}
|
|
50
|
+
}`, { projectId, itemId: projectItemId });
|
|
51
|
+
}
|
|
52
|
+
return toolSuccess({
|
|
53
|
+
number: args.number,
|
|
54
|
+
archived: !args.unarchive,
|
|
55
|
+
projectItemId,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
60
|
+
return toolError(`Failed to ${args.unarchive ? "unarchive" : "archive"} item: ${message}`);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
// -------------------------------------------------------------------------
|
|
64
|
+
// ralph_hero__remove_from_project
|
|
65
|
+
// -------------------------------------------------------------------------
|
|
66
|
+
server.tool("ralph_hero__remove_from_project", "Remove an issue from the project. This deletes the project item (not the issue itself). Returns: number, removed.", {
|
|
67
|
+
owner: z.string().optional().describe("GitHub owner. Defaults to env var"),
|
|
68
|
+
repo: z.string().optional().describe("Repository name. Defaults to env var"),
|
|
69
|
+
number: z.number().describe("Issue number"),
|
|
70
|
+
}, async (args) => {
|
|
71
|
+
try {
|
|
72
|
+
const { owner, repo, projectNumber, projectOwner } = resolveFullConfig(client, args);
|
|
73
|
+
await ensureFieldCache(client, fieldCache, projectOwner, projectNumber);
|
|
74
|
+
const projectId = fieldCache.getProjectId();
|
|
75
|
+
if (!projectId) {
|
|
76
|
+
return toolError("Could not resolve project ID");
|
|
77
|
+
}
|
|
78
|
+
const projectItemId = await resolveProjectItemId(client, fieldCache, owner, repo, args.number);
|
|
79
|
+
await client.projectMutate(`mutation($projectId: ID!, $itemId: ID!) {
|
|
80
|
+
deleteProjectV2Item(input: {
|
|
81
|
+
projectId: $projectId,
|
|
82
|
+
itemId: $itemId
|
|
83
|
+
}) {
|
|
84
|
+
deletedItemId
|
|
85
|
+
}
|
|
86
|
+
}`, { projectId, itemId: projectItemId });
|
|
87
|
+
// Invalidate cached project item ID since it no longer exists
|
|
88
|
+
client.getCache().invalidate(`project-item-id:${owner}/${repo}#${args.number}`);
|
|
89
|
+
return toolSuccess({
|
|
90
|
+
number: args.number,
|
|
91
|
+
removed: true,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
96
|
+
return toolError(`Failed to remove from project: ${message}`);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
// -------------------------------------------------------------------------
|
|
100
|
+
// ralph_hero__add_to_project
|
|
101
|
+
// -------------------------------------------------------------------------
|
|
102
|
+
server.tool("ralph_hero__add_to_project", "Add an existing issue to the project. The issue must already exist in the repository. Returns: number, projectItemId, added.", {
|
|
103
|
+
owner: z.string().optional().describe("GitHub owner. Defaults to env var"),
|
|
104
|
+
repo: z.string().optional().describe("Repository name. Defaults to env var"),
|
|
105
|
+
number: z.number().describe("Issue number"),
|
|
106
|
+
}, async (args) => {
|
|
107
|
+
try {
|
|
108
|
+
const { owner, repo, projectNumber, projectOwner } = resolveFullConfig(client, args);
|
|
109
|
+
await ensureFieldCache(client, fieldCache, projectOwner, projectNumber);
|
|
110
|
+
const projectId = fieldCache.getProjectId();
|
|
111
|
+
if (!projectId) {
|
|
112
|
+
return toolError("Could not resolve project ID");
|
|
113
|
+
}
|
|
114
|
+
const issueNodeId = await resolveIssueNodeId(client, owner, repo, args.number);
|
|
115
|
+
const result = await client.projectMutate(`mutation($projectId: ID!, $contentId: ID!) {
|
|
116
|
+
addProjectV2ItemById(input: {
|
|
117
|
+
projectId: $projectId,
|
|
118
|
+
contentId: $contentId
|
|
119
|
+
}) {
|
|
120
|
+
item { id }
|
|
121
|
+
}
|
|
122
|
+
}`, { projectId, contentId: issueNodeId });
|
|
123
|
+
const projectItemId = result.addProjectV2ItemById.item.id;
|
|
124
|
+
// Cache the new project item ID
|
|
125
|
+
client.getCache().set(`project-item-id:${owner}/${repo}#${args.number}`, projectItemId, 30 * 60 * 1000);
|
|
126
|
+
return toolSuccess({
|
|
127
|
+
number: args.number,
|
|
128
|
+
projectItemId,
|
|
129
|
+
added: true,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
134
|
+
return toolError(`Failed to add to project: ${message}`);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
// -------------------------------------------------------------------------
|
|
138
|
+
// ralph_hero__link_repository
|
|
139
|
+
// -------------------------------------------------------------------------
|
|
140
|
+
server.tool("ralph_hero__link_repository", "Link or unlink a repository to/from the project. Linked repositories enable auto-add workflows and issue filtering. Returns: repository, linked.", {
|
|
141
|
+
owner: z.string().optional().describe("GitHub owner. Defaults to env var"),
|
|
142
|
+
repoToLink: z.string()
|
|
143
|
+
.describe("Repository to link, as 'owner/name' or just 'name' (uses default owner)"),
|
|
144
|
+
unlink: z.boolean().optional().default(false)
|
|
145
|
+
.describe("If true, unlink instead of link (default: false)"),
|
|
146
|
+
}, async (args) => {
|
|
147
|
+
try {
|
|
148
|
+
const { projectNumber, projectOwner } = resolveFullConfig(client, args);
|
|
149
|
+
await ensureFieldCache(client, fieldCache, projectOwner, projectNumber);
|
|
150
|
+
const projectId = fieldCache.getProjectId();
|
|
151
|
+
if (!projectId) {
|
|
152
|
+
return toolError("Could not resolve project ID");
|
|
153
|
+
}
|
|
154
|
+
// Parse repoToLink: "owner/name" or just "name" (using default owner)
|
|
155
|
+
let repoOwner;
|
|
156
|
+
let repoName;
|
|
157
|
+
if (args.repoToLink.includes("/")) {
|
|
158
|
+
const parts = args.repoToLink.split("/");
|
|
159
|
+
repoOwner = parts[0];
|
|
160
|
+
repoName = parts[1];
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
repoOwner = client.config.owner || projectOwner;
|
|
164
|
+
repoName = args.repoToLink;
|
|
165
|
+
}
|
|
166
|
+
// Resolve repository node ID
|
|
167
|
+
const repoResult = await client.query(`query($repoOwner: String!, $repoName: String!) {
|
|
168
|
+
repository(owner: $repoOwner, name: $repoName) { id }
|
|
169
|
+
}`, { repoOwner, repoName }, { cache: true, cacheTtlMs: 60 * 60 * 1000 });
|
|
170
|
+
const repoId = repoResult.repository?.id;
|
|
171
|
+
if (!repoId) {
|
|
172
|
+
return toolError(`Repository ${repoOwner}/${repoName} not found`);
|
|
173
|
+
}
|
|
174
|
+
if (args.unlink) {
|
|
175
|
+
await client.projectMutate(`mutation($projectId: ID!, $repositoryId: ID!) {
|
|
176
|
+
unlinkProjectV2FromRepository(input: {
|
|
177
|
+
projectId: $projectId,
|
|
178
|
+
repositoryId: $repositoryId
|
|
179
|
+
}) {
|
|
180
|
+
repository { id }
|
|
181
|
+
}
|
|
182
|
+
}`, { projectId, repositoryId: repoId });
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
await client.projectMutate(`mutation($projectId: ID!, $repositoryId: ID!) {
|
|
186
|
+
linkProjectV2ToRepository(input: {
|
|
187
|
+
projectId: $projectId,
|
|
188
|
+
repositoryId: $repositoryId
|
|
189
|
+
}) {
|
|
190
|
+
repository { id }
|
|
191
|
+
}
|
|
192
|
+
}`, { projectId, repositoryId: repoId });
|
|
193
|
+
}
|
|
194
|
+
return toolSuccess({
|
|
195
|
+
repository: `${repoOwner}/${repoName}`,
|
|
196
|
+
linked: !args.unlink,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
201
|
+
return toolError(`Failed to ${args.unlink ? "unlink" : "link"} repository: ${message}`);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
// -------------------------------------------------------------------------
|
|
205
|
+
// ralph_hero__clear_field
|
|
206
|
+
// -------------------------------------------------------------------------
|
|
207
|
+
server.tool("ralph_hero__clear_field", "Clear a field value on a project item. Works for any single-select field (Workflow State, Estimate, Priority, Status, etc.). Returns: number, field, cleared.", {
|
|
208
|
+
owner: z.string().optional().describe("GitHub owner. Defaults to env var"),
|
|
209
|
+
repo: z.string().optional().describe("Repository name. Defaults to env var"),
|
|
210
|
+
number: z.number().describe("Issue number"),
|
|
211
|
+
field: z.string().describe("Field name to clear (e.g., 'Estimate', 'Priority', 'Workflow State')"),
|
|
212
|
+
}, async (args) => {
|
|
213
|
+
try {
|
|
214
|
+
const { owner, repo, projectNumber, projectOwner } = resolveFullConfig(client, args);
|
|
215
|
+
await ensureFieldCache(client, fieldCache, projectOwner, projectNumber);
|
|
216
|
+
const projectId = fieldCache.getProjectId();
|
|
217
|
+
if (!projectId) {
|
|
218
|
+
return toolError("Could not resolve project ID");
|
|
219
|
+
}
|
|
220
|
+
const fieldId = fieldCache.getFieldId(args.field);
|
|
221
|
+
if (!fieldId) {
|
|
222
|
+
const validFields = fieldCache.getFieldNames();
|
|
223
|
+
return toolError(`Field "${args.field}" not found in project. ` +
|
|
224
|
+
`Valid fields: ${validFields.join(", ")}`);
|
|
225
|
+
}
|
|
226
|
+
const projectItemId = await resolveProjectItemId(client, fieldCache, owner, repo, args.number);
|
|
227
|
+
await client.projectMutate(`mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!) {
|
|
228
|
+
clearProjectV2ItemFieldValue(input: {
|
|
229
|
+
projectId: $projectId,
|
|
230
|
+
itemId: $itemId,
|
|
231
|
+
fieldId: $fieldId
|
|
232
|
+
}) {
|
|
233
|
+
projectV2Item { id }
|
|
234
|
+
}
|
|
235
|
+
}`, { projectId, itemId: projectItemId, fieldId });
|
|
236
|
+
return toolSuccess({
|
|
237
|
+
number: args.number,
|
|
238
|
+
field: args.field,
|
|
239
|
+
cleared: true,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
244
|
+
return toolError(`Failed to clear field: ${message}`);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=project-management-tools.js.map
|
|
@@ -11,7 +11,7 @@ import { z } from "zod";
|
|
|
11
11
|
import { detectGroup } from "../lib/group-detection.js";
|
|
12
12
|
import { isValidState, isEarlierState, VALID_STATES, } from "../lib/workflow-states.js";
|
|
13
13
|
import { toolSuccess, toolError, resolveProjectOwner } from "../types.js";
|
|
14
|
-
import { ensureFieldCache, resolveIssueNodeId, resolveProjectItemId, updateProjectItemField, getCurrentFieldValue, resolveConfig, } from "../lib/helpers.js";
|
|
14
|
+
import { ensureFieldCache, resolveIssueNodeId, resolveProjectItemId, updateProjectItemField, getCurrentFieldValue, resolveConfig, syncStatusField, } from "../lib/helpers.js";
|
|
15
15
|
// ---------------------------------------------------------------------------
|
|
16
16
|
// Register relationship tools
|
|
17
17
|
// ---------------------------------------------------------------------------
|
|
@@ -411,6 +411,8 @@ export function registerRelationshipTools(server, client, fieldCache) {
|
|
|
411
411
|
// Advance the child
|
|
412
412
|
const projectItemId = await resolveProjectItemId(client, fieldCache, owner, repo, child.number);
|
|
413
413
|
await updateProjectItemField(client, fieldCache, projectItemId, "Workflow State", args.targetState);
|
|
414
|
+
// Sync default Status field (best-effort, one-way)
|
|
415
|
+
await syncStatusField(client, fieldCache, projectItemId, args.targetState);
|
|
414
416
|
advanced.push({
|
|
415
417
|
number: child.number,
|
|
416
418
|
fromState: currentState,
|