@appaflytech/zeyrek-ai-mcp 0.0.40 → 0.0.42

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 (60) hide show
  1. package/dist/knowledge/componentCatalog.js +95 -104
  2. package/dist/knowledge/componentEvents.js +34 -18
  3. package/dist/knowledge/mobileComponentCatalog.js +119 -20
  4. package/dist/knowledge/mobileComponentEvents.js +41 -0
  5. package/dist/knowledge/motionResolve.js +252 -0
  6. package/dist/knowledge/normalize.js +117 -71
  7. package/dist/knowledge/pageDiscover.js +2 -2
  8. package/dist/knowledge/platform/batchOps.js +70 -0
  9. package/dist/knowledge/platform/heroTag.js +153 -0
  10. package/dist/knowledge/platform/lint.js +128 -6
  11. package/dist/knowledge/platform/mobile.js +1 -1
  12. package/dist/knowledge/platform/mobileLayoutLint.js +8 -1
  13. package/dist/knowledge/platform/mobileRules.js +18 -0
  14. package/dist/knowledge/platform/pageTransition.js +57 -0
  15. package/dist/knowledge/platform/web.js +1 -1
  16. package/dist/knowledge/rules.js +217 -24
  17. package/dist/knowledge/styleResolve.js +0 -1
  18. package/dist/knowledge/styleResolveNative.js +88 -4
  19. package/dist/platform/capture/actions.js +27 -1
  20. package/dist/platform/capture/capture.js +10 -13
  21. package/dist/platform/capture/persistent-browser.js +130 -0
  22. package/dist/platform/capture/summary.js +4 -1
  23. package/dist/resources/examples/flow-list-to-form.json +8 -10
  24. package/dist/resources/examples/flow-load-table.json +1 -1
  25. package/dist/resources/examples/mobile-app-shell-drawer.json +1 -0
  26. package/dist/resources/examples/mobile-list-detail-form.json +7 -3
  27. package/dist/resources/examples/mobile-scan-code.json +285 -0
  28. package/dist/resources/guides/component.md +3 -3
  29. package/dist/resources/guides/entity.md +16 -0
  30. package/dist/resources/guides/expressions.md +8 -7
  31. package/dist/resources/guides/merge.md +98 -18
  32. package/dist/resources/guides/microservice.md +3 -3
  33. package/dist/resources/guides/middleware.md +2 -0
  34. package/dist/resources/guides/mobile-layout.md +2 -1
  35. package/dist/resources/guides/mobile-publish.md +1 -0
  36. package/dist/resources/guides/mobile-steps.md +67 -0
  37. package/dist/resources/guides/mobile.md +51 -70
  38. package/dist/resources/guides/page.md +229 -137
  39. package/dist/resources/guides/translation.md +67 -1
  40. package/dist/resources/guides/workflow.md +31 -1
  41. package/dist/resources/schema-fingerprint.json +2 -2
  42. package/dist/resources/schemas/ResolveMergeConflictsCommand.json +30 -1
  43. package/dist/tools/activities.js +3 -1
  44. package/dist/tools/applications.js +16 -2
  45. package/dist/tools/components.js +12 -6
  46. package/dist/tools/designSchemaPatch.js +18 -13
  47. package/dist/tools/entities.js +41 -4
  48. package/dist/tools/layouts.js +29 -9
  49. package/dist/tools/merges.js +29 -9
  50. package/dist/tools/mobile.js +15 -1
  51. package/dist/tools/pages.js +156 -168
  52. package/dist/tools/platformInfo.js +3 -2
  53. package/dist/tools/profileWrite.js +2 -2
  54. package/dist/tools/queries.js +1 -1
  55. package/dist/tools/rows.js +14 -3
  56. package/dist/tools/schemaOps.js +132 -34
  57. package/dist/tools/screenWrite.js +3 -3
  58. package/dist/tools/screens.js +42 -3
  59. package/dist/tools/translations.js +148 -6
  60. package/package.json +2 -2
@@ -11,8 +11,14 @@ const mergeDescription = z.string().trim().max(2000).optional()
11
11
  .describe("Dalda ne değişti ve neden merge edilmeli — gözden geçirene yazılan gövde. Merge bunu ASLA ezmez; opsiyoneldir ama açıklamasız istekte değişiklik listesi okunacak tek şey kalır.");
