@taiga-ai/mcp-server 0.37.0-rc.956 → 0.37.0-rc.984

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.
Files changed (2) hide show
  1. package/dist/index.js +131 -23
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -23883,6 +23883,10 @@ var TaigaClient = class {
23883
23883
  async listBuildRunSteps(id) {
23884
23884
  return this.request("GET", `/builds/${seg(id)}/steps`);
23885
23885
  }
23886
+ /** The public hosts the run reached through the egress gateway (PRO-4268). */
23887
+ async listBuildRunEgressHosts(id) {
23888
+ return this.request("GET", `/builds/${seg(id)}/hosts`);
23889
+ }
23886
23890
  async getMaintenanceSummary(productId) {
23887
23891
  return this.request("GET", `/products/${seg(productId)}/maintenance/summary`);
23888
23892
  }
@@ -23957,6 +23961,10 @@ var TaigaClient = class {
23957
23961
  async shipNotices(productId) {
23958
23962
  return this.request("POST", `/products/${seg(productId)}/maintenance/notices`, {});
23959
23963
  }
23964
+ /** Sweep one of a product's repositories (PRO-4276): its primary when none is named. */
23965
+ async startSweep(productId, productRepositoryId) {
23966
+ return this.request("POST", `/products/${seg(productId)}/maintenance/sweeps`, productRepositoryId ? { productRepositoryId } : {});
23967
+ }
23960
23968
  async remediateFinding(productId, findingId) {
23961
23969
  return this.request("POST", `/products/${seg(productId)}/maintenance/findings/${seg(findingId)}/remediate`, {});
23962
23970
  }
@@ -26210,6 +26218,46 @@ const ENVIRONMENT_TYPES = [
26210
26218
  "custom"
26211
26219
  ];
26212
26220
  //#endregion
26221
+ //#region ../../packages/types/dist/monitoring-rollups.js
26222
+ /**
26223
+ * Core Web Vitals weighted heaviest (LCP/INP/CLS are Google's "Core" trio);
26224
+ * FCP/TTFB are supporting signals. Thresholds are the published web.dev values.
26225
+ */
26226
+ const METRICS = {
26227
+ LCP: {
26228
+ good: 2500,
26229
+ ni: 4e3,
26230
+ unit: "ms",
26231
+ weight: 30
26232
+ },
26233
+ INP: {
26234
+ good: 200,
26235
+ ni: 500,
26236
+ unit: "ms",
26237
+ weight: 30
26238
+ },
26239
+ CLS: {
26240
+ good: .1,
26241
+ ni: .25,
26242
+ unit: "score",
26243
+ weight: 25
26244
+ },
26245
+ FCP: {
26246
+ good: 1800,
26247
+ ni: 3e3,
26248
+ unit: "ms",
26249
+ weight: 10
26250
+ },
26251
+ TTFB: {
26252
+ good: 800,
26253
+ ni: 1800,
26254
+ unit: "ms",
26255
+ weight: 5
26256
+ }
26257
+ };
26258
+ Object.keys(METRICS);
26259
+ Object.fromEntries(Object.entries(METRICS).map(([name, spec]) => [name, spec.weight]));
26260
+ //#endregion
26213
26261
  //#region ../../packages/types/dist/api-keys.js
26214
26262
  /**
26215
26263
  * API key scopes control what operations a key can perform.
@@ -27218,16 +27266,18 @@ const EXCEL_MAX_ROW = 1048576;
27218
27266
  * Where an engineer build's sandbox may connect to (PRO-2793, part of
27219
27267
  * PRO-1980).
27220
27268
  *
27221
- * The engineer pod's credential gateway is the sandbox's only way out. By
27222
- * default it lets through a standard list: the public package registries,
27223
- * toolchain downloads, container registries, GitHub for reading public
27224
- * dependencies, and the tenant's own registries. A product adds to that:
27269
+ * The egress gateway is the sandbox's only way out for what the other
27270
+ * gateways do not carry (packages, images, toolchains, scanners). Reads are
27271
+ * open and writes are controlled (PRO-4266): every run is held to an upload
27272
+ * budget, the gateway refuses private and metadata addresses, and it never
27273
+ * hands the sandbox a credential, whichever access a product has.
27225
27274
  *
27226
- * - `allowlist` (the default, also what `null` means): the standard list plus
27227
- * the product's own `networkHosts`.
27228
- * - `unrestricted`: any public host. For a product whose builds need hosts
27229
- * nobody can list in advance; the gateway still refuses private and
27230
- * metadata addresses, and still never hands the sandbox a credential.
27275
+ * - `unrestricted` (the default, also what `null` means): any public host.
27276
+ * A list of hosts nobody can keep complete broke builds one host at a time.
27277
+ * - `allowlist`: only the gateway's standard list (the public package
27278
+ * registries, toolchain downloads, container registries, GitHub for public
27279
+ * dependencies, the tenant's own registries) plus the product's own
27280
+ * `networkHosts`. For a product that wants to name where its builds go.
27231
27281
  *
27232
27282
  * A host is one exact name (`api.example.com`). There are no wildcards: a
27233
27283
  * wildcard over a multi-label public suffix (`*.co.uk`) or a provider's
@@ -27965,7 +28015,7 @@ const TOOLSET_PURPOSE = {
27965
28015
  core: "where products, initiatives, runs, policies and findings stand",
27966
28016
  operate: "moving work: queue, plans, runs, fixes, Action Required",
27967
28017
  setup: "creating and configuring factories, products, repositories, environments and autonomy",
27968
- observe: "deployments, monitoring, delivery metrics and the package inventory",
28018
+ observe: "deployments, monitoring, delivery metrics, the package inventory and the sweeps that read it",
27969
28019
  documents: "writing documents and knowledge, and regenerating product documents"
27970
28020
  };
27971
28021
  /** Every tool's toolset. A tool missing here fails at registration, so none can be added without a home. */
@@ -28032,6 +28082,7 @@ const TOOLSET_OF = {
28032
28082
  taiga_get_monitoring: "observe",
28033
28083
  taiga_get_delivery_metrics: "observe",
28034
28084
  taiga_list_packages: "observe",
28085
+ taiga_start_sweep: "observe",
28035
28086
  taiga_list_licenses: "observe",
28036
28087
  taiga_change_license: "setup",
28037
28088
  taiga_get_sbom: "observe",
@@ -34801,6 +34852,21 @@ const SWEEP_FIELDS = [
34801
34852
  "createdAt",
34802
34853
  "completedAt"
34803
34854
  ];
34855
+ /** Advisories a sweep's summary names, at most. */
34856
+ const ADVISORIES_SHOWN = 10;
34857
+ /**
34858
+ * The advisories whose arrival in OSV's feed started a sweep (PRO-116), only
34859
+ * where some did: a sweep a push, the clock or a person started says nothing.
34860
+ */
34861
+ function startedByAdvisories(sweep) {
34862
+ const raw = sweep.advisories;
34863
+ const advisories = Array.isArray(raw) ? raw.filter((a) => typeof a === "string") : [];
34864
+ if (advisories.length === 0) return {};
34865
+ return advisories.length > ADVISORIES_SHOWN ? {
34866
+ advisories: advisories.slice(0, ADVISORIES_SHOWN),
34867
+ advisoriesCount: advisories.length
34868
+ } : { advisories };
34869
+ }
34804
34870
  /**
34805
34871
  * The images a sweep's shipped images build on that it could not read, and
34806
34872
  * why (PRO-4073): a base nobody read is no clean base. Only where the API
@@ -34930,7 +34996,8 @@ async function sweepOverview(client, productId) {
34930
34996
  const [summary, sweeps] = await Promise.all([client.getMaintenanceSummary(productId), client.listMaintenanceSweeps(productId, { limit: 3 })]);
34931
34997
  const latest = sweeps.data.map((sweep) => ({
34932
34998
  ...pickFields([sweep], SWEEP_FIELDS)[0],
34933
- ...notReadBases(sweep)
34999
+ ...notReadBases(sweep),
35000
+ ...startedByAdvisories(sweep)
34934
35001
  }));
34935
35002
  const { lastRun: _lastRun, lastRuns: _lastRuns, topFindings: _top, violatedControls: _controls, ...counts } = summary.data;
34936
35003
  return {
@@ -35097,7 +35164,7 @@ function registerMaintenanceTools(server, client) {
35097
35164
  }, (params) => runTool(async () => toolResult({ notices: await client.getNotices(params.productId, params.linkId) })));
35098
35165
  server.registerTool("taiga_get_finding", {
35099
35166
  title: "Get a maintenance finding",
35100
- description: "Read one finding: how likely it is to be exploited, the advisory and its fixed version, where it is, which policy controls it breaches, and any fix under way. fixable: false says taiga_fix_finding would refuse it. A secret's value is never stored.",
35167
+ description: "Read one finding: how likely it is to be exploited, the advisory and its fixed version, where it is, which policy controls it breaches, any fix under way, and triage: whether the code reaches it, as its factory judged it at a commit (advice; it never changes the status). fixable: false says taiga_fix_finding would refuse it. A secret's value is never stored.",
35101
35168
  inputSchema: object({
35102
35169
  findingId,
35103
35170
  full: boolean().optional().describe("Carry the advisory's whole record: every affected range and reference (default false)")
@@ -35240,6 +35307,21 @@ function registerMaintenanceTools(server, client) {
35240
35307
  ...params.expiresAt !== void 0 ? { ignoreExpiresAt: params.expiresAt } : {}
35241
35308
  })).data);
35242
35309
  }));
35310
+ server.registerTool("taiga_start_sweep", {
35311
+ title: "Sweep a repository",
35312
+ description: "Scan one of a product's repositories now: its dependencies, secrets, code and infrastructure, the findings triaged and its code judged against the policies. Its primary repository when none is named. Returns the sweep; taiga_list_findings and taiga_get_policy_standing read what it found once it completes.",
35313
+ inputSchema: object({
35314
+ productId,
35315
+ linkId: idInput("repository link", "taiga_list_product_repositories gives it (its id); a linkable repository id is not one").optional()
35316
+ }),
35317
+ annotations: OPERATE
35318
+ }, (params) => runTool(async () => {
35319
+ const { id, ...run } = (await client.startSweep(params.productId, params.linkId)).data;
35320
+ return toolResult({
35321
+ sweepId: id,
35322
+ ...run
35323
+ });
35324
+ }));
35243
35325
  server.registerTool("taiga_fix_finding", {
35244
35326
  title: "Fix a finding",
35245
35327
  description: "Raise an initiative that fixes a finding; it ends in a pull request, which merges on its own only where the product's auto-merge allows it. wholeGroup: true fixes, in that repository, every open advisory on that package version in one bump, or every place the rule flagged. A malicious package is removed, with every advisory on that version, whatever wholeGroup says. A license finding the row marks fixable has its packages replaced by ones on the approved list. A language runtime moves every file declaring it together, in a container image only to a tag the image has published. Refused when there is no version to move to (fixable: false; for a runtime, also while its image has not published the fix), the code is in a submodule, or a secret is only in history (rotate it outside Taiga).",
@@ -35723,7 +35805,7 @@ const PRODUCT_VIEW_FIELDS = [
35723
35805
  "createdAt",
35724
35806
  "updatedAt"
35725
35807
  ];
35726
- const UNSET_MEANS = "A null setting is unset: kind reads as application; autoMerge follows the factory, then the organization; ownsInfrastructure and ownsDeployment follow the organization default (yes when it has none); ownsApplication is yes; emitDesignStandards follows how the product started; networkAccess is allowlist. signalAutonomy is what each kind of finding resolves to (off, notify, propose, build, merge) and what decided it: the product, the kind default or cap, or auto-merge consent. dailyFixLimit is how many fixes Taiga may raise on its own per day, set by the product or the starting value (setBy default).";
35808
+ const UNSET_MEANS = "A null setting is unset: kind reads as application; autoMerge follows the factory, then the organization; ownsInfrastructure and ownsDeployment follow the organization default (yes when it has none); ownsApplication is yes; emitDesignStandards follows how the product started; networkAccess is unrestricted. signalAutonomy is what each kind of finding resolves to (off, notify, propose, build, merge) and what decided it: the product, the kind default or cap, or auto-merge consent. dailyFixLimit is how many fixes Taiga may raise on its own per day, set by the product or the starting value (setBy default).";
35727
35809
  /**
35728
35810
  * Each product's policy standing beside its row: the counts the standing read opens with. A product still in setup
35729
35811
  * has none to read; a read the API refuses or fails says so on its row rather than failing the list.
@@ -36752,13 +36834,14 @@ function changeRequestRef(provider, number) {
36752
36834
  }
36753
36835
  /** What a person does about a handback, by its reason, as the web's handback detail says it, on the run's forge. */
36754
36836
  function handbackNextStep(escalation, provider = null) {
36755
- const terms = FORGE_TERMS[forgeOf({ provider }) ?? "github"];
36756
- const where = terms.name;
36837
+ const forge = forgeOf({ provider });
36838
+ const terms = FORGE_TERMS[forge ?? "github"];
36839
+ const where = forge ? ` on ${terms.name}` : "";
36757
36840
  const changeRequest = terms.changeRequest;
36758
36841
  const reason = escalation && typeof escalation === "object" ? escalation.reason : null;
36759
- if (reason === "check_weakened") return `review that change on ${where} before merging`;
36760
- if (reason === "ci_never_settled") return `look at what is still running or queued in CI on ${where}, then review the ${changeRequest}`;
36761
- return `fix it by hand, or review the ${changeRequest} on ${where}, which hands it back to the agent`;
36842
+ if (reason === "check_weakened") return `review that change${where} before merging`;
36843
+ if (reason === "ci_never_settled") return `look at what is still running or queued in CI${where}, then review the ${changeRequest}`;
36844
+ return `fix it by hand, or review the ${changeRequest}${where}, which hands it back to the agent`;
36762
36845
  }
36763
36846
  /** The web's words for why Taiga keeps a pull request a draft. */
36764
36847
  const READY_BLOCKER_SAID = {
@@ -37197,14 +37280,21 @@ function registerBuildTools(server, client) {
37197
37280
  }));
37198
37281
  server.registerTool("taiga_get_run", {
37199
37282
  title: "Get run",
37200
- description: "Read one coding agent run, and why it failed when it did: its outcome, pull request, security pass (scanCoverage names scanners that did not run) and each step with its commit, files and checks. A failed run says where it stopped (stoppedIn) and the line of the error that says why (cause). full: true adds every step's instructions and report. lastReplan says what a request for changes did to the plan the run builds now: the steps it added, edited and dropped. A failed or stopped run's nextStep says how to carry it on (taiga_resume_initiative on its initiative).",
37283
+ description: "Read one coding agent run, and why it failed when it did: its outcome, pull request, security pass (scanCoverage names scanners that did not run) and each step with its commit, files and checks. A failed run says where it stopped (stoppedIn) and the line of the error that says why (cause). full: true adds every step's instructions and report. lastReplan says what a request for changes did to the plan the run builds now: the steps it added, edited and dropped. A failed or stopped run's nextStep says how to carry it on (taiga_resume_initiative on its initiative). hostsReached lists the public hosts the run reached through the egress gateway, first reached first, with the bytes it sent and received there.",
37201
37284
  inputSchema: object({
37202
37285
  runId,
37203
37286
  full: boolean().optional().describe("Carry each step's complete instructions and report (default false: a summary)")
37204
37287
  }),
37205
37288
  annotations: READ_ONLY
37206
37289
  }, (params) => runTool(async () => {
37207
- const [run, steps] = await Promise.all([client.getBuildRun(params.runId), client.listBuildRunSteps(params.runId)]);
37290
+ const [run, steps, hosts] = await Promise.all([
37291
+ client.getBuildRun(params.runId),
37292
+ client.listBuildRunSteps(params.runId),
37293
+ client.listBuildRunEgressHosts(params.runId).catch((error) => {
37294
+ if (error instanceof TaigaApiError && error.status === 404) return { data: [] };
37295
+ throw error;
37296
+ })
37297
+ ]);
37208
37298
  const runRow = run.data;
37209
37299
  const rows = steps.data.map((step) => neverStarted(step));
37210
37300
  const where = stoppedIn(runRow, rows);
@@ -37222,7 +37312,8 @@ function registerBuildTools(server, client) {
37222
37312
  ...lastReplan ? { lastReplan: {
37223
37313
  ...lastReplan,
37224
37314
  waitsForReview
37225
- } } : {}
37315
+ } } : {},
37316
+ ...hostsReachedOf(hosts.data)
37226
37317
  };
37227
37318
  const note = verificationNote(rows);
37228
37319
  const verification = note ? { verificationNote: note } : {};
@@ -37282,6 +37373,22 @@ function steerSituation(steer) {
37282
37373
  if (steer === "after_round") return "The run is answering review comments or fixing CI; the request is planned when that round ends, and no further automatic round starts while it is open.";
37283
37374
  return "A re-plan is already running; the request joins it.";
37284
37375
  }
37376
+ /** At most this many hosts in a run's read; the rest are counted. */
37377
+ const HOSTS_REACHED_SHOWN = 50;
37378
+ /** Where a run went (PRO-4268): its hosts, first reached first, or nothing for a run that reached none. */
37379
+ function hostsReachedOf(hosts) {
37380
+ if (hosts.length === 0) return {};
37381
+ const shown = hosts.slice(0, HOSTS_REACHED_SHOWN).map(({ host, sentBytes, receivedBytes, connections }) => ({
37382
+ host,
37383
+ sentBytes,
37384
+ receivedBytes,
37385
+ connections
37386
+ }));
37387
+ return {
37388
+ hostsReached: shown,
37389
+ ...hosts.length > shown.length ? { hostsReachedNotShown: hosts.length - shown.length } : {}
37390
+ };
37391
+ }
37285
37392
  //#endregion
37286
37393
  //#region src/tools/queue.ts
37287
37394
  /** How many entries the read names; past this an entry keeps its initiativeId only. */
@@ -55408,7 +55515,7 @@ function registerSetupTools(server, client) {
55408
55515
  }));
55409
55516
  server.registerTool("taiga_update_product", {
55410
55517
  title: "Change a product's settings",
55411
- description: "Change a product's name, what Taiga builds for it (application, infrastructure, pipelines), or where its builds may connect (networkAccess: allowlist, Taiga's standard list plus the product's networkHosts, or unrestricted, any public host; networkHosts replaces the list, each one exact DNS name, no wildcard or domain anyone can host on, 100 at most; changes apply from the next build). A new name changes its slug. Later plans follow the change; planned work is not redone.",
55518
+ description: "Change a product's name, what Taiga builds for it (application, infrastructure, pipelines), or where its builds may connect (networkAccess: unrestricted, any public host, the default; or allowlist, Taiga's standard list plus the product's networkHosts; networkHosts replaces the list, each one exact DNS name, no wildcard or domain anyone can host on, 100 at most; changes apply from the next build). A new name changes its slug. Later plans follow the change; planned work is not redone.",
55412
55519
  inputSchema: object({
55413
55520
  productId,
55414
55521
  name: string$2().trim().min(1).max(255).optional().describe("A new name"),
@@ -55416,7 +55523,7 @@ function registerSetupTools(server, client) {
55416
55523
  ...buildScope,
55417
55524
  deploymentNotes: deploymentNotes.nullable().optional(),
55418
55525
  emitDesignStandards: boolean().nullable().optional().describe("Inherit the organization's design standards; null follows the default"),
55419
- networkAccess: _enum(PRODUCT_NETWORK_ACCESS).nullable().optional().describe("Where a build's sandbox may connect: allowlist (the default; null returns to it) or unrestricted"),
55526
+ networkAccess: _enum(PRODUCT_NETWORK_ACCESS).nullable().optional().describe("Where a build's sandbox may connect: unrestricted (the default; null returns to it) or allowlist"),
55420
55527
  networkHosts: array(string$2().trim().toLowerCase().min(1).max(253)).max(100).optional().describe("The product's own hosts beyond the standard list, replacing the current ones: exact DNS names such as api.example.com")
55421
55528
  }),
55422
55529
  annotations: OPERATE_SETTING
@@ -55724,6 +55831,7 @@ const PAID_WORK = /* @__PURE__ */ new Set([
55724
55831
  "taiga_review_plan",
55725
55832
  "taiga_set_auto_build",
55726
55833
  "taiga_start_import",
55834
+ "taiga_start_sweep",
55727
55835
  "taiga_stop_generating_documents",
55728
55836
  "taiga_stop_run",
55729
55837
  "taiga_sync_design_tokens"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taiga-ai/mcp-server",
3
- "version": "0.37.0-rc.956",
3
+ "version": "0.37.0-rc.984",
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",