@appaflytech/zeyrek-ai-mcp 0.0.34 → 0.0.36

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.
@@ -99,18 +99,18 @@ export const componentEventContracts = {
99
99
  mount: NO_DATA,
100
100
  change: {
101
101
  payload: { value: 'FilterGroup (iç içe and/or kural ağacı)', jexl: 'string (aynı ağacın hazır jexl ifadesi)' },
102
- reads: "setter yalnız `value`yi self’e yazar; `jexl` YALNIZ event.data’dadır (params) — sorguya bağlayacağın alan odur"
102
+ reads: "setter yalnız `value`yi self’e yazar; `jexl` YALNIZ event.data’dadır (params) — sorguya bağlayacağın alan odur. `value` (ağaç) de event.data’da gelir — State’e geri yazmak için event.data.value’yu kullan. Ağaç değişmediyse (etkin birleştiriciye yeniden basmak) olay yayılmaz"
103
103
  }
104
104
  },
105
105
  comments: {
106
106
  mount: NO_DATA,
107
107
  submit: {
108
108
  payload: { text: 'string', parentId: "string (yanıtsa üst yorumun id’si, kök yorumda '')", mentions: 'string[] (metinden çözülmüş @kişi listesi)', author: 'string (currentUser)' },
109
- reads: 'Komponent yorumu ANINDA iyimser olarak listeye ekler (bekleyen katman); kalıcılık akışın işidir — rows tazelenmezse bekleyen satır bir sonraki içerik değişiminde kaybolur'
109
+ reads: 'Yük YALNIZ event.data’dadır (self.text/self.mentions boş gelir): {{ event.data.text }}. Komponent yorumu ANINDA iyimser olarak listeye ekler (bekleyen katman); kalıcılık akışın işidir — bekleyen satır, rows’a aynı üst yorum + metin (+ yazar) ile YENİ bir satır gelince yerini ona bırakır; akış kaydetmezse ya da metni değiştirirse "gönderiliyor…" kalır'
110
110
  },
111
- like: { payload: { id: 'string', liked: 'boolean (yeni durum)', author: 'string (currentUser — işlemi yapan)' }, reads: 'beğeni de iyimserdir; sayaç rows tazelenene kadar yerel. isDisabled/isReadonly/isViewmode açıkken yayılmaz' },
112
- edit: { payload: { id: 'string', text: 'string (yeni metin)', author: 'string (currentUser — işlemi yapan)' }, reads: 'düzenleme de iyimserdir; yeni metin "düzenlendi" işaretiyle rows tazelenene kadar yerel. Metin değişmediyse yayılmaz' },
113
- delete: { payload: { id: 'string', author: 'string (currentUser — işlemi yapan)' }, reads: 'satır (kök yorumsa yanıtlarıyla birlikte) listeden hemen gizlenir; uca yazmak akışın işidir' }
111
+ like: { payload: { id: 'string', liked: 'boolean (yeni durum)', author: 'string (currentUser — işlemi yapan)' }, reads: 'Yük yalnız event.data’dadır. Beğeni de iyimserdir; sayaç rows tazelenene kadar yerel. isDisabled/isReadonly/isViewmode açıkken yayılmaz' },
112
+ edit: { payload: { id: 'string', text: 'string (yeni metin)', author: 'string (currentUser — işlemi yapan)' }, reads: 'Yük yalnız event.data’dadır. Düzenleme de iyimserdir; yeni metin "düzenlendi" işaretiyle rows tazelenene kadar yerel. Metin değişmediyse yayılmaz' },
113
+ delete: { payload: { id: 'string', author: 'string (currentUser — işlemi yapan)' }, reads: 'Yük yalnız event.data’dadır. Satır (kök yorumsa yanıtlarıyla birlikte) listeden hemen gizlenir; uca yazmak akışın işidir' }
114
114
  },
115
115
  'auth-layout': { mount: NO_DATA, primaryClick: NO_DATA, secondaryClick: NO_DATA },
116
116
  layout: { mount: NO_DATA, logout: NO_DATA },
