@webiny/mcp 6.1.0-beta.1 → 6.1.0-beta.2

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 (77) hide show
  1. package/agents/claude.d.ts +2 -0
  2. package/agents/claude.js +6 -0
  3. package/agents/claude.js.map +1 -1
  4. package/agents/cline.d.ts +2 -0
  5. package/agents/cline.js +6 -0
  6. package/agents/cline.js.map +1 -1
  7. package/agents/copilot.d.ts +2 -0
  8. package/agents/copilot.js +7 -0
  9. package/agents/copilot.js.map +1 -1
  10. package/agents/cursor.d.ts +2 -0
  11. package/agents/cursor.js +6 -0
  12. package/agents/cursor.js.map +1 -1
  13. package/agents/discover.d.ts +3 -0
  14. package/agents/discover.js +29 -0
  15. package/agents/discover.js.map +1 -0
  16. package/agents/instructions.d.ts +3 -1
  17. package/agents/instructions.js +15 -2
  18. package/agents/instructions.js.map +1 -1
  19. package/agents/kiro.d.ts +2 -0
  20. package/agents/kiro.js +6 -0
  21. package/agents/kiro.js.map +1 -1
  22. package/agents/opencode.d.ts +2 -0
  23. package/agents/opencode.js +7 -0
  24. package/agents/opencode.js.map +1 -1
  25. package/agents/types.d.ts +16 -0
  26. package/agents/types.js +3 -0
  27. package/agents/types.js.map +1 -0
  28. package/agents/windsurf.d.ts +2 -0
  29. package/agents/windsurf.js +6 -0
  30. package/agents/windsurf.js.map +1 -1
  31. package/cli/ConfigureMcp.js +21 -6
  32. package/cli/ConfigureMcp.js.map +1 -1
  33. package/package.json +3 -3
  34. package/skills/admin/admin-architect/SKILL.md +188 -0
  35. package/skills/admin/admin-permissions/SKILL.md +159 -0
  36. package/skills/api/api-architect/SKILL.md +548 -60
  37. package/skills/api/event-handler-pattern/SKILL.md +191 -23
  38. package/skills/api/graphql-api/SKILL.md +227 -31
  39. package/skills/api/permissions/SKILL.md +291 -0
  40. package/skills/api/use-case-pattern/SKILL.md +347 -12
  41. package/skills/api/v5-to-v6-migration/SKILL.md +416 -0
  42. package/skills/generated/admin/SKILL.md +1 -1
  43. package/skills/generated/admin/aco/SKILL.md +1 -1
  44. package/skills/generated/admin/build-params/SKILL.md +1 -1
  45. package/skills/generated/admin/cms/SKILL.md +1 -1
  46. package/skills/generated/admin/configs/SKILL.md +1 -1
  47. package/skills/generated/admin/env-config/SKILL.md +1 -1
  48. package/skills/generated/admin/form/SKILL.md +1 -1
  49. package/skills/generated/admin/graphql-client/SKILL.md +1 -1
  50. package/skills/generated/admin/lexical/SKILL.md +1 -1
  51. package/skills/generated/admin/local-storage/SKILL.md +1 -1
  52. package/skills/generated/admin/router/SKILL.md +1 -1
  53. package/skills/generated/admin/security/SKILL.md +1 -1
  54. package/skills/generated/admin/tenancy/SKILL.md +1 -1
  55. package/skills/generated/admin/ui/SKILL.md +1 -1
  56. package/skills/generated/admin/website-builder/SKILL.md +1 -1
  57. package/skills/generated/api/SKILL.md +1 -1
  58. package/skills/generated/api/aco/SKILL.md +1 -1
  59. package/skills/generated/api/build-params/SKILL.md +1 -1
  60. package/skills/generated/api/cms/SKILL.md +1 -1
  61. package/skills/generated/api/event-publisher/SKILL.md +1 -1
  62. package/skills/generated/api/file-manager/SKILL.md +1 -1
  63. package/skills/generated/api/graphql/SKILL.md +1 -1
  64. package/skills/generated/api/key-value-store/SKILL.md +1 -1
  65. package/skills/generated/api/logger/SKILL.md +1 -1
  66. package/skills/generated/api/opensearch/SKILL.md +1 -1
  67. package/skills/generated/api/scheduler/SKILL.md +1 -1
  68. package/skills/generated/api/security/SKILL.md +1 -1
  69. package/skills/generated/api/system/SKILL.md +1 -1
  70. package/skills/generated/api/tasks/SKILL.md +1 -1
  71. package/skills/generated/api/tenancy/SKILL.md +1 -1
  72. package/skills/generated/api/tenant-manager/SKILL.md +1 -1
  73. package/skills/generated/api/website-builder/SKILL.md +1 -1
  74. package/skills/generated/cli/SKILL.md +1 -1
  75. package/skills/generated/cli/command/SKILL.md +1 -1
  76. package/skills/generated/extensions/SKILL.md +1 -1
  77. package/skills/generated/infra/SKILL.md +1 -1
