@cubis/foundry 0.3.68 → 0.3.70

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 (152) hide show
  1. package/dist/cli/core.js +95 -2
  2. package/dist/cli/core.js.map +1 -1
  3. package/dist/cli/init/execute.js +6 -4
  4. package/dist/cli/init/execute.js.map +1 -1
  5. package/dist/cli/init/prompts.js +5 -0
  6. package/dist/cli/init/prompts.js.map +1 -1
  7. package/mcp/dist/index.js +37 -8
  8. package/mcp/src/cbxConfig/index.ts +6 -1
  9. package/mcp/src/cbxConfig/serviceConfig.ts +38 -3
  10. package/mcp/src/cbxConfig/types.ts +6 -0
  11. package/mcp/src/gateway/config.ts +69 -8
  12. package/mcp/src/gateway/manager.ts +17 -6
  13. package/mcp/src/gateway/types.ts +1 -1
  14. package/mcp/src/server.ts +18 -13
  15. package/mcp/src/tools/playwrightGetStatus.ts +60 -0
  16. package/mcp/src/tools/registry.test.ts +26 -8
  17. package/mcp/src/tools/registry.ts +29 -2
  18. package/mcp/src/tools/routeResolve.ts +1 -1
  19. package/mcp/src/upstream/passthrough.ts +69 -8
  20. package/package.json +1 -1
  21. package/src/cli/core.ts +100 -5
  22. package/src/cli/init/execute.ts +14 -5
  23. package/src/cli/init/prompts.ts +5 -0
  24. package/src/cli/init/types.ts +1 -1
  25. package/workflows/skills/generated/skill-catalog.json +806 -103
  26. package/workflows/skills/playwright-e2e/SKILL.md +21 -5
  27. package/workflows/skills/playwright-e2e/references/locator-trace-flake-checklist.md +28 -0
  28. package/workflows/skills/skills_index.json +802 -99
  29. package/workflows/workflows/agent-environment-setup/manifest.json +65 -9
  30. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/backend-specialist.md +6 -0
  31. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/code-archaeologist.md +7 -0
  32. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/database-architect.md +6 -0
  33. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/debugger.md +7 -0
  34. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/devops-engineer.md +6 -0
  35. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/documentation-writer.md +4 -0
  36. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/frontend-specialist.md +6 -0
  37. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/game-developer.md +1 -0
  38. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/mobile-developer.md +6 -0
  39. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/orchestrator.md +8 -0
  40. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/penetration-tester.md +4 -0
  41. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/performance-optimizer.md +4 -0
  42. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/product-manager.md +1 -0
  43. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/project-planner.md +8 -0
  44. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/qa-automation-engineer.md +1 -0
  45. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/researcher.md +5 -0
  46. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/security-auditor.md +6 -0
  47. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/seo-specialist.md +1 -0
  48. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/sre-engineer.md +6 -0
  49. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/test-engineer.md +5 -0
  50. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/validator.md +1 -0
  51. package/workflows/workflows/agent-environment-setup/platforms/antigravity/agents/vercel-expert.md +1 -0
  52. package/workflows/workflows/agent-environment-setup/platforms/antigravity/rules/GEMINI.md +1 -1
  53. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/backend-specialist.md +6 -0
  54. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/code-archaeologist.md +7 -0
  55. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/database-architect.md +6 -0
  56. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/debugger.md +7 -0
  57. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/devops-engineer.md +6 -0
  58. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/documentation-writer.md +4 -0
  59. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/frontend-specialist.md +6 -0
  60. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/game-developer.md +1 -0
  61. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/mobile-developer.md +6 -0
  62. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/orchestrator.md +8 -0
  63. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/penetration-tester.md +4 -0
  64. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/performance-optimizer.md +4 -0
  65. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/product-manager.md +1 -0
  66. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/project-planner.md +8 -0
  67. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/qa-automation-engineer.md +1 -0
  68. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/researcher.md +5 -0
  69. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/security-auditor.md +6 -0
  70. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/seo-specialist.md +1 -0
  71. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/sre-engineer.md +6 -0
  72. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/test-engineer.md +5 -0
  73. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/validator.md +1 -0
  74. package/workflows/workflows/agent-environment-setup/platforms/claude/agents/vercel-expert.md +1 -0
  75. package/workflows/workflows/agent-environment-setup/platforms/claude/rules/CLAUDE.md +77 -63
  76. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/playwright-e2e/SKILL.md +21 -5
  77. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/playwright-e2e/references/locator-trace-flake-checklist.md +28 -0
  78. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/skills_index.json +802 -99
  79. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/backend-specialist.md +6 -0
  80. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/code-archaeologist.md +7 -0
  81. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/database-architect.md +6 -0
  82. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/debugger.md +7 -0
  83. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/devops-engineer.md +6 -0
  84. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/documentation-writer.md +4 -0
  85. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/frontend-specialist.md +6 -0
  86. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/game-developer.md +1 -0
  87. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/mobile-developer.md +6 -0
  88. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/orchestrator.md +8 -0
  89. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/penetration-tester.md +4 -0
  90. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/performance-optimizer.md +4 -0
  91. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/product-manager.md +1 -0
  92. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/project-planner.md +8 -0
  93. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/qa-automation-engineer.md +1 -0
  94. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/researcher.md +5 -0
  95. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/security-auditor.md +6 -0
  96. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/seo-specialist.md +1 -0
  97. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/sre-engineer.md +6 -0
  98. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/test-engineer.md +5 -0
  99. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/validator.md +1 -0
  100. package/workflows/workflows/agent-environment-setup/platforms/codex/agents/vercel-expert.md +1 -0
  101. package/workflows/workflows/agent-environment-setup/platforms/codex/rules/AGENTS.md +1 -1
  102. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/backend-specialist.md +5 -0
  103. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/code-archaeologist.md +5 -0
  104. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/database-architect.md +5 -0
  105. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/debugger.md +5 -0
  106. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/devops-engineer.md +5 -0
  107. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/documentation-writer.md +3 -0
  108. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/frontend-specialist.md +5 -0
  109. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/mobile-developer.md +5 -0
  110. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/orchestrator.md +6 -0
  111. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/penetration-tester.md +3 -0
  112. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/performance-optimizer.md +3 -0
  113. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/project-planner.md +6 -0
  114. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/researcher.md +3 -0
  115. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/security-auditor.md +5 -0
  116. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/sre-engineer.md +5 -0
  117. package/workflows/workflows/agent-environment-setup/platforms/copilot/agents/test-engineer.md +3 -0
  118. package/workflows/workflows/agent-environment-setup/platforms/copilot/rules/copilot-instructions.md +87 -82
  119. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/playwright-e2e/SKILL.md +21 -5
  120. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/playwright-e2e/references/locator-trace-flake-checklist.md +28 -0
  121. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/skills_index.json +802 -99
  122. package/workflows/workflows/agent-environment-setup/shared/agents/backend-specialist.md +6 -0
  123. package/workflows/workflows/agent-environment-setup/shared/agents/code-archaeologist.md +7 -0
  124. package/workflows/workflows/agent-environment-setup/shared/agents/database-architect.md +6 -0
  125. package/workflows/workflows/agent-environment-setup/shared/agents/debugger.md +7 -0
  126. package/workflows/workflows/agent-environment-setup/shared/agents/devops-engineer.md +6 -0
  127. package/workflows/workflows/agent-environment-setup/shared/agents/documentation-writer.md +4 -0
  128. package/workflows/workflows/agent-environment-setup/shared/agents/frontend-specialist.md +6 -0
  129. package/workflows/workflows/agent-environment-setup/shared/agents/game-developer.md +1 -0
  130. package/workflows/workflows/agent-environment-setup/shared/agents/mobile-developer.md +6 -0
  131. package/workflows/workflows/agent-environment-setup/shared/agents/orchestrator.md +8 -0
  132. package/workflows/workflows/agent-environment-setup/shared/agents/penetration-tester.md +4 -0
  133. package/workflows/workflows/agent-environment-setup/shared/agents/performance-optimizer.md +4 -0
  134. package/workflows/workflows/agent-environment-setup/shared/agents/product-manager.md +1 -0
  135. package/workflows/workflows/agent-environment-setup/shared/agents/project-planner.md +8 -0
  136. package/workflows/workflows/agent-environment-setup/shared/agents/qa-automation-engineer.md +1 -0
  137. package/workflows/workflows/agent-environment-setup/shared/agents/researcher.md +5 -0
  138. package/workflows/workflows/agent-environment-setup/shared/agents/security-auditor.md +6 -0
  139. package/workflows/workflows/agent-environment-setup/shared/agents/seo-specialist.md +1 -0
  140. package/workflows/workflows/agent-environment-setup/shared/agents/sre-engineer.md +6 -0
  141. package/workflows/workflows/agent-environment-setup/shared/agents/test-engineer.md +5 -0
  142. package/workflows/workflows/agent-environment-setup/shared/agents/validator.md +1 -0
  143. package/workflows/workflows/agent-environment-setup/shared/agents/vercel-expert.md +1 -0
  144. package/workflows/workflows/agent-environment-setup/shared/rules/STEERING.md +27 -4
  145. package/workflows/workflows/agent-environment-setup/shared/rules/overrides/antigravity.md +18 -3
  146. package/workflows/workflows/agent-environment-setup/shared/rules/overrides/claude.md +12 -4
  147. package/workflows/workflows/agent-environment-setup/shared/rules/overrides/codex.md +12 -2
  148. package/workflows/workflows/agent-environment-setup/shared/rules/overrides/copilot.md +13 -3
  149. package/workflows/skills/react-best-practices/docs/AGENTS.md +0 -2934
  150. package/workflows/workflows/agent-environment-setup/platforms/claude/skills/react-best-practices/docs/AGENTS.md +0 -2934
  151. package/workflows/workflows/agent-environment-setup/platforms/copilot/rules/AGENTS.md +0 -25
  152. package/workflows/workflows/agent-environment-setup/platforms/copilot/skills/react-best-practices/docs/AGENTS.md +0 -2934
