@cubis/foundry 0.3.59 → 0.3.61

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cubis/foundry",
3
- "version": "0.3.59",
3
+ "version": "0.3.61",
4
4
  "description": "Cubis Foundry CLI for workflow-first AI agent environments",
5
5
  "type": "module",
6
6
  "bin": {
@@ -82,8 +82,10 @@
82
82
  },
83
83
  "dependencies": {
84
84
  "@inquirer/prompts": "^7.8.6",
85
+ "@modelcontextprotocol/sdk": "^1.27.1",
85
86
  "commander": "^14.0.1",
86
- "jsonc-parser": "^3.3.1"
87
+ "jsonc-parser": "^3.3.1",
88
+ "zod": "^3.25.76"
87
89
  },
88
90
  "devDependencies": {
89
91
  "@types/node": "^20.14.0",
package/src/cli/core.ts CHANGED
@@ -173,7 +173,7 @@ const CODEX_WORKFLOW_SKILL_PREFIX = "workflow-";
173
173
  const CODEX_AGENT_SKILL_PREFIX = "agent-";
174
174
  const TERMINAL_VERIFIER_PROVIDERS = ["codex", "gemini"];
175
175
  const DEFAULT_TERMINAL_VERIFIER = "codex";
176
- const POSTMAN_API_KEY_ENV_VAR = "POSTMAN_API_KEY";
176
+ const POSTMAN_API_KEY_ENV_VAR = "POSTMAN_API_KEY_DEFAULT";
177
177
  const POSTMAN_MODE_TO_URL = Object.freeze({
178
178
  minimal: "https://mcp.postman.com/minimal",
179
179
  code: "https://mcp.postman.com/code",
@@ -190,7 +190,7 @@ const FOUNDRY_MCP_SERVER_ID = "cubis-foundry";
190
190
  const FOUNDRY_MCP_COMMAND = "cbx";
191
191
  const STITCH_SKILL_ID = "stitch";
192
192
  const STITCH_MCP_SERVER_ID = "StitchMCP";
193
- const STITCH_API_KEY_ENV_VAR = "STITCH_API_KEY";
193
+ const STITCH_API_KEY_ENV_VAR = "STITCH_API_KEY_DEFAULT";
194
194
  const STITCH_MCP_URL = "https://stitch.googleapis.com/mcp";
195
195
  const POSTMAN_WORKSPACE_MANUAL_CHOICE = "__postman_workspace_manual__";
196
196
  const CBX_CONFIG_FILENAME = "cbx_config.json";
@@ -1203,6 +1203,99 @@ function parseTomlSections(content) {
1203
1203
  return sections;
1204
1204
  }
1205
1205
 
1206
+ function escapeTomlBasicString(value) {
1207
+ return String(value ?? "")
1208
+ .replace(/\\/g, "\\\\")
1209
+ .replace(/"/g, '\\"');
1210
+ }
1211
+
1212
+ async function patchCodexPostmanHttpHeaders({
1213
+ configPath,
1214
+ mcpUrl,
1215
+ bearerToken,
1216
+ dryRun = false,
1217
+ }) {
1218
+ const warnings = [];
1219
+ const normalizedToken = normalizePostmanApiKey(bearerToken);
1220
+ if (!normalizedToken) {
1221
+ return {
1222
+ action: "skipped",
1223
+ warnings: [
1224
+ "Postman API key is unavailable in current environment. Kept bearer_token_env_var wiring in Codex config.",
1225
+ ],
1226
+ };
1227
+ }
1228
+
1229
+ const configExists = await pathExists(configPath);
1230
+ const original = configExists ? await readFile(configPath, "utf8") : "";
1231
+ const lines = original.split(/\r?\n/);
1232
+ const nextLines = [];
1233
+
1234
+ const headerLine =
1235
+ `http_headers = { Authorization = "Bearer ${escapeTomlBasicString(normalizedToken)}" }`;
1236
+ const serverHeader = "[mcp_servers.postman]";
1237
+ let inPostmanSection = false;
1238
+ let postmanSectionFound = false;
1239
+ let insertedHeaders = false;
1240
+
1241
+ const flushPostmanHeaderIfNeeded = () => {
1242
+ if (inPostmanSection && !insertedHeaders) {
1243
+ nextLines.push(headerLine);
1244
+ insertedHeaders = true;
1245
+ }
1246
+ };
1247
+
1248
+ for (const line of lines) {
1249
+ const sectionMatch = line.match(/^\s*\[([^\]]+)\]\s*$/);
1250
+ if (sectionMatch) {
1251
+ flushPostmanHeaderIfNeeded();
1252
+ const sectionName = sectionMatch[1].trim();
1253
+ inPostmanSection = sectionName === "mcp_servers.postman";
1254
+ if (inPostmanSection) {
1255
+ postmanSectionFound = true;
1256
+ insertedHeaders = false;
1257
+ }
1258
+ nextLines.push(line);
1259
+ continue;
1260
+ }
1261
+
1262
+ if (inPostmanSection) {
1263
+ if (
1264
+ /^\s*(bearer_token_env_var|http_headers|env_http_headers)\s*=/.test(
1265
+ line,
1266
+ )
1267
+ ) {
1268
+ continue;
1269
+ }
1270
+ }
1271
+ nextLines.push(line);
1272
+ }
1273
+
1274
+ flushPostmanHeaderIfNeeded();
1275
+
1276
+ if (!postmanSectionFound) {
1277
+ if (nextLines.length > 0 && nextLines[nextLines.length - 1].trim() !== "") {
1278
+ nextLines.push("");
1279
+ }
1280
+ nextLines.push(serverHeader);
1281
+ nextLines.push(`url = "${escapeTomlBasicString(mcpUrl || POSTMAN_MCP_URL)}"`);
1282
+ nextLines.push(headerLine);
1283
+ }
1284
+
1285
+ const next = `${nextLines.join("\n").replace(/\n+$/g, "")}\n`;
1286
+ if (next === original) {
1287
+ return { action: "unchanged", warnings };
1288
+ }
1289
+ if (!dryRun) {
1290
+ await mkdir(path.dirname(configPath), { recursive: true });
1291
+ await writeFile(configPath, next, "utf8");
1292
+ }
1293
+ return {
1294
+ action: dryRun ? "would-patch" : "patched",
1295
+ warnings,
1296
+ };
1297
+ }
1298
+
1206
1299
  function parsePubspecDependencyNames(content) {
1207
1300
  const packages = new Set();
1208
1301
  let currentSection = null;
@@ -4208,16 +4301,31 @@ function resolveStitchMcpDefinitionPath({ scope, cwd = process.cwd() }) {
4208
4301
  );
4209
4302
  }
4210
4303
 
4211
- function buildPostmanAuthHeader({ apiKeyEnvVar = POSTMAN_API_KEY_ENV_VAR }) {
4304
+ function buildPostmanAuthHeader({
4305
+ apiKeyEnvVar = POSTMAN_API_KEY_ENV_VAR,
4306
+ apiKey = null,
4307
+ }) {
4308
+ const normalizedApiKey = normalizePostmanApiKey(apiKey);
4309
+ if (normalizedApiKey) {
4310
+ return `Bearer ${normalizedApiKey}`;
4311
+ }
4212
4312
  return `Bearer \${${apiKeyEnvVar}}`;
4213
4313
  }
4214
4314
 
4215
- function buildStitchApiHeader({ apiKeyEnvVar = STITCH_API_KEY_ENV_VAR }) {
4315
+ function buildStitchApiHeader({
4316
+ apiKeyEnvVar = STITCH_API_KEY_ENV_VAR,
4317
+ apiKey = null,
4318
+ }) {
4319
+ const normalizedApiKey = normalizePostmanApiKey(apiKey);
4320
+ if (normalizedApiKey) {
4321
+ return `X-Goog-Api-Key: ${normalizedApiKey}`;
4322
+ }
4216
4323
  return `X-Goog-Api-Key: \${${apiKeyEnvVar}}`;
4217
4324
  }
4218
4325
 
4219
4326
  function buildPostmanMcpDefinition({
4220
4327
  apiKeyEnvVar = POSTMAN_API_KEY_ENV_VAR,
4328
+ apiKey = null,
4221
4329
  mcpUrl = POSTMAN_MCP_URL,
4222
4330
  }) {
4223
4331
  return {
@@ -4226,13 +4334,14 @@ function buildPostmanMcpDefinition({
4226
4334
  transport: "http",
4227
4335
  url: mcpUrl,
4228
4336
  headers: {
4229
- Authorization: buildPostmanAuthHeader({ apiKeyEnvVar }),
4337
+ Authorization: buildPostmanAuthHeader({ apiKeyEnvVar, apiKey }),
4230
4338
  },
4231
4339
  };
4232
4340
  }
4233
4341
 
4234
4342
  function buildStitchMcpDefinition({
4235
4343
  apiKeyEnvVar = STITCH_API_KEY_ENV_VAR,
4344
+ apiKey = null,
4236
4345
  mcpUrl = STITCH_MCP_URL,
4237
4346
  }) {
4238
4347
  return {
@@ -4245,7 +4354,7 @@ function buildStitchMcpDefinition({
4245
4354
  "mcp-remote",
4246
4355
  mcpUrl,
4247
4356
  "--header",
4248
- buildStitchApiHeader({ apiKeyEnvVar }),
4357
+ buildStitchApiHeader({ apiKeyEnvVar, apiKey }),
4249
4358
  ],
4250
4359
  env: {},
4251
4360
  };
@@ -4253,13 +4362,14 @@ function buildStitchMcpDefinition({
4253
4362
 
4254
4363
  function buildVsCodePostmanServer({
4255
4364
  apiKeyEnvVar = POSTMAN_API_KEY_ENV_VAR,
4365
+ apiKey = null,
4256
4366
  mcpUrl = POSTMAN_MCP_URL,
4257
4367
  }) {
4258
4368
  return {
4259
4369
  type: "sse",
4260
4370
  url: mcpUrl,
4261
4371
  headers: {
4262
- Authorization: buildPostmanAuthHeader({ apiKeyEnvVar }),
4372
+ Authorization: buildPostmanAuthHeader({ apiKeyEnvVar, apiKey }),
4263
4373
  },
4264
4374
  };
4265
4375
  }
@@ -4283,13 +4393,14 @@ function buildVsCodeFoundryServer({ scope = "auto" } = {}) {
4283
4393
 
4284
4394
  function buildCopilotCliPostmanServer({
4285
4395
  apiKeyEnvVar = POSTMAN_API_KEY_ENV_VAR,
4396
+ apiKey = null,
4286
4397
  mcpUrl = POSTMAN_MCP_URL,
4287
4398
  }) {
4288
4399
  return {
4289
4400
  type: "http",
4290
4401
  url: mcpUrl,
4291
4402
  headers: {
4292
- Authorization: buildPostmanAuthHeader({ apiKeyEnvVar }),
4403
+ Authorization: buildPostmanAuthHeader({ apiKeyEnvVar, apiKey }),
4293
4404
  },
4294
4405
  tools: ["*"],
4295
4406
  };
@@ -4307,12 +4418,13 @@ function buildCopilotCliFoundryServer({ scope = "auto" } = {}) {
4307
4418
 
4308
4419
  function buildGeminiPostmanServer({
4309
4420
  apiKeyEnvVar = POSTMAN_API_KEY_ENV_VAR,
4421
+ apiKey = null,
4310
4422
  mcpUrl = POSTMAN_MCP_URL,
4311
4423
  }) {
4312
4424
  return {
4313
4425
  httpUrl: mcpUrl,
4314
4426
  headers: {
4315
- Authorization: buildPostmanAuthHeader({ apiKeyEnvVar }),
4427
+ Authorization: buildPostmanAuthHeader({ apiKeyEnvVar, apiKey }),
4316
4428
  },
4317
4429
  };
4318
4430
  }
@@ -4327,6 +4439,7 @@ function buildGeminiFoundryServer({ scope = "auto" } = {}) {
4327
4439
 
4328
4440
  function buildGeminiStitchServer({
4329
4441
  apiKeyEnvVar = STITCH_API_KEY_ENV_VAR,
4442
+ apiKey = null,
4330
4443
  mcpUrl = STITCH_MCP_URL,
4331
4444
  }) {
4332
4445
  return {
@@ -4336,7 +4449,7 @@ function buildGeminiStitchServer({
4336
4449
  "mcp-remote",
4337
4450
  mcpUrl,
4338
4451
  "--header",
4339
- buildStitchApiHeader({ apiKeyEnvVar }),
4452
+ buildStitchApiHeader({ apiKeyEnvVar, apiKey }),
4340
4453
  ],
4341
4454
  env: {},
4342
4455
  };
@@ -4840,6 +4953,12 @@ async function applyPostmanMcpForPlatform({
4840
4953
  const workspaceRoot = findWorkspaceRoot(cwd);
4841
4954
  const warnings = [];
4842
4955
  const foundryScope = mcpScope === "global" ? "global" : "project";
4956
+ const resolvedPostmanApiKey = normalizePostmanApiKey(
4957
+ process.env[apiKeyEnvVar || POSTMAN_API_KEY_ENV_VAR],
4958
+ );
4959
+ const resolvedStitchApiKey = normalizePostmanApiKey(
4960
+ process.env[stitchApiKeyEnvVar || STITCH_API_KEY_ENV_VAR],
4961
+ );
4843
4962
 
4844
4963
  if (platform === "antigravity") {
4845
4964
  const settingsPath =
@@ -4859,6 +4978,7 @@ async function applyPostmanMcpForPlatform({
4859
4978
  if (includePostmanMcp) {
4860
4979
  mcpServers[POSTMAN_SKILL_ID] = buildGeminiPostmanServer({
4861
4980
  apiKeyEnvVar,
4981
+ apiKey: resolvedPostmanApiKey,
4862
4982
  mcpUrl,
4863
4983
  });
4864
4984
  }
@@ -4872,6 +4992,7 @@ async function applyPostmanMcpForPlatform({
4872
4992
  if (includeStitchMcp) {
4873
4993
  mcpServers[STITCH_MCP_SERVER_ID] = buildGeminiStitchServer({
4874
4994
  apiKeyEnvVar: stitchApiKeyEnvVar,
4995
+ apiKey: resolvedStitchApiKey,
4875
4996
  mcpUrl: stitchMcpUrl,
4876
4997
  });
4877
4998
  }
@@ -4908,6 +5029,7 @@ async function applyPostmanMcpForPlatform({
4908
5029
  if (includePostmanMcp) {
4909
5030
  mcpServers[POSTMAN_SKILL_ID] = buildCopilotCliPostmanServer({
4910
5031
  apiKeyEnvVar,
5032
+ apiKey: resolvedPostmanApiKey,
4911
5033
  mcpUrl,
4912
5034
  });
4913
5035
  }
@@ -4931,6 +5053,7 @@ async function applyPostmanMcpForPlatform({
4931
5053
  if (includePostmanMcp) {
4932
5054
  servers[POSTMAN_SKILL_ID] = buildVsCodePostmanServer({
4933
5055
  apiKeyEnvVar,
5056
+ apiKey: resolvedPostmanApiKey,
4934
5057
  mcpUrl,
4935
5058
  });
4936
5059
  }
@@ -4971,6 +5094,7 @@ async function applyPostmanMcpForPlatform({
4971
5094
  if (includePostmanMcp) {
4972
5095
  servers[POSTMAN_SKILL_ID] = buildVsCodePostmanServer({
4973
5096
  apiKeyEnvVar,
5097
+ apiKey: resolvedPostmanApiKey,
4974
5098
  mcpUrl,
4975
5099
  });
4976
5100
  }
@@ -5034,6 +5158,23 @@ async function applyPostmanMcpForPlatform({
5034
5158
  ],
5035
5159
  { cwd },
5036
5160
  );
5161
+ const postmanToken = normalizePostmanApiKey(
5162
+ process.env[apiKeyEnvVar || POSTMAN_API_KEY_ENV_VAR],
5163
+ );
5164
+ const postmanPatch = await patchCodexPostmanHttpHeaders({
5165
+ configPath: codexConfigPath,
5166
+ mcpUrl,
5167
+ bearerToken: postmanToken,
5168
+ dryRun: false,
5169
+ });
5170
+ if (postmanPatch.action === "patched") {
5171
+ warnings.push(
5172
+ "Codex Postman MCP config patched to static Authorization header for startup reliability.",
5173
+ );
5174
+ }
5175
+ if (postmanPatch.warnings?.length) {
5176
+ warnings.push(...postmanPatch.warnings);
5177
+ }
5037
5178
  } catch (error) {
5038
5179
  warnings.push(
5039
5180
  `Failed to register Postman MCP via Codex CLI. Ensure 'codex' is installed and rerun. (${error.message})`,
@@ -5562,6 +5703,7 @@ async function configurePostmanInstallArtifacts({
5562
5703
  const mcpDefinitionContent = `${JSON.stringify(
5563
5704
  buildPostmanMcpDefinition({
5564
5705
  apiKeyEnvVar: effectiveApiKeyEnvVar,
5706
+ apiKey: envApiKey,
5565
5707
  mcpUrl: effectiveMcpUrl,
5566
5708
  }),
5567
5709
  null,
@@ -5583,6 +5725,7 @@ async function configurePostmanInstallArtifacts({
5583
5725
  const stitchMcpDefinitionContent = `${JSON.stringify(
5584
5726
  buildStitchMcpDefinition({
5585
5727
  apiKeyEnvVar: effectiveStitchApiKeyEnvVar,
5728
+ apiKey: envStitchApiKey,
5586
5729
  mcpUrl: effectiveStitchMcpUrl,
5587
5730
  }),
5588
5731
  null,
@@ -5721,6 +5864,12 @@ async function applyPostmanConfigArtifacts({
5721
5864
  const stitchApiKeyEnvVar =
5722
5865
  normalizePostmanApiKey(stitchState?.apiKeyEnvVar) || STITCH_API_KEY_ENV_VAR;
5723
5866
  const stitchMcpUrl = stitchState?.mcpUrl || STITCH_MCP_URL;
5867
+ const resolvedPostmanApiKey = normalizePostmanApiKey(
5868
+ process.env[postmanApiKeyEnvVar],
5869
+ );
5870
+ const resolvedStitchApiKey = normalizePostmanApiKey(
5871
+ process.env[stitchApiKeyEnvVar],
5872
+ );
5724
5873
 
5725
5874
  const mcpDefinitionPath = resolvePostmanMcpDefinitionPath({
5726
5875
  platform,
@@ -5730,6 +5879,7 @@ async function applyPostmanConfigArtifacts({
5730
5879
  const mcpDefinitionContent = `${JSON.stringify(
5731
5880
  buildPostmanMcpDefinition({
5732
5881
  apiKeyEnvVar: postmanApiKeyEnvVar,
5882
+ apiKey: resolvedPostmanApiKey,
5733
5883
  mcpUrl: postmanMcpUrl,
5734
5884
  }),
5735
5885
  null,
@@ -5751,6 +5901,7 @@ async function applyPostmanConfigArtifacts({
5751
5901
  const stitchMcpDefinitionContent = `${JSON.stringify(
5752
5902
  buildStitchMcpDefinition({
5753
5903
  apiKeyEnvVar: stitchApiKeyEnvVar,
5904
+ apiKey: resolvedStitchApiKey,
5754
5905
  mcpUrl: stitchMcpUrl,
5755
5906
  }),
5756
5907
  null,