@appaflytech/zeyrek-ai-mcp 0.0.28 → 0.0.30

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 (201) hide show
  1. package/.env.example +15 -0
  2. package/README.md +5 -5
  3. package/dist/config.js +37 -0
  4. package/dist/index.js +2 -0
  5. package/dist/knowledge/access.js +802 -0
  6. package/dist/knowledge/backendConstraints.js +18 -1
  7. package/dist/knowledge/case.js +41 -0
  8. package/dist/knowledge/componentCatalog.js +494 -34
  9. package/dist/knowledge/componentEvents.js +132 -7
  10. package/dist/knowledge/connectDataBind.js +819 -0
  11. package/dist/knowledge/connectDataDefinition.js +341 -0
  12. package/dist/knowledge/connectDataExecute.js +93 -0
  13. package/dist/knowledge/connectDataRules.js +128 -0
  14. package/dist/knowledge/decision.js +121 -0
  15. package/dist/knowledge/expressionPrelude.js +59 -0
  16. package/dist/knowledge/layoutSummary.js +140 -2
  17. package/dist/knowledge/microserviceParameters.js +58 -0
  18. package/dist/knowledge/mining.js +94 -0
  19. package/dist/knowledge/mobileComponentCatalog.js +859 -0
  20. package/dist/knowledge/mobileComponentEvents.js +239 -0
  21. package/dist/knowledge/normalize.js +236 -67
  22. package/dist/knowledge/outlines.js +36 -0
  23. package/dist/knowledge/platform/lint.js +385 -0
  24. package/dist/knowledge/platform/mobile.js +142 -0
  25. package/dist/knowledge/platform/mobileLayoutLint.js +324 -0
  26. package/dist/knowledge/platform/mobileRules.js +231 -0
  27. package/dist/knowledge/platform/mobileSpacing.js +82 -0
  28. package/dist/knowledge/platform/mobileTabs.js +108 -0
  29. package/dist/knowledge/platform/nativeBoxModel.js +44 -0
  30. package/dist/knowledge/platform/profile.js +25 -0
  31. package/dist/knowledge/platform/resolve.js +122 -0
  32. package/dist/knowledge/platform/web.js +39 -0
  33. package/dist/knowledge/policy.js +18 -4
  34. package/dist/knowledge/process.js +510 -0
  35. package/dist/knowledge/reservedTables.js +79 -0
  36. package/dist/knowledge/rowFilter.js +43 -0
  37. package/dist/knowledge/rules.js +319 -21
  38. package/dist/knowledge/schemaGuard.js +11 -0
  39. package/dist/knowledge/styleResolve.js +50 -4
  40. package/dist/knowledge/styleResolveNative.js +527 -0
  41. package/dist/knowledge/themeResolve.js +3 -3
  42. package/dist/observability/trace.js +6 -3
  43. package/dist/platform/argumentAliases.js +128 -0
  44. package/dist/platform/bodyFile.js +103 -0
  45. package/dist/platform/capture/actions.js +333 -0
  46. package/dist/platform/capture/browser.js +1 -0
  47. package/dist/platform/{screenshot.js → capture/capture.js} +105 -519
  48. package/dist/platform/capture/console-log.js +122 -0
  49. package/dist/platform/capture/index.js +11 -0
  50. package/dist/platform/capture/readiness.js +103 -0
  51. package/dist/platform/capture/summary.js +77 -0
  52. package/dist/platform/capture/target.js +5 -0
  53. package/dist/platform/capture/targets/studio-mobile.js +15 -0
  54. package/dist/platform/capture/targets/studio-web.js +5 -0
  55. package/dist/platform/diagnostics.js +10 -4
  56. package/dist/platform/domSummary.js +1 -1
  57. package/dist/platform/errors.js +162 -10
  58. package/dist/platform/http.js +29 -8
  59. package/dist/platform/impersonation.js +45 -0
  60. package/dist/platform/jsonArray.js +24 -0
  61. package/dist/platform/responses.js +39 -5
  62. package/dist/platform/schemaReadMemory.js +60 -0
  63. package/dist/platform/secrets.js +17 -1
  64. package/dist/platform/strictArguments.js +68 -12
  65. package/dist/platform/tokenVault.js +187 -4
  66. package/dist/resources/examples/bpm-gorev-kontrol.json +294 -0
  67. package/dist/resources/examples/bpm-iso-dokuman.json +228 -0
  68. package/dist/resources/examples/bpm-satinalma.json +376 -0
  69. package/dist/resources/examples/connect-data-convert-verify.json +107 -0
  70. package/dist/resources/examples/connect-data-dropdown-roles.json +66 -0
  71. package/dist/resources/examples/connect-data-edit-m2m.json +73 -0
  72. package/dist/resources/examples/connect-data-query-params.json +50 -0
  73. package/dist/resources/examples/connect-data-table-entity.json +147 -0
  74. package/dist/resources/examples/connect-data-workflow-microservice.json +65 -0
  75. package/dist/resources/examples/mobile-app-shell-drawer.json +243 -0
  76. package/dist/resources/examples/mobile-app-shell-stack.json +157 -0
  77. package/dist/resources/examples/mobile-app-shell-tab.json +208 -0
  78. package/dist/resources/examples/mobile-form-screen.json +365 -0
  79. package/dist/resources/examples/mobile-list-detail-form.json +672 -0
  80. package/dist/resources/examples/page-detail-profile.json +2 -1
  81. package/dist/resources/examples/page-dynamic-form.json +3 -2
  82. package/dist/resources/examples/page-flex-sections.json +1 -1
  83. package/dist/resources/examples/page-html-embed.json +1 -1
  84. package/dist/resources/examples/workflow-basic.json +8 -2
  85. package/dist/resources/guides/access.md +796 -0
  86. package/dist/resources/guides/bpm.md +686 -0
  87. package/dist/resources/guides/case.md +153 -0
  88. package/dist/resources/guides/component.md +91 -4
  89. package/dist/resources/guides/decision.md +185 -0
  90. package/dist/resources/guides/entity.md +50 -8
  91. package/dist/resources/guides/expressions.md +14 -5
  92. package/dist/resources/guides/functions.md +1 -1
  93. package/dist/resources/guides/getting-started.md +38 -1
  94. package/dist/resources/guides/layout.md +11 -7
  95. package/dist/resources/guides/microservice.md +81 -2
  96. package/dist/resources/guides/middleware.md +44 -2
  97. package/dist/resources/guides/mobile-layout.md +193 -0
  98. package/dist/resources/guides/mobile.md +495 -0
  99. package/dist/resources/guides/page.md +454 -75
  100. package/dist/resources/guides/theme.md +8 -2
  101. package/dist/resources/guides/translation.md +1 -1
  102. package/dist/resources/guides/workflow.md +58 -1
  103. package/dist/resources/read.js +41 -0
  104. package/dist/resources/rules.js +11 -5
  105. package/dist/resources/schema-fingerprint.json +7 -5
  106. package/dist/resources/schemas/AccessExplanationDto.json +144 -0
  107. package/dist/resources/schemas/AccessMatrixDto.json +170 -0
  108. package/dist/resources/schemas/AccessPermissionDto.json +57 -0
  109. package/dist/resources/schemas/AccessPolicyDto.json +223 -0
  110. package/dist/resources/schemas/AccessResourceDto.json +86 -0
  111. package/dist/resources/schemas/AppSessionDto.json +53 -0
  112. package/dist/resources/schemas/ConnectDataDescribeDto.json +344 -0
  113. package/dist/resources/schemas/ConnectDataRequestModel.json +202 -0
  114. package/dist/resources/schemas/ConnectDataResultDto.json +421 -0
  115. package/dist/resources/schemas/ConnectorCredentialDto.json +70 -0
  116. package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +37 -0
  117. package/dist/resources/schemas/CreateAccessPolicyCommand.json +209 -0
  118. package/dist/resources/schemas/CreateDecisionCommand.json +221 -0
  119. package/dist/resources/schemas/CreateEntityCommand.json +118 -0
  120. package/dist/resources/schemas/CreateMicroserviceCommand.json +13 -1
  121. package/dist/resources/schemas/CreateProcessDefinitionCommand.json +1337 -0
  122. package/dist/resources/schemas/CreateQueryCommand.json +4 -0
  123. package/dist/resources/schemas/CreateWorkflowCommand.json +143 -1
  124. package/dist/resources/schemas/DataJobDto.json +6 -1
  125. package/dist/resources/schemas/DecisionDto.json +302 -0
  126. package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +28 -0
  127. package/dist/resources/schemas/ExplainAccessQuery.json +33 -0
  128. package/dist/resources/schemas/GenerateProcessDocumentCommand.json +116 -0
  129. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +21 -1
  130. package/dist/resources/schemas/MicroserviceDto.json +15 -3
  131. package/dist/resources/schemas/OrganizationProjectDto.json +335 -0
  132. package/dist/resources/schemas/OrganizationSchemaDto.json +196 -0
  133. package/dist/resources/schemas/OrganizationSchemaVersionDto.json +207 -0
  134. package/dist/resources/schemas/PatchProcessDefinitionCommand.json +76 -0
  135. package/dist/resources/schemas/PreviewMicroserviceCommand.json +10 -1
  136. package/dist/resources/schemas/PreviewWorkflowCommand.json +22 -1
  137. package/dist/resources/schemas/ProcessDefinitionDto.json +1480 -0
  138. package/dist/resources/schemas/ProcessSimulationDto.json +96 -0
  139. package/dist/resources/schemas/SaveConnectorCredentialCommand.json +90 -0
  140. package/dist/resources/schemas/SaveProcessEventSourceCommand.json +61 -0
  141. package/dist/resources/schemas/SaveProcessMailSourceCommand.json +89 -0
  142. package/dist/resources/schemas/SignProcessTaskCommand.json +73 -0
  143. package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +92 -0
  144. package/dist/resources/schemas/StepDto.json +22 -1
  145. package/dist/resources/schemas/UpdateAccessPolicyCommand.json +209 -0
  146. package/dist/resources/schemas/UpdateDecisionCommand.json +216 -0
  147. package/dist/resources/schemas/UpdateEntityCommand.json +118 -0
  148. package/dist/resources/schemas/UpdateMicroserviceCommand.json +13 -1
  149. package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +1357 -0
  150. package/dist/resources/schemas/UpdateQueryCommand.json +4 -0
  151. package/dist/resources/schemas/UpdateViewCommand.json +0 -2
  152. package/dist/resources/schemas/UpdateWorkflowCommand.json +143 -1
  153. package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +1339 -0
  154. package/dist/server.js +27 -1
  155. package/dist/tools/access.js +369 -2
  156. package/dist/tools/accessOperations.js +135 -0
  157. package/dist/tools/accessPolicies.js +170 -0
  158. package/dist/tools/accessRuntime.js +203 -0
  159. package/dist/tools/applications.js +60 -3
  160. package/dist/tools/bpm.js +343 -0
  161. package/dist/tools/bpmGovernance.js +266 -0
  162. package/dist/tools/bpmOperations.js +230 -0
  163. package/dist/tools/bpmReporting.js +154 -0
  164. package/dist/tools/bpmRouting.js +150 -0
  165. package/dist/tools/bpmRuntime.js +396 -0
  166. package/dist/tools/case.js +178 -0
  167. package/dist/tools/caseRuntime.js +89 -0
  168. package/dist/tools/common.js +7 -0
  169. package/dist/tools/components.js +118 -14
  170. package/dist/tools/connectData.js +449 -0
  171. package/dist/tools/connectors.js +193 -0
  172. package/dist/tools/datasources.js +3 -3
  173. package/dist/tools/decisions.js +206 -0
  174. package/dist/tools/dependencies.js +1 -1
  175. package/dist/tools/deployments.js +2 -2
  176. package/dist/tools/designSchemaPatch.js +34 -9
  177. package/dist/tools/dtos.js +36 -5
  178. package/dist/tools/entities.js +79 -12
  179. package/dist/tools/externalComponents.js +26 -5
  180. package/dist/tools/flows.js +122 -14
  181. package/dist/tools/folders.js +1 -1
  182. package/dist/tools/imports.js +5 -2
  183. package/dist/tools/layouts.js +50 -17
  184. package/dist/tools/merges.js +1 -1
  185. package/dist/tools/microservices.js +77 -25
  186. package/dist/tools/mobile.js +221 -0
  187. package/dist/tools/modules.js +48 -0
  188. package/dist/tools/organizationStructure.js +137 -0
  189. package/dist/tools/pages.js +465 -98
  190. package/dist/tools/platformInfo.js +27 -8
  191. package/dist/tools/profileWrite.js +92 -0
  192. package/dist/tools/projects.js +71 -9
  193. package/dist/tools/rows.js +69 -13
  194. package/dist/tools/schemaOps.js +61 -1
  195. package/dist/tools/screenWrite.js +37 -8
  196. package/dist/tools/screens.js +95 -5
  197. package/dist/tools/templates.js +26 -1
  198. package/dist/tools/translations.js +1 -1
  199. package/dist/tools/variables.js +11 -5
  200. package/dist/tools/workflows.js +10 -5
  201. package/package.json +2 -2