@@ -42,9 +42,18 @@ function createTestContext(): ToolRuntimeContext {
42
42
  primarySkills: ["flutter-expert"],
43
43
  supportingSkills: [],
44
44
  artifacts: {
45
- codex: { workflowFile: "mobile.md", compatibilityAlias: "$workflow-mobile" },
46
- copilot: { workflowFile: "mobile.md", promptFile: "workflow-mobile.prompt.md" },
47
- antigravity: { workflowFile: "mobile.md", commandFile: "mobile.toml" },
45
+ codex: {
46
+ workflowFile: "mobile.md",
47
+ compatibilityAlias: "$workflow-mobile",
48
+ },
49
+ copilot: {
50
+ workflowFile: "mobile.md",
51
+ promptFile: "workflow-mobile.prompt.md",
52
+ },
53
+ antigravity: {
54
+ workflowFile: "mobile.md",
55
+ commandFile: "mobile.toml",
56
+ },
48
57
  claude: { workflowFile: "mobile.md" },
49
58
  },
50
59
  },
@@ -77,10 +86,11 @@ describe("tool registry", () => {
77
86
  expect(names).toContain("stitch_get_mode");
78
87
  expect(names).toContain("stitch_set_profile");
79
88
  expect(names).toContain("stitch_get_status");
89
+ expect(names).toContain("playwright_get_status");
80
90
  });
