@appaflytech/zeyrek-ai-mcp 0.0.6 → 0.0.7

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 (91) hide show
  1. package/.env.example +2 -2
  2. package/.env.production.example +8 -0
  3. package/README.md +9 -8
  4. package/dist/config.js +18 -3
  5. package/dist/knowledge/backendConstraints.js +85 -0
  6. package/dist/knowledge/componentCatalog.js +357 -54
  7. package/dist/knowledge/componentEvents.js +120 -25
  8. package/dist/knowledge/functionGuards.js +134 -0
  9. package/dist/knowledge/normalize.js +53 -2
  10. package/dist/knowledge/outlines.js +31 -0
  11. package/dist/knowledge/policy.js +14 -5
  12. package/dist/knowledge/rules.js +343 -1
  13. package/dist/platform/csv.js +123 -0
  14. package/dist/platform/errors.js +62 -3
  15. package/dist/platform/http.js +1 -0
  16. package/dist/platform/responses.js +16 -4
  17. package/dist/platform/screenshot.js +18 -1
  18. package/dist/resources/examples/flow-call-function.json +66 -0
  19. package/dist/resources/examples/function-total.json +70 -0
  20. package/dist/resources/examples/microfunction-node-sum.json +56 -0
  21. package/dist/resources/examples/page-dynamic-form.json +1 -1
  22. package/dist/resources/examples/page-sign-in.json +1 -1
  23. package/dist/resources/guides/component.md +13 -1
  24. package/dist/resources/guides/entity.md +321 -17
  25. package/dist/resources/guides/expressions.md +3 -0
  26. package/dist/resources/guides/functions.md +262 -0
  27. package/dist/resources/guides/getting-started.md +5 -0
  28. package/dist/resources/guides/merge.md +231 -0
  29. package/dist/resources/guides/microfunction.md +166 -0
  30. package/dist/resources/guides/microservice.md +61 -2
  31. package/dist/resources/guides/modify-existing.md +23 -0
  32. package/dist/resources/guides/page.md +20 -4
  33. package/dist/resources/guides/translation.md +24 -0
  34. package/dist/resources/guides/workflow.md +1 -1
  35. package/dist/resources/schema-fingerprint.json +4 -4
  36. package/dist/resources/schemas/AnalyzeImportQuery.json +51 -0
  37. package/dist/resources/schemas/ApplyMergePlanCommand.json +19 -0
  38. package/dist/resources/schemas/CreateBulkRowCommand.json +3 -0
  39. package/dist/resources/schemas/CreateEnvironmentCommand.json +31 -0
  40. package/dist/resources/schemas/CreateGlobalFunctionCommand.json +95 -0
  41. package/dist/resources/schemas/CreateImportPlanCommand.json +278 -0
  42. package/dist/resources/schemas/CreateMergePlanCommand.json +34 -0
  43. package/dist/resources/schemas/CreateMicrofunctionCommand.json +117 -0
  44. package/dist/resources/schemas/CreateMicrofunctionRuntimeCommand.json +51 -0
  45. package/dist/resources/schemas/CreateMicroserviceCommand.json +119 -1
  46. package/dist/resources/schemas/CreateWorkflowCommand.json +13 -2
  47. package/dist/resources/schemas/DataJobDto.json +267 -0
  48. package/dist/resources/schemas/ExportRowsCommand.json +172 -0
  49. package/dist/resources/schemas/Filter.json +3 -1
  50. package/dist/resources/schemas/GetRowsQuery.json +3 -1
  51. package/dist/resources/schemas/GlobalFunctionDto.json +89 -0
  52. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +249 -0
  53. package/dist/resources/schemas/ImportAnalysisDto.json +401 -0
  54. package/dist/resources/schemas/ImportPlanDto.json +260 -0
  55. package/dist/resources/schemas/ImportSampleDto.json +90 -0
  56. package/dist/resources/schemas/InvokeMicrofunctionCommand.json +25 -0
  57. package/dist/resources/schemas/PreviewMicroserviceCommand.json +119 -1
  58. package/dist/resources/schemas/PreviewWorkflowCommand.json +13 -2
  59. package/dist/resources/schemas/ResolveMergeConflictsCommand.json +58 -0
  60. package/dist/resources/schemas/RevertMergePlanCommand.json +19 -0
  61. package/dist/resources/schemas/RunImportCommand.json +62 -0
  62. package/dist/resources/schemas/StepDto.json +13 -2
  63. package/dist/resources/schemas/UpdateBulkRowCommand.json +3 -0
  64. package/dist/resources/schemas/UpdateEntityCommand.json +3 -1
  65. package/dist/resources/schemas/UpdateGlobalFunctionCommand.json +66 -0
  66. package/dist/resources/schemas/UpdateMicrofunctionCommand.json +121 -0
  67. package/dist/resources/schemas/UpdateMicrofunctionRuntimeCommand.json +54 -0
  68. package/dist/resources/schemas/UpdateMicroserviceCommand.json +119 -1
  69. package/dist/resources/schemas/UpdateWorkflowCommand.json +13 -2
  70. package/dist/server.js +15 -3
  71. package/dist/tools/activities.js +40 -0
  72. package/dist/tools/automations.js +14 -5
  73. package/dist/tools/common.js +16 -0
  74. package/dist/tools/dependencies.js +1 -1
  75. package/dist/tools/environments.js +52 -0
  76. package/dist/tools/files.js +51 -50
  77. package/dist/tools/flows.js +95 -2
  78. package/dist/tools/functions.js +331 -0
  79. package/dist/tools/importSchemas.js +79 -0
  80. package/dist/tools/imports.js +241 -0
  81. package/dist/tools/merges.js +113 -0
  82. package/dist/tools/microfunctions.js +155 -0
  83. package/dist/tools/microservices.js +42 -3
  84. package/dist/tools/pages.js +62 -10
  85. package/dist/tools/platformInfo.js +4 -1
  86. package/dist/tools/revisions.js +94 -0
  87. package/dist/tools/rows.js +342 -22
  88. package/dist/tools/screenWrite.js +11 -2
  89. package/dist/tools/templates.js +32 -5
  90. package/dist/tools/workflows.js +24 -6
  91. package/package.json +3 -1
