@appaflytech/zeyrek-ai-mcp 0.0.22 → 0.0.24

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 (50) hide show
  1. package/.env.example +15 -0
  2. package/dist/config.js +9 -0
  3. package/dist/index.js +2 -0
  4. package/dist/knowledge/componentCatalog.js +4 -2
  5. package/dist/knowledge/componentEvents.js +3 -3
  6. package/dist/knowledge/mobileComponentCatalog.js +308 -50
  7. package/dist/knowledge/mobileComponentEvents.js +130 -3
  8. package/dist/knowledge/normalize.js +16 -6
  9. package/dist/knowledge/platform/lint.js +110 -3
  10. package/dist/knowledge/platform/mobile.js +1 -1
  11. package/dist/knowledge/platform/mobileRules.js +70 -11
  12. package/dist/knowledge/platform/web.js +1 -1
  13. package/dist/knowledge/rules.js +106 -11
  14. package/dist/knowledge/styleResolve.js +49 -3
  15. package/dist/knowledge/styleResolveNative.js +104 -4
  16. package/dist/observability/trace.js +1 -1
  17. package/dist/platform/argumentAliases.js +128 -0
  18. package/dist/platform/bodyFile.js +103 -0
  19. package/dist/platform/capture/capture.js +29 -5
  20. package/dist/platform/capture/console-log.js +80 -0
  21. package/dist/platform/capture/index.js +1 -0
  22. package/dist/platform/diagnostics.js +10 -4
  23. package/dist/platform/http.js +23 -7
  24. package/dist/platform/responses.js +6 -2
  25. package/dist/platform/schemaReadMemory.js +60 -0
  26. package/dist/platform/secrets.js +9 -0
  27. package/dist/platform/strictArguments.js +68 -12
  28. package/dist/platform/tokenVault.js +187 -4
  29. package/dist/resources/guides/expressions.md +1 -1
  30. package/dist/resources/guides/microservice.md +9 -2
  31. package/dist/resources/guides/middleware.md +5 -1
  32. package/dist/resources/guides/mobile.md +165 -10
  33. package/dist/resources/guides/page.md +161 -41
  34. package/dist/resources/guides/theme.md +4 -1
  35. package/dist/resources/guides/workflow.md +7 -1
  36. package/dist/resources/schema-fingerprint.json +2 -2
  37. package/dist/server.js +1 -1
  38. package/dist/tools/datasources.js +1 -1
  39. package/dist/tools/designSchemaPatch.js +4 -3
  40. package/dist/tools/externalComponents.js +1 -1
  41. package/dist/tools/flows.js +70 -4
  42. package/dist/tools/layouts.js +5 -5
  43. package/dist/tools/microservices.js +26 -10
  44. package/dist/tools/pages.js +192 -36
  45. package/dist/tools/platformInfo.js +4 -1
  46. package/dist/tools/rows.js +7 -1
  47. package/dist/tools/schemaOps.js +1 -1
  48. package/dist/tools/screenWrite.js +4 -3
  49. package/dist/tools/screens.js +81 -0
  50. package/package.json +1 -1
package/.env.example CHANGED
@@ -51,6 +51,21 @@ REQUEST_TIMEOUT_MS=100000
51
51
  STUDIO_BASE_URL=http://localhost:3000
52
52
  SCREENSHOT_BROWSER_PATH=
53
53
 