@@ -1,7 +1,9 @@
1
1
  import { isFlexContainer, schemaOpValidationErrors, FLEX_LAYOUT_PROP_NAMES, PAGE_CONTAINER_ELEMENT_ID } from '../knowledge/normalize.js';
2
2
  import { findNode, outlineAppliedPatch } from './screens.js';
3
3
  import { setPropTypeErrors } from '../knowledge/propTypes.js';
4
+ import { connectDataOpIssues } from '../knowledge/connectDataDefinition.js';
4
5
  import { PlatformApiError } from '../platform/errors.js';
6
+ import { jsonArray } from '../platform/jsonArray.js';
5
7
  import { z } from 'zod';
6
8
  /*
7
9
  * Şema micro-op'larının gateway tarafı: sayfa (`page_schema_patch`), layout (`layout_schema_patch`)
@@ -24,7 +26,7 @@ export function outlineWriteResponse(response) {
24
26
  if (Array.isArray(container.appliedPatch))
25
27
  container.appliedPatch = outlineAppliedPatch(container.appliedPatch);
26
28
  }
27
- export const opsParam = z.array(z.record(z.unknown())).describe("Micro-op listesi. Op sözlüğü: replace_prop {target, prop, value} (value ham değer, code sarmalı {type: 'code', ref: '{{ … }}'} ya da translation sarmalı {type: 'translation', ref: '<çeviri anahtarı>'} — prop tipini değiştirmek için komponenti silip yeniden EKLEMEYİN, ona yazan setter'ların hedefi silinir (FLOW-018); platform replace_prop'ta expression alanını OKUMAZ — gateway onu code sarmalına çevirir) | set_binding {target, prop, expression: '{{ Page.variables.x }}'} | add_component {parent (üst elementId ya da 'root'), index?, component} | remove_component {target} | move_component {target, parent, index?, position: {x, y}} (index ÇİZİM sırası değildir, runtime çocukları blocks.position'a göre (y, sonra x) çizer. page_schema_patch'te flex kapta gateway index'i görünen sıraya çevirir ve kardeş konumlarını yeniden yazar; ızgara kapta sırayı position.y verir, sona eklemeyen index PAGE-033 uyarısıdır. layout_schema_patch ve component_schema_patch bu çeviriyi YAPMAZ: orada sırayı position.y ile verin) | set_event {target, event, eventValue, replaceBoundFlows?} (olayın BÜTÜN bağlarını bu tek akışa indirir; olayda başka akış bağlıysa gateway PAGE-034 ile reddeder — bilerek değiştirmek için replaceBoundFlows: true) | add_event {target, event, eventValue} (olaya bir akış DAHA bağlar; bağlı akışların hepsi paralel ve birbirinden bağımsız koşar, sıra garantisi yoktur — sıra gerekiyorsa flow-trigger. Aynı akış iki kez 422 duplicate-event. Mobil runtime yalnız İLK akışı koşar) | remove_event {target, event, eventValue?} (olayı diziden çıkarır; target: 'page' sayfa düzeyi olaylar. Olaya birden fazla akış bağlıysa eventValue ile hangisi olduğunu verin, yoksa 422 ambiguous-event. set_event ile eventValue: null olay SİLMEZ, değersiz ölü kayıt bırakır. Olmayan olay 422 missing-event) | set_validations {target, validations: [{type, message, value, isActive}]} (komponentin validation listesini TAMAMEN değiştirir; boş dizi hepsini siler) | set_appearance {target, appearance: {heightType?, widthType?, tooltip?, background?, …}} (kurulu düğümün appearance'ına YALNIZ verilen alanları yazar, gerisini korur; null alanı temizler; bilinmeyen alan unknown-appearance-field ile reddedilir. GÖRÜNÜRLÜK appearance'ta DEĞİLDİR: gizlemek için replace_prop {target, prop: 'isHidden', value: true}, koşul için set_binding {prop: 'isHidden'} — add_component gövdesindeki appearance.isHidden'ı gateway props.isHidden'a taşır) | resize_component {target, size?: {w,h}, appearance?: {widthType,widthString,heightType,heightString}, states?: {isWrapper,isScrollable,isSticky,isDroppable,isFloating,isQuickStack}, breakpoint?: 1024} (gateway adı: platforma set_block {target, breakpoint, size} + set_appearance {target, appearance} + set_states {target, states} olarak gider — o üç op'u doğrudan da gönderebilirsiniz. move_component'e konan size reddedilir. Izgarada blocks[].size, flex'te appearance geçerlidir; ebeveynin düzeni yazılanı etkisiz kılıyorsa PAGE-019 uyarısı çıkar. states bir PROP DEĞİL düğüm alanıdır ve replace_prop onu yazamaz — düğümü silmeden isWrapper bayrağını değiştirmenin yolu budur). set_prop_type {target, prop, propType: 'static'|'code'|'translation', ref?, data?} (replace_prop sarmalıyla aynı sonucu verir ve mevcut data'yı tasarım yedeği olarak taşır. Bu op prop'un TİPİNİ yerinde değiştirir. Taşıyıcı alan tipe göre: static → data, code ve translation → ref (runtime data'yı her turda ezer, anahtar yalnız ref'te yaşar). Eksik taşıyıcı istek gönderilmeden reddedilir; page_schema_validate aynı kararı verir) | reorder {parent ('root' ya da elementId), order: [çocuk elementId'lerinin TAMAMI, yeni sırada]} (yalnız DİZİ sırasını değiştirir; çizim sırası blocks.position'dır — görünen sırayı değiştirmek için konumları set_block/move_component ile de yazın) | set_state_binding {target, binding: {name, expression, targets}} (ada göre ekler/değiştirir) | remove_state_binding {target, name} | batch {gestureId?, label?, ops: [...]} (iç içe batch yok). target = elementId. İstek atomiktir: tek op reddedilirse hiçbiri yazılmaz.");
29
+ export const opsParam = jsonArray(z.array(z.record(z.unknown()))).describe("Micro-op listesi. Op sözlüğü: replace_prop {target, prop, value} (value ham değer, code sarmalı {type: 'code', ref: '{{ … }}'} ya da translation sarmalı {type: 'translation', ref: '<çeviri anahtarı>'} — prop tipini değiştirmek için komponenti silip yeniden EKLEMEYİN, ona yazan setter'ların hedefi silinir (FLOW-018); platform replace_prop'ta expression alanını OKUMAZ — gateway onu code sarmalına çevirir) | set_binding {target, prop, expression: '{{ Page.variables.x }}'} | add_component {parent (üst elementId ya da 'root'), index?, component} | remove_component {target} | move_component {target, parent, index?, position: {x, y}} (index ÇİZİM sırası değildir, runtime çocukları blocks.position'a göre (y, sonra x) çizer. page_schema_patch'te flex kapta gateway index'i görünen sıraya çevirir ve kardeş konumlarını yeniden yazar; ızgara kapta sırayı position.y verir, sona eklemeyen index PAGE-033 uyarısıdır. layout_schema_patch ve component_schema_patch bu çeviriyi YAPMAZ: orada sırayı position.y ile verin) | set_event {target, event, eventValue, replaceBoundFlows?} (olayın BÜTÜN bağlarını bu tek akışa indirir; olayda başka akış bağlıysa gateway PAGE-034 ile reddeder — bilerek değiştirmek için replaceBoundFlows: true) | add_event {target, event, eventValue} (olaya bir akış DAHA bağlar; bağlı akışların hepsi paralel ve birbirinden bağımsız koşar, sıra garantisi yoktur — sıra gerekiyorsa flow-trigger. Aynı akışı ikinci kez bağlamak etkisizdir (unchanged; tekrar güvenli). Mobil runtime yalnız İLK akışı koşar) | remove_event {target, event, eventValue?} (olayı diziden çıkarır; target: 'page' sayfa düzeyi olaylar. Olaya birden fazla akış bağlıysa eventValue ile hangisi olduğunu verin, yoksa 422 ambiguous-event. set_event ile eventValue: null olay SİLMEZ, değersiz ölü kayıt bırakır. Olmayan olay 422 missing-event) | set_validations {target, validations: [{type, message, value, isActive}]} (komponentin validation listesini TAMAMEN değiştirir; boş dizi hepsini siler) | set_appearance {target, appearance: {heightType?, widthType?, tooltip?, background?, …}} (kurulu düğümün appearance'ına YALNIZ verilen alanları yazar, gerisini korur; null alanı temizler; bilinmeyen alan unknown-appearance-field ile reddedilir. GÖRÜNÜRLÜK appearance'ta DEĞİLDİR: gizlemek için replace_prop {target, prop: 'isHidden', value: true}, koşul için set_binding {prop: 'isHidden'} — add_component gövdesindeki appearance.isHidden'ı gateway props.isHidden'a taşır) | resize_component {target, size?: {w,h}, appearance?: {widthType,widthString,heightType,heightString}, states?: {isWrapper,isScrollable,isSticky,isDroppable,isFloating,isQuickStack}, breakpoint?: 1024} (gateway adı: platforma set_block {target, breakpoint, size} + set_appearance {target, appearance} + set_states {target, states} olarak gider — o üç op'u doğrudan da gönderebilirsiniz. move_component'e konan size reddedilir. Izgarada blocks[].size, flex'te appearance geçerlidir; ebeveynin düzeni yazılanı etkisiz kılıyorsa PAGE-019 uyarısı çıkar. states bir PROP DEĞİL düğüm alanıdır ve replace_prop onu yazamaz — düğümü silmeden isWrapper bayrağını değiştirmenin yolu budur). set_prop_type {target, prop, propType: 'static'|'code'|'translation', ref?, data?} (replace_prop sarmalıyla aynı sonucu verir ve mevcut data'yı tasarım yedeği olarak taşır. Bu op prop'un TİPİNİ yerinde değiştirir. Taşıyıcı alan tipe göre: static → data, code ve translation → ref (runtime data'yı her turda ezer, anahtar yalnız ref'te yaşar). Eksik taşıyıcı istek gönderilmeden reddedilir; page_schema_validate aynı kararı verir) | reorder {parent ('root' ya da elementId), order: [çocuk elementId'lerinin TAMAMI, yeni sırada]} (yalnız DİZİ sırasını değiştirir; çizim sırası blocks.position'dır — görünen sırayı değiştirmek için konumları set_block/move_component ile de yazın) | set_state_binding {target, binding: {name, expression, targets}} (ada göre ekler/değiştirir) | remove_state_binding {target, name} | set_connect_data {target, path, ref, data?} (prop'u veri kaynağına BAĞLAR: değer { type: 'connectData', ref: <tanım>, data: <son satırlar> } olur; path düz prop 'rows', nesne içi 'config.series' ya da dizi öğesi 'series.1.data'; data verilmezse bağlı prop'un satırları korunur, bağlı olmayan prop'un statik satırları (iç içe sarmallar açılarak) son satır olarak taşınır — D-11; tanım şekli ve alt küme kuralları istek gitmeden denetlenir — PAGE-035 · CD-004; platform_guide('page') §Kural 1c-3) | remove_connect_data {target, path} (bağlantıyı kaldırır, değer static olur; son satırlar static öğelere sarılarak korunur) — bağlı prop'a replace_prop ile connectData sarmalı, set_binding ya da set_prop_type yazılmaz; replace_prop { value: [ham satırlar] } yalnız örnek satırları değiştirir (CD-005) | batch {gestureId?, label?, ops: [...]} (iç içe batch yok). target = elementId. İstek atomiktir: tek op reddedilirse hiçbiri yazılmaz.");
28
30
  /**
29
31
  * PAGE-008 — `set_event` uydurma bir olay adıyla 200 döner ve bağ SESSİZCE ölü kalır: motor olayı
30
32
  * komponentin yaydığı adla eşleştirir, eşleşme yoksa akış hiç çalışmaz. Kontrol yalnız hedefin
@@ -67,6 +69,29 @@ export function collectTypes(nodes, into) {
67
69
  collectTypes(node.children, into);
68
70
  }
69
71
  }
72
+ /**
73
+ * TB-129 — `replace_prop` yalnız elementId taşır; stil anahtarı çevirisinin komponent TİPİNE
74
+ * bakabilmesi için hedeflerin tipi okunan ağaçtan çıkarılır. Harita YALNIZ `style` prop'u yazan
75
+ * bir op varsa kurulur: başka türlü fazladan bir okuma maliyeti doğardı.
76
+ */
77
+ export function styleTargetTypesFrom(ops, nodes) {
78
+ if (!ops.some(entry => entry.op === 'replace_prop' && String(entry.prop ?? '') === 'style'))
79
+ return undefined;
80
+ const types = new Map();
81
+ collectTypes(nodes, types);
82
+ return types;
83
+ }
84
+ /** Aynı harita, ağacı tembel okuyan yazma yolu için; okuma düşerse çeviri eski davranışa döner. */
85
+ export async function styleTargetTypes(ops, readHost) {
86
+ if (!ops.some(entry => entry.op === 'replace_prop' && String(entry.prop ?? '') === 'style'))
87
+ return undefined;
88
+ try {
89
+ return styleTargetTypesFrom(ops, (await readHost()).schema);
90
+ }
91
+ catch {
92
+ return undefined;
93
+ }
94
+ }
70
95
  export function removeNodeFromTree(nodes, target, parent) {
71
96
  for (let index = 0; index < nodes.length; index++) {
72
97
  if (nodes[index].elementId === target)
@@ -272,9 +297,44 @@ export function assertOpBodies(opRecords, propTypeOps) {
272
297
  if (sizedMoves.length > 0) {
273
298
  throw new PlatformApiError(`move_component yalnız 'position' uygular; gövdeye konan 'size' platformda SESSİZCE düşer (ölçüldü 2026-09-04, appliedPatch'te yalnız /blocks/0/position görünür). Boyut için resize_component kullanın: { op: 'resize_component', target: '<elementId>', size: { w, h } } — flex kapsayıcı içindeyse 'appearance'. Etkilenen hedefler: ${sizedMoves.map(entry => entry.target).join(' · ')}`, 400);
274
299
  }
300
+ const connectDataIssues = opRecords.flatMap(entry => connectDataOpIssues(entry).map(issue => `${issue.code} — ${issue.message}`));
301
+ if (connectDataIssues.length > 0)
302
+ throw new PlatformApiError(`Connect Data op gövdesi geçersiz (istek gönderilmedi): ${connectDataIssues.join(' · ')}`, 400);
275
303
  const validationIssues = schemaOpValidationErrors(opRecords);
276
304
  if (validationIssues.length > 0) {
277
305
  throw new PlatformApiError(`PAGE-016 — validation gövdesi eksik (istek gönderilmedi): ${validationIssues.join(' · ')}. `
278
306
  + "Çalışan biçim dört alanı da taşır: { type: 'required'|'email'|'regex'|'max-length'|'min-length'|'max-value'|'min-value'|'value-options', message: '<kullanıcıya görünen metin>', value: <eşik/desen/true>, isActive: true }.", 400);
279
307
  }
280
308
  }
309
+ /** İskelet kurallarının okuduğu prop'lar (düzen grubu dışında). */
310
+ const SKELETON_PROPS = new Set(['edges', 'horizontal', 'refreshable', 'stickyHeader', 'isHidden']);
311
+ /** Yama iskeleti değiştirebilir mi: yalnız o zaman kabuk okunur ve fark hesaplanır. */
312
+ export function reshapesSkeleton(ops) {
313
+ return ops.some(entry => ['add_component', 'move_component', 'remove_component', 'set_appearance', 'set_states'].includes(String(entry.op))
314
+ || ((entry.op === 'replace_prop' || entry.op === 'set_binding') && (FLEX_LAYOUT_PROP_NAMES.has(String(entry.prop ?? '')) || SKELETON_PROPS.has(String(entry.prop ?? '')))));
315
+ }
316
+ /**
317
+ * `simulateLayoutOps`'un uygulamadığı ama iskeleti değiştiren op'lar: silme, görünüm, durum bayrakları ve
318
+ * iskelet prop'ları. Uygulanmasa yama "sabit boy verilen scroll-view"ü gerekçesiz, silinen app-bar'ı ikinci
319
+ * sayardı.
320
+ */
321
+ export function applySkeletonOps(tree, ops) {
322
+ for (const entry of ops) {
323
+ const target = String(entry.target ?? '');
324
+ if (entry.op === 'remove_component')
325
+ removeNodeFromTree(tree, target);
326
+ if (entry.op === 'set_appearance' || entry.op === 'set_states') {
327
+ const node = findNode(tree, target);
328
+ const field = entry.op === 'set_appearance' ? 'appearance' : 'states';
329
+ const patch = entry[field];
330
+ if (node && patch && typeof patch === 'object')
331
+ node[field] = { ...node[field], ...patch };
332
+ }
333
+ if ((entry.op === 'replace_prop' || entry.op === 'set_binding') && SKELETON_PROPS.has(String(entry.prop ?? ''))) {
334
+ const node = findNode(tree, target);
335
+ const value = entry.op === 'set_binding' ? { type: 'code', ref: entry.expression } : entry.value;
336
+ if (node)
337
+ node.props = { ...node.props, [String(entry.prop)]: value && typeof value === 'object' ? value : { type: 'static', data: value } };
338
+ }
339
+ }
340
+ }
@@ -1,6 +1,8 @@
1
- import { invalidScreenEventNames, invalidWidgetTypeNodes, nestedRepeaterNodes, nestedRepeaterMessage, blockSizeNote, heightTypeNote, sizeStringNote } from '../knowledge/normalize.js';
1
+ import { invalidScreenEventNames, invalidWidgetTypeNodes, nestedRepeaterNodes, nestedRepeaterMessage, blockSizeNote, heightTypeNote, sizeStringNote, droppableStatesNote } from '../knowledge/normalize.js';
2
+ import { catalogTypeRules, schemaCatalogErrors, schemaCatalogMessage } from '../knowledge/componentCatalog.js';
2
3
  import { FUNCTIONS_NAMESPACE } from '../knowledge/functionGuards.js';
3
- import { applyCatalogLayoutRules } from './components.js';
4
+ import { reservedExpressionName } from '../knowledge/expressionPrelude.js';
5
+ import { applyCatalogLayoutRules, applyCatalogLayoutRulesFrom, fetchCatalogComponents } from './components.js';
4
6
  import { PlatformApiError } from '../platform/errors.js';
5
7
  const GUARD_CODES = {
6
8
  page: { events: 'PAGE-011', widgets: 'PAGE-012', noun: 'sayfa', tree: 'schema' },
@@ -18,11 +20,16 @@ export function invalidComponentNames(nodes) {
18
20
  if (typeof name === 'string' && name.length > 0 && !/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name.replace(/-/g, ''))) {
19
21
  found.push(`'${name}' (${node.elementId ?? '?'})`);
20
22
  }
21
- else if (typeof name === 'string' && name.replace(/-/g, '') === FUNCTIONS_NAMESPACE) {
23
+ else if (typeof name === 'string' && reservedExpressionName(name) === FUNCTIONS_NAMESPACE) {
22
24
  // K1: preamble her komponent için `const <ad> = Components["<ad>"]` üretir; `Functions` adlı
23
25
  // komponent kullanıcı fonksiyonlarının ad alanını ezer ve sayfadaki her Functions.x() ölür.
24
26
  found.push(`'${name}' (${node.elementId ?? '?'}) — ayrılmış ad: ${FUNCTIONS_NAMESPACE} kullanıcı fonksiyonlarının ad alanıdır (K1)`);
25
27
  }
28
+ else if (typeof name === 'string' && reservedExpressionName(name) !== undefined) {
29
+ // ARC-143: runtime preamble adıyla çakışan komponenti uyarıyla eler — komponent sayfadaki hiçbir
30
+ // ifadede görünmez. Eşleme runtime'ın tire kuralıyla (yalnız ilk `-`) yapılır.
31
+ found.push(`'${name}' (${node.elementId ?? '?'}) — ayrılmış ad: ${reservedExpressionName(name)} ifade preamble'ının adıdır; runtime bu komponenti ifadelerden gizler (ARC-143)`);
32
+ }
26
33
  found.push(...invalidComponentNames(node.children));
27
34
  }
28
35
  return found;
@@ -35,9 +42,10 @@ export function invalidComponentNames(nodes) {
35
42
  * PAGE-009 ve PAGE-013'ün layout ayağı 2026-09-09'da eklendi: ikisi de yalnız sayfa yollarında
36
43
  * koşuyordu, oysa layout `views`'ü aynı runtime'dan geçer — bozuk ad o layout'a bağlı HER
37
44
  * sayfanın ifadelerini öldürür, iç içe repeater'ın geri yazma kırılması ise yapısaldır ve
38
- * barındıranın sayfa mı layout mu olduğuna bakmaz.
45
+ * barındıranın sayfa mı layout mu olduğuna bakmaz. `platform` yalnız PAGE-013 mesajının önerisini seçer
46
+ * (mobilde `grouped-list`); denetimlerin kendisi iki platformda aynıdır.
39
47
  */
40
- export function assertScreenWriteGuards(kind, screen) {
48
+ export function assertScreenWriteGuards(kind, screen, platform) {
41
49
  const codes = GUARD_CODES[kind];
42
50
  const badEvents = invalidScreenEventNames(screen.events, codes.events);
43
51
  if (badEvents.length > 0)
@@ -49,12 +57,13 @@ export function assertScreenWriteGuards(kind, screen) {
49
57
  if (badNames.length > 0) {
50
58
  throw new PlatformApiError(`PAGE-009 — komponent adı JS tanımlayıcısı değil ya da ayrılmış (istek gönderilmedi): ${badNames.join(' · ')}. `
51
59
  + 'Runtime her komponent için `const <ad> = Components["<ad>"]` üretir; boşluklu ya da geçersiz bir ad '
52
- + 'SAYFADAKİ TÜM ifadeleri "Missing initializer in const declaration" ile öldürür (layout adları her sayfaya sızar). '
60
+ + 'SAYFADAKİ TÜM ifadeleri "Missing initializer in const declaration" ile öldürür (layout adları her sayfaya sızar); '
61
+ + 'ifade preamble\'ının ayrılmış adını (Page, state, item, t, event, Row …) taşıyan komponent ise ifadelerden gizlenir. '
53
62
  + `name alanını elementId ile aynı yaz; okunabilir Türkçe başlık için props.title / props.text / props.label kullan (${codes.noun} ${codes.tree}).`, 400);
54
63
  }
55
64
  const nested = nestedRepeaterNodes(screen.schema);
56
65
  if (nested.length > 0)
57
- throw new PlatformApiError(nestedRepeaterMessage(nested), 400);
66
+ throw new PlatformApiError(nestedRepeaterMessage(nested, platform), 400);
58
67
  }
59
68
  /**
60
69
  * Katalog kurallarını (blok sınırı · auto-height · boyut string'i) ağaca uygular ve
@@ -65,5 +74,25 @@ export async function screenCatalogNotes(platform, project, environment, applica
65
74
  if (!Array.isArray(nodes) || nodes.length === 0)
66
75
  return [];
67
76
  const catalog = await applyCatalogLayoutRules(platform, project, environment, applicationId, nodes);
68
- return [...blockSizeNote(catalog.clamped), ...heightTypeNote(catalog.heights), ...sizeStringNote(catalog.sizes)];
77
+ return [...blockSizeNote(catalog.clamped), ...heightTypeNote(catalog.heights), ...sizeStringNote(catalog.sizes), ...droppableStatesNote(catalog.states)];
78
+ }
79
+ /**
80
+ * TB-123 / S2-33 — TAM ŞEMA yazan yolların kapısı: `screenCatalogNotes`'un yaptığı yerleşim
81
+ * normalizasyonuna katalog DOĞRULAMASINI ekler ve geçersiz enum/prop'ta isteği hiç göndermez.
82
+ *
83
+ * Neden yalnız bu yollarda: micro-op ucunda platformun kendi doğrulama duvarı zaten koşuyor
84
+ * (`invalid-enum-value` · `unknown-prop` · `invalid-appearance`), tam şema PUT/POST'unda ise
85
+ * koşmuyordu — aynı geçersiz değer bir yoldan 400, öbüründen 200 dönüyordu. Katalog okunamazsa
86
+ * doğrulama susar ve yazma eskisi gibi geçer: bilinmeyen sözlük yüzünden geçerli bir gövdeyi
87
+ * bloklamak, denetimi atlamaktan kötüdür.
88
+ */
89
+ export async function assertScreenCatalog(platform, project, environment, applicationId, nodes, tool) {
90
+ if (!Array.isArray(nodes) || nodes.length === 0)
91
+ return [];
92
+ const components = await fetchCatalogComponents(platform, project, environment, applicationId).catch(() => []);
93
+ const errors = schemaCatalogErrors(nodes, catalogTypeRules(components));
94
+ if (errors.length > 0)
95
+ throw new PlatformApiError(schemaCatalogMessage(errors, tool), 400);
96
+ const catalog = applyCatalogLayoutRulesFrom(components, nodes);
97
+ return [...blockSizeNote(catalog.clamped), ...heightTypeNote(catalog.heights), ...sizeStringNote(catalog.sizes), ...droppableStatesNote(catalog.states)];
69
98
  }
@@ -1,33 +1,115 @@
1
1
  import { PlatformApiError } from '../platform/errors.js';
2
2
  import { resolveNodeStyleReport } from '../knowledge/styleResolve.js';
3
+ import { nodeNativeStyle } from '../knowledge/styleResolveNative.js';
4
+ import { jsonArray } from '../platform/jsonArray.js';
3
5
  import { z } from 'zod';
4
6
  export const hostParam = z.enum(['page', 'layout', 'component'])
5
7
  .describe("Akışın barındırıcısı: page | layout | component (widget de component'tir)");
6
- export const schemaParam = z.array(z.record(z.unknown()))
8
+ export const schemaParam = jsonArray(z.array(z.record(z.unknown())))
7
9
  .describe('Komponent ağacı (DesignComponentManagementSchema listesi); verilmezse mevcut şema korunur');
8
- export const eventsParam = z.array(z.record(z.unknown()))
10
+ export const eventsParam = jsonArray(z.array(z.record(z.unknown())))
9
11
  .describe("Sayfa/layout düzeyi olaylar: [{ name, value }] — value bir flow id'sidir");
10
12
  export const modeParam = z.enum(['summary', 'subtree', 'full']).optional().describe("summary (varsayılan): yalnız id/elementId/name/type ağacı — hedef bulmak için bunu kullanın. subtree: componentId ile tek alt ağaç. full: tüm şema.");
13
+ /**
14
+ * Şema ağacındaki TÜM düğümler (kök + iç içe çocuklar); page_get, page_create özeti, page_update
15
+ * ve page_schema_get aynı sayımı kullanır. Parçalı okumanın `deferred` yer tutucuları düğüm değildir.
16
+ */
17
+ export function countSchemaNodes(nodes) {
18
+ return (nodes ?? []).reduce((total, node) => node.deferred === true ? total : total + 1 + countSchemaNodes(node.children), 0);
19
+ }
20
+ function schemaNodeKey(node) {
21
+ return typeof node.elementId === 'string' ? node.elementId : String(node.id);
22
+ }
23
+ function schemaNodeKeys(nodes) {
24
+ return (nodes ?? []).flatMap(node => [schemaNodeKey(node), ...schemaNodeKeys(node.children)]);
25
+ }
26
+ /** `stored` ağacında olup `sent` ağacında olmayan düğümlerin elementId'leri, ön-sırayla (PAGE-041). */
27
+ export function missingElementIds(stored, sent) {
28
+ const kept = new Set(schemaNodeKeys(sent));
29
+ return schemaNodeKeys(stored).filter(key => !kept.has(key));
30
+ }
31
+ /**
32
+ * ZM-28: şemayı her biri `budgetChars` karakteri (JSON uzunluğu, `shrink` ile aynı ölçü) aşmayan
33
+ * parçalara böler. Ön-sıra ve deterministik: alt ağacı sığan düğüm BÜTÜN alınır, sığmayan kabuk olarak
34
+ * yazılır ve çocuklarına inilir; parçaların birleşimi orijinal şemanın birebir aynısıdır.
35
+ */
36
+ export function splitSchemaIntoParts(schema, budgetChars) {
37
+ const parts = [];
38
+ let current = [];
39
+ let currentChars = 2;
40
+ const place = (item, chars) => {
41
+ if (current.length > 0 && currentChars + 1 + chars > budgetChars) {
42
+ parts.push(current);
43
+ current = [];
44
+ currentChars = 2;
45
+ }
46
+ currentChars += (current.length > 0 ? 1 : 0) + chars;
47
+ current.push(item);
48
+ };
49
+ const visit = (node, parentElementId, index) => {
50
+ const whole = { parentElementId, index, node };
51
+ const wholeChars = JSON.stringify(whole).length;
52
+ if (2 + wholeChars <= budgetChars) {
53
+ place(whole, wholeChars);
54
+ return;
55
+ }
56
+ const children = Array.isArray(node.children) ? node.children : [];
57
+ const shell = {
58
+ parentElementId,
59
+ index,
60
+ node: { ...node, children: children.map(child => ({ elementId: schemaNodeKey(child), deferred: true })) }
61
+ };
62
+ const shellChars = JSON.stringify(shell).length;
63
+ if (children.length === 0 || 2 + shellChars > budgetChars) {
64
+ throw new PlatformApiError(`'${schemaNodeKey(node)}' (${String(node.type)}) düğümünün kendi gövdesi ${children.length === 0 ? wholeChars : shellChars} karakter; parça bütçesi ${budgetChars} karakter olduğu için tek düğüm bile bir yanıta sığmıyor. Düğümün büyük prop'unu page_schema_patch (replace_prop) ile küçültün ya da parçalara bölün; sonra cursor:'0' ile yeniden okuyun.`, 400);
65
+ }
66
+ place(shell, shellChars);
67
+ children.forEach((child, childIndex) => visit(child, schemaNodeKey(node), childIndex));
68
+ };
69
+ schema.forEach((node, index) => visit(node, null, index));
70
+ if (current.length > 0 || parts.length === 0)
71
+ parts.push(current);
72
+ return parts;
73
+ }
74
+ /** Opak parçalı okuma cursor'ı: sürüm değişince eski cursor reddedilir. */
75
+ export function encodeSchemaCursor(version, partIndex) {
76
+ return `${version}:${partIndex}`;
77
+ }
78
+ /** `'0'` sürümsüz ilk parçadır; `<sürüm>:<parça>` sürümü taşır. Çözülemeyen cursor `undefined`. */
79
+ export function decodeSchemaCursor(cursor) {
80
+ if (/^\d+$/.test(cursor))
81
+ return { partIndex: Number(cursor) };
82
+ const separator = cursor.lastIndexOf(':');
83
+ const partIndex = cursor.slice(separator + 1);
84
+ if (separator < 0 || !/^\d+$/.test(partIndex))
85
+ return undefined;
86
+ return { version: cursor.slice(0, separator), partIndex: Number(partIndex) };
87
+ }
11
88
  /**
12
89
  * Ağacı yalnız kimlik alanlarına indirger; hedef aramak için okunur boyutta tutar.
13
90
  * `styleSource` verilirse (undefined DEĞİLSE) her düğüme efektif stil raporu da
14
91
  * yazılır: tema componentStyles → preset → düğümün kendi stili kaskadı.
15
92
  */
16
- export function summarize(node, styleSource) {
93
+ export function summarize(node, styleSource, nativeTheme) {
17
94
  const summary = {
18
95
  id: node.id,
19
96
  elementId: node.elementId,
20
97
  name: node.name,
21
98
  type: node.type
22
99
  };
23
- if (styleSource !== undefined) {
100
+ // Mobil uygulama: stil CSS değil React Native nesnesidir (`shell` kutu, `text` metin).
101
+ if (nativeTheme !== undefined) {
102
+ const { shell, text, warnings } = nodeNativeStyle(node, nativeTheme, styleSource ?? undefined);
103
+ summary.nativeStyle = { shell, text, ...(warnings.length > 0 ? { warnings } : {}) };
104
+ }
105
+ else if (styleSource !== undefined) {
24
106
  const report = resolveNodeStyleReport(node, styleSource ?? undefined);
25
107
  if (report.resolvedStyle !== undefined)
26
108
  summary.resolvedStyle = report.resolvedStyle;
27
109
  summary.styleLayers = report.styleLayers;
28
110
  }
29
111
  if (Array.isArray(node.children) && node.children.length > 0) {
30
- summary.children = node.children.map(child => summarize(child, styleSource));
112
+ summary.children = node.children.map(child => summarize(child, styleSource, nativeTheme));
31
113
  }
32
114
  return summary;
33
115
  }
@@ -96,6 +178,11 @@ export function flowPath(host, applicationId, hostId, flowId) {
96
178
  : `/components/${applicationId}/${hostId}/flows`;
97
179
  return flowId ? `${root}/${flowId}` : root;
98
180
  }
181
+ /**
182
+ * Sayfa PUT gövdesi okunan sayfadan kurulur ve o sayfanın sürümünü `baseVersion` olarak taşır:
183
+ * platform sürümsüz sayfa PUT'unu reddeder (`plans/mobil-plantcare-acigi` b-05, K11). Gövde
184
+ * okunduğu andaki sayfanın üstüne yazar; ajanın planladığı sürümü `page_update` kendisi koyar.
185
+ */
99
186
  export function pageUpdateBody(page, overrides = {}) {
100
187
  const layout = (page.layout ?? {});
101
188
  return {
@@ -110,6 +197,9 @@ export function pageUpdateBody(page, overrides = {}) {
110
197
  middlewareIds: page.middlewareIds ?? [],
111
198
  roleIds: Array.isArray(page.roleIds) ? page.roleIds : identifiers(page.roles),
112
199
  layoutId: page.layoutId ?? layout.id ?? null,
200
+ baseVersion: page.version === undefined || page.version === null ? undefined : String(page.version),
201
+ isAnonymous: page.isAnonymous ?? false,
202
+ isLoginPage: page.isLoginPage ?? false,
113
203
  ...overrides
114
204
  };
115
205
  }
@@ -48,7 +48,7 @@ export function registerTemplateTools(server, platform) {
48
48
  description: "Şablonun bir modüldeki kayıtlarını listeler (project_create'in templateOptions.filters'ını doldurmak için).",
49
49
  inputSchema: {
50
50
  id: guid,
51
- module: z.string().describe("Module değeri: entity | microservice | workflow | page | layout | component | query | view | variable | global-function (fonksiyonlar, iki kaynak) | flow … (platform Module enum değeri, kebab-case)")
51
+ module: z.string().describe("Module değeri: entity | microservice | workflow | page | layout | component | query | view | variable | global-function (fonksiyonlar, iki kaynak) | flow | process-definition (yalnız aktif sürüm; kurulumda yeni kimlik, uygulama/workflow/sayfa/DTO kimlikleri yeniden eşlenir, var olan aynı slug'lı tanımda yeni sürüm yayınlanır ve uyarlama korunur) | business-calendar … (platform Module enum değeri, kebab-case)")
52
52
  },
53
53
  annotations: readOnly
54
54
  }, handle(config, ({ id, module }) => platform.org('GET', `/templates/${id}/items`, { query: { module } })));
@@ -77,6 +77,31 @@ export function registerTemplateTools(server, platform) {
77
77
  normalized.push(await defaultTemplateEnvironmentNote(platform, projectId));
78
78
  return withNormalization(await platform.org('POST', `/projects/${projectId}/templates`, { form }), normalized);
79
79
  }));
80
+ server.registerTool('template_application_create', {
81
+ title: 'Uygulamayı şablon olarak yayımla',
82
+ description: "Tek bir APPLICATION'dan yeni bir şablon sürümü üretir (POST /applications/{id}/templates). Sistem modülü şablonları (kompleks proje açılışında otomatik kurulanlar) uygulama kaynaklıdır: aynı ad + aynı applicationId ile çağırmak MEVCUT şablona yeni SÜRÜM ekler, template_create ise proje kaynaklı AYRI bir kayıt açar ve 'system_module_slug' işaretini taşımaz. 'systemModuleSlug' benzersizdir: başka bir şablonda kullanılıyorsa platform reddeder. environmentId boşsa platform projenin production OLMAYAN ilk environment'ını paketler.",
83
+ inputSchema: {
84
+ applicationId: guid,
85
+ name: z.string().min(1),
86
+ version: z.string().min(1).describe("Sürüm etiketi, ör. '1.0.0'"),
87
+ description: z.string().optional(),
88
+ changeLog: z.string().optional(),
89
+ systemModuleSlug: z.string().min(1).optional().describe("Sistem modülü işareti (ör. 'access'); kompleks proje açılışında otomatik kurulan şablonu bu alan belirler"),
90
+ environmentId: guid.optional().describe("Paketlenecek environment; boşsa production OLMAYAN ilk environment paketlenir")
91
+ },
92
+ annotations: writes
93
+ }, handle(config, async ({ applicationId, name, version, description, changeLog, systemModuleSlug, environmentId }) => {
94
+ const body = { name, version };
95
+ if (description)
96
+ body.description = description;
97
+ if (changeLog)
98
+ body.changeLog = changeLog;
99
+ if (systemModuleSlug)
100
+ body.systemModuleSlug = systemModuleSlug;
101
+ if (environmentId)
102
+ body.environmentId = environmentId;
103
+ return platform.org('POST', `/applications/${applicationId}/templates`, { body });
104
+ }));
80
105
  server.registerTool('template_check_updates', {
81
106
  title: 'Şablon güncellemesi var mı',
82
107
  description: 'Şablondan kurulmuş projenin kaynak şablonunda yeni sürüm var mı kontrol eder.',
@@ -46,7 +46,7 @@ export function registerTranslationTools(server, platform) {
46
46
  throw new Error("'keys' ya da 'deletedKeys' parametrelerinden en az biri dolu olmalı.");
47
47
  }
48
48
  const body = { keys: keys ?? [], deletedKeys: deletedKeys ?? [] };
49
- const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'translation', body, { operation: 'update' }));
49
+ const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'translation', body, { operation: 'update' }), false);
50
50
  const languages = await languageFindings(platform, project, keys ?? []);
51
51
  return attachFindings(await platform.tenant('PUT', project, `/translations/${applicationId}`, { environment, body }), [...findings, ...languages]);
52
52
  }));
@@ -1,11 +1,15 @@
1
1
  import { parseVariableEntries, mergeVariableEntries, withNormalization } from '../knowledge/normalize.js';
2
2
  import { guid, projectParam, environmentParam, readOnly, writes, updates, destructive } from './common.js';
3
+ import { STATE_STORAGE_KINDS } from '../knowledge/platform/profile.js';
4
+ import { variableProfileWarnings } from './profileWrite.js';
3
5
  import { handle } from '../platform/responses.js';
4
6
  import { z } from 'zod';
5
7
  const variablePath = (applicationId, pageId) => pageId ? `/variables/${applicationId}/${pageId}` : `/variables/${applicationId}`;
6
8
  const variablesParam = z.array(z.object({
7
9
  key: z.string().min(1).describe("Değişken adı; sayfada state.page.<key> ile okunur"),
8
- value: z.unknown().describe('Herhangi bir JSON değeri; nesne verirseniz alanlarına state.page.<key>.<alan> ile erişilir')
10
+ value: z.unknown().describe('Herhangi bir JSON değeri; nesne verirseniz alanlarına state.page.<key>.<alan> ile erişilir'),
11
+ storage: z.enum(['memory', ...STATE_STORAGE_KINDS]).optional()
12
+ .describe("Değerin yaşadığı yer (yalnız mobil uygulamada uygulanır, MOB-014). Verilmezse kayıttaki tür korunur; yeni değişkende bellektir — state her sayfa açılışında buradaki value'dan başlar. 'device': cihaz deposu (AsyncStorage karşılığı), uygulama kapanıp açılınca son yazılan değer geri gelir. 'secure': güvenli depo (expo-secure-store), token gibi gizli ve küçük değerler için. 'memory': türü kaldırır. Çıkışta ikisi de silinir.")
9
13
  })).min(1).describe("Değişken listesi: [{ key: 'MyTest', value: { isActive: true } }]. Gateway bunu platformun beklediği JSON string'e çevirir.");
10
14
  const replaceParam = z.boolean().optional()
11
15
  .describe('true: seti komple bunlarla değiştir (diğer değişkenler silinir). Varsayılan false — gateway mevcut setle birleştirir.');
@@ -22,7 +26,7 @@ export function registerVariableTools(server, platform) {
22
26
  }
23
27
  };
