@appaflytech/zeyrek-ai-mcp 0.0.30 → 0.0.32

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 (203) hide show
  1. package/.env.example +0 -15
  2. package/README.md +5 -5
  3. package/dist/config.js +0 -37
  4. package/dist/index.js +0 -2
  5. package/dist/knowledge/backendConstraints.js +1 -18
  6. package/dist/knowledge/boxSections.js +184 -0
  7. package/dist/knowledge/componentCatalog.js +232 -562
  8. package/dist/knowledge/componentEvents.js +21 -141
  9. package/dist/knowledge/layoutSummary.js +2 -140
  10. package/dist/knowledge/normalize.js +67 -236
  11. package/dist/knowledge/outlines.js +0 -36
  12. package/dist/knowledge/policy.js +4 -18
  13. package/dist/knowledge/reservedTables.js +0 -79
  14. package/dist/knowledge/rules.js +21 -319
  15. package/dist/knowledge/schemaGuard.js +0 -11
  16. package/dist/knowledge/styleResolve.js +38 -55
  17. package/dist/knowledge/themeResolve.js +3 -3
  18. package/dist/observability/trace.js +3 -6
  19. package/dist/platform/diagnostics.js +4 -10
  20. package/dist/platform/domSummary.js +1 -1
  21. package/dist/platform/errors.js +10 -162
  22. package/dist/platform/http.js +8 -29
  23. package/dist/platform/responses.js +5 -39
  24. package/dist/platform/{capture/capture.js → screenshot.js} +519 -105
  25. package/dist/platform/secrets.js +1 -17
  26. package/dist/platform/strictArguments.js +12 -68
  27. package/dist/platform/tokenVault.js +4 -187
  28. package/dist/resources/examples/layout-app-shell.json +707 -229
  29. package/dist/resources/examples/page-detail-profile.json +1 -2
  30. package/dist/resources/examples/page-dynamic-form.json +2 -3
  31. package/dist/resources/examples/page-flex-sections.json +1 -1
  32. package/dist/resources/examples/page-html-embed.json +1 -1
  33. package/dist/resources/examples/workflow-basic.json +2 -8
  34. package/dist/resources/guides/component.md +4 -91
  35. package/dist/resources/guides/entity.md +8 -50
  36. package/dist/resources/guides/expressions.md +5 -14
  37. package/dist/resources/guides/functions.md +1 -1
  38. package/dist/resources/guides/getting-started.md +1 -38
  39. package/dist/resources/guides/layout.md +58 -55
  40. package/dist/resources/guides/microservice.md +2 -81
  41. package/dist/resources/guides/middleware.md +2 -44
  42. package/dist/resources/guides/page.md +75 -454
  43. package/dist/resources/guides/theme.md +2 -8
  44. package/dist/resources/guides/translation.md +1 -1
  45. package/dist/resources/guides/workflow.md +1 -58
  46. package/dist/resources/rules.js +5 -11
  47. package/dist/resources/schema-fingerprint.json +5 -7
  48. package/dist/resources/schemas/CreateEntityCommand.json +0 -118
  49. package/dist/resources/schemas/CreateMicroserviceCommand.json +1 -13
  50. package/dist/resources/schemas/CreateQueryCommand.json +0 -4
  51. package/dist/resources/schemas/CreateWorkflowCommand.json +1 -143
  52. package/dist/resources/schemas/DataJobDto.json +1 -6
  53. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +1 -21
  54. package/dist/resources/schemas/MicroserviceDto.json +3 -15
  55. package/dist/resources/schemas/PreviewMicroserviceCommand.json +1 -10
  56. package/dist/resources/schemas/PreviewWorkflowCommand.json +1 -22
  57. package/dist/resources/schemas/StepDto.json +1 -22
  58. package/dist/resources/schemas/UpdateEntityCommand.json +0 -118
  59. package/dist/resources/schemas/UpdateMicroserviceCommand.json +1 -13
  60. package/dist/resources/schemas/UpdateQueryCommand.json +0 -4
  61. package/dist/resources/schemas/UpdateViewCommand.json +2 -0
  62. package/dist/resources/schemas/UpdateWorkflowCommand.json +1 -143
  63. package/dist/server.js +1 -27
  64. package/dist/tools/access.js +2 -369
  65. package/dist/tools/applications.js +3 -60
  66. package/dist/tools/common.js +0 -7
  67. package/dist/tools/components.js +14 -118
  68. package/dist/tools/datasources.js +3 -3
  69. package/dist/tools/dependencies.js +1 -1
  70. package/dist/tools/deployments.js +2 -2
  71. package/dist/tools/designSchemaPatch.js +18 -34
  72. package/dist/tools/dtos.js +5 -36
  73. package/dist/tools/entities.js +12 -79
  74. package/dist/tools/externalComponents.js +5 -26
  75. package/dist/tools/flows.js +14 -122
  76. package/dist/tools/folders.js +1 -1
  77. package/dist/tools/imports.js +2 -5
  78. package/dist/tools/layouts.js +17 -50
  79. package/dist/tools/merges.js +1 -1
  80. package/dist/tools/microservices.js +25 -77
  81. package/dist/tools/pages.js +112 -465
  82. package/dist/tools/platformInfo.js +8 -27
  83. package/dist/tools/projects.js +9 -71
  84. package/dist/tools/rows.js +13 -69
  85. package/dist/tools/schemaOps.js +1 -61
  86. package/dist/tools/screenWrite.js +8 -37
  87. package/dist/tools/screens.js +5 -95
  88. package/dist/tools/templates.js +1 -26
  89. package/dist/tools/translations.js +1 -1
  90. package/dist/tools/variables.js +5 -11
  91. package/dist/tools/workflows.js +5 -10
  92. package/package.json +2 -2
  93. package/dist/knowledge/access.js +0 -802
  94. package/dist/knowledge/case.js +0 -41
  95. package/dist/knowledge/connectDataBind.js +0 -819
  96. package/dist/knowledge/connectDataDefinition.js +0 -341
  97. package/dist/knowledge/connectDataExecute.js +0 -93
  98. package/dist/knowledge/connectDataRules.js +0 -128
  99. package/dist/knowledge/decision.js +0 -121
  100. package/dist/knowledge/expressionPrelude.js +0 -59
  101. package/dist/knowledge/microserviceParameters.js +0 -58
  102. package/dist/knowledge/mining.js +0 -94
  103. package/dist/knowledge/mobileComponentCatalog.js +0 -859
  104. package/dist/knowledge/mobileComponentEvents.js +0 -239
  105. package/dist/knowledge/platform/lint.js +0 -385
  106. package/dist/knowledge/platform/mobile.js +0 -142
  107. package/dist/knowledge/platform/mobileLayoutLint.js +0 -324
  108. package/dist/knowledge/platform/mobileRules.js +0 -231
  109. package/dist/knowledge/platform/mobileSpacing.js +0 -82
  110. package/dist/knowledge/platform/mobileTabs.js +0 -108
  111. package/dist/knowledge/platform/nativeBoxModel.js +0 -44
  112. package/dist/knowledge/platform/profile.js +0 -25
  113. package/dist/knowledge/platform/resolve.js +0 -122
  114. package/dist/knowledge/platform/web.js +0 -39
  115. package/dist/knowledge/process.js +0 -510
  116. package/dist/knowledge/rowFilter.js +0 -43
  117. package/dist/knowledge/styleResolveNative.js +0 -527
  118. package/dist/platform/argumentAliases.js +0 -128
  119. package/dist/platform/bodyFile.js +0 -103
  120. package/dist/platform/capture/actions.js +0 -333
  121. package/dist/platform/capture/browser.js +0 -1
  122. package/dist/platform/capture/console-log.js +0 -122
  123. package/dist/platform/capture/index.js +0 -11
  124. package/dist/platform/capture/readiness.js +0 -103
  125. package/dist/platform/capture/summary.js +0 -77
  126. package/dist/platform/capture/target.js +0 -5
  127. package/dist/platform/capture/targets/studio-mobile.js +0 -15
  128. package/dist/platform/capture/targets/studio-web.js +0 -5
  129. package/dist/platform/impersonation.js +0 -45
  130. package/dist/platform/jsonArray.js +0 -24
  131. package/dist/platform/schemaReadMemory.js +0 -60
  132. package/dist/resources/examples/bpm-gorev-kontrol.json +0 -294
  133. package/dist/resources/examples/bpm-iso-dokuman.json +0 -228
  134. package/dist/resources/examples/bpm-satinalma.json +0 -376
  135. package/dist/resources/examples/connect-data-convert-verify.json +0 -107
  136. package/dist/resources/examples/connect-data-dropdown-roles.json +0 -66
  137. package/dist/resources/examples/connect-data-edit-m2m.json +0 -73
  138. package/dist/resources/examples/connect-data-query-params.json +0 -50
  139. package/dist/resources/examples/connect-data-table-entity.json +0 -147
  140. package/dist/resources/examples/connect-data-workflow-microservice.json +0 -65
  141. package/dist/resources/examples/mobile-app-shell-drawer.json +0 -243
  142. package/dist/resources/examples/mobile-app-shell-stack.json +0 -157
  143. package/dist/resources/examples/mobile-app-shell-tab.json +0 -208
  144. package/dist/resources/examples/mobile-form-screen.json +0 -365
  145. package/dist/resources/examples/mobile-list-detail-form.json +0 -672
  146. package/dist/resources/guides/access.md +0 -796
  147. package/dist/resources/guides/bpm.md +0 -686
  148. package/dist/resources/guides/case.md +0 -153
  149. package/dist/resources/guides/decision.md +0 -185
  150. package/dist/resources/guides/mobile-layout.md +0 -193
  151. package/dist/resources/guides/mobile.md +0 -495
  152. package/dist/resources/read.js +0 -41
  153. package/dist/resources/schemas/AccessExplanationDto.json +0 -144
  154. package/dist/resources/schemas/AccessMatrixDto.json +0 -170
  155. package/dist/resources/schemas/AccessPermissionDto.json +0 -57
  156. package/dist/resources/schemas/AccessPolicyDto.json +0 -223
  157. package/dist/resources/schemas/AccessResourceDto.json +0 -86
  158. package/dist/resources/schemas/AppSessionDto.json +0 -53
  159. package/dist/resources/schemas/ConnectDataDescribeDto.json +0 -344
  160. package/dist/resources/schemas/ConnectDataRequestModel.json +0 -202
  161. package/dist/resources/schemas/ConnectDataResultDto.json +0 -421
  162. package/dist/resources/schemas/ConnectorCredentialDto.json +0 -70
  163. package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +0 -37
  164. package/dist/resources/schemas/CreateAccessPolicyCommand.json +0 -209
  165. package/dist/resources/schemas/CreateDecisionCommand.json +0 -221
  166. package/dist/resources/schemas/CreateProcessDefinitionCommand.json +0 -1337
  167. package/dist/resources/schemas/DecisionDto.json +0 -302
  168. package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +0 -28
  169. package/dist/resources/schemas/ExplainAccessQuery.json +0 -33
  170. package/dist/resources/schemas/GenerateProcessDocumentCommand.json +0 -116
  171. package/dist/resources/schemas/OrganizationProjectDto.json +0 -335
  172. package/dist/resources/schemas/OrganizationSchemaDto.json +0 -196
  173. package/dist/resources/schemas/OrganizationSchemaVersionDto.json +0 -207
  174. package/dist/resources/schemas/PatchProcessDefinitionCommand.json +0 -76
  175. package/dist/resources/schemas/ProcessDefinitionDto.json +0 -1480
  176. package/dist/resources/schemas/ProcessSimulationDto.json +0 -96
  177. package/dist/resources/schemas/SaveConnectorCredentialCommand.json +0 -90
  178. package/dist/resources/schemas/SaveProcessEventSourceCommand.json +0 -61
  179. package/dist/resources/schemas/SaveProcessMailSourceCommand.json +0 -89
  180. package/dist/resources/schemas/SignProcessTaskCommand.json +0 -73
  181. package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +0 -92
  182. package/dist/resources/schemas/UpdateAccessPolicyCommand.json +0 -209
  183. package/dist/resources/schemas/UpdateDecisionCommand.json +0 -216
  184. package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +0 -1357
  185. package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +0 -1339
  186. package/dist/tools/accessOperations.js +0 -135
  187. package/dist/tools/accessPolicies.js +0 -170
  188. package/dist/tools/accessRuntime.js +0 -203
  189. package/dist/tools/bpm.js +0 -343
  190. package/dist/tools/bpmGovernance.js +0 -266
  191. package/dist/tools/bpmOperations.js +0 -230
  192. package/dist/tools/bpmReporting.js +0 -154
  193. package/dist/tools/bpmRouting.js +0 -150
  194. package/dist/tools/bpmRuntime.js +0 -396
  195. package/dist/tools/case.js +0 -178
  196. package/dist/tools/caseRuntime.js +0 -89
  197. package/dist/tools/connectData.js +0 -449
  198. package/dist/tools/connectors.js +0 -193
  199. package/dist/tools/decisions.js +0 -206
  200. package/dist/tools/mobile.js +0 -221
  201. package/dist/tools/modules.js +0 -48
  202. package/dist/tools/organizationStructure.js +0 -137
  203. package/dist/tools/profileWrite.js +0 -92
