@taiga-ai/mcp-server 0.26.0-dev.485 → 0.26.0-dev.487
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 +83 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -913,8 +913,9 @@ const INITIATIVE_STATES = [
|
|
|
913
913
|
* for every reader that means "on the line": the flag the API clears when an
|
|
914
914
|
* initiative leaves it, the remediation settle on the same departure, and the
|
|
915
915
|
* MCP's account of where an initiative stands (PRO-2840). Everything else
|
|
916
|
-
* (backlog, todo, done, canceled) is off it. The lifecycle derivation
|
|
917
|
-
*
|
|
916
|
+
* (backlog, todo, done, canceled) is off it. The lifecycle derivation draws a
|
|
917
|
+
* narrower line (PRO-2828): a run that ended is the initiative's state only at
|
|
918
|
+
* a station, Plan or Build; in Queue it is history, as it is off the line.
|
|
918
919
|
*/
|
|
919
920
|
const LINE_STATES = [
|
|
920
921
|
"queue",
|
|
@@ -1384,6 +1385,49 @@ z.object({
|
|
|
1384
1385
|
...e.failingChecks === void 0 ? {} : { failingChecks: e.failingChecks },
|
|
1385
1386
|
...e.blockers === void 0 ? {} : { blockers: e.blockers }
|
|
1386
1387
|
}));
|
|
1388
|
+
/**
|
|
1389
|
+
* What a run's hardening came to, coverage included (PRO-2829). `passed`
|
|
1390
|
+
* counted only blocking findings, so a run whose scanners never ran said
|
|
1391
|
+
* "passed" all the same.
|
|
1392
|
+
*
|
|
1393
|
+
* - `failed`: blocking findings remain (the gaps are still listed).
|
|
1394
|
+
* - `not_scanned`: no scanner that applies to the repository ran to the end.
|
|
1395
|
+
* - `passed_with_gaps`: nothing blocks, but some scanner did not run.
|
|
1396
|
+
* - `passed`: nothing blocks and every scanner that applies ran.
|
|
1397
|
+
*/
|
|
1398
|
+
const HARDENING_VERDICTS = [
|
|
1399
|
+
"passed",
|
|
1400
|
+
"passed_with_gaps",
|
|
1401
|
+
"not_scanned",
|
|
1402
|
+
"failed"
|
|
1403
|
+
];
|
|
1404
|
+
/**
|
|
1405
|
+
* The verdict and the gaps of a hardening result (PRO-2829), for every reader
|
|
1406
|
+
* (the run read, the web's run page, the MCP), from what the agent reported.
|
|
1407
|
+
*
|
|
1408
|
+
* A gap is a scanner that applies and did not run: `not_run` (the scan never
|
|
1409
|
+
* reached it), `skipped` (its tool was missing), or `failed` with a reason,
|
|
1410
|
+
* which is a scanner that could not finish. A `failed` scanner without one
|
|
1411
|
+
* found something (tflint fails on a MAJOR that blocks nothing, and rows from
|
|
1412
|
+
* before `scannerReasons` used `failed` for "had findings"), so it ran and is
|
|
1413
|
+
* no gap. A scanner listed in `notApplicable` is no gap; on a result from
|
|
1414
|
+
* before that list, a skipped tflint is read the same way, as the only reason
|
|
1415
|
+
* the agent ever skipped it was a repository with no Terraform.
|
|
1416
|
+
*/
|
|
1417
|
+
function hardeningCoverage(result) {
|
|
1418
|
+
const notApplicable = new Set(result.notApplicable ?? []);
|
|
1419
|
+
const applies = Object.entries(result.scanners ?? {}).filter(([scanner, status]) => !notApplicable.has(scanner) && !(result.notApplicable === void 0 && scanner === "tflint" && status === "skipped"));
|
|
1420
|
+
const reasons = result.scannerReasons ?? {};
|
|
1421
|
+
const gaps = applies.filter(([scanner, status]) => status === "not_run" || status === "skipped" || status === "failed" && scanner in reasons).map(([scanner, status]) => ({
|
|
1422
|
+
scanner,
|
|
1423
|
+
status,
|
|
1424
|
+
reason: reasons[scanner] ?? null
|
|
1425
|
+
}));
|
|
1426
|
+
return {
|
|
1427
|
+
verdict: !result.passed ? "failed" : gaps.length === applies.length ? "not_scanned" : gaps.length > 0 ? "passed_with_gaps" : "passed",
|
|
1428
|
+
gaps
|
|
1429
|
+
};
|
|
1430
|
+
}
|
|
1387
1431
|
[...BUILD_RUN_ACTIVE_STATUSES.filter((s) => s !== "reviewing")];
|
|
1388
1432
|
//#endregion
|
|
1389
1433
|
//#region ../../packages/types/dist/agents.js
|
|
@@ -3941,6 +3985,34 @@ function hardeningSaid(blocking, named) {
|
|
|
3941
3985
|
const recorded = named.length > shown.length ? `, ${named.length} recorded in taiga_get_run` : "";
|
|
3942
3986
|
return `${count}: ${shown.join("; ")}${rest > 0 ? `; and ${rest} more${recorded}` : ""}.`;
|
|
3943
3987
|
}
|
|
3988
|
+
/** How each hardening verdict reads (PRO-2829): "passed" only when every scanner that applies ran. */
|
|
3989
|
+
const VERDICT_SAID = {
|
|
3990
|
+
passed: "Hardening passed: every scanner that applies ran and nothing blocks",
|
|
3991
|
+
passed_with_gaps: "Hardening passed, but not every scanner ran, so its checks are missing from the result",
|
|
3992
|
+
not_scanned: "No security scanner ran in hardening: \"passed\" only means no blocking finding was recorded",
|
|
3993
|
+
failed: "Hardening failed: blocking findings remain"
|
|
3994
|
+
};
|
|
3995
|
+
/**
|
|
3996
|
+
* What a run's hardening came to, coverage included (PRO-2829), from the
|
|
3997
|
+
* verdict the API reads off it, or read here from an API from before that.
|
|
3998
|
+
* Null without a hardening result.
|
|
3999
|
+
*/
|
|
4000
|
+
function scanSaid(hardening) {
|
|
4001
|
+
if (!hardening || typeof hardening !== "object") return null;
|
|
4002
|
+
const h = hardening;
|
|
4003
|
+
const coverage = typeof h.verdict === "string" && HARDENING_VERDICTS.includes(h.verdict) && Array.isArray(h.gaps) ? {
|
|
4004
|
+
verdict: h.verdict,
|
|
4005
|
+
gaps: h.gaps
|
|
4006
|
+
} : typeof h.passed === "boolean" && h.scanners ? hardeningCoverage(h) : null;
|
|
4007
|
+
if (!coverage) return null;
|
|
4008
|
+
const gaps = coverage.gaps.map((gap) => `${gap.scanner}${gap.status === "failed" ? " did not finish" : ""}${gap.reason ? ` (${gap.reason})` : ""}`);
|
|
4009
|
+
const missing = gaps.length > 0 ? `; did not run: ${gaps.join(", ")}` : "";
|
|
4010
|
+
return {
|
|
4011
|
+
verdict: coverage.verdict,
|
|
4012
|
+
gaps: gaps.length,
|
|
4013
|
+
said: `${VERDICT_SAID[coverage.verdict]}${missing}.`
|
|
4014
|
+
};
|
|
4015
|
+
}
|
|
3944
4016
|
/**
|
|
3945
4017
|
* What each failedReason means for the next move (PRO-2800): reviewers met dispatch_rejected and agent_reported as
|
|
3946
4018
|
* bare enums. As @taiga/types documents them.
|
|
@@ -3967,9 +4039,11 @@ function readableRun(run, opts = {}) {
|
|
|
3967
4039
|
const hardening = run["hardeningResult"];
|
|
3968
4040
|
const blocking = typeof hardening?.blockingFindings === "number" ? hardening.blockingFindings : 0;
|
|
3969
4041
|
const named = Array.isArray(hardening?.blocking) ? hardening.blocking : [];
|
|
4042
|
+
const scan = scanSaid(hardening);
|
|
3970
4043
|
return {
|
|
3971
4044
|
...rest,
|
|
3972
4045
|
...means ? { failedReasonMeans: means } : {},
|
|
4046
|
+
...scan && scan.gaps + (scan.verdict === "not_scanned" ? 1 : 0) > 0 ? { scanCoverage: scan.said } : {},
|
|
3973
4047
|
...blocking > 0 ? { hardeningNote: hardeningSaid(blocking, named) } : {},
|
|
3974
4048
|
...opts.row || error === void 0 ? {} : { error },
|
|
3975
4049
|
...opts.row || reviewEscalation === void 0 ? {} : { reviewEscalation },
|
|
@@ -4171,7 +4245,7 @@ function registerBuildTools(server, client) {
|
|
|
4171
4245
|
}));
|
|
4172
4246
|
server.registerTool("taiga_get_run", {
|
|
4173
4247
|
title: "Get run",
|
|
4174
|
-
description: "Read one run with its steps: outcome, disposition, pull request, hardening, and per step its title, status, commit, files changed, verification and headline (first paragraph of the agent's report). verification is Taiga's own check after the step (tests, lint, build), so a docs-only step can fail on the repository's failing tests (verificationNote says when one failed throughout). A failed or stopped run has stoppedIn, lastProgressAt and failedReasonMeans (what its failedReason means). full: true adds complete instructions and reports. actions: resume and retry_from_failed_step are taiga_resume_initiative; webOnlyActions (start_over) are in the web; to stop it, move the initiative out of Build. A maintenance run has no initiative and is retried from its finding.",
|
|
4248
|
+
description: "Read one run with its steps: outcome, disposition, pull request, hardening (scanCoverage names the security scanners that did not run, and why; hardeningResult.verdict is passed only when every one ran), and per step its title, status, commit, files changed, verification and headline (first paragraph of the agent's report). verification is Taiga's own check after the step (tests, lint, build), so a docs-only step can fail on the repository's failing tests (verificationNote says when one failed throughout). A failed or stopped run has stoppedIn, lastProgressAt and failedReasonMeans (what its failedReason means). full: true adds complete instructions and reports. actions: resume and retry_from_failed_step are taiga_resume_initiative; webOnlyActions (start_over) are in the web; to stop it, move the initiative out of Build. A maintenance run has no initiative and is retried from its finding.",
|
|
4175
4249
|
inputSchema: z.object({
|
|
4176
4250
|
runId,
|
|
4177
4251
|
full: z.boolean().optional().describe("Carry each step's complete instructions and report (default false: a summary)")
|
|
@@ -4602,31 +4676,27 @@ const outcomeOf = (item) => withSituation(item, {
|
|
|
4602
4676
|
criteria: criteriaCounts(item)
|
|
4603
4677
|
});
|
|
4604
4678
|
const outcome = (item) => toolResult(outcomeOf(item));
|
|
4605
|
-
/** The statuses an initiative in each board column can have: the
|
|
4679
|
+
/** The statuses an initiative in each board column can have: the column decides it (statusForState, PRO-2828). */
|
|
4606
4680
|
const COLUMN_STATUSES = {
|
|
4607
4681
|
backlog: [
|
|
4608
4682
|
"all",
|
|
4609
4683
|
"open",
|
|
4610
|
-
"backlog"
|
|
4611
|
-
"in_progress"
|
|
4684
|
+
"backlog"
|
|
4612
4685
|
],
|
|
4613
4686
|
todo: [
|
|
4614
4687
|
"all",
|
|
4615
4688
|
"open",
|
|
4616
|
-
"backlog"
|
|
4617
|
-
"in_progress"
|
|
4689
|
+
"backlog"
|
|
4618
4690
|
],
|
|
4619
4691
|
queue: [
|
|
4620
4692
|
"all",
|
|
4621
4693
|
"open",
|
|
4622
|
-
"backlog"
|
|
4623
|
-
"in_progress"
|
|
4694
|
+
"backlog"
|
|
4624
4695
|
],
|
|
4625
4696
|
plan: [
|
|
4626
4697
|
"all",
|
|
4627
4698
|
"open",
|
|
4628
|
-
"backlog"
|
|
4629
|
-
"in_progress"
|
|
4699
|
+
"backlog"
|
|
4630
4700
|
],
|
|
4631
4701
|
build: [
|
|
4632
4702
|
"all",
|
|
@@ -4679,7 +4749,7 @@ function registerBacklogReads(server, client) {
|
|
|
4679
4749
|
"in_progress",
|
|
4680
4750
|
"done",
|
|
4681
4751
|
"canceled"
|
|
4682
|
-
]).optional().describe("open (default without state): not done or canceled; all: every one; in_progress
|
|
4752
|
+
]).optional().describe("open (default without state): not done or canceled; all: every one; in_progress is the Build column, backlog every other open one"),
|
|
4683
4753
|
planningStatus: z.enum([
|
|
4684
4754
|
"unplanned",
|
|
4685
4755
|
"planning",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taiga-ai/mcp-server",
|
|
3
|
-
"version": "0.26.0-dev.
|
|
3
|
+
"version": "0.26.0-dev.487",
|
|
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
|
"type": "module",
|