@appaflytech/zeyrek-ai-mcp 0.0.23 → 0.0.25

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 (61) hide show
  1. package/dist/config.js +0 -2
  2. package/dist/knowledge/componentCatalog.js +24 -12
  3. package/dist/knowledge/componentEvents.js +6 -13
  4. package/dist/knowledge/normalize.js +11 -52
  5. package/dist/knowledge/rules.js +12 -56
  6. package/dist/knowledge/styleResolve.js +1 -1
  7. package/dist/knowledge/themeResolve.js +3 -3
  8. package/dist/platform/domSummary.js +1 -1
  9. package/dist/platform/{capture/capture.js → screenshot.js} +509 -23
  10. package/dist/resources/examples/workflow-http-step.json +2 -2
  11. package/dist/resources/guides/component.md +1 -6
  12. package/dist/resources/guides/expressions.md +1 -1
  13. package/dist/resources/guides/functions.md +1 -1
  14. package/dist/resources/guides/layout.md +7 -11
  15. package/dist/resources/guides/microservice.md +2 -1
  16. package/dist/resources/guides/page.md +16 -69
  17. package/dist/resources/guides/translation.md +1 -1
  18. package/dist/resources/guides/workflow.md +6 -4
  19. package/dist/resources/schema-fingerprint.json +2 -2
  20. package/dist/resources/schemas/CreateWorkflowCommand.json +3 -0
  21. package/dist/resources/schemas/PreviewWorkflowCommand.json +3 -0
  22. package/dist/resources/schemas/StepDto.json +12 -9
  23. package/dist/resources/schemas/UpdateWorkflowCommand.json +3 -0
  24. package/dist/server.js +0 -2
  25. package/dist/tools/applications.js +3 -60
  26. package/dist/tools/components.js +10 -50
  27. package/dist/tools/designSchemaPatch.js +4 -13
  28. package/dist/tools/externalComponents.js +4 -25
  29. package/dist/tools/flows.js +2 -9
  30. package/dist/tools/layouts.js +9 -41
  31. package/dist/tools/pages.js +35 -115
  32. package/dist/tools/platformInfo.js +1 -2
  33. package/dist/tools/screenWrite.js +2 -2
  34. package/dist/tools/screens.js +3 -9
  35. package/dist/tools/workflows.js +1 -1
  36. package/package.json +1 -1
  37. package/dist/knowledge/mobileComponentCatalog.js +0 -628
  38. package/dist/knowledge/mobileComponentEvents.js +0 -110
  39. package/dist/knowledge/platform/lint.js +0 -205
  40. package/dist/knowledge/platform/mobile.js +0 -78
  41. package/dist/knowledge/platform/mobileRules.js +0 -126
  42. package/dist/knowledge/platform/mobileTabs.js +0 -108
  43. package/dist/knowledge/platform/profile.js +0 -20
  44. package/dist/knowledge/platform/resolve.js +0 -122
  45. package/dist/knowledge/platform/web.js +0 -38
  46. package/dist/knowledge/styleResolveNative.js +0 -410
  47. package/dist/platform/capture/actions.js +0 -333
  48. package/dist/platform/capture/browser.js +0 -1
  49. package/dist/platform/capture/index.js +0 -10
  50. package/dist/platform/capture/readiness.js +0 -103
  51. package/dist/platform/capture/summary.js +0 -77
  52. package/dist/platform/capture/target.js +0 -5
  53. package/dist/platform/capture/targets/studio-mobile.js +0 -15
  54. package/dist/platform/capture/targets/studio-web.js +0 -5
  55. package/dist/resources/examples/mobile-app-shell-drawer.json +0 -209
  56. package/dist/resources/examples/mobile-app-shell-stack.json +0 -123
  57. package/dist/resources/examples/mobile-app-shell-tab.json +0 -174
  58. package/dist/resources/examples/mobile-list-detail-form.json +0 -656
  59. package/dist/resources/guides/mobile.md +0 -283
  60. package/dist/tools/mobile.js +0 -203
  61. package/dist/tools/profileWrite.js +0 -45
@@ -10,8 +10,7 @@ import { emptyWriteDiff, schemaOpDrops, unwrapProps, withWriteDiff, writeDiff }
10
10
  import { PlatformApiError } from '../platform/errors.js';
11
11
  import { existingMatch, ifExistsParam, listAll, withOutcome } from '../platform/ifExists.js';
12
12
  import { handle, toolResult, toolError } from '../platform/responses.js';
13
- import { StudioScreenshotter } from '../platform/capture/index.js';
14
- import { captureTargetFor } from '../platform/capture/target.js';
13
+ import { StudioScreenshotter } from '../platform/screenshot.js';
15
14
  import { diffSummaries, summaryLines, summaryStats } from '../platform/domSummary.js';
16
15
  import { captureKey, imageHash, sharedCaptureMemory } from '../platform/screenshotMemory.js';
17
16
  import { summarizeLayout } from '../knowledge/layoutSummary.js';
@@ -23,9 +22,6 @@ import { dirname, resolve } from 'node:path';
23
22
  import { setPropTypeErrors } from '../knowledge/propTypes.js';
24
23
  import { designSnapshotInput } from '../knowledge/designSnapshot.js';
25
24
  import { discoverPage } from '../knowledge/pageDiscover.js';
26
- import { applicationTypeField, resolveProfile, resolveProfileBySlug } from '../knowledge/platform/resolve.js';
27
- import { resolveThemeNative } from '../knowledge/styleResolveNative.js';
28
- import { boundFlowSteps, screenProfileWarnings } from './profileWrite.js';
29
25
  import { z } from 'zod';