@@ -345,7 +345,7 @@ export const componentEventContracts = {
345
345
  'audit-basic': { mount: NO_DATA },
346
346
  'audit-history': {
347
347
  mount: NO_DATA,
348
- showMore: { payload: {}, reads: 'yalnız histories visibleLogCount’u aşınca çıkan "Daha fazla göster" düğmesine basılınca; görünür sınır visibleLogCount kadar büyür, kalan kalmayınca düğme kaybolur. Bileşen veri çekmez; backend kayıt başına en fazla 5 işlem verdiği için meta.history bağlıyken düğme ancak visibleLogCount < 5 iken çıkar' }
348
+ showMore: { payload: {}, reads: 'yalnız histories visibleLogCount’u aşınca çıkan "Daha fazla göster" düğmesine basılınca; görünür sınır visibleLogCount kadar büyür, kalan kalmayınca düğme kaybolur; en yeni (ilk) girdi değişince sınır başa döner. Bileşen veri çekmez; backend kayıt başına en fazla 5 işlem verdiği için meta.history bağlıyken düğme ancak visibleLogCount < 5 iken çıkar' }
349
349
  },
350
350
  'form-validation-errors': { mount: NO_DATA },
351
351
  'page-header': {
@@ -371,7 +371,7 @@ export const componentEventContracts = {
371
371
  },
372
372
  click: {
373
373
  payload: {},
374
- reads: 'Yalnız akışa bağlıysa sarmalayıcı tıklanabilir olur; controls açıkken oynat/duraklat düğmesine basmak da bu olayı tetikler (tıklama sarmalayıcıya kabarır). isLoading:true iken HİÇ çalışmaz — o dalda oynatıcı yerine iskelet çizilir ve sarmalayıcı tıklanabilir değildir'
374
+ reads: "Yalnız akışa bağlıysa çalışır (sarmalayıcı <div>; controls:false iken role=button + Enter/Boşluk da tetikler); controls açıkken videonun YÜZEYİNE tıklamak hem oynatır hem bu olayı tetikler, kontrol çubuğundaki yerel oynat/duraklat düğmesi ise videoyu oynatır AMA bu olayı TETİKLEMEZ (ölçüldü 2026-10-05). isLoading:true iken HİÇ çalışmaz — o dalda oynatıcı yerine iskelet çizilir ve sarmalayıcı tıklanabilir değildir"
375
375
  },
376
376
  play: {
377
377
  payload: { isPlaying: 'boolean (true)' },
@@ -384,6 +384,14 @@ export const componentEventContracts = {
384
384
  ended: {
385
385
  payload: { isPlaying: 'boolean (false)' },
386
386
  reads: 'loop açıkken HİÇ yayılmaz (döngü videosu bitmez). event.data: { currentTime, duration } — bitişte currentTime pratikte duration’a eşittir. Bitişte pause’dan SONRA gelir (spesifikasyon sırası), yani ended akışı pause akışının ardından koşar'
387
+ },
388
+ load: {
389
+ payload: {},
390
+ reads: "Kaynağın İLK KARESİ hazır olunca (loadeddata) yayılır; kaynak her değiştiğinde yeniden. Değer yazmaz (setter yok). event.data: { duration: number (saniye; sonsuz ya da bilinmiyorsa 0), width: number, height: number (kaynağın kendi piksel boyu) }. Yalnız oynatıcı çizilirken yayılır: isLoading:true iken <video> yoktur, load gelmez (iskeleti kaynağı çözen sorgudan kapat). Boş src'de ya da error'da yayılmaz"
391
+ },
392
+ error: {
393
+ payload: {},
394
+ reads: "Kaynak yüklenemediğinde yayılır (404, video olmayan dosya, desteklenmeyen biçim, ağ kopması). Değer yazmaz, ama isPlaying true ise false'a düşer. event.data: { code: number (MediaError.code: 1 iptal · 2 ağ · 3 çözümleme · 4 kaynak yok/desteklenmiyor), message: string (tarayıcıya bağlı, çoğu kez boş) }. Bileşen kendi hata görünümü çizmez: siyah kutu kalır, kullanıcıya bildirmek akışın işidir. Boş src'de yayılmaz"
387
395
  }
388
396
  },
389
397
  // — 2026-08-25 eşleme turu: ng-apps-ui'da olay YAYAN ama burada kaydı olmayan komponentler.
@@ -662,7 +670,7 @@ export const componentEventContracts = {
662
670
  fileName: 'string (okunan dosyanın adı; henüz dosya yoksa "")',
663
671
  rowCount: 'number (dosyadaki HAM veri satırı sayısı — doğrulamadan önce)'
664
672
  },
665
- reads: "adım her değiştiğinde yayılır; currentStep ve fileName düğüme de yazılır (self.currentStep), rowCount yalnız event.data'dadır"
673
+ reads: "adım her değiştiğinde yayılır; currentStep ve fileName düğüme de yazılır (self.currentStep), rowCount yalnız event.data'dadır. resetAfterComplete açıkken complete'ten hemen sonra { currentStep: 0, fileName: tamamlanan dosya, rowCount: 0 } ile bir kez daha yayılır"
666
674
  },
667
675
  complete: {
668
676
  payload: {
@@ -2,6 +2,7 @@ import { logStep } from '../observability/trace.js';
2
2
  import { PlatformApiError } from '../platform/errors.js';
3
3
  import { ensureWorkflowErrorPath } from './errorPath.js';
4
4
  import { TYPED_STYLE_COMPONENTS } from './styleResolve.js';
5
+ import { FUNCTIONS_NAMESPACE } from './functionGuards.js';
5
6
  const SORT_DEFAULT = { name: 'sortField', type: 'sortType', source: 'query-string' };
6
7
  const LIMIT_DEFAULT = { name: 'limit', offset: 'offset', source: 'query-string' };
7
8
  function asArray(value) {
@@ -358,6 +359,7 @@ const REQUIRED_COLLECTIONS = ['events', 'validations', 'stateBindings', 'childre
358
359
  *
359
360
  * - `states`: DesignComponentManagementSchema.ToDomain:47 `States.IsSticky`'yi guard'sız okur;
360
361
  * Appearance'ın satır 24'te varsayılanı var, States'in yok.
362
+ * - `blocks` doldurulmaz: konum ebeveynin düzenine bağlıdır, eksikse PAGE-037 ile reddedilir.
361
363
  * - `events` / `validations` / `stateBindings`: yalnız **micro-op yolunda** zorunlu.
362
364
  * `page_create` (POST /pages) bunlarsız 200 döner, `PATCH …/schema` NRE verir; canlı deneyde
363
365
  * üçü birlikte verilince geçti, her biri tek başına verilince patladı (klinik H-005 eki).
@@ -656,6 +658,11 @@ export function styleKeyNote(fixed) {
656
658
  + 'değer kaydedilir ama hiç uygulanmaz ve tek işareti tarayıcı konsoludur (F-06). '
657
659
  + "Seçici anahtarlara ('&__body', ':hover', '--token') dokunulmadı."];
658
660
  }
661
+ /** PAGE-009 ile aynı kural: JS tanımlayıcısı (tireler çıkarılınca) ve ayrılmış `Functions` değil. */
662
+ function isDerivableComponentName(name) {
663
+ const bare = name.replace(/-/g, '');
664
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(bare) && bare !== FUNCTIONS_NAMESPACE;
665
+ }
659
666
  /**
660
667
  * Y-15 — adı eksik, null ya da boş/boşluk olan düğüm runtime'ın ifade ön sözünü bozar: `getNodeNames`
661
668
  * null adı `"null"` anahtarına çevirir, `runCode` `const null = Components["null"]` satırını üretir
@@ -664,6 +671,7 @@ export function styleKeyNote(fixed) {
664
671
  * hiç denetlemez (`PageSchemaValidator.cs`); Studio her düğüme `name = elementId` yazar
665
672
  * (`ScreenBuilderDroppable.svelte`). Kural deterministik olduğu için reddetmek yerine dolduruyoruz.
666
673
  * Doldurulan ad da PAGE-009'dan geçmek zorunda: çağıran bunu denetimden ÖNCE koşar. Dolu ada dokunulmaz.
674
+ * `normalizeComponentDefaults` aynı boşluğu yalnız geçerli bir elementId için ikinci kez kapatır (güvenlik ağı).
667
675
  */
668
676
  export function fillComponentNames(nodes) {
669
677
  const filled = [];
@@ -688,6 +696,16 @@ export function normalizeComponentDefaults(nodes) {
688
696
  const fixed = [];
689
697
  for (const node of asObjects(nodes)) {
690
698
  const missing = [];
699
+ // name'siz düğümü platform kabul eder ama sayfada bir akış ya da `{{ }}` kod prop'u varsa
700
+ // FlowEngine runCode "Cannot read properties of undefined (reading 'catch')" ile düşer, akış
701
+ // `running:1`'de takılır ve hata adsız düğümü işaret etmez (image ölçüm turu, 2026-10-04).
702
+ // Yalnız PAGE-009'un geçerli saydığı elementId'den türetilir: page_create/page_update/layout
703
+ // yollarında PAGE-009 denetimi bu normalizasyondan ÖNCE koşar; bozuk bir elementId'den türeyen
704
+ // ad denetimi atlatıp "Missing initializer in const declaration" ile sayfayı öldürürdü.
705
+ if ((typeof node.name !== 'string' || node.name.trim() === '') && typeof node.elementId === 'string' && isDerivableComponentName(node.elementId)) {
706
+ node.name = node.elementId;
707
+ missing.push('name');
708
+ }
691
709
  if (!node.states || typeof node.states !== 'object') {
692
710
  node.states = { ...DEFAULT_STATES };
693
711
  missing.push('states');
@@ -2722,6 +2722,29 @@ export const policyRules = [
2722
2722
  return findings;
2723
2723
  })
2724
2724
  },
2725
+ {
2726
+ id: 'FLOW-027',
2727
+ module: 'flow',
2728
+ appliesTo: ['create', 'update'],
2729
+ sourceRef: "2026-10-01 kanban ölçüm turu: steps ve errorSteps'te AYNI stepId ('start') flow_create'te 500 `An item with the same key has already been added. Key: start [ArgumentException]` verdi — platform adımları tek sözlüğe stepId anahtarıyla koyuyor, hata mesajı çakışmanın stepId olduğunu söylemiyor",
2730
+ check: definition => {
2731
+ const counts = new Map();
2732
+ for (const step of flowAllSteps(definition)) {
2733
+ if (!step.stepId)
2734
+ continue;
2735
+ counts.set(step.stepId, (counts.get(step.stepId) ?? 0) + 1);
2736
+ }
2737
+ const repeated = [...counts].filter(([, count]) => count > 1).map(([stepId]) => stepId);
2738
+ return repeated.length === 0
2739
+ ? []
2740
+ : [{
2741
+ ruleId: 'FLOW-027',
2742
+ severity: 'block',
2743
+ message: `stepId'ler akışta (steps + errorSteps birlikte) benzersiz olmalı; tekrar edenler: ${repeated.map(id => `'${id}'`).join(', ')}. Platform bunları tek sözlüğe anahtar olarak koyar ve "An item with the same key has already been added" ile 500 verir (mesaj stepId'den söz etmez). errorSteps'te de kendi 'start' adımı gerekiyorsa ona farklı bir stepId verin (örn. 'err_start').`,
2744
+ guide: 'ngapps://guides/page'
2745
+ }];
2746
+ }
2747
+ },
2725
2748
  {
2726
2749
  id: 'MS-013',
2727
2750
  module: 'microservice',
@@ -395,7 +395,9 @@ const STATCARD_FLEX_ALIGN = {
395
395
  left: 'flex-start',
396
396
  center: 'center',
397
397
  right: 'flex-end',
398
- justify: 'stretch'
398
+ justify: 'stretch',
399
+ start: 'flex-start',
400
+ end: 'flex-end'
399
401
  };
400
402
  function composeStatCardParts(input, root) {
401
403
  const value = input.valueStyle;
@@ -496,6 +498,18 @@ export const TYPED_STYLE_COMPONENTS = {
496
498
  groups: ['surfaceStyle'],
497
499
  ext: { overflowTarget: ROOT_TARGET }
498
500
  },
501
+ modal: {
502
+ // Panel portal ile düğüm kutusunun DIŞINA çizilir; yüzey panelin KÖKÜNDE
503
+ // derlenir, taşma da panelin köküne iner (modal ölçümü, 2026-10-05).
504
+ groups: ['surfaceStyle'],
505
+ ext: { overflowTarget: ROOT_TARGET }
506
+ },
507
+ drawer: {
508
+ // Panel portal ile düğüm kutusunun DIŞINA çizilir; yüzey panelin KÖKÜNDE
509
+ // derlenir, taşma da panelin köküne iner (drawer ölçümü, 2026-10-05).
510
+ groups: ['surfaceStyle'],
511
+ ext: { overflowTarget: ROOT_TARGET }
512
+ },
499
513
  icon: {
500
514
  // Yalnız hover: surface çipin (chipShape/chipColor), typography da boyutun
501
515
  // (size) ve rengin (color) çift kanalı olurdu — görsel kararlar semantik
@@ -517,8 +531,6 @@ export const NODE_SURFACE_TYPES = new Set([
517
531
  'table',
518
532
  'datatable',
519
533
  'collapsible-container',
520
- 'drawer',
521
- 'modal',
522
534
  'popover',
523
535
  'tabs',
524
536
  'stepper',
@@ -29,7 +29,7 @@
29
29
  * `theme_get` bunları `unknownKeys` olarak gösterir, `theme_update` şeması reddeder.
30
30
  */
31
31
  export const THEME_TOP_LEVEL_KEYS = [
32
- 'mode', 'palette', 'paletteDark', 'fontFamily', 'headingFontFamily', 'typeScale',
32
+ 'mode', 'direction', 'palette', 'paletteDark', 'fontFamily', 'headingFontFamily', 'typeScale',
33
33
  'fontSize', 'fontWeight', 'borderRadius', 'radiusScale', 'spacing', 'spacingScale',
34
34
  'shadow', 'defaultInputSize', 'colors', 'actions', 'presets', 'componentStyles',
35
35
  'componentPresets'
@@ -30,7 +30,7 @@ export function summarizeTheme(theme) {
30
30
  if (entries.length > 0)
31
31
  overrides[key] = entries;
32
32
  }
33
- for (const key of ['fontFamily', 'headingFontFamily', 'fontSize', 'fontWeight', 'spacing', 'borderRadius', 'defaultInputSize']) {
33
+ for (const key of ['fontFamily', 'headingFontFamily', 'fontSize', 'fontWeight', 'spacing', 'borderRadius', 'defaultInputSize', 'direction']) {
34
34
  if (record[key] !== undefined)
35
35
  overrides[key] = record[key];
36
36
  }
@@ -91,6 +91,7 @@ const ratioScale = (levels) => z.object(Object.fromEntries(levels.map(level => [
91
91
  */
92
92
  export const themeInput = z.object({
93
93
  mode: z.enum(['light', 'dark']),
94
+ direction: z.enum(['ltr', 'rtl', 'auto']),
94
95
  palette: paletteSchema,
95
96
  paletteDark: paletteSchema,
96
97
  fontFamily: z.string().min(1),
@@ -127,7 +127,7 @@ Her şema düğümünde iki sözlük vardır; ikisi de ortak render katmanında
127
127
 
128
128
  | `appearance` | Değerler | Anlamı |
129
129
  |---|---|---|
130
- | `heightType` | `auto` · `fixed` · `fill` | `auto`: içerik kadar (önerilen — Kural 1d); `fixed`: `heightString` varsa o, yoksa `blocks.h × 10px`; `fill`: **kalanı doldur** — ebeveynin bıraktığı yer (ızgarada `height:100%`, flex sütununda `flex:1 1 auto`, flex satırında `align-self:stretch`). Tam ekran yerleşim kabuğu bununla kurulur, bkz. `platform_guide('layout')` |
130
+ | `heightType` | `auto` · `fixed` · `fill` | `auto`: içerik kadar (önerilen — Kural 1d); `fixed`: `heightString` varsa o, yoksa `blocks.h × 10px`; `fill`: **kalanı doldur** — ebeveynin bıraktığı yer (ızgarada `height:100%`, flex sütununda `flex:1 1 auto`, flex satırında `align-self:stretch`). Tam ekran yerleşim kabuğu bununla kurulur, bkz. `platform_guide('layout')`. **Mobilde (≤ 767 px) mobil bloğu olmayan her düğüme `height: auto !important` yazılır**: yüksekliği `height` olarak yazılan `fixed` düğüm (flex ya da CSS grid ebeveyni, stretch yokken) içeriğine göre çizilir; stretch'li satırdaki `min-height` ve 12 kolonlu eski ebeveynin `grid-row` yüksekliği bundan bağımsızdır. Yazılı yüksekliği mobilde de istiyorsan (`heightType: 'fixed'` iken) `appearance.className`'e ayrılmış **`ng-keep-height-mobile`** belirtecini yaz (`className: "hero ng-keep-height-mobile"`) |
131
131
  | `widthType` | `cover` · `contain` · `auto` · `fixed` · `fill` | İlk ikisi görsel/medya sığdırma. Kalanı **flex (ve eski cssgrid) kabın çocuğunun genişlik modu** (2026-09-01): `auto` içerik kadar, `fixed` `widthString`'den, `fill` kabın tüm genişliği (satırda `flex:1 1 100%`, sütunda `align-self:stretch`). **Yazılmazsa eski 12 kolon `blocks.size.w` payı geçerlidir** — öncelik: `fill` > `fixed` > `auto` > span |
132
132
  | `widthString` / `heightString` | CSS uzunluğu | Sabit ölçü; **yalnız ilgili `*Type: 'fixed'` iken okunur** (aksi PAGE-017 uyarısı). Kabul: çıplak sayı (px sayılır) · `px % vw vh vmin vmax rem em ch` birimli değer · `calc(...)`. Negatif/`pt`/`fr`/`auto` GEÇMEZ — platform kaydeder ama panel ve runtime sessizce düşürür (PAGE-018). Eski `widthPx` alanı 2026-09-01'de kaldırıldı |
133
133
  | `marginType` / `marginValue` | `normal` · `none` · `custom` + px | Dış boşluk: **yazılmazsa `normal` sayılır** = her kenara 4px (`spacing.ts` `CANVAS_NORMAL_MARGIN`); custom=`marginValue`. Bileşenleri dip dibe dizmek için `none` ŞART — `gap:'none'` olsa bile normal margin komşular arasında 8px bırakır (sıkı dizilim tarifi: `platform_guide('page')` Kural 1f-2) |
@@ -670,6 +670,14 @@ Tire yerine `_` kullan.
670
670
  > `component_schema_patch` yamalarında), `layout_create`, `layout_update(views)` ve `layout_patch`;
671
671
  > `page_schema_validate` aynı kararı verir. Ad doldurulduktan sonra denetlenir: geçersiz bir
672
672
  > elementId adsız gelirse o da reddedilir.
673
+ >
674
+ > **`name` hiç verilmezse** gateway onu `elementId` ile tamamlar ve `gatewayNormalized`'da `name`
675
+ > diye bildirir: adsız düğümü platform kabul eder ama sayfada bir akış ya da `{{ }}` kod prop'u
676
+ > varsa FlowEngine `runCode` "Cannot read properties of undefined (reading 'catch')" ile düşer, akış
677
+ > `running:1`'de takılır ve hata adsız düğümü işaret etmez. Tamamlama PAGE-009 denetiminden ÖNCE
678
+ > koşar, yani `elementId` bu kuralın geçerli saydığı bir ad değilse (`'Ana Baslik'`, `'1abc'`,
679
+ > `'Functions'`) tamamlanan ad da reddedilir. Yine de her `add_component` gövdesine
680
+ > `name = elementId` yaz; tamamlama bir güvenlik ağıdır.
673
681
 
674
682
  ## Kural 1d — Sayfa iskeleti: `page_container` ve boyutlandırma
675
683
 
@@ -18,6 +18,7 @@ yazmalarının aksine burada "önce development'ta dene" diye bir ayrım YOKTUR.
18
18
  | Alan | Ne yapar | Ürettiği değişken(ler) |
19
19
  |---|---|---|
20
20
  | `mode` | `'light'` (varsayılan) \| `'dark'` — yayınlanan uygulamanın modu | palet tabanını seçer |
21
+ | `direction` | `'ltr'` \| `'rtl'` \| `'auto'` — sayfanın okuma yönü; `auto` uygulama dilinden türetir (`ar` `he` `fa` `ur` `ps` `sd` `ug` `yi` `dv` → rtl). Ayar YOKSA `dir` hiç yazılmaz (sayfa üst öğenin yönünü miras alır): `ar` ile kurulmuş mevcut proje bu ayar açılmadan aynalanmaz. Sayfa oluşturucu tuvali yönü uygulamaz. Grid yerleşimi kendiliğinden aynalanır; bileşenlerin ok simgeleri ve fiziksel `left/right` CSS'i bileşen bazında düzeltilir (ADR 0006) | CSS değişkeni üretmez, kap `dir` özniteliğine yazılır |
21
22
  | `palette` | AYDINLIK moddaki renk override'ları; `accent.onPrimary` isteğe bağlıdır — accent ÜSTÜNDEKİ metin, verilmezse kontrasttan türer (`#4787FA` gibi açık bir mavi siyah metin üretir, tasarımda beyazsa buraya yazın) | `--ng-accent-*` · `--ng-background-*` · `--ng-text-*` · `--ng-border-*` · `--ng-status-*` · `--ng-text-on-accent` |
22
23
  | `paletteDark` | KARANLIK moddaki renk override'ları | aynı küme |
23
24
  | `fontFamily` · `headingFontFamily` | Gövde ve başlık yazı tipi (Google Fonts adı) | `--ng-font` · `--ng-font-heading` |
@@ -1,6 +1,6 @@
1
1
  {
2
- "hash": "06f7d6b64937424fcbe7a9c8751e90a5224556e0c970199fb199cfa3a147c7d2",
3
- "generatedAt": "2026-09-28T09:04:34.182Z",
2
+ "hash": "1ea20d454bfd3bb21195dca2930f57e7fbf7c6398d2e416566165c9075b0941e",
3
+ "generatedAt": "2026-09-28T21:44:24.531Z",
4
4
  "types": 186,
5
5
  "files": 108,
6
6
  "note": "Şemaları üreten backend kaynaklarının parmak izi. Elle düzenlemeyin: 'npm run generate-schemas' yazar, 'npm run schema:check' denetler.",
@@ -249,7 +249,8 @@
249
249
  "global-function",
250
250
  "view",
251
251
  "enum-values",
252
- "translation"
252
+ "translation",
253
+ "monitoring"
253
254
  ],
254
255
  "type": "string",
255
256
  "format": ""
@@ -428,8 +428,14 @@ export function registerFlowTools(server, platform) {
428
428
  };
429
429
  const authored = { steps: steps ?? [], errorSteps: errorSteps ?? [] };
430
430
  const normalized = [...normalizeFlowSteps(authored.steps), ...normalizeFlowSteps(authored.errorSteps)];
431
+ // Kurallar yalnız GÖNDERİLEN adımlara bakar (kayıtlı gövdeyi suçlamamak için); stepId
432
+ // benzersizliği ise birleşik akışta ölçülür: yalnız steps verilip kayıtlı errorSteps'le
433
+ // çakışan kimlik de platformda 500 verir.
431
434
  const findings = steps || errorSteps
432
- ? enforcePolicy(evaluatePolicy(config, policyRules, 'flow', authored, { operation: 'update' }, policyOverride))
435
+ ? [
436
+ ...enforcePolicy(evaluatePolicy(config, policyRules, 'flow', authored, { operation: 'update' }, policyOverride)),
437
+ ...enforcePolicy(evaluatePolicy(config, policyRules, 'flow', flow, { operation: 'update' }, policyOverride).filter(finding => finding.ruleId === 'FLOW-027'))
438
+ ]
433
439
  : [];
434
440
  const parameterWarnings = [
435
441
  ...await requiredParameterWarnings(platform, project, environment, applicationId, flow.steps),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appaflytech/zeyrek-ai-mcp",
3
- "version": "0.0.34",
3
+ "version": "0.0.36",
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",