@@ -1,8 +1,6 @@
1
1
  import { guid, entityRef, resolveEntityId, withResolved, projectParam, environmentParam, definitionParam, pagingParams, readOnly, writes, updates, destructive, microOps } from './common.js';
2
2
  import { RefResolver, isGuid } from '../platform/refs.js';
3
- import { evaluatePolicy, enforcePolicy, attachFindings, applyPolicyMode } from '../knowledge/policy.js';
4
- import { changedExistingProtections, fieldProtectionFindings, protectionMaskTypes } from '../knowledge/access.js';
5
- import { PlatformApiError } from '../platform/errors.js';
3
+ import { evaluatePolicy, enforcePolicy, attachFindings } from '../knowledge/policy.js';
6
4
  import { splitJunctionFields, withNormalization } from '../knowledge/normalize.js';
7
5
  import { unmappedMembers, introducedUnmappedMembers, withUnmappedMembers } from '../knowledge/schemaGuard.js';
8
6
  import { entityOutline, resolvePart, resolvePatchOperations, patchedSections } from '../knowledge/outlines.js';
@@ -10,11 +8,10 @@ import { patchResult, baseVersionOf } from '../platform/patch.js';
10
8
  import { isJunctionField, policyRules } from '../knowledge/rules.js';
11
9
  import { handle } from '../platform/responses.js';
12
10
  import fastJsonPatch from 'fast-json-patch';
13
- import { jsonArray } from '../platform/jsonArray.js';
14
11
  import { z } from 'zod';
15
12
  const policyOverrideParam = z.boolean().optional()
16
13
  .describe('true: politika block bulgularını warn\'a indirir (bilinçli istisna; yanıtta işaretlenir)');
17
- const patchOperationsParam = jsonArray(z.array(z.record(z.unknown())).min(1))
14
+ const patchOperationsParam = z.array(z.record(z.unknown())).min(1)
18
15
  .describe("RFC 6902 JSON Patch işlemleri; path'leri view:'outline'/'part' ile keşfedin");
19
16
  function preserveApplicationBinding(definition) {
20
17
  if (Array.isArray(definition.applicationIds))
@@ -116,7 +113,7 @@ export function registerEntityTools(server, platform) {
116
113
  }));