30
26
  /**
31
27
  * Runtime paketindeki `appFunctions`/`pageFunctions` (UiFunctionRuntimeDto: id, name, parameters,
@@ -109,7 +105,6 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
109
105
  annotations: readOnly
110
106
  }, handle(config, async ({ project, environment, applicationId, pageId }) => {
111
107
  const page = await fetchPage(platform, project, environment, applicationId, pageId);
112
- const resolved = await resolveProfile(platform, applicationId);
113
108
  const layout = (page.layout ?? {});
114
109
  return {
115
110
  id: page.id,
@@ -128,8 +123,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
128
123
  flows: (Array.isArray(page.flows) ? page.flows : [])
129
124
  .map(flow => ({ id: flow.id, name: flow.name, slug: flow.slug })),
130
125
  schemaNodes: countSchemaNodes(page.schema),
131
- updatedAt: page.audit?.updatedAt ?? page.audit?.createdAt,
132
- ...applicationTypeField(resolved)
126
+ updatedAt: page.audit?.updatedAt ?? page.audit?.createdAt
133
127
  };
134
128
  }));
135
129
  server.registerTool('page_runtime_get', {
@@ -177,17 +171,11 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
177
171
  const styleSource = resolveStyles ? (theme ?? null) : undefined;
178
172
  const asNodes = (value) => (Array.isArray(value) ? value : []);
179
173
  const named = (value) => (Array.isArray(value) ? value : []).map(entry => ({ id: entry.id, name: entry.name, slug: entry.slug }));
180
- const runtimeApplication = (body.application ?? {});
181
- // Mobil uygulama React Native stiliyle çizilir (G4): rapor CSS kaskadı değil `shell`/`text`.
182
- const nativeTheme = resolveStyles && runtimeApplication.type === 'mobile' ? resolveThemeNative((theme ?? undefined)) : undefined;
183
- const nodeStyleSource = nativeTheme ? undefined : styleSource;
184
174
  return {
185
175
  page: { id: body.id, name: body.name, slug: body.slug, browserTitle: body.browserTitle, browserTitleKey: body.browserTitleKey, isHomepage: body.isHomepage },
186
- ...(typeof runtimeApplication.type === 'string' ? { applicationType: runtimeApplication.type } : {}),
187
176
  events: body.events ?? [],
188
- layout: layout ? { id: layout.id, name: layout.name, views: asNodes(layout.views).map(node => summarize(node, nodeStyleSource, nativeTheme)) } : null,
189
- schema: asNodes(body.schema).map(node => summarize(node, nodeStyleSource, nativeTheme)),
190
- ...(nativeTheme ? { styleResolver: 'native' } : {}),
177
+ layout: layout ? { id: layout.id, name: layout.name, views: asNodes(layout.views).map(node => summarize(node, styleSource)) } : null,
178
+ schema: asNodes(body.schema).map(node => summarize(node, styleSource)),
191
179
  widgets: named(body.widgets),
192
180
  flows: named(body.flows),
193
181
  variableKeys: Object.keys((body.variables ?? {})),
@@ -206,11 +194,9 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
206
194
  }
207
195
  }
208
196
  : {}),
209
- note: nativeTheme
210
- ? "Mobil uygulama: nativeStyle, mobil çizerin düğüme verdiği React Native stilidir — shell kutunun, text içine akan metnin stili (RN'de tipografi miras alınmaz); warnings mobilde çizilmeyen değerlerdir (MOB-002). Tema componentStyles/preset katmanı mobil çizerde henüz uygulanmıyor, bu yüzden rapora girmez."
211
- : resolveStyles
212
- ? "schema, layout'taki slot'un İÇİNE yerleşerek çizilir (Kural 1f). resolvedStyle = componentStyles → preset → düğüm stili kaskadı (aibox'ta tipli grupların derlemesi TABAN katmandır); styleLayers hangi katmanların konuştuğunu söyler — styleLayers.componentPreset ise CSS DEĞİL, düğümün hangi bileşen preseti versiyonundan kurulduğunun işaretidir."
213
- : "schema, layout'taki slot'un İÇİNE yerleşerek çizilir (Kural 1f); tam gövde gerekirse view:'full'. Bir düğümün ekranda GERÇEKTEN aldığı stili görmek için resolveStyles:true."
197
+ note: resolveStyles
198
+ ? "schema, layout'taki slot'un İÇİNE yerleşerek çizilir (Kural 1f). resolvedStyle = componentStyles → preset → düğüm stili kaskadı (aibox'ta tipli grupların derlemesi TABAN katmandır); styleLayers hangi katmanların konuştuğunu söyler — styleLayers.componentPreset ise CSS DEĞİL, düğümün hangi bileşen preseti versiyonundan kurulduğunun işaretidir."
199
+ : "schema, layout'taki slot'un İÇİNE yerleşerek çizilir (Kural 1f); tam gövde gerekirse view:'full'. Bir düğümün ekranda GERÇEKTEN aldığı stili görmek için resolveStyles:true."
214
200
  };
215
201
  }));
216
202
  const screenshotter = injectedScreenshotter ?? new StudioScreenshotter(config);
@@ -227,15 +213,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
227
213
  viewport: z.object({
228
214
  width: z.number().int().min(320).max(3840),
229
215
  height: z.number().int().min(240).max(2160)
230
- }).optional().describe('Varsayılan 1280x800 (deviceScaleFactor 1); mobil uygulamada varsayılan device. Verilirse device yok sayılır'),
231
- device: z.union([
232
- z.enum(['phone', 'tablet']),
233
- z.object({
234
- width: z.number().int().min(320).max(3840),
235
- height: z.number().int().min(240).max(2160),
236
- scale: z.number().min(1).max(3).optional()
237
- })
238
- ]).optional().describe("Yalnız MOBİL uygulama: cihaz ön ayarı — 'phone' 390x844 @2x (varsayılan), 'tablet' 820x1180 @2x, ya da { width, height, scale? }. Kare cihaz piksel yoğunluğunda çıkar (phone → 780x1688 px); raster küçültme için scale parametresi bununla çarpılır. Web uygulamasında reddedilir: dar ekran için viewport verin."),
216
+ }).optional().describe('Varsayılan 1280x800 (deviceScaleFactor 1)'),
239
217
  fullPage: z.boolean().optional().describe('true: kaydırılan kısım dahil tüm sayfa; varsayılan yalnız viewport karesi'),
240
218
  delayMs: z.number().int().min(0).max(60000).optional().describe("Hazırlık bütçesine EK süre (ms). Varsayılan bütçe 15 sn'dir ve kare sayfa hazır olur olmaz alınır (akışsız giriş ekranı ~1 sn, dashboard mount akışları bitince) — normalde vermeye gerek yok. Yalnız sayfa gerçekten uzun sürüyorsa (soğuk Vite derlemesi, ağır mount akışı) büyütün: bütçe dolduğunda sayfa hâlâ hazır değilse çağrı hatayla döner, kare alınmaz. Sayfanın AÇILMASI için beklenen 20 sn'lik navigasyon süresi de bu kadar uzar — soğuk Studio'da tek düğme budur (09-08 S-8)."),
241
219
  captureUnready: z.boolean().optional().describe("true: TEŞHİS kipi — bütçe dolduğunda sayfa hazır olmasa da kare alınır ve yanıt pageState: 'not-ready' taşır (iskelet/yarım kare görülebilir). Varsayılan false: yüklenmemiş sayfa çekilmez, hata döner."),
@@ -251,7 +229,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
251
229
  value: z.unknown().optional().describe("'set' için yazılacak değer. Tarih kutularına ISO yazın ('2026-08-01'); çok alanlı tarih aralığında kök DEĞİL kutu hedeflenir: '<elementId>__start' / '<elementId>__end'. 'tab' için sekmenin ANAHTARI ('iot') ya da görünen metni; 'select' için seçeneğin value'su ya da görünen metni"),
252
230
  ms: z.number().int().min(0).max(15000).optional().describe("'wait' için bekleme süresi")
253
231
  })).max(20).optional().describe("Kare ALINMADAN ÖNCE sayfada koşturulacak etkileşim adımları: [{action:'set', target:'flt_month', value:'2022-10'}, {action:'click', target:'btn_sign_in'}, {action:'tab', target:'tabs_settings', value:'iot'}, {action:'select', target:'dd_city', value:'34'}, {action:'submit', target:'frm_note'}, {action:'drag', target:'kb_board__card-42', to:'kb_board__col-Assigned'}]. 'tab' SEKME SEÇER: sekme grubunun köküne 'click' göndermek DOM sırasındaki İLK sekmeye gider ve ikinci sekme hiç açılamıyordu — tablist köküne click artık reddedilir ve bu fiile yönlendirir. Eşleme önce '<elementId>__tab-<sekme anahtarı>' kimliğiyle, o yoksa görünen metinle yapılır; actionsReport.matchedBy hangisi olduğunu, actionsReport.activeTab adımdan SONRA hangi sekmenin açık olduğunu söyler. Etkin olmayan sekmenin içeriği DOM'da YOKTUR: o sekmedeki bir düğüme yazmadan önce 'tab' adımı gerekir. 'select' açılır kutudan seçer — kutu native alan değildir, değeri yazmak hiçbir şey yapmaz, seçeneğe tıklanması gerekir; liste 3 sn'ye kadar YOKLANIR (sorgudan beslenen kutuda seçenekler geç basılır) ve actionsReport.optionsSeen + waitedMs neyin görüldüğünü söyler. 'submit' formu gönder butonu OLMADAN gönderir (form.requestSubmit); actionsReport.submitVia hangi yolun kullanıldığını yazar. 'drag' HTML5 sürükle-bırak olaylarını (dragstart→dragover→drop→dragend) hedefin merkezinde atar; kanban cardMove ve takvim eventMove bununla tetiklenir. 'set' native setter kullanır ve input+change olaylarını bubbles ile atar (düz DOM ataması framework'ün duyduğu olayı üretmez); ardından kök düğümün runtime prop'larını yeniden okur: actionsReport.propWritten değerin prop'a ULAŞIP ulaşmadığıdır ve false ise applied da false döner — DOM'a yazılmış ama bileşenin duymadığı değer 'uygulandı' sayılmaz (G-14). Her adımdan sonra yerleşme beklenir ve yanıttaki actionsReport hedefin bulunup bulunmadığını ve adımdan sonra KAÇ AĞ İSTEĞİ çıktığını söyler — 'bağ kuruldu' ile 'çalışıyor' arasındaki farkı ancak bu ayırır (G-24)."),
254
- language: z.string().min(1).optional().describe("Kareyi BU DİLDE çeker: adrese '?lang=<kod>' eklenir ve runtime dili oradan seçer (öncelik: ?lang → tarayıcıda kayıtlı seçim → tarayıcı dilleri → projenin varsayılanı). Seçim hem çeviriye bağlı prop'ları hem çok dilli alanların satır değerlerini kapsar, yani ikinci dilin karesi için sayfaya dil değiştirici KOYMAK GEREKMEZ — referans tasarımı bozulmadan ikinci dil kanıtlanır. ISO 639-1 iki harfli kod ('tr', 'en'); bölgeli kod ('tr-TR') indirgenir ve indirgeme yanıtta bildirilir. Kod projenin languages listesinde yoksa çağrı REDDEDİLİR: runtime tanımadığı kodu yok sayıp kareyi varsayılan dilde çizerdi ve 'çevrildi' sanılan yanlış bir kare raporlanırdı. MOBİL uygulamada da geçerlidir (/preview aynı ?lang'i okur); cihazın kendisinde ?lang yoktur (platform_guide('mobile') §Çok dil)."),
232
+ language: z.string().min(1).optional().describe("Kareyi BU DİLDE çeker: adrese '?lang=<kod>' eklenir ve runtime dili oradan seçer (öncelik: ?lang → tarayıcıda kayıtlı seçim → tarayıcı dilleri → projenin varsayılanı). Seçim hem çeviriye bağlı prop'ları hem çok dilli alanların satır değerlerini kapsar, yani ikinci dilin karesi için sayfaya dil değiştirici KOYMAK GEREKMEZ — referans tasarımı bozulmadan ikinci dil kanıtlanır. ISO 639-1 iki harfli kod ('tr', 'en'); bölgeli kod ('tr-TR') indirgenir ve indirgeme yanıtta bildirilir. Kod projenin languages listesinde yoksa çağrı REDDEDİLİR: runtime tanımadığı kodu yok sayıp kareyi varsayılan dilde çizerdi ve 'çevrildi' sanılan yanlış bir kare raporlanırdı."),
255
233
  colorScheme: z.enum(['light', 'dark']).optional().describe("Kareyi açık ya da koyu temada çeker. Ziyaretçi tema tercihi çerezde değil localStorage'da yaşar ve tema store'u onu sayfa açılırken bir kez okur; gateway tercihi sayfa script'lerinden ÖNCE eker, bu yüzden sayfada 'theme-toggle' komponenti OLMASA DA koyu tema karesi alınabilir. Verilmezse projenin kendi modu çizilir."),
256
234
  format: z.enum(['png', 'jpeg']).optional().describe("Kare biçimi; varsayılan 'png'. Doğrulama karesi için 'jpeg' + quality 60 bağlamı küçültür (ölçüldü 2026-09-16, aynı sayfa: scale 1'de png 8639 B / jpeg60 8691 B — kazanç yok; scale 0.5'te png 3603 B / jpeg60 3035 B). Asıl kaldıraç ÖLÇEKTİR; renk ve kenar keskinliğinin kendisi inceleniyorsa png'de kalın."),
257
235
  quality: z.number().int().min(1).max(100).optional().describe("Yalnız format:'jpeg' ile: 1-100, doğrulama için 60 yeter. format 'png' iken verilirse çağrı reddedilir — PNG kayıpsızdır, kalite ayarı yoktur."),
@@ -266,7 +244,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
266
244
  outPath: z.string().min(1).optional().describe('Verilirse PNG bu yerel yola yazılır ve inline görüntü DÖNMEZ; yalnız özet (yol, boyut) döner — büyük fullPage kareleri için')
267
245
  },
268
246
  annotations: readOnly
269
- }, async ({ project, environment, applicationSlug, pageSlug, viewport, device, fullPage, delayMs, captureUnready, anonymous, asUser, cookies, layoutReport, actions, outPath, expectFailure, language, colorScheme, summary, image, format, quality, scale, clip, diff }) => {
247
+ }, async ({ project, environment, applicationSlug, pageSlug, viewport, fullPage, delayMs, captureUnready, anonymous, asUser, cookies, layoutReport, actions, outPath, expectFailure, language, colorScheme, summary, image, format, quality, scale, clip, diff }) => {
270
248
  try {
271
249
  if (anonymous === true && (asUser !== undefined || cookies !== undefined)) {
272
250
  throw new PlatformApiError("page_screenshot: anonymous:true ile asUser/cookies birlikte verilemez — biri kimliksiz kareyi, diğeri belirli bir kimlikle çekilen kareyi ister. Anonim kare için yalnız anonymous:true, üye kimliğiyle kare için yalnız asUser (ve gerekiyorsa cookies) gönderin.");
@@ -310,24 +288,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
310
288
  }
311
289
  }
312
290
  const url = `${config.studioBaseUrl}/${lane}/${projectSlug}/${applicationSlug}/${pageSlug}${languageChoice ? `?lang=${languageChoice.code}` : ''}`;
313
- // Hedef ve cihaz uygulamanın platform profilinden (G3): mobil uygulama react-native-web
314
- // çizimidir, varsayılan kare telefon ön ayarıdır. Tip okunamazsa web davranışı aynen.
315
- const resolved = await resolveProfileBySlug(platform, projectSlug, applicationSlug);
316
- const target = captureTargetFor(resolved.profile.capture.target);
317
- const mobile = resolved.profile.platform === 'mobile';
318
- if (device !== undefined && !mobile) {
319
- throw new PlatformApiError(`page_screenshot: device yalnız MOBİL uygulamada geçerlidir — '${applicationSlug}' ${resolved.known ? 'bir web uygulaması' : 'uygulamasının tipi okunamadı (web varsayıldı)'}. Web'in dar ekran kırılımını görmek için viewport verin (ör. { width: 390, height: 844 }).`);
320
- }
321
- const deviceName = typeof device === 'string' ? device : device === undefined && mobile ? resolved.profile.capture.defaultDevice : undefined;
322
- const preset = typeof device === 'object'
323
- ? { width: device.width, height: device.height, dpr: device.scale ?? 1 }
324
- : deviceName === undefined ? undefined : resolved.profile.capture.devices[deviceName];
325
- const appliedDevice = viewport === undefined && preset !== undefined ? preset : undefined;
326
- const deviceNote = viewport !== undefined && device !== undefined
327
- ? 'viewport verildiği için device yok sayıldı: kare verilen viewport ve deviceScaleFactor 1 ile çekildi.'
328
- : undefined;
329
- const size = viewport ?? (appliedDevice ? { width: appliedDevice.width, height: appliedDevice.height } : { width: 1280, height: 800 });
330
- const dpr = appliedDevice && appliedDevice.dpr !== 1 ? appliedDevice.dpr : undefined;
291
+ const size = viewport ?? { width: 1280, height: 800 };
331
292
  const extraCookies = Object.entries(cookies ?? {}).map(([name, value]) => ({ name, value }));
332
293
  const identity = anonymous === true ? 'anonymous' : asUser === undefined ? 'gateway' : 'asUser';
333
294
  const identityToken = anonymous ? undefined : resolveIdentity(asUser) ?? await platform.accessToken();
@@ -352,9 +313,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
352
313
  ...(quality === undefined ? {} : { quality }),
353
314
  ...(scale === undefined ? {} : { scale }),
354
315
  ...(clip === undefined ? {} : { clip: clip }),
355
- ...(actions === undefined ? {} : { actions: actions }),
356
- ...(mobile ? { target } : {}),
357
- ...(dpr === undefined ? {} : { dpr })
316
+ ...(actions === undefined ? {} : { actions: actions })
358
317
  });
359
318
  // Fark ÖZETTEN çıkar; `summary:false` verilse de fark için toplanmıştır (yanıta girmez).
360
319
  // Anahtar KİMLİĞİ ayırır (K8): 'asUser' etiketi yetmez — iki farklı üyenin jetonu aynı
@@ -425,11 +384,6 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
425
384
  ...(languageChoice?.note ? { languageNote: languageChoice.note } : {}),
426
385
  ...(colorScheme === undefined ? {} : { colorScheme }),
427
386
  viewport: size,
428
- ...(appliedDevice === undefined ? {} : { device: typeof device === 'object' ? { ...device } : deviceName, deviceScaleFactor: appliedDevice.dpr }),
429
- ...(deviceNote === undefined ? {} : { deviceNote }),
430
- // Web karesinin yanıtı profil öncesiyle aynı kalır (G3 kısıtı); alan yalnız mobilde.
431
- ...(mobile ? applicationTypeField(resolved) : {}),
432
- ...(target.platformNote === undefined ? {} : { platformNote: target.platformNote }),
433
387
  fullPage: fullPage === true,
434
388
  identity,
435
389
  cookieNames,
@@ -581,20 +535,19 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
581
535
  annotations: readOnly
582
536
  }, handle(config, async ({ project, environment, applicationId, pageId, mode, componentId }) => {
583
537
  const page = await fetchPage(platform, project, environment, applicationId, pageId);
584
- const typeField = applicationTypeField(await resolveProfile(platform, applicationId));
585
538
  const updatedAt = page.audit?.updatedAt ?? page.audit?.createdAt;
586
539
  const version = page.version;
587
540
  if (mode === 'full')
588
- return { version, updatedAt, ...typeField, schema: page.schema ?? [] };
541
+ return { version, updatedAt, schema: page.schema ?? [] };
589
542
  if (mode === 'subtree') {
590
543
  if (!componentId)
591
544
  throw new PlatformApiError("mode='subtree' için componentId zorunludur.");
592
545
  const subtree = findNode(page.schema, componentId);
593
546
  if (!subtree)
594
547
  throw new PlatformApiError(`Sayfada '${componentId}' id'li bir komponent yok; page_schema_get'i summary kipinde çağırıp hedefi doğrulayın.`);
595
- return { version, updatedAt, ...typeField, schema: subtree };
548
+ return { version, updatedAt, schema: subtree };
596
549
  }
597
- return { version, updatedAt, ...typeField, schema: (page.schema ?? []).map(node => summarize(node)) };
550
+ return { version, updatedAt, schema: (page.schema ?? []).map(node => summarize(node)) };
598
551
  }));
599
552
  server.registerTool('page_state', {
600
553
  title: 'Sayfa durumunu getir',
@@ -620,20 +573,15 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
620
573
  ...schemaOpValidationErrors(opRecords).map(issue => `PAGE-016 — ${issue}`),
621
574
  ...codePropTemplateErrors(opRecords).map(issue => `PAGE-032 — ${issue}`)
622
575
  ];
623
- const resolved = await resolveProfile(platform, applicationId);
624
- const ordering = resolved.profile.layout.orderBy === 'block-position'
625
- ? await orderByIndex(opRecords, () => fetchPage(platform, project, environment, applicationId, pageId))
626
- : { ops: opRecords, moved: [], warnings: [] };
627
- const profileWarnings = await screenProfileWarnings(platform, resolved, project, environment, applicationId, { kind: 'page', ops: opRecords });
576
+ const ordering = await orderByIndex(opRecords, () => fetchPage(platform, project, environment, applicationId, pageId));
628
577
  const response = ((await platform.tenant('POST', project, `/pages/${applicationId}/${pageId}/schema/validate`, {
629
578
  environment,
630
579
  body: { ops: [...allOps.filter(entry => entry.op === 'resize_component').flatMap(resizeServerOps), ...ordering.ops] }
631
580
  })) ?? {});
632
581
  if (validationIssues.length > 0)
633
582
  response.validationWarnings = validationIssues;
634
- if (ordering.warnings.length > 0 || profileWarnings.length > 0)
635
- response.layoutWarnings = [...ordering.warnings, ...profileWarnings];
636
- Object.assign(response, applicationTypeField(resolved));
583
+ if (ordering.warnings.length > 0)
584
+ response.layoutWarnings = ordering.warnings;
637
585
  return withNormalization(response, [
638
586
  ...componentDefaultsNote(normalized.components),
639
587
  ...validationNote(normalized.validations),
@@ -721,12 +669,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
721
669
  retargeted = retargetRootAdds(opRecords, PAGE_CONTAINER_ELEMENT_ID);
722
670
  }
723
671
  }
724
- const resolved = await resolveProfile(platform, applicationId);
725
- const blocksMeaningful = resolved.profile.layout.blocksMeaningful;
726
- // Mobil (dizi sırası): index platformun kendi add/move index'idir, konum çevirisi yapılmaz.
727
- const ordering = resolved.profile.layout.orderBy === 'block-position'
728
- ? await orderByIndex(opRecords, readPage)
729
- : { ops: opRecords, moved: [], warnings: [] };
672
+ const ordering = await orderByIndex(opRecords, readPage);
730
673
  const sentOps = ordering.ops;
731
674
  // Akış silen op'lar yamadan ÖNCE hesaplanır: uyarı sonradan geldiğinde akış zaten kalıcı
732
675
  // silinmiş oluyordu ve "önce yedekle" tavsiyesi uygulanamıyordu (09-05 koşusu, G-21).
@@ -786,10 +729,10 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
786
729
  // görünür, iç içeliği ancak hedef parent zinciri belli olunca anlarsın.
787
730
  nestedAfterOps = nestedRepeaterNodes(simulated);
788
731
  layoutWarnings = [
789
- ...(blocksMeaningful ? pageContainerPositionWarning(page.schema) : []),
790
- ...(blocksMeaningful ? verticalGapWarnings(simulated, 'PAGE-010 (uyarı)', touched) : []),
732
+ ...pageContainerPositionWarning(page.schema),
733
+ ...verticalGapWarnings(simulated, 'PAGE-010 (uyarı)', touched),
791
734
  ...stringStyleWarning(stringStyleNodes(simulated)),
792
- ...(resolved.profile.layout.modes.has('grid') ? inertFlexPropWarning(inertFlexPropNodes(simulated)) : []),
735
+ ...inertFlexPropWarning(inertFlexPropNodes(simulated)),
793
736
  ...flexSizeWarnings(simulated, 'PAGE-017 (uyarı)', 'PAGE-018 (uyarı)'),
794
737
  ...spacingLayerWarnings(simulated, 'PAGE-029 (uyarı)', 'PAGE-030 (uyarı)')
795
738
  ];
@@ -804,12 +747,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
804
747
  const resized = resizeOps.length > 0 ? planResizes((await readPage()).schema ?? [], resizeOps) : { serverOps: [], applied: [], warnings: [] };
805
748
  const propTypes = propTypeOps.length > 0 ? planPropTypes((await readPage()).schema ?? [], propTypeOps) : { serverOps: [], applied: [] };
806
749
  const serverOps = [...removeEventOps, ...resized.serverOps, ...propTypes.serverOps, ...sentOps];
807
- const profileWarnings = await screenProfileWarnings(platform, resolved, project, environment, applicationId, {
808
- kind: 'page',
809
- ops: [...opRecords, ...propTypeOps],
810
- steps: await boundFlowSteps(platform, resolved, project, environment, 'page', applicationId, pageId, opRecords)
811
- });
812
- layoutWarnings = [...ordering.warnings, ...layoutWarnings, ...profileWarnings];
750
+ layoutWarnings = [...ordering.warnings, ...layoutWarnings];
813
751
  // Tek istek, tek sürüm: öykünülen op'lar 2026-09-14'e kadar ayrı GET + tam PUT çiftleriydi ve
814
752
  // yamadan ÖNCE yazılıyordu — PATCH reddedilse bile kalıcıydılar. Artık hepsi aynı atomik PATCH'te.
815
753
  // baseVersion yalnız biliniyorsa gider (ajanın verdiği ya da bu çağrıda zaten okunan sayfanınki):
@@ -863,7 +801,6 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
863
801
  opDrops = emptyWriteDiff();
864
802
  }
865
803
  }
866
- Object.assign(response, applicationTypeField(resolved));
867
804
  return withWriteDiff(withNormalization(response, [
868
805
  ...rootAddsNote(retargeted, PAGE_CONTAINER_ELEMENT_ID),
869
806
  ...componentDefaultsNote(normalized.components),
@@ -908,21 +845,16 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
908
845
  },
909
846
  annotations: writes
910
847
  }, handle(config, async ({ project, environment, applicationId, name, slug, browserTitle, browserTitleKey, layoutId, roleIds, middlewareIds, events, schema, view, ifExists }) => {
911
- const resolved = await resolveProfile(platform, applicationId);
912
- const blocksMeaningful = resolved.profile.layout.blocksMeaningful;
913
- const container = ensurePageContainer(schema ?? [], resolved.profile.layout.rootContainer);
848
+ const container = ensurePageContainer(schema ?? []);
914
849
  assertScreenWriteGuards('page', { schema: container.schema, events });
915
850
  const stringStyles = stringStyleNodes(container.schema);
916
851
  const fixed = normalizeComponentDefaults(container.schema);
917
- // Mobil çizer blokları okumaz (D3): kök konumu sıfırlama, blok sıralama ve dikey boşluk
918
- // uyarısı yalnız ızgaranın anlamlı olduğu profilde koşar.
919
- const reset = blocksMeaningful ? resetPageContainerPosition(container.schema) : [];
852
+ const reset = resetPageContainerPosition(container.schema);
920
853
  const catalogNotes = (schema ?? []).length > 0
921
854
  ? await screenCatalogNotes(platform, project, environment, applicationId, container.schema)
922
855
  : [];
923
- const moved = blocksMeaningful ? reorderSchemaBlocks(container.schema) : [];
924
- const gaps = (schema ?? []).length > 0 && blocksMeaningful ? verticalGapWarnings(container.schema, 'PAGE-010 (uyarı)') : [];
925
- const profileWarnings = await screenProfileWarnings(platform, resolved, project, environment, applicationId, { kind: 'page', nodes: container.schema });
856
+ const moved = reorderSchemaBlocks(container.schema);
857
+ const gaps = (schema ?? []).length > 0 ? verticalGapWarnings(container.schema, 'PAGE-010 (uyarı)') : [];
926
858
  const existing = await existingMatch({
927
859
  code: 'PAGE-035',
928
860
  noun: 'sayfa',
@@ -950,13 +882,12 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
950
882
  await platform.tenant('PUT', project, `/pages/${applicationId}/${pageId}`, { environment, body });
951
883
  const updateWarnings = schema === undefined
952
884
  ? []
953
- : [...gaps, ...stringStyleWarning(stringStyles), ...(resolved.profile.layout.modes.has('grid') ? inertFlexPropWarning(inertFlexPropNodes(container.schema)) : []), ...flexSizeWarnings(container.schema, 'PAGE-017 (uyarı)', 'PAGE-018 (uyarı)'), ...spacingLayerWarnings(container.schema, 'PAGE-029 (uyarı)', 'PAGE-030 (uyarı)'), ...profileWarnings];
885
+ : [...gaps, ...stringStyleWarning(stringStyles), ...inertFlexPropWarning(inertFlexPropNodes(container.schema)), ...flexSizeWarnings(container.schema, 'PAGE-017 (uyarı)', 'PAGE-018 (uyarı)'), ...spacingLayerWarnings(container.schema, 'PAGE-029 (uyarı)', 'PAGE-030 (uyarı)')];
954
886
  const summary = {
955
887
  id: pageId,
956
888
  outcome: 'updated',
957
889
  changed,
958
- preserved: { schemaNodes: countSchemaNodes(body.schema), events: body.events.length },
959
- ...applicationTypeField(resolved)
890
+ preserved: { schemaNodes: countSchemaNodes(body.schema), events: body.events.length }
960
891
  };
961
892
  if (updateWarnings.length > 0)
962
893
  summary.layoutWarnings = updateWarnings;
@@ -989,13 +920,10 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
989
920
  saved.schema = saved.schema.map(node => summarize(node));
990
921
  }
991
922
  const normalized = withWriteDiff(withNormalization(withOutcome(response, undefined), [...container.fixes, ...reset, ...componentDefaultsNote(fixed), ...catalogNotes, ...reorderNote(moved)]), drops);
992
- const createWarnings = [...gaps, ...stringStyleWarning(stringStyles), ...(resolved.profile.layout.modes.has('grid') ? inertFlexPropWarning(inertFlexPropNodes(container.schema)) : []), ...flexSizeWarnings(container.schema, 'PAGE-017 (uyarı)', 'PAGE-018 (uyarı)'), ...spacingLayerWarnings(container.schema, 'PAGE-029 (uyarı)', 'PAGE-030 (uyarı)'), ...profileWarnings];
993
- const typeField = applicationTypeField(resolved);
994
- if (!normalized || typeof normalized !== 'object')
923
+ const createWarnings = [...gaps, ...stringStyleWarning(stringStyles), ...inertFlexPropWarning(inertFlexPropNodes(container.schema)), ...flexSizeWarnings(container.schema, 'PAGE-017 (uyarı)', 'PAGE-018 (uyarı)'), ...spacingLayerWarnings(container.schema, 'PAGE-029 (uyarı)', 'PAGE-030 (uyarı)')];
924
+ if (createWarnings.length === 0 || !normalized || typeof normalized !== 'object')
995
925
  return normalized;
996
- if (createWarnings.length === 0)
997
- return Object.keys(typeField).length === 0 ? normalized : { ...normalized, ...typeField };
998
- return { ...normalized, ...typeField, layoutWarnings: createWarnings };
926
+ return { ...normalized, layoutWarnings: createWarnings };
999
927
  }));
1000
928
  server.registerTool('page_update', {
1001
929
  title: 'Sayfa üstbilgisini güncelle',
@@ -1020,21 +948,13 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
1020
948
  const overrides = Object.fromEntries(Object.entries(changes).filter(([, value]) => value !== undefined));
1021
949
  assertScreenWriteGuards('page', { schema: overrides.schema, events: overrides.events });
1022
950
  const current = await fetchHost(platform, 'page', project, environment, applicationId, pageId);
1023
- const resolved = overrides.schema === undefined ? undefined : await resolveProfile(platform, applicationId);
1024
- const blocksMeaningful = resolved?.profile.layout.blocksMeaningful ?? true;
1025
951
  const fixed = normalizeComponentDefaults(overrides.schema);
1026
- const reset = overrides.schema === undefined || !blocksMeaningful ? [] : resetPageContainerPosition(overrides.schema);
952
+ const reset = overrides.schema === undefined ? [] : resetPageContainerPosition(overrides.schema);
1027
953
  const catalogNotes = await screenCatalogNotes(platform, project, environment, applicationId, overrides.schema);
1028
- const moved = overrides.schema === undefined || !blocksMeaningful ? [] : reorderSchemaBlocks(overrides.schema);
954
+ const moved = overrides.schema === undefined ? [] : reorderSchemaBlocks(overrides.schema);
1029
955
  const gaps = overrides.schema === undefined
1030
956
  ? []
1031
- : [
1032
- ...(blocksMeaningful ? verticalGapWarnings(overrides.schema, 'PAGE-010 (uyarı)') : []),
1033
- ...(resolved?.profile.layout.modes.has('grid') ?? true ? inertFlexPropWarning(inertFlexPropNodes(overrides.schema)) : []),
1034
- ...flexSizeWarnings(overrides.schema, 'PAGE-017 (uyarı)', 'PAGE-018 (uyarı)'),
1035
- ...spacingLayerWarnings(overrides.schema, 'PAGE-029 (uyarı)', 'PAGE-030 (uyarı)'),
1036
- ...(resolved ? await screenProfileWarnings(platform, resolved, project, environment, applicationId, { kind: 'page', nodes: overrides.schema }) : [])
1037
- ];
957
+ : [...verticalGapWarnings(overrides.schema, 'PAGE-010 (uyarı)'), ...inertFlexPropWarning(inertFlexPropNodes(overrides.schema)), ...flexSizeWarnings(overrides.schema, 'PAGE-017 (uyarı)', 'PAGE-018 (uyarı)'), ...spacingLayerWarnings(overrides.schema, 'PAGE-029 (uyarı)', 'PAGE-030 (uyarı)')];
1038
958
  const body = pageUpdateBody(current, overrides);
1039
959
  await platform.tenant('PUT', project, `/pages/${applicationId}/${pageId}`, { environment, body });
1040
960
  const summary = {
@@ -64,8 +64,7 @@ const guideRouting = {
64
64
  microfunction: 'kendi runtime\'ında koşan Node/Python fonksiyonu: protokol, yayın döngüsü, step kullanımı',
65
65
  entity: "alan tipleri, ilişkiler, hazır entity'ler",
66
66
  page: 'sayfa/flow işleri; flex düzen prop grubu ve boyut modları (Kural 1f-2)',
67
- layout: 'yerleşim kabuğu: tek slot, views, dar ekranda yığılma, widthType fill/fixed/auto',
68
- mobile: "mobil UYGULAMA (type:'mobile'): kurulum sırası (mobile_app_create), flex-only yerleşim, tipli stil, sekmeler (properties.mobile.tabs) ve çekmece, adım sözlüğü, MOB-* bulguları, page_screenshot device",
67
+ layout: 'yerleşim kabuğu: tek slot, views, mobil yığılma, widthType fill/fixed/auto',
69
68
  component: 'komponent modeli, olay sözleşmeleri, appearance boyut sözlüğü (widthString/heightString)',
70
69
  html: 'hazır komponent yetmediğinde tek seferlik kaçış kapısı (Mustache, fireEvent, script kuralları)',
71
70
  'external-component': 'kalıcı ihtiyaçta kendi komponentini yazıp yayınlama',
@@ -1,4 +1,4 @@
1
- import { invalidScreenEventNames, invalidWidgetTypeNodes, nestedRepeaterNodes, nestedRepeaterMessage, blockSizeNote, heightTypeNote, sizeStringNote, droppableStatesNote } from '../knowledge/normalize.js';
1
+ import { invalidScreenEventNames, invalidWidgetTypeNodes, nestedRepeaterNodes, nestedRepeaterMessage, blockSizeNote, heightTypeNote, sizeStringNote } from '../knowledge/normalize.js';
2
2
  import { FUNCTIONS_NAMESPACE } from '../knowledge/functionGuards.js';
3
3
  import { applyCatalogLayoutRules } from './components.js';
4
4
  import { PlatformApiError } from '../platform/errors.js';
@@ -65,5 +65,5 @@ export async function screenCatalogNotes(platform, project, environment, applica
65
65
  if (!Array.isArray(nodes) || nodes.length === 0)
66
66
  return [];
67
67
  const catalog = await applyCatalogLayoutRules(platform, project, environment, applicationId, nodes);
68
- return [...blockSizeNote(catalog.clamped), ...heightTypeNote(catalog.heights), ...sizeStringNote(catalog.sizes), ...droppableStatesNote(catalog.states)];
68
+ return [...blockSizeNote(catalog.clamped), ...heightTypeNote(catalog.heights), ...sizeStringNote(catalog.sizes)];
69
69
  }
@@ -1,6 +1,5 @@
1
1
  import { PlatformApiError } from '../platform/errors.js';
2
2
  import { resolveNodeStyleReport } from '../knowledge/styleResolve.js';
3
- import { nodeNativeStyle } from '../knowledge/styleResolveNative.js';
4
3
  import { z } from 'zod';
5
4
  export const hostParam = z.enum(['page', 'layout', 'component'])
6
5
  .describe("Akışın barındırıcısı: page | layout | component (widget de component'tir)");
@@ -14,26 +13,21 @@ export const modeParam = z.enum(['summary', 'subtree', 'full']).optional().descr
14
13
  * `styleSource` verilirse (undefined DEĞİLSE) her düğüme efektif stil raporu da
15
14
  * yazılır: tema componentStyles → preset → düğümün kendi stili kaskadı.
16
15
  */
