@taiga-ai/mcp-server 0.26.0-dev.479 → 0.26.0-dev.482
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 +93 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1763,6 +1763,70 @@ const MAINTENANCE_IGNORE_REASONS = [
|
|
|
1763
1763
|
"accepted_risk",
|
|
1764
1764
|
"wont_fix"
|
|
1765
1765
|
];
|
|
1766
|
+
/**
|
|
1767
|
+
* What one lockfile's group list says, read against what its osv-scanner
|
|
1768
|
+
* (osv-scalibr) extractor actually writes. Checked per extractor, because the
|
|
1769
|
+
* same list means different things in different files:
|
|
1770
|
+
*
|
|
1771
|
+
* - package-lock.json / npm-shrinkwrap.json: every package entry carries npm's
|
|
1772
|
+
* `dev` / `optional` / `devOptional` flags, transitive ones included, so an
|
|
1773
|
+
* EMPTY list is a runtime dependency, `dev` alone is dev-only, `optional`
|
|
1774
|
+
* alone is shipped, and `dev` + `optional` (devOptional) is left undecided.
|
|
1775
|
+
* - pnpm-lock.yaml: `dev` comes from a per-package `dev: true` that lockfile
|
|
1776
|
+
* v9 no longer writes, so an empty list says nothing; `dev` still means dev.
|
|
1777
|
+
* - poetry.lock: group names with `main` dropped; a non-main, non-optional
|
|
1778
|
+
* group is not in the runtime install. Poetry 1.x lockfiles carry no groups
|
|
1779
|
+
* at all, so an empty list says nothing.
|
|
1780
|
+
* - uv.lock: only direct members of a group are tagged, so an empty list says
|
|
1781
|
+
* nothing; `dev` means dev.
|
|
1782
|
+
* - yarn.lock, go.mod/go.sum, Cargo.lock, Gemfile.lock and the rest carry no
|
|
1783
|
+
* group information: unknown whatever the list says.
|
|
1784
|
+
*
|
|
1785
|
+
* Anything this cannot place is `unknown`, never `runtime`: a wrong "runtime"
|
|
1786
|
+
* on a build tool is the claim this exists to stop, and a wrong "dev only" on a
|
|
1787
|
+
* shipped package is worse.
|
|
1788
|
+
*/
|
|
1789
|
+
function lockfileScope(path, groups) {
|
|
1790
|
+
const name = path.slice(path.lastIndexOf("/") + 1);
|
|
1791
|
+
const set = new Set(groups.map((g) => g.trim().toLowerCase()).filter((g) => g !== ""));
|
|
1792
|
+
switch (name) {
|
|
1793
|
+
case "package-lock.json":
|
|
1794
|
+
case "npm-shrinkwrap.json": {
|
|
1795
|
+
if (set.size === 0) return "runtime";
|
|
1796
|
+
const dev = set.has("dev");
|
|
1797
|
+
const optional = set.has("optional");
|
|
1798
|
+
if (dev && optional) return "unknown";
|
|
1799
|
+
if (dev) return "dev";
|
|
1800
|
+
if (optional && set.size === 1) return "runtime";
|
|
1801
|
+
return "unknown";
|
|
1802
|
+
}
|
|
1803
|
+
case "pnpm-lock.yaml":
|
|
1804
|
+
case "uv.lock": return set.size === 1 && set.has("dev") ? "dev" : "unknown";
|
|
1805
|
+
case "poetry.lock": return set.size > 0 && !set.has("optional") && !set.has("main") ? "dev" : "unknown";
|
|
1806
|
+
default: return "unknown";
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
/**
|
|
1810
|
+
* Whether a dependency finding sits only in development dependencies, in at
|
|
1811
|
+
* least one runtime dependency set, or in lockfiles that do not say. Decided
|
|
1812
|
+
* per lockfile (`lockfileScope`) and combined pessimistically: one runtime
|
|
1813
|
+
* lockfile makes the finding runtime, one lockfile that cannot say makes it
|
|
1814
|
+
* unknown, and only all-dev reads as dev. Groups the sweep did not record
|
|
1815
|
+
* (older images, code kinds) are unknown. Presentation only: the tier and the
|
|
1816
|
+
* auto-remediation gate do not read this, and a malicious package runs its
|
|
1817
|
+
* install script in any group.
|
|
1818
|
+
*/
|
|
1819
|
+
function dependencyScope(finding) {
|
|
1820
|
+
if (finding.kind !== "vulnerable_dependency" && finding.kind !== "outdated_dependency") return "unknown";
|
|
1821
|
+
const entries = Object.entries(finding.dependencyGroups ?? {});
|
|
1822
|
+
if (entries.length === 0) return "unknown";
|
|
1823
|
+
return combineScopes(entries.map(([path, groups]) => lockfileScope(path, Array.isArray(groups) ? groups : [])));
|
|
1824
|
+
}
|
|
1825
|
+
function combineScopes(scopes) {
|
|
1826
|
+
if (scopes.includes("runtime")) return "runtime";
|
|
1827
|
+
if (scopes.includes("unknown") || scopes.length === 0) return "unknown";
|
|
1828
|
+
return "dev";
|
|
1829
|
+
}
|
|
1766
1830
|
new Set(CODE_REMEDIATION_KINDS);
|
|
1767
1831
|
/** A non-empty string, or null. */
|
|
1768
1832
|
const locationText = z.string().min(1).nullable().catch(null);
|
|
@@ -4892,6 +4956,30 @@ function withFixability(row) {
|
|
|
4892
4956
|
};
|
|
4893
4957
|
return row;
|
|
4894
4958
|
}
|
|
4959
|
+
/**
|
|
4960
|
+
* Dev-only, runtime or unknown, said on a dependency row (PRO-2861) in place of the raw per-lockfile groups
|
|
4961
|
+
* the API carries: the groups need the lockfile name to read, which `dependencyScope` does once here.
|
|
4962
|
+
*/
|
|
4963
|
+
function withDependencyScope(row, { keepGroups = false } = {}) {
|
|
4964
|
+
const { dependencyGroups: _groups, ...lean } = row;
|
|
4965
|
+
const rest = keepGroups ? row : lean;
|
|
4966
|
+
if (!(row["kind"] === "vulnerable_dependency" || row["kind"] === "outdated_dependency")) return rest;
|
|
4967
|
+
return {
|
|
4968
|
+
...rest,
|
|
4969
|
+
dependencyScope: dependencyScope({
|
|
4970
|
+
kind: row["kind"],
|
|
4971
|
+
dependencyGroups: row["dependencyGroups"]
|
|
4972
|
+
})
|
|
4973
|
+
};
|
|
4974
|
+
}
|
|
4975
|
+
/** A finding as a tool answers it: the row fields, the scope, and whether Fix would take it. */
|
|
4976
|
+
function findingRows(findings, extra = []) {
|
|
4977
|
+
return pickFields(findings, [
|
|
4978
|
+
...FINDING_ROW_FIELDS,
|
|
4979
|
+
"dependencyGroups",
|
|
4980
|
+
...extra
|
|
4981
|
+
]).map((row) => withDependencyScope(row)).map(withFixability);
|
|
4982
|
+
}
|
|
4895
4983
|
/** The parts of an advisory record an agent reads; the rest (every affected range, every reference) is full: true. */
|
|
4896
4984
|
const ADVISORY_KEPT = [
|
|
4897
4985
|
"id",
|
|
@@ -5015,7 +5103,7 @@ function registerMaintenanceTools(server, client) {
|
|
|
5015
5103
|
sweep: null,
|
|
5016
5104
|
sweepNote: "The sweep overview could not be read: an empty list here is not an all-clear."
|
|
5017
5105
|
} : sweep ? { sweep } : {},
|
|
5018
|
-
...page(
|
|
5106
|
+
...page(findingRows(result.data), result.nextCursor),
|
|
5019
5107
|
...typeof result.totalCount === "number" ? { totalCount: result.totalCount } : {},
|
|
5020
5108
|
...params.status === void 0 && params.severity === void 0 && params.kind === void 0 && typeof result.totalCount === "number" && sweep && sweep !== "unread" && typeof sweep["openFindings"] === "number" && sweep["openFindings"] !== result.totalCount ? { totalNote: "totalCount includes findings with a fix under way (remediating) and ignored findings whose ignore has expired; sweep.openFindings counts open ones only." } : {}
|
|
5021
5109
|
});
|
|
@@ -5030,10 +5118,10 @@ function registerMaintenanceTools(server, client) {
|
|
|
5030
5118
|
annotations: READ_ONLY
|
|
5031
5119
|
}, (params) => runTool(async () => {
|
|
5032
5120
|
const { runId, ...raw } = (await client.getFinding(params.findingId)).data;
|
|
5033
|
-
const finding = withFixability(params.full ? raw : {
|
|
5121
|
+
const finding = withFixability(params.full ? withDependencyScope(raw, { keepGroups: true }) : withDependencyScope({
|
|
5034
5122
|
...raw,
|
|
5035
5123
|
data: leanAdvisory(raw["data"])
|
|
5036
|
-
});
|
|
5124
|
+
}));
|
|
5037
5125
|
return toolResult(runId === void 0 ? finding : {
|
|
5038
5126
|
sweepId: runId,
|
|
5039
5127
|
...finding
|
|
@@ -5120,7 +5208,7 @@ function registerMaintenanceTools(server, client) {
|
|
|
5120
5208
|
...params.expiresAt !== void 0 ? { ignoreExpiresAt: params.expiresAt } : {}
|
|
5121
5209
|
} : { status: "open" };
|
|
5122
5210
|
const finding = (await client.updateFinding(params.findingId, body)).data;
|
|
5123
|
-
return toolResult(
|
|
5211
|
+
return toolResult(findingRows([finding], ["ignoreNote"])[0]);
|
|
5124
5212
|
}));
|
|
5125
5213
|
server.registerTool("taiga_fix_finding", {
|
|
5126
5214
|
title: "Fix a finding",
|
|
@@ -5136,7 +5224,7 @@ function registerMaintenanceTools(server, client) {
|
|
|
5136
5224
|
const fixed = (await client.remediateFinding(params.productId, params.findingId)).data;
|
|
5137
5225
|
return toolResult({
|
|
5138
5226
|
backlogItemId: fixed.backlogItemId,
|
|
5139
|
-
finding: fixed.finding ?
|
|
5227
|
+
finding: fixed.finding ? findingRows([fixed.finding])[0] : null
|
|
5140
5228
|
});
|
|
5141
5229
|
}
|
|
5142
5230
|
const finding = (await client.getFinding(params.findingId)).data;
|
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.482",
|
|
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",
|