@appaflytech/zeyrek-ai-mcp 0.0.21 → 0.0.22

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 (51) hide show
  1. package/dist/config.js +2 -0
  2. package/dist/knowledge/componentCatalog.js +3 -3
  3. package/dist/knowledge/componentEvents.js +9 -2
  4. package/dist/knowledge/mobileComponentCatalog.js +543 -0
  5. package/dist/knowledge/mobileComponentEvents.js +98 -0
  6. package/dist/knowledge/normalize.js +52 -11
  7. package/dist/knowledge/platform/lint.js +205 -0
  8. package/dist/knowledge/platform/mobile.js +78 -0
  9. package/dist/knowledge/platform/mobileRules.js +123 -0
  10. package/dist/knowledge/platform/mobileTabs.js +108 -0
  11. package/dist/knowledge/platform/profile.js +20 -0
  12. package/dist/knowledge/platform/resolve.js +122 -0
  13. package/dist/knowledge/platform/web.js +38 -0
  14. package/dist/knowledge/rules.js +6 -8
  15. package/dist/knowledge/styleResolve.js +1 -1
  16. package/dist/knowledge/styleResolveNative.js +410 -0
  17. package/dist/knowledge/themeResolve.js +3 -3
  18. package/dist/platform/capture/actions.js +333 -0
  19. package/dist/platform/capture/browser.js +1 -0
  20. package/dist/platform/{screenshot.js → capture/capture.js} +23 -509
  21. package/dist/platform/capture/index.js +10 -0
  22. package/dist/platform/capture/readiness.js +103 -0
  23. package/dist/platform/capture/summary.js +77 -0
  24. package/dist/platform/capture/target.js +5 -0
  25. package/dist/platform/capture/targets/studio-mobile.js +15 -0
  26. package/dist/platform/capture/targets/studio-web.js +5 -0
  27. package/dist/platform/domSummary.js +1 -1
  28. package/dist/resources/examples/mobile-app-shell-drawer.json +209 -0
  29. package/dist/resources/examples/mobile-app-shell-stack.json +123 -0
  30. package/dist/resources/examples/mobile-app-shell-tab.json +174 -0
  31. package/dist/resources/examples/mobile-list-detail-form.json +656 -0
  32. package/dist/resources/guides/component.md +6 -1
  33. package/dist/resources/guides/functions.md +1 -1
  34. package/dist/resources/guides/layout.md +11 -7
  35. package/dist/resources/guides/mobile.md +264 -0
  36. package/dist/resources/guides/page.md +55 -15
  37. package/dist/resources/guides/translation.md +1 -1
  38. package/dist/server.js +2 -0
  39. package/dist/tools/applications.js +60 -3
  40. package/dist/tools/components.js +50 -10
  41. package/dist/tools/designSchemaPatch.js +13 -4
  42. package/dist/tools/externalComponents.js +25 -4
  43. package/dist/tools/flows.js +9 -2
  44. package/dist/tools/layouts.js +41 -9
  45. package/dist/tools/mobile.js +203 -0
  46. package/dist/tools/pages.js +115 -35
  47. package/dist/tools/platformInfo.js +2 -1
  48. package/dist/tools/profileWrite.js +45 -0
  49. package/dist/tools/screenWrite.js +2 -2
  50. package/dist/tools/screens.js +9 -3
  51. package/package.json +1 -1
@@ -4,6 +4,10 @@ Sayfaların paylaştığı kabuk: yan menü, üst şerit, kullanıcı menüsü v
4
4
  gireceği delik. Şema gövdesi ve koordinat modeli için `platform_guide('page')` (Kural 1,
5
5
  1d, 1f); komponent sözleşmeleri için `platform_guide('component')`.
6
6
 
7
+ > **Mobil uygulamada** kabuk `app-bar` + tek `slot`'tur; sekmeler uygulama ayarı
8
+ > (`properties.mobile.tabs`), çekmece `drawer` widget'ıdır. Web kabuk bileşenleri (`navigations`,
9
+ > `sidebar`, `header`) `MOB-004` alır — `platform_guide('mobile')` §Gezinme.
10
+
7
11
  ## Karar kuralları
8
12
 
9
13
  **1. Layout, tek `slot` içeren SIRADAN bir komponent ağacıdır.** Ayrı bir dil yoktur:
@@ -61,7 +65,7 @@ yapılan eski numaraya artık gerek yok.
61
65
  NEREDE durduğunu değil, BİÇİMİNİ söyler (dikey kolon / yatay şerit / dolgu yüzeyi). Hem
62
66
  runtime hem Studio tuvali bölgeleri 12 kolonluk ızgarayla yerleştirir.
63
67
 
64
- **7. Mobilde flex YIĞILMAZ.** Runtime'ın mobil kuralı yalnız ızgara özelliklerini ezer.
68
+ **7. Dar ekranda flex YIĞILMAZ.** Runtime'ın dar ekran kuralı yalnız ızgara özelliklerini ezer.
65
69
  Telefonda alt alta düşmesi gereken satırı `layout:'grid'` ile kur; `layout:'flex'` +
66
70
  `direction:'row'` telefonda da yan yana kalır (375px'te ölçüldü: ızgara çocukları 375/375px
67
71
  alt alta, flex çocukları 49/310px yan yana). Not: `wrap` varsayılanı artık açık (2026-09-01) —
@@ -140,8 +144,8 @@ bağlantı nesnesi ya da tam yol).
140
144
  "direction": { "type": "static", "data": "row" } },
141
145
  "blocks": [{ "breakpoint": 1024, "size": { "w": 12, "h": 80 }, "position": { "x": 0, "y": 0 } }] }
142
146
 
143
- // KÖTÜ — telefonda 49px'lik yan menü: row flex mobilde yığılmaz (Kural 7)
144
- // Mobilde alt alta düşmesi gerekiyorsa kökü layout:'grid' kur — bedeli, fill'in
147
+ // KÖTÜ — telefonda 49px'lik yan menü: row flex dar ekranda yığılmaz (Kural 7)
148
+ // Dar ekranda alt alta düşmesi gerekiyorsa kökü layout:'grid' kur — bedeli, fill'in
145
149
  // flex anlamının devreye girmemesi.