24
28
  const write = async (method, { project, environment, applicationId, pageId, variables, replace }) => {
25
- const incoming = variables.map(entry => ({ key: entry.key, value: entry.value ?? null }));
29
+ const incoming = variables.map(entry => ({ key: entry.key, value: entry.value, ...(entry.storage ? { storage: entry.storage } : {}) }));
26
30
  const existing = replace === true ? [] : await readEntries(project, environment, applicationId, pageId);
27
31
  const merged = mergeVariableEntries(existing, incoming, replace === true);
28
32
  const response = await platform.tenant(method, project, variablePath(applicationId, pageId), {
@@ -33,9 +37,11 @@ export function registerVariableTools(server, platform) {
33
37
  data: JSON.stringify(merged.entries)
34
38
  }
35
39
  });
40
+ const platformWarnings = await variableProfileWarnings(platform, applicationId, merged.entries.filter(entry => incoming.some(current => current.key === entry.key)));
36
41
  return withNormalization({
37
42
  scope: pageId ? 'page' : 'application',
38
43
  variables: merged.entries.map(entry => entry.key),
44
+ ...(platformWarnings.length > 0 ? { platformWarnings } : {}),
39
45
  response
40
46
  }, [
41
47
  ...merged.fixes,
@@ -44,7 +50,7 @@ export function registerVariableTools(server, platform) {
44
50
  };
45
51
  server.registerTool('variable_list', {
46
52
  title: 'Değişkenleri getir',
47
- description: "Application (pageId verilirse sayfa) değişken setini getirir. Platform seti tek kayıtta ve JSON STRING olarak tutar; gateway çözüp [{key, value}] dizisi döndürür. Sayfada okuma yolu: state.page.<key> (uygulama düzeyinde state.app.<key>).",
53
+ description: "Application (pageId verilirse sayfa) değişken setini getirir. Platform seti tek kayıtta ve JSON STRING olarak tutar; gateway çözüp [{key, value, storage?}] dizisi döndürür; storage yoksa değişken bellektedir. Sayfada okuma yolu: state.page.<key> (uygulama düzeyinde state.app.<key>).",
48
54
  inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, pageId: guid.optional() },
49
55
  annotations: readOnly
50
56
  }, handle(config, async ({ project, environment, applicationId, pageId }) => ({
@@ -61,7 +67,7 @@ export function registerVariableTools(server, platform) {
61
67
  }, handle(config, ({ project, environment, applicationId }) => platform.tenant('GET', project, `/variables/${applicationId}/pages`, { environment })));
62
68
  server.registerTool('variable_create', {
63
69
  title: 'Değişken tanımla',
64
- description: "Application (pageId verilirse sayfa) değişkeni tanımlar. Platform uygulama/sayfa başına TEK kayıt tutar ve seti komple değiştirir; gateway mevcut setle birleştirir (replace: true ile ezersiniz). Sayfada kullanım: prop { type:'code', ref:\"{{ state.page.<key>.<alan> }}\" } ya da flow'da value { type:'state', ref:'<key>' }.",
70
+ description: "Application (pageId verilirse sayfa) değişkeni tanımlar. Platform uygulama/sayfa başına TEK kayıt tutar ve seti komple değiştirir; gateway mevcut setle birleştirir (replace: true ile ezersiniz). Sayfada kullanım: prop { type:'code', ref:\"{{ state.page.<key>.<alan> }}\" } ya da flow'da value { type:'state', ref:'<key>' }. State varsayılan olarak BELLEKTEDİR: sayfa her açıldığında value'dan başlar. Mobil uygulamada kalıcı olması için variables[].storage verin (platform_guide('mobile') §Kalıcı state).",
65
71
  inputSchema: {
66
72
  project: projectParam,
67
73
  environment: environmentParam,
@@ -74,7 +80,7 @@ export function registerVariableTools(server, platform) {
74
80
  }, handle(config, input => write('POST', input)));
75
81
  server.registerTool('variable_update', {
76
82
  title: 'Değişken güncelle',
77
- description: "Var olan değişken setini günceller (variable_create zaten kayıt varsa update'e düşer; ikisi de aynı sonucu verir). Anahtar bazında birleştirir, replace: true ile seti komple değiştirir.",
83
+ description: "Var olan değişken setini günceller (variable_create zaten kayıt varsa update'e düşer; ikisi de aynı sonucu verir). Anahtar bazında birleştirir, replace: true ile seti komple değiştirir. storage vermediğiniz değişkenin kayıttaki saklama türü korunur.",
78
84
  inputSchema: {
79
85
  project: projectParam,
80
86
  environment: environmentParam,
@@ -5,18 +5,20 @@ import { workflowOutline, resolvePart, resolvePatchOperations } from '../knowled
5
5
  import { patchResult, baseVersionOf } from '../platform/patch.js';
6
6
  import { writeDiff, withWriteDiff } from '../platform/writeDiff.js';
7
7
  import { policyRules, microfunctionStepFindings, workflowStepFindings, undefinedInputFieldFindings } from '../knowledge/rules.js';
8
+ import { identityMiddlewareFindings } from '../knowledge/access.js';
8
9
  import { languageHeader } from '../knowledge/languageCodes.js';
9
10
  import { handle } from '../platform/responses.js';
10
11
  import { existingMatch, ifExistsParam, listAll, platformRename, withOutcome, withRename } from '../platform/ifExists.js';
11
12
  import { outlineWrite, recordWriteViewParam } from '../platform/writeView.js';
12
13
  import fastJsonPatch from 'fast-json-patch';
14
+ import { jsonArray } from '../platform/jsonArray.js';
13
15
  import { z } from 'zod';
14
16
  import { constraintSummary } from '../knowledge/backendConstraints.js';
15
17
  import { unmappedMembers, introducedUnmappedMembers, withUnmappedMembers } from '../knowledge/schemaGuard.js';
16
18
  const workflowIfExistsParam = ifExistsParam('workflow', 'mevcut workflow\'u bu tanımla tam gövde günceller (id\'si korunur; workflow_update ile aynı yazma)');
17
19
  const policyOverrideParam = z.boolean().optional()
18
20
  .describe('true: politika block bulgularını warn\'a indirir (bilinçli istisna; yanıtta işaretlenir)');
19
- const patchOperationsParam = z.array(z.record(z.unknown())).min(1)
21
+ const patchOperationsParam = jsonArray(z.array(z.record(z.unknown())).min(1))
20
22
  .describe("RFC 6902 JSON Patch işlemleri. Step hedeflerken İNDEKS YERİNE SEÇİCİ kullanın: { op: 'replace', path: '/steps[id=<stepId>]/rule/expression', value: '…' } — saklanan steps sırası gönderdiğiniz sıra DEĞİLDİR, indeks yolu sessizce başka adımı yazar. Seçici gövde platforma gitmeden indekse çevrilir; çözülemezse istek hiç gönderilmez. '/steps[name=setUser]/rule/joins' ve düz '/steps/2/...' de kabul edilir; yanıt her op'un hangi adıma indiğini patchTargets ile döner.");
21
23
  /**
22
24
  * Platform `set-user` step'i için `StepRule.Name`'i BOŞ döndürür (adı sabit: 'user') ve DTO
@@ -123,7 +125,8 @@ export function registerWorkflowTools(server, platform) {
123
125
  const stepFindings = [
124
126
  ...await microfunctionStepFindings(platform, project, environment, definition, definition.type, policyOverride),
125
127
  ...await workflowStepFindings(platform, project, environment, applicationId, definition, definition.type, policyOverride),
126
- ...await undefinedInputFieldFindings(platform, project, environment, definition, definition.type, policyOverride)
128
+ ...await undefinedInputFieldFindings(platform, project, environment, definition, definition.type, policyOverride),
129
+ ...await identityMiddlewareFindings(platform, project, environment, definition, definition.type, policyOverride)
127
130
  ];
128
131
  const bodyFindings = (operation) => evaluatePolicy(config, policyRules, 'workflow', definition, { operation, workflowKind: definition.type }, policyOverride);
129
132
  const createFindings = enforcePolicy([...bodyFindings('create'), ...stepFindings]);
@@ -164,7 +167,8 @@ export function registerWorkflowTools(server, platform) {
164
167
  ...evaluatePolicy(config, policyRules, 'workflow', definition, { operation: 'update', workflowKind: definition.type }, policyOverride),
165
168
  ...await microfunctionStepFindings(platform, project, environment, definition, definition.type, policyOverride),
166
169
  ...await workflowStepFindings(platform, project, environment, applicationId, definition, definition.type, policyOverride),
167
- ...await undefinedInputFieldFindings(platform, project, environment, definition, definition.type, policyOverride)
170
+ ...await undefinedInputFieldFindings(platform, project, environment, definition, definition.type, policyOverride),
171
+ ...await identityMiddlewareFindings(platform, project, environment, definition, definition.type, policyOverride)
168
172
  ]);
169
173
  const drift = unmappedMembers('UpdateWorkflowCommand', definition);
170
174
  const payload = await platform.tenant('PUT', project, `/workflows/${applicationId}/${id}`, { environment, body: definition });
@@ -186,7 +190,8 @@ export function registerWorkflowTools(server, platform) {
186
190
  ...evaluatePolicy(config, policyRules, 'workflow', patched, { operation: 'update', workflowKind: patched.type }, policyOverride),
187
191
  ...await microfunctionStepFindings(platform, project, environment, patched, patched.type, policyOverride),
188
192
  ...await workflowStepFindings(platform, project, environment, applicationId, patched, patched.type, policyOverride),
189
- ...await undefinedInputFieldFindings(platform, project, environment, patched, patched.type, policyOverride)
193
+ ...await undefinedInputFieldFindings(platform, project, environment, patched, patched.type, policyOverride),
194
+ ...await identityMiddlewareFindings(platform, project, environment, patched, patched.type, policyOverride)
190
195
  ]);
191
196
  const drift = introducedUnmappedMembers('UpdateWorkflowCommand', (current?.data ?? current), patched);
192
197
  // Gövde değil FARK gönderilir: gateway normalizasyonları da op'a çevrilsin diye net diff
@@ -218,7 +223,7 @@ export function registerWorkflowTools(server, platform) {
218
223
  }, handle(config, ({ project, environment, id }) => platform.tenant('POST', project, `/workflows/clone/${id}`, { environment })));
219
224
  server.registerTool('workflow_preview', {
220
225
  title: 'Workflow önizle',
221
- description: "Kaydedilmemiş workflow tanımını çalıştırır; kaydetmeden önce her akışı preview ile doğrulayın. definition = PreviewWorkflowCommand gövdesi. Test girdisi 'previewPayload' anahtarıyla verilir ('parameters'/'input' ÇALIŞMAZ), değişkenler 'previewVariables'. previewPayload STRING olmalıdır (JSON.stringify(...) ya da \"({ id: 1 })\") — nesne gönderilirse platform 'Unexpected end of input' ile 500 döner. Akışın parameterDtoId'si YOKSA previewPayload verilmez (platform 400 döner; gateway alanı düşürüp gatewayNormalized ile bildirir). Preview tek transaction'da koşar ve sonunda ROLLBACK edilir: table create/update step'leri kalıcı satır YAZMAZ (ölçüldü, İK koşusu W-1). Tek istisna code step içindeki dış HTTP çağrılarıdır — onlar geri alınamaz. Yanıt WorkflowPreviewDto: steps[] (her adım: step{id,name,type}, input[] ifade→değer, output, hasError, errorType, errorMessage, errorDetail, elapsedMilliseconds, nextStep, children[] loop/alt akış, automations[]), input, output, executionSuccess. executionSuccess YALNIZ son adıma bakar; gateway tüm ağacı tarayıp hata bulursa yanıta 'runtimeErrors' ekler — HTTP 200 akışın geçtiği anlamına gelmez, ÖNCE bu alana bakın; 'input' boşsa girdi hiç bağlanmamıştır. Kayıtlı bir akışı çalıştırmadan sınamak için workflow_get gövdesini (steps + kayıtlı previewPayload/previewVariables) olduğu gibi verin — Studio'nun Önizleme düğmesi de bunu yapar. Zamanlanmış işin akışında previewPayload vermeyin (iş girdisiz koşar); job geçmişi hatayı mesaj olarak yazar, adım izini burada görün (platform_guide('microservice') §Zamanlanmış işin gerçek sonucunu görmek). Okuma rehberi: platform_guide('workflow') §Önizleme çıktısını okumak. " + constraintSummary('PreviewWorkflowCommand'),
226
+ description: "Kaydedilmemiş workflow tanımını çalıştırır; kaydetmeden önce her akışı preview ile doğrulayın. definition = PreviewWorkflowCommand gövdesi. Test girdisi 'previewPayload' anahtarıyla verilir ('parameters'/'input' ÇALIŞMAZ), değişkenler 'previewVariables'. previewPayload STRING bir JavaScript İFADESİDİR ve parantezli nesne yazılır: \"({ id: 1 })\" — nesne gönderilirse platform 'Unexpected end of input' ile 500 döner; '{' ile başlayan metin blok olarak ayrıştırılır, 'JSON.stringify(…)' metni nesne değil string üretir — ikisi de sessizce input: {} ile koşardı ve WF-016 ile istek gitmeden durur (38/M-12). Akışın parameterDtoId'si YOKSA previewPayload verilmez (platform 400 döner; gateway alanı düşürüp gatewayNormalized ile bildirir). Preview tek transaction'da koşar ve sonunda ROLLBACK edilir: table create/update step'leri kalıcı satır YAZMAZ (ölçüldü, İK koşusu W-1). Tek istisna code step içindeki dış HTTP çağrılarıdır — onlar geri alınamaz. Yanıt WorkflowPreviewDto: steps[] (her adım: step{id,name,type}, input[] ifade→değer, output, hasError, errorType, errorMessage, errorDetail, elapsedMilliseconds, nextStep, children[] loop/alt akış, automations[]), input, output, executionSuccess. executionSuccess YALNIZ son adıma bakar; gateway tüm ağacı tarayıp hata bulursa yanıta 'runtimeErrors' ekler — HTTP 200 akışın geçtiği anlamına gelmez, ÖNCE bu alana bakın; 'input' boşsa girdi hiç bağlanmamıştır. Kayıtlı bir akışı çalıştırmadan sınamak için workflow_get gövdesini (steps + kayıtlı previewPayload/previewVariables) olduğu gibi verin — Studio'nun Önizleme düğmesi de bunu yapar. Zamanlanmış işin akışında previewPayload vermeyin (iş girdisiz koşar); job geçmişi hatayı mesaj olarak yazar, adım izini burada görün (platform_guide('microservice') §Zamanlanmış işin gerçek sonucunu görmek). Okuma rehberi: platform_guide('workflow') §Önizleme çıktısını okumak. " + constraintSummary('PreviewWorkflowCommand'),
222
227
  inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, definition: definitionParam, policyOverride: policyOverrideParam, language: languageParam },
223
228
  annotations: writes
224
229
  }, handle(config, async ({ project, environment, applicationId, definition, policyOverride, language }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appaflytech/zeyrek-ai-mcp",
3
- "version": "0.0.28",
3
+ "version": "0.0.30",
4
4
  "type": "module",
5
5
  "description": "Zeyrek (NgApps) platform APIs as MCP tools — data, logic and Studio design surface in one gateway",
6
6
  "license": "UNLICENSED",
@@ -60,4 +60,4 @@
60
60
  "typescript": "^5.7.2",
61
61
  "vitest": "^3.0.0"
62
62
  }
63
- }
63
+ }