@taiga-ai/mcp-server 0.28.0-dev.598 → 0.28.0-dev.599
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 +96 -16
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -22484,8 +22484,11 @@ var TaigaClient = class {
|
|
|
22484
22484
|
return this.request("POST", `/builds/${seg(id)}/stop`);
|
|
22485
22485
|
}
|
|
22486
22486
|
/** Ask the coding agent for changes to the run's pull request (PRO-3035). */
|
|
22487
|
-
async requestBuildRunChanges(id, notes) {
|
|
22488
|
-
return this.request("POST", `/builds/${seg(id)}/request-changes`, {
|
|
22487
|
+
async requestBuildRunChanges(id, notes, opts = {}) {
|
|
22488
|
+
return this.request("POST", `/builds/${seg(id)}/request-changes`, {
|
|
22489
|
+
notes,
|
|
22490
|
+
...opts.reviewPlan !== void 0 ? { reviewPlan: opts.reviewPlan } : {}
|
|
22491
|
+
});
|
|
22489
22492
|
}
|
|
22490
22493
|
async listBuildRunSteps(id) {
|
|
22491
22494
|
return this.request("GET", `/builds/${seg(id)}/steps`);
|
|
@@ -23579,14 +23582,16 @@ object({
|
|
|
23579
23582
|
headSha: lenient(string$2()),
|
|
23580
23583
|
file: lenient(string$2()),
|
|
23581
23584
|
failingChecks: lenient(lenientList(storedFailingCheck)),
|
|
23582
|
-
blockers: lenient(lenientList(_enum(READY_BLOCKERS)))
|
|
23585
|
+
blockers: lenient(lenientList(_enum(READY_BLOCKERS))),
|
|
23586
|
+
detail: lenient(string$2())
|
|
23583
23587
|
}).transform((e) => ({
|
|
23584
23588
|
reason: e.reason,
|
|
23585
23589
|
...e.rounds === void 0 ? {} : { rounds: e.rounds },
|
|
23586
23590
|
...e.headSha === void 0 ? {} : { headSha: e.headSha },
|
|
23587
23591
|
...e.file === void 0 ? {} : { file: e.file },
|
|
23588
23592
|
...e.failingChecks === void 0 ? {} : { failingChecks: e.failingChecks },
|
|
23589
|
-
...e.blockers === void 0 ? {} : { blockers: e.blockers }
|
|
23593
|
+
...e.blockers === void 0 ? {} : { blockers: e.blockers },
|
|
23594
|
+
...e.detail === void 0 ? {} : { detail: e.detail }
|
|
23590
23595
|
}));
|
|
23591
23596
|
/**
|
|
23592
23597
|
* What a run's hardening came to, coverage included (PRO-2829). `passed`
|
|
@@ -27309,7 +27314,7 @@ function handbackSaid(escalation) {
|
|
|
27309
27314
|
case "review_bot_cap": return `review bots still have open comments${rounds}`;
|
|
27310
27315
|
case "ci_never_settled": return "CI did not finish in time";
|
|
27311
27316
|
case "review_fix_stalled": return "Taiga could not fix some review comments; its replies say what it tried";
|
|
27312
|
-
case "changes_not_planned": return
|
|
27317
|
+
case "changes_not_planned": return `the planner did not plan the request for changes${typeof e.detail === "string" && e.detail ? ` (${e.detail})` : ""}, so the pull request is as it was`;
|
|
27313
27318
|
case "ready_blocked": return `CI is green, but Taiga kept the pull request a draft${blockers.length ? `: ${blockers.join("; ")}` : ""}`;
|
|
27314
27319
|
case "check_weakened": return `CI went green only after a fix changed ${typeof e.file === "string" ? e.file : "a CI workflow or a test"}`;
|
|
27315
27320
|
default: return typeof e.reason === "string" ? e.reason : null;
|
|
@@ -27356,16 +27361,34 @@ function runOutcome(run) {
|
|
|
27356
27361
|
return {
|
|
27357
27362
|
disposition,
|
|
27358
27363
|
outcome: {
|
|
27359
|
-
in_flight: status === "pending" ? "Queued: waiting to start." : `Running: ${RUNNING[status] ?? status}${progress}.`,
|
|
27364
|
+
in_flight: status === "pending" ? "Queued: waiting to start." : status === "replanning" ? steerPaused(run["failedReason"], progress) : `Running: ${RUNNING[status] ?? status}${progress}.`,
|
|
27360
27365
|
gated: handback ? `Handed back to a person: ${handback}. ${pr}${draft ? `${draft},` : ""} waits for them to ${handbackNextStep(run["reviewEscalation"])}.` : `Waiting for a person to review and merge ${pr}${draft}.`,
|
|
27361
27366
|
succeeded: `Merged: ${pr} is in ${typeof run["baseBranch"] === "string" ? run["baseBranch"] : "the base branch"}.`,
|
|
27362
27367
|
unmerged: typeof run["prNumber"] === "number" || run["prUrl"] ? `Settled without merging: ${pr} was left unmerged.` : "Settled without a merged pull request.",
|
|
27363
27368
|
failed: `Failed${why ? `: ${why}` : ""}${progress}.`,
|
|
27364
|
-
stopped: `Stopped before it finished${progress}.`,
|
|
27369
|
+
stopped: replanHandedBack(run["failedReason"], why, progress) ?? `Stopped before it finished${progress}.`,
|
|
27365
27370
|
rejected: `${pr} was closed without merging, so the work did not land.${handback ? ` It had been handed back: ${handback}.` : ""}`
|
|
27366
27371
|
}[disposition] ?? status
|
|
27367
27372
|
};
|
|
27368
27373
|
}
|
|
27374
|
+
/**
|
|
27375
|
+
* A run re-planning for a request for changes (PRO-3161), in one sentence:
|
|
27376
|
+
* the re-plan in flight, or the revised plan waiting for review.
|
|
27377
|
+
*/
|
|
27378
|
+
function steerPaused(reason, progress) {
|
|
27379
|
+
if (reason === "steer_review") return `Paused${progress}: the plan revised for a request for changes waits for a person to review it (taiga_review_plan).`;
|
|
27380
|
+
return `Paused after a step${progress}: its plan is being revised for a request for changes.`;
|
|
27381
|
+
}
|
|
27382
|
+
/**
|
|
27383
|
+
* A run its re-plan handed back (PRO-3165), in one sentence with the
|
|
27384
|
+
* planner's reason. Null for any other stop.
|
|
27385
|
+
*/
|
|
27386
|
+
function replanHandedBack(reason, why, progress) {
|
|
27387
|
+
const said = why && why !== reason ? `: ${why}` : ".";
|
|
27388
|
+
if (reason === "replan_refused") return `Stopped${progress}, handed back: the planner would not plan the request for changes${said} Resume continues the original plan.`;
|
|
27389
|
+
if (reason === "replan_failed") return `Stopped${progress}, handed back: ${why && why !== reason ? why.replace(/\.?$/, ".") : "the plan could not be revised."} Resume continues the original plan.`;
|
|
27390
|
+
return null;
|
|
27391
|
+
}
|
|
27369
27392
|
/** Words a sentence does not end at: "e.g." and the like, and a lone initial. */
|
|
27370
27393
|
const ABBREVIATION = /(?:\b(?:e\.g|i\.e|etc|vs|cf|incl|approx)|(?:^|\s)[A-Za-z])\.$/i;
|
|
27371
27394
|
/** A finding's first sentence, capped: it ends at . ! or ? before white space, but not at an abbreviation. */
|
|
@@ -27710,20 +27733,27 @@ function registerBuildTools(server, client) {
|
|
|
27710
27733
|
});
|
|
27711
27734
|
}));
|
|
27712
27735
|
if (!client.hasCapability("products:write")) return;
|
|
27736
|
+
const steering = client.hasFeature("steerRuns");
|
|
27713
27737
|
if (client.hasFeature("requestChanges")) server.registerTool("taiga_request_changes", {
|
|
27714
|
-
title: "Request changes on a pull request",
|
|
27715
|
-
description: "Tell the coding agent what should change on a run's open pull request, as a person's review would: it splits the request into separate asks, makes the changes on the same pull request, and answers each one there (done, answered, or not done and why). Only for a run whose pull request is waiting for review (the initiative is in review with its pull request open); refused otherwise, and where the organization does not have it yet. taiga_wait follows the run until it is back in review.",
|
|
27738
|
+
title: steering ? "Request changes on a run" : "Request changes on a pull request",
|
|
27739
|
+
description: steering ? "Tell Taiga what should change in a run, while it builds or once its pull request waits for review. The run stops after the step it is building (at once when it is not building one), the planner revises the steps still to build on top of the committed work (adding, editing, dropping, or reverting committed steps exactly), and the run continues with the revised steps; never a new initiative. A request while the run hardens, checks CI or is already being re-planned waits and joins the next re-plan. reviewPlan holds the run until a person has looked at the revised plan (taiga_review_plan approves it or comments to revise it again). A request the planner will not plan, a policy conflict, hands the run back with the reason, still on its original plan. The answer says what happened to it (steer). For a plan that waits for its build to be approved, comment on the plan with taiga_review_plan instead." : "Tell the coding agent what should change on a run's open pull request, as a person's review would: it splits the request into separate asks, makes the changes on the same pull request, and answers each one there (done, answered, or not done and why). Only for a run whose pull request is waiting for review (the initiative is in review with its pull request open); refused otherwise, and where the organization does not have it yet. taiga_wait follows the run until it is back in review.",
|
|
27716
27740
|
inputSchema: object({
|
|
27717
27741
|
runId,
|
|
27718
|
-
notes: string$2().trim().min(1).max(CHANGE_REQUEST_MAX_CHARS).describe("What should change, in markdown: a list of changes, questions, or both")
|
|
27742
|
+
notes: string$2().trim().min(1).max(CHANGE_REQUEST_MAX_CHARS).describe("What should change, in markdown: a list of changes, questions, or both"),
|
|
27743
|
+
...steering ? { reviewPlan: boolean().optional().describe("Hold the run until a person has reviewed the revised plan (default false)") } : {}
|
|
27719
27744
|
}),
|
|
27720
27745
|
annotations: OPERATE
|
|
27721
27746
|
}, (params) => runTool(async () => {
|
|
27722
|
-
const
|
|
27747
|
+
const reviewPlan = "reviewPlan" in params ? params.reviewPlan : void 0;
|
|
27748
|
+
const result = await client.requestBuildRunChanges(params.runId, params.notes, { reviewPlan });
|
|
27723
27749
|
const row = pickFields([result.data], RUN_OUTCOME_FIELDS)[0];
|
|
27724
27750
|
return toolResult({
|
|
27725
27751
|
...readableRow(row),
|
|
27726
|
-
requestId: result.data.requestId
|
|
27752
|
+
requestId: result.data.requestId,
|
|
27753
|
+
...result.data.steer ? {
|
|
27754
|
+
steer: result.data.steer,
|
|
27755
|
+
situation: steerSituation(result.data.steer)
|
|
27756
|
+
} : {}
|
|
27727
27757
|
});
|
|
27728
27758
|
}));
|
|
27729
27759
|
server.registerTool("taiga_stop_run", {
|
|
@@ -27736,6 +27766,12 @@ function registerBuildTools(server, client) {
|
|
|
27736
27766
|
return toolResult(readableRow(pickFields([result.data], RUN_OUTCOME_FIELDS)[0]));
|
|
27737
27767
|
}));
|
|
27738
27768
|
}
|
|
27769
|
+
/** What happened to a request that steers a run (PRO-3161), in one sentence. */
|
|
27770
|
+
function steerSituation(steer) {
|
|
27771
|
+
if (steer === "replanning") return "The run has paused and its plan is being revised for the request.";
|
|
27772
|
+
if (steer === "after_step") return "The run stops when the step it is building ends, then its plan is revised.";
|
|
27773
|
+
return "The run is hardening, checking CI or already being re-planned; the request joins the next re-plan.";
|
|
27774
|
+
}
|
|
27739
27775
|
//#endregion
|
|
27740
27776
|
//#region src/tools/queue.ts
|
|
27741
27777
|
/** How many entries the read names; past this an entry keeps its initiativeId only. */
|
|
@@ -28152,6 +28188,37 @@ async function planFailureOf(client, initiativeId, itemCause) {
|
|
|
28152
28188
|
by: typeof actor.name === "string" ? actor.name : actor.type ?? null
|
|
28153
28189
|
};
|
|
28154
28190
|
}
|
|
28191
|
+
/**
|
|
28192
|
+
* What a request for changes did to this plan (PRO-3161), when one revised it:
|
|
28193
|
+
* the steps the re-plan added, edited and dropped, and the committed steps it
|
|
28194
|
+
* reverts, from the `run_replanned` event that made this version. Null for a
|
|
28195
|
+
* plan no request revised, or when the history cannot be read.
|
|
28196
|
+
*/
|
|
28197
|
+
async function planRevisionOf(client, initiativeId, planId) {
|
|
28198
|
+
let events;
|
|
28199
|
+
try {
|
|
28200
|
+
events = (await client.listBacklogItemActivity(initiativeId)).data;
|
|
28201
|
+
} catch (error) {
|
|
28202
|
+
if (error instanceof TaigaApiError || isNetworkFailure(error)) return null;
|
|
28203
|
+
throw error;
|
|
28204
|
+
}
|
|
28205
|
+
for (const event of [...events].reverse()) {
|
|
28206
|
+
if (event.kind !== "turn" || event.trigger !== "run_replanned") continue;
|
|
28207
|
+
const data = event.data ?? {};
|
|
28208
|
+
if (data["planId"] !== planId) continue;
|
|
28209
|
+
return {
|
|
28210
|
+
revisedFor: "a request for changes",
|
|
28211
|
+
previousPlanId: data["previousPlanId"] ?? null,
|
|
28212
|
+
added: data["added"] ?? [],
|
|
28213
|
+
edited: data["edited"] ?? [],
|
|
28214
|
+
dropped: data["dropped"] ?? [],
|
|
28215
|
+
reverted: data["reverted"] ?? [],
|
|
28216
|
+
waitsForReview: data["reviewPlan"] === true,
|
|
28217
|
+
at: event.occurredAt ?? null
|
|
28218
|
+
};
|
|
28219
|
+
}
|
|
28220
|
+
return null;
|
|
28221
|
+
}
|
|
28155
28222
|
const planId = idInput("plan", "taiga_get_plan gives the initiative's active plan and its ID");
|
|
28156
28223
|
const initiativeId = idInput("initiative", "taiga_list_initiatives (query finds one by title) gives it");
|
|
28157
28224
|
/** The plan without its steps' prose: enough to approve it or say what a run will do. */
|
|
@@ -28170,7 +28237,9 @@ const PLAN_STEP_SUMMARY_FIELDS = [
|
|
|
28170
28237
|
"dependencies",
|
|
28171
28238
|
"writes",
|
|
28172
28239
|
"reads",
|
|
28173
|
-
"createsResources"
|
|
28240
|
+
"createsResources",
|
|
28241
|
+
"revertsSteps",
|
|
28242
|
+
"changeRequestIds"
|
|
28174
28243
|
];
|
|
28175
28244
|
/** The outcome fields of an initiative, with how many of its criteria are met, and where it stands. */
|
|
28176
28245
|
const outcomeOf = (item) => withSituation(item, {
|
|
@@ -28290,7 +28359,7 @@ function registerBacklogReads(server, client) {
|
|
|
28290
28359
|
}));
|
|
28291
28360
|
server.registerTool("taiga_get_plan", {
|
|
28292
28361
|
title: "Get the active plan",
|
|
28293
|
-
description: "Read an initiative's active plan, step by step: what each builds, the files it writes and reads, and what it depends on. Enough to approve or reject it; full: true adds each step's complete instructions (long). NOT_FOUND when there is no active plan; the initiative's situation says why.",
|
|
28362
|
+
description: "Read an initiative's active plan, step by step: what each builds, the files it writes and reads, and what it depends on. Enough to approve or reject it; full: true adds each step's complete instructions (long). A plan a request for changes revised says so in revision: the steps it added, edited and dropped, and the committed steps it reverts. NOT_FOUND when there is no active plan; the initiative's situation says why.",
|
|
28294
28363
|
inputSchema: object({
|
|
28295
28364
|
initiativeId,
|
|
28296
28365
|
full: boolean().optional().describe("Carry each step's complete instructions (default false: a summary)")
|
|
@@ -28298,10 +28367,16 @@ function registerBacklogReads(server, client) {
|
|
|
28298
28367
|
annotations: READ_ONLY
|
|
28299
28368
|
}, (params) => runTool(async () => {
|
|
28300
28369
|
const plan = (await client.getActivePlan(params.initiativeId)).data;
|
|
28301
|
-
|
|
28370
|
+
const revision = await planRevisionOf(client, params.initiativeId, plan.id);
|
|
28371
|
+
const revised = revision ? { revision } : {};
|
|
28372
|
+
if (params.full) return toolResult({
|
|
28373
|
+
...plan,
|
|
28374
|
+
...revised
|
|
28375
|
+
});
|
|
28302
28376
|
const steps = Array.isArray(plan.steps) ? plan.steps : [];
|
|
28303
28377
|
return toolResult({
|
|
28304
28378
|
...pickFields([plan], PLAN_SUMMARY_FIELDS)[0],
|
|
28379
|
+
...revised,
|
|
28305
28380
|
steps: pickFields(steps, PLAN_STEP_SUMMARY_FIELDS)
|
|
28306
28381
|
});
|
|
28307
28382
|
}));
|
|
@@ -28465,7 +28540,7 @@ function registerResume(server, client) {
|
|
|
28465
28540
|
function registerPlanReview(server, client) {
|
|
28466
28541
|
server.registerTool("taiga_review_plan", {
|
|
28467
28542
|
title: "Approve or reject a plan",
|
|
28468
|
-
description: "Give an initiative's plan its verdict. approve starts the run that builds it; reject sends it back with a comment and the planner
|
|
28543
|
+
description: "Give an initiative's plan its verdict. approve starts the run that builds it; reject sends it back with a comment and the planner revises it from the comment, keeping what the comment does not object to. Read the plan first (taiga_get_plan) and pass its ID; refused if the plan was replaced since, a new one is being written, or a run is already going." + (client.hasFeature("steerRuns") ? " A plan a request for changes revised while its run waits for this review (taiga_request_changes with reviewPlan): approve continues that run on its branch, and reject comments to revise it again." : ""),
|
|
28469
28544
|
inputSchema: object({
|
|
28470
28545
|
planId,
|
|
28471
28546
|
verdict: _enum(["approve", "reject"]).describe("approve builds the plan; reject sends it back"),
|
|
@@ -45490,6 +45565,7 @@ const RUN_REPORT_FIELDS = [
|
|
|
45490
45565
|
];
|
|
45491
45566
|
const runSignature = (run) => JSON.stringify([
|
|
45492
45567
|
run.status,
|
|
45568
|
+
run.failedReason,
|
|
45493
45569
|
run.completedSteps,
|
|
45494
45570
|
run.prUrl,
|
|
45495
45571
|
run.prState,
|
|
@@ -45502,6 +45578,10 @@ function judgeBuild(until) {
|
|
|
45502
45578
|
reached: false,
|
|
45503
45579
|
stoppedBecause: `the run is ${String(run.status)}`
|
|
45504
45580
|
};
|
|
45581
|
+
if (until !== "changed" && run.status === "replanning" && run.failedReason === "steer_review") return {
|
|
45582
|
+
reached: false,
|
|
45583
|
+
stoppedBecause: "the run waits for a person to review its revised plan (taiga_review_plan)"
|
|
45584
|
+
};
|
|
45505
45585
|
return null;
|
|
45506
45586
|
};
|
|
45507
45587
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taiga-ai/mcp-server",
|
|
3
|
-
"version": "0.28.0-dev.
|
|
3
|
+
"version": "0.28.0-dev.599",
|
|
4
4
|
"description": "Taiga for AI coding assistants: read products, policies, initiatives and runs, and operate the line, over MCP",
|
|
5
5
|
"mcpName": "ga.tai/mcp-server",
|
|
6
6
|
"license": "UNLICENSED",
|