146
150
  ```
147
151
 
@@ -179,9 +183,9 @@ bunlardan biri olabilir:
179
183
  |---|---|
180
184
  | ~~`heightType` yalnız `auto` \| `fixed`~~ | **28 Ağustos'ta kapandı:** üçüncü değer `fill` (Kural 5b) |
181
185
  | ~~Kök kap viewport'a kilitlenmez~~ | **28 Ağustos'ta kapandı:** `fill` verilmiş kök 100vh (Kural 5b) |
182
- | Flex mobilde yığılmaz | Kural 7 — kabuk bugün bir MASAÜSTÜ kabuğudur |
183
- | Kırılıma duyarlı prop yok | `direction`/`gap` masaüstü ve mobilde AYNI; yalnız `blocks` ve `appearance.hideOn` kırılım bilir |
184
- | Mobil çekmece (overlay) yok | Telefonda içeriğin üstüne binen panel kurulamaz |
186
+ | Flex dar ekranda yığılmaz | Kural 7 — kabuk bugün bir MASAÜSTÜ kabuğudur |
187
+ | Kırılıma duyarlı prop yok | `direction`/`gap` masaüstü ve dar ekranda AYNI; yalnız `blocks` ve `appearance.hideOn` kırılım bilir |
188
+ | Dar ekranda çekmece (overlay) yok | Telefon genişliğinde içeriğin üstüne binen panel kurulamaz (mobil UYGULAMADA çekmece `drawer` widget'ıdır — `platform_guide('mobile')`) |
185
189
 
186
190
  ---
187
191
 
@@ -189,7 +193,7 @@ bunlardan biri olabilir:
189
193
  (`injectPageSchemaIntoSlots`, `getResolvedLayoutViews`), `apps/studio/src/features/page/api/page.mappers.ts`
190
194
  (`mapPageLayoutToPreview`), `packages/ng-apps-ui/src/shared/render/render.functions.ts`
191
195
  (`resolveNodeBoxStyle` — slot'un `y / auto` satırı, flex çocuk genişliği),
192
- `packages/ng-apps-ui/src/shared/render/RenderComponent.svelte` (mobil media kuralı),
196
+ `packages/ng-apps-ui/src/shared/render/RenderComponent.svelte` (dar ekran media kuralı),
193
197
  `packages/ng-apps-screen-builder/src/flex-layout.ts` (`getFlexChildStyle` — `widthType`
194
198
  fill/fixed/auto dalları, `normalizeCssSize` kabul kuralı; tuval ve runtime aynı fonksiyonu okur),
195
199
  `apps/studio/src/features/page/components/appearance/appearance-size.functions.ts` (panelin
@@ -0,0 +1,264 @@
1
+ # Mobil uygulama rehberi
2
+
3
+ Mobil uygulama (`application_create` → `type: 'mobile'`) web uygulamasıyla **aynı şemayı**, aynı
4
+ micro-op sözlüğünü ve aynı akış motorunu kullanır; farkı çizerdedir. Sayfalar
5
+ `@ng-apps/ui-native` ile React Native olarak çizilir: Studio'da (kanvas, `/preview`, `/dev|/view`)
6
+ react-native-web üzerinde, cihazda Expo uygulamasında. Gateway uygulamanın tipini kendisi okur
7
+ (platform profili) ve mobilde çizilmeyecek her yazımı `MOB-*` satırıyla söyler — yazım yine
8
+ platforma gider, veri düşürülmez.
9
+
10
+ **Sözlük.** Bu rehberde "mobil" yalnız **mobil uygulama** demektir. Web uygulamasının telefondaki
11
+ dar ekran kırılımı (`hideOn: 'mobile'`, `breakpoint: mobile`) ayrı bir kavramdır ve
12
+ `platform_guide('page')` / `platform_guide('layout')`'ta anlatılır; alan adları değişmedi, yalnız
13
+ anlamları ayrı.
14
+
15
+ ## Kurulum sırası
16
+
17
+ 1. **Uygulama ve kabuk.** Tek çağrıda: `mobile_app_create` (uygulama + sayfalar + kabuk layout'u +
18
+ sekme ayarı + ana sayfa bağı, `dryRun` ile önce planı görün). Tekil araçlarla aynı sıra:
19
+ `application_create({ type: 'mobile' })` → `page_create` × N → `layout_create` (kabuk) →
20
+ `page_update({ layoutId })` × N → `application_update({ homepageId, properties.mobile.tabs })`.
21
+ Sekme ayarı sayfa **id**'si ister; bu yüzden sayfalardan SONRA yazılır.
22
+ 2. **Veri.** Entity, microservice ve workflow web'dekiyle aynıdır (`platform_guide('microservice')`).
23
+ Sayfa akışı `microservice` adımıyla aynı uçları çağırır.
24
+ 3. **Ekranlar.** `page_schema_patch` ile bileşen ekle, akış bağla (`flow_create` → `set_event`).
25
+ 4. **Doğrulama.** `page_screenshot` (mobilde varsayılan `device: 'phone'`, 390x844 @2) ve
26
+ `page_runtime_get({ resolveStyles: true })` (düğümün React Native stili). Ayrıntı §Doğrulama.
27
+
28
+ `page_create` mobil uygulamada kökü kendisi kurar: `page_container`, `layout` prop'u YOK,
29
+ `direction: 'column'`, `blocks: []`, `appearance.heightType: 'fill'` — kök telefon ekranını doldurur.
30
+
31
+ ## Bileşenler
32
+
33
+ Mobil uygulamanın bileşen kataloğu ayrıdır (backend satırları `(slug, type: 'mobile')`).
34
+ `component_list` ve `component_get` mobil uygulamada **kendiliğinden** mobil kataloğu okur.
35
+ `component_get` yanıtı `platform: 'mobile'` ile üç katman taşır: `knowledge` (web kaydı — mobil
36
+ şema web sınıfını genişlettiği için prop'ların anlamı oradadır), `mobileKnowledge` (bu bileşenin
37
+ mobil farkları: düşen prop, değişen etkileşim, mobile özgü prop notları) ve `mobileNotes` (bütün
38
+ mobil bileşenlere geçen notlar). Web'de karşılığı olmayan bileşende (`app-bar`, `safe-area`,
39
+ `scroll-view`, `choice-chips`, `tooltip`, `markdown`, `calendar`, `stack`, `list-item`, `fab`, `timer`,
40
+ `audio`, `lottie`, `webview`) bilgi yalnız `mobileKnowledge`'tadır. Olay yükleri
41
+ (`events[].payload`) önce mobile özgü sözleşmeden okunur (`app-bar.clickAction`, `repeater.swipe`,
42
+ `choice-chips.change`…), yoksa web'inkinden.
43
+
44
+ - Katalogda olmayan tip `MOB-003` alır ve backend `unknown-type` (422) ile reddeder. Mobil pakette
45
+ olan ama bu uygulamanın kataloğuna yazılmamış tip için gateway katalog senkronunu gösterir; web'de
46
+ olup mobilde henüz olmayan için ne zaman geleceğini söyler (Dalga 2, Faz 3).
47
+ - **Katalog A** (FlutterFlow paritesi, 2026-09-24) on bileşen ekledi: `badge`, `avatar`, `progress`,
48
+ `radio`, `checkboxgroup`, `choice-chips`, `collapsible-container`, `slider`, `tabs`, `tooltip`;
49
+ `button` mobilde `secondary`/`ghost`/`link` varyantlarını ve `icon` boyunu alır. Tam liste
50
+ `component_list`'tir.
51
+ - **Katalog B** (FlutterFlow paritesi) önce dört prop'la başladı; hepsi YALNIZ mobil şemadadır:
52
+ `scroll-view.stickyHeader` (ilk çocuk dikey kaydırmada üstte kalır), `numberinput.variant: stepper`
53
+ (± düğmeleri, iç roller `__decrement`/`__increment`), `modal.presentation: center | sheet | fullscreen`
54
+ (alt sayfa şeritten aşağı sürükleyince `change { isOpen: false }` ile kapanır; en çok ekranın %90'ı,
55
+ uzun içerik için içine `scroll-view`). En-boy oranı yeni
56
+ prop DEĞİLDİR: boyut panelinin `appearance.aspectRatio`'su mobilde kaplara da uygulanır
57
+ (§Yerleşim).
58
+ İkinci adımda dört bileşen: `markdown` (Markdown çizer, HTML çalıştırmaz; bağlantı `linkClick { href }`)
59
+ ve `calendar` (satır içi takvim, tek gün ya da aralık; prop adları ve `change` biçimi web
60
+ `datepicker`ınki) mobile özgüdür; `otpinput` ve `qrcode` web ikizleridir, kuralları web modülünden.
61
+ Üçüncü adımda dört bileşen daha: `stack` (katmanlar: ilk çocuk taban, üsttekiler yığının 9 noktalı
62
+ `alignment`ıyla hizalanır — çocukta hiza alanı YOKTUR), `list-item` (satır: baş · başlık · alt başlık ·
63
+ son; `click`), `fab` (yüzen düğme: sayfanın neresinde olursa olsun ekranın alt köşesinde durur, içerikle
64
+ kaymaz; `click`, iç rol `__press`) mobile özgüdür; `carousel` web ikizidir (`activeIndex`,
65
+ `slideChange`) ve mobilde bırakılabilir — çocukları sayfalardır.
66
+ Dördüncü adım Katalog B'yi kapattı: `timer` (mobile özgü; başlat/duraklat `isRunning`, sıfırlama `value`
67
+ yazmak; `tick { value }` her saniye, `finish`), `rating`, `multi-select` (değer `{ label, value }`
68
+ dizisi) ve `toast` web ikizleridir. `toast`ın bildirimi sayfadan bağımsız yaşar (`redirect`ten sonra da
69
+ görünür), açık modal ya da çekmecenin de üstünde çizilir; akışın tipli `alert` uyarıları cihazda da
70
+ toast'tur.
71
+ - **Katalog C** (cihaz modüllü bileşenler) medyayla başladı: `video` web ikizidir (cihazda `expo-video`,
72
+ kanvas ve önizlemede HTML5 `<video>`; `click` yalnız `controls: false` iken), `audio` (oynat/duraklat,
73
+ ilerleme izi; iç roller `__toggle`, `__track`) ve `lottie` (Lottie JSON ya da `.lottie`) mobile özgüdür.
74
+ İkisinde çalma `isPlaying` prop'udur: akış `true`/`false` yazar, bileşen `play`/`pause`/`ended` ya da
75
+ `finish` olayında `{ isPlaying }` yayar ve prop'u gerçeğe döndürür.
76
+ İkinci adım: `signature` web ikizidir (her vuruşta `change { value }` PNG data URL; vuruş sürerken sayfa
77
+ kaymaz; iOS'ta itilmiş sayfada sağa vuruş sayfayı kapatır, ARC-116) ve `webview` mobile özgüdür (web
78
+ `iframe`inin karşılığı): `src` ya da `html`; yüklemeden sonra başka belgeye giden gezinme varsayılan olarak
79
+ engellenir ve `navigate { url }` yayar, adres yalnız kullanıcının dokunduğu bağlantıda sistem tarayıcısında
80
+ açılır (`allowNavigation` görünümde açar); sayfa akışa `window.ReactNativeWebView.postMessage(metin)` →
81
+ `message { data }` ile yazar, yüklenemeyen sayfa `error` yayar.
82
+ - Web'e özgü bileşenlerin mobil karşılığı:
83
+
84
+ | Web | Mobilde |
85
+ |---|---|
86
+ | `navigations`, `sidebar`, `header`, `layout-shell` | `app-bar` + Ayarlar › Sekmeler + `drawer` widget'ı (`MOB-004`) |
87
+ | `popover` | `modal` widget'ı |
88
+ | `pagination` | `repeater` + "daha fazla yükle" düğmesi |
89
+ | `breadcrumb` | yığın gezinmesi (app-bar geri düğmesi) |
90
+ | `iframe` | `webview` (`src` ya da `html`) |
91
+ | `theme-toggle` | cihaz teması |
92
+
93
+ **Harici bileşen mobilde yoktur** (`MOB-006`): protokol v1 tarayıcı `.mjs` paketidir;
94
+ `external_component_*` araçları mobil uygulamada platforma gitmez.
95
+
96
+ ## Yerleşim — yalnız flex
97
+
98
+ Mobil çizer 12 sütunlu ızgarayı **okumaz**: sıra dizi indeksidir, yerleşim flex'tir.
99
+
100
+ - `blocks[]`, `set_block`, `layout: 'grid' | 'cssgrid'` yazılır ama çizilmez (`MOB-001`).
101
+ `add_component` / `move_component`'ın `index`'i dizideki sıradır; gateway konum çevirisi yapmaz.
102
+ - Kaplar flex kabıdır: `direction`, `gap`, `horizontalAlign`, `verticalAlign`, `wrap`, `size`.
103
+ Mobil `container` şemasında `layout` prop'u yoktur.
104
+ - Ölçü `appearance` ile: `widthType: 'fill' | 'auto' | 'fixed'` (+ `widthString`),
105
+ `heightType: 'fill' | 'auto' | 'fixed'` (+ `heightString`). `fill` kalan alanı alır.
106
+ - En-boy oranı `appearance.aspectRatio` (sayı; 16:9 için `1.78`): boy genişlikten türer. Koşullar:
107
+ `heightType: 'auto'` ve genişlik belli — `widthType: 'fill'` ya da `'fixed'` (içerik genişliğinde
108
+ web ile cihaz oranı ters yönden çözer, uygulanmaz). Web'den farkı: mobilde **akış kapları** da oran
109
+ alır (`container`, `form`, `safe-area`, `scroll-view`) ve akışları oranlı boyu doldurur; öteki
110
+ bırakılabilir tipler, widget örneği, sayfa kökü ve `modal`/`drawer` almaz; `image` oranı kendi
111
+ çizimine yazar.
112
+ - Hiza (`verticalAlign` `top | middle | bottom`, `horizontalAlign` `left | center | right`) web ile
113
+ aynıdır. Dikey hizanın boşluğu kabın boyundan gelir: `heightType` `fill`, `fixed` ya da oranlı kapta
114
+ akış kabın boyunu doldurur; boyu içerikten gelen sütun kapta dikey hiza etkisizdir (satır kapta farklı
115
+ boydaki kardeşleri yine hizalar). `stretch` de web gibi: ana eksende çocukları yayar, çapraz eksende gerer.
116
+ - Birim: `px` ve `%`. `em`/`rem` tema puntosuyla çarpılır; `calc()` ve `vw/vh` React Native'de yoktur
117
+ (`MOB-002`).
118
+
119
+ ## Görünüm — tipli gruplar
120
+
121
+ React Native'de CSS yoktur; tipli stil grupları **derlenir** (web'in `composeTypedStyle` ikizi,
122
+ aynı katman sırası: tema taban → gruplar → serbest `style`).
123
+
124
+ - `surfaceStyle` → zemin, köşe, kenarlık, gölge (tek katman), opaklık, taşma.
125
+ - `typographyStyle` → renk, aile (tek ad), punto, kalınlık, hizalama, satır yüksekliği.
126
+ - Tema token'ları (`var(--ng-*)`) sayılara çözülür; proje teması değişince mobil de değişir.
127
+
128
+ Çizilmeyen alanlar (`MOB-002`) ve yerine ne:
129
+
130
+ | Alan | Yerine |
131
+ |---|---|
132
+ | `className` | `surfaceStyle` / `typographyStyle` |
133
+ | serbest `style` nesnesi (alt seçici `&:hover`, `&__body`) | tipli gruplar; düz anahtarlar (ör. `padding`) çevrilir, alt seçici düşer |
134
+ | `hoverStyle` | yok — dokunmatikte üzerine gelme durumu yoktur |
135
+ | `tooltip`, `tooltipPosition` | düğümü `tooltip` bileşenine sarın (dokunuşla açılır, yanı `side`) ya da açıklamayı metin olarak koyun |
136
+ | `zIndex` | katman için `modal` ya da `drawer` widget'ı |
137
+
138
+ Düğümün gerçek stilini görmek: `page_runtime_get({ applicationSlug, pageSlug, resolveStyles: true })`
139
+ → her düğümde `nativeStyle: { shell, text, warnings }` (`shell` kutunun, `text` içine akan metnin
140
+ stili; RN'de tipografi miras alınmaz). Yanıtta `styleResolver: 'native'`. Temanın
141
+ `componentStyles`/preset katmanı mobil çizerde henüz uygulanmıyor ve rapora da girmez.
142
+
143
+ ## Görünüm — shadcn/ui
144
+
145
+ Bileşenler shadcn/ui görünümünde çizilir (react-native-reusables ilkelleri, NativeWind). Renk ve
146
+ köşe yine **proje temasından** gelir: `--ng-*` değişkenleri shadcn token'larına köprüyle çevrilir
147
+ (`--primary` ← `accent.primary`, `--destructive` ← hata rengi, `--border`, `--input`, `--ring`…).
148
+ `theme_update` web'i ve mobili birlikte değiştirir; koyu kip aynı köprünün ikinci çözümüdür. Ölçü
149
+ (alan yüksekliği, punto, iç boşluk) temanın `--ng-form-*` değişkenlerinden gelir. Yazı **ailesi**
150
+ köprüde yoktur: temanın ailesi alanlarda, başlıklarda ve sekme çubuğunda uygulanır; `text` ve düğme
151
+ etiketi ailesini `typographyStyle`'dan alır, alan etiketleri platform yazı tipiyle çizilir.
152
+
153
+ - `button`: `kind` rengi, `variant` kullanımını seçer — `solid` dolu (`kind: error` → shadcn
154
+ `destructive`), `outline` çerçeveli, `text`/`ghost` zeminsiz; mobilde ayrıca `secondary` (nötr
155
+ dolgu) ve `link`. `info`/`success`/`warning` → temanın `--status-*` renkleri. Eşlemenin tamamı ve
156
+ bilinen sınırlar: `component_get('button')` → `mobileKnowledge.propNotes`.
157
+ - `switch` platformun kendi anahtarı DEĞİLDİR: üç barındırıcıda (kanvas, önizleme, cihaz) aynı
158
+ shadcn anahtarı çizilir; kanvasta basılamadığı için soluk görünür.
159
+ - Web sayfası kendi bileşen ailesiyle çizilir; iki platformun görünüm farkı bilinçlidir, ortak olan
160
+ temadır. Yakalama seçicileri (`role="button"`, `__tabs__item-<slug>`, `submit` köprüsü) görünümden
161
+ bağımsızdır (§Doğrulama).
162
+
163
+ ## Gezinme
164
+
165
+ - **Yığın varsayılandır; ayar yoktur.** `redirect` adımı hedef sayfayı yığına iter, geri hareketi
166
+ (cihaz geri tuşu, app-bar geri düğmesi, tarayıcı geri) önceki ekrana döner. Göreli yol uygulama
167
+ köküne eklenir; tam adres (`https://…`) dışarıda açılır.
168
+ - **Sekmeler uygulama ayarıdır, layout'ta değil.** `application_update({ properties: { mobile: { tabs } } })`:
169
+
170
+ ```json
171
+ {
172
+ "mobile": {
173
+ "tabs": {
174
+ "enabled": true,
175
+ "style": "default",
176
+ "items": [
177
+ { "page": "<page_list id>", "label": "Görevler", "icon": "list" },
178
+ { "page": "<page_list id>", "label": "Profil", "icon": "user" }
179
+ ],
180
+ "showLabels": true
181
+ }
182
+ }
183
+ }
184
+ ```
185
+
186
+ `items` 1–5 sayfa **id**'si (slug değil), tekrar yok; `style: 'floating'` köşe `pill` + gölge `md`
187
+ çizer. Çubuğun rengi ayarda YOKTUR: zemin `surface`, seçili `accent-primary`, seçilmemiş
188
+ `text-secondary` — değiştirmek için `theme_update`; eski `appearance` alanı okunmaz; `style: 'custom'` + `customWidgetId` çubuğu kendi widget'ınla çizer. Tutarsız ayar ve
189
+ layout/sayfada eski `tab-bar` / `drawer-menu` düğümü `MOB-007` alır. Sekme dışı sayfalar yığına açılır.
190
+ - **Çekmece bir bileşendir.** `drawer` widget'ı + `app-bar`'ın `menuTarget` prop'u çekmeceyi açar.
191
+ - Kabuk örnekleri: `ngapps://examples/mobile-app-shell-stack` (yığın), `ngapps://examples/mobile-app-shell-tab`
192
+ (sekmeler), `ngapps://examples/mobile-app-shell-drawer` (çekmece); üç sayfalık liste → detay → form akışı:
193
+ `ngapps://examples/mobile-list-detail-form`.
194
+
195
+ ## Çok dil
196
+
197
+ Mobil uygulama web ile **aynı sözlüğü ve aynı motoru** kullanır (plans/mobil-coklu-dil, 2026-09-25):
198
+ `project_update(languages, defaultLanguage)` → prop'u bağla (`set_prop_type(target, prop, 'translation', ref)`)
199
+ → `translation_update`. Kurulum ve fallback zinciri `platform_guide('translation')`.
200
+
201
+ - **Dil değiştirici:** `language-selector` mobil katalogdadır (`component_get` → `mobileKnowledge`):
202
+ `dropdown`un tam ekran `Modal` listesi, tetikleyici `role="combobox"`, seçenekler dilin yerel adıyla
203
+ (`tr` → Türkçe). Seçim `machine.setLanguage` ile bütün prop'ları yerinde çözer ve cihazda uygulama
204
+ çapında yayılır: öteki sekmelerin ekranları ve sekme etiketleri de değişir, makine yeniden kurulmaz.
205
+ - **Cihazda boot sırası:** uygulama içi seçim → cihazda kayıtlı seçim (`zeyrek:<app>:lang`) → cihaz dili
206
+ → projenin varsayılanı. `?lang` CİHAZDA YOKTUR; `/preview`'da vardır, bu yüzden `page_screenshot(language:)`
207
+ mobil sayfada da çalışır — kanıt için sayfaya seçici koymak gerekmez.
208
+ - **Sekme etiketi:** `properties.mobile.tabs[].label` `t:<anahtar>` ile çevrilir (doğrulama mesajıyla aynı
209
+ önek); `mobile_app_create` `tabs[].label` de kabul eder. Sayfa adı fallback'i düz kalır.
210
+ - **Çerçeve:** cihazda `alert`/`confirm` düğmeleri (`Tamam`/`Evet`/`Hayır` ↔ `OK`/`Yes`/`No`) uygulama dilini
211
+ izler; mesaj gövdesi akışın kendi metnidir.
212
+ - **Doğrulama:** `page_screenshot({ language: 'en' })` ikinci dilin karesi;
213
+ `page_screenshot({ actions: [{ select: '<seçici elementId>', value: 'en' }] })` seçiciyi sürer
214
+ (`optionsSeen` proje dili sayısıdır); seçici sonrası sekme çubuğunun `t:` etiketleri de aynı karede
215
+ çevrilir (ölçüldü 2026-09-25: `Ana/Liste`).
216
+ - **Bilinen fark:** mobilde istemci tarafı şema doğrulaması yoktur, `t:` doğrulama mesajı akışta
217
+ (`Loc()` / `t()`) çözülür.
218
+
219
+ ## Akış adımları
220
+
221
+ Motorun kendi adımları (`setter`, `condition`, `microservice`, `code`, `function`, `flow-trigger`,
222
+ `validation`) iki platformda aynıdır. Barındırıcıya dokunan adımlar:
223
+
224
+ | Adım | Mobilde |
225
+ |---|---|
226
+ | `redirect` | yığına iter (göreli yol) ya da dışarıda açar (tam adres) |
227
+ | `navigate` | eski mobil şemaların adı — `redirect`'in takma adıdır; gateway `redirect`'e çevirir |
228
+ | `alert` | tipli uyarı (`success`/`error`/`info`/`warning`) toast'tur ve beklemez; düz uyarı onay bekler |
229
+ | `confirm` | `yes` / `no` dalları |
230
+ | `download` | adres cihazın açma sayfasında açılır, gövde paylaşım sayfasına gider (`MOB-005`, bilgi) |
231
+ | `storage` | cihaz deposu |
232
+ | `setcookie` | cihaz deposuna yazar (`MOB-005`, bilgi); paletten yalnız web'de sunulur |
233
+
234
+ Sayfa ve layout `mount` akışları ilk çizimden sonra, `destroy` akışları sayfa kalkarken koşar.
235
+ `Functions.<ad>()` uygulama ve sayfa fonksiyonlarını görür (`platform_guide('functions')`).
236
+
237
+ ## Doğrulama
238
+
239
+ - `page_screenshot({ applicationSlug, pageSlug })` mobil uygulamada `device: 'phone'` (390x844, kare
240
+ 780x1688 px) çeker; `'tablet'` 820x1180 @2 ya da `{ width, height, scale? }`. `viewport` verilirse
241
+ cihaz yok sayılır (`deviceNote`). Yanıt `applicationType: 'mobile'` ve `platformNote` taşır: kare
242
+ react-native-web çizimidir, cihazdakiyle yapısal olarak (düğüm, sıra, ölçü, renk) aynıdır.
243
+ - Eylemler aynı sözlük: `click` basılabilir öğeyi (`role="button"`) bulur; `submit` runtime
244
+ köprüsüyle gider (`submitVia: 'bridge'`); sekme öğesi `__tabs__item-<sayfa slug'ı>`, çubuk `__tabs`
245
+ özet satırıdır. `select` açılır listeyi açar ve seçeneği değerle ya da görünen metinle seçer
246
+ (liste katmanda açılır, `optionsSeen` kaç seçenek görüldüğünü söyler); `tab` bir `tabs`
247
+ bileşeninin sekmesini anahtarıyla (`<elementId>__tab-<anahtar>`) bulur.
248
+ - `flowRuns: 0` + `requests: 0` bir tıklamada akışın koşmadığını söyler: olay bağını
249
+ `page_runtime_get`, akışı `flow_get` ile doğrulayın.
250
+ - Kuru doğrulama: `page_schema_validate` mobil kataloğa karşı doğrular (`MOB-003`).
251
+
252
+ ## Cihazda önizleme
253
+
254
+ Expo uygulaması (`apps/mobile-runtime`) aynı sayfayı native çizer. Derin bağlantı
255
+ `zeyrek://open/{proje}/{uygulama}/{sayfa}?env=<ortam>` **token taşımaz**: cihazdaki uygulama zaten giriş
256
+ yapmış olmalıdır. Canlı önizleme sayfa şeması değişikliğini (`/hubs/page-schema`) dinler; yazdığın
257
+ yama cihazda yenilenir.
258
+
259
+ ## Bilinen farklar
260
+
261
+ - Piksel paritesi yoktur: yazı tipi ölçüsü, gölge ve güvenli alan cihaza göre değişir. Parite yapısaldır.
262
+ - Bileşen kataloğu dalga dalga gelir; `component_list` ne döndürüyorsa odur.
263
+ - Temanın bileşen stilleri (`componentStyles`, preset'ler) mobil çizerde henüz uygulanmıyor.
264
+ - Dar ekran kırılımı (`hideOn: 'mobile'`) mobil uygulamada anlamsızdır: ekran zaten tek boydur.
@@ -4,6 +4,10 @@ Studio'nun tuval tarafı. Buradaki kurallar controller + komut kodundan doğrula
4
4
  (`zeyrek-mcp/docs/13-faz2-envanter.md` §4); veri/mantık tarafı için
5
5
  `platform_guide('entity')`, `('microservice')`, `('workflow')`.
6
6
 
7
+ > **Mobil uygulamada** (`type: 'mobile'`) şema ve micro-op'lar aynıdır ama yerleşim yalnız flex'tir
8
+ > (blocks çizilmez), görünüm tipli gruplarla yazılır ve `page_create` kökü flex sütun kurar —
9
+ > `platform_guide('mobile')`. Bu rehberdeki "dar ekran" notları WEB uygulamasının telefon kırılımıdır.
10
+
7
11
  ## Kuruluş sırası
8
12
 
9
13
  ```
@@ -386,11 +390,8 @@ göstermek error flow'un işidir.
386
390
  > `errorTasks.some(t => t.type !== 'start')` arar. Start'ın ardına en az bir adım bağla —
387
391
  > gateway `FLOW-021` ile uyarır.
388
392
  >
389
- > **Mobilde `errorSteps` diye bir şey YOK.** `ScreenRuntime.tsx` `mapFlowsToMachine` yalnız
390
- > `tasks` üretir (web `Runtime.svelte` ayrıca `errorTasks` verir), yani mobil uygulamada
391
- > `hasErrorFlow` her zaman false: hata yolu hiç koşmaz ve akış yukarıdaki 2. yoldan —
392
- > `always` + hata gövdeli storage — devam eder. Mobil sayfada hata yolunu `condition
393
- > Steps.<adımAdı>.error` ile kur.
393
+ > **Mobil uygulama:** mobil runtime (`@ng-apps/ui-native` `NativeRuntime`) `errorSteps`'i web gibi
394
+ > `errorTasks`'a eşler — hata yolu iki platformda aynı koşar.
394
395
 
395
396
  > **Hata metni ÜÇ ayrı yerde durur ve ikisi kullanıcıya gösterilecek metin DEĞİLDİR.**
396
397
  > `onError` hata akışını koşturmadan önce `machine.setStorage('error', errorInfo)` yapar
@@ -520,14 +521,14 @@ değer tipleri: `static · page · property · storage · variable · code · it
520
521
  > tip register eder, gerisini uygulama ekler. Bir sayfa TEK bir uygulamaya aittir
521
522
  > (`Page.ApplicationId`) ve uygulamanın tipi `web` ya da `mobile`'dır (`ApplicationType.cs`), yani
522
523
  > sayfanın barındırıcısı bellidir — matris "hangi tip sende çalışır"ı söyler, iki barındırıcıda
523
- > birden koşmayı değil (web `Runtime.svelte`, mobil `ScreenRuntime.tsx`):
524
+ > birden koşmayı değil (web `Runtime.svelte`, mobil uygulama `@ng-apps/ui-native` `NativeRuntime`):
524
525
  >
525
- > | Adım tipi | Web | Mobil | Nerede register ediliyor |
526
+ > | Adım tipi | Web | Mobil uygulama | Nerede register ediliyor |
526
527
  > |---|---|---|---|
527
- > | `start` · `setter` · `code` · `condition` · `microservice` · `validation` · `flow-trigger` · `function` | ✅ | ✅ | `flow-engine.ts` — motorun kendisi (`function` mobilde kayıtlıdır ama mobil runtime `Functions`'ı boş kurar — K11, çağrı çalışmaz) |
528
- > | `alert` · `redirect` · `setcookie` · `storage` | ✅ | ✅ | uygulama; mobilde `redirect` navigate, `setcookie` storage uygulamasına eşlenir |
529
- > | `confirm` · `download` | ✅ | ❌ | yalnız `Runtime.svelte` |
530
- > | `navigate` | ❌ | ✅ | yalnız `ScreenRuntime.tsx` — web'deki karşılığı `redirect` |
528
+ > | `start` · `setter` · `code` · `condition` · `microservice` · `validation` · `flow-trigger` · `function` | ✅ | ✅ | `flow-engine.ts` — motorun kendisi |
529
+ > | `alert` · `redirect` · `setcookie` · `storage` | ✅ | ✅ | barındırıcı; mobilde `setcookie` cihaz deposuna yazar (`MOB-005`) |
530
+ > | `confirm` · `download` | ✅ | ✅ | `Runtime.svelte` · `runtime-tasks.ts` (`download` mobilde açma/paylaşım — `MOB-005`) |
531
+ > | `navigate` | ❌ | ✅ (`redirect` takma adı) | web'deki karşılığı `redirect`; gateway `redirect`'e çevirir |
531
532
  > | `end` · `query` | ❌ | ❌ | hiçbir yerde — üstelik `query` backend sözlüğünde de yok (`StepType.cs` onu saymaz), yalnız frontend enum'unda duruyor |
532
533
  >
533
534
  > **Register edilmemiş bir tipe gelen akış SESSİZCE durur.** `flow-engine.ts` `process()`
@@ -861,7 +862,7 @@ kullanır: `page.mappers.ts` `mapPageLayoutToPreview` — layout varsa çizilen
861
862
  > `add_component` ile yeniden kurmaktır (sonrasında Kural 2'deki flow yeniden kaydetme adımı
862
863
  > ZORUNLU olur).
863
864
 
864
- Mobil not: <768px'te ızgara tek kolona düşer (`RenderComponent` media query'si) — y sırası
865
+ Dar ekran notu: <768px'te ızgara tek kolona düşer (`RenderComponent` media query'si) — y sırası
865
866
  dikey sıraya dönüşür, x/w yok sayılır. Yerleşimi masaüstü (breakpoint 1024) bloğuyla kur.