54
+ # Jeton kasasi (g-09): MCP_STATE_DIR verilirse tok_ referanslari ve test kullanicisi jetonlari
55
+ # <dizin>/token-vault.json'a (0600) yazilir ve gateway yeniden baslayinca da cozulur. Yalniz lokal
56
+ # hedefte (ORG_API_BASE_URL localhost) yazilir. MCP_TOKEN_TTL_MINUTES referansin omru (dakika).
57
+ MCP_STATE_DIR=
58
+ MCP_TOKEN_TTL_MINUTES=60
59
+
60
+ # asUser: 'test:<ad>' icin test kullanicilari — satiri INSAN yazar, AI .env'i duzenlemez.
61
+ # Bicim (JSON, tek satir): uygulamanin kendi giris ucu ve onun bekledigi govde. Ayrinti: docs/ortam.md
62
+ # MCP_TEST_USER_OGRENCI={"application":"<uygulama slug>","microservice":"<giris ucu slug>","body":{"email":"…","password":"…"}}
63
+
64
+ # bodyFile icin: tanim yazan araclarin (page_create, flow_create, microservice_create, *_patch …)
65
+ # govdeyi okuyabilecegi ek dizin. Gateway surecinin calisma dizini her zaman izinlidir; bu dizin
66
+ # ek olarak izinli olur. Bos birakilirsa yalniz calisma dizini okunur. Sembolik bag cozulur.
67
+ MCP_INPUT_DIR=
68
+
54
69
  # generate-schemas icin swagger adresleri. Bos birakilirsa sirayla denenir:
55
70
  # 1) asagidaki override, 2) {API_BASE_URL}/swagger/v1/swagger.json, 3) localhost:3000 frontend proxy'si
56
71
  ORG_SWAGGER_URL=
package/dist/config.js CHANGED
@@ -120,6 +120,9 @@ const environmentSchema = z.object({
120
120
  STUDIO_BASE_URL: z.string().url().optional(),
121
121
  SCREENSHOT_BROWSER_PATH: z.string().min(1).optional(),
122
122
  SCREENSHOT_QUEUE_WAIT_MS: z.coerce.number().int().positive().default(120000),
123
+ MCP_INPUT_DIR: z.string().min(1).optional(),
124
+ MCP_STATE_DIR: z.string().min(1).optional(),
125
+ MCP_TOKEN_TTL_MINUTES: z.coerce.number().int().positive().optional(),
123
126
  });
124
127
  export const environmentKeys = Object.keys(environmentSchema.shape);