117
114
  server.registerTool('entity_create', {
118
115
  title: 'Entity oluştur',
119
- description: "Datasource altında yeni entity oluşturur (definition = CreateEntityCommand: name, fields[], applicationIds, ...). İlişkiler ve alan tipi kararı için platform_guide('entity') okuyun. Alan koruması (fields[].protection: masked · encrypted · masked-encrypted) ve türetilmiş sorgu alanı (fields[].derivedFromFieldId + derivationRule) aynı gövdede geçirgen gider — korunamayan tip/display (PROT-003) ve geçersiz türetme kuralı (PROT-004) istek gitmeden durur; kurallar platform_guide('access') §'Alan koruması'. Gövde politika kontrolünden geçer. applicationIds create'te platformca bağlanır (CreateEntityCommandHandler entityApplications'ı Entity ctor'una geçirir); satır uçları bu bağa İHTİYAÇ DUYMAZ — bağ yalnız Studio'nun application'a göre entity listesini ve bağımlılık sorgularını etkiler. `fields[].isLocalized: true` alanı ana tablodan çıkarıp companion `<slug>_localization` entity'sine taşır (yalnız düz METİN alanı; anahtar/unique/ilişki olamaz) — platform_guide('entity') §'Çoklu dilli alan'. SEÇİM LİSTESİNE (enum) TEK DEĞER: listeyi yeniden göndermeyin — ekleme `{op:'add', path:'/fields[slug=status]/valueOptions/-', value:{value:'Onayda', order:4}}`, silme `{op:'remove', path:'/fields[slug=status]/valueOptions[value=Eski]'}`, yeniden adlandırma `{op:'replace', path:'/fields[slug=status]/valueOptions[value=Eski]/value', value:'Yeni'}`; `isEnum` türetilmiştir, ayrıca yazılmaz. Silme/yeniden adlandırmadan ÖNCE o değeri taşıyan satırları taşıyın — yoksa istek reddedilir ve hiçbir şey yazılmaz ('check constraint … is violated by some row') (platform_guide('entity') §'Alan tipine karar verme').",
116
+ description: "Datasource altında yeni entity oluşturur (definition = CreateEntityCommand: name, fields[], applicationIds, ...). İlişkiler ve alan tipi kararı için platform_guide('entity') okuyun. Gövde politika kontrolünden geçer. applicationIds create'te platformca bağlanır (CreateEntityCommandHandler entityApplications'ı Entity ctor'una geçirir); satır uçları bu bağa İHTİYAÇ DUYMAZ — bağ yalnız Studio'nun application'a göre entity listesini ve bağımlılık sorgularını etkiler. `fields[].isLocalized: true` alanı ana tablodan çıkarıp companion `<slug>_localization` entity'sine taşır (yalnız düz METİN alanı; anahtar/unique/ilişki olamaz) — platform_guide('entity') §'Çoklu dilli alan'. SEÇİM LİSTESİNE (enum) TEK DEĞER: listeyi yeniden göndermeyin — ekleme `{op:'add', path:'/fields[slug=status]/valueOptions/-', value:{value:'Onayda', order:4}}`, silme `{op:'remove', path:'/fields[slug=status]/valueOptions[value=Eski]'}`, yeniden adlandırma `{op:'replace', path:'/fields[slug=status]/valueOptions[value=Eski]/value', value:'Yeni'}`; `isEnum` türetilmiştir, ayrıca yazılmaz. Silme/yeniden adlandırmadan ÖNCE o değeri taşıyan satırları taşıyın — yoksa istek reddedilir ve hiçbir şey yazılmaz ('check constraint … is violated by some row') (platform_guide('entity') §'Alan tipine karar verme').",
120
117
  inputSchema: { project: projectParam, environment: environmentParam, datasourceId: guid, definition: definitionParam, policyOverride: policyOverrideParam },
121
118
  annotations: writes
122
119
  }, handle(config, async ({ project, environment, datasourceId, definition, policyOverride }) => {
@@ -131,28 +128,12 @@ export function registerEntityTools(server, platform) {
131
128
  if (!createdId) {
132
129
  throw new Error(`Entity kuruldu ama id okunamadı; m2m alanları (${deferred.map(field => field.slug ?? field.name).join(', ')}) eklenmedi — entity_get ile kaydı bulup entity_patch ile ekleyin.`);
133
130
  }
134
- // 38/U-15: ertelenen alanlar TEK TEK eklenir. Hepsi tek PUT'ta gidince çoklu enum (VARCHAR + many-to-many +
135
- // valueOptions) başka bir junction alanıyla birlikteyken platform 400 RowHasExistingRelation ("Related table:
136
- // 'Entities', column: 'Relation Id'") döndü: çoklu enum alanının relationId'si aynı güncellemede açılan değer
137
- // entity'sini gösterir ve iki junction'lı yazmada alan kaydı o entity'den önce düşüyor (EntityService.UpdateAsync
138
- // fieldRepository.CreateRange → manyToManyFieldProcessor/entityRepository.Create). Ölçüldü 2026-09-21 cdt-mcp:
139
- // m2m+dosya-m2m+çoklu enum, dosya-m2m+çoklu enum, çoklu enum×2 düştü; m2m×2 geçti; tek tek hepsi geçti.
140
- let updated;
141
- for (const field of deferred) {
142
- const current = await platform.tenant('GET', project, `/entities/${datasourceId}/${createdId}`, { environment });
143
- const full = structuredClone((current?.data ?? current));
144
- full.fields = [...(Array.isArray(full.fields) ? full.fields : []), field];
145
- preserveApplicationBinding(full);
146
- try {
147
- updated = await platform.tenant('PUT', project, `/entities/${createdId}`, { environment, body: full });
148
- }
149
- catch (error) {
150
- const added = deferred.slice(0, deferred.indexOf(field)).map(item => item.slug ?? item.name);
151
- const missing = deferred.slice(deferred.indexOf(field)).map(item => item.slug ?? item.name);
152
- throw new PlatformApiError(`Entity ${createdId} kuruldu${added.length ? `, ${added.join(', ')} eklendi` : ''}; '${String(field.slug ?? field.name)}' eklenirken platform reddetti: ${error instanceof Error ? error.message : String(error)} — eklenmeyen alanlar (${missing.join(', ')}) entity_patch ile tek tek eklenebilir.`, error instanceof PlatformApiError ? error.status : 400, error instanceof PlatformApiError ? error.code : undefined);
153
- }
154
- }
155
- const note = `m2m/çoklu alanlar (${deferred.map(field => field.slug ?? field.name).join(', ')}) ayrı güncelleme turlarında TEK TEK eklendi: create yolu junction kaydını açar ama fiziksel tabloyu kurmaz (platform bug'ı P-01), update yolu kurar; çoklu enum başka bir junction alanıyla aynı güncellemede platformda düşer (38/U-15).`;
131
+ const current = await platform.tenant('GET', project, `/entities/${datasourceId}/${createdId}`, { environment });
132
+ const full = structuredClone((current?.data ?? current));
133
+ full.fields = [...(Array.isArray(full.fields) ? full.fields : []), ...deferred];
134
+ preserveApplicationBinding(full);
135
+ const updated = await platform.tenant('PUT', project, `/entities/${createdId}`, { environment, body: full });
136
+ const note = `m2m/çoklu alanlar (${deferred.map(field => field.slug ?? field.name).join(', ')}) ayrı bir güncelleme turunda eklendi: create yolu junction kaydını açar ama fiziksel tabloyu kurmaz (platform bug'ı P-01), update yolu kurar.`;
156
137
  return attachFindings(withUnmappedMembers(withNormalization(updated, [note]), drift), findings);
157
138
  }));
158
139
  server.registerTool('entity_create_discovered', {
@@ -163,7 +144,7 @@ export function registerEntityTools(server, platform) {
163
144
  }, handle(config, ({ project, environment, datasourceId, definition }) => platform.tenant('POST', project, `/entities/${datasourceId}/discovered`, { environment, body: definition })));
164
145
  server.registerTool('entity_update', {
165
146
  title: 'Entity güncelle',
166
- description: "Entity tanımını günceller (tam gövde). VAR OLAN alanın korumasını bu araç değiştiremez (platform 400 ProtectionChangeNotAllowed) — entity_protection_update; yeni alan korumayı gövdeyle alır (PROT-003/PROT-004). Türetilmiş alan eklemek ya da kaynağını/kuralını değiştirmek dolu satırları arka planda dolduran bir derived-fill işi açar (tablo kilitlenmez); bitişi import_history { entityId } ile izleyin. Hedefli değişiklik için entity_patch tercih edin. Gövde politika kontrolünden geçer. DİKKAT: gövdede 'indexes' YOKSA platform entity'nin bütün index'lerini siler — gateway alan verilmemişse mevcut index'leri taşır ve bunu bildirir; silmek için 'indexes: []' yazın. `fields[].isLocalized: true` alanı ana tablodan çıkarıp companion `<slug>_localization` entity'sine taşır (yalnız düz METİN alanı; anahtar/unique/ilişki olamaz) — platform_guide('entity') §'Çoklu dilli alan'.",
147
+ description: "Entity tanımını günceller (tam gövde). Hedefli değişiklik için entity_patch tercih edin. Gövde politika kontrolünden geçer. DİKKAT: gövdede 'indexes' YOKSA platform entity'nin bütün index'lerini siler — gateway alan verilmemişse mevcut index'leri taşır ve bunu bildirir; silmek için 'indexes: []' yazın. `fields[].isLocalized: true` alanı ana tablodan çıkarıp companion `<slug>_localization` entity'sine taşır (yalnız düz METİN alanı; anahtar/unique/ilişki olamaz) — platform_guide('entity') §'Çoklu dilli alan'.",
167
148
  inputSchema: { project: projectParam, environment: environmentParam, datasourceId: guid.optional().describe('Verilmezse gateway datasource ağacından bulur'), id: entityRef, definition: definitionParam, policyOverride: policyOverrideParam },
168
149
  annotations: updates
169
150
  }, handle(config, async ({ project, environment, datasourceId, id, definition, policyOverride }) => {
@@ -178,7 +159,7 @@ export function registerEntityTools(server, platform) {
178
159
  }));
179
160
  server.registerTool('entity_patch', {
180
161
  title: 'Entity\'ye patch uygula',
181
- description: "YENİ alanı korumayla ya da türetilmiş alan olarak eklemek için de kullanılır (PROT-003/PROT-004); eklenen ya da kuralı değişen türetilmiş alanı dolu satırlarda derived-fill işi doldurur (tablo kilitlenmez, bitiş import_history { entityId }). VAR OLAN alanın korumasını değiştirmez — platform 400 ProtectionChangeNotAllowed döner, gateway istek göndermeden durdurur ve yol entity_protection_update'tir. Tam gövdeyi bağlama almadan hedefli değişiklik: gateway mevcut tanımı okur, yolları çözer ve op'ları platformun PATCH /entities/{id} ucuna `{ baseVersion, ops }` olarak geçirir — tam gövde PUT'u ATILMAZ, yalnız fark yazılır. Yanıt outline özetidir. YOLLARDA SEÇİCİ KULLANIN, indeks değil: '/fields[slug=email]/nullable' — indeksle yazmak alan sırası değişince SESSİZCE yanlış alanı yazar. Gateway seçiciyi indekse çevirir ve hangi kayda indiğini yanıttaki patchTargets ile söyler. `baseVersion` okunan kaydın `version` alanından gelir; kayıt bu arada değiştiyse platform 409 döner ve HİÇBİR op uygulanmaz. 'applications' → 'applicationIds' çevirisini artık platform yapar. `fields[].isLocalized: true` alanı ana tablodan çıkarıp companion `<slug>_localization` entity'sine taşır (yalnız düz METİN alanı; anahtar/unique/ilişki olamaz) — platform_guide('entity') §'Çoklu dilli alan'.",
162
+ description: "Tam gövdeyi bağlama almadan hedefli değişiklik: gateway mevcut tanımı okur, yolları çözer ve op'ları platformun PATCH /entities/{id} ucuna `{ baseVersion, ops }` olarak geçirir — tam gövde PUT'u ATILMAZ, yalnız fark yazılır. Yanıt outline özetidir. YOLLARDA SEÇİCİ KULLANIN, indeks değil: '/fields[slug=email]/nullable' — indeksle yazmak alan sırası değişince SESSİZCE yanlış alanı yazar. Gateway seçiciyi indekse çevirir ve hangi kayda indiğini yanıttaki patchTargets ile söyler. `baseVersion` okunan kaydın `version` alanından gelir; kayıt bu arada değiştiyse platform 409 döner ve HİÇBİR op uygulanmaz. 'applications' → 'applicationIds' çevirisini artık platform yapar. `fields[].isLocalized: true` alanı ana tablodan çıkarıp companion `<slug>_localization` entity'sine taşır (yalnız düz METİN alanı; anahtar/unique/ilişki olamaz) — platform_guide('entity') §'Çoklu dilli alan'.",
182
163
  inputSchema: { project: projectParam, environment: environmentParam, datasourceId: guid.optional().describe('Verilmezse gateway datasource ağacından bulur'), id: entityRef, operations: patchOperationsParam.optional(), ops: patchOperationsParam.optional().describe("'operations' ile aynı alan (eşanlamlı) — sayfa micro-op tool'larıyla aynı adı kullanabilmeniz için"), policyOverride: policyOverrideParam },
183
164
  annotations: updates
184
165
  }, handle(config, async ({ project, environment, datasourceId, id, operations: givenOperations, ops, policyOverride }) => {
@@ -190,10 +171,6 @@ export function registerEntityTools(server, platform) {
190
171
  const resolvedOps = resolvePatchOperations(definition, operations, 'entity_get');
191
172
  // Politika, yazmadan önce sonucu görmeli; yerel kopya YALNIZ değerlendirme için, gövde olarak gönderilmez.
192
173
  const preview = fastJsonPatch.applyPatch(definition, resolvedOps.operations, true, false).newDocument;
193
- const protectionChanges = changedExistingProtections(current?.data ?? current, preview);
194
- if (protectionChanges.length > 0) {
195
- throw new PlatformApiError(`entity_patch: var olan alanın korumasını değiştiriyor (${protectionChanges.join(', ')}) — platform bunu 400 ProtectionChangeNotAllowed ile reddeder, çünkü dolu satırlar arka plan işiyle dönüştürülmelidir. entity_protection_update { entityId, field: '${protectionChanges[0]}', protection } kullanın; istek gönderilmedi. Yeni bir alanı korumayla eklemek entity_patch ile serbesttir.`, 400);
196
- }
197
174
  const findings = [
198
175
  ...enforcePolicy(evaluatePolicy(config, policyRules, 'entity', preview, { operation: 'update' }, policyOverride)),
199
176
  ...inPlaceIndexEdits(current?.data ?? current, preview)
@@ -218,48 +195,6 @@ export function registerEntityTools(server, platform) {
218
195
  outline: entityOutline(written.data)
219
196
  }, resolver.resolved), drift), findings);
220
197
  }));
221
- server.registerTool('entity_protection_update', {
222
- title: 'Alan korumasını değiştir',
223
- description: "VAR OLAN bir alanın koruma modunu değiştirir (none · masked · encrypted · masked-encrypted): platform gizli kolonları ekler ve dolu satırları arka plan işiyle dönüştürür — yanıt 202 + jobId; ilerleme import_status { jobId } (aynı DataJobs ucu, tür protection-apply / protection-remove). entity_update / entity_patch var olan alanın korumasını DEĞİŞTİREMEZ (400 ProtectionChangeNotAllowed). İş sürerken aynı entity'ye yazım 409; iş hata verirse AYNI çağrı kaldığı yerden sürdürür. PROT-003 istek gitmeden uygulanır; kurallar platform_guide('access') §'Alan koruması'.",
224
- inputSchema: {
225
- project: projectParam,
226
- environment: environmentParam,
227
- entityId: entityRef,
228
- field: z.string().min(1).describe("Alanın id'si (GUID) ya da slug'ı"),
229
- protection: z.object({
230
- mode: z.enum(['none', 'masked', 'encrypted', 'masked-encrypted']).describe("'none' korumayı kaldırır"),
231
- mask: z.object({
232
- type: z.enum(protectionMaskTypes()),
233
- visible: z.number().int().min(0).optional().describe('last-n / first-n için > 0; phone varsayılanı 2 hane; first-n-last-n\'de baştan görünen karakter sayısı (> 0)'),
234
- visibleEnd: z.number().int().min(0).optional().describe('Yalnız first-n-last-n: sondan görünen karakter sayısı (> 0) — 10000000146, visible 3 + visibleEnd 2 → 100******46'),
235
- char: z.string().length(1).optional().describe("Varsayılan '*'; phone maskesinde ayırıcı ya da boşluk (+-()./) olamaz"),
236
- pattern: z.string().optional().describe("pattern türünde: '#' açık karakter, diğerleri olduğu gibi yazılır")
237
- }).optional().describe('masked ve masked-encrypted modunda zorunlu'),
238
- exactSearch: z.boolean().optional().describe('Şifreli modda tam eşleşme araması için blind index (HMAC) kolonu'),
239
- normalize: z.enum(['none', 'digits', 'lower', 'trim']).optional().describe('Eşleşme ve blind index öncesi değeri normalleştirir (TCKN için digits)')
240
- }),
241
- policyOverride: z.boolean().optional().describe('true: politika block bulgularını warn\'a indirir (bilinçli istisna; yanıtta işaretlenir)')
242
- },
243
- annotations: updates
244
- }, handle(config, async ({ project, environment, entityId, field, protection, policyOverride }) => {
245
- const resolver = new RefResolver(platform, project, environment);
246
- const entity = await resolver.entity(entityId);
247
- const record = await resolver.entityRecord(entity);
248
- const fields = (Array.isArray(record.fields) ? record.fields : []);
249
- const target = fields.find(entry => entry.id === field || entry.slug === field);
250
- if (!target) {
251
- throw new PlatformApiError(`entity_protection_update: '${field}' alanı '${entity.slug}' entity'sinde yok. Alanları entity_get view:'outline' ile görün.`, 404);
252
- }
253
- const findings = config.policyMode === 'off' ? [] : enforcePolicy(applyPolicyMode(config, fieldProtectionFindings([{ ...target, protection }]), policyOverride));
254
- const payload = await platform.tenant('POST', project, `/entities/${entity.entityId}/fields/${String(target.id)}/protection`, { environment, body: { protection } });
255
- const jobId = payload?.data?.jobId ?? payload?.data?.dataJobId;
256
- return attachFindings(withResolved({
257
- jobId,
258
- field: target.slug,
259
- mode: protection.mode,
260
- note: `Koruma işi kuyruğa alındı. İlerleme: import_status { jobId: '${String(jobId)}' }. İş bitene kadar '${entity.slug}' entity'sine yazım 409 döner ve okumalar geçiş durumundadır (işlenmiş satırlar maskeli, işlenmemişler düz). Anahtar yapılandırılmamış ortamda iş ProtectionKeyUnavailable ile düşer.`
261
- }, resolver.resolved), findings);
262
- }));
263
198
  server.registerTool('entity_delete', {
264
199
  title: 'Entity sil',
265
200
  description: 'Entity tanımını siler; önce entity_dependencies ile bağımlılıklarını kontrol edin.',
@@ -302,15 +237,13 @@ export function registerEntityTools(server, platform) {
302
237
  }, handle(config, ({ project, environment, id }) => platform.tenant('GET', project, `/entities/${id}/dependencies`, { environment })));
303
238
  server.registerTool('entity_audit_trails', {
304
239
  title: 'Audit kayıtları',
305
- description: 'Entity\'nin satır bazlı audit trail kayıtlarını listeler (audit trail açık olmalı). `source: CONNECT_DATA` bağlı bileşenden (connectData ucu) gelen yazmaları süzer.',
240
+ description: 'Entity\'nin satır bazlı audit trail kayıtlarını listeler (audit trail açık olmalı).',
306
241
  inputSchema: {
307
242
  project: projectParam,
308
243
  environment: environmentParam,
309
244
  entityId: guid,
310
245
  rowId: z.string().optional(),
311
246
  userId: z.string().optional(),
312
- action: z.enum(['CREATE', 'UPDATE', 'DELETE', 'REVEAL', 'UNRESTRICTED-QUERY']).optional(),
313
- source: z.enum(['PLATFORM', 'APPLICATION', 'CONNECT_DATA']).optional(),
314
247
  ...pagingParams
315
248
  },
316
249
  annotations: readOnly
@@ -7,23 +7,6 @@ import { z } from 'zod';
7
7
  import { evaluatePolicy, enforcePolicy } from '../knowledge/policy.js';
8
8
  import { policyRules } from '../knowledge/rules.js';
9
9
  import { EXTERNAL_COMPONENT_PROTOCOL_VERSION } from '../knowledge/backendConstraints.js';
10
- import { resolveProfile } from '../knowledge/platform/resolve.js';
11
- import { findingLine } from '../knowledge/platform/profile.js';
12
- /**
13
- * MOB-006 — harici bileşen protokolü v1 tarayıcıda koşan `.mjs` custom element'tir; mobil
14
- * uygulamanın native çizeri onu yükleyemez (mobil protokol v2 Faz 3). Profil kapalı derse çağrı
15
- * platforma GİTMEZ: yüklenen paket hiçbir ekranda çizilmeyecekti.
16
- */
17
- async function assertExternalComponentsAllowed(platform, applicationId, tool) {
18
- const resolved = await resolveProfile(platform, applicationId);
19
- if (resolved.profile.externalComponents)
20
- return;
21
- throw new PlatformApiError(`${tool}: ${findingLine({
22
- code: 'MOB-006',
23
- severity: 'warn',
24
- message: "harici bileşen mobil uygulamada desteklenmiyor — protokol v1 tarayıcıda koşan .mjs custom element'tir, native çizer onu yükleyemez (mobil protokol v2 Faz 3). Çağrı platforma gönderilmedi; mobil ekranı katalog bileşenleriyle kurun (component_list). Katalogda karşılığı olmayan küçük görünüm için geçici yol 'html' bileşenidir: içerik korumalı belgede tema değişkenleriyle çizilir, fireEvent/ngApps.emit ile akışa bağlanır (component_get('html'))."
25
- })}`, 400);
26
- }
27
10
  /** Platformun köprü protokolü; scaffold ve publish bu sürüme göre üretir/doğrular (backend ExternalComponentRules.CurrentProtocolVersion) */
28
11
  const PROTOCOL_VERSION = EXTERNAL_COMPONENT_PROTOCOL_VERSION;
29
12
  /** Backend `ExternalComponentRules.MaxBundleSizeBytes` ile aynı sınır */
@@ -216,7 +199,6 @@ export function registerExternalComponentTools(server, platform) {
216
199
  },
217
200
  annotations: writes
218
201
  }, handle(config, async ({ project, environment, applicationId, bundlePath, manifestPath, version }) => {
219
- await assertExternalComponentsAllowed(platform, applicationId, 'external_component_publish');
220
202
  const manifestFile = resolve(manifestPath);
221
203
  const bundleFile = resolve(bundlePath);
222
204
  let manifest;
@@ -242,7 +224,7 @@ export function registerExternalComponentTools(server, platform) {
242
224
  }
243
225
  // EXT-001: protocolVersion, definition.blocks, ayrılmış prop adları ve prop tipleri — kayıt
244
226
  // ucu 422 dönmeden manifest'te yakalanır; paket yükleme ikinci istek olduğu için yarım kayıt kalmaz.
245
- enforcePolicy(evaluatePolicy(config, policyRules, 'externalComponent', { ...manifest, slug }, { operation: 'create' }), false);
227
+ enforcePolicy(evaluatePolicy(config, policyRules, 'externalComponent', { ...manifest, slug }, { operation: 'create' }));
246
228
  const record = await platform.tenant('POST', project, `/components/${applicationId}/external`, {
247
229
  environment,
248
230
  body: {
@@ -280,13 +262,10 @@ export function registerExternalComponentTools(server, platform) {
280
262
  acknowledgeWarnings: z.boolean().optional().describe('Doğrulama uyarılarını okuyup kabul ettiğinizi bildirir; uyarısı olan sürümlerde zorunlu')
281
263
  },
282
264
  annotations: updates
283
- }, handle(config, async ({ project, environment, applicationId, slug, version, acknowledgeWarnings }) => {
284
- await assertExternalComponentsAllowed(platform, applicationId, 'external_component_activate');
285
- return platform.tenant('POST', project, `/components/${applicationId}/external/${slug}/activate`, {
286
- environment,
287
- body: { version, acknowledgeWarnings: acknowledgeWarnings === true }
288
- });
289
- }));
265
+ }, handle(config, ({ project, environment, applicationId, slug, version, acknowledgeWarnings }) => platform.tenant('POST', project, `/components/${applicationId}/external/${slug}/activate`, {
266
+ environment,
267
+ body: { version, acknowledgeWarnings: acknowledgeWarnings === true }
268
+ })));
290
269
  server.registerTool('external_component_versions', {
291
270
  title: 'Paket sürümlerini listele',
292
271
  description: 'Bir harici komponentin yayınlanmış paket sürümlerini, hangisinin aktif olduğunu ve her sürümün doğrulama raporunu listeler. Geri alınacak sürümü buradan seçin.',
@@ -1,7 +1,6 @@
1
1
  import { fetchHost, flowPath, hostParam, unwrap } from './screens.js';
2
2
  import { guid, projectParam, environmentParam, readOnly, writes, updates, destructive, microOps } from './common.js';
3
- import { applyPolicyMode, evaluatePolicy, enforcePolicy, attachFindings } from '../knowledge/policy.js';
4
- import { connectedSetterFindings } from '../knowledge/connectDataDefinition.js';
3
+ import { evaluatePolicy, enforcePolicy, attachFindings } from '../knowledge/policy.js';
5
4
  import { flowBindings, normalizeFlowSteps, targetlessSetterWarnings, unknownSetterTargetWarnings, withNormalization } from '../knowledge/normalize.js';
6
5
  import { flowBodyWarnings } from '../knowledge/coverage.js';
7
6
  import { PlatformApiError } from '../platform/errors.js';
@@ -14,8 +13,6 @@ import { policyRules, flowExpressionSites } from '../knowledge/rules.js';
14
13
  import { functionCallRefs } from '../knowledge/functionGuards.js';
15
14
  import { existingMatch, ifExistsParam, platformRename, withRename } from '../platform/ifExists.js';
16
15
  import { randomUUID } from 'node:crypto';
17
- import { flowProfileWarnings } from './profileWrite.js';
18
- import { jsonArray } from '../platform/jsonArray.js';
19
16
  import { z } from 'zod';
20
17
  /**
21
18
  * Akış yazması yanıtında gövdeyi geri döndürmüyor, bu yüzden diff için akışı bir kez okuruz.
@@ -37,9 +34,9 @@ async function flowWriteDrops(platform, host, project, environment, applicationI
37
34
  return emptyWriteDiff();
38
35
  }
39
36
  }
40
- const stepsParam = jsonArray(z.array(z.record(z.unknown()))).describe("Adım listesi (StepManagementSchema: { stepId, name, type, kind, args, branches }). DİKKAT: branches[].nextStepId bir GUID değil, hedef adımın stepId STRING'idir; dal ADI motorun anahtarıdır ve start/setter/code/function adımlarında 'always' olmak zorundadır. Tam şablon: ngapps://examples/flow-load-table (ya da flow_get çıktısı); adım tipleri ve setter/parameters şekli platform_guide('page') Kural 1c. Kullanıcı fonksiyonu çağırmak için 'function' adımı: { type:'function', args:{ functionId:'<function_list id>', functionName:'<ad>', parameters:[{ name:'<bildirimdeki ad>', value:{ type:'static'|'property'|'storage'|'state'|'code', ref } }] } } → çıktı Steps.<adımAdı>.data (ngapps://examples/flow-call-function, platform_guide('functions')).");
37
+ const stepsParam = z.array(z.record(z.unknown())).describe("Adım listesi (StepManagementSchema: { stepId, name, type, kind, args, branches }). DİKKAT: branches[].nextStepId bir GUID değil, hedef adımın stepId STRING'idir; dal ADI motorun anahtarıdır ve start/setter/code/function adımlarında 'always' olmak zorundadır. Tam şablon: ngapps://examples/flow-load-table (ya da flow_get çıktısı); adım tipleri ve setter/parameters şekli platform_guide('page') Kural 1c. Kullanıcı fonksiyonu çağırmak için 'function' adımı: { type:'function', args:{ functionId:'<function_list id>', functionName:'<ad>', parameters:[{ name:'<bildirimdeki ad>', value:{ type:'static'|'property'|'storage'|'state'|'code', ref } }] } } → çıktı Steps.<adımAdı>.data (ngapps://examples/flow-call-function, platform_guide('functions')).");
41
38
  const policyOverrideParam = z.boolean().optional();
42
- const patchOperationsParam = jsonArray(z.array(z.record(z.unknown())).min(1)).describe("RFC 6902 JSON Patch işlemleri; yolları flow_get çıktısıyla keşfedin. Dizi öğelerinde indeks yerine seçici kullanılabilir: '/steps[stepId=paint]/args/iteratees[element=tbl_recruiters]/mapping/source' — seçici gövde platforma gitmeden indekse çevrilir, çözülemezse istek hiç gönderilmez.");
39
+ const patchOperationsParam = z.array(z.record(z.unknown())).min(1).describe("RFC 6902 JSON Patch işlemleri; yolları flow_get çıktısıyla keşfedin. Dizi öğelerinde indeks yerine seçici kullanılabilir: '/steps[stepId=paint]/args/iteratees[element=tbl_recruiters]/mapping/source' — seçici gövde platforma gitmeden indekse çevrilir, çözülemezse istek hiç gönderilmez.");
43
40
  const flowIdParam = guid.describe("Akış id'si; şemadaki events[].value bu id'dir");
44
41
  function flowSummary(flow) {
45
42
  return {
@@ -59,27 +56,6 @@ function hostNodes(record) {
59
56
  return record.schema ?? record.views ?? [];
60
57
  }
61
58
  const BINDINGS_UNAVAILABLE = 'Barındırıcı kaydı okunamadığı için olay bağları hesaplanamadı; akış listesi yine de günceldir.';
62
- /**
63
- * TB-126 / S2-36 — satır aksiyonu taşıyabilen komponentler. Bu tiplerin `actions` prop'unu çoğu
64
- * zaman YÜKLEME AKIŞI çalışma zamanında yazar (aksiyon role göre eklenip çıkarılıyorsa başka yolu
65
- * da yoktur), yani bağ statik şemada GÖRÜNMEZ. Böyle bir sayfada "bağsız akışları temizle" refleksi
66
- * canlı aksiyonu siler; `unboundFlowIds` bu yüzden dürüstçe işaretlenir.
67
- */
68
- const RUNTIME_ACTION_TYPES = new Set(['table', 'datatable']);
69
- const RUNTIME_BINDING_NOTE = 'Bu barındırıcıda satır aksiyonu taşıyan bir tablo var: satır aksiyonları çalışma zamanında yazılabilir, '
70
- + 'silmeden önce doğrulayın — unboundFlowIds statik şemadan hesaplanır ve çalışma zamanı bağını göremez.';
71
- function hasRuntimeActionHost(nodes) {
72
- for (const node of Array.isArray(nodes) ? nodes : []) {
73
- if (!node || typeof node !== 'object')
74
- continue;
75
- const record = node;
76
- if (typeof record.type === 'string' && RUNTIME_ACTION_TYPES.has(record.type))
77
- return true;
78
- if (hasRuntimeActionHost(record.children))
79
- return true;
80
- }
81
- return false;
82
- }
83
59
  /**
84
60
  * Akış listesine bağları ekler. `danglingBindings` ters yönü söyler: şemada id'si geçen ama
85
61
  * barındırıcıda karşılığı olmayan akış — olay tetiklenir, hiçbir şey koşmaz.
@@ -92,12 +68,9 @@ function flowListResult(flows, record) {
92
68
  const danglingBindings = [...bindings.entries()]
93
69
  .filter(([flowId]) => !known.has(flowId))
94
70
  .flatMap(([flowId, entries]) => entries.map(entry => ({ flowId, ...entry })));
95
- const unboundFlowIds = flows.map(flow => String(flow.id)).filter(flowId => !bindings.has(flowId.toLowerCase()));
96
- const mayBeBoundAtRuntime = unboundFlowIds.length > 0 && hasRuntimeActionHost(hostNodes(record));
97
71
  return {
98
72
  flows: flows.map(flow => ({ ...flowSummary(flow), bindings: bindings.get(String(flow.id).toLowerCase()) ?? [] })),
99
- unboundFlowIds,
100
- ...(mayBeBoundAtRuntime ? { mayBeBoundAtRuntime: true, mayBeBoundAtRuntimeNote: RUNTIME_BINDING_NOTE } : {}),
73
+ unboundFlowIds: flows.map(flow => String(flow.id)).filter(flowId => !bindings.has(flowId.toLowerCase())),
101
74
  ...(danglingBindings.length > 0 ? { danglingBindings } : {})
102
75
  };
103
76
  }
@@ -301,7 +274,7 @@ async function functionWarnings(platform, host, project, environment, applicatio
301
274
  }
302
275
  const missing = fn.parameters.filter(parameter => parameter.required && !given.includes(parameter.name)).map(parameter => parameter.name);
303
276
  if (missing.length > 0) {
304
- warnings.add(`FLOW-024: '${label(step)}' adımında '${fn.name}' fonksiyonunun zorunlu parametresi eksik: ${missing.join(', ')} — çağrı 'Functions.${fn.name}: "${missing[0]}" is required' ile düşer, Steps.${String(step.name ?? label(step))}.error.message dolar ve .data null'dur; errorSteps yoksa akış 'always' dalından devam eder.`);
277
+ warnings.add(`FLOW-024: '${label(step)}' adımında '${fn.name}' fonksiyonunun zorunlu parametresi eksik: ${missing.join(', ')} — çağrı 'Functions.${fn.name}: "${missing[0]}" is required' ile düşer, Steps.${String(step.name ?? label(step))}.error dolar ve akış hata gövdesiyle 'always' dalından devam eder.`);
305
278
  }
306
279
  }
307
280
  for (const { step, origin, ref } of callSites) {
@@ -322,65 +295,11 @@ async function functionWarnings(platform, host, project, environment, applicatio
322
295
  }
323
296
  return [...warnings];
324
297
  }
325
- /**
326
- * FLOW-036 (g-02, ADR 0004 — ZM-07). `microservice.ts` `.finally` üç yoldan birini dener: adımın
327
- * kendi `error` dalı bağlıysa oradan sürer, yoksa flow `errorSteps`'i (`engine.onError`) devralır,
328
- * ikisi de yoksa `always` koşar ve storage artık `{ data: null, headers: null, error }`'dır — hata
329
- * gövdesi ARTIK `data`'da DEĞİL. İkisi de bağlı değilken bu adımın `.data`'sını okuyan bir
330
- * setter/condition varsa hata anında NULL üzerinden koşar ve yazar hiç fark etmez. Aynı yürüyüş
331
- * FLOW-024/025'in kullandığı `flowExpressionSites` taramasıdır; setter'ın STORAGE (kod olmayan)
332
- * referansı ayrıca kendi düz alanından okunur (FLOW-008/009 deseni, `rowsTargetsByStepName`).
333
- */
334
- function microserviceAlwaysDataWarnings(steps, errorSteps) {
335
- const mainSteps = (Array.isArray(steps) ? steps : []).filter(isRecord);
336
- const hasErrorFlow = (Array.isArray(errorSteps) ? errorSteps : []).filter(isRecord).some(step => String(step.type ?? '') !== 'start');
337
- const label = (step) => String(step.stepId ?? step.name ?? '?');
338
- const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
339
- const warnings = new Set();
340
- for (const step of mainSteps) {
341
- if (String(step.type ?? '') !== 'microservice')
342
- continue;
343
- const name = String(step.name ?? step.stepId ?? '');
344
- if (name === '')
345
- continue;
346
- const hasErrorBranch = (Array.isArray(step.branches) ? step.branches : [])
347
- .filter(isRecord)
348
- .some(branch => String(branch.name ?? '') === 'error' && Boolean(branch.nextStepId));
349
- if (hasErrorBranch || hasErrorFlow)
350
- continue;
351
- const pattern = new RegExp(`Steps\\s*(?:\\.\\s*${escapeRegExp(name)}\\b|\\[\\s*['"]${escapeRegExp(name)}['"]\\s*\\])\\s*\\??\\.\\s*data\\b`);
352
- const message = (other) => `FLOW-036: '${label(other)}' adımı 'always' dalında '${name}.data' okuyor ama '${name}' adımının ne bağlı bir 'error' dalı ne akışın 'errorSteps'i var — uç hata dönerse bu adımın 'data'sı NULL olur (eskiden hata gövdesiydi, ADR 0004) ve '${label(other)}' boş/null veriyle koşar. '${name}' adımına 'error' dalı bağlayın ya da flow'a errorSteps verin.`;
353
- for (const other of mainSteps) {
354
- if (other === step)
355
- continue;
356
- if (String(other.type ?? '') === 'setter') {
357
- const iteratees = Array.isArray(other.args?.iteratees)
358
- ? other.args.iteratees.filter(isRecord)
359
- : [];
360
- for (const iteratee of iteratees) {
361
- const mapping = (iteratee.mapping ?? {});
362
- const value = (iteratee.value ?? {});
363
- const reference = typeof mapping.source === 'string' && mapping.source.length > 0
364
- ? mapping.source
365
- : typeof value.ref === 'string' ? value.ref : '';
366
- if (value.type === 'storage' && (reference === `${name}.data` || reference.startsWith(`${name}.data.`) || reference.startsWith(`${name}.data[`))) {
367
- warnings.add(message(other));
368
- }
369
- }
370
- }
371
- for (const site of flowExpressionSites(other)) {
372
- if (pattern.test(site.expression))
373
- warnings.add(message(other));
374
- }
375
- }
376
- }
377
- return [...warnings];
378
- }
379
298
  export function registerFlowTools(server, platform) {
380
299
  const config = platform.config;
381
300
  server.registerTool('flow_list', {
382
301
  title: 'Akışları listele',
383
- description: "Barındırıcının olay akışlarını, her birine bağlı olaylarla (bindings: [{ target: elementId | 'page', event }]) listeler. unboundFlowIds hiçbir olaya bağlı olmayan (sahipsiz) akışlardır; danglingBindings şemada id'si geçen ama barındırıcıda olmayan akışlardır. Yanıtta mayBeBoundAtRuntime: true varsa sayfada table/datatable vardır ve satır aksiyonları (actions[].flow) çalışma zamanında yazılmış olabilir: unboundFlowIds o hâlde KESİN DEĞİLDİR, silmeden önce doğrulayın (TB-126). Sayfa ve layout akışları önbelleksiz liste ucundan, widget akışları kaydın kendi gövdesinden okunur; bağlar barındırıcının şemasından hesaplanır.",
302
+ description: "Barındırıcının olay akışlarını, her birine bağlı olaylarla (bindings: [{ target: elementId | 'page', event }]) listeler. unboundFlowIds hiçbir olaya bağlı olmayan (sahipsiz) akışlardır; danglingBindings şemada id'si geçen ama barındırıcıda olmayan akışlardır. Sayfa ve layout akışları önbelleksiz liste ucundan, widget akışları kaydın kendi gövdesinden okunur; bağlar barındırıcının şemasından hesaplanır.",
384
303
  inputSchema: { project: projectParam, environment: environmentParam, host: hostParam, applicationId: guid, hostId: guid },
385
304
  annotations: readOnly
386
305
  }, handle(config, async ({ project, environment, host, applicationId, hostId }) => {
@@ -442,18 +361,14 @@ export function registerFlowTools(server, platform) {
442
361
  ...(host === 'page' ? { pageId: hostId } : host === 'layout' ? { layoutId: hostId } : { componentId: hostId })
443
362
  };
444
363
  const normalized = [...normalizeFlowSteps(flow.steps), ...normalizeFlowSteps(flow.errorSteps)];
445
- const findings = [
446
- ...enforcePolicy(evaluatePolicy(config, policyRules, 'flow', flow, { operation: 'create' }, policyOverride)),
447
- ...enforcePolicy(config.policyMode === 'off' ? [] : applyPolicyMode(config, connectedSetterFindings(steps, errorSteps ?? [], hostNodes(hostRecord)), policyOverride))
448
- ];
364
+ const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'flow', flow, { operation: 'create' }, policyOverride));
449
365
  const existing = await existingFlowMatch(platform, host, project, environment, applicationId, hostId, hostRecord, name, slug, flowId, ifExists);
450
366
  const writtenFlowId = existing === undefined ? resolvedFlowId : String(existing.id);
451
367
  const parameterWarnings = [
452
368
  ...await requiredParameterWarnings(platform, project, environment, applicationId, steps),
453
369
  ...await functionWarnings(platform, host, project, environment, applicationId, hostId, steps),
454
370
  ...flowBodyWarnings(steps),
455
- ...unknownSetterTargetWarnings(steps, errorSteps ?? [], hostNodes(hostRecord)),
456
- ...microserviceAlwaysDataWarnings(steps, errorSteps ?? [])
371
+ ...unknownSetterTargetWarnings(steps, errorSteps ?? [], hostNodes(hostRecord))
457
372
  ];
458
373
  // Gövde yalnız akıştır (designer-partial-update K1): barındırıcı zarfı platformda hâlâ isteğe bağlı
459
374
  // ama gönderilirse okunan tam kaydı yeniden yazar, açık Studio designer'ının kayıtlı tabanını
@@ -467,7 +382,6 @@ export function registerFlowTools(server, platform) {
467
382
  // Diff YALNIZ çağıranın yazdığı alanları kapsar; `id` ve barındırıcı bağı (`pageId` vb.)
468
383
  // gövdeye gateway koyar, kullanıcının düzeltebileceği bir şey değildir.
469
384
  const drops = await flowWriteDrops(platform, host, project, environment, applicationId, hostId, writtenFlowId, { name: flow.name, slug: flow.slug, steps: flow.steps, errorSteps: flow.errorSteps }, ifExists === 'duplicate');
470
- const platformWarnings = await flowProfileWarnings(platform, applicationId, [...(flow.steps ?? []), ...(flow.errorSteps ?? [])]);
471
385
  return attachFindings(withWriteDiff(withRename(withNormalization({
472
386
  host,
473
387
  hostId,
@@ -479,7 +393,6 @@ export function registerFlowTools(server, platform) {
479
393
  steps: steps.length
480
394
  },
481
395
  ...(parameterWarnings.length > 0 ? { parameterWarnings } : {}),
482
- ...(platformWarnings.length > 0 ? { platformWarnings } : {}),
483
396
  hint: "Akışı bir olaya bağlamak için: page_schema_patch (layout'ta layout_schema_patch, widget'ta component_schema_patch) ops:[{op:'set_event', target:<elementId>, event:'<component_get events listesindeki ad>', eventValue:<flow id>}]; olayda zaten akış bağlıysa ikinciyi add_event ile ekleyin (set_event bağlı akışı değiştirir, PAGE-034). Olay adları komponente özeldir ve 'on' ÖNEKİ ALMAZ (button → 'click', form → 'submit', table → 'mount'/'select'/'sort'…); uydurma ad 200 döner ama bağ sessizce ölü kalır — gateway PAGE-008 ile yakalar."
484
397
  }, normalized), drops.renamed), drops), findings);
485
398
  }));
@@ -516,17 +429,13 @@ export function registerFlowTools(server, platform) {
516
429
  const authored = { steps: steps ?? [], errorSteps: errorSteps ?? [] };
517
430
  const normalized = [...normalizeFlowSteps(authored.steps), ...normalizeFlowSteps(authored.errorSteps)];
518
431
  const findings = steps || errorSteps
519
- ? [
520
- ...enforcePolicy(evaluatePolicy(config, policyRules, 'flow', authored, { operation: 'update' }, policyOverride)),
521
- ...enforcePolicy(config.policyMode === 'off' ? [] : applyPolicyMode(config, connectedSetterFindings(authored.steps, authored.errorSteps, hostNodes(hostRecord)), policyOverride))
522
- ]
432
+ ? enforcePolicy(evaluatePolicy(config, policyRules, 'flow', authored, { operation: 'update' }, policyOverride))
523
433
  : [];
524
434
  const parameterWarnings = [
525
435
  ...await requiredParameterWarnings(platform, project, environment, applicationId, flow.steps),
526
436
  ...await functionWarnings(platform, host, project, environment, applicationId, hostId, flow.steps),
527
437
  ...flowBodyWarnings(flow.steps),
528
- ...unknownSetterTargetWarnings(flow.steps, flow.errorSteps, hostNodes(hostRecord)),
529
- ...microserviceAlwaysDataWarnings(flow.steps, flow.errorSteps)
438
+ ...unknownSetterTargetWarnings(flow.steps, flow.errorSteps, hostNodes(hostRecord))
530
439
  ];
531
440
  await platform.tenant('PUT', project, flowPath(host, applicationId, hostId, flowId), { environment, body: { flow } });
532
441
  // Kısmi güncellemede yalnız GÖNDERİLEN alanlar karşılaştırılır; verilmeyen alan için
@@ -537,9 +446,7 @@ export function registerFlowTools(server, platform) {
537
446
  ...(steps === undefined ? {} : { steps }),
538
447
  ...(errorSteps === undefined ? {} : { errorSteps })
539
448
  });
540
- const platformWarnings = await flowProfileWarnings(platform, applicationId, [...(flow.steps ?? []), ...(flow.errorSteps ?? [])]);
541
- return attachFindings(withWriteDiff(withNormalization({ host, hostId, flow: flowSummary(flow), ...(parameterWarnings.length > 0 ? { parameterWarnings } : {}),
542
- ...(platformWarnings.length > 0 ? { platformWarnings } : {}) }, normalized), drops), findings);
449
+ return attachFindings(withWriteDiff(withNormalization({ host, hostId, flow: flowSummary(flow), ...(parameterWarnings.length > 0 ? { parameterWarnings } : {}) }, normalized), drops), findings);
543
450
  }));
544
451
  server.registerTool('flow_patch', {
545
452
  title: "Akışa patch uygula",
@@ -573,16 +480,12 @@ export function registerFlowTools(server, platform) {
573
480
  ...(host === 'page' ? { pageId: hostId } : host === 'layout' ? { layoutId: hostId } : { componentId: hostId })
574
481
  };
575
482
  const normalized = [...normalizeFlowSteps(flow.steps), ...normalizeFlowSteps(flow.errorSteps)];
576
- const findings = [
577
- ...enforcePolicy(evaluatePolicy(config, policyRules, 'flow', flow, { operation: 'update' }, policyOverride)),
578
- ...enforcePolicy(config.policyMode === 'off' ? [] : applyPolicyMode(config, connectedSetterFindings(flow.steps, flow.errorSteps, hostNodes(hostRecord)), policyOverride))
579
- ];
483
+ const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'flow', flow, { operation: 'update' }, policyOverride));
580
484
  const parameterWarnings = [
581
485
  ...await requiredParameterWarnings(platform, project, environment, applicationId, flow.steps),
582
486
  ...await functionWarnings(platform, host, project, environment, applicationId, hostId, flow.steps),
583
487
  ...flowBodyWarnings(flow.steps),
584
- ...unknownSetterTargetWarnings(flow.steps, flow.errorSteps, hostNodes(hostRecord)),
585
- ...microserviceAlwaysDataWarnings(flow.steps, flow.errorSteps)
488
+ ...unknownSetterTargetWarnings(flow.steps, flow.errorSteps, hostNodes(hostRecord))
586
489
  ];
587
490
  // Gövde değil FARK gönderilir; platform PATCH ucu akışı tek başına yazar. Net diff okunan kayıt ile son hâl arasından hesaplanır.
588
491
  const netOps = fastJsonPatch.compare(current, flow);
@@ -592,7 +495,6 @@ export function registerFlowTools(server, platform) {
592
495
  });
593
496
  const written = patchResult(saved, flow);
594
497
  const drops = await flowWriteDrops(platform, host, project, environment, applicationId, hostId, flowId, { steps: flow.steps, errorSteps: flow.errorSteps });
595
- const platformWarnings = await flowProfileWarnings(platform, applicationId, [...(flow.steps ?? []), ...(flow.errorSteps ?? [])]);
596
498
  return attachFindings(withWriteDiff(withNormalization({
597
499
  host,
598
500
  hostId,
@@ -600,8 +502,7 @@ export function registerFlowTools(server, platform) {
600
502
  newVersion: written.newVersion,
601
503
  patchTargets: resolved.targets,
602
504
  flow: flowSummary(written.data),
603
- ...(parameterWarnings.length > 0 ? { parameterWarnings } : {}),
604
- ...(platformWarnings.length > 0 ? { platformWarnings } : {})
505
+ ...(parameterWarnings.length > 0 ? { parameterWarnings } : {})
605
506
  }, [...normalized, ...resolved.notes.map(note => `patch yolu seçiciden indekse çözüldü: ${note}`)]), drops), findings);
606
507
  }));
607
508
  server.registerTool('flow_delete', {
@@ -613,13 +514,4 @@ export function registerFlowTools(server, platform) {
613
514
  await platform.tenant('DELETE', project, flowPath(host, applicationId, hostId, flowId), { environment, body: { id: flowId } });
614
515
  return { deleted: flowId, host, hostId };
615
516
  }));
616
- server.registerTool('flow_restore', {
617
- title: 'Silinen akışı geri yükle',
618
- description: "Silinmiş bir akışı revizyon defterindeki son içeriğiyle (ad, slug, adımlar, barındırıcı) AYNI id ile yeniden kurar. Sayfa kaydı bağı kalmayan akışı kalıcı siler (FLOW-002, allowFlowDeletion) — Studio'nun eski sekmesi boş şema kaydettiğinde de (ZM-27). Akışı olaya YENİDEN BAĞLAMAZ: geri geldikten sonra set_event ile bağlayın. SINIR: adımları sayfanın bir komponentini hedefliyorsa (tetikleyen element, iterate/parametre komponenti) o komponent de şemada olmalıdır, yoksa geri yükleme reddedilir — sayfa boşaldıysa (ZM-27) page_restore kullanın: sayfayı ve akışlarını birlikte geri kurar. Akış hâlâ varsa 409, saklama süresi dolup revizyonu budanmışsa 404 döner. Silinen akışı revision_list(module: 'flow') satırlarında operation: delete olarak bulun; recordId akış id'sidir.",
619
- inputSchema: { project: projectParam, environment: environmentParam, flowId: flowIdParam },
620
- annotations: writes
621
- }, handle(config, async ({ project, environment, flowId }) => {
622
- const restored = unwrap(await platform.tenant('POST', project, `/flows/${flowId}/restore`, { environment }));
623
- return { restored: flowId, flow: restored };
624
- }));
625
517
  }