866
867
 
867
868
  ## Kural 1f-2 — Kapsayıcı düzeni: `flex` (varsayılan) ↔ `grid`
@@ -950,10 +951,10 @@ Beş şeyi bilmeden flex kurma:
950
951
  4. **`layout: 'grid'` iken diğer altı prop ÖLÜDÜR.** Katalogda tanımlı oldukları için
951
952
  doğrulama duvarı susar, renderer da okumaz: ızgara kapsayıcıya `direction: 'column'` yazmak
952
953
  sessizce hiçbir şey yapmaz. Gateway bunu **PAGE-015 (uyarı)** ile söyler.
953
- 5. **Flex düzeni kırılım BİLMEZ.** `direction`/`gap`/hizalama masaüstü ve mobilde AYNIDIR;
954
- sıra ve span'lar Desktop (1024) bloğundandır — Studio, mobil kırılım düzenlenirken flex
954
+ 5. **Flex düzeni kırılım BİLMEZ.** `direction`/`gap`/hizalama masaüstü ve dar ekranda AYNIDIR;
955
+ sıra ve span'lar Desktop (1024) bloğundandır — Studio, dar ekran kırılımı düzenlenirken flex
955
956
  bölgeyi salt-okunur kilitler. Kırılım bilen yalnız `blocks[]` ve `appearance.hideOn`'dur;