81
91
 
82
- it("has exactly 14 built-in tools", () => {
83
- expect(TOOL_REGISTRY).toHaveLength(14);
92
+ it("has exactly 15 built-in tools", () => {
93
+ expect(TOOL_REGISTRY).toHaveLength(15);
84
94
  });
85
95
 
86
96
  it("has no duplicate tool names", () => {
@@ -94,7 +104,9 @@ describe("tool registry", () => {
94
104
  expect(entry.name).toBeTruthy();
95
105
  expect(entry.description).toBeTruthy();
96
106
  expect(entry.schema).toBeTruthy();
97
- expect(entry.category).toMatch(/^(skill|route|postman|stitch)$/);
107
+ expect(entry.category).toMatch(
108
+ /^(skill|route|postman|stitch|playwright)$/,
109
+ );
98
110
  expect(typeof entry.createHandler).toBe("function");
99
111
  }
100
112
  });
@@ -128,7 +140,11 @@ describe("tool registry", () => {
128
140
  (t) => t.name === "skill_list_categories",
129
141
  )!;
130
142
  const handler = entry.createHandler(ctx);
131
- const result = (await handler({})) as {
143
+ const result = (await (
144
+ handler as unknown as (
145
+ args: Record<string, never>,
146
+ ) => Promise<{ content: Array<{ text: string }> }>
147
+ )({})) as {
132
148
  content: Array<{ text: string }>;
133
149
  };
134
150
  const data = JSON.parse(result.content[0].text);
@@ -137,15 +153,17 @@ describe("tool registry", () => {
137
153
 
138
154
  it("buildRegistrySummary produces correct structure", () => {
139
155
  const summary = buildRegistrySummary();
140
- expect(summary.totalTools).toBe(14);
156
+ expect(summary.totalTools).toBe(15);
141
157
  expect(summary.categories).toHaveProperty("route");
142
158
  expect(summary.categories).toHaveProperty("skill");
143
159
  expect(summary.categories).toHaveProperty("postman");
144
160
  expect(summary.categories).toHaveProperty("stitch");
161
+ expect(summary.categories).toHaveProperty("playwright");
145
162
  expect(summary.categories.route.tools).toHaveLength(1);
146
163
  expect(summary.categories.skill.tools).toHaveLength(7);
147
164
  expect(summary.categories.postman.tools).toHaveLength(3);
148
165
  expect(summary.categories.stitch.tools).toHaveLength(3);
166
+ expect(summary.categories.playwright.tools).toHaveLength(1);
149
167
  });
150
168
 
151
169
  it("each schema has a valid .shape property", () => {
@@ -12,13 +12,19 @@
12
12
  */
13
13
 
14
14
  import { z } from "zod";
15
+ import type { ToolCallback } from "@modelcontextprotocol/sdk/server/mcp.js";
15
16
  import type { VaultManifest } from "../vault/types.js";
16
17
  import type { RouteManifest } from "../routes/types.js";
17
18
  import type { ConfigScope } from "../cbxConfig/types.js";
18
19
 
19
20
  // ─── Core types ─────────────────────────────────────────────
20
21
 
21
- export type ToolCategory = "skill" | "route" | "postman" | "stitch";
22
+ export type ToolCategory =
23
+ | "skill"
24
+ | "route"
25
+ | "postman"
26
+ | "stitch"
27
+ | "playwright";
22
28
 
23
29
  export interface ToolRegistryEntry {
24
30
  /** Tool name exposed to MCP clients. */
@@ -35,7 +41,7 @@ export interface ToolRegistryEntry {
35
41
  */
36
42
  createHandler: (
37
43
  ctx: ToolRuntimeContext,
38
- ) => (args: unknown) => Promise<unknown>;
44
+ ) => ToolCallback<z.ZodObject<z.ZodRawShape>>;
39
45
  }
40
46
 
41
47
  export interface ToolRuntimeContext {
@@ -146,6 +152,13 @@ import {
146
152
  handleStitchGetStatus,
147
153
  } from "./stitchGetStatus.js";
148
154
 
155
+ import {
156
+ playwrightGetStatusName,
157
+ playwrightGetStatusDescription,
158
+ playwrightGetStatusSchema,
159
+ handlePlaywrightGetStatus,
160
+ } from "./playwrightGetStatus.js";
161
+
149
162
  // ─── Scope helper ───────────────────────────────────────────
150
163
 
151
164
  function withDefaultScope(
@@ -335,6 +348,20 @@ export const TOOL_REGISTRY: readonly ToolRegistryEntry[] = [
335
348
  >,
336
349
  ),
337
350
  },
351
+
352
+ // ── Playwright tools ──────────────────────────────────────
353
+ {
354
+ name: playwrightGetStatusName,
355
+ description: playwrightGetStatusDescription,
356
+ schema: playwrightGetStatusSchema,
357
+ category: "playwright",
358
+ createHandler: (ctx) => async (args) =>
359
+ handlePlaywrightGetStatus(
360
+ withDefaultScope(args, ctx.defaultConfigScope) as z.infer<
361
+ typeof playwrightGetStatusSchema
362
+ >,
363
+ ),
364
+ },
338
365
  ];
339
366
 
340
367
  // ─── Helpers ────────────────────────────────────────────────
@@ -359,7 +359,7 @@ async function fileExists(target: string) {
359
359
 
360
360
  async function detectLanguageSkillHint() {
361
361
  const cwd = process.cwd();
362
- const candidates = await fs.readdir(cwd).catch(() => []);
362
+ const candidates: string[] = await fs.readdir(cwd).catch(() => []);
363
363
  const has = (fileName: string) => candidates.includes(fileName);
364
364
 
365
365
  for (const entry of LANGUAGE_SIGNAL_FILES) {
@@ -6,14 +6,16 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
6
6
  import path from "node:path";
7
7
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
8
8
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
9
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
9
10
  import {
10
11
  parsePostmanState,
11
12
  parseStitchState,
13
+ parsePlaywrightState,
12
14
  readEffectiveConfig,
13
15
  } from "../cbxConfig/index.js";
14
16
  import type { CbxConfig, ConfigScope } from "../cbxConfig/types.js";
15
17
 
16
- type ServiceId = "postman" | "stitch";
18
+ type ServiceId = "postman" | "stitch" | "playwright";
17
19
 
18
20
  export interface UpstreamToolInfo {
19
21
  name: string;
@@ -125,7 +127,10 @@ async function loadCachedCatalogTools({
125
127
  }
126
128
  }
127
129
 
128
- function getServiceAuth(config: CbxConfig, service: ServiceId): {
130
+ function getServiceAuth(
131
+ config: CbxConfig,
132
+ service: ServiceId,
133
+ ): {
129
134
  mcpUrl: string | null;
130
135
  activeProfileName: string | null;
131
136
  envVar: string | null;
@@ -133,6 +138,17 @@ function getServiceAuth(config: CbxConfig, service: ServiceId): {
133
138
  configured: boolean;
134
139
  error?: string;
135
140
  } {
141
+ if (service === "playwright") {
142
+ const state = parsePlaywrightState(config);
143
+ return {
144
+ mcpUrl: state.mcpUrl,
145
+ activeProfileName: null,
146
+ envVar: null,
147
+ headers: {},
148
+ configured: Boolean(state.mcpUrl),
149
+ };
150
+ }
151
+
136
152
  if (service === "postman") {
137
153
  const state = parsePostmanState(config);
138
154
  const activeProfile = state.activeProfile;
@@ -209,6 +225,42 @@ async function withUpstreamClient<T>({
209
225
  }
210
226
  }
211
227
 
228
+ function isCallToolResult(
229
+ result: Awaited<ReturnType<Client["callTool"]>>,
230
+ ): result is CallToolResult {
231
+ return Array.isArray(
232
+ (
233
+ result as {
234
+ content?: unknown;
235
+ }
236
+ ).content,
237
+ );
238
+ }
239
+
240
+ function normalizeUpstreamToolResult(
241
+ result: Awaited<ReturnType<Client["callTool"]>>,
242
+ ): CallToolResult {
243
+ if (isCallToolResult(result)) {
244
+ return result;
245
+ }
246
+
247
+ return {
248
+ content: [
249
+ {
250
+ type: "text",
251
+ text: JSON.stringify(
252
+ {
253
+ toolResult: result.toolResult,
254
+ },
255
+ null,
256
+ 2,
257
+ ),
258
+ },
259
+ ],
260
+ _meta: result._meta,
261
+ };
262
+ }
263
+
212
264
  async function persistCatalog(catalog: UpstreamCatalog): Promise<void> {
213
265
  if (!catalog.configPath) return;
214
266
  const catalogDir = resolveCatalogDir(catalog.configPath);
@@ -240,6 +292,7 @@ export async function discoverUpstreamCatalogs(
240
292
  ): Promise<{
241
293
  postman: UpstreamCatalog;
242
294
  stitch: UpstreamCatalog;
295
+ playwright: UpstreamCatalog;
243
296
  }> {
244
297
  const effective = readEffectiveConfig(scope);
245
298
  if (!effective) {
@@ -256,9 +309,14 @@ export async function discoverUpstreamCatalogs(
256
309
  discoveryError: "cbx_config.json not found",
257
310
  };
258
311
  const missingStitch: UpstreamCatalog = { ...missing, service: "stitch" };
312
+ const missingPlaywright: UpstreamCatalog = {
313
+ ...missing,
314
+ service: "playwright",
315
+ };
259
316
  return {
260
317
  postman: missing,
261
318
  stitch: missingStitch,
319
+ playwright: missingPlaywright,
262
320
  };
263
321
  }
264
322
 
@@ -331,6 +389,7 @@ export async function discoverUpstreamCatalogs(
331
389
  return {
332
390
  postman: await discoverOne("postman"),
333
391
  stitch: await discoverOne("stitch"),
392
+ playwright: await discoverOne("playwright"),
334
393
  };
335
394
  }
336
395
 
@@ -344,7 +403,7 @@ export async function callUpstreamTool({
344
403
  name: string;
345
404
  argumentsValue: Record<string, unknown>;
346
405
  scope?: ConfigScope | "auto";
347
- }) {
406
+ }): Promise<CallToolResult> {
348
407
  const effective = readEffectiveConfig(scope);
349
408
  if (!effective) {
350
409
  throw new Error("cbx_config.json not found");
@@ -360,10 +419,12 @@ export async function callUpstreamTool({
360
419
  return withUpstreamClient({
361
420
  url: auth.mcpUrl,
362
421
  headers: auth.headers,
363
- fn: async (client) =>
364
- client.callTool({
365
- name,
366
- arguments: argumentsValue,
367
- }),
422
+ fn: async (client): Promise<CallToolResult> =>
423
+ normalizeUpstreamToolResult(
424
+ await client.callTool({
425
+ name,
426
+ arguments: argumentsValue,
427
+ }),
428
+ ),
368
429
  });
369
430
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cubis/foundry",
3
- "version": "0.3.68",
3
+ "version": "0.3.70",
4
4
  "description": "Cubis Foundry CLI for workflow-first AI agent environments",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli/core.ts CHANGED
@@ -217,6 +217,10 @@ const STITCH_SKILL_ID = "stitch";
217
217
  const STITCH_MCP_SERVER_ID = "StitchMCP";
218
218
  const STITCH_API_KEY_ENV_VAR = "STITCH_API_KEY_DEFAULT";
219
219
  const STITCH_MCP_URL = "https://stitch.googleapis.com/mcp";
220
+ const PLAYWRIGHT_SKILL_ID = "playwright";
221
+ const PLAYWRIGHT_MCP_SERVER_ID = "PlaywrightMCP";
222
+ const PLAYWRIGHT_DEFAULT_PORT = 8931;
223
+ const PLAYWRIGHT_MCP_URL = `http://localhost:${PLAYWRIGHT_DEFAULT_PORT}/mcp`;
220
224
  const POSTMAN_WORKSPACE_MANUAL_CHOICE = "__postman_workspace_manual__";
221
225
  const CBX_CONFIG_FILENAME = "cbx_config.json";
222
226
  const CBX_CREDENTIALS_ENV_FILENAME = "credentials.env";
@@ -4719,6 +4723,30 @@ function buildGeminiStitchServer({
4719
4723
  };
4720
4724
  }
4721
4725
 
4726
+ function buildVsCodePlaywrightServer({ mcpUrl = PLAYWRIGHT_MCP_URL } = {}) {
4727
+ return {
4728
+ type: "http",
4729
+ url: mcpUrl,
4730
+ headers: {},
4731
+ };
4732
+ }
4733
+
4734
+ function buildCopilotCliPlaywrightServer({ mcpUrl = PLAYWRIGHT_MCP_URL } = {}) {
4735
+ return {
4736
+ type: "http",
4737
+ url: mcpUrl,
4738
+ headers: {},
4739
+ tools: ["*"],
4740
+ };
4741
+ }
4742
+
4743
+ function buildGeminiPlaywrightServer({ mcpUrl = PLAYWRIGHT_MCP_URL } = {}) {
4744
+ return {
4745
+ httpUrl: mcpUrl,
4746
+ headers: {},
4747
+ };
4748
+ }
4749
+
4722
4750
  function getPostmanApiKeySource({ apiKey, envApiKey }) {
4723
4751
  if (apiKey) return "inline";
4724
4752
  if (envApiKey) return "env";
@@ -5210,6 +5238,7 @@ async function applyPostmanMcpForPlatform({
5210
5238
  stitchMcpUrl,
5211
5239
  includeStitchMcp = false,
5212
5240
  includeFoundryMcp = true,
5241
+ includePlaywrightMcp = false,
5213
5242
  foundryRuntime = "local",
5214
5243
  dryRun = false,
5215
5244
  cwd = process.cwd(),
@@ -5278,6 +5307,9 @@ async function applyPostmanMcpForPlatform({
5278
5307
  mcpUrl: stitchMcpUrl,
5279
5308
  });
5280
5309
  }
5310
+ if (includePlaywrightMcp) {
5311
+ mcpServers[PLAYWRIGHT_MCP_SERVER_ID] = buildGeminiPlaywrightServer();
5312
+ }
5281
5313
  next.mcpServers = mcpServers;
5282
5314
  return next;
5283
5315
  },
@@ -5324,6 +5356,10 @@ async function applyPostmanMcpForPlatform({
5324
5356
  } else {
5325
5357
  delete mcpServers[FOUNDRY_MCP_SERVER_ID];
5326
5358
  }
5359
+ if (includePlaywrightMcp) {
5360
+ mcpServers[PLAYWRIGHT_MCP_SERVER_ID] =
5361
+ buildCopilotCliPlaywrightServer();
5362
+ }
5327
5363
  next.mcpServers = mcpServers;
5328
5364
  return next;
5329
5365
  }
@@ -5350,6 +5386,9 @@ async function applyPostmanMcpForPlatform({
5350
5386
  } else {
5351
5387
  delete servers[FOUNDRY_MCP_SERVER_ID];
5352
5388
  }
5389
+ if (includePlaywrightMcp) {
5390
+ servers[PLAYWRIGHT_MCP_SERVER_ID] = buildVsCodePlaywrightServer();
5391
+ }
5353
5392
  next.servers = servers;
5354
5393
  return next;
5355
5394
  },
@@ -5401,6 +5440,9 @@ async function applyPostmanMcpForPlatform({
5401
5440
  } else {
5402
5441
  delete servers[FOUNDRY_MCP_SERVER_ID];
5403
5442
  }
5443
+ if (includePlaywrightMcp) {
5444
+ servers[PLAYWRIGHT_MCP_SERVER_ID] = buildVsCodePlaywrightServer();
5445
+ }
5404
5446
  next.servers = servers;
5405
5447
  return next;
5406
5448
  },
@@ -5529,6 +5571,57 @@ async function applyPostmanMcpForPlatform({
5529
5571
  };
5530
5572
  }
5531
5573
 
5574
+ if (platform === "claude") {
5575
+ const claudeConfigPath =
5576
+ mcpScope === "global"
5577
+ ? path.join(os.homedir(), ".claude", "mcp.json")
5578
+ : path.join(workspaceRoot, ".mcp.json");
5579
+ const result = await upsertJsonObjectFile({
5580
+ targetPath: claudeConfigPath,
5581
+ updater: (existing) => {
5582
+ const next = { ...existing };
5583
+ const mcpServers =
5584
+ next.mcpServers &&
5585
+ typeof next.mcpServers === "object" &&
5586
+ !Array.isArray(next.mcpServers)
5587
+ ? { ...next.mcpServers }
5588
+ : {};
5589
+ if (includeFoundryMcp) {
5590
+ if (normalizedFoundryRuntime === "docker") {
5591
+ mcpServers[FOUNDRY_MCP_SERVER_ID] = {
5592
+ type: "url",
5593
+ url: buildFoundryDockerUrl({ port: foundryDockerPort }),
5594
+ };
5595
+ } else {
5596
+ mcpServers[FOUNDRY_MCP_SERVER_ID] = {
5597
+ type: "stdio",
5598
+ command: FOUNDRY_MCP_COMMAND,
5599
+ args: buildFoundryServeArgs({ scope: foundryScope }),
5600
+ };
5601
+ }
5602
+ } else {
5603
+ delete mcpServers[FOUNDRY_MCP_SERVER_ID];
5604
+ }
5605
+ if (includePlaywrightMcp) {
5606
+ mcpServers[PLAYWRIGHT_MCP_SERVER_ID] = {
5607
+ type: "url",
5608
+ url: PLAYWRIGHT_MCP_URL,
5609
+ };
5610
+ }
5611
+ next.mcpServers = mcpServers;
5612
+ return next;
5613
+ },
5614
+ dryRun,
5615
+ });
5616
+ return {
5617
+ kind: "claude-mcp",
5618
+ scope: mcpScope,
5619
+ path: claudeConfigPath,
5620
+ action: result.action,
5621
+ warnings: [...warnings, ...result.warnings],
5622
+ };
5623
+ }
5624
+
5532
5625
  return {
5533
5626
  kind: "unknown",
5534
5627
  scope: mcpScope,
@@ -5606,10 +5699,7 @@ async function resolvePostmanInstallSelection({
5606
5699
  : null;
5607
5700
  let workspaceSelectionSource = hasWorkspaceOption ? "option" : "none";
5608
5701
  const requestedMcpScope = options.mcpScope
5609
- ? coerceWorkspaceOnlyMcpScope(
5610
- options.mcpScope,
5611
- "--mcp-scope",
5612
- )
5702
+ ? coerceWorkspaceOnlyMcpScope(options.mcpScope, "--mcp-scope")
5613
5703
  : null;
5614
5704
  let mcpScope = requestedMcpScope?.scope || "project";
5615
5705
  const warnings = [];
@@ -6057,6 +6147,7 @@ async function configurePostmanInstallArtifacts({
6057
6147
  stitchMcpUrl: effectiveStitchMcpUrl,
6058
6148
  includeStitchMcp: shouldInstallStitch,
6059
6149
  includeFoundryMcp: postmanSelection.foundryMcpEnabled,
6150
+ includePlaywrightMcp: postmanSelection.playwrightEnabled ?? false,
6060
6151
  foundryRuntime: postmanSelection.effectiveMcpRuntime || "local",
6061
6152
  dryRun,
6062
6153
  cwd,
@@ -6167,6 +6258,7 @@ async function applyPostmanConfigArtifacts({
6167
6258
  POSTMAN_API_KEY_ENV_VAR;
6168
6259
  const postmanMcpUrl = postmanState.mcpUrl || POSTMAN_MCP_URL;
6169
6260
  const stitchEnabled = Boolean(stitchState);
6261
+ const playwrightEnabled = Boolean(configValue?.playwright);
6170
6262
  const stitchApiKeyEnvVar =
6171
6263
  normalizePostmanApiKey(stitchState?.apiKeyEnvVar) || STITCH_API_KEY_ENV_VAR;
6172
6264
  const stitchMcpUrl = stitchState?.mcpUrl || STITCH_MCP_URL;
@@ -6239,6 +6331,7 @@ async function applyPostmanConfigArtifacts({
6239
6331
  stitchMcpUrl,
6240
6332
  includeStitchMcp: stitchEnabled,
6241
6333
  includeFoundryMcp: true,
6334
+ includePlaywrightMcp: playwrightEnabled ?? false,
6242
6335
  foundryRuntime,
6243
6336
  dryRun,
6244
6337
  cwd,
@@ -8239,7 +8332,9 @@ async function performWorkflowInstall(
8239
8332
  cancelled: false,
8240
8333
  cwd,
8241
8334
  scope,
8242
- warnings: requestedInstallScope.warning ? [requestedInstallScope.warning] : [],
8335
+ warnings: requestedInstallScope.warning
8336
+ ? [requestedInstallScope.warning]
8337
+ : [],
8243
8338
  ruleScope,
8244
8339
  dryRun,
8245
8340
  platform,
@@ -23,12 +23,20 @@ export function buildInitExecutionPlan({
23
23
  const planItems: InitExecutionPlanItem[] = [];
24
24
  const wantsPostman = hasMcpSelection(selections.selectedMcps, "postman");
25
25
  const wantsStitch = hasMcpSelection(selections.selectedMcps, "stitch");
26
- const wantsFoundry = hasMcpSelection(selections.selectedMcps, "cubis-foundry");
26
+ const wantsFoundry = hasMcpSelection(
27
+ selections.selectedMcps,
28
+ "cubis-foundry",
29
+ );
30
+ const wantsPlaywright = hasMcpSelection(
31
+ selections.selectedMcps,
32
+ "playwright",
33
+ );
27
34
 
28
35
  for (const platform of selections.platforms) {
29
36
  const stitchSupported = platform === "antigravity";
30
37
  const stitchEnabled = wantsStitch && stitchSupported;
31
- const hasAnyMcp = wantsPostman || stitchEnabled || wantsFoundry;
38
+ const hasAnyMcp =
39
+ wantsPostman || stitchEnabled || wantsFoundry || wantsPlaywright;
32
40
  const warnings: string[] = [];
33
41
  if (wantsStitch && !stitchSupported) {
34
42
  warnings.push(
@@ -48,10 +56,11 @@ export function buildInitExecutionPlan({
48
56
  target,
49
57
  postman: wantsPostman,
50
58
  stitch: stitchEnabled,
59
+ playwright: wantsPlaywright,
51
60
  stitchDefaultForAntigravity: false,
52
61
  mcpScope: selections.mcpScope,
53
62
  foundryMcp: wantsFoundry,
54
- mcpToolSync: wantsPostman || stitchEnabled,
63
+ mcpToolSync: wantsPostman || stitchEnabled || wantsPlaywright,
55
64
  mcpRuntime: hasAnyMcp ? selections.mcpRuntime : "local",
56
65
  mcpFallback: "local",
57
66
  mcpBuildLocal: hasAnyMcp ? selections.mcpBuildLocal : false,
@@ -83,9 +92,9 @@ export function formatInitSummary(selections: InitWizardSelections) {
83
92
  `- Skill profile: ${selections.skillProfile}`,
84
93
  `- Skills scope: ${selections.skillsScope}`,
85
94
  `- MCP scope: ${selections.mcpScope}`,
86
- `- MCP runtime: ${selections.mcpRuntime}${selections.mcpRuntime === "docker" ? selections.mcpBuildLocal ? " (build local image)" : " (pull image)" : ""}`,
95
+ `- MCP runtime: ${selections.mcpRuntime}${selections.mcpRuntime === "docker" ? (selections.mcpBuildLocal ? " (build local image)" : " (pull image)") : ""}`,
87
96
  `- MCP selections: ${selections.selectedMcps.length > 0 ? selections.selectedMcps.join(", ") : "(none)"}`,
88
97
  `- Postman mode: ${postmanSelected ? selections.postmanMode : "(not selected)"}`,
89
- `- Postman workspace: ${postmanSelected ? selections.postmanWorkspaceId === null ? "null" : selections.postmanWorkspaceId : "(not selected)"}`,
98
+ `- Postman workspace: ${postmanSelected ? (selections.postmanWorkspaceId === null ? "null" : selections.postmanWorkspaceId) : "(not selected)"}`,
90
99
  ].join("\n");
91
100
  }
@@ -90,6 +90,11 @@ export async function promptInitMcpSelection(defaultMcps: InitMcpId[]) {
90
90
  value: "stitch",
91
91
  checked: defaultMcps.includes("stitch"),
92
92
  },
93
+ {
94
+ name: "Playwright",
95
+ value: "playwright",
96
+ checked: defaultMcps.includes("playwright"),
97
+ },
93
98
  ],
94
99
  });
95
100
  }
@@ -1,6 +1,6 @@
1
1
  export type InitScope = "project" | "global";
2
2
  export type InitSkillProfile = "core" | "web-backend" | "full";
3
- export type InitMcpId = "cubis-foundry" | "postman" | "stitch";
3
+ export type InitMcpId = "cubis-foundry" | "postman" | "stitch" | "playwright";
4
4
  export type InitPostmanMode = "full" | "minimal";
5
5
  export type InitPlatformId = "codex" | "antigravity" | "copilot" | "claude";
6
6
  export type InitMcpRuntime = "local" | "docker";