@plitzi/sdk-server 0.32.5 → 0.32.7

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 (175) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/core/services/mcp.js +1 -1
  3. package/dist/helpers/buildServerInfo.js +3 -9
  4. package/dist/index.js +2 -1
  5. package/dist/modules/ai/toolkit.js +1 -0
  6. package/dist/modules/mcp/catalogs/builtinCallbacks.js +204 -0
  7. package/dist/modules/mcp/catalogs/builtinComponents.js +170 -0
  8. package/dist/modules/mcp/catalogs/builtinElementCallbacks.js +50 -0
  9. package/dist/modules/mcp/catalogs/builtinTransformers.js +148 -0
  10. package/dist/modules/mcp/catalogs/builtinUtilities.js +90 -0
  11. package/dist/modules/mcp/{tools/operations/style → catalogs}/cssCatalog.js +75 -2
  12. package/dist/modules/mcp/catalogs/observed.js +90 -0
  13. package/dist/modules/mcp/catalogs/paramSpec.js +69 -0
  14. package/dist/modules/mcp/catalogs/registry.js +89 -0
  15. package/dist/modules/mcp/handler.js +41 -13
  16. package/dist/modules/mcp/helpers/agentPrompt.js +104 -0
  17. package/dist/modules/mcp/helpers/guide.js +334 -15
  18. package/dist/modules/mcp/helpers/interactions.js +123 -0
  19. package/dist/modules/mcp/helpers/log.js +54 -0
  20. package/dist/modules/mcp/helpers/space.js +184 -33
  21. package/dist/modules/mcp/helpers/uris.js +44 -0
  22. package/dist/modules/mcp/resources/canonical.js +6 -21
  23. package/dist/modules/mcp/resources/core.js +4 -3
  24. package/dist/modules/mcp/resources/primer.js +13 -8
  25. package/dist/modules/mcp/resources/register.js +37 -5
  26. package/dist/modules/mcp/resources/schema.js +30 -20
  27. package/dist/modules/mcp/resources/style.js +18 -11
  28. package/dist/modules/mcp/server.js +29 -8
  29. package/dist/modules/mcp/tools/apply/dispatch.js +38 -18
  30. package/dist/modules/mcp/tools/apply/index.js +19 -4
  31. package/dist/modules/mcp/tools/apply/writeResult.js +2 -1
  32. package/dist/modules/mcp/tools/index.js +3 -1
  33. package/dist/modules/mcp/tools/operations/index.js +13 -2
  34. package/dist/modules/mcp/tools/operations/schema/bindings/deleteBinding.js +32 -0
  35. package/dist/modules/mcp/tools/operations/schema/bindings/patchBinding.js +36 -0
  36. package/dist/modules/mcp/tools/operations/schema/bindings/upsertBinding.js +47 -0
  37. package/dist/modules/mcp/tools/operations/schema/{deleteElement.js → elements/deleteElement.js} +10 -6
  38. package/dist/modules/mcp/tools/operations/schema/{moveElement.js → elements/moveElement.js} +8 -6
  39. package/dist/modules/mcp/tools/operations/schema/{patchElement.js → elements/patchElement.js} +19 -7
  40. package/dist/modules/mcp/tools/operations/schema/{upsertElement.js → elements/upsertElement.js} +11 -5
  41. package/dist/modules/mcp/tools/operations/schema/{deleteFolder.js → folders/deleteFolder.js} +4 -4
  42. package/dist/modules/mcp/tools/operations/schema/{upsertFolder.js → folders/upsertFolder.js} +4 -4
  43. package/dist/modules/mcp/tools/operations/schema/interactions/deleteInteraction.js +52 -0
  44. package/dist/modules/mcp/tools/operations/schema/interactions/patchInteractionNode.js +47 -0
  45. package/dist/modules/mcp/tools/operations/schema/interactions/upsertInteractionFlow.js +43 -0
  46. package/dist/modules/mcp/tools/operations/schema/operations.js +25 -11
  47. package/dist/modules/mcp/tools/operations/schema/{deletePage.js → pages/deletePage.js} +8 -5
  48. package/dist/modules/mcp/tools/operations/schema/pages/upsertPage.js +75 -0
  49. package/dist/modules/mcp/tools/operations/schema/settings/patchSettings.js +45 -0
  50. package/dist/modules/mcp/tools/operations/schema/shared.js +94 -2
  51. package/dist/modules/mcp/tools/operations/schema/translator.js +77 -10
  52. package/dist/modules/mcp/tools/operations/schema/{deleteVariable.js → variables/deleteVariable.js} +3 -3
  53. package/dist/modules/mcp/tools/operations/schema/{upsertVariable.js → variables/upsertVariable.js} +4 -4
  54. package/dist/modules/mcp/tools/operations/schema/write.js +78 -13
  55. package/dist/modules/mcp/tools/operations/style/{deleteDefinition.js → definitions/deleteDefinition.js} +4 -3
  56. package/dist/modules/mcp/tools/operations/style/{patchDefinition.js → definitions/patchDefinition.js} +6 -5
  57. package/dist/modules/mcp/tools/operations/style/{upsertDefinition.js → definitions/upsertDefinition.js} +5 -4
  58. package/dist/modules/mcp/tools/operations/style/{deleteGlobalStyle.js → globalStyles/deleteGlobalStyle.js} +4 -3
  59. package/dist/modules/mcp/tools/operations/style/{patchGlobalStyle.js → globalStyles/patchGlobalStyle.js} +6 -5
  60. package/dist/modules/mcp/tools/operations/style/{upsertGlobalStyle.js → globalStyles/upsertGlobalStyle.js} +5 -4
  61. package/dist/modules/mcp/tools/operations/style/idStyles/deleteIdStyle.js +21 -0
  62. package/dist/modules/mcp/tools/operations/style/idStyles/patchIdStyle.js +28 -0
  63. package/dist/modules/mcp/tools/operations/style/idStyles/upsertIdStyle.js +24 -0
  64. package/dist/modules/mcp/tools/operations/style/operations.js +14 -8
  65. package/dist/modules/mcp/tools/operations/style/translator.js +25 -1
  66. package/dist/modules/mcp/tools/operations/style/{deleteStyleVariable.js → variables/deleteStyleVariable.js} +4 -4
  67. package/dist/modules/mcp/tools/operations/style/{upsertStyleVariable.js → variables/upsertStyleVariable.js} +4 -4
  68. package/dist/modules/mcp/tools/operations/style/write.js +19 -11
  69. package/dist/modules/mcp/tools/read.js +1 -1
  70. package/dist/modules/mcp/tools/render.js +114 -0
  71. package/dist/modules/mcp/tools/search.js +34 -27
  72. package/dist/modules/mcp/tools/shared/tool.js +1 -0
  73. package/dist/modules/mcp/tools/shared/validator/audit.js +124 -0
  74. package/dist/modules/mcp/tools/shared/validator/batch.js +30 -0
  75. package/dist/modules/mcp/tools/shared/validator/bindings.js +70 -0
  76. package/dist/modules/mcp/tools/shared/validator/context.js +35 -0
  77. package/dist/modules/mcp/tools/shared/validator/css.js +47 -0
  78. package/dist/modules/mcp/tools/shared/validator/elements.js +55 -0
  79. package/dist/modules/mcp/tools/shared/validator/index.js +226 -0
  80. package/dist/modules/mcp/tools/shared/validator/interactions.js +106 -0
  81. package/dist/modules/mcp/tools/shared/validator/refs.js +28 -0
  82. package/dist/modules/mcp/tools/validate.js +23 -3
  83. package/dist/modules/ssr/preview.js +1 -1
  84. package/dist/modules/ssr/views/template.ejs +2 -0
  85. package/dist/src/index.d.ts +1 -1
  86. package/dist/src/modules/mcp/catalogs/builtinCallbacks.d.ts +23 -0
  87. package/dist/src/modules/mcp/catalogs/builtinComponents.d.ts +4 -0
  88. package/dist/src/modules/mcp/catalogs/builtinElementCallbacks.d.ts +20 -0
  89. package/dist/src/modules/mcp/catalogs/builtinTransformers.d.ts +28 -0
  90. package/dist/src/modules/mcp/catalogs/builtinTransformers.test.d.ts +1 -0
  91. package/dist/src/modules/mcp/catalogs/builtinUtilities.d.ts +18 -0
  92. package/dist/src/modules/mcp/{tools/operations/style → catalogs}/cssCatalog.d.ts +5 -1
  93. package/dist/src/modules/mcp/catalogs/index.d.ts +9 -0
  94. package/dist/src/modules/mcp/catalogs/observed.d.ts +48 -0
  95. package/dist/src/modules/mcp/catalogs/paramSpec.d.ts +42 -0
  96. package/dist/src/modules/mcp/catalogs/registry.d.ts +35 -0
  97. package/dist/src/modules/mcp/handler.d.ts +2 -2
  98. package/dist/src/modules/mcp/helpers/agentPrompt.d.ts +4 -0
  99. package/dist/src/modules/mcp/helpers/guide.d.ts +2 -1
  100. package/dist/src/modules/mcp/helpers/index.d.ts +4 -0
  101. package/dist/src/modules/mcp/helpers/interactions.d.ts +30 -0
  102. package/dist/src/modules/mcp/helpers/log.d.ts +8 -0
  103. package/dist/src/modules/mcp/helpers/log.test.d.ts +1 -0
  104. package/dist/src/modules/mcp/helpers/space.d.ts +68 -11
  105. package/dist/src/modules/mcp/helpers/uris.d.ts +28 -0
  106. package/dist/src/modules/mcp/index.d.ts +1 -1
  107. package/dist/src/modules/mcp/mcp.bench.d.ts +1 -0
  108. package/dist/src/modules/mcp/resources/canonical.d.ts +0 -1
  109. package/dist/src/modules/mcp/resources/index.d.ts +2 -3
  110. package/dist/src/modules/mcp/resources/primer.d.ts +2 -1
  111. package/dist/src/modules/mcp/resources/register.d.ts +2 -2
  112. package/dist/src/modules/mcp/server.d.ts +5 -2
  113. package/dist/src/modules/mcp/tools/apply/index.d.ts +191 -2
  114. package/dist/src/modules/mcp/tools/index.d.ts +1 -0
  115. package/dist/src/modules/mcp/tools/operations/index.d.ts +383 -4
  116. package/dist/src/modules/mcp/tools/operations/schema/bindings/deleteBinding.d.ts +17 -0
  117. package/dist/src/modules/mcp/tools/operations/schema/bindings/patchBinding.d.ts +25 -0
  118. package/dist/src/modules/mcp/tools/operations/schema/bindings/upsertBinding.d.ts +27 -0
  119. package/dist/src/modules/mcp/tools/operations/schema/{deleteElement.d.ts → elements/deleteElement.d.ts} +2 -2
  120. package/dist/src/modules/mcp/tools/operations/schema/{moveElement.d.ts → elements/moveElement.d.ts} +2 -2
  121. package/dist/src/modules/mcp/tools/operations/schema/{patchElement.d.ts → elements/patchElement.d.ts} +7 -2
  122. package/dist/src/modules/mcp/tools/operations/schema/{upsertElement.d.ts → elements/upsertElement.d.ts} +3 -3
  123. package/dist/src/modules/mcp/tools/operations/schema/{deleteFolder.d.ts → folders/deleteFolder.d.ts} +2 -2
  124. package/dist/src/modules/mcp/tools/operations/schema/{upsertFolder.d.ts → folders/upsertFolder.d.ts} +2 -2
  125. package/dist/src/modules/mcp/tools/operations/schema/index.d.ts +17 -11
  126. package/dist/src/modules/mcp/tools/operations/schema/interactions/deleteInteraction.d.ts +12 -0
  127. package/dist/src/modules/mcp/tools/operations/schema/interactions/patchInteractionNode.d.ts +18 -0
  128. package/dist/src/modules/mcp/tools/operations/schema/interactions/upsertInteractionFlow.d.ts +27 -0
  129. package/dist/src/modules/mcp/tools/operations/schema/operations.d.ts +131 -0
  130. package/dist/src/modules/mcp/tools/operations/schema/{deletePage.d.ts → pages/deletePage.d.ts} +2 -2
  131. package/dist/src/modules/mcp/tools/operations/schema/{upsertPage.d.ts → pages/upsertPage.d.ts} +3 -2
  132. package/dist/src/modules/mcp/tools/operations/schema/settings/patchSettings.d.ts +34 -0
  133. package/dist/src/modules/mcp/tools/operations/schema/shared.d.ts +53 -0
  134. package/dist/src/modules/mcp/tools/operations/schema/translator.d.ts +5 -2
  135. package/dist/src/modules/mcp/tools/operations/schema/{deleteVariable.d.ts → variables/deleteVariable.d.ts} +2 -2
  136. package/dist/src/modules/mcp/tools/operations/schema/{upsertVariable.d.ts → variables/upsertVariable.d.ts} +2 -2
  137. package/dist/src/modules/mcp/tools/operations/schema/write.d.ts +38 -8
  138. package/dist/src/modules/mcp/tools/operations/style/{deleteDefinition.d.ts → definitions/deleteDefinition.d.ts} +2 -2
  139. package/dist/src/modules/mcp/tools/operations/style/{patchDefinition.d.ts → definitions/patchDefinition.d.ts} +2 -2
  140. package/dist/src/modules/mcp/tools/operations/style/{upsertDefinition.d.ts → definitions/upsertDefinition.d.ts} +2 -2
  141. package/dist/src/modules/mcp/tools/operations/style/{deleteGlobalStyle.d.ts → globalStyles/deleteGlobalStyle.d.ts} +2 -2
  142. package/dist/src/modules/mcp/tools/operations/style/{patchGlobalStyle.d.ts → globalStyles/patchGlobalStyle.d.ts} +2 -2
  143. package/dist/src/modules/mcp/tools/operations/style/{upsertGlobalStyle.d.ts → globalStyles/upsertGlobalStyle.d.ts} +2 -2
  144. package/dist/src/modules/mcp/tools/operations/style/idStyles/deleteIdStyle.d.ts +9 -0
  145. package/dist/src/modules/mcp/tools/operations/style/idStyles/patchIdStyle.d.ts +37 -0
  146. package/dist/src/modules/mcp/tools/operations/style/idStyles/upsertIdStyle.d.ts +37 -0
  147. package/dist/src/modules/mcp/tools/operations/style/index.d.ts +11 -9
  148. package/dist/src/modules/mcp/tools/operations/style/operations.d.ts +70 -2
  149. package/dist/src/modules/mcp/tools/operations/style/shared.d.ts +1 -1
  150. package/dist/src/modules/mcp/tools/operations/style/translator.d.ts +4 -1
  151. package/dist/src/modules/mcp/tools/operations/style/{deleteStyleVariable.d.ts → variables/deleteStyleVariable.d.ts} +3 -3
  152. package/dist/src/modules/mcp/tools/operations/style/{upsertStyleVariable.d.ts → variables/upsertStyleVariable.d.ts} +3 -3
  153. package/dist/src/modules/mcp/tools/operations/style/write.d.ts +2 -7
  154. package/dist/src/modules/mcp/tools/preview.d.ts +191 -2
  155. package/dist/src/modules/mcp/tools/render.d.ts +434 -0
  156. package/dist/src/modules/mcp/tools/render.test.d.ts +1 -0
  157. package/dist/src/modules/mcp/tools/screenshot.d.ts +191 -2
  158. package/dist/src/modules/mcp/tools/shared/tool.d.ts +4 -0
  159. package/dist/src/modules/mcp/tools/shared/validator/audit.d.ts +4 -0
  160. package/dist/src/modules/mcp/tools/shared/validator/batch.d.ts +5 -0
  161. package/dist/src/modules/mcp/tools/shared/validator/bindings.d.ts +6 -0
  162. package/dist/src/modules/mcp/tools/shared/validator/context.d.ts +34 -0
  163. package/dist/src/modules/mcp/tools/shared/validator/css.d.ts +4 -0
  164. package/dist/src/modules/mcp/tools/shared/validator/elements.d.ts +6 -0
  165. package/dist/src/modules/mcp/tools/shared/validator/index.d.ts +8 -0
  166. package/dist/src/modules/mcp/tools/shared/validator/interactions.d.ts +3 -0
  167. package/dist/src/modules/mcp/tools/shared/validator/refs.d.ts +4 -0
  168. package/dist/src/modules/mcp/tools/validate.d.ts +191 -2
  169. package/dist/src/modules/mcp/types/aiSchema.d.ts +93 -1
  170. package/package.json +12 -10
  171. package/dist/modules/mcp/tools/operations/schema/registry.js +0 -55
  172. package/dist/modules/mcp/tools/operations/schema/upsertPage.js +0 -64
  173. package/dist/modules/mcp/tools/shared/validator.js +0 -262
  174. package/dist/src/modules/mcp/tools/operations/schema/registry.d.ts +0 -22
  175. package/dist/src/modules/mcp/tools/shared/validator.d.ts +0 -4
