@appaflytech/zeyrek-ai-mcp 0.0.33 → 0.0.35

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 (170) hide show
  1. package/.env.example +0 -15
  2. package/dist/config.js +0 -11
  3. package/dist/index.js +0 -2
  4. package/dist/knowledge/boxSections.js +184 -0
  5. package/dist/knowledge/componentCatalog.js +634 -255
  6. package/dist/knowledge/componentEvents.js +38 -32
  7. package/dist/knowledge/layoutSummary.js +2 -140
  8. package/dist/knowledge/normalize.js +144 -117
  9. package/dist/knowledge/rules.js +42 -291
  10. package/dist/knowledge/styleResolve.js +53 -58
  11. package/dist/knowledge/themeResolve.js +4 -4
  12. package/dist/knowledge/themeSchema.js +2 -1
  13. package/dist/observability/trace.js +1 -1
  14. package/dist/platform/diagnostics.js +4 -10
  15. package/dist/platform/domSummary.js +1 -1
  16. package/dist/platform/http.js +7 -23
  17. package/dist/platform/responses.js +2 -6
  18. package/dist/platform/screenshot.js +1162 -0
  19. package/dist/platform/secrets.js +0 -9
  20. package/dist/platform/strictArguments.js +12 -68
  21. package/dist/platform/tokenVault.js +4 -187
  22. package/dist/resources/examples/layout-app-shell.json +707 -229
  23. package/dist/resources/examples/page-flex-sections.json +1 -1
  24. package/dist/resources/guides/component.md +6 -14
  25. package/dist/resources/guides/entity.md +5 -3
  26. package/dist/resources/guides/expressions.md +5 -14
  27. package/dist/resources/guides/functions.md +1 -1
  28. package/dist/resources/guides/layout.md +58 -55
  29. package/dist/resources/guides/microservice.md +2 -9
  30. package/dist/resources/guides/middleware.md +2 -34
  31. package/dist/resources/guides/page.md +179 -256
  32. package/dist/resources/guides/theme.md +3 -8
  33. package/dist/resources/guides/translation.md +1 -1
  34. package/dist/resources/guides/workflow.md +1 -7
  35. package/dist/resources/schema-fingerprint.json +4 -4
  36. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +1 -3
  37. package/dist/resources/schemas/MicroserviceDto.json +2 -2
  38. package/dist/server.js +1 -7
  39. package/dist/tools/applications.js +3 -60
  40. package/dist/tools/components.js +16 -103
  41. package/dist/tools/datasources.js +1 -1
  42. package/dist/tools/designSchemaPatch.js +19 -23
  43. package/dist/tools/externalComponents.js +4 -25
  44. package/dist/tools/flows.js +13 -80
  45. package/dist/tools/layouts.js +20 -48
  46. package/dist/tools/microservices.js +10 -32
  47. package/dist/tools/pages.js +115 -396
  48. package/dist/tools/platformInfo.js +2 -7
  49. package/dist/tools/rows.js +1 -7
  50. package/dist/tools/schemaOps.js +4 -35
  51. package/dist/tools/screenWrite.js +37 -25
  52. package/dist/tools/screens.js +4 -91
  53. package/dist/tools/variables.js +5 -11
  54. package/package.json +2 -2
  55. package/dist/knowledge/access.js +0 -802
  56. package/dist/knowledge/case.js +0 -41
  57. package/dist/knowledge/connectDataBind.js +0 -819
  58. package/dist/knowledge/connectDataDefinition.js +0 -341
  59. package/dist/knowledge/connectDataExecute.js +0 -93
  60. package/dist/knowledge/connectDataRules.js +0 -128
  61. package/dist/knowledge/decision.js +0 -121
  62. package/dist/knowledge/expressionPrelude.js +0 -59
  63. package/dist/knowledge/microserviceParameters.js +0 -58
  64. package/dist/knowledge/mining.js +0 -94
  65. package/dist/knowledge/mobileComponentCatalog.js +0 -864
  66. package/dist/knowledge/mobileComponentEvents.js +0 -239
  67. package/dist/knowledge/mobileStore.js +0 -227
  68. package/dist/knowledge/platform/lint.js +0 -385
  69. package/dist/knowledge/platform/mobile.js +0 -142
  70. package/dist/knowledge/platform/mobileLayoutLint.js +0 -324
  71. package/dist/knowledge/platform/mobileRules.js +0 -231
  72. package/dist/knowledge/platform/mobileSpacing.js +0 -82
  73. package/dist/knowledge/platform/mobileTabs.js +0 -108
  74. package/dist/knowledge/platform/nativeBoxModel.js +0 -44
  75. package/dist/knowledge/platform/profile.js +0 -25
  76. package/dist/knowledge/platform/resolve.js +0 -122
  77. package/dist/knowledge/platform/web.js +0 -39
  78. package/dist/knowledge/process.js +0 -510
  79. package/dist/knowledge/rowFilter.js +0 -43
  80. package/dist/knowledge/styleResolveNative.js +0 -527
  81. package/dist/platform/argumentAliases.js +0 -128
  82. package/dist/platform/bodyFile.js +0 -103
  83. package/dist/platform/capture/actions.js +0 -333
  84. package/dist/platform/capture/browser.js +0 -1
  85. package/dist/platform/capture/capture.js +0 -659
  86. package/dist/platform/capture/console-log.js +0 -122
  87. package/dist/platform/capture/index.js +0 -11
  88. package/dist/platform/capture/readiness.js +0 -103
  89. package/dist/platform/capture/summary.js +0 -77
  90. package/dist/platform/capture/target.js +0 -5
  91. package/dist/platform/capture/targets/studio-mobile.js +0 -15
  92. package/dist/platform/capture/targets/studio-web.js +0 -5
  93. package/dist/platform/impersonation.js +0 -45
  94. package/dist/platform/jsonArray.js +0 -24
  95. package/dist/platform/schemaReadMemory.js +0 -60
  96. package/dist/resources/examples/bpm-gorev-kontrol.json +0 -294
  97. package/dist/resources/examples/bpm-iso-dokuman.json +0 -228
  98. package/dist/resources/examples/bpm-satinalma.json +0 -376
  99. package/dist/resources/examples/connect-data-convert-verify.json +0 -107
  100. package/dist/resources/examples/connect-data-dropdown-roles.json +0 -66
  101. package/dist/resources/examples/connect-data-edit-m2m.json +0 -73
  102. package/dist/resources/examples/connect-data-query-params.json +0 -50
  103. package/dist/resources/examples/connect-data-table-entity.json +0 -147
  104. package/dist/resources/examples/connect-data-workflow-microservice.json +0 -65
  105. package/dist/resources/examples/mobile-app-shell-drawer.json +0 -244
  106. package/dist/resources/examples/mobile-app-shell-stack.json +0 -157
  107. package/dist/resources/examples/mobile-app-shell-tab.json +0 -208
  108. package/dist/resources/examples/mobile-form-screen.json +0 -365
  109. package/dist/resources/examples/mobile-list-detail-form.json +0 -703
  110. package/dist/resources/guides/access.md +0 -796
  111. package/dist/resources/guides/bpm.md +0 -686
  112. package/dist/resources/guides/case.md +0 -153
  113. package/dist/resources/guides/decision.md +0 -185
  114. package/dist/resources/guides/mobile-layout.md +0 -193
  115. package/dist/resources/guides/mobile.md +0 -578
  116. package/dist/resources/read.js +0 -41
  117. package/dist/resources/schemas/AccessExplanationDto.json +0 -144
  118. package/dist/resources/schemas/AccessMatrixDto.json +0 -170
  119. package/dist/resources/schemas/AccessPermissionDto.json +0 -57
  120. package/dist/resources/schemas/AccessPolicyDto.json +0 -223
  121. package/dist/resources/schemas/AccessResourceDto.json +0 -86
  122. package/dist/resources/schemas/AppSessionDto.json +0 -53
  123. package/dist/resources/schemas/ConnectDataDescribeDto.json +0 -344
  124. package/dist/resources/schemas/ConnectDataRequestModel.json +0 -202
  125. package/dist/resources/schemas/ConnectDataResultDto.json +0 -421
  126. package/dist/resources/schemas/ConnectorCredentialDto.json +0 -70
  127. package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +0 -37
  128. package/dist/resources/schemas/CreateAccessPolicyCommand.json +0 -209
  129. package/dist/resources/schemas/CreateDecisionCommand.json +0 -221
  130. package/dist/resources/schemas/CreateProcessDefinitionCommand.json +0 -1337
  131. package/dist/resources/schemas/DecisionDto.json +0 -302
  132. package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +0 -28
  133. package/dist/resources/schemas/ExplainAccessQuery.json +0 -33
  134. package/dist/resources/schemas/GenerateProcessDocumentCommand.json +0 -116
  135. package/dist/resources/schemas/OrganizationProjectDto.json +0 -335
  136. package/dist/resources/schemas/OrganizationSchemaDto.json +0 -196
  137. package/dist/resources/schemas/OrganizationSchemaVersionDto.json +0 -207
  138. package/dist/resources/schemas/PatchProcessDefinitionCommand.json +0 -76
  139. package/dist/resources/schemas/ProcessDefinitionDto.json +0 -1480
  140. package/dist/resources/schemas/ProcessSimulationDto.json +0 -96
  141. package/dist/resources/schemas/SaveConnectorCredentialCommand.json +0 -90
  142. package/dist/resources/schemas/SaveProcessEventSourceCommand.json +0 -61
  143. package/dist/resources/schemas/SaveProcessMailSourceCommand.json +0 -89
  144. package/dist/resources/schemas/SignProcessTaskCommand.json +0 -73
  145. package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +0 -92
  146. package/dist/resources/schemas/StartMobileBuildCommand.json +0 -54
  147. package/dist/resources/schemas/UpdateAccessPolicyCommand.json +0 -209
  148. package/dist/resources/schemas/UpdateDecisionCommand.json +0 -216
  149. package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +0 -1357
  150. package/dist/resources/schemas/UpsertMobileStoreSettingsCommand.json +0 -259
  151. package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +0 -1339
  152. package/dist/tools/accessOperations.js +0 -135
  153. package/dist/tools/accessPolicies.js +0 -170
  154. package/dist/tools/accessRuntime.js +0 -203
  155. package/dist/tools/bpm.js +0 -343
  156. package/dist/tools/bpmGovernance.js +0 -266
  157. package/dist/tools/bpmOperations.js +0 -230
  158. package/dist/tools/bpmReporting.js +0 -154
  159. package/dist/tools/bpmRouting.js +0 -150
  160. package/dist/tools/bpmRuntime.js +0 -396
  161. package/dist/tools/case.js +0 -178
  162. package/dist/tools/caseRuntime.js +0 -89
  163. package/dist/tools/connectData.js +0 -449
  164. package/dist/tools/connectors.js +0 -193
  165. package/dist/tools/decisions.js +0 -206
  166. package/dist/tools/mobile.js +0 -221
  167. package/dist/tools/mobileStore.js +0 -268
  168. package/dist/tools/modules.js +0 -48
  169. package/dist/tools/organizationStructure.js +0 -137
  170. package/dist/tools/profileWrite.js +0 -92