12
12
  const resolution = z.object({
13
13
  itemKey: z.string().min(1).describe("Plan kaydının anahtarı, ör. 'page:8f1c…' (merge_get çıktısındaki items[].key)"),
14
- path: z.string().optional().describe("Eleman yolu, ör. 'components[elementId=btn_save].props[name=label].ref'; boş bırakılırsa o kaydın TÜM çakışmaları çözülür"),
15
- choice: z.enum(['source', 'target']).describe("source = dal, target = development")
14
+ path: z.string().optional().describe("Eleman yolu, ör. 'components[elementId=btn_save].props[name=label].ref'; boş bırakılırsa o kaydın TÜM çakışmaları çözülür (custom'da yalnız kaydın tek çakışması varsa)"),
15
+ choice: z.enum(['source', 'target', 'both', 'custom']).describe("source = dal, target = development, both = iki tarafın birleşimi — yalnız combinable: true elemanda, birleşimi platform hesaplar; duplicate'te ikisini de tut demektir (slug taşıyan kopyada kapalı, combinable: false; base dolu kopyada source da kapalı). custom = value'daki değer"),
16
+ value: z.unknown().optional().describe("YALNIZ choice='custom' ile ve orada ZORUNLU: yazılacak değer. Türü (dizi/nesne/skaler) source ya da target ile aynı olmalı. Kök yolda kaydın gövdesidir, order-conflict'te kimlik listesidir, duplicate'te tek öğedir (kimliği development'ınki olur), tipi değişen prop'ta ('…props[id=…]') prop gövdesidir — valueType ile ref birlikte yazılır, kimliği yoldan gelir, statik listenin satırlarını (children) sunucu ref'ten kurar.")
17
+ }).superRefine((entry, context) => {
18
+ if (entry.choice === 'custom' && entry.value === undefined)
19
+ context.addIssue({ code: 'custom', path: ['value'], message: "choice='custom' değer ister: yazılacak değeri value alanında gönderin" });
20
+ if (entry.choice !== 'custom' && entry.value !== undefined)
21
+ context.addIssue({ code: 'custom', path: ['value'], message: "value yalnız choice='custom' ile gönderilir; source / target / both değer taşımaz" });
16
22
  });