@@ -1,5 +1,6 @@
1
- import { emptySpaceMessage, unauthorizedSpaceMessage } from "./helpers/space.js";
1
+ import { emptySpace, emptySpaceMessage, unauthorizedSpaceMessage } from "./helpers/space.js";
2
2
  import { serverInstructions } from "./helpers/guide.js";
3
+ import { createMcpLog } from "./helpers/log.js";
3
4
  import { registerResources } from "./resources/register.js";
4
5
  import { tools } from "./tools/index.js";
5
6
  import { isCallToolResult } from "../ai/toolkit.js";
@@ -10,7 +11,8 @@ var asText = (data) => ({ content: [{
10
11
  type: "text",
11
12
  text: JSON.stringify(data)
12
13
  }] });
13
- var createMcpServer = ({ adapters, getSpaceId, preview, screenshot }) => {
14
+ var createMcpServer = ({ adapters, getSpaceId, preview, screenshot, logger }) => {
15
+ const log = createMcpLog(logger);
14
16
  let spaceIdPromise;
15
17
  const requireSpaceId = () => spaceIdPromise ??= getSpaceId().then((id) => {
16
18
  if (!id) throw new Error(unauthorizedSpaceMessage);
@@ -18,11 +20,16 @@ var createMcpServer = ({ adapters, getSpaceId, preview, screenshot }) => {
18
20
  });
19
21
  const loadSpace = async () => {
20
22
  const spaceId = await requireSpaceId();
21
- const [schema, style] = await Promise.all([adapters.getSchema?.(spaceId, MCP_ENV), adapters.getStyle?.(spaceId, MCP_ENV)]);
23
+ const [schema, style, catalog] = await Promise.all([
24
+ adapters.getSchema?.(spaceId, MCP_ENV),
25
+ adapters.getStyle?.(spaceId, MCP_ENV),
26
+ adapters.getComponentCatalog?.(spaceId, MCP_ENV).catch(() => void 0)
27
+ ]);
22
28
  if (!schema || !style) throw new Error(emptySpaceMessage);
23
29
  return {
24
30
  schema,
25
- style
31
+ style,
32
+ catalog
26
33
  };
27
34
  };
28
35
  const { saveSchema, saveStyle } = adapters;
@@ -34,9 +41,9 @@ var createMcpServer = ({ adapters, getSpaceId, preview, screenshot }) => {
34
41
  const getSpace = () => spacePromise ??= loadSpace();
35
42
  const server = new McpServer({
36
43
  name: "plitzi-mcp",
37
- version: "0.3.0"
44
+ version: "0.32.7"
38
45
  }, { instructions: serverInstructions });
39
- registerResources(server, getSpace, MCP_ENV);
46
+ registerResources(server, getSpace, MCP_ENV, log);
40
47
  const toolContext = async () => ({
41
48
  space: await getSpace(),
42
49
  env: MCP_ENV,
@@ -45,6 +52,13 @@ var createMcpServer = ({ adapters, getSpaceId, preview, screenshot }) => {
45
52
  preview,
46
53
  screenshot
47
54
  });
55
+ const spacelessContext = () => ({
56
+ space: emptySpace(),
57
+ env: MCP_ENV,
58
+ persisters,
59
+ preview,
60
+ screenshot
61
+ });
48
62
  for (const tool of tools) {
49
63
  if (tool.requires === "screenshot" && !screenshot) continue;
50
64
  server.registerTool(tool.name, {
@@ -52,8 +66,15 @@ var createMcpServer = ({ adapters, getSpaceId, preview, screenshot }) => {
52
66
  description: tool.description,
53
67
  inputSchema: tool.inputShape
54
68
  }, async (args) => {
55
- const result = await tool.execute(args, await toolContext());
56
- return isCallToolResult(result) ? result : asText(result);
69
+ const start = performance.now();
70
+ try {
71
+ const result = await tool.execute(args, tool.spaceless ? spacelessContext() : await toolContext());
72
+ log.toolCall(tool.name, args, performance.now() - start);
73
+ return isCallToolResult(result) ? result : asText(result);
74
+ } catch (error) {
75
+ log.toolCall(tool.name, args, performance.now() - start, error);
76
+ throw error;
77
+ }
57
78
  });
58
79
  }
59
80
  return server;
@@ -1,22 +1,32 @@
1
1
  import { fail } from "../../helpers/opResult.js";
2
- import { deleteElement } from "../operations/schema/deleteElement.js";
3
- import { deleteFolder } from "../operations/schema/deleteFolder.js";
4
- import { deletePage } from "../operations/schema/deletePage.js";
5
- import { deleteVariable } from "../operations/schema/deleteVariable.js";
6
- import { moveElement } from "../operations/schema/moveElement.js";
7
- import { patchElement } from "../operations/schema/patchElement.js";
8
- import { upsertElement } from "../operations/schema/upsertElement.js";
9
- import { upsertFolder } from "../operations/schema/upsertFolder.js";
10
- import { upsertPage } from "../operations/schema/upsertPage.js";
11
- import { upsertVariable } from "../operations/schema/upsertVariable.js";
12
- import { deleteDefinition } from "../operations/style/deleteDefinition.js";
13
- import { deleteGlobalStyle } from "../operations/style/deleteGlobalStyle.js";
14
- import { deleteStyleVariable } from "../operations/style/deleteStyleVariable.js";
15
- import { patchDefinition } from "../operations/style/patchDefinition.js";
16
- import { patchGlobalStyle } from "../operations/style/patchGlobalStyle.js";
17
- import { upsertDefinition } from "../operations/style/upsertDefinition.js";
18
- import { upsertGlobalStyle } from "../operations/style/upsertGlobalStyle.js";
19
- import { upsertStyleVariable } from "../operations/style/upsertStyleVariable.js";
2
+ import { deleteBinding } from "../operations/schema/bindings/deleteBinding.js";
3
+ import { patchBinding } from "../operations/schema/bindings/patchBinding.js";
4
+ import { upsertBinding } from "../operations/schema/bindings/upsertBinding.js";
5
+ import { deleteElement } from "../operations/schema/elements/deleteElement.js";
6
+ import { moveElement } from "../operations/schema/elements/moveElement.js";
7
+ import { patchElement } from "../operations/schema/elements/patchElement.js";
8
+ import { upsertElement } from "../operations/schema/elements/upsertElement.js";
9
+ import { deleteFolder } from "../operations/schema/folders/deleteFolder.js";
10
+ import { upsertFolder } from "../operations/schema/folders/upsertFolder.js";
11
+ import { deleteInteraction } from "../operations/schema/interactions/deleteInteraction.js";
12
+ import { patchInteractionNode } from "../operations/schema/interactions/patchInteractionNode.js";
13
+ import { upsertInteractionFlow } from "../operations/schema/interactions/upsertInteractionFlow.js";
14
+ import { deletePage } from "../operations/schema/pages/deletePage.js";
15
+ import { upsertPage } from "../operations/schema/pages/upsertPage.js";
16
+ import { patchSettings } from "../operations/schema/settings/patchSettings.js";
17
+ import { deleteVariable } from "../operations/schema/variables/deleteVariable.js";
18
+ import { upsertVariable } from "../operations/schema/variables/upsertVariable.js";
19
+ import { deleteDefinition } from "../operations/style/definitions/deleteDefinition.js";
20
+ import { patchDefinition } from "../operations/style/definitions/patchDefinition.js";
21
+ import { upsertDefinition } from "../operations/style/definitions/upsertDefinition.js";
22
+ import { deleteGlobalStyle } from "../operations/style/globalStyles/deleteGlobalStyle.js";
23
+ import { patchGlobalStyle } from "../operations/style/globalStyles/patchGlobalStyle.js";
24
+ import { upsertGlobalStyle } from "../operations/style/globalStyles/upsertGlobalStyle.js";
25
+ import { deleteIdStyle } from "../operations/style/idStyles/deleteIdStyle.js";
26
+ import { patchIdStyle } from "../operations/style/idStyles/patchIdStyle.js";
27
+ import { upsertIdStyle } from "../operations/style/idStyles/upsertIdStyle.js";
28
+ import { deleteStyleVariable } from "../operations/style/variables/deleteStyleVariable.js";
29
+ import { upsertStyleVariable } from "../operations/style/variables/upsertStyleVariable.js";
20
30
  import { isStyleOp } from "../operations/index.js";
21
31
  //#region src/modules/mcp/tools/apply/dispatch.ts
22
32
  var executeOp = (space, env, op) => {
@@ -31,12 +41,22 @@ var executeOp = (space, env, op) => {
31
41
  case "deleteFolder": return deleteFolder(space, env, op);
32
42
  case "upsertVariable": return upsertVariable(space, env, op);
33
43
  case "deleteVariable": return deleteVariable(space, env, op);
44
+ case "upsertBinding": return upsertBinding(space, env, op);
45
+ case "patchBinding": return patchBinding(space, env, op);
46
+ case "deleteBinding": return deleteBinding(space, env, op);
47
+ case "upsertInteractionFlow": return upsertInteractionFlow(space, env, op);
48
+ case "patchInteractionNode": return patchInteractionNode(space, env, op);
49
+ case "deleteInteraction": return deleteInteraction(space, env, op);
50
+ case "patchSettings": return patchSettings(space, env, op);
34
51
  case "upsertDefinition": return upsertDefinition(space, env, op);
35
52
  case "patchDefinition": return patchDefinition(space, env, op);
36
53
  case "deleteDefinition": return deleteDefinition(space, env, op);
37
54
  case "upsertGlobalStyle": return upsertGlobalStyle(space, env, op);
38
55
  case "patchGlobalStyle": return patchGlobalStyle(space, env, op);
39
56
  case "deleteGlobalStyle": return deleteGlobalStyle(space, env, op);
57
+ case "upsertIdStyle": return upsertIdStyle(space, env, op);
58
+ case "patchIdStyle": return patchIdStyle(space, env, op);
59
+ case "deleteIdStyle": return deleteIdStyle(space, env, op);
40
60
  case "upsertStyleVariable": return upsertStyleVariable(space, env, op);
41
61
  case "deleteStyleVariable": return deleteStyleVariable(space, env, op);
42
62
  default: return fail("type", `Unknown operation "${op.type}"`, "See the Operation union");
@@ -3,7 +3,8 @@ import { environment, operations } from "../operations/index.js";
3
3
  import { applyOperations } from "./dispatch.js";
4
4
  import { changedResources, conflictMessage, detectConflicts, resolvedElements } from "./writeResult.js";
5
5
  import { defineTool } from "../shared/tool.js";
6
- import { validateOperations } from "../shared/validator.js";
6
+ import { validateOperations } from "../shared/validator/index.js";
7
+ import { auditResources } from "../shared/validator/audit.js";
7
8
  import { z } from "zod";
8
9
  import { validateSchema } from "@plitzi/sdk-schema";
9
10
  //#region src/modules/mcp/tools/apply/index.ts
@@ -76,6 +77,20 @@ var apply = async (input, space, persisters) => {
76
77
  errors: integrity.errors.map(schemaErrorToValidation),
77
78
  warnings: noWarnings(validation.warnings)
78
79
  };
80
+ const audit = auditResources(draft, input.operations);
81
+ const warnings = [...validation.warnings, ...audit.warnings];
82
+ if (audit.errors.length > 0) return {
83
+ applied: false,
84
+ persisted: false,
85
+ summary: {
86
+ created: 0,
87
+ updated: 0,
88
+ deleted: 0
89
+ },
90
+ changed: [],
91
+ errors: audit.errors,
92
+ warnings: noWarnings(warnings)
93
+ };
79
94
  if (input.dryRun) return {
80
95
  applied: false,
81
96
  dryRun: true,
@@ -86,7 +101,7 @@ var apply = async (input, space, persisters) => {
86
101
  },
87
102
  changed: changedResources(draft, env, outcome.staleResources),
88
103
  elements: resolvedElements(draft, env, outcome.elementRefs),
89
- warnings: noWarnings(validation.warnings)
104
+ warnings: noWarnings(warnings)
90
105
  };
91
106
  let persisted = true;
92
107
  if (outcome.changedSchema) if (persisters?.schema) await persisters.schema(draft.schema);
@@ -103,13 +118,13 @@ var apply = async (input, space, persisters) => {
103
118
  },
104
119
  changed: changedResources(draft, env, outcome.staleResources),
105
120
  elements: resolvedElements(draft, env, outcome.elementRefs),
106
- warnings: noWarnings(validation.warnings)
121
+ warnings: noWarnings(warnings)
107
122
  };
108
123
  };
109
124
  var applyTool = defineTool({
110
125
  name: "plitzi_apply",
111
126
  title: "Apply",
112
- description: "Validate, apply and persist a batch of operations atomically. Returns the changed resources and their new versions, plus the full detail of every element it created or updated. Pass dryRun to apply in memory only (inspect the outcome without committing). Rejects the whole batch on any error or version conflict.",
127
+ description: "Validate, apply and persist a batch of operations atomically. Returns the changed resources and their new versions, plus the full detail of every element it created or updated. Pass dryRun to apply in memory only (inspect the outcome without committing). Rejects the whole batch on any error or version conflict — INCLUDING a pre-existing malformation in any resource the batch touches (fix it in the same batch to unblock the save).",
113
128
  inputShape: applyShape,
114
129
  access: "write",
115
130
  run: (input, ctx) => apply({
@@ -1,3 +1,4 @@
1
+ import { elementUri } from "../../helpers/uris.js";
1
2
  import { readResource, resourceVersion } from "../../resources/router.js";
2
3
  //#region src/modules/mcp/tools/apply/writeResult.ts
3
4
  var detectConflicts = (space, env, expected) => {
@@ -21,7 +22,7 @@ var changedResources = (space, env, uris) => uris.map((uri) => ({
21
22
  * in the same batch). Returns undefined when there is nothing, so the field stays off the response. */
22
23
  var resolvedElements = (space, env, refs) => {
23
24
  const elements = refs.map((ref) => {
24
- const uri = `plitzi://schema/${env}/elements/${ref}`;
25
+ const uri = elementUri(env, ref);
25
26
  const res = readResource(space, env, uri);
26
27
  return res ? {
27
28
  uri,
@@ -1,9 +1,10 @@
1
1
  import { operation } from "./operations/index.js";
2
2
  import { applyOperations } from "./apply/dispatch.js";
3
- import { validateOperations } from "./shared/validator.js";
3
+ import { validateOperations } from "./shared/validator/index.js";
4
4
  import { apply, applyShape, applyTool } from "./apply/index.js";
5
5
  import { previewTool } from "./preview.js";
6
6
  import { read, readShape, readTool } from "./read.js";
7
+ import { renderTool } from "./render.js";
7
8
  import { screenshotTool } from "./screenshot.js";
8
9
  import { search, searchShape, searchTool } from "./search.js";
9
10
  import { validate, validateShape, validateTool } from "./validate.js";
@@ -15,6 +16,7 @@ var tools = [
15
16
  validateTool,
16
17
  searchTool,
17
18
  readTool,
19
+ renderTool,
18
20
  previewTool,
19
21
  screenshotTool
20
22
  ];
@@ -13,18 +13,29 @@ var operation = z.discriminatedUnion("type", [
13
13
  elementOps.deleteFolder,
14
14
  elementOps.upsertVariable,
15
15
  elementOps.deleteVariable,
16
+ elementOps.upsertBinding,
17
+ elementOps.patchBinding,
18
+ elementOps.deleteBinding,
19
+ elementOps.upsertInteractionFlow,
20
+ elementOps.patchInteractionNode,
21
+ elementOps.deleteInteraction,
22
+ elementOps.patchSettings,
16
23
  styleOps.upsertDefinition,
17
24
  styleOps.patchDefinition,
18
25
  styleOps.deleteDefinition,
19
26
  styleOps.upsertGlobalStyle,
20
27
  styleOps.patchGlobalStyle,
21
28
  styleOps.deleteGlobalStyle,
29
+ styleOps.upsertIdStyle,
30
+ styleOps.patchIdStyle,
31
+ styleOps.deleteIdStyle,
22
32
  styleOps.upsertStyleVariable,
23
33
  styleOps.deleteStyleVariable
24
34
  ]);
25
35
  var STYLE_OP_TYPES = new Set(Object.keys(styleOps));
26
36
  var isStyleOp = (type) => STYLE_OP_TYPES.has(type);
37
+ var MAX_OPS = 1e3;
27
38
  var environment = z.string().optional().describe("Environment; default main");
28
- var operations = z.array(operation).max(100).describe("Operations applied atomically, in order (max 100)");
39
+ var operations = z.array(operation).max(MAX_OPS).describe(`Operations applied atomically, in order (max ${MAX_OPS})`);
29
40
  //#endregion
30
- export { environment, isStyleOp, operation, operations };
41
+ export { MAX_OPS, environment, isStyleOp, operation, operations };
@@ -0,0 +1,32 @@
1
+ import { pageUri } from "../../../../helpers/uris.js";
2
+ import { empty, fail } from "../../../../helpers/opResult.js";
3
+ import { bindingCategory } from "../shared.js";
4
+ import { resolveElement } from "../write.js";
5
+ import { z } from "zod";
6
+ //#region src/modules/mcp/tools/operations/schema/bindings/deleteBinding.ts
7
+ var deleteBindingOp = z.object({
8
+ type: z.literal("deleteBinding"),
9
+ pageRef: z.string().describe("Page ref or id"),
10
+ ref: z.string().describe("Element ref or id"),
11
+ category: bindingCategory,
12
+ to: z.string().describe("Target of the binding to remove"),
13
+ id: z.string().optional().describe("Match by id instead of to")
14
+ }).describe("Remove a data binding from an element (matched by id when given, else by to). Fails if none matches.");
15
+ var deleteBinding = (space, env, op) => {
16
+ const found = resolveElement(space, env, op.pageRef, op.ref);
17
+ if ("error" in found) return found.error;
18
+ const bindings = found.el.definition.bindings;
19
+ const list = bindings?.[op.category];
20
+ const index = list ? list.findIndex((b) => op.id ? b.id === op.id : b.to === op.to) : -1;
21
+ if (!bindings || !list || index < 0) return fail("to", `No ${op.category} binding matching "${op.id ?? op.to}" on "${op.ref}"`, "Nothing to delete");
22
+ list.splice(index, 1);
23
+ if (list.length === 0) Reflect.deleteProperty(bindings, op.category);
24
+ return {
25
+ ...empty(),
26
+ deleted: 1,
27
+ staleResources: [pageUri(env, op.pageRef)],
28
+ elementRefs: [op.ref]
29
+ };
30
+ };
31
+ //#endregion
32
+ export { deleteBinding, deleteBindingOp };
@@ -0,0 +1,36 @@
1
+ import { pageUri } from "../../../../helpers/uris.js";
2
+ import { empty, fail } from "../../../../helpers/opResult.js";
3
+ import { bindingCategory, bindingInput } from "../shared.js";
4
+ import { resolveElement } from "../write.js";
5
+ import { z } from "zod";
6
+ //#region src/modules/mcp/tools/operations/schema/bindings/patchBinding.ts
7
+ var patchBindingOp = z.object({
8
+ type: z.literal("patchBinding"),
9
+ pageRef: z.string().describe("Page ref or id"),
10
+ ref: z.string().describe("Element ref or id"),
11
+ category: bindingCategory,
12
+ to: z.string().describe("Target of the binding to patch"),
13
+ id: z.string().optional().describe("Match by id instead of to"),
14
+ source: bindingInput.shape.source.optional(),
15
+ transformers: bindingInput.shape.transformers,
16
+ when: bindingInput.shape.when,
17
+ enabled: bindingInput.shape.enabled
18
+ }).describe("Partially update an EXISTING binding (matched by id when given, else by to): only the fields you pass change. Never creates — fails if no binding matches.");
19
+ var patchBinding = (space, env, op) => {
20
+ const found = resolveElement(space, env, op.pageRef, op.ref);
21
+ if ("error" in found) return found.error;
22
+ const binding = (found.el.definition.bindings?.[op.category])?.find((b) => op.id ? b.id === op.id : b.to === op.to);
23
+ if (!binding) return fail("to", `No ${op.category} binding matching "${op.id ?? op.to}" on "${op.ref}"`, "Use upsertBinding to add it");
24
+ if (op.source !== void 0) binding.source = op.source;
25
+ if (op.transformers !== void 0) binding.transformers = op.transformers;
26
+ if (op.when !== void 0) binding.when = op.when;
27
+ if (op.enabled !== void 0) binding.enabled = op.enabled;
28
+ return {
29
+ ...empty(),
30
+ updated: 1,
31
+ staleResources: [pageUri(env, op.pageRef)],
32
+ elementRefs: [op.ref]
33
+ };
34
+ };
35
+ //#endregion
36
+ export { patchBinding, patchBindingOp };
@@ -0,0 +1,47 @@
1
+ import { generateObjectId } from "../../../../helpers/space.js";
2
+ import { pageUri } from "../../../../helpers/uris.js";
3
+ import { empty } from "../../../../helpers/opResult.js";
4
+ import { bindingCategory, bindingInput } from "../shared.js";
5
+ import { resolveElement } from "../write.js";
6
+ import { z } from "zod";
7
+ //#region src/modules/mcp/tools/operations/schema/bindings/upsertBinding.ts
8
+ var upsertBindingOp = z.object({
9
+ type: z.literal("upsertBinding"),
10
+ pageRef: z.string().describe("Page ref or id"),
11
+ ref: z.string().describe("Element ref or id"),
12
+ category: bindingCategory,
13
+ binding: bindingInput
14
+ }).describe("Add a data binding to an element, or replace the one already feeding the same target (matched by binding.id when given, else by binding.to). Connects a data source to a prop, style value, or initialState key.");
15
+ var upsertBinding = (space, env, op) => {
16
+ const found = resolveElement(space, env, op.pageRef, op.ref);
17
+ if ("error" in found) return found.error;
18
+ const bindings = found.el.definition.bindings ??= {};
19
+ const list = bindings[op.category] ??= [];
20
+ const index = list.findIndex((b) => op.binding.id ? b.id === op.binding.id : b.to === op.binding.to);
21
+ const binding = {
22
+ id: op.binding.id ?? (index >= 0 ? list[index].id : generateObjectId()),
23
+ to: op.binding.to,
24
+ source: op.binding.source
25
+ };
26
+ if (op.binding.transformers) binding.transformers = op.binding.transformers;
27
+ if (op.binding.when !== void 0) binding.when = op.binding.when;
28
+ if (op.binding.enabled !== void 0) binding.enabled = op.binding.enabled;
29
+ if (index >= 0) {
30
+ list[index] = binding;
31
+ return {
32
+ ...empty(),
33
+ updated: 1,
34
+ staleResources: [pageUri(env, op.pageRef)],
35
+ elementRefs: [op.ref]
36
+ };
37
+ }
38
+ list.push(binding);
39
+ return {
40
+ ...empty(),
41
+ created: 1,
42
+ staleResources: [pageUri(env, op.pageRef)],
43
+ elementRefs: [op.ref]
44
+ };
45
+ };
46
+ //#endregion
47
+ export { upsertBinding, upsertBindingOp };
@@ -1,8 +1,9 @@
1
- import { descendantIds, findPageByRef, resolveRef } from "../../../helpers/space.js";
2
- import { empty, fail } from "../../../helpers/opResult.js";
3
- import { pageUri, removeFromParent } from "./write.js";
1
+ import { descendantIds, findPageByRef, indexRemoveElements, resolveRef } from "../../../../helpers/space.js";
2
+ import { pageUri } from "../../../../helpers/uris.js";
3
+ import { empty, fail } from "../../../../helpers/opResult.js";
4
+ import { removeFromParent } from "../write.js";
4
5
  import { z } from "zod";
5
- //#region src/modules/mcp/tools/operations/schema/deleteElement.ts
6
+ //#region src/modules/mcp/tools/operations/schema/elements/deleteElement.ts
6
7
  var deleteElementOp = z.object({
7
8
  type: z.literal("deleteElement"),
8
9
  pageRef: z.string().describe("Page ref or id"),
@@ -13,8 +14,11 @@ var deleteElement = (space, env, op) => {
13
14
  if (!page) return fail("pageRef", `Page "${op.pageRef}" not found`, "Read the pages resource for valid refs");
14
15
  const el = resolveRef(space.schema, page, op.ref);
15
16
  if (!el || el.id === page.id) return fail("ref", `Element "${op.ref}" not found in page "${op.pageRef}"`, "Read the page resource for valid refs");
16
- for (const id of [...descendantIds(space.schema, el.id), el.id]) Reflect.deleteProperty(space.schema.flat, id);
17
- removeFromParent(space, el.id);
17
+ const ids = [...descendantIds(space.schema, el.id), el.id];
18
+ const removed = ids.map((id) => space.schema.flat[id]);
19
+ for (const id of ids) Reflect.deleteProperty(space.schema.flat, id);
20
+ removeFromParent(space, el);
21
+ indexRemoveElements(space.schema, removed);
18
22
  return {
19
23
  ...empty(),
20
24
  deleted: 1,
@@ -1,9 +1,10 @@
1
- import { findPageByRef, resolveRef } from "../../../helpers/space.js";
2
- import { empty, fail } from "../../../helpers/opResult.js";
3
- import { pageUri, placeChild, removeFromParent } from "./write.js";
4
- import { position } from "./shared.js";
1
+ import { findPageByRef, indexInvalidateDetails, resolveRef } from "../../../../helpers/space.js";
2
+ import { pageUri } from "../../../../helpers/uris.js";
3
+ import { empty, fail } from "../../../../helpers/opResult.js";
4
+ import { position } from "../shared.js";
5
+ import { placeChild, removeFromParent } from "../write.js";
5
6
  import { z } from "zod";
6
- //#region src/modules/mcp/tools/operations/schema/moveElement.ts
7
+ //#region src/modules/mcp/tools/operations/schema/elements/moveElement.ts
7
8
  var moveElementOp = z.object({
8
9
  type: z.literal("moveElement"),
9
10
  pageRef: z.string().describe("Page ref or id"),
@@ -18,7 +19,7 @@ var moveElement = (space, env, op) => {
18
19
  const anchor = resolveRef(space.schema, page, op.toParentRef);
19
20
  if (!el || el.id === page.id) return fail("ref", `Element "${op.ref}" not found`, "Read the page resource for valid refs");
20
21
  if (!anchor) return fail("toParentRef", `Target "${op.toParentRef}" not found`, "Read the page resource for valid refs");
21
- removeFromParent(space, el.id);
22
+ removeFromParent(space, el);
22
23
  let parent = anchor;
23
24
  let index;
24
25
  if (op.position === "before" || op.position === "after") {
@@ -28,6 +29,7 @@ var moveElement = (space, env, op) => {
28
29
  }
29
30
  el.definition.parentId = parent.id;
30
31
  placeChild(parent, el.id, index);
32
+ indexInvalidateDetails(space.schema);
31
33
  return {
32
34
  ...empty(),
33
35
  updated: 1,
@@ -1,23 +1,34 @@
1
- import { findPageByRef, resolveRef } from "../../../helpers/space.js";
2
- import { empty, fail } from "../../../helpers/opResult.js";
3
- import { pageUri } from "./write.js";
4
- import { styleRefs } from "./shared.js";
1
+ import { findPageByRef, resolveRef } from "../../../../helpers/space.js";
2
+ import { pageUri } from "../../../../helpers/uris.js";
3
+ import { empty, fail } from "../../../../helpers/opResult.js";
4
+ import { initialStateInput, styleRefs } from "../shared.js";
5
+ import { guardNewRef, writeInitialState } from "../write.js";
5
6
  import { z } from "zod";
6
- //#region src/modules/mcp/tools/operations/schema/patchElement.ts
7
+ import { repointIdRefs } from "@plitzi/sdk-schema/helpers/idRef";
8
+ //#region src/modules/mcp/tools/operations/schema/elements/patchElement.ts
7
9
  var patchElementOp = z.object({
8
10
  type: z.literal("patchElement"),
9
11
  pageRef: z.string().describe("Page ref or id"),
10
12
  ref: z.string().describe("Existing element ref or id"),
13
+ idRef: z.string().optional().describe("Assign or rename the idRef of this element ([A-Za-z0-9_-], starting with a letter, unique in the space). Give an element one to make it bindable: without an idRef it publishes no data source. Renaming one moves its source name with it — every binding and interaction across the space that targeted the old name is repointed for you, so the wiring survives the rename."),
11
14
  label: z.string().optional(),
12
15
  subType: z.string().optional(),
13
16
  props: z.record(z.string(), z.unknown()).optional().describe("Merged onto existing props: listed keys change, null unsets a key, others are preserved"),
14
- style: styleRefs.optional().describe("Merged onto existing style: base replaces base, listed slots replace slots")
15
- }).describe("Partially update an EXISTING element: only the fields you pass change (props/style are merged, not replaced). Never creates — fails if ref does not resolve. Use upsertElement to create or fully replace.");
17
+ style: styleRefs.optional().describe("Merged onto existing style: base replaces base, listed slots replace slots"),
18
+ initialState: initialStateInput.optional().describe("Merged onto existing initialState: styleVariant overlays per class/selector, visibility overrides")
19
+ }).describe("Partially update an EXISTING element: only the fields you pass change (props/style/initialState are merged, not replaced). Never creates — fails if ref does not resolve. Use upsertElement to create or fully replace.");
16
20
  var patchElement = (space, env, op) => {
17
21
  const page = findPageByRef(space.schema, op.pageRef);
18
22
  if (!page) return fail("pageRef", `Page "${op.pageRef}" not found`, "Read plitzi://schema/" + env + "/pages for valid refs");
19
23
  const el = resolveRef(space.schema, page, op.ref);
20
24
  if (!el || el.id === page.id) return fail("ref", `Element "${op.ref}" not found in page "${op.pageRef}"`, "patchElement only updates an existing element; use upsertElement to create one");
25
+ if (op.idRef !== void 0 && op.idRef !== el.idRef) {
26
+ const guard = guardNewRef(space, op.idRef, "idRef");
27
+ if (guard) return guard;
28
+ const previous = el.idRef;
29
+ el.idRef = op.idRef;
30
+ if (previous) repointIdRefs(space.schema.flat, { [previous]: op.idRef });
31
+ }
21
32
  if (op.label !== void 0) el.definition.label = op.label;
22
33
  if (op.subType !== void 0) el.attributes = {
23
34
  ...el.attributes,
@@ -35,6 +46,7 @@ var patchElement = (space, env, op) => {
35
46
  for (const [slot, classes] of Object.entries(op.style.slots ?? {})) selectors[slot] = classes.join(" ");
36
47
  el.definition.styleSelectors = selectors;
37
48
  }
49
+ if (op.initialState !== void 0) writeInitialState(el, op.initialState, true);
38
50
  return {
39
51
  ...empty(),
40
52
  updated: 1,
@@ -1,9 +1,10 @@
1
- import { findPageByRef, resolveRef } from "../../../helpers/space.js";
2
- import { empty, fail } from "../../../helpers/opResult.js";
3
- import { createElement, pageUri } from "./write.js";
4
- import { elementInput, position } from "./shared.js";
1
+ import { findPageByRef, resolveRef } from "../../../../helpers/space.js";
2
+ import { pageUri } from "../../../../helpers/uris.js";
3
+ import { empty, fail } from "../../../../helpers/opResult.js";
4
+ import { elementInput, position } from "../shared.js";
5
+ import { collectInputRefs, createElement, guardNewRef, writeInitialState } from "../write.js";
5
6
  import { z } from "zod";
6
- //#region src/modules/mcp/tools/operations/schema/upsertElement.ts
7
+ //#region src/modules/mcp/tools/operations/schema/elements/upsertElement.ts
7
8
  var upsertElementOp = z.object({
8
9
  type: z.literal("upsertElement"),
9
10
  pageRef: z.string().describe("Page ref or id"),
@@ -29,6 +30,7 @@ var upsertElement = (space, env, op) => {
29
30
  for (const [slot, classes] of Object.entries(op.element.style.slots ?? {})) selectors[slot] = classes.join(" ");
30
31
  existing.definition.styleSelectors = selectors;
31
32
  }
33
+ if (op.element.initialState !== void 0) writeInitialState(existing, op.element.initialState, false);
32
34
  return {
33
35
  ...empty(),
34
36
  updated: 1,
@@ -36,6 +38,10 @@ var upsertElement = (space, env, op) => {
36
38
  elementRefs: [op.element.ref]
37
39
  };
38
40
  }
41
+ for (const ref of collectInputRefs(op.element)) {
42
+ const guard = guardNewRef(space, ref, "element.ref");
43
+ if (guard) return guard;
44
+ }
39
45
  let parent = page;
40
46
  let index;
41
47
  if (op.parentRef) {
@@ -1,8 +1,8 @@
1
- import { findFolderByRef, isPageElement, pageFoldersOf, sortFolders } from "../../../helpers/space.js";
2
- import { empty, fail } from "../../../helpers/opResult.js";
3
- import { folderUri, foldersUri, pagesUri } from "./write.js";
1
+ import { findFolderByRef, isPageElement, pageFoldersOf, sortFolders } from "../../../../helpers/space.js";
2
+ import { folderUri, foldersUri, pagesUri } from "../../../../helpers/uris.js";
3
+ import { empty, fail } from "../../../../helpers/opResult.js";
4
4
  import { z } from "zod";
5
- //#region src/modules/mcp/tools/operations/schema/deleteFolder.ts
5
+ //#region src/modules/mcp/tools/operations/schema/folders/deleteFolder.ts
6
6
  var deleteFolderOp = z.object({
7
7
  type: z.literal("deleteFolder"),
8
8
  ref: z.string()
@@ -1,8 +1,8 @@
1
- import { findFolderByRef, pageFoldersOf, slugify, sortFolders } from "../../../helpers/space.js";
2
- import { empty, fail } from "../../../helpers/opResult.js";
3
- import { folderUri, foldersUri } from "./write.js";
1
+ import { findFolderByRef, pageFoldersOf, slugify, sortFolders } from "../../../../helpers/space.js";
2
+ import { folderUri, foldersUri } from "../../../../helpers/uris.js";
3
+ import { empty, fail } from "../../../../helpers/opResult.js";
4
4
  import { z } from "zod";
5
- //#region src/modules/mcp/tools/operations/schema/upsertFolder.ts
5
+ //#region src/modules/mcp/tools/operations/schema/folders/upsertFolder.ts
6
6
  var upsertFolderOp = z.object({
7
7
  type: z.literal("upsertFolder"),
8
8
  ref: z.string().describe("Folder ref: an existing folder id/name/slug to update, or a new id you choose"),
@@ -0,0 +1,52 @@
1
+ import { pageUri } from "../../../../helpers/uris.js";
2
+ import { empty, fail } from "../../../../helpers/opResult.js";
3
+ import { resolveElement } from "../write.js";
4
+ import { z } from "zod";
5
+ //#region src/modules/mcp/tools/operations/schema/interactions/deleteInteraction.ts
6
+ var deleteInteractionOp = z.object({
7
+ type: z.literal("deleteInteraction"),
8
+ pageRef: z.string().describe("Page ref or id"),
9
+ ref: z.string().describe("Element ref or id"),
10
+ flowId: z.string().optional().describe("Remove the whole flow with this id (the trigger node id)"),
11
+ nodeId: z.string().optional().describe("Remove a single step; its neighbors are re-linked. Deleting a trigger removes its flow")
12
+ }).describe("DESTRUCTIVE, not undoable — remove an interaction flow (by flowId) or a single step (by nodeId). Provide exactly one. To merely turn a step OFF without removing it, use patchInteractionNode { enabled: false } instead. Confirm with the user before deleting.");
13
+ var removeFlow = (interactions, flowId) => {
14
+ let deleted = 0;
15
+ for (const [nodeId, node] of Object.entries(interactions)) if ((node.flowId || node.id) === flowId) {
16
+ Reflect.deleteProperty(interactions, nodeId);
17
+ deleted++;
18
+ }
19
+ return deleted;
20
+ };
21
+ var deleteInteraction = (space, env, op) => {
22
+ if (Boolean(op.flowId) === Boolean(op.nodeId)) return fail("nodeId", "Provide exactly one of flowId or nodeId", "flowId removes a whole flow; nodeId removes a step");
23
+ const found = resolveElement(space, env, op.pageRef, op.ref);
24
+ if ("error" in found) return found.error;
25
+ const interactions = found.el.definition.interactions;
26
+ if (!interactions) return fail("ref", `Element "${op.ref}" has no interactions`, "Nothing to delete");
27
+ let deleted = 0;
28
+ if (op.flowId) deleted = removeFlow(interactions, op.flowId);
29
+ else if (op.nodeId) {
30
+ if (!(op.nodeId in interactions)) return fail("nodeId", `Interaction node "${op.nodeId}" not found on "${op.ref}"`, "Read the element to list nodes");
31
+ const node = interactions[op.nodeId];
32
+ if (node.type === "trigger") deleted = removeFlow(interactions, node.flowId || node.id);
33
+ else {
34
+ const before = node.beforeNode ? interactions[node.beforeNode] : void 0;
35
+ const after = node.afterNode ? interactions[node.afterNode] : void 0;
36
+ if (before) before.afterNode = node.afterNode;
37
+ if (after) after.beforeNode = node.beforeNode;
38
+ Reflect.deleteProperty(interactions, op.nodeId);
39
+ deleted = 1;
40
+ }
41
+ }
42
+ if (deleted === 0) return fail("flowId", `No interaction matching "${op.flowId ?? op.nodeId}" on "${op.ref}"`, "Nothing to delete");
43
+ if (Object.keys(interactions).length === 0) Reflect.deleteProperty(found.el.definition, "interactions");
44
+ return {
45
+ ...empty(),
46
+ deleted,
47
+ staleResources: [pageUri(env, op.pageRef)],
48
+ elementRefs: [op.ref]
49
+ };
50
+ };
51
+ //#endregion
52
+ export { deleteInteraction, deleteInteractionOp };