@@ -308,6 +308,193 @@ export const DashboardFeature = createFeature({
308
308
 
309
309
  > **Prefer the typical pattern.** Only use the one-off pattern when the business logic is truly presentation-specific and will never be reused by other features.
310
310
 
311
+ ## Observable Service Implementation
312
+
313
+ For long-lived services that hold observable state (e.g., project config, feature flags):
314
+
315
+ ```ts
316
+ import { makeAutoObservable, runInAction } from "mobx";
317
+ import { WcpService as ServiceAbstraction, WcpGateway } from "./abstractions.js";
318
+
319
+ class WcpServiceImpl implements ServiceAbstraction.Interface {
320
+ private project: ILicense | null = null;
321
+
322
+ constructor(private gateway: WcpGateway.Interface) {
323
+ makeAutoObservable(this);
324
+ }
325
+
326
+ getProject(): ILicense {
327
+ return this.project;
328
+ }
329
+
330
+ async loadProject(): Promise<void> {
331
+ const data = await this.gateway.fetchProject();
332
+ runInAction(() => {
333
+ this.project = data;
334
+ });
335
+ }
336
+ }
337
+
338
+ export const WcpService = ServiceAbstraction.createImplementation({
339
+ implementation: WcpServiceImpl,
340
+ dependencies: [WcpGateway]
341
+ });
342
+ ```
343
+
344
+ - Registered in **singleton scope** — long-lived, holds state
345
+ - Use `makeAutoObservable(this)` in the constructor
346
+ - Wrap async state mutations in `runInAction`
347
+
348
+ ## Repository Implementation
349
+
350
+ Repositories own domain data and cache. They use MobX for reactivity:
351
+
352
+ ```ts
353
+ import { makeAutoObservable, runInAction } from "mobx";
354
+ import {
355
+ NextjsConfigRepository as RepositoryAbstraction,
356
+ NextjsConfigGateway,
357
+ NextjsConfig
358
+ } from "./abstractions.js";
359
+
360
+ class NextjsConfigRepositoryImpl implements RepositoryAbstraction.Interface {
361
+ private config: NextjsConfig | undefined = undefined;
362
+
363
+ constructor(private gateway: NextjsConfigGateway.Interface) {
364
+ makeAutoObservable(this);
365
+ }
366
+
367
+ getConfig(): NextjsConfig | undefined {
368
+ return this.config;
369
+ }
370
+
371
+ async loadConfig(): Promise<void> {
372
+ if (this.config) {
373
+ return; // Already loaded — cache hit
374
+ }
375
+
376
+ const config = await this.gateway.getConfig();
377
+ runInAction(() => {
378
+ this.config = config;
379
+ });
380
+ }
381
+ }
382
+
383
+ export const NextjsConfigRepository = RepositoryAbstraction.createImplementation({
384
+ implementation: NextjsConfigRepositoryImpl,
385
+ dependencies: [NextjsConfigGateway]
386
+ });
387
+ ```
388
+
389
+ ## Gateway Implementation (GraphQL)
390
+
391
+ Gateways handle external I/O. Use `GraphQLClient` for GraphQL calls:
392
+
393
+ ```ts
394
+ import { NextjsConfigGateway as GatewayAbstraction } from "./abstractions.js";
395
+ import { GraphQLClient } from "@webiny/app/features/graphqlClient";
396
+
397
+ const GET_NEXTJS_CONFIG = /* GraphQL */ `
398
+ query GetNextjsConfig {
399
+ websiteBuilder {
400
+ getNextjsConfig {
401
+ data
402
+ error { code message data }
403
+ }
404
+ }
405
+ }
406
+ `;
407
+
408
+ type GetNextjsConfigResponse = {
409
+ websiteBuilder: {
410
+ getNextjsConfig:
411
+ | { data: string; error: null }
412
+ | { data: null; error: { code: string; message: string; data: any } };
413
+ };
414
+ };
415
+
416
+ class NextjsGraphQLGateway implements GatewayAbstraction.Interface {
417
+ constructor(private client: GraphQLClient.Interface) {}
418
+
419
+ async getConfig(): Promise<string> {
420
+ const response = await this.client.execute<GetNextjsConfigResponse>({
421
+ query: GET_NEXTJS_CONFIG
422
+ });
423
+
424
+ const envelope = response.websiteBuilder.getNextjsConfig;
425
+ if (envelope.error) {
426
+ throw new Error(envelope.error.message);
427
+ }
428
+
429
+ return envelope.data;
430
+ }
431
+ }
432
+
433
+ export const NextjsConfigGateway = GatewayAbstraction.createImplementation({
434
+ implementation: NextjsGraphQLGateway,
435
+ dependencies: [GraphQLClient]
436
+ });
437
+ ```
438
+
439
+ **Key points:**
440
+ - Define the GraphQL query as a string constant with `/* GraphQL */` comment for syntax highlighting
441
+ - Type the response shape explicitly
442
+ - Handle the `data`/`error` envelope pattern
443
+ - Inject `GraphQLClient` from `@webiny/app/features/graphqlClient`
444
+
445
+ ## Composite Features (Aggregating Child Features)
446
+
447
+ When grouping related features, create a composite with no `resolve`:
448
+
449
+ ```ts
450
+ import { createFeature } from "webiny/admin";
451
+
452
+ export const FoldersFeature = createFeature({
453
+ name: "Folders",
454
+ register(container) {
455
+ CreateFolderFeature.register(container);
456
+ UpdateFolderFeature.register(container);
457
+ DeleteFolderFeature.register(container);
458
+ }
459
+ });
460
+ ```
461
+
462
+ ## Extending Features (Decorators)
463
+
464
+ Decorators add cross-cutting concerns without modifying the core implementation:
465
+
466
+ ```ts
467
+ class ListFoldersUseCaseWithLoading implements UseCaseAbstraction.Interface {
468
+ constructor(
469
+ private loadingRepository: FoldersLoadingRepository.Interface,
470
+ private decoratee: UseCaseAbstraction.Interface // decoratee is LAST
471
+ ) {}
472
+
473
+ async execute() {
474
+ await this.loadingRepository.runCallBack(
475
+ this.decoratee.execute(),
476
+ LoadingActionsEnum.list
477
+ );
478
+ }
479
+ }
480
+ ```
481
+
482
+ Register with `container.registerDecorator()`:
483
+
484
+ ```ts
485
+ export const MyExtensionFeature = createFeature({
486
+ name: "MyExtension",
487
+ register(container) {
488
+ container.registerDecorator(MyPresenterDecorator);
489
+ }
490
+ });
491
+ ```
492
+
493
+ **Rules:**
494
+ - Implements the same interface as the decorated abstraction
495
+ - Constructor: extra dependencies first, `decoratee` **last**
496
+ - The `dependencies` array does NOT include the decoratee
497
+
311
498
  ## Reading Admin BuildParams
312
499
 
313
500
  There are two ways to read build parameters on the Admin side:
@@ -384,6 +571,7 @@ Creates a feature definition for the admin runtime.
384
571
 
385
572
  ## Related Skills
386
573
 
574
+ - **webiny-admin-permissions** — Admin permission UI registration (Security.Permissions schema, custom UIs)
387
575
  - **webiny-full-stack-architect** — Top-level component, shared domain layer, BuildParam declarations
388
576
  - **webiny-dependency-injection** — The `createImplementation` DI pattern and injectable services
389
577
  - **webiny-admin-ui-extensions** — Admin UI customization, decorators, theming, forms, and config
@@ -0,0 +1,159 @@
1
+ ---
2
+ name: webiny-admin-permissions
3
+ context: webiny-extensions
4
+ description: >
5
+ Admin-side permission UI registration using Security.Permissions. Use this skill when
6
+ adding permission controls to the admin UI — schema-based auto-generated forms, custom
7
+ permission UIs with usePermissionValue/usePermissionForm, entity dependencies, and
8
+ the Security.Permissions component props. Covers both simple apps and complex
9
+ multi-entity permission schemas.
10
+ ---
11
+
12
+ # Admin Permissions UI
13
+
14
+ ## Overview
15
+
16
+ Register permissions via `AdminConfig` + `Security.Permissions`. The framework auto-generates the UI from a schema and handles serialization. No form code needed for most apps.
17
+
18
+ ## Schema-Based (Auto-Generated UI)
19
+
20
+ ```tsx
21
+ import React from "react";
22
+ import { AdminConfig } from "@webiny/app-admin";
23
+ import { ReactComponent as Icon } from "@webiny/icons/shield.svg";
24
+
25
+ const { Security } = AdminConfig;
26
+
27
+ export const MyPermission = () => {
28
+ return (
29
+ <AdminConfig>
30
+ <Security.Permissions
31
+ name="store-manager"
32
+ title="Store Manager"
33
+ description="Manage Store Manager permissions."
34
+ icon={<Icon />}
35
+ schema={{
36
+ prefix: "sm",
37
+ fullAccess: { name: "sm.*" },
38
+ entities: [
39
+ {
40
+ id: "product",
41
+ title: "Products",
42
+ permission: "sm.product",
43
+ scopes: ["full", "own"],
44
+ actions: [
45
+ { name: "rwd" },
46
+ { name: "pw" },
47
+ { name: "import", label: "Import products" },
48
+ { name: "export", label: "Export products" }
49
+ ]
50
+ },
51
+ {
52
+ id: "category",
53
+ title: "Categories",
54
+ permission: "sm.category",
55
+ scopes: ["full"],
56
+ actions: [{ name: "rwd" }]
57
+ },
58
+ {
59
+ id: "settings",
60
+ title: "Settings",
61
+ permission: "sm.settings",
62
+ scopes: ["full"]
63
+ }
64
+ ]
65
+ }}
66
+ />
67
+ </AdminConfig>
68
+ );
69
+ };
70
+ ```
71
+
72
+ Render `<MyPermission />` anywhere in your app's extension component.
73
+
74
+ ## Schema Reference
75
+
76
+ | Field | Type | Required | Description |
77
+ | ------------ | -------------------- | -------- | -------------------------------------------------------------- |
78
+ | `prefix` | `string` | Yes | Permission prefix (e.g., `"sm"`) |
79
+ | `fullAccess` | `{ name: string }` | Yes | Permission emitted on "Full access" (e.g., `{ name: "sm.*" }`) |
80
+ | `entities` | `EntityDefinition[]` | No | Entity definitions. Omit for binary full/no access. |
81
+
82
+ ### Entity Definition
83
+
84
+ | Field | Type | Required | Description |
85
+ | ------------ | -------------------------------------- | -------- | ---------------------------------------------- |
86
+ | `id` | `string` | Yes | Unique identifier for form field naming |
87
+ | `title` | `string` | No | Display title. Falls back to `id`. |
88
+ | `permission` | `string` | Yes | Permission name emitted (e.g., `"sm.product"`) |
89
+ | `scopes` | `("full" \| "own")[]` | Yes | Available access scopes |
90
+ | `actions` | `ActionDefinition[]` | No | Actions on this entity |
91
+ | `dependsOn` | `{ entity: string; requires: string }` | No | Dependency on another entity |
92
+
93
+ ### Actions
94
+
95
+ - `{ name: "rwd" }` — Read/Write/Delete select dropdown. Auto-set to `"rwd"` when scope is `"own"`.
96
+ - `{ name: "pw" }` — Publish/Unpublish checkbox group.
97
+ - `{ name: "custom", label: "Label" }` — Custom boolean flag.
98
+
99
+ ### Entity Dependencies
100
+
101
+ Child entities can depend on a parent. If the parent lacks the required action, the child is pruned from output. `"own"` scope cascades to dependents.
102
+
103
+ ```ts
104
+ {
105
+ id: "review",
106
+ permission: "sm.review",
107
+ scopes: ["full", "own"],
108
+ actions: [{ name: "rwd" }],
109
+ dependsOn: { entity: "product", requires: "r" }
110
+ }
111
+ ```
112
+
113
+ ---
114
+
115
+ ## Simple Apps (No Entities)
116
+
117
+ Omit `entities` for binary full/no access:
118
+
119
+ ```tsx
120
+ <Security.Permissions
121
+ name="my-app"
122
+ title="My App"
123
+ description="Manage My App access permissions."
124
+ schema={{ prefix: "ma", fullAccess: { name: "ma.*" } }}
125
+ />
126
+ ```
127
+
128
+ ---
129
+
130
+ ## `Security.Permissions` Props
131
+
132
+ | Prop | Type | Required | Description |
133
+ | ------------- | ------------------ | ------------------------- | ----------------------------------------------- |
134
+ | `name` | `string` | Yes | Unique identifier for this permission renderer |
135
+ | `title` | `string` | Yes | Display title in the accordion header |
136
+ | `description` | `string` | No | Description shown below the title |
137
+ | `icon` | `ReactElement` | No | Icon in the accordion header |
138
+ | `schema` | `PermissionSchema` | One of `schema`/`element` | Auto-generate UI from schema |
139
+ | `element` | `ReactElement` | One of `schema`/`element` | Fully custom permission UI |
140
+ | `system` | `boolean` | No | If `true`, renders before app-level permissions |
141
+
142
+ ---
143
+
144
+ ## Matching API-Side Permissions
145
+
146
+ The admin schema and the API-side `createPermissions` schema should use the **same prefix, entity IDs, and action names**. This ensures the permissions emitted by the admin UI are correctly evaluated by the API.
147
+
148
+ ```
149
+ Admin: schema={{ prefix: "sm", entities: [{ id: "product", permission: "sm.product", ... }] }}
150
+ API: createPermissions({ prefix: "sm", entities: [{ id: "product", permission: "sm.product", ... }] })
151
+ ```
152
+
153
+ See **webiny-api-permissions** for the API-side implementation.
154
+
155
+ ## Related Skills
156
+
157
+ - **webiny-api-permissions** — API-side permission checking (canRead, canEdit, etc.)
158
+ - **webiny-admin-architect** — Admin architecture, headless and presentation features
159
+ - **webiny-admin-ui-extensions** — Admin UI customization, decorators, config