17
23
  /**
18
24
  * B-08 (2026-09-09 koşusu): `ResolveMergeConflictsCommandHandler` yanıtı
@@ -30,7 +36,7 @@ export function resolveSummary(payload, planId, requested) {
30
36
  ...(plan.status === undefined ? {} : { status: plan.status }),
31
37
  ...(plan.summary === undefined ? {} : { summary: plan.summary }),
32
38
  resolved: { requested, elements: resolvedElements },
33
- note: "Yanıt ÖZETTİR — plan gövdesi kesildi. Planın kalan çakışmaları için merge_get { projectId, planId, view: 'conflicts' }; summary.unresolved 0 olduğunda merge_apply."
39
+ note: "Yanıt ÖZETTİR — plan gövdesi kesildi. Planın kalan çakışmaları için merge_get { projectId, planId, view: 'conflicts' }; summary.unresolved 0 olduğunda merge_apply. summary.duplicates çözümsüz olası kopyalardır: combinable: true olan kopya merge'ü engellemez (ikisi de yazılır), slug taşıyan kopya (combinable: false) ise summary.unresolved'a sayılır ve birini seçene kadar apply edilmez; merge_get { checks: true } okunmadan apply edilmez."
34
40
  };
35
41
  }
36
42
  export function registerMergeTools(server, platform) {
@@ -55,13 +61,27 @@ export function registerMergeTools(server, platform) {
55
61
  }, handle(config, ({ projectId, ...query }) => platform.org('GET', `/merges/${projectId}`, { query })));
56
62
  server.registerTool('merge_get', {
57
63
  title: 'Merge planını oku',
58
- description: "Bir merge planını döner. items[] yalnız DEĞİŞEN kayıtları taşır; her kayıtta kind (add|update|delete|conflict) ve elements[] vardır. Çakışan elemanlarda base/source/target üç değeri birden gelir. dataRisk: true olan kalemde SEBEP dataRiskReasons[] içindedir: 'field-removed' (alan siliniyor), 'field-narrowed' (tip/nullable/unique daraltılıyor), 'not-null-without-default-on-populated-table' (hedefte satır varken varsayılansız NOT NULL alan ekleniyor — bu apply'ı DDL aşamasında düşürür, alanı nullable yapın ya da varsayılan verin), 'table-removed' (hedefte satırı olan tablo siliniyor). dataRisk bir UYARIDIR, apply'ı bloklamaz. items[].dependents[] ({ id, name, module }) dolu olan kalem, DALIN SİLDİĞİ ama development'ın dal açıldıktan sonra kullanmaya başladığı kayıttır: silme ÇAKIŞMAYA döner; hedef lehine çözüm kaydı ve bağımlısını korur, kaynak lehine çözüm siler (bağımlı FK ile düşebilir). Sorgunun çıktı DTO'su ve alanları aynı çakışma grubuna girer. Süreç kenarlarında (edges) iki taraf AYNI geçidin çıkışlarına dokunduysa yol 'versions[id=…].model.edges{from=<düğüm>}' olan TEK çakışma gelir; farklı geçitler kendiliğinden birleşir. Merge çevirileri (translation, adı 'key') ve microfunction'ları da taşır; microfunction hedefte TASLAK kalır, yayını kullanıcı yapar. derivedFromKey dolu olan kalem OTOMATİK ÜRETİLMİŞ bir kayıttır (varsayılan DTO); kaynağını (entity ya da query) çözdüğünüzde aynı yoldaki çakışması aynı tarafa KENDİLİĞİNDEN çözülür — ayrı ayrı ve zıt çözülemez. Uygulanmış planlarda title, description, createdBy ve appliedBy da gelir. kind=revert ise bu bir geri alma planıdır: revertsPlanId geri aldığı planı verir ve elements'te source merge ÖNCESİ, target ŞİMDİKİ değerdir. isStale: true ise plan alındığından beri DAL ya da development değişmiştir: items o değişikliği taşimaz ve merge_apply 409 döner — merge_refresh ile planı tazeleyin. elements[].isNoise: true olan eleman GÖSTERİM gürültüsüdür — kanvasın kendi durumu (workflow schema), DTO'dan türetilen şema (microservice schema.parameterScheme/returnScheme), sunucu yönetimli anahtar; merge gövdesinde KALIR ve uygulanır, yalnız okurken atlanır. Çakışan eleman asla işaretlenmez. items[].references[] o kalemin gövdesindeki guid'lerin karşılığıdır ({ id, name, module }): bir table step'in rule.entityId'si hangi tabloya, bir branch'in nextStepId'si hangi adıma, bir filtrenin fieldId'si hangi alana işaret ediyor — plan dışına çıkmadan okunur. items[].parentKey dolu olan kayıt başka bir kaydın çocuğudur (DTO çocukları, iç içe klasörler); ebeveyniyle birlikte okunur. items[].recordType kaydın modül içindeki türüdür — bir workflow kaydı 'workflow', 'automation' ya da 'middleware' olabilir ve modül üçüne de workflow der. items[].hiddenFields o kaydın GÖVDESİNDE okunmayacak anahtarlardır (aynı politika; eklenen/silinen kayıt tek eleman olarak geldiği için yolun değil anahtarın sorusudur).",
59
- inputSchema: { projectId: guid, planId: guid, view: mergeView },
64
+ description: "Bir merge planını döner. items[] yalnız DEĞİŞEN kayıtları taşır; her kayıtta kind (add|update|delete|conflict) ve elements[] vardır. Çakışan elemanlarda base/source/target üç değeri birden gelir. dataRisk: true olan kalemde SEBEP dataRiskReasons[] içindedir: 'field-removed' (alan siliniyor), 'field-narrowed' (tip/nullable/unique daraltılıyor), 'not-null-without-default-on-populated-table' (hedefte satır varken varsayılansız NOT NULL alan ekleniyor — bu apply'ı DDL aşamasında düşürür, alanı nullable yapın ya da varsayılan verin), 'table-removed' (hedefte satırı olan tablo siliniyor). dataRisk bir UYARIDIR, apply'ı bloklamaz. items[].dependents[] ({ id, name, module }) dolu olan kalem, DALIN SİLDİĞİ ama development'ın dal açıldıktan sonra kullanmaya başladığı kayıttır: silme ÇAKIŞMAYA döner; hedef lehine çözüm kaydı ve bağımlısını korur, kaynak lehine çözüm siler (bağımlı FK ile düşebilir). Sorgunun çıktı DTO'su ve alanları aynı çakışma grubuna girer. Süreç kenarlarında (edges) iki taraf AYNI geçidin çıkışlarına dokunduysa yol 'versions[id=…].model.edges{from=<düğüm>}' olan TEK çakışma gelir; farklı geçitler kendiliğinden birleşir. Merge çevirileri (translation, adı 'key') ve microfunction'ları da taşır; microfunction hedefte TASLAK kalır, yayını kullanıcı yapar. derivedFromKey dolu olan kalem OTOMATİK ÜRETİLMİŞ bir kayıttır (varsayılan DTO); kaynağını (entity ya da query) çözdüğünüzde aynı yoldaki çakışması aynı tarafa KENDİLİĞİNDEN çözülür — ayrı ayrı ve zıt çözülemez. Uygulanmış planlarda title, description, createdBy ve appliedBy da gelir. kind=revert ise bu bir geri alma planıdır: revertsPlanId geri aldığı planı verir ve elements'te source merge ÖNCESİ, target ŞİMDİKİ değerdir. isStale: true ise plan alındığından beri DAL ya da development değişmiştir: items o değişikliği taşimaz ve merge_apply 409 döner — merge_refresh ile planı tazeleyin. elements[].isNoise: true olan eleman GÖSTERİM gürültüsüdür — kanvasın kendi durumu (workflow schema), DTO'dan türetilen şema (microservice schema.parameterScheme/returnScheme), sunucu yönetimli anahtar; merge gövdesinde KALIR ve uygulanır, yalnız okurken atlanır. Çakışan eleman asla işaretlenmez. items[].references[] o kalemin gövdesindeki guid'lerin karşılığıdır ({ id, name, module }): bir table step'in rule.entityId'si hangi tabloya, bir branch'in nextStepId'si hangi adıma, bir filtrenin fieldId'si hangi alana işaret ediyor — plan dışına çıkmadan okunur. items[].parentKey dolu olan kayıt başka bir kaydın çocuğudur (DTO çocukları, iç içe klasörler); ebeveyniyle birlikte okunur. items[].recordType kaydın modül içindeki türüdür — bir workflow kaydı 'workflow', 'automation' ya da 'middleware' olabilir ve modül üçüne de workflow der. items[].hiddenFields o kaydın GÖVDESİNDE okunmayacak anahtarlardır (aynı politika; eklenen/silinen kayıt tek eleman olarak geldiği için yolun değil anahtarın sorusudur). Bir taraf prop'un TİPİNİ (valueType: static → code) değiştirip öbür taraf da tipine ya da değerine (ref/data) dokunduysa eleman prop'un KENDİSİDİR: yol '…props[id=…]', base/source/target prop gövdesi, combinable: false — tip ile değer tek karardır. Nesne prop'unda (icon, surfaceStyle) anahtarın değeri '…ref.<anahtar>…', çizilen satırı '…children[name=<anahtar>]…' yolundadır; ikisi de çakışırsa kararı ref'e verin — satır karar istemez, unresolved'a sayılmaz; merge onu değerin birleşik hâlinden kurar. ÇÖZÜM DEĞER TAŞIR: elements[].combinable: true olan çakışma (kimliksiz ya da gruplu liste) both ile birleştirilebilir; elements[].value both/custom çözümünün yazılacak değeridir. kind='duplicate' OLASI KOPYADIR: iki taraf aynı içeriği farklı kimlikle eklemiş, twinPath development'taki ikizdir. combinable: true olan kopya ENGELLEMEZ — çözümsüzse ikisi de yazılır; kopyalar aynı slug'ı taşıyorsa (tablo alanı = kolon, sayfa = rota) combinable: false gelir, ikisi birden kalamaz: unresolved sayılır, both reddedilir, birini seçmek gerekir. Tablo alanında slug, bileşen prop'unda ad TEKİLDİR: içerik farklı olsa da aynı slug'lı alan ya da aynı adlı prop eklemesi combinable: false kopyadır; aynı ad farklı slug'lı iki alan ayrı eklenir (name-clash uyarısı). Development tabanda var olan bir alanı dalın eklediği slug'a yeniden adlandırdıysa dalın alanı yine duplicate gelir; base doludur (alanın taban hâli) ve source 400 döner — veri taşıyan alan silinmez, target ya da custom seçilir. target dalınkini düşürür, source development'ınkini çıkarır, custom tek öğe yazar; düşen kopyadan türemiş DTO alanı da düşer. summary.duplicates çözümsüz kopya sayısıdır. items[].derivedFromPath dolu olan DTO alanı tablo alanına bağlıdır (fields[id=…]); tablo alanı kararı ona kendiliğinden geçer. checks: true merge öncesi doğrulamayı da ekler: unresolved (error) · duplicate-open · name-clash (aynı adla iki kardeş) · dangling-reference (merge'ün düşürdüğü kimliğe kalan başvuru) — uyarılar engellemez, merge_apply'dan önce okunur.",
65
+ inputSchema: {
66
+ projectId: guid,
67
+ planId: guid,
68
+ view: mergeView,
69
+ checks: z.boolean().optional().describe("true ise planın merge öncesi doğrulaması (checks[]) yanıta eklenir; plan planned değilse boş gelir")
70
+ },
60
71
  annotations: readOnly
61
- }, handle(config, ({ projectId, planId, view }) => platform.org('GET', `/merges/${projectId}/${planId}?view=${view ?? 'conflicts'}`)));
72
+ }, handle(config, async ({ projectId, planId, view, checks }) => {
73
+ const payload = await platform.org('GET', `/merges/${projectId}/${planId}?view=${view ?? 'conflicts'}`);
74
+ if (!checks)
75
+ return payload;
76
+ const checkPayload = await platform.org('GET', `/merges/${projectId}/${planId}/checks`);
77
+ return {
78
+ ...(payload && typeof payload === 'object' ? payload : { data: payload }),
79
+ checks: checkPayload?.data?.checks ?? []
80
+ };
81
+ }));
62
82
  server.registerTool('merge_resolve', {
63
83
  title: 'Merge çakışmalarını çöz',
64
- description: "Çakışan elemanlar için dal (source) ya da development (target) seçimini plana yazar. Yalnız status=planned iken çalışır. path boş bırakılırsa o kaydın tüm çakışmaları aynı tarafa çözülür. YANIT ÖZETTİR: { planId, status, summary, resolved } — platform planın tamamını döner ama gateway onu kesip yalnız sayaçları verir (orta boy planda tam gövde 68-121 KB'a çıkıyor ve yanıt sınırını aşıyordu; çağrı hata gibi görünürken çözüm UYGULANMIŞ oluyordu). Planın kendisini görmek için merge_get { planId, view:'conflicts' } çağırın; kalan çakışma sayısı summary.unresolved'dadır.",
84
+ description: "Çakışan elemanlar ve olası kopyalar için kararı plana yazar: source (dal), target (development), both (iki tarafın birleşimi — yalnız combinable: true elemanda; kopyada ikisini de tut) ya da custom (value'daki değer). Yalnız status=planned iken çalışır. path boş bırakılırsa o kaydın tüm çakışmaları aynı karara çözülür. Türetilmiş kaydı (varsayılan DTO) kaynağına zıt çözmek 400 döner. YANIT ÖZETTİR: { planId, status, summary, resolved } — platform planın tamamını döner ama gateway onu kesip yalnız sayaçları verir (orta boy planda tam gövde 68-121 KB'a çıkıyor ve yanıt sınırını aşıyordu; çağrı hata gibi görünürken çözüm UYGULANMIŞ oluyordu). Planın kendisini görmek için merge_get { planId, view:'conflicts' } çağırın; kalan çakışma sayısı summary.unresolved'dadır.",
65
85
  inputSchema: { projectId: guid, planId: guid, resolutions: z.array(resolution).min(1) },
66
86
  annotations: updates
67
87
  }, handle(config, async ({ projectId, planId, resolutions }) => {
@@ -82,14 +102,14 @@ export function registerMergeTools(server, platform) {
82
102
  }));
83
103
  server.registerTool('merge_refresh', {
84
104
  title: 'Merge planını tazele',
85
- description: "Açık bir planı dalın ve development'ın ŞU ANKİ hâline göre yeniden hesaplatır. İstek yerinde kalır: id'si, başlığı, açıklaması ve geçmişi korunur — yalnız değişiklik listesi yenilenir. KAYDEDİLMİŞ ÇAKIŞMA SEÇİMLERİ DÜŞER: yeni plan yeni elemanlar üretir, çözümler baştan verilir. Yalnız status=planned bir planda çalışır ve dal ready olmalıdır. Bayat bir planı (merge_get → isStale: true, ya da merge_apply 409) düzeltmenin yolu budur; merge_discard + merge_plan istemez. Asenkron: yanıt 202, plan planning durumundadır — merge_get ile planned bekleyin.",
105
+ description: "Açık bir planı dalın ve development'ın ŞU ANKİ hâline göre yeniden hesaplatır. İstek yerinde kalır: id'si, başlığı, açıklaması ve geçmişi korunur — yalnız değişiklik listesi yenilenir. DEĞİŞMEYEN ELEMANIN KARARI KORUNUR: aynı kalem, aynı yol ve üç tarafı (base/source/target) aynı kalan elemanın kararı ve değeri yeni plana taşınır; değişenler yeniden sorulur (etkinlikte merge.resolutions_carried { carried, dropped }). Yalnız status=planned bir planda çalışır ve dal ready olmalıdır. Bayat bir planı (merge_get → isStale: true, ya da merge_apply 409) düzeltmenin yolu budur; merge_discard + merge_plan istemez. Asenkron: yanıt 202, plan planning durumundadır — merge_get ile planned bekleyin.",
86
106
  inputSchema: { projectId: guid, planId: guid },
87
107
  annotations: writes
88
108
  }, handle(config, async ({ projectId, planId }) => {
89
109
  const payload = await platform.org('POST', `/merges/${projectId}/${planId}/refresh`);
90
110
  return {
91
111
  ...(payload && typeof payload === 'object' ? payload : { data: payload }),
92
- note: "plan yeniden hesaplanıyor; merge_get ile status=planned bekleyin — çakışma çözümleri baştan verilir"
112
+ note: "plan yeniden hesaplanıyor; merge_get ile status=planned bekleyin — değişmeyen elemanların kararları korunur, yalnız değişenler yeniden sorulur"
93
113
  };
94
114
  }));
95
115
  server.registerTool('merge_revert', {
@@ -49,6 +49,7 @@ export function buildMobileAppPlan(input) {
49
49
  ];
50
50
  }
51
51
  /** Kabuk ağacı örnek dosyasından okunur — örnek ile aracın kurduğu layout tek kaynaktır. */
