@taiga-ai/mcp-server 0.36.0-rc.892 → 0.36.0-rc.926
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 +337 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24687,6 +24687,19 @@ const PRODUCT_DOCUMENT_DISPLAY_NAMES = {
|
|
|
24687
24687
|
const PRODUCT_DOCUMENT_ORIGINS = ["plan", "reality"];
|
|
24688
24688
|
/** The forges a repository link can name: `FORGE_PROVIDERS`, under the name links have always used. */
|
|
24689
24689
|
const VCS_PROVIDERS = FORGE_PROVIDERS;
|
|
24690
|
+
Object.fromEntries(Object.entries({
|
|
24691
|
+
specification: "specification",
|
|
24692
|
+
"user-flows": "user_flow",
|
|
24693
|
+
architecture: "architecture",
|
|
24694
|
+
"tech-decisions": "technology_decisions",
|
|
24695
|
+
"data-flow": "data_flow",
|
|
24696
|
+
"threat-model": "threat_model",
|
|
24697
|
+
dpia: "privacy_assessment",
|
|
24698
|
+
"risk-register": "risk_register",
|
|
24699
|
+
"service-blueprint": "service_blueprint",
|
|
24700
|
+
"ui-direction": "ui_direction",
|
|
24701
|
+
"codebase-snapshot": "codebase_snapshot"
|
|
24702
|
+
}).map(([slug, apiType]) => [apiType, slug]));
|
|
24690
24703
|
//#endregion
|
|
24691
24704
|
//#region ../../packages/types/dist/route-key.js
|
|
24692
24705
|
/**
|
|
@@ -25478,6 +25491,7 @@ discriminatedUnion("kind", [
|
|
|
25478
25491
|
})).max(20),
|
|
25479
25492
|
moreFailed: number$1().int().min(0).optional(),
|
|
25480
25493
|
observedAt: optionalMoment,
|
|
25494
|
+
repository: string$2().min(1).max(255).optional(),
|
|
25481
25495
|
stepId: optionalUuid
|
|
25482
25496
|
}),
|
|
25483
25497
|
object({
|
|
@@ -26070,6 +26084,92 @@ object({
|
|
|
26070
26084
|
...outcomes === void 0 ? {} : { outcomes }
|
|
26071
26085
|
}));
|
|
26072
26086
|
//#endregion
|
|
26087
|
+
//#region ../../packages/types/dist/registries.js
|
|
26088
|
+
/**
|
|
26089
|
+
* The package ecosystems a registry can serve: every ecosystem the coding
|
|
26090
|
+
* agent builds (its skills and its image), keyed by the install tooling that
|
|
26091
|
+
* reads the credential. `maven` is a Maven repository, and Maven builds get
|
|
26092
|
+
* its credential (PRO-2916); Gradle builds name theirs in their own build
|
|
26093
|
+
* scripts and get none yet (PRO-2928).
|
|
26094
|
+
*/
|
|
26095
|
+
const REGISTRY_ECOSYSTEMS = [
|
|
26096
|
+
"npm",
|
|
26097
|
+
"terraform",
|
|
26098
|
+
"pypi",
|
|
26099
|
+
"nuget",
|
|
26100
|
+
"go",
|
|
26101
|
+
"cargo",
|
|
26102
|
+
"maven",
|
|
26103
|
+
"rubygems",
|
|
26104
|
+
"composer"
|
|
26105
|
+
];
|
|
26106
|
+
const REGISTRY_VENDORS = [
|
|
26107
|
+
"npmjs",
|
|
26108
|
+
"github",
|
|
26109
|
+
"gcp_artifact",
|
|
26110
|
+
"generic",
|
|
26111
|
+
"hcp_terraform",
|
|
26112
|
+
"scalr",
|
|
26113
|
+
"azure_artifacts",
|
|
26114
|
+
"jfrog",
|
|
26115
|
+
"git_host",
|
|
26116
|
+
"aws_codeartifact"
|
|
26117
|
+
];
|
|
26118
|
+
/** An IAM role ARN, as the CodeArtifact credential takes it. */
|
|
26119
|
+
const AWS_ROLE_ARN_PATTERN = /^arn:aws:iam::\d{12}:role\/[\w+=,.@/-]{1,512}$/;
|
|
26120
|
+
//#endregion
|
|
26121
|
+
//#region ../../packages/types/dist/gitlab.js
|
|
26122
|
+
/**
|
|
26123
|
+
* GitLab connections (PRO-3096, P-PRO-150): the shared request/response
|
|
26124
|
+
* contract of `/v1/gitlab/connections`. A connection is one GitLab host
|
|
26125
|
+
* (GitLab.com, a self-managed instance or GitLab Dedicated) with a bot token
|
|
26126
|
+
* the tenant pasted. The token is write-only and appears in no response.
|
|
26127
|
+
*/
|
|
26128
|
+
const GITLAB_CONNECTION_STATUSES = [
|
|
26129
|
+
"valid",
|
|
26130
|
+
"auth_failed",
|
|
26131
|
+
"unreachable"
|
|
26132
|
+
];
|
|
26133
|
+
//#endregion
|
|
26134
|
+
//#region ../../packages/types/dist/cloud-connections.js
|
|
26135
|
+
const CLOUD_CONNECTION_STATUSES = [
|
|
26136
|
+
"pending_setup",
|
|
26137
|
+
"validating",
|
|
26138
|
+
"active",
|
|
26139
|
+
"error",
|
|
26140
|
+
"suspended",
|
|
26141
|
+
"disconnected"
|
|
26142
|
+
];
|
|
26143
|
+
/**
|
|
26144
|
+
* Keys in `providerConfig` that only Taiga's provisioning path may write.
|
|
26145
|
+
*
|
|
26146
|
+
* PRO-858. `accountName` is the correlation key the AFT account-ready callback
|
|
26147
|
+
* arrives with, and the webhook resolves it under service context with no
|
|
26148
|
+
* tenant predicate -- it has to, because the callback carries no tenant. It is
|
|
26149
|
+
* also guessable: `generateAccountName` derives it from tenant, team and
|
|
26150
|
+
* project slugs. So a tenant that could write this key could plant a row
|
|
26151
|
+
* claiming another tenant's account name, wait for that callback, and have the
|
|
26152
|
+
* victim's `deployConfig` (accountId, deployRoleArn, stateBucket) delivered to
|
|
26153
|
+
* their own environment.
|
|
26154
|
+
*
|
|
26155
|
+
* `accountKey` is the same identity in unguessable form
|
|
26156
|
+
* (`sha256(tenantId:productId:envType)`), and is what the AFT module is named
|
|
26157
|
+
* for -- equally not the caller's to assert.
|
|
26158
|
+
*
|
|
26159
|
+
* Neither is tenant-facing: no provider schema models them, and
|
|
26160
|
+
* `providerConfigProblem` documents them as the shape a MANAGED row has. The
|
|
26161
|
+
* update path merges and persists the RAW config precisely so Zod does not
|
|
26162
|
+
* strip them off managed rows, which is what made a tenant-supplied value
|
|
26163
|
+
* durable. Rejecting rather than stripping, so a client sending one is told,
|
|
26164
|
+
* instead of silently having it dropped.
|
|
26165
|
+
*/
|
|
26166
|
+
const TAIGA_MANAGED_PROVIDER_CONFIG_KEYS = ["accountName", "accountKey"];
|
|
26167
|
+
/** Whether `config` leaves alone the keys only Taiga's provisioning writes. */
|
|
26168
|
+
function isTenantWritableProviderConfig(config) {
|
|
26169
|
+
return !TAIGA_MANAGED_PROVIDER_CONFIG_KEYS.some((key) => key in config);
|
|
26170
|
+
}
|
|
26171
|
+
const TAIGA_MANAGED_PROVIDER_CONFIG_MESSAGE = `providerConfig may not set ${TAIGA_MANAGED_PROVIDER_CONFIG_KEYS.join(" or ")}: Taiga's provisioning owns those keys`;
|
|
26172
|
+
//#endregion
|
|
26073
26173
|
//#region ../../packages/types/dist/environments.js
|
|
26074
26174
|
const ENVIRONMENT_TYPES = [
|
|
26075
26175
|
"development",
|
|
@@ -26083,6 +26183,31 @@ const ENVIRONMENT_TYPES = [
|
|
|
26083
26183
|
//#endregion
|
|
26084
26184
|
//#region ../../packages/types/dist/api-keys.js
|
|
26085
26185
|
/**
|
|
26186
|
+
* API key scopes control what operations a key can perform.
|
|
26187
|
+
* Scopes act as a ceiling -- the effective permissions are the intersection
|
|
26188
|
+
* of the key's scopes and the user's role-based capabilities.
|
|
26189
|
+
*
|
|
26190
|
+
* Convention: "resource:action" matching the existing Capability type.
|
|
26191
|
+
*/
|
|
26192
|
+
const API_KEY_SCOPES = [
|
|
26193
|
+
"products:read",
|
|
26194
|
+
"products:write",
|
|
26195
|
+
"backlog:read",
|
|
26196
|
+
"backlog:write",
|
|
26197
|
+
"factories:read",
|
|
26198
|
+
"factories:documents:write",
|
|
26199
|
+
"users:read",
|
|
26200
|
+
"tenant:documents:read",
|
|
26201
|
+
"tenant:documents:write",
|
|
26202
|
+
"vcs:read",
|
|
26203
|
+
"customDocuments:read",
|
|
26204
|
+
"customDocuments:write",
|
|
26205
|
+
"customDocuments:delete",
|
|
26206
|
+
"factories:write",
|
|
26207
|
+
"vcs:manage"
|
|
26208
|
+
];
|
|
26209
|
+
const API_KEY_PREFIX = "taiga_sk_live_";
|
|
26210
|
+
/**
|
|
26086
26211
|
* The groups the MCP server's tools come in (PRO-2838). A key may name the ones
|
|
26087
26212
|
* its AI tool sees; null is every one. This is focus, not security: a tool the
|
|
26088
26213
|
* key's role or scopes do not allow is never offered, whatever is named here.
|
|
@@ -26216,10 +26341,24 @@ function isFixableFinding(finding) {
|
|
|
26216
26341
|
if (finding.status !== "open") return false;
|
|
26217
26342
|
if (finding.location?.historyOnly) return false;
|
|
26218
26343
|
if (!isAgentRemediable(finding)) return false;
|
|
26219
|
-
if (finding.fingerprint?.startsWith("base-image:")
|
|
26344
|
+
if (finding.fingerprint?.startsWith("base-image:") || finding.baseImageFix) {
|
|
26345
|
+
if (finding.baseImageFix) return finding.baseImageFix.way === "move" || finding.baseImageFix.way === "upgrade";
|
|
26346
|
+
return typeof finding.baseMove === "boolean" ? finding.baseMove : baseImageMoveRemoves(finding.data);
|
|
26347
|
+
}
|
|
26220
26348
|
if (finding.kind === "vulnerable_dependency" && isMaliciousPackageFinding(finding)) return true;
|
|
26349
|
+
if (isPinBlocked(finding)) return false;
|
|
26221
26350
|
return isCodeRemediationKind(finding.kind) || !!finding.recommendedVersion;
|
|
26222
26351
|
}
|
|
26352
|
+
/**
|
|
26353
|
+
* Whether a Fix cannot work: another package's pin caps this finding's fix, and
|
|
26354
|
+
* the last fix ended still vulnerable against it (`opentelemetry-api` under
|
|
26355
|
+
* `aws-opentelemetry-distro`'s `==1.44.0`). Another would spend a run to meet
|
|
26356
|
+
* it again. Blocked with no such fix, a person's Fix still runs (AC-17): they
|
|
26357
|
+
* may know a way round. The gate lifts the hold when the pin moves.
|
|
26358
|
+
*/
|
|
26359
|
+
function isPinBlocked(finding) {
|
|
26360
|
+
return finding.autoFixHeld?.reason === "blocked_by_dependency" && finding.autoFixHeld.fixFailed === true;
|
|
26361
|
+
}
|
|
26223
26362
|
function baseImageMoveRemoves(data) {
|
|
26224
26363
|
const baseImage = typeof data === "object" && data !== null ? data.baseImage : null;
|
|
26225
26364
|
const bases = typeof baseImage === "object" && baseImage !== null ? baseImage.bases : null;
|
|
@@ -27080,6 +27219,14 @@ const cloudProviderConfig = discriminatedUnion("provider", [
|
|
|
27080
27219
|
bestPractices: cloudBestPractices
|
|
27081
27220
|
})
|
|
27082
27221
|
]);
|
|
27222
|
+
const newCloudConnection = strictObject({
|
|
27223
|
+
name: string$2().min(1).max(150),
|
|
27224
|
+
provider: _enum(CLOUD_PROVIDERS),
|
|
27225
|
+
providerConfig: cloudProviderConfig
|
|
27226
|
+
}).refine((connection) => connection.provider === connection.providerConfig.provider, {
|
|
27227
|
+
message: "connection.provider must match connection.providerConfig.provider",
|
|
27228
|
+
path: ["providerConfig", "provider"]
|
|
27229
|
+
});
|
|
27083
27230
|
const columnIndex = number$1().int().min(1).max(EXCEL_MAX_COLUMN);
|
|
27084
27231
|
const sheetMap = object({
|
|
27085
27232
|
sheetName: string$2().min(1).max(120),
|
|
@@ -27137,7 +27284,7 @@ strictObject({ type: productDocumentType }), object({
|
|
|
27137
27284
|
shown: array(string$2()),
|
|
27138
27285
|
count: number$1().int().min(0)
|
|
27139
27286
|
})
|
|
27140
|
-
}), strictObject({ type: productDocumentType }), strictObject({ type: productDocumentType }), strictObject({
|
|
27287
|
+
}), strictObject({ type: productDocumentType }), strictObject({ type: productDocumentType }), strictObject({
|
|
27141
27288
|
githubRepositoryId: uuid.optional(),
|
|
27142
27289
|
/** A GitLab project, by the connection whose bot reaches it and GitLab's numeric id (P-PRO-150). */
|
|
27143
27290
|
gitlabConnectionId: uuid.optional(),
|
|
@@ -27223,15 +27370,8 @@ strictObject({ type: productDocumentType }), object({
|
|
|
27223
27370
|
literal(12)
|
|
27224
27371
|
]),
|
|
27225
27372
|
note: string$2().trim().max(1e3).optional()
|
|
27226
|
-
}), strictObject({ environments: array(string$2()).default(["development"]) }), strictObject({
|
|
27227
|
-
connection:
|
|
27228
|
-
name: string$2().min(1).max(150),
|
|
27229
|
-
provider: _enum(CLOUD_PROVIDERS),
|
|
27230
|
-
providerConfig: cloudProviderConfig
|
|
27231
|
-
}).refine((connection) => connection.provider === connection.providerConfig.provider, {
|
|
27232
|
-
message: "connection.provider must match connection.providerConfig.provider",
|
|
27233
|
-
path: ["providerConfig", "provider"]
|
|
27234
|
-
}),
|
|
27373
|
+
}), strictObject({ environments: array(string$2()).default(["development"]) }), object({ id: string$2().uuid() }), strictObject({
|
|
27374
|
+
connection: newCloudConnection,
|
|
27235
27375
|
environment: object({
|
|
27236
27376
|
name: string$2().min(1).max(100),
|
|
27237
27377
|
slug: string$2().min(1).max(63).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "Slug must be lowercase letters, digits, and dashes"),
|
|
@@ -27240,6 +27380,19 @@ strictObject({ type: productDocumentType }), object({
|
|
|
27240
27380
|
isProtected: boolean().default(false)
|
|
27241
27381
|
}).optional()
|
|
27242
27382
|
});
|
|
27383
|
+
/**
|
|
27384
|
+
* The MCP toolsets a key's AI tool sees: at least one, each once, or null for
|
|
27385
|
+
* every one (PRO-2838). An empty list would start a server with no tools at all.
|
|
27386
|
+
*/
|
|
27387
|
+
const mcpToolsets = array(_enum(MCP_TOOLSETS)).min(1).refine((sets) => new Set(sets).size === sets.length, "Name each toolset once").nullable();
|
|
27388
|
+
strictObject({
|
|
27389
|
+
key: string$2().regex(new RegExp(`^${API_KEY_PREFIX}[0-9a-f]{64}$`)),
|
|
27390
|
+
name: string$2().min(1).max(255),
|
|
27391
|
+
scopes: array(_enum(API_KEY_SCOPES)).optional(),
|
|
27392
|
+
expiresInDays: number$1().int().min(1).max(365).optional(),
|
|
27393
|
+
mcpToolsets: mcpToolsets.optional()
|
|
27394
|
+
}), object({ keyId: uuid });
|
|
27395
|
+
strictObject({ mcpToolsets });
|
|
27243
27396
|
object({
|
|
27244
27397
|
url: string$2().url(),
|
|
27245
27398
|
expiresAt: string$2()
|
|
@@ -27261,7 +27414,125 @@ object({
|
|
|
27261
27414
|
/** A factory document type, its legacy name read as the current one. */
|
|
27262
27415
|
const factoryDocumentType = _enum([...FACTORY_DOCUMENT_TYPES, LEGACY_FACTORY_INSTRUCTIONS_TYPE]).transform((type) => type === "team_instructions" ? FACTORY_INSTRUCTIONS_TYPE : type);
|
|
27263
27416
|
strictObject({ type: factoryDocumentType }), strictObject({ type: factoryDocumentType });
|
|
27264
|
-
|
|
27417
|
+
/**
|
|
27418
|
+
* A registry scope: an npm scope ("@acme") or a Go module path prefix
|
|
27419
|
+
* ("github.com/acme"), as `POST /registries` takes one (PRO-3670). Which
|
|
27420
|
+
* ecosystem takes which is the service's rule.
|
|
27421
|
+
*/
|
|
27422
|
+
const namedSegments = (value) => value.split("/").every((seg) => seg !== "" && seg !== "." && seg !== "..");
|
|
27423
|
+
const registryScope = string$2().regex(/^@?[A-Za-z0-9][A-Za-z0-9._~/-]*$/, "Not a valid scope").max(214).refine(namedSegments, "Not a valid scope");
|
|
27424
|
+
/** The package a registry's check fetches, in the union of the ecosystems' grammars. */
|
|
27425
|
+
const registryTestPackage = string$2().min(1).max(214).regex(/^@?[A-Za-z0-9_][A-Za-z0-9._~/:-]*$/, "Must be a valid package name").refine(namedSegments, "Must be a valid package name");
|
|
27426
|
+
/** KMS direct-encrypt takes 4096 bytes; the raw secret stays well under. */
|
|
27427
|
+
const REGISTRY_CREDENTIAL_MAX_BYTES = 3500;
|
|
27428
|
+
/** A registry's write-only credential: exactly one of a token, a GCP key or an AWS role, as the route takes it. */
|
|
27429
|
+
const registryCredential = strictObject({
|
|
27430
|
+
token: string$2().min(1).max(REGISTRY_CREDENTIAL_MAX_BYTES).optional(),
|
|
27431
|
+
username: string$2().min(1).max(256).regex(/^[^:\s]+$/, "Username must not contain a colon or whitespace").optional(),
|
|
27432
|
+
credentialsJson: string$2().min(2).max(REGISTRY_CREDENTIAL_MAX_BYTES).optional(),
|
|
27433
|
+
awsRoleArn: string$2().max(600).regex(AWS_ROLE_ARN_PATTERN, "Not an IAM role ARN").optional()
|
|
27434
|
+
}).refine((c) => [
|
|
27435
|
+
c.token,
|
|
27436
|
+
c.credentialsJson,
|
|
27437
|
+
c.awsRoleArn
|
|
27438
|
+
].filter((v) => v != null).length === 1, { message: "Provide exactly one of token, credentialsJson or awsRoleArn" }).refine((c) => c.username == null || c.token != null, { message: "A username goes with a token" }).refine((c) => new TextEncoder().encode(JSON.stringify(c)).length <= 4e3, { message: "Credential is too large to encrypt (must be under 4 KB once JSON-encoded)" });
|
|
27439
|
+
/** An instant as an ISO string, which the service reads as a date. */
|
|
27440
|
+
const isoInstant = string$2().datetime({ offset: true });
|
|
27441
|
+
object({
|
|
27442
|
+
status: _enum([
|
|
27443
|
+
"unvalidated",
|
|
27444
|
+
"valid",
|
|
27445
|
+
"auth_failed",
|
|
27446
|
+
"unreachable"
|
|
27447
|
+
]),
|
|
27448
|
+
lastValidatedAt: string$2(),
|
|
27449
|
+
detail: string$2().nullable()
|
|
27450
|
+
});
|
|
27451
|
+
strictObject({
|
|
27452
|
+
displayName: string$2().min(1).max(255).optional(),
|
|
27453
|
+
registryUrl: string$2().url().max(512).optional(),
|
|
27454
|
+
scopes: array(registryScope).max(50).optional(),
|
|
27455
|
+
expiresAt: isoInstant.nullable().optional(),
|
|
27456
|
+
credential: registryCredential.optional(),
|
|
27457
|
+
testPackage: registryTestPackage.nullable().optional()
|
|
27458
|
+
});
|
|
27459
|
+
/** A GitLab bot token, as the route takes one. */
|
|
27460
|
+
const gitlabToken = string$2().trim().min(20, "That does not look like a GitLab access token").max(1024).regex(/^[A-Za-z0-9_.-]+$/, "That does not look like a GitLab access token");
|
|
27461
|
+
/** A private CA as PEM certificates; the service parses it. */
|
|
27462
|
+
const gitlabCaBundle = string$2().min(1).max(65536);
|
|
27463
|
+
/** What a connect or a token change learned, beyond the connection's record. */
|
|
27464
|
+
const gitlabValidationReport = object({
|
|
27465
|
+
pushableProjectCount: number$1().int().nullable(),
|
|
27466
|
+
warnings: array(string$2())
|
|
27467
|
+
});
|
|
27468
|
+
strictObject({
|
|
27469
|
+
displayName: string$2().trim().min(1).max(255).optional(),
|
|
27470
|
+
token: gitlabToken.optional(),
|
|
27471
|
+
caBundlePem: gitlabCaBundle.nullable().optional()
|
|
27472
|
+
}), gitlabValidationReport.optional(), object({
|
|
27473
|
+
status: _enum(GITLAB_CONNECTION_STATUSES),
|
|
27474
|
+
lastValidatedAt: string$2(),
|
|
27475
|
+
detail: string$2().nullable()
|
|
27476
|
+
}), object({ finished: boolean() }), strictObject({ search: string$2().trim().max(100).optional() }), object({
|
|
27477
|
+
projects: array(object({
|
|
27478
|
+
id: number$1().int(),
|
|
27479
|
+
pathWithNamespace: string$2(),
|
|
27480
|
+
nameWithNamespace: string$2(),
|
|
27481
|
+
webUrl: string$2(),
|
|
27482
|
+
defaultBranch: string$2().nullable()
|
|
27483
|
+
})).nullable(),
|
|
27484
|
+
truncated: boolean()
|
|
27485
|
+
});
|
|
27486
|
+
object({
|
|
27487
|
+
outcome: _enum([
|
|
27488
|
+
"uninstalled",
|
|
27489
|
+
"left_in_use",
|
|
27490
|
+
"uninstall_failed"
|
|
27491
|
+
]),
|
|
27492
|
+
manageUrl: string$2().nullable()
|
|
27493
|
+
});
|
|
27494
|
+
/** A value GitHub's redirect carries back: a state token, or a one-time code. */
|
|
27495
|
+
const githubCallbackSecret = string$2().trim().min(1).max(1024);
|
|
27496
|
+
strictObject({
|
|
27497
|
+
displayName: string$2().trim().min(1).max(255),
|
|
27498
|
+
baseUrl: string$2().trim().min(1).max(480),
|
|
27499
|
+
token: gitlabToken,
|
|
27500
|
+
caBundlePem: gitlabCaBundle.nullable().optional()
|
|
27501
|
+
}), object({
|
|
27502
|
+
connectionId: uuid,
|
|
27503
|
+
validation: gitlabValidationReport
|
|
27504
|
+
}), strictObject({
|
|
27505
|
+
displayName: string$2().min(1).max(255),
|
|
27506
|
+
ecosystem: _enum(REGISTRY_ECOSYSTEMS).optional(),
|
|
27507
|
+
vendor: _enum(REGISTRY_VENDORS),
|
|
27508
|
+
registryUrl: string$2().url().max(512),
|
|
27509
|
+
scopes: array(registryScope).max(50).optional(),
|
|
27510
|
+
expiresAt: isoInstant.nullable().optional(),
|
|
27511
|
+
credential: registryCredential,
|
|
27512
|
+
testPackage: registryTestPackage.optional()
|
|
27513
|
+
}), strictObject({ hostId: uuid.optional() }), object({ installUrl: string$2().url() }), strictObject({ state: githubCallbackSecret }), object({
|
|
27514
|
+
clientId: string$2(),
|
|
27515
|
+
authorizeUrl: string$2(),
|
|
27516
|
+
redirectUri: string$2().optional()
|
|
27517
|
+
}), strictObject({
|
|
27518
|
+
installationId: number$1().int().positive(),
|
|
27519
|
+
setupAction: _enum(["install", "update"]),
|
|
27520
|
+
state: githubCallbackSecret.optional(),
|
|
27521
|
+
code: githubCallbackSecret.optional()
|
|
27522
|
+
}), strictObject({
|
|
27523
|
+
subdomain: string$2().min(1).max(39).optional(),
|
|
27524
|
+
serverUrl: string$2().min(1).max(2048).optional(),
|
|
27525
|
+
caBundlePem: string$2().max(65536).optional(),
|
|
27526
|
+
orgLogin: string$2().min(1).max(39),
|
|
27527
|
+
displayName: string$2().max(255).optional()
|
|
27528
|
+
}), object({
|
|
27529
|
+
manifest: record(string$2(), unknown$1()),
|
|
27530
|
+
postUrl: string$2().url(),
|
|
27531
|
+
state: string$2()
|
|
27532
|
+
}), strictObject({
|
|
27533
|
+
state: githubCallbackSecret,
|
|
27534
|
+
code: githubCallbackSecret
|
|
27535
|
+
}), strictObject({ type: _enum(TENANT_DOCUMENT_TYPES) }), strictObject({ type: _enum(TENANT_DOCUMENT_TYPES).refine((type) => type !== "design_standards", { message: "The design standards draft is not made through sync" }) }), strictObject({
|
|
27265
27536
|
name: string$2().min(1).max(50),
|
|
27266
27537
|
action: _enum(["accept", "decline"])
|
|
27267
27538
|
}), object({
|
|
@@ -27306,10 +27577,19 @@ strictObject({ type: _enum(TENANT_DOCUMENT_TYPES) }), strictObject({ type: _enum
|
|
|
27306
27577
|
}).refine((a) => Boolean(a.approve) !== Boolean(a.remove), { message: "Name one license to approve or remove" }), object({
|
|
27307
27578
|
enrolled: number$1().int().nonnegative(),
|
|
27308
27579
|
total: number$1().int().nonnegative()
|
|
27580
|
+
}), object({
|
|
27581
|
+
principalArn: string$2().nullable(),
|
|
27582
|
+
externalId: string$2()
|
|
27309
27583
|
});
|
|
27310
27584
|
strictObject({ kind: _enum(["sbom", "notices"]) }), object({
|
|
27311
27585
|
url: string$2().url().nullable(),
|
|
27312
27586
|
expiresAt: string$2().nullable()
|
|
27587
|
+
}), object({
|
|
27588
|
+
branches: array(object({
|
|
27589
|
+
name: string$2(),
|
|
27590
|
+
protected: boolean()
|
|
27591
|
+
})).nullable(),
|
|
27592
|
+
truncated: boolean()
|
|
27313
27593
|
});
|
|
27314
27594
|
strictObject({
|
|
27315
27595
|
ignoreReason: _enum(MAINTENANCE_IGNORE_REASONS),
|
|
@@ -27322,6 +27602,11 @@ strictObject({ tier: _enum([
|
|
|
27322
27602
|
"staging",
|
|
27323
27603
|
"production"
|
|
27324
27604
|
]) });
|
|
27605
|
+
strictObject({
|
|
27606
|
+
name: string$2().min(1).max(150).optional(),
|
|
27607
|
+
status: _enum(CLOUD_CONNECTION_STATUSES).optional(),
|
|
27608
|
+
providerConfig: record(string$2(), unknown$1()).refine(isTenantWritableProviderConfig, { message: TAIGA_MANAGED_PROVIDER_CONFIG_MESSAGE }).optional()
|
|
27609
|
+
});
|
|
27325
27610
|
object({
|
|
27326
27611
|
url: string$2().url(),
|
|
27327
27612
|
expiresAt: string$2(),
|
|
@@ -28379,6 +28664,7 @@ const FINDING_ROW_FIELDS = [
|
|
|
28379
28664
|
"malicious",
|
|
28380
28665
|
"baseMove",
|
|
28381
28666
|
"baseImageMove",
|
|
28667
|
+
"baseImageFix",
|
|
28382
28668
|
"removal",
|
|
28383
28669
|
"replaceable",
|
|
28384
28670
|
"status",
|
|
@@ -28506,7 +28792,7 @@ function withFixability(row) {
|
|
|
28506
28792
|
return {
|
|
28507
28793
|
...row,
|
|
28508
28794
|
fixable: false,
|
|
28509
|
-
fixNote: reason === "not_shipped" ? "No longer applies: the package is only a build for platforms the repository does not deploy to. Nothing to do." : reason === "license_approved" ? "No longer applies: its license is on the organization's approved list. Nothing to do." : reason === "license_undecided" ? "No longer applies: its license can no longer be judged against the list (some of what it can stand for is approved). Nothing to do." : reason === "superseded" ? "Replaced by the repository's finding of its license, which lists every package under it. Nothing to do here." : "Resolved: the sweep no longer reports it. Nothing to do."
|
|
28795
|
+
fixNote: reason === "not_shipped" ? "No longer applies: the package is only a build for platforms the repository does not deploy to. Nothing to do." : reason === "license_approved" ? "No longer applies: its license is on the organization's approved list. Nothing to do." : reason === "license_undecided" ? "No longer applies: its license can no longer be judged against the list (some of what it can stand for is approved). Nothing to do." : reason === "superseded" ? "Replaced by the repository's finding of its license, which lists every package under it. Nothing to do here." : reason === "license_not_judged" ? "No longer applies: an OS package's license is judged only when it restricts use. Its packages keep it. Nothing to do." : "Resolved: the sweep no longer reports it. Nothing to do."
|
|
28510
28796
|
};
|
|
28511
28797
|
}
|
|
28512
28798
|
if (row["kind"] === "license_violation" && row["replaceable"] === true) return {
|
|
@@ -28545,7 +28831,30 @@ function withFixability(row) {
|
|
|
28545
28831
|
fixable: true,
|
|
28546
28832
|
fixNote: "A malicious package: taiga_fix_finding removes it (or replaces it), with every advisory on that version."
|
|
28547
28833
|
} : row;
|
|
28548
|
-
|
|
28834
|
+
const held = row["autoFixHeld"];
|
|
28835
|
+
const inBase = row["baseImageFix"] != null || typeof row["baseMove"] === "boolean";
|
|
28836
|
+
if (row["status"] === "open" && !inBase && held && isPinBlocked({ autoFixHeld: held })) {
|
|
28837
|
+
const what = held.blockingPackage ?? "another dependency";
|
|
28838
|
+
return {
|
|
28839
|
+
...row,
|
|
28840
|
+
fixable: false,
|
|
28841
|
+
fixNote: `Waiting on ${what}${held.blockingConstraint ? `, which requires ${held.blockingConstraint}` : ""}. taiga_fix_finding refuses it until that moves.`
|
|
28842
|
+
};
|
|
28843
|
+
}
|
|
28844
|
+
const base = row["baseImageFix"];
|
|
28845
|
+
if (base && base.way !== "move" && isAgentRemediable({ remediableBy: remediableByOf(row) })) {
|
|
28846
|
+
if (base.way === "upgrade") return row["status"] === "open" ? {
|
|
28847
|
+
...row,
|
|
28848
|
+
fixable: true,
|
|
28849
|
+
fixNote: "taiga_fix_finding adds a temporary line to the Dockerfile that upgrades this package over its base, until the base publishes a build with the fix."
|
|
28850
|
+
} : row;
|
|
28851
|
+
return {
|
|
28852
|
+
...row,
|
|
28853
|
+
fixable: false,
|
|
28854
|
+
fixNote: baseImageWaitNote(base)
|
|
28855
|
+
};
|
|
28856
|
+
}
|
|
28857
|
+
if (typeof row["baseMove"] === "boolean" && isAgentRemediable({ remediableBy: remediableByOf(row) })) return row["baseMove"] === true && row["status"] === "open" ? {
|
|
28549
28858
|
...row,
|
|
28550
28859
|
fixable: true,
|
|
28551
28860
|
fixNote: "taiga_fix_finding moves the base images it is in to the builds their tags name now, the FROM line alone, with every other advisory that move removes."
|
|
@@ -28615,6 +28924,14 @@ function withResolutionLabel(row) {
|
|
|
28615
28924
|
previouslyResolvedReason: resolvedReason
|
|
28616
28925
|
};
|
|
28617
28926
|
}
|
|
28927
|
+
/** Why a base image's finding has no Fix, in the page's words (`maintaining_base_wait_*`). */
|
|
28928
|
+
function baseImageWaitNote(fix) {
|
|
28929
|
+
if (fix.way === "wait_for_distro") return `${fix.distro} has no fix for this yet.`;
|
|
28930
|
+
if (fix.way === "end_of_life") return `${fix.distro} has reached its end of life, so upgrading this one package is no fix. It clears when the base moves to a supported release.`;
|
|
28931
|
+
const image = fix.images.join(", ") || "The base image";
|
|
28932
|
+
return `${fix.distro} has fixed this, but ${image} has not published a build with the fix yet. It clears when it does.`;
|
|
28933
|
+
}
|
|
28934
|
+
const remediableByOf = (row) => typeof row["remediableBy"] === "string" ? row["remediableBy"] : null;
|
|
28618
28935
|
/** A finding as a tool answers it: the row fields, the scope, and whether Fix would take it. */
|
|
28619
28936
|
function findingRows(findings, extra = []) {
|
|
28620
28937
|
return pickFields(findings, [
|
|
@@ -30602,10 +30919,11 @@ function runOutcome(run) {
|
|
|
30602
30919
|
const why = errorSaid(run["error"]) ?? (typeof run["failedReason"] === "string" ? run["failedReason"] : null);
|
|
30603
30920
|
const handback = handbackSaid(run["reviewEscalation"]);
|
|
30604
30921
|
const draft = run["prDraft"] === true ? `, still a draft` : "";
|
|
30922
|
+
const blocked = reasonOnOneLine(run["factoryBlockedBecause"]);
|
|
30605
30923
|
return {
|
|
30606
30924
|
disposition,
|
|
30607
30925
|
outcome: {
|
|
30608
|
-
in_flight: status === "pending" ? "Queued: waiting to start." : status === "replanning" ? steerPaused(run["failedReason"], progress) : `Running: ${RUNNING[status] ?? status}${progress}.`,
|
|
30926
|
+
in_flight: blocked ? `Blocked: the factory has stopped working on this run${progress}. ${blocked}` : status === "pending" ? "Queued: waiting to start." : status === "replanning" ? steerPaused(run["failedReason"], progress) : `Running: ${RUNNING[status] ?? status}${progress}.`,
|
|
30609
30927
|
gated: handback ? `Handed back to a person: ${handback}. ${pr}${draft ? `${draft},` : ""} waits for them to ${handbackNextStep(run["reviewEscalation"], run["provider"])}.` : `Waiting for a person to review and merge ${pr}${draft}.`,
|
|
30610
30928
|
succeeded: `Merged: ${pr} is in ${typeof run["baseBranch"] === "string" ? run["baseBranch"] : "the base branch"}.`,
|
|
30611
30929
|
unmerged: typeof run["prNumber"] === "number" || run["prUrl"] ? `Settled without merging: ${pr} was left unmerged.` : "Settled without a merged pull request.",
|
|
@@ -30629,12 +30947,12 @@ function steerPaused(reason, progress) {
|
|
|
30629
30947
|
*/
|
|
30630
30948
|
function replanHandedBack(reason, error, progress) {
|
|
30631
30949
|
if (reason !== "replan_refused" && reason !== "replan_failed") return null;
|
|
30632
|
-
const why =
|
|
30950
|
+
const why = reasonOnOneLine(error);
|
|
30633
30951
|
if (reason === "replan_refused") return `Stopped${progress}, handed back: the planner would not plan the request for changes${why ? `: ${why}` : "."} Resume continues the original plan.`;
|
|
30634
30952
|
return `Stopped${progress}, handed back: ${why ?? "the plan could not be revised."} Resume continues the original plan.`;
|
|
30635
30953
|
}
|
|
30636
30954
|
/** A hand-back's reason on one line, ending as a sentence, capped for a row. */
|
|
30637
|
-
function
|
|
30955
|
+
function reasonOnOneLine(error) {
|
|
30638
30956
|
if (typeof error !== "string") return null;
|
|
30639
30957
|
const text = error.replace(/\s+/g, " ").trim();
|
|
30640
30958
|
if (!text) return null;
|
|
@@ -30720,7 +31038,7 @@ const FAILED_REASON_MEANS = {
|
|
|
30720
31038
|
* text out: its first sentence is in the outcome, and taiga_get_run has it all.
|
|
30721
31039
|
*/
|
|
30722
31040
|
function readableRun(run, opts = {}) {
|
|
30723
|
-
const { prDraft, error, reviewEscalation, runtime: _runtime, origin, ...rest } = run;
|
|
31041
|
+
const { prDraft, error, reviewEscalation, runtime: _runtime, origin, factoryBlockedBecause: _inTheOutcome, ...rest } = run;
|
|
30724
31042
|
const said = runOutcome(run);
|
|
30725
31043
|
const means = FAILED_REASON_MEANS[String(run["failedReason"])];
|
|
30726
31044
|
const hardening = run["hardeningResult"];
|
|
@@ -31085,6 +31403,7 @@ function registerBuildTools(server, client) {
|
|
|
31085
31403
|
}
|
|
31086
31404
|
/** What happened to a request that steers a run (PRO-3161), in one sentence. */
|
|
31087
31405
|
function steerSituation(steer) {
|
|
31406
|
+
if (steer === "sent") return "The run takes it as an instruction while it keeps working.";
|
|
31088
31407
|
if (steer === "replanning") return "The run has paused and its plan is being revised for the request.";
|
|
31089
31408
|
if (steer === "after_step") return "The run stops when the step it is building ends, then its plan is revised.";
|
|
31090
31409
|
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.";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taiga-ai/mcp-server",
|
|
3
|
-
"version": "0.36.0-rc.
|
|
3
|
+
"version": "0.36.0-rc.926",
|
|
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",
|