125
128
  /**
@@ -228,5 +231,11 @@ export function loadConfig(env) {
228
231
  studioBaseUrl: values.STUDIO_BASE_URL?.replace(/\/+$/, ""),
229
232
  screenshotBrowserPath: values.SCREENSHOT_BROWSER_PATH,
230
233
  screenshotQueueWaitMs: values.SCREENSHOT_QUEUE_WAIT_MS,
234
+ inputDirectory: values.MCP_INPUT_DIR,
235
+ stateDirectory: values.MCP_STATE_DIR,
236
+ tokenTtlMinutes: values.MCP_TOKEN_TTL_MINUTES,
237
+ testUsers: Object.fromEntries(Object.entries(env)
238
+ .filter((entry) => entry[0].startsWith("MCP_TEST_USER_") && typeof entry[1] === "string" && entry[1] !== "")
239
+ .map(([key, value]) => [key.slice("MCP_TEST_USER_".length).toLowerCase(), value])),
231
240
  };
232
241
  }
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
3
3
  import { configureLogging, logGatewayEvent } from './observability/trace.js';
4
+ import { configureTokenVault } from './platform/tokenVault.js';
4
5
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
6
  import { Platform, requestAuthStorage } from './platform/http.js';
6
7
  import { createGatewayServer } from './server.js';
@@ -31,6 +32,7 @@ catch (error) {
31
32
  const platform = new Platform(config);
32
33
  const useStdio = process.argv.includes('--stdio');
33
34
  configureLogging(config, useStdio ? 'stdio' : 'http');
35
+ configureTokenVault(config);
34
36
  if (useStdio) {
35
37
  if (config.authMode === 'passthrough') {
36
38
  logger.error('stdio kipi passthrough auth ile kullanılamaz; AUTH_MODE=local yapın.');
@@ -32,7 +32,7 @@ export const TABLE_COLUMN_TYPE_NOTE = "KOLON TİPİ SÖZLÜĞÜ (bekler → çiz
32
32
  "tags: [{ value, color }] dizisi ya da metin dizisi → çok rozet, renk SATIR VERİSİNDEN (serbest hex burada geçer), sığmayanlar +N ile toplanır. " +
33
33
  "action: veri kolonu DEĞİL — aksiyon sütunu ayrı çizilir; kolon tanımında seçilirse ham değer metin olarak görünür.";
34
34
  export const STYLE_GROUP_NOTES = {
35
- surfaceStyle: "{ background, radius, borderTop, borderRight, borderBottom, borderLeft, shadow, contentOverflow(visible|hidden|auto), opacity(0–100 yüzde; 100/boş yazılmaz) }. radius: tema kademesi ('var(--ng-radius-md)'; sm/lg 'Border radius'un oranı, md temanın kendisi), tek uzunluk ('18px') YA DA dört köşe ('90px 14px 14px 14px' — sol-üst, sağ-üst, sağ-alt, sol-alt). KENARLIK YÖN BAŞINADIR: her yön kendi CSS kısayolunu taşır ('1px solid var(--ng-border-primary)'), 'none' o kenarı kapatır; eski borderWidth/borderStyle/borderColor üçlüsü EMEKLİ (yalnız hiçbir yön yazılmamışsa okunur). shadow: çok katmanlı `box-shadow` metni ('0px 2px 5px 0px rgba(0,0,0,.2), inset 8px 5px 7px 0px #000'), tema token'ı ('var(--ng-shadow-md)') ya da eski preset anahtarı (none|sm|md|lg).",
35
+ surfaceStyle: "{ background, radius, borderTop, borderRight, borderBottom, borderLeft, shadow, contentOverflow(visible|hidden|auto), opacity(0–100 yüzde; 100/boş yazılmaz), rotate(derece, −360…360), scale(YÜZDE 10–500; 100 aynı boy ve varsayılan — 1.1 değil 110), translateX/translateY(px, −1000…1000) }. radius: tema kademesi ('var(--ng-radius-md)'; sm/lg 'Border radius'un oranı, md temanın kendisi), tek uzunluk ('18px') YA DA dört köşe ('90px 14px 14px 14px' — sol-üst, sağ-üst, sağ-alt, sol-alt). KENARLIK YÖN BAŞINADIR: her yön kendi CSS kısayolunu taşır ('1px solid var(--ng-border-primary)'), 'none' o kenarı kapatır; eski borderWidth/borderStyle/borderColor üçlüsü EMEKLİ (yalnız hiçbir yön yazılmamışsa okunur). shadow: çok katmanlı `box-shadow` metni ('0px 2px 5px 0px rgba(0,0,0,.2), inset 8px 5px 7px 0px #000'), tema token'ı ('var(--ng-shadow-md)') ya da eski preset anahtarı (none|sm|md|lg). DÖNDÜR/ÖLÇEKLE/KAYDIR (ADR 0005): dört alan TEK transform'a derlenir — sıra kaydır → döndür → ölçekle, köken merkez, düğüm çocuklarıyla döner; nötr değer (0°, 100, 0 px) hiçbir şey yazmaz. Değer BİRİMSİZ sayıdır ('15deg', '20px', '110%' yazılmaz) ve aralık dışı yazılmaz — mobilde ikisi de nativeStyle.warnings'e düşer. Transform'lu düğümün İÇİNDEKİ portal açmayan açılır menü/liste düğümün kutusuna hapsolur. hoverStyle.lift düğümün transform'unu ezmez, önüne eklenir. Katmanlar (modal, drawer, popover) ve uygulama kabukları (layout, layout-region, layout-shell, auth-layout, qm-content, qm-sidebar) bu dört alanı TAŞIMAZ: transform'lu ata position:fixed katmanı ekrandan koparır. Döndürmeyi serbest style.transform'a yazma — mobil yalnız tipli alanı çizer (MOB-002).",
36
36
  typographyStyle: "{ textColor, fontFamily('var(--ng-font)' tema gövde | 'var(--ng-font-heading)' tema başlık | 'monospace' — token tema fontunu izler; serbest Google fontu yazma, tema yüklemez ve sessizce düşer), fontSize(CSS uzunluğu: '15px'|'1.1em'; çıplak sayı px sayılır), fontWeight(400|500|600|700), fontStyle(normal|italic), textDecoration(none|underline|line-through), lineHeight(TEK alan, üç yazım: oran '1.4' | yüzde '140%' | uzunluk '24px'; eski kayıtlardaki çıplak 140 yüzde sayılır), letterSpacing(CSS uzunluğu, negatif meşru: '-0.4px'), textAlign(left|center|right|justify) }. Komponentin içeriğine miras kalır.",
37
37
  hoverStyle: "{ background, borderColor, shadow(none|sm|md|lg), lift(CSS uzunluğu: '2px'), transitionMs }. Hiçbir alan dolu değilse hover bloğu ve geçiş HİÇ yazılmaz.",
38
38
  colorTokens: "RENK ALANLARI (background, textColor, borderColor, hover.background/borderColor) hex kadar tema token'ı da alır: 'var(--ng-accent-primary)', 'var(--ng-status-error)', 'var(--ng-background-inverse)'. Token yazılan alan tema değişince izler, hex yazılan kopar; tasarım sistemi renklerinde ÖNCE token'ı tercih et (studio panelinde aynı seçim tema chip'iyle yapılır).",
@@ -769,7 +769,7 @@ export const componentKnowledge = {
769
769
  value: "Seçili dosya(lar). Panelde ÇİZİLİR ve akıştan yazılabilir (2026-09-17'ye kadar gizliydi, bu yüzden AI sözlüğünde de görünmüyordu): kayıtlı bir dosyayı forma geri basmanın yolu budur. Tekli kipte nesne, çoklu kipte dizi; boşaltmak için null (çoklu kipte []). Kipiyle uyuşmayan şekil de OKUNUR: çoklu kipte yazılan tek nesne listelenir, tekli kipte yazılan dizinin ilk dosyası çizilir (2026-09-17'ye kadar ikisi de sessizce hiçbir şey göstermiyordu). İçeriği olmayan kayıt (ne value ne data ne absolute_path) hiç çizilmez.",
770
770
  text: 'Butonun üzerindeki metin (varsayılan "Attach File"); ikon sabittir. Alanın başlığı ayrı bir prop\'tur: label.',
771
771
  description: 'Butonun altındaki yardım metni. Dosya seçilir seçilmez yerini dosya listesi alır, seçim temizlenince geri gelir (fileInput ile aynı kural).',
772
- allowedFiletypes: 'İzin verilen uzantılar (çoklu seçim, kapalı liste). Hem dosya diyaloğunun accept süzgecini hem de seçimden SONRAKİ denetimi besler: liste dışı bir dosya seçilirse değere girmez ve komponentin içinde "desteklenmiyor" uyarısı çizilir (2026-09-17; öncesinde yalnız diyalog süzgeciydi, "Tüm dosyalar" ile aşılabiliyordu). Hem allowedFiletypes hem customFiletypes boşsa her tür serbesttir.',
772
+ allowedFiletypes: 'İzin verilen uzantılar (çoklu seçim, kapalı liste). Hem dosya diyaloğunun accept süzgecini hem de seçimden SONRAKİ denetimi besler: liste dışı bir dosya seçilirse değere girmez ve komponentin içinde "desteklenmiyor" uyarısı çizilir (2026-09-17; öncesinde yalnız diyalog süzgeciydi, "Tüm dosyalar" ile aşılabiliyordu). Hem allowedFiletypes hem customFiletypes boşsa her tür serbesttir. Akış prop\'a düz metin yazabilir ("pdf,png", customFiletypes ile aynı ayraçlar) — 2026-09-25`e kadar bu komponenti `input.map is not a function` ile düşürüyordu (fileInput okuyordu).',
773
773
  customFiletypes: 'Listede olmayan uzantılar, serbest metin ("heic, dwg;psd"). Virgül, noktalı virgül ve boşluk ayraçtır; baştaki nokta ve yıldız atılır, büyük/küçük harf fark etmez. allowedFiletypes ile BİRLEŞİR, onun yerine geçmez (fileInput ile aynı ad ve aynı kural). Çok parçalı uzantı da yazılabilir ("tar.gz"): eşleşme adın SONUNA bakar, son noktadan sonrasına değil.',
774
774
  maxFileSizeMb: 'Dosya BAŞINA en büyük boyut (MB). Boş/0/negatif değer sınırsız demektir; aşan dosya değere girmez, uyarı komponentin içinde çizilir.',
775
775
  maxFileCount: "Çoklu kipte toplam dosya sayısı sınırı — zaten seçili olanlar da sayılır. Boş/0/negatif sınırsız. Tekli kipte hiç okunmaz ve panelde de gizlidir (isMultiple'a bağlı).",
@@ -1553,6 +1553,8 @@ export const componentKnowledge = {
1553
1553
  'aggregate/sort/topN/nullMode veriyi çizimden ÖNCE dönüştürür — aynı işi akışta yapmana gerek yok.',
1554
1554
  'isDrillDown:true iken veri noktasına tıklamak kırıntı seviyesi ekler; dataPointClick yükü kaynak satırın TAMAMINI (row) taşır, böylece alt seviye sorgusu tek olayla kurulur. Geri dönüş breadcrumbClick ile bildirilir ve yeniden sorgulamak akışın işidir.',
1555
1555
  'isExportable "tablo olarak gör" + dışa aktarma araç çubuğunu açar; showRefresh refresh olayını yayan bir yenile düğmesi ekler.',
1556
+ "OLAYLAR (2026-09-25 düzeltmesi): nokta tıklaması YALNIZ dataPointClick, kategori ekseninin etiketine basış YALNIZ axisLabelClick yayar (yatay çubukta etiketler y eksenindedir). Öncesinde axisLabelClick her nokta tıklamasında noktanın değeriyle geliyor, etikete basış ise hiç gelmiyordu: triggerEvent eksen yerine axisLabel altındaydı ve olay sorgusu nesne olduğu için süzmüyordu. Hedef çizgisi, bant ve eksen başlığı tıklaması olay değildir; selectionChange yalnız selectionMode açıkken gelir (kapalıyken ECharts'ın boş seçimi self.selected'ı eziyordu); dataPointClick.row kategori adıyla bulunur (nullMode skip sonrası kayan dataIndex yanlış satırı veriyordu). Eşleme mobil chart ile ortak (chart-events.ts).",
1557
+ 'BOZUK BAĞLI VERİ (2026-09-25): series/rows beklenmedik şekilde gelirse (dizi yerine metin, okunamayan alan) grafik düşmez — veri çözülemezse emptyText, seçenek kurulamazsa önceki çizim kalır. Eksen başlığı (categoryAxis.title / valueAxis.title) varsayılan ızgarada tuvalden taşar ve görünmez (ARC-129).',
1556
1558
  "PASTA/HALKA ETİKETİ (2026-08-27 düzeltmesi): dataLabels.show artık pie/donut'a da geçiyor. Öncesinde prop bu dala hiç ulaşmıyordu ve dilim etiketleri HİÇBİR ayarla kapatılamıyordu — çekme çizgileri legend'in üstüne bindiği için halka fiilen kullanılamıyordu. Temiz halka için dataLabels:{ show:false } yaz.",
1557
1559
  'LEGENDDEN SERİ GİZLEME ÇALIŞIYOR (2026-09-16 düzeltmesi): legend tıklaması artık kalıcı. Öncesinde tıklama ~8 ms sonra kendiliğinden geri alınıyordu — olay yükü prop’lara yazılıyor, tepkime notMerge çizim yapıyor ve ECharts’ın legend.selected durumu siliniyordu. Seçim çizimden önce option’a geri yazılıyor; listede olmayan seri adları elenir.',
1558
1560
  'YATAY + İKİNCİL EKSEN ÇİZİLİYOR (2026-09-16 düzeltmesi): orientation:"horizontal" ile bir seride axis:"secondary" birlikte verilince grafik SESSİZCE boş çiziliyordu — yatayda değer eksenleri xAxis dizisindedir, yAxis tek kategori eksenidir. Kombo grafiği artık iki yönelimde de kurulabilir.',
@@ -454,11 +454,11 @@ export const componentEventContracts = {
454
454
  },
455
455
  chart: {
456
456
  mount: NO_DATA,
457
- dataPointClick: { payload: { name: 'string (kategori); scatter grafiğinde x değeri', seriesName: 'string', value: 'number | null; scatter grafiğinde y', dataIndex: 'number', row: 'kaynak satırın TAMAMI | null' }, reads: 'YALNIZ seri noktasında yayılır; eksen etiketi tıklaması axisLabelClick’tir (2026-09-16 öncesinde o da boş bir dataPointClick üretiyordu). scatter noktası ECharts tarafında [x, y, size] dizisidir, yük tek değere indirgenir: name = x, value = y' },
457
+ dataPointClick: { payload: { name: 'string (kategori); scatter grafiğinde x değeri', seriesName: 'string', value: 'number | null; scatter grafiğinde y', dataIndex: 'number (çizimdeki sıra)', row: 'kaynak satırın TAMAMI | null' }, reads: 'YALNIZ seri noktasına basışta; eksen etiketi tıklaması axisLabelClick’tir (2026-09-16 öncesinde o da boş bir dataPointClick üretiyordu), hedef çizgisi (referenceLines) ve bant (plotBands) olay değildir. row kategori adıyla — scatter’da x değeriyle — bulunur (nullMode skip ya da huni sıralaması dataIndex`i kaydırır); kategorisi olmayan noktada (histogram kutusu, radar serisi, funnelflow düğümü/bağı) null. scatter noktası ECharts tarafında [x, y, size] dizisidir, yük tek değere indirgenir: name = x, value = y' },
458
458
  breadcrumbClick: { payload: { filterValue: 'hedef seviyenin filtre değeri (kök seviyede undefined)' } },
459
- selectionChange: { payload: { selected: 'seçili veri noktaları' } },
459
+ selectionChange: { payload: { selected: 'seçili veri noktaları' }, reads: "yalnız selectionMode 'single'/'multi' iken; 'none' iken ECharts'ın her tıklamada attığı boş seçim yayılmaz (2026-09-25 öncesi yayılıyordu)" },
460
460
  legendClick: { payload: { name: 'string (seri adı)', selected: 'seri → görünürlük haritası' } },
461
- axisLabelClick: { payload: { value: 'string (tıklanan eksen etiketi)' }, reads: 'Kategori ekseni hangi eksene düşerse oradan gelir — yatay yönelimde yAxis (2026-09-16 öncesinde yatayda hiç yayılmıyordu)' },
461
+ axisLabelClick: { payload: { value: 'string (tıklanan eksen etiketi)' }, reads: 'yalnız kategori ekseninin etiketine basışta; kategori ekseni hangi eksene düşerse oradan gelir — yatay yönelimde yAxis (2026-09-16 öncesinde yatayda hiç yayılmıyordu). Nokta tıklaması ve eksen başlığı (categoryAxis.title) bu olayı yaymaz — 2026-09-25 öncesinde nesne sorgusu süzmediği için her nokta tıklamasında noktanın değeriyle yayılıyordu' },
462
462
  zoom: { payload: { start: 'number | null (görünen aralığın başlangıç yüzdesi)', end: 'number | null (bitiş yüzdesi)', startValue: 'number | null (eksenin kendi birimindeki mutlak alt sınır)', endValue: 'number | null (mutlak üst sınır)' }, reads: 'Yük normalize edilir: ECharts iki dataZoom bileşeniyle alanları batch içine koysa da akış her zaman bu dört alanı görür. Aralığı sorguya çevirecekseniz yüzdeleri değil startValue/endValue kullanın (2026-09-16)' },
463
463
  refresh: NO_DATA,
464
464
  retry: NO_DATA