52
+ const drawerButtonId = (pageSlug) => `menu_${pageSlug.replace(/[^A-Za-z0-9]+/g, '_')}`;
52
53
  function shellViews(input) {
53
54
  const example = JSON.parse(readKnowledgeFile('examples', input.drawer ? 'mobile-app-shell-drawer.json' : 'mobile-app-shell-stack.json'));
54
55
  const views = structuredClone(example.layoutCreate.views);
@@ -57,6 +58,19 @@ function shellViews(input) {
57
58
  const appBar = findAppBar(views);
58
59
  if (appBar && input.title)
59
60
  appBar.props.title = { type: 'static', ref: null, data: input.title };
61
+ // 37 S-9 / g-24: örneğin düğmeleri ŞABLONDUR; çekmece uygulamanın kendi sayfalarından birer düğme taşır.
62
+ const drawer = views.find(node => node.type === 'drawer');
63
+ const template = drawer?.children?.find(node => node.type === 'button');
64
+ if (drawer && template) {
65
+ drawer.children = input.pages.map(page => {
66
+ const elementId = drawerButtonId(page.pageSlug);
67
+ const button = structuredClone(template);
68
+ button.elementId = elementId;
69
+ button.name = elementId;
70
+ button.props = { ...button.props, text: { type: 'static', ref: null, data: page.pageName } };
71
+ return button;
72
+ });
73
+ }
60
74
  return views;
61
75
  }
62
76
  const SHELL_TYPES = ['app-bar', 'slot'];
@@ -274,7 +288,7 @@ export function registerMobileTools(server, platform) {
274
288
  ...(tabs ? { tabs: tabs.map(tab => tab.pageSlug) } : {}),
275
289
  completed,
276
290
  ...(warnings.length > 0 ? { warnings } : {}),
277
- next: "Ekranları page_schema_patch ile doldurun; doğrulama page_screenshot (mobilde varsayılan device: 'phone'). platform_guide('mobile')."
291
+ next: `Ekranları page_schema_patch ile doldurun; doğrulama page_screenshot (mobilde varsayılan device: 'phone'). ${input.drawer ? `Çekmece düğmeleri sayfalardan türedi (${pages.map(page => drawerButtonId(page.pageSlug)).join(', ')}): her birine flow_create (host: 'layout', redirect) + layout_schema_patch set_event { event: 'click' } bağlayın. ` : ''}platform_guide('mobile').`
278
292
  };
279
293
  }));
280
294
  }