@cubis/foundry 0.3.74 → 0.3.76

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 (115) hide show
  1. package/README.md +98 -76
  2. package/dist/cli/commands/register.js +1 -1
  3. package/dist/cli/commands/register.js.map +1 -1
  4. package/dist/cli/core.js +348 -216
  5. package/dist/cli/core.js.map +1 -1
  6. package/dist/cli/init/execute.js +5 -7
  7. package/dist/cli/init/execute.js.map +1 -1
  8. package/dist/cli/workflows/commands.js +2 -2
  9. package/dist/cli/workflows/commands.js.map +1 -1
  10. package/package.json +4 -3
  11. package/src/cli/commands/register.ts +1 -1
  12. package/src/cli/core.ts +429 -267
  13. package/src/cli/init/execute.ts +5 -9
  14. package/src/cli/workflows/commands.ts +2 -2
  15. package/workflows/skills/_schema/skill-platform-attributes.json +7 -0
  16. package/workflows/skills/generated/skill-audit.json +11 -2
  17. package/workflows/skills/generated/skill-catalog.json +30 -4
  18. package/workflows/skills/skills_index.json +26 -0
  19. package/workflows/skills/stitch/SKILL.md +79 -0
  20. package/workflows/skills/stitch/evals/assertions.md +45 -0
  21. package/workflows/skills/stitch/evals/evals.json +68 -0
  22. package/workflows/skills/stitch/examples/01-new-screen.md +13 -0
  23. package/workflows/skills/stitch/examples/02-update-existing-screen.md +13 -0
  24. package/workflows/skills/stitch/examples/03-mobile-handoff.md +13 -0
  25. package/workflows/skills/stitch/examples/04-prompt-enhancement.md +21 -0
  26. package/workflows/skills/stitch/examples/05-design-sync-loop.md +16 -0
  27. package/workflows/skills/stitch/references/implementation-patterns.md +20 -0
  28. package/workflows/skills/stitch/references/platform-setup.md +46 -0
  29. package/workflows/skills/stitch/references/update-diff-workflow.md +23 -0
  30. package/workflows/workflows/agent-environment-setup/generated/route-manifest.json +15 -7
  31. package/workflows/workflows/agent-environment-setup/manifest.json +5 -0
  32. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/frontend-specialist.md +10 -2
  33. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/mobile-developer.md +6 -2
  34. package/workflows/workflows/agent-environment-setup/platforms/antigravity/rules/GEMINI.md +1 -0
  35. package/workflows/workflows/agent-environment-setup/platforms/antigravity/skills/stitch/SKILL.md +87 -0
  36. package/workflows/workflows/agent-environment-setup/platforms/antigravity/skills/stitch/evals/assertions.md +45 -0
  37. package/workflows/workflows/agent-environment-setup/platforms/antigravity/skills/stitch/evals/evals.json +68 -0
  38. package/workflows/workflows/agent-environment-setup/platforms/antigravity/skills/stitch/examples/01-new-screen.md +13 -0
  39. package/workflows/workflows/agent-environment-setup/platforms/antigravity/skills/stitch/examples/02-update-existing-screen.md +13 -0
  40. package/workflows/workflows/agent-environment-setup/platforms/antigravity/skills/stitch/examples/03-mobile-handoff.md +13 -0
  41. package/workflows/workflows/agent-environment-setup/platforms/antigravity/skills/stitch/examples/04-prompt-enhancement.md +21 -0
  42. package/workflows/workflows/agent-environment-setup/platforms/antigravity/skills/stitch/examples/05-design-sync-loop.md +16 -0
  43. package/workflows/workflows/agent-environment-setup/platforms/antigravity/skills/stitch/references/implementation-patterns.md +20 -0
  44. package/workflows/workflows/agent-environment-setup/platforms/antigravity/skills/stitch/references/platform-setup.md +46 -0
  45. package/workflows/workflows/agent-environment-setup/platforms/antigravity/skills/stitch/references/update-diff-workflow.md +23 -0
  46. package/workflows/workflows/agent-environment-setup/platforms/antigravity/workflows/create.md +3 -2
  47. package/workflows/workflows/agent-environment-setup/platforms/antigravity/workflows/mobile.md +4 -3
  48. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/frontend-specialist.md +10 -2
  49. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/mobile-developer.md +6 -2
  50. package/workflows/workflows/agent-environment-setup/platforms/claude/rules/CLAUDE.md +1 -0
  51. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/skills_index.json +26 -0
  52. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/stitch/SKILL.md +93 -0
  53. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/stitch/evals/assertions.md +45 -0
  54. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/stitch/evals/evals.json +68 -0
  55. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/stitch/examples/01-new-screen.md +13 -0
  56. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/stitch/examples/02-update-existing-screen.md +13 -0
  57. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/stitch/examples/03-mobile-handoff.md +13 -0
  58. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/stitch/examples/04-prompt-enhancement.md +21 -0
  59. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/stitch/examples/05-design-sync-loop.md +16 -0
  60. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/stitch/references/implementation-patterns.md +20 -0
  61. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/stitch/references/platform-setup.md +46 -0
  62. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/stitch/references/update-diff-workflow.md +23 -0
  63. package/workflows/workflows/agent-environment-setup/platforms/claude/workflows/create.md +3 -2
  64. package/workflows/workflows/agent-environment-setup/platforms/claude/workflows/mobile.md +4 -3
  65. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/frontend-specialist.md +10 -2
  66. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/mobile-developer.md +6 -2
  67. package/workflows/workflows/agent-environment-setup/platforms/codex/rules/AGENTS.md +1 -0
  68. package/workflows/workflows/agent-environment-setup/platforms/codex/skills/stitch/SKILL.md +87 -0
  69. package/workflows/workflows/agent-environment-setup/platforms/codex/skills/stitch/evals/assertions.md +45 -0
  70. package/workflows/workflows/agent-environment-setup/platforms/codex/skills/stitch/evals/evals.json +68 -0
  71. package/workflows/workflows/agent-environment-setup/platforms/codex/skills/stitch/examples/01-new-screen.md +13 -0
  72. package/workflows/workflows/agent-environment-setup/platforms/codex/skills/stitch/examples/02-update-existing-screen.md +13 -0
  73. package/workflows/workflows/agent-environment-setup/platforms/codex/skills/stitch/examples/03-mobile-handoff.md +13 -0
  74. package/workflows/workflows/agent-environment-setup/platforms/codex/skills/stitch/examples/04-prompt-enhancement.md +21 -0
  75. package/workflows/workflows/agent-environment-setup/platforms/codex/skills/stitch/examples/05-design-sync-loop.md +16 -0
  76. package/workflows/workflows/agent-environment-setup/platforms/codex/skills/stitch/references/implementation-patterns.md +20 -0
  77. package/workflows/workflows/agent-environment-setup/platforms/codex/skills/stitch/references/platform-setup.md +46 -0
  78. package/workflows/workflows/agent-environment-setup/platforms/codex/skills/stitch/references/update-diff-workflow.md +23 -0
  79. package/workflows/workflows/agent-environment-setup/platforms/codex/workflows/create.md +3 -2
  80. package/workflows/workflows/agent-environment-setup/platforms/codex/workflows/mobile.md +4 -3
  81. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/frontend-specialist.md +6 -2
  82. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/mobile-developer.md +6 -2
  83. package/workflows/workflows/agent-environment-setup/platforms/copilot/rules/copilot-instructions.md +1 -0
  84. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/skills_index.json +26 -0
  85. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/stitch/SKILL.md +92 -0
  86. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/stitch/evals/assertions.md +45 -0
  87. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/stitch/evals/evals.json +68 -0
  88. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/stitch/examples/01-new-screen.md +13 -0
  89. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/stitch/examples/02-update-existing-screen.md +13 -0
  90. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/stitch/examples/03-mobile-handoff.md +13 -0
  91. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/stitch/examples/04-prompt-enhancement.md +21 -0
  92. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/stitch/examples/05-design-sync-loop.md +16 -0
  93. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/stitch/references/implementation-patterns.md +20 -0
  94. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/stitch/references/platform-setup.md +46 -0
  95. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/stitch/references/update-diff-workflow.md +23 -0
  96. package/workflows/workflows/agent-environment-setup/platforms/copilot/workflows/create.md +3 -2
  97. package/workflows/workflows/agent-environment-setup/platforms/copilot/workflows/mobile.md +4 -3
  98. package/workflows/workflows/agent-environment-setup/platforms/gemini/rules/GEMINI.md +1 -0
  99. package/workflows/workflows/agent-environment-setup/platforms/gemini/skills/stitch/SKILL.md +87 -0
  100. package/workflows/workflows/agent-environment-setup/platforms/gemini/skills/stitch/evals/assertions.md +45 -0
  101. package/workflows/workflows/agent-environment-setup/platforms/gemini/skills/stitch/evals/evals.json +68 -0
  102. package/workflows/workflows/agent-environment-setup/platforms/gemini/skills/stitch/examples/01-new-screen.md +13 -0
  103. package/workflows/workflows/agent-environment-setup/platforms/gemini/skills/stitch/examples/02-update-existing-screen.md +13 -0
  104. package/workflows/workflows/agent-environment-setup/platforms/gemini/skills/stitch/examples/03-mobile-handoff.md +13 -0
  105. package/workflows/workflows/agent-environment-setup/platforms/gemini/skills/stitch/examples/04-prompt-enhancement.md +21 -0
  106. package/workflows/workflows/agent-environment-setup/platforms/gemini/skills/stitch/examples/05-design-sync-loop.md +16 -0
  107. package/workflows/workflows/agent-environment-setup/platforms/gemini/skills/stitch/references/implementation-patterns.md +20 -0
  108. package/workflows/workflows/agent-environment-setup/platforms/gemini/skills/stitch/references/platform-setup.md +46 -0
  109. package/workflows/workflows/agent-environment-setup/platforms/gemini/skills/stitch/references/update-diff-workflow.md +23 -0
  110. package/workflows/workflows/agent-environment-setup/platforms/gemini/workflows/create.md +3 -2
  111. package/workflows/workflows/agent-environment-setup/platforms/gemini/workflows/mobile.md +4 -3
  112. package/workflows/workflows/agent-environment-setup/shared/agents/frontend-specialist.md +10 -2
  113. package/workflows/workflows/agent-environment-setup/shared/agents/mobile-developer.md +6 -2
  114. package/workflows/workflows/agent-environment-setup/shared/workflows/create.md +3 -2
  115. package/workflows/workflows/agent-environment-setup/shared/workflows/mobile.md +4 -3