package/.env.example CHANGED
@@ -51,21 +51,6 @@ REQUEST_TIMEOUT_MS=100000
51
51
  STUDIO_BASE_URL=http://localhost:3000
52
52
  SCREENSHOT_BROWSER_PATH=
53
53
 
54
- # Jeton kasasi (g-09): MCP_STATE_DIR verilirse tok_ referanslari ve test kullanicisi jetonlari
55
- # <dizin>/token-vault.json'a (0600) yazilir ve gateway yeniden baslayinca da cozulur. Yalniz lokal
56
- # hedefte (ORG_API_BASE_URL localhost) yazilir. MCP_TOKEN_TTL_MINUTES referansin omru (dakika).
57
- MCP_STATE_DIR=
58
- MCP_TOKEN_TTL_MINUTES=60
59
-
60
- # asUser: 'test:<ad>' icin test kullanicilari — satiri INSAN yazar, AI .env'i duzenlemez.
61
- # Bicim (JSON, tek satir): uygulamanin kendi giris ucu ve onun bekledigi govde. Ayrinti: docs/ortam.md
62
- # MCP_TEST_USER_OGRENCI={"application":"<uygulama slug>","microservice":"<giris ucu slug>","body":{"email":"…","password":"…"}}
63
-
64
- # bodyFile icin: tanim yazan araclarin (page_create, flow_create, microservice_create, *_patch …)
65
- # govdeyi okuyabilecegi ek dizin. Gateway surecinin calisma dizini her zaman izinlidir; bu dizin
66
- # ek olarak izinli olur. Bos birakilirsa yalniz calisma dizini okunur. Sembolik bag cozulur.
67
- MCP_INPUT_DIR=
68
-
69
54
  # generate-schemas icin swagger adresleri. Bos birakilirsa sirayla denenir:
70
55
  # 1) asagidaki override, 2) {API_BASE_URL}/swagger/v1/swagger.json, 3) localhost:3000 frontend proxy'si
71
56
  ORG_SWAGGER_URL=
package/dist/config.js CHANGED
@@ -35,7 +35,6 @@ export const moduleNames = [
35
35
  "merge",
36
36
  "activity",
37
37
  "revision",
38
- "mobile",
39
38
  ];
40
39
  export const modulePresets = {
41
40
  core: [
@@ -76,7 +75,6 @@ export const modulePresets = {
76
75
  "access",
77
76
  "translation",
78
77
  "revision",
79
- "mobile",
80
78
  ],
81
79
  admin: ["platform", "template", "organization", "deployment", "environment", "merge", "activity"],
82
80
  };
@@ -120,9 +118,6 @@ const environmentSchema = z.object({
120
118
  STUDIO_BASE_URL: z.string().url().optional(),
121
119
  SCREENSHOT_BROWSER_PATH: z.string().min(1).optional(),
122
120
  SCREENSHOT_QUEUE_WAIT_MS: z.coerce.number().int().positive().default(120000),
123
- MCP_INPUT_DIR: z.string().min(1).optional(),
124
- MCP_STATE_DIR: z.string().min(1).optional(),
125
- MCP_TOKEN_TTL_MINUTES: z.coerce.number().int().positive().optional(),
126
121
  });
127
122
  export const environmentKeys = Object.keys(environmentSchema.shape);
128
123
  /**
@@ -231,11 +226,5 @@ export function loadConfig(env) {
231
226
  studioBaseUrl: values.STUDIO_BASE_URL?.replace(/\/+$/, ""),
232
227
  screenshotBrowserPath: values.SCREENSHOT_BROWSER_PATH,
233
228
  screenshotQueueWaitMs: values.SCREENSHOT_QUEUE_WAIT_MS,
234
- inputDirectory: values.MCP_INPUT_DIR,
235
- stateDirectory: values.MCP_STATE_DIR,
236
- tokenTtlMinutes: values.MCP_TOKEN_TTL_MINUTES,
237
- testUsers: Object.fromEntries(Object.entries(env)
238
- .filter((entry) => entry[0].startsWith("MCP_TEST_USER_") && typeof entry[1] === "string" && entry[1] !== "")
239
- .map(([key, value]) => [key.slice("MCP_TEST_USER_".length).toLowerCase(), value])),
240
229
  };
241
230
  }
package/dist/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
3
3
  import { configureLogging, logGatewayEvent } from './observability/trace.js';
4
- import { configureTokenVault } from './platform/tokenVault.js';
5
4
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
6
5
  import { Platform, requestAuthStorage } from './platform/http.js';
7
6
  import { createGatewayServer } from './server.js';
@@ -32,7 +31,6 @@ catch (error) {
32
31
  const platform = new Platform(config);
33
32
  const useStdio = process.argv.includes('--stdio');
34
33
  configureLogging(config, useStdio ? 'stdio' : 'http');
35
- configureTokenVault(config);
36
34
  if (useStdio) {
37
35
  if (config.authMode === 'passthrough') {
38
36
  logger.error('stdio kipi passthrough auth ile kullanılamaz; AUTH_MODE=local yapın.');
@@ -0,0 +1,184 @@
1
+ function asObjects(value) {
2
+ return Array.isArray(value) ? value.filter((entry) => !!entry && typeof entry === 'object' && !Array.isArray(entry)) : [];
3
+ }
4
+ /**
5
+ * Bölge bir bayrak değil DÜĞÜMDÜR (QA BX-002, 2026-09-30). Studio `hasHeader`/`hasFooter`
6
+ * anahtarını çevirince `syncBoxSections` (zeyrek-frontend `box-sections.store.ts`) ayrı bir
7
+ * `box-section` çocuğu kurar; runtime ve kanvas bölgeyi o düğümün `role` prop'undan çizer
8
+ * (`box-shell.ts` `groupBoxShellChildren`). Gateway yalnız bayrağı yazıyordu: panel "Has header"
9
+ * işaretli, ekranda ve kanvasta bölge yok (qa-box-01 / bx_hdrflag ölçümü). Bu modül Studio'nun
10
+ * yaptığını yamaya ekler — `page_container`'ı kendisi kurduğu gibi (`ensurePageContainer`).
11
+ */
12
+ export const BOX_SECTION_HOSTS = new Set(['box', 'aibox']);
13
+ export const BOX_SECTION_TYPE = 'box-section';
14
+ const SECTION_FLAGS = { hasHeader: 'header', hasFooter: 'footer' };
15
+ /**
16
+ * Studio'nun bölgeye yazdığı prop'lar: `box-section/schema.ts` varsayılanları + `role`.
17
+ * Kopyadır, çünkü gateway katalog varsayılanını yazma anında okumaz; `page_container` yerleşim
18
+ * setiyle aynı emsal. Eksik bırakılsa bölge `verticalAlign` yokken üste yaslanır, `wrap` yokken
19
+ * sarmazdı (`flex-layout.ts` `FLEX_ABSENT_PROPS`) — Studio'nun kurduğu bölgeden farklı çizilirdi.
20
+ */
21
+ const SECTION_PROPS = {
22
+ layout: 'flex',
23
+ direction: 'row',
24
+ horizontalAlign: 'left',
25
+ verticalAlign: 'middle',
26
+ size: 'shrink',
27
+ gap: 'medium',
28
+ wrap: true
29
+ };
30
+ const propData = (value) => value && typeof value === 'object' && !Array.isArray(value) && 'type' in value ? value.data : value;
31
+ const isSection = (node) => node.type === BOX_SECTION_TYPE;
32
+ /** Rol yazılmamışsa `header` sayılır — `box-shell.ts` `sectionRoleOf` ile aynı kural. */
33
+ const roleOf = (node) => propData(node.props?.role) === 'footer' ? 'footer' : 'header';
34
+ const findSection = (children, role) => children.find(child => isSection(child) && roleOf(child) === role);
35
+ const uniqueId = (base, taken) => {
36
+ let id = base;
37
+ for (let suffix = 2; taken.has(id); suffix++)
38
+ id = `${base}_${suffix}`;
39
+ taken.add(id);
40
+ return id;
41
+ };
42
+ /**
43
+ * Studio `generateBoxSection` şeklinin aynısı: 12 kolon blok (başlık y=0, altlık y=999), bırakılabilir,
44
+ * kendi boşluğunu eklemez (`marginType/paddingType: 'none'`). Tohum metni YOKTUR — Studio'daki
45
+ * "Header"/"Footer" yer tutucusu tasarımcıya bir davet; AI içeriği kendisi koyar.
46
+ */
47
+ export function boxSectionNode(boxId, role, taken) {
48
+ const elementId = uniqueId(`${boxId}_${role}`, taken);
49
+ return {
50
+ elementId,
51
+ name: elementId,
52
+ kind: 'component',
53
+ type: BOX_SECTION_TYPE,
54
+ // Prop sarmalı burada kurulur: layout/widget yazma yolunda normalizasyon kaydı okumadan ÖNCE
55
+ // koşar, bölge ondan sonra eklenir (`designSchemaPatch.ts`). Çıplak değer platformda 422 verir.
56
+ props: Object.fromEntries(Object.entries({ ...SECTION_PROPS, role }).map(([name, data]) => [name, { type: 'static', ref: null, data }])),
57
+ blocks: [{ breakpoint: 1024, size: { w: 12, h: role === 'header' ? 6 : 5 }, position: { x: 0, y: role === 'header' ? 0 : 999 } }],
58
+ states: { isSticky: false, isDroppable: true, isScrollable: false, isWrapper: false, isFloating: false, isQuickStack: false },
59
+ appearance: { heightType: 'auto', marginType: 'none', paddingType: 'none' },
60
+ events: [],
61
+ validations: [],
62
+ stateBindings: [],
63
+ children: []
64
+ };
65
+ }
66
+ export function collectIds(nodes, into) {
67
+ for (const node of asObjects(nodes)) {
68
+ if (typeof node.elementId === 'string')
69
+ into.add(node.elementId);
70
+ collectIds(node.children, into);
71
+ }
72
+ return into;
73
+ }
74
+ /**
75
+ * add_component gövdelerindeki box/aibox düğümlerine eksik bölgeyi ekler (iç içe kutular dahil).
76
+ * Başlık ilk, altlık son çocuk olur (`orderBoxChildren`). Verilmiş bölge ikinci kez eklenmez.
77
+ */
78
+ export function ensureBoxSections(nodes, taken) {
79
+ const created = [];
80
+ for (const node of asObjects(nodes)) {
81
+ if (BOX_SECTION_HOSTS.has(String(node.type))) {
82
+ const props = (node.props ?? {});
83
+ const children = asObjects(node.children);
84
+ for (const [flag, role] of Object.entries(SECTION_FLAGS)) {
85
+ if (propData(props[flag]) !== true || findSection(children, role))
86
+ continue;
87
+ const section = boxSectionNode(String(node.elementId ?? node.type), role, taken);
88
+ if (role === 'header')
89
+ children.unshift(section);
90
+ else
91
+ children.push(section);
92
+ created.push(String(section.elementId));
93
+ }
94
+ node.children = children;
95
+ }
96
+ created.push(...ensureBoxSections(node.children, taken));
97
+ }
98
+ return created;
99
+ }
100
+ function findNode(nodes, elementId) {
101
+ for (const node of asObjects(nodes)) {
102
+ if (node.elementId === elementId)
103
+ return node;
104
+ const nested = findNode(node.children, elementId);
105
+ if (nested)
106
+ return nested;
107
+ }
108
+ return undefined;
109
+ }
110
+ const blockOf = (node) => {
111
+ const position = (asObjects(node.blocks)[0]?.position ?? {});
112
+ return { x: Number(position.x) || 0, y: Number(position.y) || 0 };
113
+ };
114
+ /**
115
+ * Kapatılan bölgenin çocukları gövdenin neresine gider: başlığınkiler başa, altlığınkiler sona.
116
+ * Studio `orphanTargetY` ile aynı kural — sıra blok konumundan türetilir, eski y'yi koruyan düğüm
117
+ * gövdenin ORTASINA düşerdi.
118
+ */
119
+ function orphanY(role, body) {
120
+ const ys = body.map(child => blockOf(child).y);
121
+ if (ys.length === 0)
122
+ return 0;
123
+ return role === 'header' ? Math.min(...ys) - 1 : Math.max(...ys) + 1;
124
+ }
125
+ /**
126
+ * Studio bölgeyi açarken içine "Header"/"Footer" metni koyar; dokunulmadıysa bölgeyle birlikte
127
+ * silinir, taşınmaz (`isPristineSectionSeed`, ölçüldü 2026-09-18). Gateway taşısaydı Studio'da
128
+ * açılıp MCP ile kapatılan bölge gövdeye anlamsız bir "Header" metni bırakırdı (qa-box-01 bx_row).
129
+ */
130
+ function isPristineSeed(node, role) {
131
+ if (node.type !== 'text')
132
+ return false;
133
+ if (propData(node.props?.content) !== (role === 'footer' ? 'Footer' : 'Header'))
134
+ return false;
135
+ return [node.events, node.validations, node.stateBindings, node.children].every(list => asObjects(list).length === 0);
136
+ }
137
+ /**
138
+ * Kayıtlı kutuya `replace_prop hasHeader|hasFooter` yazılınca Studio'nun `syncBoxSections` adımını
139
+ * yamaya ekler: açılınca bölge düğümü `add_component`; kapanınca bölgenin çocukları gövdeye
140
+ * `move_component` ile taşınır ve bölge `remove_component` ile silinir — içerik sessizce silinmez.
141
+ * Eklenen op'lar tetikleyen `replace_prop`'un hemen arkasına yerleşir; `ops` yerinde değişir.
142
+ */
143
+ export function expandSectionToggles(ops, schema, taken) {
144
+ const result = { created: [], removed: [] };
145
+ for (let index = 0; index < ops.length; index++) {
146
+ const op = ops[index];
147
+ const role = SECTION_FLAGS[String(op.prop)];
148
+ if (op.op !== 'replace_prop' || !role || typeof op.target !== 'string')
149
+ continue;
150
+ const box = findNode(schema, op.target);
151
+ if (!box || !BOX_SECTION_HOSTS.has(String(box.type)))
152
+ continue;
153
+ const children = asObjects(box.children);
154
+ const existing = findSection(children, role);
155
+ const wanted = propData(op.value) === true;
156
+ const extra = [];
157
+ if (wanted && !existing) {
158
+ const section = boxSectionNode(op.target, role, taken);
159
+ extra.push({ op: 'add_component', parent: op.target, component: section });
160
+ result.created.push(String(section.elementId));
161
+ }
162
+ if (!wanted && existing) {
163
+ const targetY = orphanY(role, children.filter(child => !isSection(child)));
164
+ for (const orphan of asObjects(existing.children).filter(child => !isPristineSeed(child, role))) {
165
+ extra.push({ op: 'move_component', target: orphan.elementId, parent: op.target, position: { x: blockOf(orphan).x, y: targetY } });
166
+ }
167
+ extra.push({ op: 'remove_component', target: existing.elementId });
168
+ result.removed.push(String(existing.elementId));
169
+ }
170
+ ops.splice(index + 1, 0, ...extra);
171
+ index += extra.length;
172
+ }
173
+ return result;
174
+ }
175
+ export function boxSectionNote(created, removed = []) {
176
+ const notes = [];
177
+ if (created.length > 0) {
178
+ notes.push(`box bölgesi eklendi: ${created.join(', ')} — hasHeader/hasFooter bayrağı tek başına bölge çizmez, bölge ayrı bir box-section düğümüdür (Studio aynısını yapar). Bölgeye içerik eklemek için add_component parent: '<bu elementId>'`);
179
+ }
180
+ if (removed.length > 0) {
181
+ notes.push(`box bölgesi kaldırıldı: ${removed.join(', ')} — içindeki çocuklar kutunun gövdesine taşındı (silinmedi)`);
182
+ }
183
+ return notes;
184
+ }