@@ -1,5 +1,6 @@
1
- import { guid, projectParam, environmentParam, pagingParams, readOnly, writes, updates, destructive, microOps } from './common.js';
2
- import { orphanedFlowWarnings, orphanedFlowPlan, orphanedFlowMessage, staleSetterWarnings, normalizeComponentDefaults, normalizeSchemaOps, schemaOpValidationErrors, validationNote, componentDefaultsNote, replacePropNote, ensurePageContainer, retargetRootAdds, rootAddsNote, flexSizeWarnings, reorderSchemaBlocks, reorderNote, nestedRepeaterNodes, nestedRepeaterMessage, stringStyleNodes, stringStyleWarning, inertFlexPropNodes, inertFlexPropWarning, isFlexContainer, FLEX_LAYOUT_PROP_NAMES, resetPageContainerPosition, pageContainerPositionWarning, verticalGapWarnings, withNormalization, PAGE_CONTAINER_ELEMENT_ID } from '../knowledge/normalize.js';
1
+ import { guid, projectParam, environmentParam, pagingParams, readOnly, writes, updates, destructive, microOps, isBranchName } from './common.js';
2
+ import { orphanedFlowWarnings, orphanedFlowPlan, orphanedFlowMessage, staleSetterWarnings, normalizeComponentDefaults, normalizeSchemaOps, schemaOpValidationErrors, validationNote, componentDefaultsNote, replacePropNote, ensurePageContainer, retargetRootAdds, rootAddsNote, flexSizeWarnings, reorderSchemaBlocks, reorderNote, nestedRepeaterNodes, nestedRepeaterMessage, stringStyleNodes, stringStyleWarning, inertFlexPropNodes, inertFlexPropWarning, isFlexContainer, FLEX_LAYOUT_PROP_NAMES, resetPageContainerPosition, pageContainerPositionWarning, verticalGapWarnings, withNormalization, parseVariableEntries, PAGE_CONTAINER_ELEMENT_ID } from '../knowledge/normalize.js';
3
+ import { functionSignature } from '../knowledge/functionGuards.js';
3
4
  import { fetchHost, pageUpdateBody, schemaParam, eventsParam, unwrap, modeParam, summarize, outlineAppliedPatch, findNode, flowPath } from './screens.js';
4
5
  import { fetchComponentEventNames } from './components.js';
5
6
  import { assertScreenWriteGuards, screenCatalogNotes } from './screenWrite.js';
@@ -9,11 +10,31 @@ import { PlatformApiError } from '../platform/errors.js';
9
10
  import { handle, toolResult, toolError } from '../platform/responses.js';
10
11
  import { StudioScreenshotter } from '../platform/screenshot.js';
11
12
  import { summarizeLayout } from '../knowledge/layoutSummary.js';
13
+ import { normalizeLanguageCode } from '../knowledge/languageCodes.js';
14
+ import { readProjectLanguages } from '../knowledge/languages.js';
12
15
  import { resolveIdentityToken } from '../platform/tokenVault.js';
13
16
  import { mkdir, writeFile } from 'node:fs/promises';