@@ -23,7 +23,7 @@ export function registerFolderTools(server, platform) {
23
23
  inputSchema: { project: projectParam, environment: environmentParam, definition: definitionParam },
24
24
  annotations: writes
25
25
  }, handle(config, async ({ project, environment, definition }) => {
26
- const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'folder', definition, { operation: 'create' }), false);
26
+ const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'folder', definition, { operation: 'create' }));
27
27
  return attachFindings(await platform.tenant('POST', project, '/folders', { environment, body: definition }), findings);
28
28
  }));
29
29
  server.registerTool('folder_update', {
@@ -182,10 +182,7 @@ export function registerImportTools(server, platform) {
182
182
  return { ...payload, note: "Plan henüz çalıştırılmadı: import_run { datasourceId, planId } ile başlatın — planId bu jobId'dir ve plan bir saat geçerlidir." };
183
183
  }
184
184
  if (status === 'failed') {
185
- // Koruma işi (entity_protection_update) düşerse alan geçişte kalır ve entity yazımı 409'a kilitlenir;
186
- // otomatik yeniden deneme yok, kurtarma aynı isteği aynı gövdeyle tekrarlamaktır (TB-31).
187
- const isProtection = job?.kind === 'protection-apply' || job?.kind === 'protection-remove';
188
- return { ...payload, note: `İş düştü; \`error\` alanı nedeni söyler.${isImport ? ' Yazılmış partiler yerinde kalır; bugün geri alınamaz.' : ''}${isProtection ? " Koruma işi: alan geçiş durumunda kalır ve entity'ye yazım 409 döner. Nedeni giderdikten sonra AYNI entity_protection_update çağrısını AYNI gövdeyle tekrarlayın — iş kaldığı yerden sürer (TB-31)." : ''}` };
185
+ return { ...payload, note: `İş düştü; \`error\` alanı nedeni söyler.${isImport ? ' Yazılmış partiler yerinde kalır; bugün geri alınamaz.' : ''}` };
189
186
  }
190
187
  if (status === 'cancelled') {
191
188
  return { ...payload, note: `İş iptal edildi.${isImport ? ' Yazılmış partiler yerinde kalır; bugün geri alınamaz.' : ''}` };
@@ -194,7 +191,7 @@ export function registerImportTools(server, platform) {
194
191
  }));
195
192
  server.registerTool('import_history', {
196
193
  title: 'Veri işleri geçmişi',
197
- description: "Projedeki içe/dışa aktarma, geri alma, alan koruması (protection-*) ve türetilmiş alan doldurma (derived-fill) işlerini sayfalı listeler; order verilmezse en yeni iş önce gelir. Her satır kind, status, entityIds ve result taşır. kind: 'import' çalıştırılmamış planları (planned) da içerir; datasource filtresi yoktur. Geri alınabilir bir iş aramak (kind: 'import', status: 'completed', undoAvailableUntil geçmemiş) ya da düşen bir işin nedenini bulmak için kullanılır.",
194
+ description: "Projedeki içe/dışa aktarma ve geri alma işlerini sayfalı listeler; order verilmezse en yeni iş önce gelir. Her satır kind, status, entityIds ve result taşır. kind: 'import' çalıştırılmamış planları (planned) da içerir; datasource filtresi yoktur. Geri alınabilir bir iş aramak (kind: 'import', status: 'completed', undoAvailableUntil geçmemiş) ya da düşen bir işin nedenini bulmak için kullanılır.",
198
195
  inputSchema: {
199
196
  project: projectParam,
200
197
  environment: environmentParam,