@mycompbox/compbox-mcp 1.20.0 → 1.21.1

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/index.js +953 -1
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -178,6 +178,34 @@ var init_organization = __esm({
178
178
  }
179
179
  });
180
180
 
181
+ // ../shared/dist/types/github.js
182
+ var init_github = __esm({
183
+ "../shared/dist/types/github.js"() {
184
+ "use strict";
185
+ }
186
+ });
187
+
188
+ // ../shared/dist/types/cloud.js
189
+ var init_cloud = __esm({
190
+ "../shared/dist/types/cloud.js"() {
191
+ "use strict";
192
+ }
193
+ });
194
+
195
+ // ../shared/dist/types/stack.js
196
+ var init_stack = __esm({
197
+ "../shared/dist/types/stack.js"() {
198
+ "use strict";
199
+ }
200
+ });
201
+
202
+ // ../shared/dist/types/deployment.js
203
+ var init_deployment = __esm({
204
+ "../shared/dist/types/deployment.js"() {
205
+ "use strict";
206
+ }
207
+ });
208
+
181
209
  // ../shared/dist/types/index.js
182
210
  var init_types = __esm({
183
211
  "../shared/dist/types/index.js"() {
@@ -190,6 +218,10 @@ var init_types = __esm({
190
218
  init_interview();
191
219
  init_attachment();
192
220
  init_organization();
221
+ init_github();
222
+ init_cloud();
223
+ init_stack();
224
+ init_deployment();
193
225
  }
194
226
  });
195
227
 
@@ -1050,14 +1082,898 @@ var init_interview_conversation = __esm({
1050
1082
  }
1051
1083
  });
1052
1084
 
1085
+ // ../shared/dist/cloud-setup.js
1086
+ function isGcpProjectId(value) {
1087
+ return PROJECT_ID.test(value);
1088
+ }
1089
+ function isGcpProjectNumber(value) {
1090
+ return PROJECT_NUMBER.test(value);
1091
+ }
1092
+ function isGcpRegion(value) {
1093
+ return GCP_REGIONS.includes(value);
1094
+ }
1095
+ function isGitHubLogin(value) {
1096
+ return GITHUB_LOGIN.test(value);
1097
+ }
1098
+ function gcpServiceAccountEmail(projectId) {
1099
+ return `${GCP_DEPLOY_ACCOUNT}@${projectId}.iam.gserviceaccount.com`;
1100
+ }
1101
+ function gcpWorkloadProvider(projectNumber) {
1102
+ return `projects/${projectNumber}/locations/global/workloadIdentityPools/${GCP_IDENTITY_POOL}/providers/${GCP_IDENTITY_PROVIDER}`;
1103
+ }
1104
+ function gcpStateBucket(projectId) {
1105
+ return `${projectId}-compbox-tfstate`;
1106
+ }
1107
+ function buildGcpSetupScript(input) {
1108
+ if (!isGcpProjectId(input.projectId))
1109
+ throw new Error("Not a Google Cloud project ID.");
1110
+ if (!isGcpRegion(input.region))
1111
+ throw new Error("Not a supported region.");
1112
+ if (input.githubOwners.length === 0)
1113
+ throw new Error("Connect GitHub first.");
1114
+ for (const owner of input.githubOwners) {
1115
+ if (!isGitHubLogin(owner))
1116
+ throw new Error(`Not a GitHub account name: ${owner}`);
1117
+ }
1118
+ const owners = [...new Set(input.githubOwners)];
1119
+ const condition = `assertion.repository_owner in [${owners.map((o) => `'${o}'`).join(", ")}]`;
1120
+ const pool = `--location=global --workload-identity-pool=${GCP_IDENTITY_POOL}`;
1121
+ const oidc = [
1122
+ "--issuer-uri=https://token.actions.githubusercontent.com",
1123
+ '--attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository,attribute.repository_owner=assertion.repository_owner"',
1124
+ `--attribute-condition="${condition}"`
1125
+ ].join(" ");
1126
+ return `# CompBox \u2192 Google Cloud (keyless). Paste into Google Cloud Shell.
1127
+ set -euo pipefail
1128
+ PROJECT=${input.projectId}
1129
+ REGION=${input.region}
1130
+ SA=${gcpServiceAccountEmail(input.projectId)}
1131
+
1132
+ gcloud config set project "$PROJECT"
1133
+ gcloud services enable run.googleapis.com artifactregistry.googleapis.com iam.googleapis.com \\
1134
+ iamcredentials.googleapis.com sts.googleapis.com cloudresourcemanager.googleapis.com
1135
+ NUMBER=$(gcloud projects describe "$PROJECT" --format='value(projectNumber)')
1136
+
1137
+ # The account deploys run as.
1138
+ gcloud iam service-accounts describe "$SA" >/dev/null 2>&1 || \\
1139
+ gcloud iam service-accounts create ${GCP_DEPLOY_ACCOUNT} --display-name="CompBox deploys"
1140
+ for ROLE in ${GCP_DEPLOY_ROLES.join(" ")}; do
1141
+ gcloud projects add-iam-policy-binding "$PROJECT" --member="serviceAccount:$SA" --role="$ROLE" --condition=None --quiet >/dev/null
1142
+ done
1143
+
1144
+ # Trust GitHub Actions from your GitHub only: ${owners.join(", ")}.
1145
+ gcloud iam workload-identity-pools describe ${GCP_IDENTITY_POOL} --location=global >/dev/null 2>&1 || \\
1146
+ gcloud iam workload-identity-pools create ${GCP_IDENTITY_POOL} --location=global --display-name="CompBox"
1147
+ if gcloud iam workload-identity-pools providers describe ${GCP_IDENTITY_PROVIDER} ${pool} >/dev/null 2>&1; then
1148
+ gcloud iam workload-identity-pools providers update-oidc ${GCP_IDENTITY_PROVIDER} ${pool} ${oidc}
1149
+ else
1150
+ gcloud iam workload-identity-pools providers create-oidc ${GCP_IDENTITY_PROVIDER} ${pool} ${oidc}
1151
+ fi
1152
+ for OWNER in ${owners.join(" ")}; do
1153
+ gcloud iam service-accounts add-iam-policy-binding "$SA" --role=roles/iam.workloadIdentityUser --quiet >/dev/null \\
1154
+ --member="principalSet://iam.googleapis.com/projects/$NUMBER/locations/global/workloadIdentityPools/${GCP_IDENTITY_POOL}/attribute.repository_owner/$OWNER"
1155
+ done
1156
+
1157
+ # Where each project's infrastructure state is kept.
1158
+ gcloud storage buckets describe "gs://${gcpStateBucket(input.projectId)}" >/dev/null 2>&1 || \\
1159
+ gcloud storage buckets create "gs://${gcpStateBucket(input.projectId)}" --location="$REGION" --uniform-bucket-level-access
1160
+
1161
+ echo
1162
+ echo "Done. Your project number is: $NUMBER"
1163
+ echo "Paste it into CompBox to finish."
1164
+ `;
1165
+ }
1166
+ var GCP_REGIONS, GCP_DEPLOY_ACCOUNT, GCP_IDENTITY_POOL, GCP_IDENTITY_PROVIDER, GCP_DEPLOY_ROLES, PROJECT_ID, PROJECT_NUMBER, GITHUB_LOGIN, GCP_CONNECT_STEPS, GCP_CONNECT_STEP_LABELS;
1167
+ var init_cloud_setup = __esm({
1168
+ "../shared/dist/cloud-setup.js"() {
1169
+ "use strict";
1170
+ GCP_REGIONS = [
1171
+ "us-central1",
1172
+ "us-east1",
1173
+ "us-east4",
1174
+ "us-west1",
1175
+ "us-west2",
1176
+ "northamerica-northeast1",
1177
+ "europe-west1",
1178
+ "europe-west2",
1179
+ "europe-west3",
1180
+ "europe-west4",
1181
+ "asia-south1",
1182
+ "asia-southeast1",
1183
+ "asia-northeast1",
1184
+ "australia-southeast1"
1185
+ ];
1186
+ GCP_DEPLOY_ACCOUNT = "compbox-deploy";
1187
+ GCP_IDENTITY_POOL = "compbox";
1188
+ GCP_IDENTITY_PROVIDER = "github";
1189
+ GCP_DEPLOY_ROLES = [
1190
+ "roles/run.admin",
1191
+ "roles/artifactregistry.admin",
1192
+ "roles/iam.serviceAccountUser",
1193
+ "roles/iam.serviceAccountAdmin",
1194
+ "roles/storage.admin",
1195
+ "roles/serviceusage.serviceUsageConsumer"
1196
+ ];
1197
+ PROJECT_ID = /^[a-z][a-z0-9-]{4,28}[a-z0-9]$/;
1198
+ PROJECT_NUMBER = /^\d{6,20}$/;
1199
+ GITHUB_LOGIN = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/;
1200
+ GCP_CONNECT_STEPS = ["project", "services", "account", "identity", "trust", "storage"];
1201
+ GCP_CONNECT_STEP_LABELS = {
1202
+ project: "Checking your project",
1203
+ services: "Turning on Google Cloud services",
1204
+ account: "Creating the deploy account",
1205
+ identity: "Trusting your GitHub",
1206
+ trust: "Letting your GitHub deploy",
1207
+ storage: "Making a place for deploy state"
1208
+ };
1209
+ }
1210
+ });
1211
+
1212
+ // ../shared/dist/cloud-connect.js
1213
+ function isAwsAccountId(value) {
1214
+ return AWS_ACCOUNT.test(value);
1215
+ }
1216
+ function isAwsRegion(value) {
1217
+ return AWS_REGION.test(value);
1218
+ }
1219
+ function isAwsRoleArn(value) {
1220
+ return AWS_ROLE_ARN.test(value);
1221
+ }
1222
+ function isS3BucketName(value) {
1223
+ return S3_BUCKET.test(value);
1224
+ }
1225
+ function buildAwsConnectTemplate() {
1226
+ const sub = (s) => ({ "Fn::Sub": s });
1227
+ return {
1228
+ AWSTemplateFormatVersion: "2010-09-09",
1229
+ Description: "CompBox keyless deploys: GitHub Actions from your GitHub accounts deploy as a role. No keys are stored.",
1230
+ Parameters: {
1231
+ GitHubOwners: { Type: "CommaDelimitedList", Description: "GitHub accounts whose Actions may deploy." },
1232
+ CompBoxConnectUrl: { Type: "String", Description: "Where the stack tells CompBox it's done." },
1233
+ CompBoxConnectToken: { Type: "String", NoEcho: true, Description: "One-time link from CompBox." }
1234
+ },
1235
+ Resources: {
1236
+ SetupFunctionRole: {
1237
+ Type: "AWS::IAM::Role",
1238
+ Properties: {
1239
+ AssumeRolePolicyDocument: {
1240
+ Version: "2012-10-17",
1241
+ Statement: [{ Effect: "Allow", Principal: { Service: "lambda.amazonaws.com" }, Action: "sts:AssumeRole" }]
1242
+ },
1243
+ ManagedPolicyArns: [sub("arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole")],
1244
+ Policies: [
1245
+ {
1246
+ PolicyName: "github-oidc",
1247
+ PolicyDocument: {
1248
+ Version: "2012-10-17",
1249
+ Statement: [
1250
+ {
1251
+ Effect: "Allow",
1252
+ Action: [
1253
+ "iam:ListOpenIDConnectProviders",
1254
+ "iam:GetOpenIDConnectProvider",
1255
+ "iam:CreateOpenIDConnectProvider",
1256
+ "iam:AddClientIDToOpenIDConnectProvider"
1257
+ ],
1258
+ Resource: "*"
1259
+ }
1260
+ ]
1261
+ }
1262
+ }
1263
+ ]
1264
+ }
1265
+ },
1266
+ SetupFunction: {
1267
+ Type: "AWS::Lambda::Function",
1268
+ Properties: {
1269
+ Runtime: "python3.12",
1270
+ Handler: "index.handler",
1271
+ Timeout: 60,
1272
+ Role: { "Fn::GetAtt": ["SetupFunctionRole", "Arn"] },
1273
+ Code: { ZipFile: AWS_SETUP_FUNCTION }
1274
+ }
1275
+ },
1276
+ GitHubOidc: {
1277
+ Type: "Custom::GitHubOidc",
1278
+ Properties: { ServiceToken: { "Fn::GetAtt": ["SetupFunction", "Arn"] }, Action: "oidc" }
1279
+ },
1280
+ StateBucket: {
1281
+ Type: "AWS::S3::Bucket",
1282
+ DeletionPolicy: "Retain",
1283
+ UpdateReplacePolicy: "Retain",
1284
+ Properties: {
1285
+ VersioningConfiguration: { Status: "Enabled" },
1286
+ PublicAccessBlockConfiguration: {
1287
+ BlockPublicAcls: true,
1288
+ BlockPublicPolicy: true,
1289
+ IgnorePublicAcls: true,
1290
+ RestrictPublicBuckets: true
1291
+ },
1292
+ BucketEncryption: { ServerSideEncryptionConfiguration: [{ ServerSideEncryptionByDefault: { SSEAlgorithm: "AES256" } }] }
1293
+ }
1294
+ },
1295
+ DeployRole: {
1296
+ Type: "AWS::IAM::Role",
1297
+ Properties: {
1298
+ Description: "CompBox deploys (GitHub Actions, keyless)",
1299
+ AssumeRolePolicyDocument: {
1300
+ Version: "2012-10-17",
1301
+ Statement: [
1302
+ {
1303
+ Effect: "Allow",
1304
+ Principal: { Federated: { "Fn::GetAtt": ["GitHubOidc", "Arn"] } },
1305
+ Action: "sts:AssumeRoleWithWebIdentity",
1306
+ Condition: {
1307
+ StringEquals: { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" },
1308
+ // repo:<owner>/* for every owner.
1309
+ StringLike: {
1310
+ "token.actions.githubusercontent.com:sub": {
1311
+ "Fn::Split": [",", { "Fn::Sub": ["repo:${Owners}/*", { Owners: { "Fn::Join": ["/*,repo:", { Ref: "GitHubOwners" }] } }] }]
1312
+ }
1313
+ }
1314
+ }
1315
+ }
1316
+ ]
1317
+ },
1318
+ ManagedPolicyArns: [
1319
+ sub("arn:${AWS::Partition}:iam::aws:policy/AWSAppRunnerFullAccess"),
1320
+ sub("arn:${AWS::Partition}:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser")
1321
+ ],
1322
+ Policies: [
1323
+ {
1324
+ PolicyName: "compbox-deploy",
1325
+ PolicyDocument: {
1326
+ Version: "2012-10-17",
1327
+ Statement: [
1328
+ {
1329
+ Sid: "State",
1330
+ Effect: "Allow",
1331
+ Action: ["s3:ListBucket", "s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
1332
+ Resource: [{ "Fn::GetAtt": ["StateBucket", "Arn"] }, sub("${StateBucket.Arn}/*")]
1333
+ },
1334
+ {
1335
+ Sid: "AppRoles",
1336
+ Effect: "Allow",
1337
+ Action: [
1338
+ "iam:GetRole",
1339
+ "iam:PassRole",
1340
+ "iam:CreateRole",
1341
+ "iam:DeleteRole",
1342
+ "iam:TagRole",
1343
+ "iam:AttachRolePolicy",
1344
+ "iam:DetachRolePolicy",
1345
+ "iam:PutRolePolicy",
1346
+ "iam:DeleteRolePolicy",
1347
+ "iam:ListAttachedRolePolicies",
1348
+ "iam:ListRolePolicies",
1349
+ "iam:GetRolePolicy"
1350
+ ],
1351
+ Resource: sub("arn:${AWS::Partition}:iam::${AWS::AccountId}:role/compbox-*")
1352
+ }
1353
+ ]
1354
+ }
1355
+ }
1356
+ ]
1357
+ }
1358
+ },
1359
+ Connect: {
1360
+ Type: "Custom::CompBoxConnect",
1361
+ Properties: {
1362
+ ServiceToken: { "Fn::GetAtt": ["SetupFunction", "Arn"] },
1363
+ Action: "notify",
1364
+ Url: { Ref: "CompBoxConnectUrl" },
1365
+ Token: { Ref: "CompBoxConnectToken" },
1366
+ AccountId: { Ref: "AWS::AccountId" },
1367
+ Region: { Ref: "AWS::Region" },
1368
+ RoleArn: { "Fn::GetAtt": ["DeployRole", "Arn"] },
1369
+ Bucket: { Ref: "StateBucket" },
1370
+ // Re-tell CompBox when the GitHub accounts change.
1371
+ Owners: { "Fn::Join": [",", { Ref: "GitHubOwners" }] }
1372
+ }
1373
+ }
1374
+ },
1375
+ Outputs: {
1376
+ DeployRoleArn: { Value: { "Fn::GetAtt": ["DeployRole", "Arn"] } },
1377
+ StateBucket: { Value: { Ref: "StateBucket" } }
1378
+ }
1379
+ };
1380
+ }
1381
+ function awsQuickCreateUrl(input) {
1382
+ if (!isAwsRegion(input.region))
1383
+ throw new Error("Not an AWS region.");
1384
+ const owners = uniqueOwners(input.githubOwners);
1385
+ const params = new URLSearchParams({
1386
+ templateURL: input.templateUrl,
1387
+ stackName: "CompBox",
1388
+ param_GitHubOwners: owners.join(","),
1389
+ param_CompBoxConnectUrl: input.connectUrl,
1390
+ param_CompBoxConnectToken: input.connectToken
1391
+ });
1392
+ return `https://${input.region}.console.aws.amazon.com/cloudformation/home?region=${input.region}#/stacks/quickcreate?${params.toString()}`;
1393
+ }
1394
+ function isAzureGuid(value) {
1395
+ return GUID.test(value);
1396
+ }
1397
+ function isAzureResourceGroup(value) {
1398
+ return RESOURCE_GROUP.test(value);
1399
+ }
1400
+ function isAzureLocation(value) {
1401
+ return AZURE_LOCATION.test(value);
1402
+ }
1403
+ function isAzureStorageAccount(value) {
1404
+ return STORAGE_ACCOUNT.test(value);
1405
+ }
1406
+ function azureGitHubSubject(owner) {
1407
+ return `repository_owner:${owner}`;
1408
+ }
1409
+ function buildAzureConnectTemplate(input) {
1410
+ const owners = uniqueOwners(input.githubOwners);
1411
+ const identityId = `[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', '${AZURE_DEPLOY_IDENTITY}')]`;
1412
+ const identityRef = `reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', '${AZURE_DEPLOY_IDENTITY}'), '2023-01-31')`;
1413
+ return {
1414
+ $schema: "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
1415
+ contentVersion: "1.0.0.0",
1416
+ metadata: { description: "CompBox keyless deploys: GitHub Actions from your GitHub accounts deploy as a managed identity." },
1417
+ parameters: {
1418
+ location: { type: "string", defaultValue: "[resourceGroup().location]" },
1419
+ githubOwners: { type: "array", defaultValue: owners },
1420
+ connectUrl: { type: "string", defaultValue: input.connectUrl }
1421
+ },
1422
+ variables: {
1423
+ storageName: "[concat('cbstate', uniqueString(resourceGroup().id))]"
1424
+ },
1425
+ resources: [
1426
+ {
1427
+ type: "Microsoft.ManagedIdentity/userAssignedIdentities",
1428
+ apiVersion: "2023-01-31",
1429
+ name: AZURE_DEPLOY_IDENTITY,
1430
+ location: "[parameters('location')]"
1431
+ },
1432
+ {
1433
+ type: "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials",
1434
+ apiVersion: "2023-01-31",
1435
+ name: `[concat('${AZURE_DEPLOY_IDENTITY}/github-', parameters('githubOwners')[copyIndex()])]`,
1436
+ // Azure rejects concurrent writes to one identity's credentials.
1437
+ copy: { name: "owners", count: "[length(parameters('githubOwners'))]", mode: "Serial", batchSize: 1 },
1438
+ dependsOn: [identityId],
1439
+ properties: {
1440
+ issuer: "https://token.actions.githubusercontent.com",
1441
+ subject: "[concat('repository_owner:', parameters('githubOwners')[copyIndex()])]",
1442
+ audiences: ["api://AzureADTokenExchange"]
1443
+ }
1444
+ },
1445
+ {
1446
+ type: "Microsoft.Authorization/roleAssignments",
1447
+ apiVersion: "2022-04-01",
1448
+ name: `[guid(resourceGroup().id, '${AZURE_DEPLOY_IDENTITY}', 'contributor')]`,
1449
+ dependsOn: [identityId],
1450
+ properties: {
1451
+ roleDefinitionId: `[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '${AZURE_CONTRIBUTOR}')]`,
1452
+ principalId: `[${identityRef}.principalId]`,
1453
+ principalType: "ServicePrincipal"
1454
+ }
1455
+ },
1456
+ {
1457
+ type: "Microsoft.Storage/storageAccounts",
1458
+ apiVersion: "2023-01-01",
1459
+ name: "[variables('storageName')]",
1460
+ location: "[parameters('location')]",
1461
+ sku: { name: "Standard_LRS" },
1462
+ kind: "StorageV2",
1463
+ properties: { minimumTlsVersion: "TLS1_2", allowBlobPublicAccess: false, supportsHttpsTrafficOnly: true }
1464
+ },
1465
+ {
1466
+ type: "Microsoft.Storage/storageAccounts/blobServices/containers",
1467
+ apiVersion: "2023-01-01",
1468
+ name: "[concat(variables('storageName'), '/default/tfstate')]",
1469
+ dependsOn: ["[resourceId('Microsoft.Storage/storageAccounts', variables('storageName'))]"]
1470
+ },
1471
+ {
1472
+ type: "Microsoft.Authorization/roleAssignments",
1473
+ apiVersion: "2022-04-01",
1474
+ name: `[guid(resourceGroup().id, '${AZURE_DEPLOY_IDENTITY}', 'state')]`,
1475
+ scope: "[concat('Microsoft.Storage/storageAccounts/', variables('storageName'))]",
1476
+ dependsOn: [identityId, "[resourceId('Microsoft.Storage/storageAccounts', variables('storageName'))]"],
1477
+ properties: {
1478
+ roleDefinitionId: `[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '${AZURE_BLOB_DATA_CONTRIBUTOR}')]`,
1479
+ principalId: `[${identityRef}.principalId]`,
1480
+ principalType: "ServicePrincipal"
1481
+ }
1482
+ },
1483
+ {
1484
+ type: "Microsoft.Resources/deployments",
1485
+ apiVersion: "2022-09-01",
1486
+ name: "compbox-connect",
1487
+ dependsOn: [
1488
+ "owners",
1489
+ `[resourceId('Microsoft.Authorization/roleAssignments', guid(resourceGroup().id, '${AZURE_DEPLOY_IDENTITY}', 'contributor'))]`,
1490
+ "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', variables('storageName'), 'default', 'tfstate')]"
1491
+ ],
1492
+ properties: {
1493
+ mode: "Incremental",
1494
+ templateLink: {
1495
+ uri: `[format('{0}&subscriptionId={1}&tenantId={2}&resourceGroup={3}&location={4}&clientId={5}&storageAccount={6}', parameters('connectUrl'), subscription().subscriptionId, subscription().tenantId, uriComponent(resourceGroup().name), uriComponent(parameters('location')), ${identityRef}.clientId, variables('storageName'))]`
1496
+ }
1497
+ }
1498
+ }
1499
+ ],
1500
+ outputs: {
1501
+ clientId: { type: "string", value: `[${identityRef}.clientId]` },
1502
+ storageAccount: { type: "string", value: "[variables('storageName')]" }
1503
+ }
1504
+ };
1505
+ }
1506
+ function azureDeployUrl(templateUrl) {
1507
+ return `https://portal.azure.com/#create/Microsoft.Template/uri/${encodeURIComponent(templateUrl)}`;
1508
+ }
1509
+ function uniqueOwners(owners) {
1510
+ if (owners.length === 0)
1511
+ throw new Error("Connect GitHub first.");
1512
+ for (const owner of owners) {
1513
+ if (!isGitHubLogin(owner))
1514
+ throw new Error(`Not a GitHub account name: ${owner}`);
1515
+ }
1516
+ return [...new Set(owners)];
1517
+ }
1518
+ var AWS_REGIONS, AWS_ACCOUNT, AWS_REGION, AWS_ROLE_ARN, S3_BUCKET, GITHUB_OIDC_THUMBPRINTS, AWS_SETUP_FUNCTION, GUID, RESOURCE_GROUP, AZURE_LOCATION, STORAGE_ACCOUNT, AZURE_DEPLOY_IDENTITY, AZURE_CONTRIBUTOR, AZURE_BLOB_DATA_CONTRIBUTOR, EMPTY_ARM_TEMPLATE;
1519
+ var init_cloud_connect = __esm({
1520
+ "../shared/dist/cloud-connect.js"() {
1521
+ "use strict";
1522
+ init_cloud_setup();
1523
+ AWS_REGIONS = [
1524
+ "us-east-1",
1525
+ "us-east-2",
1526
+ "us-west-2",
1527
+ "ca-central-1",
1528
+ "eu-west-1",
1529
+ "eu-west-2",
1530
+ "eu-central-1",
1531
+ "ap-south-1",
1532
+ "ap-southeast-1",
1533
+ "ap-southeast-2",
1534
+ "ap-northeast-1"
1535
+ ];
1536
+ AWS_ACCOUNT = /^\d{12}$/;
1537
+ AWS_REGION = /^[a-z]{2}(?:-gov)?-[a-z]+-\d$/;
1538
+ AWS_ROLE_ARN = /^arn:aws[a-z-]*:iam::\d{12}:role\/[\w+=,.@/-]{1,512}$/;
1539
+ S3_BUCKET = /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;
1540
+ GITHUB_OIDC_THUMBPRINTS = ["6938fd4d98bab03faadb97b34396831e3780aea1", "1c58a3a8518e8759bf075b76b750d4f2df264fcd"];
1541
+ AWS_SETUP_FUNCTION = `import json, urllib.error, urllib.request
1542
+ import boto3
1543
+
1544
+ ISSUER = "token.actions.githubusercontent.com"
1545
+
1546
+
1547
+ def respond(event, ok, data=None, reason=""):
1548
+ body = json.dumps({
1549
+ "Status": "SUCCESS" if ok else "FAILED",
1550
+ "Reason": (reason or "See the function's CloudWatch logs")[:1000],
1551
+ "PhysicalResourceId": event.get("PhysicalResourceId") or event["LogicalResourceId"],
1552
+ "StackId": event["StackId"],
1553
+ "RequestId": event["RequestId"],
1554
+ "LogicalResourceId": event["LogicalResourceId"],
1555
+ "Data": data or {},
1556
+ }).encode()
1557
+ req = urllib.request.Request(event["ResponseURL"], data=body, method="PUT", headers={"Content-Type": ""})
1558
+ urllib.request.urlopen(req, timeout=30)
1559
+
1560
+
1561
+ def github_oidc():
1562
+ iam = boto3.client("iam")
1563
+ for p in iam.list_open_id_connect_providers()["OpenIDConnectProviderList"]:
1564
+ arn = p["Arn"]
1565
+ if arn.endswith("/" + ISSUER):
1566
+ if "sts.amazonaws.com" not in iam.get_open_id_connect_provider(OpenIDConnectProviderArn=arn)["ClientIDList"]:
1567
+ iam.add_client_id_to_open_id_connect_provider(OpenIDConnectProviderArn=arn, ClientID="sts.amazonaws.com")
1568
+ return arn
1569
+ return iam.create_open_id_connect_provider(
1570
+ Url="https://" + ISSUER, ClientIDList=["sts.amazonaws.com"], ThumbprintList=${JSON.stringify(GITHUB_OIDC_THUMBPRINTS)}
1571
+ )["OpenIDConnectProviderArn"]
1572
+
1573
+
1574
+ def notify(p):
1575
+ body = json.dumps({
1576
+ "token": p["Token"], "accountId": p["AccountId"], "region": p["Region"],
1577
+ "roleArn": p["RoleArn"], "stateBucket": p["Bucket"],
1578
+ }).encode()
1579
+ req = urllib.request.Request(p["Url"], data=body, method="POST", headers={"Content-Type": "application/json"})
1580
+ try:
1581
+ urllib.request.urlopen(req, timeout=30)
1582
+ except urllib.error.HTTPError as e:
1583
+ raise RuntimeError("CompBox said: " + e.read().decode(errors="replace")[:500])
1584
+
1585
+
1586
+ def handler(event, context):
1587
+ try:
1588
+ props = event["ResourceProperties"]
1589
+ if event["RequestType"] == "Delete":
1590
+ return respond(event, True)
1591
+ if props["Action"] == "oidc":
1592
+ return respond(event, True, {"Arn": github_oidc()})
1593
+ try:
1594
+ notify(props)
1595
+ except Exception:
1596
+ # The connect link expires; a later stack update shouldn't fail on it.
1597
+ if event["RequestType"] != "Update":
1598
+ raise
1599
+ respond(event, True)
1600
+ except Exception as e:
1601
+ print(e)
1602
+ respond(event, False, reason=str(e))
1603
+ `;
1604
+ GUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1605
+ RESOURCE_GROUP = /^[-\w.()]{0,89}[-\w()]$/;
1606
+ AZURE_LOCATION = /^[a-z0-9]{2,40}$/;
1607
+ STORAGE_ACCOUNT = /^[a-z0-9]{3,24}$/;
1608
+ AZURE_DEPLOY_IDENTITY = "compbox-deploy";
1609
+ AZURE_CONTRIBUTOR = "b24988ac-6180-42a0-ab88-20f7382dd24c";
1610
+ AZURE_BLOB_DATA_CONTRIBUTOR = "ba92f5b4-2d11-453d-a403-e96b0029c9fe";
1611
+ EMPTY_ARM_TEMPLATE = {
1612
+ $schema: "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
1613
+ contentVersion: "1.0.0.0",
1614
+ resources: []
1615
+ };
1616
+ }
1617
+ });
1618
+
1619
+ // ../shared/dist/stack-files.js
1620
+ function stackEnvironments(tier) {
1621
+ return STACK_TIERS[tier].environments;
1622
+ }
1623
+ function deployRunTitle(environment) {
1624
+ return `Deploy to ${environment}`;
1625
+ }
1626
+ function cloudRunUrl(service, projectNumber, region) {
1627
+ return `https://${service}-${projectNumber}.${region}.run.app`;
1628
+ }
1629
+ function stackAppName(repoName) {
1630
+ let slug = repoName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^[^a-z]+/, "").slice(0, 20).replace(/-+$/, "");
1631
+ if (slug.length < 2)
1632
+ slug = `app${slug}`.slice(0, 20);
1633
+ return slug;
1634
+ }
1635
+ function envSettings(env) {
1636
+ return env === "prod" ? { min: 0, max: 10 } : { min: 0, max: 2 };
1637
+ }
1638
+ function buildStackFiles(input) {
1639
+ const { tier, app, defaultBranch, cloud } = input;
1640
+ if (!APP.test(app))
1641
+ throw new Error("Not a valid app name.");
1642
+ if (!BRANCH.test(defaultBranch))
1643
+ throw new Error("Not a valid branch name.");
1644
+ const envs = stackEnvironments(tier);
1645
+ const registry = `${cloud.region}-docker.pkg.dev/${cloud.projectId}/${app}`;
1646
+ const files = [];
1647
+ files.push({
1648
+ path: "infra/versions.tf",
1649
+ content: `# Managed by CompBox. Changes here are applied on the next deploy.
1650
+ terraform {
1651
+ required_version = ">= 1.6"
1652
+ required_providers {
1653
+ google = {
1654
+ source = "hashicorp/google"
1655
+ version = "~> 6.0"
1656
+ }
1657
+ }
1658
+ # Bucket and prefix are passed by the deploy workflow.
1659
+ backend "gcs" {}
1660
+ }
1661
+
1662
+ provider "google" {
1663
+ project = var.project_id
1664
+ region = var.region
1665
+ }
1666
+ `
1667
+ });
1668
+ files.push({
1669
+ path: "infra/variables.tf",
1670
+ content: `variable "project_id" {
1671
+ type = string
1672
+ }
1673
+
1674
+ variable "region" {
1675
+ type = string
1676
+ }
1677
+
1678
+ variable "app" {
1679
+ type = string
1680
+ }
1681
+
1682
+ variable "environment" {
1683
+ type = string
1684
+ }
1685
+
1686
+ variable "min_instances" {
1687
+ type = number
1688
+ default = 0
1689
+ }
1690
+
1691
+ variable "max_instances" {
1692
+ type = number
1693
+ default = 2
1694
+ }
1695
+
1696
+ # Only used the first time; every deploy sets the real image.
1697
+ variable "bootstrap_image" {
1698
+ type = string
1699
+ default = "us-docker.pkg.dev/cloudrun/container/hello"
1700
+ }
1701
+ `
1702
+ });
1703
+ files.push({
1704
+ path: "infra/main.tf",
1705
+ content: `locals {
1706
+ service = "\${var.app}-\${var.environment}"
1707
+ }
1708
+
1709
+ # One image registry for the app, created with dev and shared by every environment.
1710
+ resource "google_artifact_registry_repository" "app" {
1711
+ count = var.environment == "dev" ? 1 : 0
1712
+ repository_id = var.app
1713
+ location = var.region
1714
+ format = "DOCKER"
1715
+ }
1716
+
1717
+ # The account the app runs as in this environment (no permissions by default).
1718
+ resource "google_service_account" "runtime" {
1719
+ account_id = local.service
1720
+ display_name = "\${local.service} (CompBox)"
1721
+ }
1722
+
1723
+ resource "google_cloud_run_v2_service" "app" {
1724
+ name = local.service
1725
+ location = var.region
1726
+ ingress = "INGRESS_TRAFFIC_ALL"
1727
+ deletion_protection = var.environment == "prod"
1728
+
1729
+ template {
1730
+ service_account = google_service_account.runtime.email
1731
+ scaling {
1732
+ min_instance_count = var.min_instances
1733
+ max_instance_count = var.max_instances
1734
+ }
1735
+ containers {
1736
+ image = var.bootstrap_image
1737
+ }
1738
+ }
1739
+
1740
+ # Deploys change the image; Terraform owns everything else.
1741
+ lifecycle {
1742
+ ignore_changes = [template[0].containers[0].image, client, client_version]
1743
+ }
1744
+ }
1745
+
1746
+ # Anyone with the link can open it. Remove this to keep the app private.
1747
+ resource "google_cloud_run_v2_service_iam_member" "public" {
1748
+ name = google_cloud_run_v2_service.app.name
1749
+ location = var.region
1750
+ role = "roles/run.invoker"
1751
+ member = "allUsers"
1752
+ }
1753
+
1754
+ output "url" {
1755
+ value = google_cloud_run_v2_service.app.uri
1756
+ }
1757
+ `
1758
+ });
1759
+ for (const env of envs) {
1760
+ const s = envSettings(env);
1761
+ files.push({
1762
+ path: `infra/envs/${env}.tfvars`,
1763
+ content: `project_id = "${cloud.projectId}"
1764
+ region = "${cloud.region}"
1765
+ app = "${app}"
1766
+ environment = "${env}"
1767
+ min_instances = ${String(s.min)}
1768
+ max_instances = ${String(s.max)}
1769
+ `
1770
+ });
1771
+ }
1772
+ const options = envs.map((e) => ` - ${e}`).join("\n");
1773
+ files.push({
1774
+ path: ".github/workflows/compbox.yml",
1775
+ content: `# Managed by CompBox: every push to ${defaultBranch} deploys to dev.${envs.length > 1 ? "\n# Stage and prod: Actions \u2192 CompBox \u2192 Run workflow. Prod waits for its environment's approval." : ""}
1776
+ name: CompBox
1777
+ run-name: Deploy to \${{ inputs.environment || 'dev' }}
1778
+
1779
+ on:
1780
+ push:
1781
+ branches: [${JSON.stringify(defaultBranch)}]
1782
+ workflow_dispatch:
1783
+ inputs:
1784
+ environment:
1785
+ description: Where to deploy
1786
+ type: choice
1787
+ default: dev
1788
+ options:
1789
+ ${options}
1790
+
1791
+ permissions:
1792
+ contents: read
1793
+ id-token: write
1794
+
1795
+ jobs:
1796
+ deploy:
1797
+ uses: ./.github/workflows/compbox-deploy.yml
1798
+ with:
1799
+ environment: \${{ inputs.environment || 'dev' }}
1800
+ `
1801
+ });
1802
+ files.push({
1803
+ path: ".github/workflows/compbox-deploy.yml",
1804
+ content: `# Managed by CompBox. Signs in to Google Cloud without stored keys (Workload Identity).
1805
+ name: CompBox deploy
1806
+
1807
+ on:
1808
+ workflow_call:
1809
+ inputs:
1810
+ environment:
1811
+ type: string
1812
+ required: true
1813
+
1814
+ permissions:
1815
+ contents: read
1816
+ id-token: write
1817
+
1818
+ concurrency:
1819
+ group: compbox-\${{ inputs.environment }}
1820
+ cancel-in-progress: false
1821
+
1822
+ jobs:
1823
+ deploy:
1824
+ runs-on: ubuntu-latest
1825
+ environment:
1826
+ name: \${{ inputs.environment }}
1827
+ url: \${{ steps.deploy.outputs.url }}
1828
+ env:
1829
+ ENVIRONMENT: \${{ inputs.environment }}
1830
+ PROJECT_ID: ${cloud.projectId}
1831
+ REGION: ${cloud.region}
1832
+ APP: ${app}
1833
+ IMAGE: ${registry}/app:\${{ github.sha }}
1834
+ STATE_BUCKET: ${gcpStateBucket(cloud.projectId)}
1835
+ steps:
1836
+ - uses: actions/checkout@v4
1837
+
1838
+ - uses: google-github-actions/auth@v2
1839
+ with:
1840
+ workload_identity_provider: ${cloud.workloadProvider}
1841
+ service_account: ${cloud.serviceAccountEmail}
1842
+
1843
+ - uses: google-github-actions/setup-gcloud@v2
1844
+
1845
+ - uses: hashicorp/setup-terraform@v3
1846
+
1847
+ - name: Infrastructure
1848
+ working-directory: infra
1849
+ run: |
1850
+ terraform init -input=false -backend-config="bucket=$STATE_BUCKET" -backend-config="prefix=$APP/$ENVIRONMENT"
1851
+ terraform apply -input=false -auto-approve -var-file="envs/$ENVIRONMENT.tfvars"
1852
+
1853
+ - name: Build
1854
+ run: |
1855
+ if [ ! -f Dockerfile ]; then
1856
+ echo "::error::Add a Dockerfile at the repository root: CompBox deploys the app as a container that listens on \\$PORT."
1857
+ exit 1
1858
+ fi
1859
+ gcloud auth configure-docker "$REGION-docker.pkg.dev" --quiet
1860
+ docker build -t "$IMAGE" .
1861
+ docker push "$IMAGE"
1862
+
1863
+ - name: Deploy
1864
+ id: deploy
1865
+ run: |
1866
+ SERVICE="$APP-$ENVIRONMENT"
1867
+ gcloud run deploy "$SERVICE" --image "$IMAGE" --region "$REGION" --project "$PROJECT_ID" --quiet
1868
+ URL=$(gcloud run services describe "$SERVICE" --region "$REGION" --project "$PROJECT_ID" --format='value(status.url)')
1869
+ echo "url=$URL" >> "$GITHUB_OUTPUT"
1870
+ echo "### Live at $URL" >> "$GITHUB_STEP_SUMMARY"
1871
+ `
1872
+ });
1873
+ files.push({
1874
+ path: "infra/README.md",
1875
+ content: `# Infrastructure (managed by CompBox)
1876
+
1877
+ This project deploys to Google Cloud project \`${cloud.projectId}\` (${cloud.region}) as a Cloud Run service per environment: ${envs.map((e) => `\`${app}-${e}\``).join(", ")}.
1878
+
1879
+ - **Dev:** every push to \`${defaultBranch}\` deploys it.${envs.length > 1 ? "\n- **Stage and prod:** in GitHub, Actions \u2192 CompBox \u2192 Run workflow, then pick the environment. Add required reviewers to the `prod` environment (Settings \u2192 Environments) so prod waits for approval." : ""}
1880
+ - **The app:** a \`Dockerfile\` at the repository root, for a container that listens on \`$PORT\` (8080).
1881
+ - **Sign-in:** GitHub Actions sign in to Google Cloud through Workload Identity \u2014 there are no keys to store or rotate.
1882
+ - **Changes:** edit the Terraform here; the next deploy applies it. Services are public by default; remove the \`public\` resource in \`main.tf\` to keep one private.
1883
+ `
1884
+ });
1885
+ return files;
1886
+ }
1887
+ var STACK_TIERS, STACK_WORKFLOW, APP, BRANCH;
1888
+ var init_stack_files = __esm({
1889
+ "../shared/dist/stack-files.js"() {
1890
+ "use strict";
1891
+ init_cloud_setup();
1892
+ STACK_TIERS = {
1893
+ dev: { label: "Dev only", environments: ["dev"] },
1894
+ full: { label: "Dev, stage and prod", environments: ["dev", "stage", "prod"] }
1895
+ };
1896
+ STACK_WORKFLOW = "compbox.yml";
1897
+ APP = /^[a-z][a-z0-9-]{1,19}$/;
1898
+ BRANCH = /^[A-Za-z0-9._/-]{1,200}$/;
1899
+ }
1900
+ });
1901
+
1902
+ // ../shared/dist/github-repo.js
1903
+ function githubRepoKey(remote) {
1904
+ if (typeof remote !== "string")
1905
+ return null;
1906
+ const normalized = normalizeGitRemote(remote);
1907
+ const match = /^https:\/\/([^/]+)\/(.*)$/.exec(normalized);
1908
+ if (!match)
1909
+ return null;
1910
+ const host = match[1];
1911
+ const path4 = match[2];
1912
+ if (host !== "github.com" || path4 === void 0)
1913
+ return null;
1914
+ const segments = path4.split("/");
1915
+ if (segments.length !== 2)
1916
+ return null;
1917
+ const [owner, name] = segments;
1918
+ if (!owner || !name)
1919
+ return null;
1920
+ return `${owner}/${name}`.toLowerCase();
1921
+ }
1922
+ var init_github_repo = __esm({
1923
+ "../shared/dist/github-repo.js"() {
1924
+ "use strict";
1925
+ init_mailbox();
1926
+ }
1927
+ });
1928
+
1929
+ // ../shared/dist/return-to.js
1930
+ function safeReturnTo(value) {
1931
+ if (typeof value !== "string")
1932
+ return null;
1933
+ if (value.length < 1 || value.length > RETURN_TO_MAX_LENGTH)
1934
+ return null;
1935
+ if (!value.startsWith("/"))
1936
+ return null;
1937
+ const second = value.charAt(1);
1938
+ if (second === "/" || second === "\\")
1939
+ return null;
1940
+ if (value.includes("\\"))
1941
+ return null;
1942
+ if (value.includes("://"))
1943
+ return null;
1944
+ for (let i = 0; i < value.length; i++) {
1945
+ const code = value.charCodeAt(i);
1946
+ if (code < 32 || code === 127)
1947
+ return null;
1948
+ }
1949
+ return value;
1950
+ }
1951
+ var RETURN_TO_MAX_LENGTH;
1952
+ var init_return_to = __esm({
1953
+ "../shared/dist/return-to.js"() {
1954
+ "use strict";
1955
+ RETURN_TO_MAX_LENGTH = 512;
1956
+ }
1957
+ });
1958
+
1053
1959
  // ../shared/dist/index.js