17
- export function summarize(node, styleSource, nativeTheme) {
16
+ export function summarize(node, styleSource) {
18
17
  const summary = {
19
18
  id: node.id,
20
19
  elementId: node.elementId,
21
20
  name: node.name,
22
21
  type: node.type
23
22
  };
24
- // Mobil uygulama: stil CSS değil React Native nesnesidir (`shell` kutu, `text` metin).
25
- if (nativeTheme !== undefined) {
26
- const { shell, text, warnings } = nodeNativeStyle(node, nativeTheme);
27
- summary.nativeStyle = { shell, text, ...(warnings.length > 0 ? { warnings } : {}) };
28
- }
29
- else if (styleSource !== undefined) {
23
+ if (styleSource !== undefined) {
30
24
  const report = resolveNodeStyleReport(node, styleSource ?? undefined);
31
25
  if (report.resolvedStyle !== undefined)
32
26
  summary.resolvedStyle = report.resolvedStyle;
33
27
  summary.styleLayers = report.styleLayers;
34
28
  }
35
29
  if (Array.isArray(node.children) && node.children.length > 0) {
36
- summary.children = node.children.map(child => summarize(child, styleSource, nativeTheme));
30
+ summary.children = node.children.map(child => summarize(child, styleSource));
37
31
  }
38
32
  return summary;
39
33
  }
@@ -240,7 +240,7 @@ export function registerWorkflowTools(server, platform) {
240
240
  }));