package/src/cli/core.ts CHANGED
@@ -4561,10 +4561,14 @@ function resolvePostmanMcpDefinitionPath({
4561
4561
  );
4562
4562
  }
4563
4563
 
4564
- function resolveStitchMcpDefinitionPath({ scope, cwd = process.cwd() }) {
4564
+ function resolveStitchMcpDefinitionPath({
4565
+ platform,
4566
+ scope,
4567
+ cwd = process.cwd(),
4568
+ }) {
4565
4569
  return path.join(
4566
4570
  resolveMcpRootPath({ scope, cwd }),
4567
- "antigravity",
4571
+ platform,
4568
4572
  "stitch.json",
4569
4573
  );
4570
4574
  }
@@ -5271,11 +5275,7 @@ async function removeGeneratedArtifactIfExists({ targetPath, dryRun = false }) {
5271
5275
  async function applyPostmanMcpForPlatform({
5272
5276
  platform,
5273
5277
  mcpScope,
5274
- apiKeyEnvVar,
5275
- mcpUrl,
5276
- includePostmanMcp = true,
5277
- stitchApiKeyEnvVar,
5278
- stitchMcpUrl,
5278
+ includePostmanMcp = false,
5279
5279
  includeStitchMcp = false,
5280
5280
  includeFoundryMcp = true,
5281
5281
  includePlaywrightMcp = false,
@@ -5287,12 +5287,11 @@ async function applyPostmanMcpForPlatform({
5287
5287
  const warnings = [];
5288
5288
  const foundryScope = mcpScope === "global" ? "global" : "project";
5289
5289
  const normalizedFoundryRuntime = normalizeMcpRuntime(foundryRuntime, "local");
5290
- const resolvedPostmanApiKey = normalizePostmanApiKey(
5291
- process.env[apiKeyEnvVar || POSTMAN_API_KEY_ENV_VAR],
5292
- );
5293
- const resolvedStitchApiKey = normalizePostmanApiKey(
5294
- process.env[stitchApiKeyEnvVar || STITCH_API_KEY_ENV_VAR],
5295
- );
5290
+ const cleanupLegacyServers = (servers) => {
5291
+ delete servers[POSTMAN_SKILL_ID];
5292
+ delete servers[STITCH_MCP_SERVER_ID];
5293
+ return servers;
5294
+ };
5296
5295
  let foundryDockerPort = DEFAULT_MCP_DOCKER_HOST_PORT;
5297
5296
  if (includeFoundryMcp && normalizedFoundryRuntime === "docker") {
5298
5297
  const runningPort = await resolveDockerContainerHostPort({
@@ -5324,13 +5323,7 @@ async function applyPostmanMcpForPlatform({
5324
5323
  !Array.isArray(next.mcpServers)
5325
5324
  ? { ...next.mcpServers }
5326
5325
  : {};
5327
- if (includePostmanMcp) {
5328
- mcpServers[POSTMAN_SKILL_ID] = buildGeminiPostmanServer({
5329
- apiKeyEnvVar,
5330
- apiKey: resolvedPostmanApiKey,
5331
- mcpUrl,
5332
- });
5333
- }
5326
+ cleanupLegacyServers(mcpServers);
5334
5327
  if (includeFoundryMcp) {
5335
5328
  mcpServers[FOUNDRY_MCP_SERVER_ID] = buildGeminiFoundryServer({
5336
5329
  scope: foundryScope,
@@ -5340,13 +5333,6 @@ async function applyPostmanMcpForPlatform({
5340
5333
  } else {
5341
5334
  delete mcpServers[FOUNDRY_MCP_SERVER_ID];
5342
5335
  }
5343
- if (includeStitchMcp) {
5344
- mcpServers[STITCH_MCP_SERVER_ID] = buildGeminiStitchServer({
5345
- apiKeyEnvVar: stitchApiKeyEnvVar,
5346
- apiKey: resolvedStitchApiKey,
5347
- mcpUrl: stitchMcpUrl,
5348
- });
5349
- }
5350
5336
  if (includePlaywrightMcp) {
5351
5337
  mcpServers[PLAYWRIGHT_MCP_SERVER_ID] = buildGeminiPlaywrightServer();
5352
5338
  }
@@ -5380,13 +5366,7 @@ async function applyPostmanMcpForPlatform({
5380
5366
  !Array.isArray(next.mcpServers)
5381
5367
  ? { ...next.mcpServers }
5382
5368
  : {};
5383
- if (includePostmanMcp) {
5384
- mcpServers[POSTMAN_SKILL_ID] = buildCopilotCliPostmanServer({
5385
- apiKeyEnvVar,
5386
- apiKey: resolvedPostmanApiKey,
5387
- mcpUrl,
5388
- });
5389
- }
5369
+ cleanupLegacyServers(mcpServers);
5390
5370
  if (includeFoundryMcp) {
5391
5371
  mcpServers[FOUNDRY_MCP_SERVER_ID] = buildCopilotCliFoundryServer({
5392
5372
  scope: foundryScope,
@@ -5410,13 +5390,7 @@ async function applyPostmanMcpForPlatform({
5410
5390
  !Array.isArray(next.servers)
5411
5391
  ? { ...next.servers }
5412
5392
  : {};
5413
- if (includePostmanMcp) {
5414
- servers[POSTMAN_SKILL_ID] = buildVsCodePostmanServer({
5415
- apiKeyEnvVar,
5416
- apiKey: resolvedPostmanApiKey,
5417
- mcpUrl,
5418
- });
5419
- }
5393
+ cleanupLegacyServers(servers);
5420
5394
  if (includeFoundryMcp) {
5421
5395
  servers[FOUNDRY_MCP_SERVER_ID] = buildVsCodeFoundryServer({
5422
5396
  scope: foundryScope,
@@ -5464,13 +5438,7 @@ async function applyPostmanMcpForPlatform({
5464
5438
  !Array.isArray(next.servers)
5465
5439
  ? { ...next.servers }
5466
5440
  : {};
5467
- if (includePostmanMcp) {
5468
- servers[POSTMAN_SKILL_ID] = buildVsCodePostmanServer({
5469
- apiKeyEnvVar,
5470
- apiKey: resolvedPostmanApiKey,
5471
- mcpUrl,
5472
- });
5473
- }
5441
+ cleanupLegacyServers(servers);
5474
5442
  if (includeFoundryMcp) {
5475
5443
  servers[FOUNDRY_MCP_SERVER_ID] = buildVsCodeFoundryServer({
5476
5444
  scope: foundryScope,
@@ -5513,6 +5481,11 @@ async function applyPostmanMcpForPlatform({
5513
5481
  } catch {
5514
5482
  // Best effort. Add will still run and becomes source of truth.
5515
5483
  }
5484
+ try {
5485
+ await execFile("codex", ["mcp", "remove", STITCH_MCP_SERVER_ID], { cwd });
5486
+ } catch {
5487
+ // Best effort. Add will still run and becomes source of truth.
5488
+ }
5516
5489
  try {
5517
5490
  await execFile("codex", ["mcp", "remove", FOUNDRY_MCP_SERVER_ID], {
5518
5491
  cwd,
@@ -5520,51 +5493,12 @@ async function applyPostmanMcpForPlatform({
5520
5493
  } catch {
5521
5494
  // Best effort. Add will still run and becomes source of truth.
5522
5495
  }
5523
-
5524
- if (includePostmanMcp) {
5525
- try {
5526
- await execFile(
5527
- "codex",
5528
- [
5529
- "mcp",
5530
- "add",
5531
- POSTMAN_SKILL_ID,
5532
- "--url",
5533
- mcpUrl,
5534
- "--bearer-token-env-var",
5535
- apiKeyEnvVar || POSTMAN_API_KEY_ENV_VAR,
5536
- ],
5537
- { cwd },
5538
- );
5539
- const postmanToken = normalizePostmanApiKey(
5540
- process.env[apiKeyEnvVar || POSTMAN_API_KEY_ENV_VAR],
5541
- );
5542
- const postmanPatch = await patchCodexPostmanHttpHeaders({
5543
- configPath: codexConfigPath,
5544
- mcpUrl,
5545
- bearerToken: postmanToken,
5546
- dryRun: false,
5547
- });
5548
- if (postmanPatch.action === "patched") {
5549
- warnings.push(
5550
- "Codex Postman MCP config patched to static Authorization header for startup reliability.",
5551
- );
5552
- }
5553
- if (postmanPatch.warnings?.length) {
5554
- warnings.push(...postmanPatch.warnings);
5555
- }
5556
- } catch (error) {
5557
- warnings.push(
5558
- `Failed to register Postman MCP via Codex CLI. Ensure 'codex' is installed and rerun. (${error.message})`,
5559
- );
5560
- return {
5561
- kind: "codex-cli",
5562
- scope: mcpScope,
5563
- path: codexConfigPath,
5564
- action: "failed",
5565
- warnings,
5566
- };
5567
- }
5496
+ try {
5497
+ await execFile("codex", ["mcp", "remove", PLAYWRIGHT_MCP_SERVER_ID], {
5498
+ cwd,
5499
+ });
5500
+ } catch {
5501
+ // Best effort. Add will still run and becomes source of truth.
5568
5502
  }
5569
5503
 
5570
5504
  if (includeFoundryMcp) {
@@ -5601,6 +5535,19 @@ async function applyPostmanMcpForPlatform({
5601
5535
  );
5602
5536
  }
5603
5537
  }
5538
+ if (includePlaywrightMcp) {
5539
+ try {
5540
+ await execFile(
5541
+ "codex",
5542
+ ["mcp", "add", PLAYWRIGHT_MCP_SERVER_ID, "--url", PLAYWRIGHT_MCP_URL],
5543
+ { cwd },
5544
+ );
5545
+ } catch (error) {
5546
+ warnings.push(
5547
+ `Failed to register ${PLAYWRIGHT_MCP_SERVER_ID} MCP via Codex CLI. Ensure 'codex' is installed and rerun. (${error.message})`,
5548
+ );
5549
+ }
5550
+ }
5604
5551
 
5605
5552
  return {
5606
5553
  kind: "codex-cli",
@@ -5626,6 +5573,7 @@ async function applyPostmanMcpForPlatform({
5626
5573
  !Array.isArray(next.mcpServers)
5627
5574
  ? { ...next.mcpServers }
5628
5575
  : {};
5576
+ cleanupLegacyServers(mcpServers);
5629
5577
  if (includeFoundryMcp) {
5630
5578
  if (normalizedFoundryRuntime === "docker") {
5631
5579
  mcpServers[FOUNDRY_MCP_SERVER_ID] = {
@@ -5668,7 +5616,7 @@ async function applyPostmanMcpForPlatform({
5668
5616
  path: null,
5669
5617
  action: "skipped",
5670
5618
  warnings: [
5671
- `Unsupported platform '${platform}' for Postman MCP installation.`,
5619
+ `Unsupported platform '${platform}' for Foundry MCP installation.`,
5672
5620
  ],
5673
5621
  };
5674
5622
  }
@@ -5716,13 +5664,28 @@ async function resolvePostmanInstallSelection({
5716
5664
  }
5717
5665
 
5718
5666
  const stitchRequested = Boolean(options.stitch);
5667
+ const playwrightRequested = Boolean(options.playwright);
5719
5668
  const postmanRequested =
5720
5669
  Boolean(options.postman) ||
5721
5670
  hasWorkspaceOption ||
5722
5671
  options.postmanMode !== undefined;
5672
+ const stitchEnabled = stitchRequested;
5673
+ const gatewayRequested = postmanRequested || stitchEnabled;
5674
+ const foundryMcpRequested = options.foundryMcp === true;
5675
+ const foundryMcpEnabled =
5676
+ options.foundryMcp === false && !gatewayRequested
5677
+ ? false
5678
+ : foundryMcpRequested || gatewayRequested;
5723
5679
  const foundryOnlyRequested =
5724
- options.foundryMcp === true && !postmanRequested && !stitchRequested;
5725
- const enabled = postmanRequested || stitchRequested || foundryOnlyRequested;
5680
+ foundryMcpRequested &&
5681
+ !postmanRequested &&
5682
+ !stitchRequested &&
5683
+ !playwrightRequested;
5684
+ const enabled =
5685
+ postmanRequested ||
5686
+ stitchRequested ||
5687
+ playwrightRequested ||
5688
+ foundryOnlyRequested;
5726
5689
  if (!enabled) return { enabled: false };
5727
5690
  const requestedPostmanMode = postmanRequested
5728
5691
  ? normalizePostmanMode(options.postmanMode, DEFAULT_POSTMAN_INSTALL_MODE)
@@ -5743,19 +5706,20 @@ async function resolvePostmanInstallSelection({
5743
5706
  : null;
5744
5707
  let mcpScope = requestedMcpScope?.scope || "project";
5745
5708
  const warnings = [];
5709
+ if (options.foundryMcp === false && gatewayRequested) {
5710
+ warnings.push(
5711
+ "Ignoring --no-foundry-mcp because Postman/Stitch now route through the Cubis Foundry MCP gateway.",
5712
+ );
5713
+ }
5746
5714
  if (requestedMcpScope?.warning) {
5747
5715
  warnings.push(requestedMcpScope.warning);
5748
5716
  }
5749
- const stitchEnabled =
5750
- stitchRequested ||
5751
- (platform === "antigravity" &&
5752
- options.stitchDefaultForAntigravity !== false);
5753
5717
  const envStitchApiKey = normalizePostmanApiKey(
5754
5718
  process.env[STITCH_API_KEY_ENV_VAR],
5755
5719
  );
5756
5720
  const requestedRuntime = normalizeMcpRuntime(
5757
5721
  options.mcpRuntime,
5758
- DEFAULT_MCP_RUNTIME,
5722
+ foundryMcpEnabled ? DEFAULT_MCP_RUNTIME : "local",
5759
5723
  );
5760
5724
  const requestedFallback = normalizeMcpFallback(
5761
5725
  options.mcpFallback,
@@ -5768,8 +5732,8 @@ async function resolvePostmanInstallSelection({
5768
5732
  DEFAULT_MCP_UPDATE_POLICY,
5769
5733
  );
5770
5734
  const mcpBuildLocal = Boolean(options.mcpBuildLocal);
5771
- const mcpToolSync = options.mcpToolSync !== false;
5772
- const foundryMcpEnabled = options.foundryMcp !== false;
5735
+ const mcpToolSync =
5736
+ options.mcpToolSync !== false && (postmanRequested || stitchEnabled);
5773
5737
 
5774
5738
  const canPrompt =
5775
5739
  !options.yes && !options.dryRun && !process.env.CI && process.stdin.isTTY;
@@ -5783,10 +5747,10 @@ async function resolvePostmanInstallSelection({
5783
5747
  workspaceSelectionSource = "interactive";
5784
5748
  }
5785
5749
 
5786
- let effectiveRuntime = requestedRuntime;
5787
- let runtimeSkipped = false;
5788
- let dockerImageAction = "not-requested";
5789
- if (requestedRuntime === "docker") {
5750
+ let effectiveRuntime = foundryMcpEnabled ? requestedRuntime : null;
5751
+ let runtimeSkipped = !foundryMcpEnabled;
5752
+ let dockerImageAction = foundryMcpEnabled ? "not-requested" : "not-needed";
5753
+ if (foundryMcpEnabled && requestedRuntime === "docker") {
5790
5754
  const dockerAvailable = await checkDockerAvailable({ cwd });
5791
5755
  if (!dockerAvailable) {
5792
5756
  if (requestedFallback === "fail") {
@@ -5871,11 +5835,12 @@ async function resolvePostmanInstallSelection({
5871
5835
  generatedAt: new Date().toISOString(),
5872
5836
  mcp: {
5873
5837
  scope: mcpScope,
5874
- server: postmanRequested
5875
- ? POSTMAN_SKILL_ID
5876
- : stitchEnabled
5877
- ? STITCH_MCP_SERVER_ID
5878
- : FOUNDRY_MCP_SERVER_ID,
5838
+ server:
5839
+ foundryMcpEnabled || gatewayRequested
5840
+ ? FOUNDRY_MCP_SERVER_ID
5841
+ : playwrightRequested
5842
+ ? PLAYWRIGHT_MCP_SERVER_ID
5843
+ : FOUNDRY_MCP_SERVER_ID,
5879
5844
  platform,
5880
5845
  runtime: requestedRuntime,
5881
5846
  fallback: requestedFallback,
@@ -5918,12 +5883,20 @@ async function resolvePostmanInstallSelection({
5918
5883
  mcpUrl: STITCH_MCP_URL,
5919
5884
  };
5920
5885
  }
5886
+ if (playwrightRequested) {
5887
+ cbxConfig.playwright = {
5888
+ enabled: true,
5889
+ server: PLAYWRIGHT_MCP_SERVER_ID,
5890
+ mcpUrl: PLAYWRIGHT_MCP_URL,
5891
+ };
5892
+ }
5921
5893
 
5922
5894
  return {
5923
5895
  enabled: true,
5924
5896
  postmanEnabled: postmanRequested,
5925
5897
  apiKeySource,
5926
5898
  stitchEnabled,
5899
+ playwrightEnabled: playwrightRequested,
5927
5900
  stitchApiKeySource,
5928
5901
  mcpRuntime: requestedRuntime,
5929
5902
  effectiveMcpRuntime: runtimeSkipped ? null : effectiveRuntime,
@@ -5951,6 +5924,7 @@ async function configurePostmanInstallArtifacts({
5951
5924
  profilePaths,
5952
5925
  postmanSelection,
5953
5926
  overwrite = false,
5927
+ persistCredentials = true,
5954
5928
  dryRun = false,
5955
5929
  cwd = process.cwd(),
5956
5930
  }) {
@@ -6123,50 +6097,30 @@ async function configurePostmanInstallArtifacts({
6123
6097
  gitIgnoreResults.push(mcpIgnore);
6124
6098
  }
6125
6099
 
6126
- let mcpDefinitionPath = null;
6127
- let mcpDefinitionResult = null;
6100
+ const legacyDefinitionCleanupResults = [];
6128
6101
  if (shouldInstallPostman) {
6129
- mcpDefinitionPath = resolvePostmanMcpDefinitionPath({
6130
- platform,
6131
- scope: postmanSelection.mcpScope,
6132
- cwd,
6133
- });
6134
- const mcpDefinitionContent = `${JSON.stringify(
6135
- buildPostmanMcpDefinition({
6136
- apiKeyEnvVar: effectiveApiKeyEnvVar,
6137
- apiKey: envApiKey,
6138
- mcpUrl: effectiveMcpUrl,
6102
+ legacyDefinitionCleanupResults.push(
6103
+ await removeGeneratedArtifactIfExists({
6104
+ targetPath: resolvePostmanMcpDefinitionPath({
6105
+ platform,
6106
+ scope: postmanSelection.mcpScope,
6107
+ cwd,
6108
+ }),
6109
+ dryRun,
6139
6110
  }),
6140
- null,
6141
- 2,
6142
- )}\n`;
6143
- mcpDefinitionResult = await writeGeneratedArtifact({
6144
- destination: mcpDefinitionPath,
6145
- content: mcpDefinitionContent,
6146
- dryRun,
6147
- });
6111
+ );
6148
6112
  }
6149
- let stitchMcpDefinitionPath = null;
6150
- let stitchMcpDefinitionResult = null;
6151
6113
  if (shouldInstallStitch) {
6152
- stitchMcpDefinitionPath = resolveStitchMcpDefinitionPath({
6153
- scope: postmanSelection.mcpScope,
6154
- cwd,
6155
- });
6156
- const stitchMcpDefinitionContent = `${JSON.stringify(
6157
- buildStitchMcpDefinition({
6158
- apiKeyEnvVar: effectiveStitchApiKeyEnvVar,
6159
- apiKey: envStitchApiKey,
6160
- mcpUrl: effectiveStitchMcpUrl,
6114
+ legacyDefinitionCleanupResults.push(
6115
+ await removeGeneratedArtifactIfExists({
6116
+ targetPath: resolveStitchMcpDefinitionPath({
6117
+ platform,
6118
+ scope: postmanSelection.mcpScope,
6119
+ cwd,
6120
+ }),
6121
+ dryRun,
6161
6122
  }),
6162
- null,
6163
- 2,
6164
- )}\n`;
6165
- stitchMcpDefinitionResult = await writeGeneratedArtifact({
6166
- destination: stitchMcpDefinitionPath,
6167
- content: stitchMcpDefinitionContent,
6168
- dryRun,
6169
- });
6123
+ );
6170
6124
  }
6171
6125
 
6172
6126
  const mcpRuntimeResult = postmanSelection.runtimeSkipped
@@ -6229,6 +6183,28 @@ async function configurePostmanInstallArtifacts({
6229
6183
  dryRun,
6230
6184
  })
6231
6185
  : null;
6186
+ const credentialEnvVarNames = [];
6187
+ if (persistCredentials && shouldInstallPostman && effectiveApiKeySource === "env") {
6188
+ credentialEnvVarNames.push(
6189
+ effectiveApiKeyEnvVar || POSTMAN_API_KEY_ENV_VAR,
6190
+ );
6191
+ }
6192
+ if (
6193
+ persistCredentials &&
6194
+ shouldInstallStitch &&
6195
+ effectiveStitchApiKeySource === "env"
6196
+ ) {
6197
+ credentialEnvVarNames.push(
6198
+ effectiveStitchApiKeyEnvVar || STITCH_API_KEY_ENV_VAR,
6199
+ );
6200
+ }
6201
+ const persistedCredentials =
6202
+ credentialEnvVarNames.length > 0
6203
+ ? await persistManagedCredentialsEnv({
6204
+ envVarNames: [...new Set(credentialEnvVarNames)],
6205
+ dryRun,
6206
+ })
6207
+ : null;
6232
6208
 
6233
6209
  return {
6234
6210
  enabled: true,
@@ -6243,6 +6219,7 @@ async function configurePostmanInstallArtifacts({
6243
6219
  mcpToolSync: postmanSelection.mcpToolSync,
6244
6220
  foundryMcpEnabled: postmanSelection.foundryMcpEnabled,
6245
6221
  postmanEnabled: shouldInstallPostman,
6222
+ playwrightEnabled: Boolean(postmanSelection.playwrightEnabled),
6246
6223
  postmanMode:
6247
6224
  shouldInstallPostman && effectiveMcpUrl
6248
6225
  ? resolvePostmanModeFromUrl(
@@ -6251,6 +6228,9 @@ async function configurePostmanInstallArtifacts({
6251
6228
  )
6252
6229
  : null,
6253
6230
  postmanMcpUrl: shouldInstallPostman ? effectiveMcpUrl : null,
6231
+ playwrightMcpUrl: postmanSelection.playwrightEnabled
6232
+ ? PLAYWRIGHT_MCP_URL
6233
+ : null,
6254
6234
  apiKeySource: effectiveApiKeySource,
6255
6235
  stitchApiKeySource: effectiveStitchApiKeySource,
6256
6236
  defaultWorkspaceId: effectiveDefaultWorkspaceId,
@@ -6258,13 +6238,11 @@ async function configurePostmanInstallArtifacts({
6258
6238
  cbxConfigPath: postmanSelection.cbxConfigPath,
6259
6239
  cbxConfigResult,
6260
6240
  gitIgnoreResults,
6261
- mcpDefinitionPath,
6262
- mcpDefinitionResult,
6263
- stitchMcpDefinitionPath,
6264
- stitchMcpDefinitionResult,
6241
+ legacyDefinitionCleanupResults,
6265
6242
  mcpRuntimeResult,
6266
6243
  mcpCatalogSyncResults,
6267
6244
  legacySkillMcpCleanup,
6245
+ persistedCredentials,
6268
6246
  };
6269
6247
  }
6270
6248
 
@@ -6291,14 +6269,32 @@ async function applyPostmanConfigArtifacts({
6291
6269
  cwd = process.cwd(),
6292
6270
  }) {
6293
6271
  const warnings = [];
6294
- const postmanState = ensureCredentialServiceState(configValue, "postman");
6272
+ const storedPostmanState = parseStoredPostmanConfig(configValue);
6273
+ const postmanEnabled = Boolean(storedPostmanState);
6274
+ const postmanState =
6275
+ storedPostmanState ||
6276
+ parseStoredCredentialServiceConfig({ service: "postman", rawService: {} });
6295
6277
  const stitchState = parseStoredStitchConfig(configValue);
6296
- const postmanApiKeyEnvVar =
6297
- normalizePostmanApiKey(postmanState.apiKeyEnvVar) ||
6298
- POSTMAN_API_KEY_ENV_VAR;
6299
- const postmanMcpUrl = postmanState.mcpUrl || POSTMAN_MCP_URL;
6278
+ const postmanApiKeyEnvVar = postmanEnabled
6279
+ ? normalizePostmanApiKey(postmanState.apiKeyEnvVar) ||
6280
+ POSTMAN_API_KEY_ENV_VAR
6281
+ : POSTMAN_API_KEY_ENV_VAR;
6282
+ const postmanMcpUrl = postmanEnabled
6283
+ ? postmanState.mcpUrl || POSTMAN_MCP_URL
6284
+ : POSTMAN_MCP_URL;
6300
6285
  const stitchEnabled = Boolean(stitchState);
6301
- const playwrightEnabled = Boolean(configValue?.playwright);
6286
+ const playwrightConfig =
6287
+ configValue?.playwright &&
6288
+ typeof configValue.playwright === "object" &&
6289
+ !Array.isArray(configValue.playwright)
6290
+ ? configValue.playwright
6291
+ : null;
6292
+ const playwrightEnabled = Boolean(
6293
+ playwrightConfig?.enabled ?? configValue?.playwright,
6294
+ );
6295
+ const playwrightMcpUrl =
6296
+ String(playwrightConfig?.mcpUrl || PLAYWRIGHT_MCP_URL).trim() ||
6297
+ PLAYWRIGHT_MCP_URL;
6302
6298
  const stitchApiKeyEnvVar =
6303
6299
  normalizePostmanApiKey(stitchState?.apiKeyEnvVar) || STITCH_API_KEY_ENV_VAR;
6304
6300
  const stitchMcpUrl = stitchState?.mcpUrl || STITCH_MCP_URL;
@@ -6306,54 +6302,31 @@ async function applyPostmanConfigArtifacts({
6306
6302
  configValue?.mcp?.effectiveRuntime || configValue?.mcp?.runtime,
6307
6303
  "local",
6308
6304
  );
6309
- const resolvedPostmanApiKey = normalizePostmanApiKey(
6310
- process.env[postmanApiKeyEnvVar],
6311
- );
6312
- const resolvedStitchApiKey = normalizePostmanApiKey(
6313
- process.env[stitchApiKeyEnvVar],
6314
- );
6315
-
6316
- const mcpDefinitionPath = resolvePostmanMcpDefinitionPath({
6317
- platform,
6318
- scope: mcpScope,
6319
- cwd,
6320
- });
6321
- const mcpDefinitionContent = `${JSON.stringify(
6322
- buildPostmanMcpDefinition({
6323
- apiKeyEnvVar: postmanApiKeyEnvVar,
6324
- apiKey: resolvedPostmanApiKey,
6325
- mcpUrl: postmanMcpUrl,
6326
- }),
6327
- null,
6328
- 2,
6329
- )}\n`;
6330
- const mcpDefinitionResult = await writeGeneratedArtifact({
6331
- destination: mcpDefinitionPath,
6332
- content: mcpDefinitionContent,
6333
- dryRun,
6334
- });
6305
+ const legacyDefinitionCleanupResults = [];
6306
+ if (postmanEnabled && platform) {
6307
+ legacyDefinitionCleanupResults.push(
6308
+ await removeGeneratedArtifactIfExists({
6309
+ targetPath: resolvePostmanMcpDefinitionPath({
6310
+ platform,
6311
+ scope: mcpScope,
6312
+ cwd,
6313
+ }),
6314
+ dryRun,
6315
+ }),
6316
+ );
6317
+ }
6335
6318
 
6336
- let stitchMcpDefinitionPath = null;
6337
- let stitchMcpDefinitionResult = null;
6338
6319
  if (stitchEnabled) {
6339
- stitchMcpDefinitionPath = resolveStitchMcpDefinitionPath({
6340
- scope: mcpScope,
6341
- cwd,
6342
- });
6343
- const stitchMcpDefinitionContent = `${JSON.stringify(
6344
- buildStitchMcpDefinition({
6345
- apiKeyEnvVar: stitchApiKeyEnvVar,
6346
- apiKey: resolvedStitchApiKey,
6347
- mcpUrl: stitchMcpUrl,
6320
+ legacyDefinitionCleanupResults.push(
6321
+ await removeGeneratedArtifactIfExists({
6322
+ targetPath: resolveStitchMcpDefinitionPath({
6323
+ platform,
6324
+ scope: mcpScope,
6325
+ cwd,
6326
+ }),
6327
+ dryRun,
6348
6328
  }),
6349
- null,
6350
- 2,
6351
- )}\n`;
6352
- stitchMcpDefinitionResult = await writeGeneratedArtifact({
6353
- destination: stitchMcpDefinitionPath,
6354
- content: stitchMcpDefinitionContent,
6355
- dryRun,
6356
- });
6329
+ );
6357
6330
  }
6358
6331
 
6359
6332
  let mcpRuntimeResult = null;
@@ -6367,6 +6340,7 @@ async function applyPostmanConfigArtifacts({
6367
6340
  mcpScope,
6368
6341
  apiKeyEnvVar: postmanApiKeyEnvVar,
6369
6342
  mcpUrl: postmanMcpUrl,
6343
+ includePostmanMcp: postmanEnabled,
6370
6344
  stitchApiKeyEnvVar,
6371
6345
  stitchMcpUrl,
6372
6346
  includeStitchMcp: stitchEnabled,
@@ -6380,10 +6354,10 @@ async function applyPostmanConfigArtifacts({
6380
6354
  }
6381
6355
 
6382
6356
  return {
6383
- mcpDefinitionPath,
6384
- mcpDefinitionResult,
6385
- stitchMcpDefinitionPath,
6386
- stitchMcpDefinitionResult,
6357
+ postmanEnabled,
6358
+ playwrightEnabled,
6359
+ playwrightMcpUrl: playwrightEnabled ? playwrightMcpUrl : null,
6360
+ legacyDefinitionCleanupResults,
6387
6361
  mcpRuntimeResult,
6388
6362
  warnings,
6389
6363
  };
@@ -7361,11 +7335,16 @@ function printPostmanSetupSummary({ postmanSetup }) {
7361
7335
 
7362
7336
  console.log("\nMCP setup:");
7363
7337
  console.log(`- MCP scope: ${postmanSetup.mcpScope}`);
7338
+ if (postmanSetup.playwrightEnabled) {
7339
+ console.log(
7340
+ `- Playwright MCP: enabled (${postmanSetup.playwrightMcpUrl || PLAYWRIGHT_MCP_URL})`,
7341
+ );
7342
+ }
7364
7343
  if (postmanSetup.postmanEnabled && postmanSetup.postmanMode) {
7365
7344
  console.log(`- Postman mode: ${postmanSetup.postmanMode}`);
7366
7345
  }
7367
7346
  if (postmanSetup.postmanEnabled && postmanSetup.postmanMcpUrl) {
7368
- console.log(`- Postman MCP URL: ${postmanSetup.postmanMcpUrl}`);
7347
+ console.log(`- Postman upstream MCP URL: ${postmanSetup.postmanMcpUrl}`);
7369
7348
  }
7370
7349
  console.log(
7371
7350
  `- Config file: ${postmanSetup.cbxConfigResult.action} (${postmanSetup.cbxConfigPath})`,
@@ -7385,7 +7364,7 @@ function printPostmanSetupSummary({ postmanSetup }) {
7385
7364
  `- MCP tool sync: ${postmanSetup.mcpToolSync ? "enabled" : "disabled"}`,
7386
7365
  );
7387
7366
  console.log(
7388
- `- Foundry MCP side-by-side: ${postmanSetup.foundryMcpEnabled ? (postmanSetup.effectiveMcpRuntime === "docker" ? "enabled (docker endpoint)" : "enabled (cbx mcp serve)") : "disabled"}`,
7367
+ `- Foundry MCP gateway: ${postmanSetup.foundryMcpEnabled ? (postmanSetup.effectiveMcpRuntime === "docker" ? "enabled (docker endpoint)" : "enabled (cbx mcp serve)") : "disabled"}`,
7389
7368
  );
7390
7369
  if (postmanSetup.postmanEnabled) {
7391
7370
  console.log(`- Postman API key source: ${postmanSetup.apiKeySource}`);
@@ -7403,17 +7382,9 @@ function printPostmanSetupSummary({ postmanSetup }) {
7403
7382
  `- .gitignore (${ignoreResult.filePath}): ${ignoreResult.action}`,
7404
7383
  );
7405
7384
  }
7406
- if (postmanSetup.mcpDefinitionPath && postmanSetup.mcpDefinitionResult) {
7385
+ for (const cleanupResult of postmanSetup.legacyDefinitionCleanupResults || []) {
7407
7386
  console.log(
7408
- `- Managed MCP definition (${postmanSetup.mcpDefinitionPath}): ${postmanSetup.mcpDefinitionResult.action}`,
7409
- );
7410
- }
7411
- if (
7412
- postmanSetup.stitchMcpDefinitionPath &&
7413
- postmanSetup.stitchMcpDefinitionResult
7414
- ) {
7415
- console.log(
7416
- `- Managed Stitch MCP definition (${postmanSetup.stitchMcpDefinitionPath}): ${postmanSetup.stitchMcpDefinitionResult.action}`,
7387
+ `- Legacy direct MCP cleanup (${cleanupResult.path}): ${cleanupResult.action}`,
7417
7388
  );
7418
7389
  }
7419
7390
  if (postmanSetup.mcpRuntimeResult) {
@@ -7434,6 +7405,19 @@ function printPostmanSetupSummary({ postmanSetup }) {
7434
7405
  }
7435
7406
  }
7436
7407
  }
7408
+ if (postmanSetup.persistedCredentials) {
7409
+ console.log(
7410
+ `- Credential vault (${postmanSetup.persistedCredentials.envPath}): ${postmanSetup.persistedCredentials.action}`,
7411
+ );
7412
+ console.log(
7413
+ `- Credential vars: ${postmanSetup.persistedCredentials.persisted.length > 0 ? postmanSetup.persistedCredentials.persisted.join(", ") : "(none)"}`,
7414
+ );
7415
+ if (postmanSetup.persistedCredentials.missing.length > 0) {
7416
+ console.log(
7417
+ `- Missing credential vars: ${postmanSetup.persistedCredentials.missing.join(", ")}`,
7418
+ );
7419
+ }
7420
+ }
7437
7421
  if (postmanSetup.legacySkillMcpCleanup) {
7438
7422
  console.log(
7439
7423
  `- Legacy skill mcp.json cleanup (${postmanSetup.legacySkillMcpCleanup.path}): ${postmanSetup.legacySkillMcpCleanup.action}`,
@@ -7865,7 +7849,7 @@ function withInstallOptions(command) {
7865
7849
  .option("--overwrite", "overwrite existing files")
7866
7850
  .option(
7867
7851
  "--postman",
7868
- "optional: install Postman skill and generate cbx_config.json",
7852
+ "optional: configure Postman profiles and gateway-backed Foundry MCP wiring",
7869
7853
  )
7870
7854
  .option(
7871
7855
  "--postman-mode <mode>",
@@ -7873,7 +7857,11 @@ function withInstallOptions(command) {
7873
7857
  )
7874
7858
  .option(
7875
7859
  "--stitch",
7876
- "optional: include Stitch MCP profile/config alongside Postman",
7860
+ "optional: configure Stitch profiles and gateway-backed Foundry MCP wiring",
7861
+ )
7862
+ .option(
7863
+ "--playwright",
7864
+ "optional: include Playwright MCP server wiring",
7877
7865
  )
7878
7866
  .option(
7879
7867
  "--postman-api-key <key>",
@@ -7922,7 +7910,7 @@ function withInstallOptions(command) {
7922
7910
  .option("--no-mcp-tool-sync", "disable automatic MCP tool catalog sync")
7923
7911
  .option(
7924
7912
  "--no-foundry-mcp",
7925
- "disable side-by-side cubis-foundry MCP registration during --postman setup",
7913
+ "deprecated: Postman/Stitch always use Cubis Foundry MCP gateway wiring",
7926
7914
  )
7927
7915
  .option(
7928
7916
  "--terminal-integration",
@@ -7934,7 +7922,7 @@ function withInstallOptions(command) {
7934
7922
  )
7935
7923
  .option(
7936
7924
  "--skill-profile <profile>",
7937
- "skill install profile: core|web-backend|full (default: core)",
7925
+ "skill install profile: core|web-backend|full",
7938
7926
  DEFAULT_SKILL_PROFILE,
7939
7927
  )
7940
7928
  .option("--all-skills", "alias for --skill-profile full")
@@ -8343,6 +8331,7 @@ async function performWorkflowInstall(
8343
8331
  profilePaths: installResult.profilePaths,
8344
8332
  postmanSelection,
8345
8333
  overwrite: Boolean(options.overwrite),
8334
+ persistCredentials: !options.initWizardMode,
8346
8335
  dryRun,
8347
8336
  cwd,
8348
8337
  });
@@ -9263,14 +9252,16 @@ async function runWorkflowRemoveAll(options) {
9263
9252
  dryRun,
9264
9253
  records: removedRecords,
9265
9254
  });
9266
- if (platform === "antigravity") {
9267
- await removePathRecord({
9268
- targetPath: resolveStitchMcpDefinitionPath({ scope, cwd }),
9269
- category: `${platform}/${scope}/stitch-mcp-definition`,
9270
- dryRun,
9271
- records: removedRecords,
9272
- });
9273
- }
9255
+ await removePathRecord({
9256
+ targetPath: resolveStitchMcpDefinitionPath({
9257
+ platform,
9258
+ scope,
9259
+ cwd,
9260
+ }),
9261
+ category: `${platform}/${scope}/stitch-mcp-definition`,
9262
+ dryRun,
9263
+ records: removedRecords,
9264
+ });
9274
9265
 
9275
9266
  const runtimeResults = await removePlatformMcpRuntimeTargets({
9276
9267
  platform,
@@ -9592,7 +9583,7 @@ function prepareConfigDocument(existingValue, { scope, generatedBy }) {
9592
9583
  if (!next.mcp || typeof next.mcp !== "object" || Array.isArray(next.mcp))
9593
9584
  next.mcp = {};
9594
9585
  next.mcp.scope = scope;
9595
- if (!next.mcp.server) next.mcp.server = POSTMAN_SKILL_ID;
9586
+ if (!next.mcp.server) next.mcp.server = FOUNDRY_MCP_SERVER_ID;
9596
9587
  return next;
9597
9588
  }
9598
9589
 
@@ -9879,30 +9870,160 @@ function migrateInlineCredentialsInConfig(configValue) {
9879
9870
  };
9880
9871
  }
9881
9872
 
9882
- async function collectInlineHeaderFindings({ scope, cwd = process.cwd() }) {
9883
- const findings = [];
9884
- const stitchDefinitionPath = resolveStitchMcpDefinitionPath({ scope, cwd });
9885
- const geminiSettingsPath =
9873
+ function resolveCredentialLeakScanTargets({ scope, cwd = process.cwd() }) {
9874
+ const workspaceRoot = findWorkspaceRoot(cwd);
9875
+ const targets = new Set([
9876
+ resolveLegacyPostmanConfigPath({ scope, cwd }),
9886
9877
  scope === "global"
9887
9878
  ? path.join(os.homedir(), ".gemini", "settings.json")
9888
- : path.join(findWorkspaceRoot(cwd), ".gemini", "settings.json");
9879
+ : path.join(workspaceRoot, ".gemini", "settings.json"),
9880
+ scope === "global"
9881
+ ? path.join(os.homedir(), ".claude", "mcp.json")
9882
+ : path.join(workspaceRoot, ".mcp.json"),
9883
+ scope === "global"
9884
+ ? path.join(os.homedir(), ".copilot", "mcp-config.json")
9885
+ : path.join(workspaceRoot, ".vscode", "mcp.json"),
9886
+ ]);
9889
9887
 
9890
- const scanFile = async (filePath) => {
9891
- if (!(await pathExists(filePath))) return;
9892
- const raw = await readFile(filePath, "utf8");
9893
- const unsafeStitchHeader =
9894
- /X-Goog-Api-Key:(?!\s*\$\{[A-Za-z_][A-Za-z0-9_]*\})\s*[^"\n]+/i;
9895
- const unsafeBearerHeader = /"Authorization"\s*:\s*"Bearer\s+(?!\$\{)[^"]+/i;
9896
- if (unsafeStitchHeader.test(raw) || unsafeBearerHeader.test(raw)) {
9897
- findings.push(filePath);
9888
+ if (scope === "global") {
9889
+ targets.add(path.join(os.homedir(), ".codex", "config.toml"));
9890
+ }
9891
+
9892
+ for (const platform of Object.keys(WORKFLOW_PROFILES)) {
9893
+ targets.add(resolvePostmanMcpDefinitionPath({ platform, scope, cwd }));
9894
+ targets.add(resolveStitchMcpDefinitionPath({ platform, scope, cwd }));
9895
+ }
9896
+
9897
+ return [...targets];
9898
+ }
9899
+
9900
+ function collectCredentialLeakMatches(raw) {
9901
+ const matches = [];
9902
+ const patterns = [
9903
+ {
9904
+ id: "inline-apiKey-field",
9905
+ pattern: /"apiKey"\s*:\s*"(?!\$\{)[^"]+/i,
9906
+ },
9907
+ {
9908
+ id: "inline-bearer-header-json",
9909
+ pattern: /"Authorization"\s*:\s*"Bearer\s+(?!\$\{)[^"]+/i,
9910
+ },
9911
+ {
9912
+ id: "inline-bearer-header-toml",
9913
+ pattern:
9914
+ /http_headers\s*=\s*\{[^}]*Authorization\s*=\s*"Bearer\s+(?!\$\{)[^"]+/is,
9915
+ },
9916
+ {
9917
+ id: "inline-stitch-header-arg",
9918
+ pattern: /X-Goog-Api-Key:(?!\s*\$\{[A-Za-z_][A-Za-z0-9_]*\})\s*[^"\n]+/i,
9919
+ },
9920
+ {
9921
+ id: "inline-stitch-header-json",
9922
+ pattern: /"X-Goog-Api-Key"\s*:\s*"(?!\$\{)[^"]+/i,
9923
+ },
9924
+ ];
9925
+
9926
+ for (const { id, pattern } of patterns) {
9927
+ if (pattern.test(raw)) {
9928
+ matches.push(id);
9898
9929
  }
9899
- };
9930
+ }
9931
+
9932
+ return matches;
9933
+ }
9900
9934
 
9901
- await scanFile(stitchDefinitionPath);
9902
- await scanFile(geminiSettingsPath);
9935
+ async function collectCredentialLeakFindings({ scope, cwd = process.cwd() }) {
9936
+ const findings = [];
9937
+ for (const filePath of resolveCredentialLeakScanTargets({ scope, cwd })) {
9938
+ if (!(await pathExists(filePath))) continue;
9939
+ const raw = await readFile(filePath, "utf8");
9940
+ const matches = collectCredentialLeakMatches(raw);
9941
+ if (matches.length > 0) {
9942
+ findings.push({ filePath, matches });
9943
+ }
9944
+ }
9903
9945
  return findings;
9904
9946
  }
9905
9947
 
9948
+ async function cleanupLegacyDirectCredentialArtifacts({
9949
+ scope,
9950
+ dryRun = false,
9951
+ cwd = process.cwd(),
9952
+ }) {
9953
+ const workspaceRoot = findWorkspaceRoot(cwd);
9954
+ const cleanupResults = [];
9955
+ const legacyServerIds = [POSTMAN_SKILL_ID, STITCH_MCP_SERVER_ID];
9956
+
9957
+ cleanupResults.push(
9958
+ await removeMcpRuntimeEntriesJson({
9959
+ filePath:
9960
+ scope === "global"
9961
+ ? path.join(os.homedir(), ".gemini", "settings.json")
9962
+ : path.join(workspaceRoot, ".gemini", "settings.json"),
9963
+ keyName: "mcpServers",
9964
+ serverIds: legacyServerIds,
9965
+ dryRun,
9966
+ }),
9967
+ );
9968
+ cleanupResults.push(
9969
+ await removeMcpRuntimeEntriesJson({
9970
+ filePath:
9971
+ scope === "global"
9972
+ ? path.join(os.homedir(), ".claude", "mcp.json")
9973
+ : path.join(workspaceRoot, ".mcp.json"),
9974
+ keyName: "mcpServers",
9975
+ serverIds: legacyServerIds,
9976
+ dryRun,
9977
+ }),
9978
+ );
9979
+ if (scope === "global") {
9980
+ cleanupResults.push(
9981
+ await removeMcpRuntimeEntriesJson({
9982
+ filePath: path.join(os.homedir(), ".copilot", "mcp-config.json"),
9983
+ keyName: "mcpServers",
9984
+ serverIds: legacyServerIds,
9985
+ dryRun,
9986
+ }),
9987
+ );
9988
+ cleanupResults.push(
9989
+ await removeMcpRuntimeEntriesCodexToml({
9990
+ filePath: path.join(os.homedir(), ".codex", "config.toml"),
9991
+ serverIds: legacyServerIds,
9992
+ dryRun,
9993
+ cwd,
9994
+ }),
9995
+ );
9996
+ } else {
9997
+ cleanupResults.push(
9998
+ await removeMcpRuntimeEntriesJson({
9999
+ filePath: path.join(workspaceRoot, ".vscode", "mcp.json"),
10000
+ keyName: "servers",
10001
+ serverIds: legacyServerIds,
10002
+ dryRun,
10003
+ }),
10004
+ );
10005
+ }
10006
+
10007
+ for (const platform of Object.keys(WORKFLOW_PROFILES)) {
10008
+ cleanupResults.push(
10009
+ await removeGeneratedArtifactIfExists({
10010
+ targetPath: resolvePostmanMcpDefinitionPath({ platform, scope, cwd }),
10011
+ dryRun,
10012
+ }),
10013
+ );
10014
+ cleanupResults.push(
10015
+ await removeGeneratedArtifactIfExists({
10016
+ targetPath: resolveStitchMcpDefinitionPath({ platform, scope, cwd }),
10017
+ dryRun,
10018
+ }),
10019
+ );
10020
+ }
10021
+
10022
+ return cleanupResults.filter(
10023
+ (item) => item.action !== "missing" && item.action !== "unchanged",
10024
+ );
10025
+ }
10026
+
9906
10027
  async function runWorkflowConfigKeysList(options) {
9907
10028
  try {
9908
10029
  const opts = resolveActionOptions(options);
@@ -10178,6 +10299,7 @@ async function runWorkflowConfigKeysMigrateInline(options) {
10178
10299
  const scopeArg = readCliOptionFromArgv("--scope");
10179
10300
  const scope = normalizeMcpScope(scopeArg ?? opts.scope, "global");
10180
10301
  const dryRun = hasCliFlag("--dry-run") || Boolean(opts.dryRun);
10302
+ await loadManagedCredentialsEnv();
10181
10303
 
10182
10304
  const { configPath, existing, existingValue } = await loadConfigForScope({
10183
10305
  scope,
@@ -10194,6 +10316,22 @@ async function runWorkflowConfigKeysMigrateInline(options) {
10194
10316
  existingExists: existing.exists,
10195
10317
  dryRun,
10196
10318
  });
10319
+ const cleanupResults = await cleanupLegacyDirectCredentialArtifacts({
10320
+ scope,
10321
+ dryRun,
10322
+ cwd,
10323
+ });
10324
+ const platform = normalizePlatform(result.next?.mcp?.platform);
10325
+ const secureArtifacts =
10326
+ platform && WORKFLOW_PROFILES[platform]
10327
+ ? await applyPostmanConfigArtifacts({
10328
+ platform,
10329
+ mcpScope: resolveMcpScopeFromConfigDocument(result.next, scope),
10330
+ configValue: result.next,
10331
+ dryRun,
10332
+ cwd,
10333
+ })
10334
+ : null;
10197
10335
 
10198
10336
  console.log(`Config file: ${configPath}`);
10199
10337
  console.log(`Action: ${action}`);
@@ -10209,6 +10347,21 @@ async function runWorkflowConfigKeysMigrateInline(options) {
10209
10347
  console.log(`- ${envVar}`);
10210
10348
  }
10211
10349
  }
10350
+ console.log(`Legacy direct MCP cleanup actions: ${cleanupResults.length}`);
10351
+ for (const cleanup of cleanupResults) {
10352
+ console.log(`- ${cleanup.action} ${cleanup.path}`);
10353
+ }
10354
+ if (secureArtifacts?.mcpRuntimeResult) {
10355
+ console.log(
10356
+ `Secure platform MCP target: ${secureArtifacts.mcpRuntimeResult.action} (${secureArtifacts.mcpRuntimeResult.path || "n/a"})`,
10357
+ );
10358
+ }
10359
+ for (const cleanup of secureArtifacts?.legacyDefinitionCleanupResults || []) {
10360
+ console.log(`- ${cleanup.action} ${cleanup.path}`);
10361
+ }
10362
+ for (const warning of secureArtifacts?.warnings || []) {
10363
+ console.log(`Warning: ${warning}`);
10364
+ }
10212
10365
  } catch (error) {
10213
10366
  if (error?.name === "ExitPromptError") {
10214
10367
  console.error("\nCancelled.");
@@ -10225,6 +10378,7 @@ async function runWorkflowConfigKeysDoctor(options) {
10225
10378
  const cwd = process.cwd();
10226
10379
  const scopeArg = readCliOptionFromArgv("--scope");
10227
10380
  const scope = normalizeMcpScope(scopeArg ?? opts.scope, "global");
10381
+ await loadManagedCredentialsEnv();
10228
10382
  const { configPath, existing, existingValue } = await loadConfigForScope({
10229
10383
  scope,
10230
10384
  cwd,
@@ -10237,7 +10391,7 @@ async function runWorkflowConfigKeysDoctor(options) {
10237
10391
  }
10238
10392
 
10239
10393
  const configFindings = collectInlineCredentialFindings(existingValue);
10240
- const artifactFindings = await collectInlineHeaderFindings({ scope, cwd });
10394
+ const artifactFindings = await collectCredentialLeakFindings({ scope, cwd });
10241
10395
  const migrationPreview = migrateInlineCredentialsInConfig(existingValue);
10242
10396
 
10243
10397
  console.log(`Inline key findings: ${configFindings.length}`);
@@ -10245,9 +10399,9 @@ async function runWorkflowConfigKeysDoctor(options) {
10245
10399
  console.log(`- ${finding.path}`);
10246
10400
  }
10247
10401
 
10248
- console.log(`Unsafe header findings: ${artifactFindings.length}`);
10249
- for (const filePath of artifactFindings) {
10250
- console.log(`- ${filePath}`);
10402
+ console.log(`Credential leak findings: ${artifactFindings.length}`);
10403
+ for (const finding of artifactFindings) {
10404
+ console.log(`- ${finding.filePath} [${finding.matches.join(", ")}]`);
10251
10405
  }
10252
10406
 
10253
10407
  if (migrationPreview.requiredEnvVars.length > 0) {
@@ -10263,7 +10417,7 @@ async function runWorkflowConfigKeysDoctor(options) {
10263
10417
  console.log(
10264
10418
  "Doctor result: issues detected. Run `cbx workflows config keys migrate-inline --scope " +
10265
10419
  scope +
10266
- "` and reinstall with `--overwrite`.",
10420
+ "` to scrub keys and reapply secure Foundry MCP wiring.",
10267
10421
  );
10268
10422
  }
10269
10423
  } catch (error) {
@@ -10501,6 +10655,7 @@ async function runWorkflowConfig(options) {
10501
10655
  if (!next.mcp || typeof next.mcp !== "object" || Array.isArray(next.mcp)) {
10502
10656
  next.mcp = {};
10503
10657
  }
10658
+ next.mcp.server = FOUNDRY_MCP_SERVER_ID;
10504
10659
  if (hasMcpRuntimeOption) {
10505
10660
  next.mcp.runtime = mcpRuntime;
10506
10661
  next.mcp.effectiveRuntime = mcpRuntime;
@@ -10572,15 +10727,10 @@ async function runWorkflowConfig(options) {
10572
10727
  console.log(`postman.mode: ${effectivePostmanMode}`);
10573
10728
  console.log(`postman.mcpUrl: ${effectivePostmanState.mcpUrl}`);
10574
10729
  if (postmanArtifacts) {
10575
- console.log(
10576
- `postman.definition: ${postmanArtifacts.mcpDefinitionResult.action} (${postmanArtifacts.mcpDefinitionPath})`,
10577
- );
10578
- if (
10579
- postmanArtifacts.stitchMcpDefinitionPath &&
10580
- postmanArtifacts.stitchMcpDefinitionResult
10581
- ) {
10730
+ for (const cleanupResult of postmanArtifacts.legacyDefinitionCleanupResults ||
10731
+ []) {
10582
10732
  console.log(
10583
- `stitch.definition: ${postmanArtifacts.stitchMcpDefinitionResult.action} (${postmanArtifacts.stitchMcpDefinitionPath})`,
10733
+ `legacy.definition.cleanup: ${cleanupResult.action} (${cleanupResult.path})`,
10584
10734
  );
10585
10735
  }
10586
10736
  if (postmanArtifacts.mcpRuntimeResult) {
@@ -11884,7 +12034,12 @@ function normalizeInitPlatforms(value) {
11884
12034
  }
11885
12035
 
11886
12036
  function normalizeInitMcpSelections(value) {
11887
- const allowed = new Set(["cubis-foundry", "postman", "stitch"]);
12037
+ const allowed = new Set([
12038
+ "cubis-foundry",
12039
+ "postman",
12040
+ "stitch",
12041
+ "playwright",
12042
+ ]);
11888
12043
  const items = Array.isArray(value) ? value : parseCsvOption(value);
11889
12044
  const normalized = [];
11890
12045
  for (const item of items) {
@@ -12012,7 +12167,9 @@ async function runInitWizard(options) {
12012
12167
  throw new Error("No platforms selected.");
12013
12168
  }
12014
12169
 
12015
- const runtimeSelectableMcp = selections.selectedMcps.length > 0;
12170
+ const runtimeSelectableMcp = selections.selectedMcps.some(
12171
+ (item) => item !== "playwright",
12172
+ );
12016
12173
 
12017
12174
  if (runtimeSelectableMcp && isInteractive) {
12018
12175
  const runtimeSelection = await promptInitMcpRuntime({
@@ -12185,11 +12342,16 @@ async function runInitWizard(options) {
12185
12342
  }
12186
12343
 
12187
12344
  if (emitJson) {
12345
+ const sanitizedSelections = {
12346
+ ...selections,
12347
+ postmanApiKey: selections.postmanApiKey ? "***REDACTED***" : null,
12348
+ stitchApiKey: selections.stitchApiKey ? "***REDACTED***" : null,
12349
+ };
12188
12350
  console.log(
12189
12351
  JSON.stringify(
12190
12352
  {
12191
12353
  dryRun,
12192
- selections,
12354
+ selections: sanitizedSelections,
12193
12355
  results,
12194
12356
  persistedCredentials,
12195
12357
  },