1054
1960
  var dist_exports = {};
1055
1961
  __export(dist_exports, {
1056
1962
  AI_PROVIDERS: () => AI_PROVIDERS,
1057
1963
  APPEND_DESCRIPTION_MAX: () => APPEND_DESCRIPTION_MAX,
1964
+ AWS_REGIONS: () => AWS_REGIONS,
1965
+ AZURE_DEPLOY_IDENTITY: () => AZURE_DEPLOY_IDENTITY,
1058
1966
  COMPLETION_REPAIR_INSTRUCTION: () => COMPLETION_REPAIR_INSTRUCTION,
1059
1967
  CONVERSATION_QUALITY_ROUNDS: () => CONVERSATION_QUALITY_ROUNDS,
1060
1968
  DESCRIPTION_MAX: () => DESCRIPTION_MAX,
1969
+ EMPTY_ARM_TEMPLATE: () => EMPTY_ARM_TEMPLATE,
1970
+ GCP_CONNECT_STEPS: () => GCP_CONNECT_STEPS,
1971
+ GCP_CONNECT_STEP_LABELS: () => GCP_CONNECT_STEP_LABELS,
1972
+ GCP_DEPLOY_ACCOUNT: () => GCP_DEPLOY_ACCOUNT,
1973
+ GCP_DEPLOY_ROLES: () => GCP_DEPLOY_ROLES,
1974
+ GCP_IDENTITY_POOL: () => GCP_IDENTITY_POOL,
1975
+ GCP_IDENTITY_PROVIDER: () => GCP_IDENTITY_PROVIDER,
1976
+ GCP_REGIONS: () => GCP_REGIONS,
1061
1977
  INTERVIEW_DEFINITION: () => INTERVIEW_DEFINITION,
1062
1978
  INTERVIEW_FIELD_MIN_WORDS: () => INTERVIEW_FIELD_MIN_WORDS,
1063
1979
  INTERVIEW_STATUSES: () => INTERVIEW_STATUSES,
@@ -1067,6 +1983,9 @@ __export(dist_exports, {
1067
1983
  MODEL_CATALOG: () => MODEL_CATALOG,
1068
1984
  ORG_ROLES: () => ORG_ROLES,
1069
1985
  PXPIPE_DEFAULT_PROXY_URL: () => PXPIPE_DEFAULT_PROXY_URL,
1986
+ RETURN_TO_MAX_LENGTH: () => RETURN_TO_MAX_LENGTH,
1987
+ STACK_TIERS: () => STACK_TIERS,
1988
+ STACK_WORKFLOW: () => STACK_WORKFLOW,
1070
1989
  START_EXECUTION_KINDS: () => START_EXECUTION_KINDS,
1071
1990
  SUBSCRIPTION_STATUSES: () => SUBSCRIPTION_STATUSES,
1072
1991
  SUMMARY_MAX: () => SUMMARY_MAX,
@@ -1076,25 +1995,50 @@ __export(dist_exports, {
1076
1995
  agentSchema: () => agentSchema,
1077
1996
  aiProviderValues: () => aiProviderValues,
1078
1997
  aiRouteValues: () => aiRouteValues,
1998
+ awsQuickCreateUrl: () => awsQuickCreateUrl,
1999
+ azureDeployUrl: () => azureDeployUrl,
2000
+ azureGitHubSubject: () => azureGitHubSubject,
1079
2001
  buildAuditFeedback: () => buildAuditFeedback,
2002
+ buildAwsConnectTemplate: () => buildAwsConnectTemplate,
2003
+ buildAzureConnectTemplate: () => buildAzureConnectTemplate,
1080
2004
  buildConversationSystemPrompt: () => buildConversationSystemPrompt,
2005
+ buildGcpSetupScript: () => buildGcpSetupScript,
1081
2006
  buildInterviewSystemPrompt: () => buildInterviewSystemPrompt,
2007
+ buildStackFiles: () => buildStackFiles,
2008
+ cloudRunUrl: () => cloudRunUrl,
1082
2009
  complianceFromRecord: () => complianceFromRecord,
2010
+ deployRunTitle: () => deployRunTitle,
1083
2011
  err: () => err,
1084
2012
  extractCompletionJson: () => extractCompletionJson,
2013
+ gcpServiceAccountEmail: () => gcpServiceAccountEmail,
2014
+ gcpStateBucket: () => gcpStateBucket,
2015
+ gcpWorkloadProvider: () => gcpWorkloadProvider,
1085
2016
  getAnthropicProxyUrl: () => getAnthropicProxyUrl,
1086
2017
  getModelById: () => getModelById,
1087
2018
  getModelDisplayName: () => getModelDisplayName,
1088
2019
  getOpenAiProxyUrl: () => getOpenAiProxyUrl,
2020
+ githubRepoKey: () => githubRepoKey,
1089
2021
  instructionSchema: () => instructionSchema,
1090
2022
  interviewFieldKeys: () => interviewFieldKeys,
1091
2023
  interviewSectionKeys: () => interviewSectionKeys,
2024
+ isAwsAccountId: () => isAwsAccountId,
2025
+ isAwsRegion: () => isAwsRegion,
2026
+ isAwsRoleArn: () => isAwsRoleArn,
2027
+ isAzureGuid: () => isAzureGuid,
2028
+ isAzureLocation: () => isAzureLocation,
2029
+ isAzureResourceGroup: () => isAzureResourceGroup,
2030
+ isAzureStorageAccount: () => isAzureStorageAccount,
2031
+ isGcpProjectId: () => isGcpProjectId,
2032
+ isGcpProjectNumber: () => isGcpProjectNumber,
2033
+ isGcpRegion: () => isGcpRegion,
2034
+ isGitHubLogin: () => isGitHubLogin,
1092
2035
  isInterviewStatus: () => isInterviewStatus,
1093
2036
  isJobStatus: () => isJobStatus,
1094
2037
  isJobType: () => isJobType,
1095
2038
  isMachineStatus: () => isMachineStatus,
1096
2039
  isOrgRole: () => isOrgRole,
1097
2040
  isPxpipeEnabled: () => isPxpipeEnabled,
2041
+ isS3BucketName: () => isS3BucketName,
1098
2042
  isSessionErrorEvent: () => isSessionErrorEvent,
1099
2043
  isSessionFeatureEvent: () => isSessionFeatureEvent,
1100
2044
  isSessionLifecycleEvent: () => isSessionLifecycleEvent,
@@ -1115,12 +2059,15 @@ __export(dist_exports, {
1115
2059
  renderConversationPrompt: () => renderConversationPrompt,
1116
2060
  resolveRouting: () => resolveRouting,
1117
2061
  runConversationStep: () => runConversationStep,
2062
+ safeReturnTo: () => safeReturnTo,
1118
2063
  safeValidateSkillPackManifest: () => safeValidateSkillPackManifest,
1119
2064
  savedContextFromRecord: () => savedContextFromRecord,
1120
2065
  savedMessage: () => savedMessage,
1121
2066
  skillPackManifestSchema: () => skillPackManifestSchema,
1122
2067
  skillSchema: () => skillSchema,
1123
2068
  sleep: () => sleep,
2069
+ stackAppName: () => stackAppName,
2070
+ stackEnvironments: () => stackEnvironments,
1124
2071
  thinkingLevelValues: () => thinkingLevelValues,
1125
2072
  toConversationMessages: () => toConversationMessages,
1126
2073
  validatePackName: () => validatePackName,
@@ -1138,6 +2085,11 @@ var init_dist = __esm({
1138
2085
  init_interview_definition();
1139
2086
  init_interview_completion();
1140
2087
  init_interview_conversation();
2088
+ init_cloud_setup();
2089
+ init_cloud_connect();
2090
+ init_stack_files();
2091
+ init_github_repo();
2092
+ init_return_to();
1141
2093
  }
1142
2094
  });
1143
2095
 
@@ -11318,7 +12270,7 @@ function withLegacyToolCallRewrite(transport) {
11318
12270
  var SERVER_NAME = "compbox-mcp";
11319
12271
  function resolveServerVersion() {
11320
12272
  if (true) {
11321
- return "1.20.0";
12273
+ return "1.21.1";
11322
12274
  }
11323
12275
  const require2 = createRequire(import.meta.url);
11324
12276
  for (const candidate of ["../package.json", "./package.json"]) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mycompbox/compbox-mcp",
3
- "version": "1.20.0",
3
+ "version": "1.21.1",
4
4
  "description": "CompBox MCP server - Uses HTTP API client (no direct database access)",
5
5
  "license": "MIT",
6
6
  "type": "module",