956
- mobilde farklı davranış gereken satır için `layout: 'grid'` kullan (Kural 1f mobil notu).
957
+ dar ekranda farklı davranış gereken satır için `layout: 'grid'` kullan (Kural 1f dar ekran notu).
957
958
 
958
959
  ```jsonc
959
960
  // Ortalanmış giriş kartı — style ile CSS hack'i YOK, kabın kendi düzeni
@@ -1097,6 +1098,45 @@ kendisi nesneye çevirir; Studio tablosunda `[object Object]` görünmesi normal
1097
1098
  (`platform_guide('entity')` → "TEXT kolonunda JSON"). Ekranın görsel tarafı için **Kural 1h**:
1098
1099
  tema `--ng-*` değişkenleriyle tek yerden çevrilir, `html` kaçış kapısına gerek kalmaz.
1099
1100
 
1101
+ ## Kural 1g-2 — Mobil davranış: dört ayar, dört ayrı sahip
1102
+
1103
+ Mobil listelerin davranışı TEK bileşende toplanmaz. Hangi ayarın kimde olduğunu bilmeden yazılan
1104
+ şema sessizce çalışmaz — prop var olmayan bileşene yazılır ve `page_schema_patch` onu düşürmez,
1105
+ çizer yok sayar.
1106
+
1107
+ | Davranış | Sahip bileşen | Prop / olay |
1108
+ |---|---|---|
1109
+ | Çekerek yenile | `scroll-view` (listeyi SARAN kap) | `refreshable: true` + `refresh` olayı |
1110
+ | Sonsuz kaydırma | `scroll-view` | `scrollEnd` olayı (prop yok) |
1111
+ | Kaydırma eylemleri | `repeater` | `swipeActions: [{ key, label, tone, icon }]` + `swipe` olayı, payload `{ key, index, row }` |
1112
+ | Satıra dokunma | `repeater` | `itemPressable: true` + `itemPress` olayı, payload `{ index, row }` |
1113
+
1114
+ Çekerek yenileyi `repeater`'a yazmak en sık hatadır: liste kendi kaydırmasını yapmaz, onu saran
1115
+ `scroll-view` yapar. `repeater` kökteyse (kap yok) yenileme hiç çizilmez.
1116
+
1117
+ Satıra dokunmanın kartın `click`'iyle yapılan eski yolu mobilde bırakıldı: `itemPress` satır
1118
+ bağlamını payload'da taşır ve seçimi (`selectedIndex`) de yazar, yani akış satırı
1119
+ `<tekrarlayıcı>.selectedItem` ile okumaya devam eder.
1120
+
1121
+ ### `redirect.presentation`
1122
+
1123
+ `redirect` adımının `args.presentation` alanı ekranın NASIL açıldığını söyler ve kapalı bir küme
1124
+ alır:
1125
+
1126
+ - `push` — yığına ekler, geri düğmesi önceki ekrana döner (**varsayılan**; alan yazılmayabilir)
1127
+ - `modal` — alttan açılan ayrı bir sunum; geri onu kapatır, altındaki ekran yerinde kalır
1128
+ - `replace` — geçerli ekranı değiştirir, geçmişe girmez (giriş → ana ekran için doğru olan)
1129
+
1130
+ Küme dışı bir değer **MOB-008** uyarısıdır ve backend doğrulayıcısı 422 döner. Alanı hiç yazmamak
1131
+ kusur değildir.
1132
+
1133
+ **Sekme hedefinde `modal` çalışmaz.** Hedef sayfa bir sekmeyse gezinme her zaman `navigate`'e
1134
+ düşer: sekme yığını kendi geçmişini tutar ve modal onu kırardı. `presentation`ı yazabilirsiniz,
1135
+ çizer sessizce yok sayar — sekme dışı bir sayfaya modal istiyorsanız o sayfayı sekme listesinden
1136
+ çıkarın.
1137
+
1138
+ Web uygulamasında alan yok sayılır; gateway web profilinde bu konuda bulgu üretmez.
1139
+
1100
1140
  ## Kural 1h — Tasarım: `style` prop'u ve tema değişkenleri
1101
1141
 
1102
1142
  Her komponentin `style` prop'u vardır ve emotion `css()` bloğudur: iç seçiciler, pseudo-class'lar
@@ -208,7 +208,7 @@ gerekmez — `schema.ts`'e dokunulmaz, katalog yeniden yüklenmez.
208
208
  `translation_update` artık uygulamanın bütün sayfalarının önbellek satırlarını düşürüyor
209
209
  (`RefreshPageCacheWhenTranslationChangedCommand`), okuma yolu cache-aside olduğu için bir
210
210
  sonraki `page_runtime_get` taze değeri kurar. Yazmadan hemen sonra okuyabilirsin.
211
- - Mobil runtime (`apps/mobile`) bu özelliği henüz beslemiyor — yalnız web.
211
+ - Mobil uygulama runtime'ı (`@ng-apps/ui-native`, Expo) web ile aynı sözlüğü ve motoru kullanır (2026-09-25, plans/mobil-coklu-dil): `language-selector` mobil katalogda, cihazda dil sırası uygulama içi seçim → kayıtlı seçim → cihaz dili → varsayılan (`?lang` yalnız `/preview`'da), seçim uygulama çapında ve kalıcı, sekme etiketi `t:<anahtar>`, `X-Data-Language` sonraki isteklerle gider. Ayrıntı `platform_guide('mobile')` §Çok dil.
212
212
 
213
213
  ## Backend doğrulama sınırları (TR-001)
214
214
 
package/dist/server.js CHANGED
@@ -39,6 +39,7 @@ import { registerMergeTools } from "./tools/merges.js";
39
39
  import { registerRevisionTools } from "./tools/revisions.js";
40
40
  import { registerActivityTools } from "./tools/activities.js";
41
41
  import { registerDtoTools } from "./tools/dtos.js";
42
+ import { registerMobileTools } from "./tools/mobile.js";
42
43
  const moduleRegistrations = {
43
44
  platform: registerPlatformTools,
44
45
  project: registerProjectTools,
@@ -80,6 +81,7 @@ const moduleRegistrations = {
80
81
  merge: registerMergeTools,
81
82
  activity: registerActivityTools,
82
83
  revision: registerRevisionTools,
84
+ mobile: registerMobileTools,
83
85
  };
84
86
  export function createGatewayServer(platform) {
85
87
  const server = rejectUnknownArguments(instrumentServer(new McpServer({ name: "ngapps", version: "0.1.0" }), platform.config));
@@ -1,6 +1,44 @@
1
1
  import { guid, pagingParams, readOnly, writes, updates, destructive } from './common.js';
2
2
  import { handle } from '../platform/responses.js';
3
+ import { forgetApplication, readApplicationPlatform, resolveApplication } from '../knowledge/platform/resolve.js';
4
+ import { mobileTabsProblems, readMobileTabs } from '../knowledge/platform/mobileTabs.js';
5
+ import { findingLine } from '../knowledge/platform/profile.js';
3
6
  import { z } from 'zod';
7
+ /**
8
+ * MOB-007 (sekme ayarı) — `properties.mobile.tabs` yazan mobil uygulama çağrısının denetimi. Yazım
9
+ * platforma YİNE gider (D3; backend `properties`'i doğrulamaz): bulgu `platformWarnings`'e düşer.
10
+ * Sayfa ve widget listesi okunamazsa o denetimler atlanır, biçim denetimi yine koşar.
11
+ */
12
+ export async function mobileTabsWarnings(platform, applicationId, projectSlug, homepageId, properties) {
13
+ const tabs = readMobileTabs(properties);
14
+ if (tabs === undefined)
15
+ return [];
16
+ const pages = applicationId && projectSlug
17
+ ? await platform.tenant('GET', projectSlug, `/pages/${applicationId}`, { query: { pageIndex: 0, pageLength: 200 } })
18
+ .then(response => (response?.data ?? []).map(page => ({ id: String(page.id ?? '') })))
19
+ .catch(() => undefined)
20
+ : undefined;
21
+ const widgetIds = applicationId && projectSlug
22
+ ? await platform.tenant('GET', projectSlug, `/components/${applicationId}`, { query: { pageIndex: 0, pageLength: 999 } })
23
+ .then(response => new Set((response?.data ?? []).filter(entry => entry.kind === 'widget').map(entry => String(entry.id ?? ''))))
24
+ .catch(() => undefined)
25
+ : undefined;
26
+ return mobileTabsProblems(tabs, {
27
+ ...(pages ? { pages } : {}),
28
+ ...(homepageId ? { homepageId } : {}),
29
+ ...(widgetIds ? { widgetIds } : {})
30
+ }).map(message => findingLine({
31
+ code: 'MOB-007',
32
+ severity: 'warn',
33
+ message,
34
+ guide: "platform_guide('mobile') §Gezinme"
35
+ }));
36
+ }
37
+ function withPlatformWarnings(response, warnings) {
38
+ if (warnings.length === 0 || !response || typeof response !== 'object' || Array.isArray(response))
39
+ return response;
40
+ return { ...response, platformWarnings: warnings };
41
+ }
4
42
  export function registerApplicationTools(server, platform) {
5
43
  const config = platform.config;
6
44
  server.registerTool('application_list', {
@@ -34,7 +72,14 @@ export function registerApplicationTools(server, platform) {
34
72
  notFoundPageId: guid.optional()
35
73
  },
36
74
  annotations: writes
37
- }, handle(config, ({ projectId, ...body }) => platform.org('POST', `/applications/${projectId}`, { body })));
75
+ }, handle(config, async ({ projectId, ...body }) => {
76
+ const warnings = readApplicationPlatform(body.type) === 'mobile'
77
+ ? await mobileTabsWarnings(platform, undefined, undefined, undefined, body.properties)
78
+ : [];
79
+ const response = await platform.org('POST', `/applications/${projectId}`, { body });
80
+ forgetApplication(platform);
81
+ return withPlatformWarnings(response, warnings);
82
+ }));
38
83
  server.registerTool('application_update', {
39
84
  title: 'Application güncelle',
40
85
  description: 'Application bilgilerini günceller; homepageId zorunludur (mevcut değeri application_get ile alın).',
@@ -49,11 +94,23 @@ export function registerApplicationTools(server, platform) {
49
94
  notFoundPageId: guid.optional()
50
95
  },
51
96
  annotations: updates
52
- }, handle(config, ({ id, ...body }) => platform.org('PUT', `/applications/${id}`, { body })));
97
+ }, handle(config, async ({ id, ...body }) => {
98
+ const current = await resolveApplication(platform, id);
99
+ const warnings = current?.platform === 'mobile'
100
+ ? await mobileTabsWarnings(platform, id, current.projectSlug, body.homepageId, body.properties)
101
+ : [];
102
+ const response = await platform.org('PUT', `/applications/${id}`, { body });
103
+ forgetApplication(platform, id);
104
+ return withPlatformWarnings(response, warnings);
105
+ }));
53
106
  server.registerTool('application_delete', {
54
107
  title: 'Application sil',
55
108
  description: 'Application\'ı kalıcı olarak siler.',
56
109
  inputSchema: { id: guid },
57
110
  annotations: destructive
58
- }, handle(config, args => platform.org('DELETE', `/applications/${args.id}`)));
111
+ }, handle(config, async (args) => {
112
+ const response = await platform.org('DELETE', `/applications/${args.id}`);
113
+ forgetApplication(platform, args.id);
114
+ return response;
115
+ }));
59
116
  }