241
241
  server.registerTool('workflow_step_schema', {
242
242
  title: 'Step şeması üret',
243
- description: "Verilen step tanımı için girdi/çıktı şemasını üretir (parameterScheme / returnScheme); step yazarken definition'ı doğrulamanın en hızlı yolu. type:'workflow' adımında (rule.workflowId) çağrılan akışın parametre ve dönüş DTO'sunu döner — alt akışa girdi YALNIZ rule.expression ile geçer, nesne literalinin anahtarları bu parameterScheme'in alanlarıdır (WF-032; platform_guide('workflow') §Workflow adımı). ŞEMA ALAN ADLARINI VERİR, HANGİ ALANIN ÇALIŞTIĞINI DEĞİL — üç ölçülmüş sapma (2026-09-16): (1) 'http' adımının returnScheme'i kök seviyede { httpStatusCode, data } der, koşumda ise adım { data, meta: { httpStatusCode }, error }'dır, yani <adım>.httpStatusCode UNDEFINED, doğrusu <adım>.meta.httpStatusCode; (2) 'workflow' adımında workflowId boşken parameterScheme/returnScheme boş döner ve şema girdinin rule.expression ile bağlandığını söylemez; (3) 'email' adımında şemanın gösterdiği alıcı adı çalışmaz (36/W-6). Sözleşmenin ölçülmüş hâli: ngapps://examples/workflow-http-step · workflow-call-workflow · workflow-loop-step ve platform_guide('workflow').",
243
+ description: "Verilen step tanımı için girdi/çıktı şemasını üretir (parameterScheme / returnScheme); step yazarken definition'ı doğrulamanın en hızlı yolu. type:'workflow' adımında (rule.workflowId) çağrılan akışın parametre ve dönüş DTO'sunu döner — alt akışa girdi YALNIZ rule.expression ile geçer, nesne literalinin anahtarları bu parameterScheme'in alanlarıdır (WF-032; platform_guide('workflow') §Workflow adımı). 'workflow' adımında returnBehavior çağrılan akışın dönüş biçimidir (array → liste). returnScheme adımın GÖVDESİDİR; koşumda her adım { data, meta, error } zarfındadır — 'http' adımında gövde tipsizdir (<adım>.data), durum kodu <adım>.meta.httpStatusCode. ŞEMA ALAN ADLARINI VERİR, HANGİ ALANIN ÇALIŞTIĞINI DEĞİL — iki ölçülmüş sapma (2026-09-16): (1) 'workflow' adımında workflowId boşken parameterScheme/returnScheme boş döner ve şema girdinin rule.expression ile bağlandığını söylemez; (2) 'email' adımında şemanın gösterdiği alıcı adı çalışmaz (36/W-6). Sözleşmenin ölçülmüş hâli: ngapps://examples/workflow-http-step · workflow-call-workflow · workflow-loop-step ve platform_guide('workflow').",
244
244
  inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, id: guid, step: definitionParam },
245
245
  annotations: readOnly
246
246
  }, handle(config, ({ project, environment, applicationId, id, step }) => platform.tenant('POST', project, `/workflows/${applicationId}/${id}/steps/schema`, { environment, body: step })));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appaflytech/zeyrek-ai-mcp",
3
- "version": "0.0.23",
3
+ "version": "0.0.25",
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",