14
17
  import { dirname, resolve } from 'node:path';
15
18
  import { applyPropTypesToSchema, setPropTypeErrors } from '../knowledge/propTypes.js';
16
19
  import { z } from 'zod';
20
+ /**
21
+ * Runtime paketindeki `appFunctions`/`pageFunctions` (UiFunctionRuntimeDto: id, name, parameters,
22
+ * body, isAsync) — imza taşınır, GÖVDE TAŞINMAZ (MAX_RESPONSE_BYTES). Ajan Functions.<ad>(…)
23
+ * yazarken adı ve parametre sırasını buradan alır (G-06).
24
+ */
25
+ function runtimeFunctions(value) {
26
+ return (Array.isArray(value) ? value : [])
27
+ .filter((entry) => Boolean(entry) && typeof entry === 'object')
28
+ .map(entry => ({
29
+ id: entry.id,
30
+ name: entry.name,
31
+ signature: functionSignature(entry),
32
+ isAsync: entry.isAsync === true,
33
+ parameters: (Array.isArray(entry.parameters) ? entry.parameters : [])
34
+ .filter((parameter) => Boolean(parameter) && typeof parameter === 'object')
35
+ .map(parameter => ({ name: parameter.name, required: parameter.required === true, defaultValue: parameter.defaultValue ?? null }))
36
+ }));
37
+ }
17
38
  /**
18
39
  * Yazma yanıtındaki şema gövdesinin biçimi (B-55 · S-9). Varsayılan `outline`: gövde ajanın
19
40
  * aynı turda kendi gönderdiği içeriğin yankısıdır, kanıt ise pointer'da ve `silentlyDropped`ta
@@ -324,7 +345,7 @@ export function registerPageTools(server, platform, injectedScreenshotter) {
324
345
  }));
325
346
  server.registerTool('page_runtime_get', {
326
347
  title: 'Sayfanın runtime çıktısını getir',
327
- description: "Çıkan uygulamanın sayfa için aldığı GERÇEK paketi döner (GET /{project}/{application}/p/{slug} — sayfanın ham serve yolu budur; Studio preview ve runtime aynı ucu tüketir): sayfa şeması + layout views'ü + sayfa olayları + flow'lar + değişken anahtarları. Kurduğun sayfanın SON hâlini doğrulamanın yolu budur (layout-slot yerleşimi dahil — Kural 1f). DİKKAT: sayfaya bağlı middleware'ler bu çağrıda GERÇEKTEN koşar; middleware reddederse yanıt middlewareBlocked ile döner — korumalı sayfada bu beklenen davranıştır ve kendisi bir doğrulamadır.",
348
+ description: "Çıkan uygulamanın sayfa için aldığı GERÇEK paketi döner (GET /{project}/{application}/p/{slug} — sayfanın ham serve yolu budur; Studio preview ve runtime aynı ucu tüketir): sayfa şeması + layout views'ü + sayfa olayları + flow'lar + değişken anahtarları (variableKeys: middleware değişkenleri, pageVariableKeys/appVariableKeys: state.page/state.app anahtarları) + kullanıcı fonksiyonu imzaları (appFunctions/pageFunctions — bir ifadeye Functions.<ad>(…) yazmadan önce adı ve parametre sırasını buradan alın; gövde taşınmaz, function_get ile okunur). Kurduğun sayfanın SON hâlini doğrulamanın yolu budur (layout-slot yerleşimi dahil — Kural 1f). DİKKAT: sayfaya bağlı middleware'ler bu çağrıda GERÇEKTEN koşar; middleware reddederse yanıt middlewareBlocked ile döner — korumalı sayfada bu beklenen davranıştır ve kendisi bir doğrulamadır.",
328
349
  inputSchema: {
329
350
  project: projectParam,
330
351
  environment: environmentParam,
@@ -375,6 +396,10 @@ export function registerPageTools(server, platform, injectedScreenshotter) {
375
396
  widgets: named(body.widgets),
376
397
  flows: named(body.flows),
377
398
  variableKeys: Object.keys((body.variables ?? {})),
399
+ pageVariableKeys: parseVariableEntries(body.pageVariables).map(entry => entry.key),
400
+ appVariableKeys: parseVariableEntries(body.appVariables).map(entry => entry.key),
401
+ appFunctions: runtimeFunctions(body.appFunctions),
402
+ pageFunctions: runtimeFunctions(body.pageFunctions),
378
403
  hasTheme: Boolean(body.project?.theme),
379
404
  note: resolveStyles
380
405
  ? "schema, layout'taki slot'un İÇİNE yerleşerek çizilir (Kural 1f). resolvedStyle = componentStyles → preset → düğüm stili kaskadı (aibox'ta tipli grupların derlemesi TABAN katmandır); styleLayers hangi katmanların konuştuğunu söyler."
@@ -385,7 +410,7 @@ export function registerPageTools(server, platform, injectedScreenshotter) {
385
410
  const maxInlinePngBytes = 5 * 1024 * 1024;
386
411
  server.registerTool('page_screenshot', {
387
412
  title: 'Sayfanın ekran görüntüsünü al',
388
- description: "Studio arayüzünün runtime render rotasını (/dev ya da /view) headless Chromium'da açar ve sayfanın PNG ekran görüntüsünü inline görüntü olarak döner — kurduğun sayfayı GÖZLE doğrulamanın yolu budur (page_runtime_get paketi verir, bu tool ekranda ne ÇİZİLDİĞİNİ gösterir). Sayfaya bağlı middleware'ler gerçekten koşar; reddedilirse yanıtta middlewareBlocked işaretlenir ve Studio'nun çizdiği hata durumu karesi döner — bu da bir doğrulamadır. YÜKLENMEMİŞ SAYFA ASLA ÇEKİLMEZ: kare, runtime çizilip mount akışları bitince alınır (yanıtta pageState + readyAfterMs); bütçe dolduğunda sayfa hâlâ iskelette ya da akış koşuyorsa çağrı ne görüldüğünü söyleyen bir hatayla döner, boş/yarım kare dönmez. Sayfa akışı bir adımda düşerse (patlayan ifade, hata dönen uç) yanıt runtimeErrors taşır ve hangi komponentin hangi prop'unun YAZILMADIĞINI söyler — kare 'çalışıyor' görünürken sessizce boş kalan komponenti ancak bu yakalar. STUDIO_BASE_URL tanımlı olmalı; ilk kullanım için `npx playwright-core install chromium` gerekir.",
413
+ description: "Studio arayüzünün runtime render rotasını (/dev ya da /view) headless Chromium'da açar ve sayfanın PNG ekran görüntüsünü inline görüntü olarak döner — kurduğun sayfayı GÖZLE doğrulamanın yolu budur (page_runtime_get paketi verir, bu tool ekranda ne ÇİZİLDİĞİNİ gösterir). Sayfaya bağlı middleware'ler gerçekten koşar; reddedilirse yanıtta middlewareBlocked işaretlenir ve Studio'nun çizdiği hata durumu karesi döner — bu da bir doğrulamadır. YÜKLENMEMİŞ SAYFA ASLA ÇEKİLMEZ: kare, runtime çizilip mount akışları bitince alınır (yanıtta pageState + readyAfterMs); bütçe dolduğunda sayfa hâlâ iskelette ya da akış koşuyorsa çağrı ne görüldüğünü söyleyen bir hatayla döner, boş/yarım kare dönmez. Sayfa akışı bir adımda düşerse (patlayan ifade, hata dönen uç) yanıt runtimeErrors taşır ve hangi komponentin hangi prop'unun YAZILMADIĞINI söyler — kare 'çalışıyor' görünürken sessizce boş kalan komponenti ancak bu yakalar. Kare DİLİ ve TEMASI seçilebilir: 'language' adrese ?lang ekler (çeviriye bağlı prop'lar da çok dilli alanların satır değerleri de o dilde çözülür), 'colorScheme' ziyaretçinin tema tercihini sayfa açılmadan eker — ikisi de sayfaya dil değiştirici ya da theme-toggle koymayı GEREKTİRMEZ, yani referansa sadık bir tasarımın ikinci dili ve koyu teması bozulmadan kanıtlanır. STUDIO_BASE_URL tanımlı olmalı; ilk kullanım için `npx playwright-core install chromium` gerekir. DAL ORTAMI DA GÖRÜNTÜLENİR (2026-09-09'dan beri): 'development' /dev, 'production' /view, dal ise /branch/{dal} şeridinden açılır ve sayfanın BÜTÜN istekleri (şema da akışlar da) o dala gider — dalda kurulan sayfa artık merge'i beklemeden gözle doğrulanır (platform_guide('merge') §Dalda görsel doğrulama).",
389
414
  inputSchema: {
390
415
  project: projectParam,
391
416
  environment: environmentParam,
@@ -409,10 +434,12 @@ export function registerPageTools(server, platform, injectedScreenshotter) {
409
434
  value: z.unknown().optional().describe("'set' için yazılacak değer"),
410
435
  ms: z.number().int().min(0).max(15000).optional().describe("'wait' için bekleme süresi")
411
436
  })).max(20).optional().describe("Kare ALINMADAN ÖNCE sayfada koşturulacak etkileşim adımları: [{action:'set', target:'flt_month', value:'2022-10'}, {action:'click', target:'btn_sign_in'}]. 'set' native setter kullanır ve input+change olaylarını bubbles ile atar (düz DOM ataması framework'ün duyduğu olayı üretmez). Her adımdan sonra yerleşme beklenir ve yanıttaki actionsReport hedefin bulunup bulunmadığını ve adımdan sonra KAÇ AĞ İSTEĞİ çıktığını söyler — 'bağ kuruldu' ile 'çalışıyor' arasındaki farkı ancak bu ayırır (G-24)."),
437
+ language: z.string().min(1).optional().describe("Kareyi BU DİLDE çeker: adrese '?lang=<kod>' eklenir ve runtime dili oradan seçer (öncelik: ?lang → tarayıcıda kayıtlı seçim → tarayıcı dilleri → projenin varsayılanı). Seçim hem çeviriye bağlı prop'ları hem çok dilli alanların satır değerlerini kapsar, yani ikinci dilin karesi için sayfaya dil değiştirici KOYMAK GEREKMEZ — referans tasarımı bozulmadan ikinci dil kanıtlanır. ISO 639-1 iki harfli kod ('tr', 'en'); bölgeli kod ('tr-TR') indirgenir ve indirgeme yanıtta bildirilir. Kod projenin languages listesinde yoksa çağrı REDDEDİLİR: runtime tanımadığı kodu yok sayıp kareyi varsayılan dilde çizerdi ve 'çevrildi' sanılan yanlış bir kare raporlanırdı."),
438
+ colorScheme: z.enum(['light', 'dark']).optional().describe("Kareyi açık ya da koyu temada çeker. Ziyaretçi tema tercihi çerezde değil localStorage'da yaşar ve tema store'u onu sayfa açılırken bir kez okur; gateway tercihi sayfa script'lerinden ÖNCE eker, bu yüzden sayfada 'theme-toggle' komponenti OLMASA DA koyu tema karesi alınabilir. Verilmezse projenin kendi modu çizilir."),
412
439
  outPath: z.string().min(1).optional().describe('Verilirse PNG bu yerel yola yazılır ve inline görüntü DÖNMEZ; yalnız özet (yol, boyut) döner — büyük fullPage kareleri için')
413
440
  },
414
441
  annotations: readOnly
415
- }, async ({ project, environment, applicationSlug, pageSlug, viewport, fullPage, delayMs, captureUnready, anonymous, asUser, cookies, layoutReport, actions, outPath, expectFailure }) => {
442
+ }, async ({ project, environment, applicationSlug, pageSlug, viewport, fullPage, delayMs, captureUnready, anonymous, asUser, cookies, layoutReport, actions, outPath, expectFailure, language, colorScheme }) => {
416
443
  try {
417
444
  if (anonymous === true && (asUser !== undefined || cookies !== undefined)) {
418
445
  throw new PlatformApiError("page_screenshot: anonymous:true ile asUser/cookies birlikte verilemez — biri kimliksiz kareyi, diğeri belirli bir kimlikle çekilen kareyi ister. Anonim kare için yalnız anonymous:true, üye kimliğiyle kare için yalnız asUser (ve gerekiyorsa cookies) gönderin.");
@@ -421,11 +448,31 @@ export function registerPageTools(server, platform, injectedScreenshotter) {
421
448
  throw new PlatformApiError("page_screenshot için STUDIO_BASE_URL tanımlı değil. Studio arayüzünün kök adresini .env'e ekleyin (yerel geliştirmede http://localhost:3000, dağıtımda nginx adresi).");
422
449
  }
423
450
  const resolvedEnvironment = platform.resolveEnvironment(environment);
424
- const lane = resolvedEnvironment === 'development' ? 'dev' : resolvedEnvironment === 'production' ? 'view' : undefined;
451
+ // U-04 (2026-09-09): kısıt önce gateway'de DEĞİL Studio'da olduğu için reddediliyordu —
452
+ // runtime rotası dal adı taşımıyor, ortamı modül içi bir store belirliyordu ve dal adıyla
453
+ // istenen kare development'ı gösterirdi. Studio artık `/branch/{env}/…` şeridini tanıyor ve
454
+ // ortamı URL'den okuyor (f-02); dal karesi bu yüzden GERÇEKTEN o dalın karesi. Geriye yalnız
455
+ // platformun dal diye kabul etmeyeceği adlar kalıyor — onlar için şerit kurulmaz.
456
+ const lane = resolvedEnvironment === 'development'
457
+ ? 'dev'
458
+ : resolvedEnvironment === 'production'
459
+ ? 'view'
460
+ : isBranchName(resolvedEnvironment) ? `branch/${resolvedEnvironment}` : undefined;
425
461
  if (!lane) {
426
- throw new PlatformApiError(`page_screenshot yalnız 'development' (/dev) ve 'production' (/view) ortamlarını görüntüleyebilir; '${resolvedEnvironment}' için Studio'da karşılık gelen bir rota yok.`);
462
+ throw new PlatformApiError(`page_screenshot '${resolvedEnvironment}' ortamını görüntüleyemez: bu ad ne sabit bir ortam ne de geçerli bir dal adı. Sabitler 'development' (/dev) ve 'production' (/view); dal adı bir harfle başlar, yalnız küçük harf/rakam/alt çizgi taşır (3-31 karakter) ve rezerve olamaz ('public', 'api', 'pg_*' gibi). Projedeki dalları environment_list ile görün.`);
463
+ }
464
+ const projectSlug = platform.resolveProject(project);
465
+ const languageChoice = language === undefined ? undefined : normalizeLanguageCode(language, 'language');
466
+ if (languageChoice) {
467
+ // Bağ burada kurulmazsa sessiz yanlış kare doğar: runtime tanımadığı kodu yok sayar ve
468
+ // sayfayı varsayılan dilde çizer (resolveRuntimeLanguage yalnız projenin taşıdığı kodu
469
+ // seçer), kare de 'ikinci dil' diye rapora girerdi.
470
+ const state = readProjectLanguages(await platform.org('GET', `/p/${projectSlug}`).catch(() => undefined));
471
+ if (state && state.languages.length > 0 && !state.languages.includes(languageChoice.code)) {
472
+ throw new PlatformApiError(`page_screenshot: '${languageChoice.code}' projenin dilleri arasında değil (${state.languages.join(', ')}). Runtime bilmediği kodu yok sayıp kareyi varsayılan dilde çizer — dili project_update(languages) ile ekleyin ya da listedeki bir kodu verin.`);
473
+ }
427
474
  }
428
- const url = `${config.studioBaseUrl}/${lane}/${platform.resolveProject(project)}/${applicationSlug}/${pageSlug}`;
475
+ const url = `${config.studioBaseUrl}/${lane}/${projectSlug}/${applicationSlug}/${pageSlug}${languageChoice ? `?lang=${languageChoice.code}` : ''}`;
429
476
  const size = viewport ?? { width: 1280, height: 800 };
430
477
  const extraCookies = Object.entries(cookies ?? {}).map(([name, value]) => ({ name, value }));
431
478
  const identity = anonymous === true ? 'anonymous' : asUser === undefined ? 'gateway' : 'asUser';
@@ -441,11 +488,15 @@ export function registerPageTools(server, platform, injectedScreenshotter) {
441
488
  delayMs: delayMs ?? 0,
442
489
  ...(captureUnready === true ? { captureUnready: true } : {}),
443
490
  ...(layoutReport === true ? { layoutReport: true } : {}),
491
+ ...(colorScheme === undefined ? {} : { colorScheme }),
444
492
  ...(actions === undefined ? {} : { actions: actions })
445
493
  });
446
494
  const meta = {
447
495
  url,
448
496
  environment: resolvedEnvironment,
497
+ ...(languageChoice ? { language: languageChoice.code } : {}),
498
+ ...(languageChoice?.note ? { languageNote: languageChoice.note } : {}),
499
+ ...(colorScheme === undefined ? {} : { colorScheme }),
449
500
  viewport: size,
450
501
  fullPage: fullPage === true,
451
502
  identity,
@@ -507,8 +558,9 @@ export function registerPageTools(server, platform, injectedScreenshotter) {
507
558
  ...(shot.actions?.some(outcome => !outcome.found)
508
559
  ? { actionsNote: `Bulunamayan hedef var: ${shot.actions.filter(outcome => !outcome.found).map(outcome => outcome.target ?? '?').join(' · ')}. elementId'leri page_schema_get ile doğrulayın; runtime düğümü data-element-id ile bulunuyor.` }
509
560
  : {}),
510
- ...(shot.actions?.some(outcome => outcome.applied && outcome.requests === 0 && (outcome.flowRuns ?? 0) === 0)
511
- ? { actionsNote: `Uygulandı ama HİÇ AĞ İSTEĞİ çıkmadı ve HİÇBİR AKIŞ KOŞMADI: ${shot.actions.filter(outcome => outcome.applied && outcome.requests === 0 && (outcome.flowRuns ?? 0) === 0).map(outcome => `${outcome.action} '${outcome.target ?? '?'}'`).join(' · ')}. Olay bağı şemada görünse bile akış koşmamış olabilir — bağın gerçekten kurulu olduğunu page_runtime_get ile, akışın gövdesini flow_get ile doğrulayın.` }
561
+ // 'wait' bir eylem değil bekleyiştir: akış sayacı ona bağlanmaz, notu tetiklemez (33/S-1).
562
+ ...(shot.actions?.some(outcome => outcome.action !== 'wait' && outcome.applied && outcome.requests === 0 && (outcome.flowRuns ?? 0) === 0)
563
+ ? { actionsNote: `Uygulandı ama HİÇ AĞ İSTEĞİ çıkmadı ve HİÇBİR AKIŞ KOŞMADI: ${shot.actions.filter(outcome => outcome.action !== 'wait' && outcome.applied && outcome.requests === 0 && (outcome.flowRuns ?? 0) === 0).map(outcome => `${outcome.action} '${outcome.target ?? '?'}'`).join(' · ')}. Olay bağı şemada görünse bile akış koşmamış olabilir — bağın gerçekten kurulu olduğunu page_runtime_get ile, akışın gövdesini flow_get ile doğrulayın.` }
512
564
  : {}),
513
565
  ...(shot.layout === undefined
514
566
  ? {}
@@ -61,6 +61,7 @@ const guideRouting = {
61
61
  'modify-existing': 'mevcut yapıyı bozmadan değiştirme disiplini',
62
62
  workflow: 'DTO-önce akışı, branch bağlama, tip×step matrisi',
63
63
  microservice: 'kaynak seçimi (table > query), selectFields disiplini',
64
+ microfunction: 'kendi runtime\'ında koşan Node/Python fonksiyonu: protokol, yayın döngüsü, step kullanımı',
64
65
  entity: "alan tipleri, ilişkiler, hazır entity'ler",
65
66
  page: 'sayfa/flow işleri; flex düzen prop grubu ve boyut modları (Kural 1f-2)',
66
67
  layout: 'yerleşim kabuğu: tek slot, views, mobil yığılma, widthType fill/fixed/auto',
@@ -70,7 +71,9 @@ const guideRouting = {
70
71
  middleware: 'auth/oturum/yetki',
71
72
  view: 'tam metin arama indeksi',
72
73
  expressions: 'ifade fonksiyon/bağlam sözlüğü (system.*, file.*, Page.*, state.*, Steps…)',
73
- translation: 'sayfa/içerik çevirileri (çoklu dil)'
74
+ functions: "fonksiyonlar, iki kaynak tek biçim: source:'studio' tarayıcıda Functions.<ad>() (kapsam uygulama/sayfa, UI flow 'function' adımı), source:'workflow' sunucuda çıplak ad; parametre/varsayılan/required, tuzaklar",
75
+ translation: 'sayfa/içerik çevirileri (çoklu dil)',
76
+ merge: "dal aç, dalda çalış, development'a merge et; çakışma çözümü ve apply kapıları"
74
77
  };
75
78
  // page.md 123 KB; section'sız dönerse yanıt tool çıktı sınırını aşıyor ve rehber MCP kanalından
76
79
  // HİÇ okunamıyor (27/05 E-1, 09-04 koşusu). Eşik ÖLÇÜLEN kopma noktasından türetilir, "bugün
@@ -0,0 +1,94 @@
1
+ import { guid, pagingParams, readOnly } from './common.js';
2
+ import { handle } from '../platform/responses.js';
3
+ import { z } from 'zod';
4
+ const revisionModule = z.enum([
5
+ 'entity',
6
+ 'query',
7
+ 'view',
8
+ 'data_transfer_object',
9
+ 'microservice',
10
+ 'workflow',
11
+ 'flow',
12
+ 'page',
13
+ 'layout',
14
+ 'component',
15
+ 'variable',
16
+ 'application',
17
+ 'role',
18
+ 'folder'
19
+ ]).describe('Tanım türü; defter yalnız bu kökleri izler');
20
+ const environmentName = z.string().min(1).optional()
21
+ .describe("Ortam adı, ör. 'development' ya da bir dal adı; boşsa DEFAULT_ENVIRONMENT");
22
+ export function summarizeElements(elements) {
23
+ if (!Array.isArray(elements) || elements.length === 0)
24
+ return 'fark yok';
25
+ const lines = [];
26
+ for (const element of elements.slice(0, 20)) {
27
+ if (!element || typeof element !== 'object')
28
+ continue;
29
+ const { kind, label, path, before, after } = element;
30
+ const where = (typeof label === 'string' && label.length > 0 ? label : String(path ?? '')) || '(kök)';
31
+ const short = (value) => {
32
+ if (value === null || value === undefined)
33
+ return '—';
34
+ const text = typeof value === 'string' ? value : JSON.stringify(value);
35
+ return text.length > 60 ? `${text.slice(0, 57)}…` : text;
36
+ };
37
+ if (kind === 'add')
38
+ lines.push(`+ ${where} = ${short(after)}`);
39
+ else if (kind === 'delete')
40
+ lines.push(`- ${where} (${short(before)})`);
41
+ else
42
+ lines.push(`~ ${where}: ${short(before)} → ${short(after)}`);
43
+ }
44
+ if (elements.length > lines.length)
45
+ lines.push(`… ve ${elements.length - lines.length} değişiklik daha`);
46
+ return lines.join('\n');
47
+ }
48
+ export function registerRevisionTools(server, platform) {
49
+ const config = platform.config;
50
+ const defaultEnvironment = () => config.defaultEnvironment;
51
+ server.registerTool('revision_list', {
52
+ title: 'Tanım revizyonlarını listele',
53
+ description: "Bir ortamdaki tanım yazmalarını en yeniden eskiye listeler: hangi kayıt, kaçıncı revizyon, hangi işlem (create|update|delete), kim yaptı ve nereden geldi (source: studio|mcp|merge|deployment|template|revert|backfill). Gövde bu uçta DÖNMEZ — tek bir sürümün gövdesi için revision_get, iki sürüm arasındaki fark için revision_diff kullanın. source='mcp' satırları bu gateway üzerinden yapılan değişikliklerdir; bir kaydı değiştirmeden önce son revizyona bakmak, başka birinin üstüne yazmayı önler.",
54
+ inputSchema: {
55
+ projectId: guid,
56
+ environment: environmentName,
57
+ module: revisionModule.optional(),
58
+ recordId: guid.optional().describe('Tek bir tanım kaydının geçmişi'),
59
+ correlationId: z.string().min(1).optional().describe('Aynı komutun ya da merge activity id\'sinin yazdığı bütün revizyonlar'),
60
+ since: z.string().min(1).optional().describe("ISO tarih; bu andan sonraki revizyonlar"),
61
+ ...pagingParams
62
+ },
63
+ annotations: readOnly
64
+ }, handle(config, ({ projectId, environment, ...rest }) => platform.org('GET', `/revisions/${projectId}`, { query: { environment: environment ?? defaultEnvironment(), ...rest } })));
65
+ server.registerTool('revision_get', {
66
+ title: 'Tek revizyonu gövdesiyle oku',
67
+ description: "Bir revizyonu tam gövdesiyle (payload) döner — kaydın o andaki hali, deployment ve merge'ün taşıdığı biçimin aynısı. Entity revizyonlarında ddlDelta o yazmada eklenen/değişen/silinen alan adlarını taşır. Büyük sayfalarda gövde MB'lar tutabilir ve yanıt kırpılır; ne değiştiğini anlamak için önce revision_diff deneyin.",
68
+ inputSchema: { projectId: guid, id: guid.describe('revision_list çıktısındaki satır id\'si') },
69
+ annotations: readOnly
70
+ }, handle(config, ({ projectId, id }) => platform.org('GET', `/revisions/${projectId}/${id}`)));
71
+ server.registerTool('revision_diff', {
72
+ title: 'İki revizyon arasındaki farkı al',
73
+ description: "Bir tanım kaydının iki sürümü arasındaki farkı alan bazlı döner: her satırda path, label, kind (add|update|delete) ve before/after değerleri. from/to boş bırakılırsa son iki revizyon karşılaştırılır. Yanıta ayrıca summaryText eklenir — farkın tek bakışta okunur özeti. Merge ekranıyla aynı diff motorunu kullanır.",
74
+ inputSchema: {
75
+ projectId: guid,
76
+ environment: environmentName,
77
+ module: revisionModule,
78
+ recordId: guid,
79
+ from: z.number().int().min(0).optional().describe('Başlangıç revizyon numarası'),
80
+ to: z.number().int().min(0).optional().describe('Bitiş revizyon numarası')
81
+ },
82
+ annotations: readOnly
83
+ }, handle(config, async ({ projectId, environment, ...rest }) => {
84
+ const payload = await platform.org('GET', `/revisions/${projectId}/diff`, {
85
+ query: { environment: environment ?? defaultEnvironment(), ...rest }
86
+ });
87
+ if (!payload || typeof payload !== 'object')
88
+ return payload;
89
+ const data = payload.data;
90
+ if (!data || typeof data !== 'object')
91
+ return payload;
92
+ return { ...payload, summaryText: summarizeElements(data.elements) };
93
+ }));
94
+ }